UNPKG

@dpml/agent

Version:

Agent implementation for DPML

1,309 lines (1,281 loc) 41.7 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // ../../node_modules/.pnpm/tsup@8.4.0_@swc+core@1.11.24_postcss@8.5.3_typescript@5.8.2_yaml@2.7.1/node_modules/tsup/assets/cjs_shims.js var init_cjs_shims = __esm({ "../../node_modules/.pnpm/tsup@8.4.0_@swc+core@1.11.24_postcss@8.5.3_typescript@5.8.2_yaml@2.7.1/node_modules/tsup/assets/cjs_shims.js"() { "use strict"; } }); // ../../node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv/package.json var require_package = __commonJS({ "../../node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv/package.json"(exports2, module2) { module2.exports = { name: "dotenv", version: "16.5.0", description: "Loads environment variables from .env file", main: "lib/main.js", types: "lib/main.d.ts", exports: { ".": { types: "./lib/main.d.ts", require: "./lib/main.js", default: "./lib/main.js" }, "./config": "./config.js", "./config.js": "./config.js", "./lib/env-options": "./lib/env-options.js", "./lib/env-options.js": "./lib/env-options.js", "./lib/cli-options": "./lib/cli-options.js", "./lib/cli-options.js": "./lib/cli-options.js", "./package.json": "./package.json" }, scripts: { "dts-check": "tsc --project tests/types/tsconfig.json", lint: "standard", pretest: "npm run lint && npm run dts-check", test: "tap run --allow-empty-coverage --disable-coverage --timeout=60000", "test:coverage": "tap run --show-full-coverage --timeout=60000 --coverage-report=lcov", prerelease: "npm test", release: "standard-version" }, repository: { type: "git", url: "git://github.com/motdotla/dotenv.git" }, homepage: "https://github.com/motdotla/dotenv#readme", funding: "https://dotenvx.com", keywords: [ "dotenv", "env", ".env", "environment", "variables", "config", "settings" ], readmeFilename: "README.md", license: "BSD-2-Clause", devDependencies: { "@types/node": "^18.11.3", decache: "^4.6.2", sinon: "^14.0.1", standard: "^17.0.0", "standard-version": "^9.5.0", tap: "^19.2.0", typescript: "^4.8.4" }, engines: { node: ">=12" }, browser: { fs: false } }; } }); // ../../node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv/lib/main.js var require_main = __commonJS({ "../../node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv/lib/main.js"(exports2, module2) { "use strict"; init_cjs_shims(); var fs2 = require("fs"); var path2 = require("path"); var os = require("os"); var crypto = require("crypto"); var packageJson = require_package(); var version = packageJson.version; var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg; function parse(src) { const obj = {}; let lines = src.toString(); lines = lines.replace(/\r\n?/mg, "\n"); let match; while ((match = LINE.exec(lines)) != null) { const key = match[1]; let value = match[2] || ""; value = value.trim(); const maybeQuote = value[0]; value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2"); if (maybeQuote === '"') { value = value.replace(/\\n/g, "\n"); value = value.replace(/\\r/g, "\r"); } obj[key] = value; } return obj; } __name(parse, "parse"); function _parseVault(options) { const vaultPath = _vaultPath(options); const result = DotenvModule.configDotenv({ path: vaultPath }); if (!result.parsed) { const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`); err.code = "MISSING_DATA"; throw err; } const keys = _dotenvKey(options).split(","); const length = keys.length; let decrypted; for (let i = 0; i < length; i++) { try { const key = keys[i].trim(); const attrs = _instructions(result, key); decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key); break; } catch (error) { if (i + 1 >= length) { throw error; } } } return DotenvModule.parse(decrypted); } __name(_parseVault, "_parseVault"); function _warn(message) { console.log(`[dotenv@${version}][WARN] ${message}`); } __name(_warn, "_warn"); function _debug(message) { console.log(`[dotenv@${version}][DEBUG] ${message}`); } __name(_debug, "_debug"); function _dotenvKey(options) { if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) { return options.DOTENV_KEY; } if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) { return process.env.DOTENV_KEY; } return ""; } __name(_dotenvKey, "_dotenvKey"); function _instructions(result, dotenvKey) { let uri; try { uri = new URL(dotenvKey); } catch (error) { if (error.code === "ERR_INVALID_URL") { const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development"); err.code = "INVALID_DOTENV_KEY"; throw err; } throw error; } const key = uri.password; if (!key) { const err = new Error("INVALID_DOTENV_KEY: Missing key part"); err.code = "INVALID_DOTENV_KEY"; throw err; } const environment = uri.searchParams.get("environment"); if (!environment) { const err = new Error("INVALID_DOTENV_KEY: Missing environment part"); err.code = "INVALID_DOTENV_KEY"; throw err; } const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`; const ciphertext = result.parsed[environmentKey]; if (!ciphertext) { const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`); err.code = "NOT_FOUND_DOTENV_ENVIRONMENT"; throw err; } return { ciphertext, key }; } __name(_instructions, "_instructions"); function _vaultPath(options) { let possibleVaultPath = null; if (options && options.path && options.path.length > 0) { if (Array.isArray(options.path)) { for (const filepath of options.path) { if (fs2.existsSync(filepath)) { possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`; } } } else { possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`; } } else { possibleVaultPath = path2.resolve(process.cwd(), ".env.vault"); } if (fs2.existsSync(possibleVaultPath)) { return possibleVaultPath; } return null; } __name(_vaultPath, "_vaultPath"); function _resolveHome(envPath) { return envPath[0] === "~" ? path2.join(os.homedir(), envPath.slice(1)) : envPath; } __name(_resolveHome, "_resolveHome"); function _configVault(options) { const debug = Boolean(options && options.debug); if (debug) { _debug("Loading env from encrypted .env.vault"); } const parsed = DotenvModule._parseVault(options); let processEnv = process.env; if (options && options.processEnv != null) { processEnv = options.processEnv; } DotenvModule.populate(processEnv, parsed, options); return { parsed }; } __name(_configVault, "_configVault"); function configDotenv(options) { const dotenvPath = path2.resolve(process.cwd(), ".env"); let encoding = "utf8"; const debug = Boolean(options && options.debug); if (options && options.encoding) { encoding = options.encoding; } else { if (debug) { _debug("No encoding is specified. UTF-8 is used by default"); } } let optionPaths = [ dotenvPath ]; if (options && options.path) { if (!Array.isArray(options.path)) { optionPaths = [ _resolveHome(options.path) ]; } else { optionPaths = []; for (const filepath of options.path) { optionPaths.push(_resolveHome(filepath)); } } } let lastError; const parsedAll = {}; for (const path3 of optionPaths) { try { const parsed = DotenvModule.parse(fs2.readFileSync(path3, { encoding })); DotenvModule.populate(parsedAll, parsed, options); } catch (e) { if (debug) { _debug(`Failed to load ${path3} ${e.message}`); } lastError = e; } } let processEnv = process.env; if (options && options.processEnv != null) { processEnv = options.processEnv; } DotenvModule.populate(processEnv, parsedAll, options); if (lastError) { return { parsed: parsedAll, error: lastError }; } else { return { parsed: parsedAll }; } } __name(configDotenv, "configDotenv"); function config(options) { if (_dotenvKey(options).length === 0) { return DotenvModule.configDotenv(options); } const vaultPath = _vaultPath(options); if (!vaultPath) { _warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`); return DotenvModule.configDotenv(options); } return DotenvModule._configVault(options); } __name(config, "config"); function decrypt(encrypted, keyStr) { const key = Buffer.from(keyStr.slice(-64), "hex"); let ciphertext = Buffer.from(encrypted, "base64"); const nonce = ciphertext.subarray(0, 12); const authTag = ciphertext.subarray(-16); ciphertext = ciphertext.subarray(12, -16); try { const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce); aesgcm.setAuthTag(authTag); return `${aesgcm.update(ciphertext)}${aesgcm.final()}`; } catch (error) { const isRange = error instanceof RangeError; const invalidKeyLength = error.message === "Invalid key length"; const decryptionFailed = error.message === "Unsupported state or unable to authenticate data"; if (isRange || invalidKeyLength) { const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)"); err.code = "INVALID_DOTENV_KEY"; throw err; } else if (decryptionFailed) { const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY"); err.code = "DECRYPTION_FAILED"; throw err; } else { throw error; } } } __name(decrypt, "decrypt"); function populate(processEnv, parsed, options = {}) { const debug = Boolean(options && options.debug); const override = Boolean(options && options.override); if (typeof parsed !== "object") { const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate"); err.code = "OBJECT_REQUIRED"; throw err; } for (const key of Object.keys(parsed)) { if (Object.prototype.hasOwnProperty.call(processEnv, key)) { if (override === true) { processEnv[key] = parsed[key]; } if (debug) { if (override === true) { _debug(`"${key}" is already defined and WAS overwritten`); } else { _debug(`"${key}" is already defined and was NOT overwritten`); } } } else { processEnv[key] = parsed[key]; } } } __name(populate, "populate"); var DotenvModule = { configDotenv, _configVault, _parseVault, config, decrypt, parse, populate }; module2.exports.configDotenv = DotenvModule.configDotenv; module2.exports._configVault = DotenvModule._configVault; module2.exports._parseVault = DotenvModule._parseVault; module2.exports.config = DotenvModule.config; module2.exports.decrypt = DotenvModule.decrypt; module2.exports.parse = DotenvModule.parse; module2.exports.populate = DotenvModule.populate; module2.exports = DotenvModule; } }); // src/index.ts var index_exports = {}; __export(index_exports, { AgentError: () => AgentError, AgentErrorType: () => AgentErrorType, agentDPML: () => agentDPML, compiler: () => compiler, createAgent: () => createAgent2 }); module.exports = __toCommonJS(index_exports); init_cjs_shims(); var import_core2 = require("@dpml/core"); // src/config/index.ts init_cjs_shims(); // src/config/schema.ts init_cjs_shims(); var schema = { // 根元素定义 root: { element: "agent", children: { elements: [ { $ref: "llm" }, { $ref: "prompt" }, { $ref: "experimental" } ] } }, // 可复用类型定义 types: [ { // LLM配置元素 element: "llm", attributes: [ { name: "api-type", required: true }, { name: "api-url" }, { name: "api-key" }, { name: "model", required: true } ] }, { // 提示词元素 element: "prompt", content: { type: "text", required: true } }, { // 实验性功能元素 element: "experimental", children: { elements: [ { $ref: "tools" } ] } }, { // 工具集元素 element: "tools", children: { elements: [ { $ref: "tool" } ] } }, { // 工具元素 element: "tool", attributes: [ { name: "name", required: true }, { name: "description", required: true } ] } ] }; // src/config/transformers.ts init_cjs_shims(); var import_core = require("@dpml/core"); var definer = (0, import_core.createTransformerDefiner)(); var agentTransformer = definer.defineStructuralMapper("agentTransformer", [ { // 将LLM元素转换为LLM配置 selector: "agent > llm", targetPath: "llm", transform: /* @__PURE__ */ __name((value) => { const node = value; const llmConfig = { apiType: node.attributes.get("api-type") || "", apiUrl: node.attributes.get("api-url"), apiKey: node.attributes.get("api-key"), model: node.attributes.get("model") || "" }; return llmConfig; }, "transform") }, { // 将prompt元素转换为提示词 selector: "agent > prompt", targetPath: "prompt", transform: /* @__PURE__ */ __name((value) => { const node = value; return node.content || ""; }, "transform") } ]); var transformers = [ agentTransformer ]; // src/config/cli.ts init_cjs_shims(); var import_promises = __toESM(require("fs/promises")); var import_path = __toESM(require("path")); var import_readline = __toESM(require("readline")); var import_dotenv = __toESM(require_main()); // src/api/agent.ts init_cjs_shims(); // src/core/agentService.ts init_cjs_shims(); // src/types/index.ts init_cjs_shims(); // src/types/errors.ts init_cjs_shims(); var AgentErrorType = /* @__PURE__ */ function(AgentErrorType2) { AgentErrorType2["CONFIG"] = "CONFIG"; AgentErrorType2["LLM_SERVICE"] = "LLM_SERVICE"; AgentErrorType2["CONTENT"] = "CONTENT"; AgentErrorType2["SESSION"] = "SESSION"; AgentErrorType2["UNKNOWN"] = "UNKNOWN"; return AgentErrorType2; }({}); var _AgentError = class _AgentError extends Error { /** * 创建Agent错误 * * @param message 错误消息 * @param type 错误类型 * @param code 错误码 * @param cause 原始错误 */ constructor(message, type = "UNKNOWN", code = "AGENT_ERROR", cause) { super(message); /** * 错误类型 */ __publicField(this, "type"); /** * 错误码 */ __publicField(this, "code"); /** * 原始错误 */ __publicField(this, "cause"); this.name = "AgentError"; this.type = type; this.code = code; this.cause = cause; } }; __name(_AgentError, "AgentError"); var AgentError = _AgentError; // src/core/AgentRunner.ts init_cjs_shims(); var _AgentRunner = class _AgentRunner { constructor(config, llmClient, session) { __publicField(this, "config"); __publicField(this, "llmClient"); __publicField(this, "session"); this.config = config; this.llmClient = llmClient; this.session = session; } /** * 发送消息并获取响应 * * @param input 输入内容 * @param stream 是否使用流式响应 * @returns 响应内容或流式响应迭代器 */ sendMessage(input, stream) { const userMessage = { role: "user", content: input.content }; this.session.addMessage(userMessage); const messages = this.prepareMessages(); return this.llmClient.sendMessages(messages, stream); } /** * 准备发送给LLM的消息列表 * * @returns 按照正确顺序排列的消息列表 */ prepareMessages() { const messages = []; if (this.config.prompt) { messages.push({ role: "system", content: { type: "text", value: this.config.prompt } }); } const historyMessages = this.session.getMessages(); if (historyMessages.length > 0) { messages.push(...historyMessages); } return messages; } }; __name(_AgentRunner, "AgentRunner"); var AgentRunner = _AgentRunner; // src/core/llm/llmFactory.ts init_cjs_shims(); // src/core/llm/AnthropicClient.ts init_cjs_shims(); var _AnthropicClient = class _AnthropicClient { constructor(config) { __publicField(this, "apiKey"); __publicField(this, "apiUrl"); __publicField(this, "model"); this.apiKey = config.apiKey || ""; this.apiUrl = config.apiUrl || "https://api.anthropic.com/v1"; this.model = config.model; if (!this.apiKey) { throw new AgentError("Anthropic API\u5BC6\u94A5\u672A\u63D0\u4F9B", AgentErrorType.CONFIG, "MISSING_API_KEY"); } } async sendMessages(messages, stream) { try { const anthropicMessages = this.convertToAnthropicMessages(messages); if (stream) { return this.streamMessages(anthropicMessages); } else { return this.sendMessagesSync(anthropicMessages); } } catch (error) { throw new AgentError(`LLM\u670D\u52A1\u8C03\u7528\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, AgentErrorType.LLM_SERVICE, "LLM_API_ERROR", error instanceof Error ? error : new Error(String(error))); } } async sendMessagesSync(anthropicMessages) { const requestBody = { model: this.model, messages: anthropicMessages.messages, max_tokens: 1024, stream: false }; const response = await fetch(`${this.apiUrl}/messages`, { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": this.apiKey, "anthropic-version": "2023-06-01" }, body: JSON.stringify(requestBody) }); if (!response.ok) { const errorData = await response.text(); throw new Error(`Anthropic API\u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText} - ${errorData}`); } const data = await response.json(); const content = data.content?.[0]?.text; if (!content) { throw new Error("Anthropic\u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u6CA1\u6709\u627E\u5230\u5185\u5BB9"); } return { content: { type: "text", value: content } }; } async *streamMessages(anthropicMessages) { const requestBody = { model: this.model, messages: anthropicMessages.messages, max_tokens: 1024, stream: true }; const response = await fetch(`${this.apiUrl}/messages`, { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": this.apiKey, "anthropic-version": "2023-06-01" }, body: JSON.stringify(requestBody) }); if (!response.ok) { const errorData = await response.text(); throw new Error(`Anthropic API\u6D41\u5F0F\u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText} - ${errorData}`); } if (!response.body) { throw new Error("Anthropic API\u6D41\u5F0F\u54CD\u5E94\u6CA1\u6709\u54CD\u5E94\u4F53"); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; try { while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { if (line.startsWith("data: ") && line !== "data: [DONE]") { const jsonData = line.substring(6); try { const data = JSON.parse(jsonData); if (data.type === "content_block_delta" && data.delta?.text) { yield { content: { type: "text", value: data.delta.text } }; } } catch (e) { console.error("\u89E3\u6790SSE\u4E8B\u4EF6\u5931\u8D25:", e); } } } } } finally { reader.releaseLock(); } } convertToAnthropicMessages(messages) { const systemMessage = messages.find((msg) => msg.role === "system"); const userAssistantMessages = messages.filter((msg) => msg.role !== "system").map((msg) => ({ role: msg.role, content: this.convertContent(msg.content) })); return { system: systemMessage ? this.extractTextContent(systemMessage.content) : "", messages: userAssistantMessages }; } convertContent(content) { if (Array.isArray(content)) { return content.filter((item) => item.type === "text").map((item) => item.value).join("\n"); } else if (content.type === "text") { return content.value; } return `[\u4E0D\u652F\u6301\u7684\u5185\u5BB9\u7C7B\u578B: ${Array.isArray(content) ? "\u591A\u6A21\u6001\u5185\u5BB9" : content.type}]`; } extractTextContent(content) { if (Array.isArray(content)) { return content.filter((item) => item.type === "text").map((item) => item.value).join("\n"); } else if (content.type === "text") { return content.value; } return ""; } }; __name(_AnthropicClient, "AnthropicClient"); var AnthropicClient = _AnthropicClient; // src/core/llm/OpenAIClient.ts init_cjs_shims(); var _OpenAIClient = class _OpenAIClient { constructor(config) { __publicField(this, "apiKey"); __publicField(this, "apiUrl"); __publicField(this, "model"); this.apiKey = config.apiKey || ""; this.apiUrl = config.apiUrl || "https://api.openai.com/v1"; this.model = config.model; if (!this.apiKey) { throw new AgentError("OpenAI API\u5BC6\u94A5\u672A\u63D0\u4F9B", AgentErrorType.CONFIG, "MISSING_API_KEY"); } } async sendMessages(messages, stream) { try { const openaiMessages = this.convertToOpenAIMessages(messages); if (stream) { return this.streamMessages(openaiMessages); } else { return this.sendMessagesSync(openaiMessages); } } catch (error) { if (error instanceof AgentError) { throw error; } throw new AgentError(`LLM\u670D\u52A1\u8C03\u7528\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, AgentErrorType.LLM_SERVICE, "LLM_API_ERROR", error instanceof Error ? error : new Error(String(error))); } } async sendMessagesSync(openaiMessages) { try { const requestBody = { model: this.model, messages: openaiMessages, stream: false }; const response = await fetch(`${this.apiUrl}/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${this.apiKey}` }, body: JSON.stringify(requestBody) }); if (!response.ok) { const errorData = await response.text(); throw new AgentError(`OpenAI API\u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText} - ${errorData}`, AgentErrorType.LLM_SERVICE, "LLM_API_ERROR"); } const data = await response.json(); const content = data.choices[0]?.message?.content; if (!content) { throw new AgentError("OpenAI\u54CD\u5E94\u683C\u5F0F\u65E0\u6548\uFF0C\u6CA1\u6709\u627E\u5230\u5185\u5BB9", AgentErrorType.LLM_SERVICE, "INVALID_RESPONSE_FORMAT"); } return { content: { type: "text", value: content } }; } catch (error) { if (error instanceof AgentError) { throw error; } throw new AgentError(`LLM\u670D\u52A1\u8C03\u7528\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, AgentErrorType.LLM_SERVICE, "LLM_API_ERROR", error instanceof Error ? error : new Error(String(error))); } } async *streamMessages(openaiMessages) { try { const requestBody = { model: this.model, messages: openaiMessages, stream: true }; const response = await fetch(`${this.apiUrl}/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${this.apiKey}` }, body: JSON.stringify(requestBody) }); if (!response.ok) { const errorData = await response.text(); throw new AgentError(`OpenAI API\u6D41\u5F0F\u8BF7\u6C42\u5931\u8D25: ${response.status} ${response.statusText} - ${errorData}`, AgentErrorType.LLM_SERVICE, "LLM_API_ERROR"); } if (!response.body) { throw new AgentError("OpenAI API\u6D41\u5F0F\u54CD\u5E94\u6CA1\u6709\u54CD\u5E94\u4F53", AgentErrorType.LLM_SERVICE, "MISSING_RESPONSE_BODY"); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; try { while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { if (line.startsWith("data: ") && line !== "data: [DONE]") { const jsonData = line.substring(6); try { const data = JSON.parse(jsonData); const content = data.choices[0]?.delta?.content; if (content) { yield { content: { type: "text", value: content } }; } } catch (e) { console.error("\u89E3\u6790SSE\u4E8B\u4EF6\u5931\u8D25:", e); throw new AgentError(`\u89E3\u6790SSE\u4E8B\u4EF6\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`, AgentErrorType.LLM_SERVICE, "SSE_PARSING_ERROR", e instanceof Error ? e : new Error(String(e))); } } } } } finally { reader.releaseLock(); } } catch (error) { if (error instanceof AgentError) { throw error; } throw new AgentError(`LLM\u670D\u52A1\u8C03\u7528\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, AgentErrorType.LLM_SERVICE, "LLM_API_ERROR", error instanceof Error ? error : new Error(String(error))); } } convertToOpenAIMessages(messages) { return messages.map((msg) => { return { role: msg.role, content: this.convertContent(msg.content) }; }); } convertContent(content) { if (Array.isArray(content)) { return content.map((item) => this.convertContentItem(item)); } return this.convertContentItem(content); } convertContentItem(item) { switch (item.type) { case "text": return item.value; case "image": return { type: "image_url", image_url: { url: `data:${item.mimeType || "image/jpeg"};base64,${this.arrayBufferToBase64(item.value)}` } }; case "audio": case "video": case "file": default: return `[\u4E0D\u652F\u6301\u7684\u5185\u5BB9\u7C7B\u578B: ${item.type}]`; } } arrayBufferToBase64(buffer) { if (typeof Buffer !== "undefined") { return Buffer.from(buffer).toString("base64"); } else { let binary = ""; const len = buffer.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(buffer[i]); } return btoa(binary); } } }; __name(_OpenAIClient, "OpenAIClient"); var OpenAIClient = _OpenAIClient; // src/core/llm/llmFactory.ts function validateConfig(config) { if (!config.model) { throw new AgentError("\u7F3A\u5C11\u5FC5\u8981\u7684\u6A21\u578B\u540D\u79F0\u53C2\u6570", AgentErrorType.CONFIG, "MISSING_MODEL_NAME"); } if (config.apiType.toLowerCase() === "openai" && !config.apiKey) { throw new AgentError("OpenAI API\u5BC6\u94A5\u672A\u63D0\u4F9B", AgentErrorType.CONFIG, "MISSING_API_KEY"); } if (config.apiType.toLowerCase() === "anthropic" && !config.apiKey) { throw new AgentError("Anthropic API\u5BC6\u94A5\u672A\u63D0\u4F9B", AgentErrorType.CONFIG, "MISSING_API_KEY"); } } __name(validateConfig, "validateConfig"); function createClient(config) { validateConfig(config); switch (config.apiType.toLowerCase()) { case "openai": return new OpenAIClient(config); case "anthropic": return new AnthropicClient(config); default: throw new AgentError(`\u4E0D\u652F\u6301\u7684API\u7C7B\u578B: ${config.apiType}`, AgentErrorType.CONFIG, "UNSUPPORTED_LLM_TYPE"); } } __name(createClient, "createClient"); // src/core/session/InMemoryAgentSession.ts init_cjs_shims(); var _InMemoryAgentSession = class _InMemoryAgentSession { constructor(capacity = 100) { __publicField(this, "messages", []); __publicField(this, "capacity"); this.capacity = capacity; } addMessage(message) { this.messages.push(message); if (this.messages.length > this.capacity) { this.messages.shift(); } } getMessages() { return [ ...this.messages ]; } }; __name(_InMemoryAgentSession, "InMemoryAgentSession"); var InMemoryAgentSession = _InMemoryAgentSession; // src/core/agentService.ts function createAgent(config) { const llmClient = createClient(config.llm); const session = new InMemoryAgentSession(); const runner = new AgentRunner(config, llmClient, session); return { chat: /* @__PURE__ */ __name((input) => handleChat(runner, input), "chat"), chatStream: /* @__PURE__ */ __name((input) => handleChatStream(runner, input), "chatStream") }; } __name(createAgent, "createAgent"); async function handleChat(runner, input) { try { const chatInput = normalizeChatInput(input); const response = await runner.sendMessage(chatInput, false); if (Symbol.asyncIterator in response) { throw new AgentError("\u610F\u5916\u6536\u5230\u6D41\u5F0F\u54CD\u5E94", AgentErrorType.UNKNOWN, "UNEXPECTED_STREAM_RESPONSE"); } return extractTextFromContent(response.content); } catch (error) { if (error instanceof AgentError) { throw error; } throw new AgentError(`\u804A\u5929\u8BF7\u6C42\u5904\u7406\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, AgentErrorType.UNKNOWN, "CHAT_PROCESSING_ERROR", error instanceof Error ? error : new Error(String(error))); } } __name(handleChat, "handleChat"); async function* handleChatStream(runner, input) { const chatInput = normalizeChatInput(input); try { const responseStream = await runner.sendMessage(chatInput, true); if (!(Symbol.asyncIterator in responseStream)) { yield extractTextFromContent(responseStream.content); return; } for await (const chunk of responseStream) { const textContent = extractTextFromContent(chunk.content); if (textContent) { yield textContent; } } } catch (error) { if (error instanceof AgentError) { throw error; } throw new AgentError(`\u6D41\u5F0F\u804A\u5929\u8BF7\u6C42\u5904\u7406\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, AgentErrorType.UNKNOWN, "STREAM_PROCESSING_ERROR", error instanceof Error ? error : new Error(String(error))); } } __name(handleChatStream, "handleChatStream"); function normalizeChatInput(input) { if (typeof input === "string") { return { content: { type: "text", value: input } }; } return input; } __name(normalizeChatInput, "normalizeChatInput"); function extractTextFromContent(content) { if (Array.isArray(content)) { const textItem = content.find((item) => item.type === "text"); return textItem ? textItem.value : ""; } else if (content.type === "text") { return content.value; } return ""; } __name(extractTextFromContent, "extractTextFromContent"); // src/api/agent.ts function createAgent2(config) { return createAgent(config); } __name(createAgent2, "createAgent"); // src/api/agentenv.ts init_cjs_shims(); // src/core/agentenv/agentenvCore.ts init_cjs_shims(); // src/core/agentenv/constants.ts init_cjs_shims(); var ENV_VAR_PATTERN = /@agentenv:([A-Z0-9_]+)/g; // src/core/agentenv/agentenvCore.ts function replaceEnvVars(value) { if (value === null || value === void 0) { return value; } if (typeof value === "string") { return replaceInString(value); } if (Array.isArray(value)) { return value.map((item) => replaceEnvVars(item)); } if (typeof value === "object") { const result = {}; for (const key in value) { result[key] = replaceEnvVars(value[key]); } return result; } return value; } __name(replaceEnvVars, "replaceEnvVars"); function replaceInString(value) { return value.replace(ENV_VAR_PATTERN, (_match, envName) => { const envValue = process.env[envName]; if (envValue === void 0) { console.warn(`\u8B66\u544A: \u73AF\u5883\u53D8\u91CF ${envName} \u672A\u5B9A\u4E49`); return _match; } return envValue; }); } __name(replaceInString, "replaceInString"); // src/api/agentenv.ts function replaceEnvVars2(value) { return replaceEnvVars(value); } __name(replaceEnvVars2, "replaceEnvVars"); // src/config/cli.ts function loadEnvironmentVariables(options) { if (options.envFile) { const envPath = import_path.default.resolve(process.cwd(), options.envFile); import_dotenv.default.config({ path: envPath }); } if (options.env) { for (const envVar of options.env) { const [key, value] = envVar.split("="); if (key && value) { process.env[key] = value; } } } } __name(loadEnvironmentVariables, "loadEnvironmentVariables"); async function handleRegularChat(agent, input) { try { const response = await agent.chat(input); console.log("\n" + response + "\n"); } catch (error) { console.error("\u9519\u8BEF:", error instanceof Error ? error.message : String(error)); } } __name(handleRegularChat, "handleRegularChat"); async function handleStreamChat(agent, input) { try { process.stdout.write("\n"); for await (const chunk of agent.chatStream(input)) { process.stdout.write(chunk); } process.stdout.write("\n\n"); } catch (error) { console.error("\n\u9519\u8BEF:", error instanceof Error ? error.message : String(error)); } } __name(handleStreamChat, "handleStreamChat"); async function executeChat(actionContext, filePath, options) { try { loadEnvironmentVariables(options); console.log("\nDPML Agent Chat"); console.log(`\u52A0\u8F7DAgent\u914D\u7F6E: ${filePath} `); const content = await import_promises.default.readFile(filePath, "utf-8"); const config = await actionContext.getCompiler().compile(content); const processedConfig = replaceEnvVars2(config); const agent = createAgent2(processedConfig); const rl = import_readline.default.createInterface({ input: process.stdin, output: process.stdout }); console.log("\u4F60\u597D\uFF0C\u6211\u662FAI\u52A9\u624B\u3002\u6709\u4EC0\u4E48\u6211\u53EF\u4EE5\u5E2E\u4F60\u7684\uFF1F"); const useStream = options.stream !== false; const askQuestion = /* @__PURE__ */ __name(() => { rl.question("> ", async (input) => { if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit" || input.toLowerCase() === "bye") { console.log("\u4F1A\u8BDD\u7ED3\u675F\u3002"); rl.close(); return; } if (useStream) { await handleStreamChat(agent, input); } else { await handleRegularChat(agent, input); } askQuestion(); }); }, "askQuestion"); askQuestion(); } catch (error) { console.error("\u9519\u8BEF:", error instanceof Error ? error.message : String(error)); process.exit(1); } } __name(executeChat, "executeChat"); var commandsConfig = { // 包含标准validate命令 includeStandard: true, // 自定义命令 actions: [ { name: "chat", description: "\u542F\u52A8\u4E0EAgent\u7684\u4EA4\u4E92\u5F0F\u804A\u5929", args: [ { name: "filePath", description: "Agent\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84", required: true } ], options: [ { flags: "-e, --env <KEY=VALUE...>", description: "\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF" }, { flags: "-f, --env-file <path>", description: "\u6307\u5B9A\u73AF\u5883\u53D8\u91CF\u6587\u4EF6\u8DEF\u5F84" }, { flags: "-d, --debug", description: "\u542F\u7528\u8C03\u8BD5\u6A21\u5F0F" }, { flags: "-s, --stream", description: "\u542F\u7528\u6D41\u5F0F\u8F93\u51FA\u6A21\u5F0F\uFF08\u9ED8\u8BA4\u5F00\u542F\uFF09", defaultValue: true } ], action: executeChat } ] }; // src/api/index.ts init_cjs_shims(); // src/index.ts var agentDPML = (0, import_core2.createDomainDPML)({ domain: "agent", description: "AI Agent Domain", schema, transformers, commands: commandsConfig, options: { strictMode: true, errorHandling: "throw" } }); var compiler = agentDPML.compiler; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { AgentError, AgentErrorType, agentDPML, compiler, createAgent }); //# sourceMappingURL=index.js.map