@dpml/agent
Version:
Agent implementation for DPML
1,309 lines (1,281 loc) • 41.7 kB
JavaScript
;
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