UNPKG

dify-ai-provider

Version:
404 lines (397 loc) 13.9 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { createDifyProvider: () => createDifyProvider, difyProvider: () => difyProvider }); module.exports = __toCommonJS(index_exports); // src/dify-provider.ts var import_provider_utils2 = require("@ai-sdk/provider-utils"); // src/dify-chat-language-model.ts var import_provider = require("@ai-sdk/provider"); var import_provider_utils = require("@ai-sdk/provider-utils"); // src/dify-chat-schema.ts var import_zod = require("zod"); var completionResponseSchema = import_zod.z.object({ id: import_zod.z.string(), answer: import_zod.z.string(), task_id: import_zod.z.string(), conversation_id: import_zod.z.string(), message_id: import_zod.z.string(), metadata: import_zod.z.object({ usage: import_zod.z.object({ completion_tokens: import_zod.z.number(), prompt_tokens: import_zod.z.number(), total_tokens: import_zod.z.number() }) }) }); var errorResponseSchema = import_zod.z.object({ code: import_zod.z.string(), message: import_zod.z.string(), status: import_zod.z.number() }); var difyStreamEventBase = import_zod.z.object({ event: import_zod.z.string(), conversation_id: import_zod.z.string().optional(), message_id: import_zod.z.string().optional(), task_id: import_zod.z.string().optional(), created_at: import_zod.z.number().optional() }).passthrough(); var workflowStartedSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("workflow_started"), workflow_run_id: import_zod.z.string(), data: import_zod.z.object({ id: import_zod.z.string(), workflow_id: import_zod.z.string(), created_at: import_zod.z.number() }).passthrough() }); var workflowFinishedSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("workflow_finished"), workflow_run_id: import_zod.z.string(), data: import_zod.z.object({ id: import_zod.z.string(), workflow_id: import_zod.z.string(), total_tokens: import_zod.z.number().optional(), created_at: import_zod.z.number() }).passthrough() }); var nodeStartedSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("node_started"), workflow_run_id: import_zod.z.string(), data: import_zod.z.object({ id: import_zod.z.string(), node_id: import_zod.z.string(), node_type: import_zod.z.string() }).passthrough() }); var nodeFinishedSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("node_finished"), workflow_run_id: import_zod.z.string(), data: import_zod.z.object({ id: import_zod.z.string(), node_id: import_zod.z.string(), node_type: import_zod.z.string() }).passthrough() }); var messageSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("message"), id: import_zod.z.string().optional(), answer: import_zod.z.string(), from_variable_selector: import_zod.z.array(import_zod.z.string()).optional() }); var messageEndSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("message_end"), id: import_zod.z.string(), metadata: import_zod.z.object({ usage: import_zod.z.object({ prompt_tokens: import_zod.z.number(), completion_tokens: import_zod.z.number(), total_tokens: import_zod.z.number() }).passthrough() }).passthrough(), files: import_zod.z.array(import_zod.z.unknown()).optional() }); var ttsMessageSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("tts_message"), audio: import_zod.z.string() }); var ttsMessageEndSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("tts_message_end"), audio: import_zod.z.string() }); var agentMessageSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("agent_message"), answer: import_zod.z.string() }); var agentThoughtSchema = difyStreamEventBase.extend({ event: import_zod.z.literal("agent_thought"), thought: import_zod.z.string(), observation: import_zod.z.string(), tool: import_zod.z.string(), tool_labels: import_zod.z.record(import_zod.z.string(), import_zod.z.string()), tool_input: import_zod.z.string(), message_files: import_zod.z.array(import_zod.z.unknown()) }); var difyStreamEventSchema = import_zod.z.discriminatedUnion("event", [ workflowStartedSchema, workflowFinishedSchema, nodeStartedSchema, nodeFinishedSchema, messageSchema, messageEndSchema, ttsMessageSchema, ttsMessageEndSchema, agentThoughtSchema, agentMessageSchema ]).or(difyStreamEventBase); // src/dify-chat-language-model.ts var difyFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponseHandler)({ errorSchema: errorResponseSchema, errorToMessage: (data) => { console.log("Dify API error:", data); return `Dify API error: ${data.message}`; } }); var DifyChatLanguageModel = class { constructor(modelId, settings, config) { this.settings = settings; this.specificationVersion = "v1"; this.defaultObjectGenerationMode = void 0; this.modelId = modelId; this.config = config; this.generateId = import_provider_utils.generateId; this.chatMessagesEndpoint = `${this.config.baseURL}/chat-messages`; if (!this.settings.responseMode) { this.settings.responseMode = "streaming"; } } get provider() { return this.config.provider; } async doGenerate(options) { var _a, _b, _c, _d; const { abortSignal } = options; const requestBody = this.getRequestBody(options); const { responseHeaders, value: data } = await (0, import_provider_utils.postJsonToApi)({ url: this.chatMessagesEndpoint, headers: (0, import_provider_utils.combineHeaders)(this.config.headers(), options.headers), body: requestBody, abortSignal, failedResponseHandler: difyFailedResponseHandler, successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)( completionResponseSchema ), fetch: this.config.fetch }); return { text: data.answer, toolCalls: [], // Dify doesn't currently support tool calls finishReason: "stop", // Dify doesn't specify finish reason usage: { promptTokens: ((_b = (_a = data.metadata) == null ? void 0 : _a.usage) == null ? void 0 : _b.prompt_tokens) || 0, completionTokens: ((_d = (_c = data.metadata) == null ? void 0 : _c.usage) == null ? void 0 : _d.completion_tokens) || 0 }, rawCall: this.createRawCall(options), providerMetadata: { difyWorkflowData: { conversationId: data.conversation_id, messageId: data.message_id } }, rawResponse: { headers: responseHeaders, body: data }, request: { body: JSON.stringify(requestBody) }, response: { id: data.id, timestamp: /* @__PURE__ */ new Date() } }; } async doStream(options) { const { abortSignal } = options; const requestBody = this.getRequestBody(options); const body = { ...requestBody, response_mode: "streaming" }; const { responseHeaders, value: responseStream } = await (0, import_provider_utils.postJsonToApi)({ url: this.chatMessagesEndpoint, headers: (0, import_provider_utils.combineHeaders)(this.config.headers(), options.headers), body, failedResponseHandler: difyFailedResponseHandler, successfulResponseHandler: (0, import_provider_utils.createEventSourceResponseHandler)( difyStreamEventSchema ), abortSignal, fetch: this.config.fetch }); let conversationId; let messageId; let taskId; return { stream: responseStream.pipeThrough( new TransformStream({ transform(chunk, controller) { if (!chunk.success) { controller.enqueue({ type: "error", error: chunk.error }); return; } const data = chunk.value; if (data.conversation_id) conversationId = data.conversation_id; if (data.message_id) messageId = data.message_id; if (data.task_id) taskId = data.task_id; switch (data.event) { case "workflow_finished": case "message_end": { let totalTokens = 0; if ("data" in data && data.data && typeof data.data === "object" && "total_tokens" in data.data && typeof data.data.total_tokens === "number") { totalTokens = data.data.total_tokens; } controller.enqueue({ type: "finish", finishReason: "stop", providerMetadata: { difyWorkflowData: { conversationId, messageId, taskId } }, usage: { promptTokens: 0, completionTokens: totalTokens } }); break; } case "message": case "agent_message": { if ("answer" in data && typeof data.answer === "string") { controller.enqueue({ type: "text-delta", textDelta: data.answer }); if ("id" in data && typeof data.id === "string") { controller.enqueue({ type: "response-metadata", id: data.id }); } } break; } } } }) ), rawCall: this.createRawCall(options), rawResponse: { headers: responseHeaders }, request: { body: JSON.stringify(body) } }; } /** * Get the request body for the Dify API */ getRequestBody(options) { var _a, _b, _c; const messages = options.messages || options.prompt; if (!messages || !messages.length) { throw new import_provider.APICallError({ message: "No messages provided", url: this.chatMessagesEndpoint, requestBodyValues: options }); } const latestMessage = messages[messages.length - 1]; if (latestMessage.role !== "user") { throw new import_provider.APICallError({ message: "The last message must be a user message", url: this.chatMessagesEndpoint, requestBodyValues: { latestMessageRole: latestMessage.role } }); } const hasAttachments = Array.isArray(latestMessage.content) && latestMessage.content.some((part) => { return typeof part !== "string" && part.type === "image"; }); if (hasAttachments) { throw new import_provider.APICallError({ message: "Dify provider does not currently support image attachments", url: this.chatMessagesEndpoint, requestBodyValues: { hasAttachments: true } }); } let query = ""; if (typeof latestMessage.content === "string") { query = latestMessage.content; } else if (Array.isArray(latestMessage.content)) { query = latestMessage.content.map((part) => { if (typeof part === "string") { return part; } else if (part.type === "text") { return part.text; } return ""; }).filter(Boolean).join(" "); } const conversationId = (_a = options.headers) == null ? void 0 : _a["chat-id"]; const userId = (_c = (_b = options.headers) == null ? void 0 : _b["user-id"]) != null ? _c : "you_should_pass_user-id"; const { "chat-id": _, "user-id": __, ...cleanHeaders } = options.headers || {}; options.headers = cleanHeaders; return { inputs: this.settings.inputs || {}, query, response_mode: this.settings.responseMode, conversation_id: conversationId, user: userId }; } /** * Create the rawCall object for response */ createRawCall(options) { return { rawPrompt: options.messages || options.prompt, rawSettings: { ...this.settings } }; } supportsUrl(url) { return false; } }; // src/dify-provider.ts function createDifyProvider(options = {}) { const createChatModel = (modelId, settings = {}) => new DifyChatLanguageModel(modelId, settings, { provider: "dify.chat", baseURL: options.baseURL || "https://api.dify.ai/v1", headers: () => ({ Authorization: `Bearer ${(0, import_provider_utils2.loadApiKey)({ apiKey: settings.apiKey, environmentVariableName: "DIFY_API_KEY", description: "Dify API Key" })}`, "Content-Type": "application/json", ...options.headers }) }); const provider = function(modelId, settings) { if (new.target) { throw new Error( "The model factory function cannot be called with the new keyword." ); } return createChatModel(modelId, settings); }; provider.chat = createChatModel; return provider; } var difyProvider = createDifyProvider(); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createDifyProvider, difyProvider });