mirror of
https://github.com/langgenius/dify.git
synced 2026-07-21 02:28:30 +08:00
Signed-off-by: yyh <yuanyouhuilyz@gmail.com> Co-authored-by: 盐粒 Yanli <mail@yanli.one> Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: zyssyz123 <916125788@qq.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: 盐粒 Yanli <yanli@dify.ai> Co-authored-by: 林玮 (Jade Lin) <linw1995@icloud.com>
182 lines
4.5 KiB
TypeScript
182 lines
4.5 KiB
TypeScript
import type {
|
|
AgentApiAccessResponse,
|
|
ApiKeyItem,
|
|
} from '@dify/contracts/api/console/agent/types.gen'
|
|
import type {
|
|
ChatRequestPayloadWithUser,
|
|
PostChatMessagesResponse,
|
|
} from '@dify/contracts/api/service/types.gen'
|
|
import type { APIResponse } from '@playwright/test'
|
|
import { request } from '@playwright/test'
|
|
import { createApiContext, expectApiResponseOK, setAppSiteEnabled } from '../../../support/api'
|
|
import { getTestAgent } from './agent'
|
|
|
|
export type AgentServiceApiChatResult = {
|
|
body: PostChatMessagesResponse | unknown
|
|
ok: boolean
|
|
status: number
|
|
}
|
|
|
|
type ServiceApiSseEvent = {
|
|
data: unknown
|
|
event?: string
|
|
}
|
|
|
|
async function parseServiceApiChatResponse(response: APIResponse) {
|
|
const contentType = response.headers()['content-type'] ?? ''
|
|
const text = await response.text().catch(() => '')
|
|
|
|
if (contentType.includes('text/event-stream'))
|
|
return parseServiceApiSseText(text)
|
|
|
|
if (contentType.includes('application/json')) {
|
|
try {
|
|
return JSON.parse(text) as unknown
|
|
}
|
|
catch {
|
|
return { message: text }
|
|
}
|
|
}
|
|
|
|
try {
|
|
return JSON.parse(text) as unknown
|
|
}
|
|
catch {
|
|
return { message: text }
|
|
}
|
|
}
|
|
|
|
function parseServiceApiSseText(text: string) {
|
|
const events: ServiceApiSseEvent[] = []
|
|
const answers: string[] = []
|
|
|
|
for (const block of text.split(/\r?\n\r?\n/)) {
|
|
const lines = block.split(/\r?\n/)
|
|
const eventName = lines
|
|
.find(line => line.startsWith('event:'))
|
|
?.slice('event:'.length)
|
|
.trim()
|
|
const dataText = lines
|
|
.filter(line => line.startsWith('data:'))
|
|
.map(line => line.slice('data:'.length).trimStart())
|
|
.join('\n')
|
|
|
|
if (!dataText)
|
|
continue
|
|
|
|
let data: unknown = dataText
|
|
try {
|
|
data = JSON.parse(dataText) as unknown
|
|
}
|
|
catch {
|
|
data = dataText
|
|
}
|
|
|
|
events.push({
|
|
data,
|
|
...(eventName ? { event: eventName } : {}),
|
|
})
|
|
|
|
if (
|
|
data
|
|
&& typeof data === 'object'
|
|
&& !Array.isArray(data)
|
|
&& 'answer' in data
|
|
&& typeof data.answer === 'string'
|
|
) {
|
|
answers.push(data.answer)
|
|
}
|
|
}
|
|
|
|
return {
|
|
answer: answers.join(''),
|
|
events,
|
|
raw: text,
|
|
}
|
|
}
|
|
|
|
export async function setAgentSiteAccessAndGetURL(
|
|
agentId: string,
|
|
enabled: boolean,
|
|
): Promise<string> {
|
|
const agent = await getTestAgent(agentId)
|
|
const appId = agent.app_id ?? agent.backing_app_id
|
|
if (!appId)
|
|
throw new Error(`Agent v2 ${agentId} does not expose a backing app ID.`)
|
|
|
|
const appDetail = await setAppSiteEnabled(appId, enabled)
|
|
const token = agent.site?.access_token ?? agent.site?.code ?? appDetail.site.access_token
|
|
const baseURL = agent.site?.app_base_url ?? appDetail.site.app_base_url
|
|
|
|
return `${baseURL.replace(/\/$/, '')}/agent/${token}`
|
|
}
|
|
|
|
export async function setAgentApiAccess(
|
|
agentId: string,
|
|
enabled: boolean,
|
|
): Promise<AgentApiAccessResponse> {
|
|
const ctx = await createApiContext()
|
|
try {
|
|
const response = await ctx.post(`/console/api/agent/${agentId}/api-enable`, {
|
|
data: { enable_api: enabled },
|
|
})
|
|
await expectApiResponseOK(
|
|
response,
|
|
`${enabled ? 'Enable' : 'Disable'} Agent v2 API access for ${agentId}`,
|
|
)
|
|
return (await response.json()) as AgentApiAccessResponse
|
|
}
|
|
finally {
|
|
await ctx.dispose()
|
|
}
|
|
}
|
|
|
|
export async function createAgentApiKey(agentId: string): Promise<ApiKeyItem> {
|
|
const ctx = await createApiContext()
|
|
try {
|
|
const response = await ctx.post(`/console/api/agent/${agentId}/api-keys`)
|
|
await expectApiResponseOK(response, `Create Agent v2 API key for ${agentId}`)
|
|
return (await response.json()) as ApiKeyItem
|
|
}
|
|
finally {
|
|
await ctx.dispose()
|
|
}
|
|
}
|
|
|
|
export async function sendAgentServiceApiChatMessage({
|
|
apiKey,
|
|
query = 'Please reply with the test success marker.',
|
|
serviceApiBaseURL,
|
|
}: {
|
|
apiKey: string
|
|
query?: string
|
|
serviceApiBaseURL: string
|
|
}): Promise<AgentServiceApiChatResult> {
|
|
const ctx = await request.newContext()
|
|
const body = {
|
|
inputs: {},
|
|
query,
|
|
response_mode: 'streaming',
|
|
user: 'e2e-agent-access-point',
|
|
} satisfies ChatRequestPayloadWithUser
|
|
|
|
try {
|
|
const response = await ctx.post(`${serviceApiBaseURL.replace(/\/$/, '')}/chat-messages`, {
|
|
data: body,
|
|
headers: {
|
|
Authorization: `Bearer ${apiKey}`,
|
|
},
|
|
})
|
|
const responseBody = await parseServiceApiChatResponse(response)
|
|
|
|
return {
|
|
body: responseBody as PostChatMessagesResponse | unknown,
|
|
ok: response.ok(),
|
|
status: response.status(),
|
|
}
|
|
}
|
|
finally {
|
|
await ctx.dispose()
|
|
}
|
|
}
|