diff --git a/README.md b/README.md index 23aa137..c292001 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,14 @@ AgentRun SDK 是阿里云 AgentRun 服务的 Node.js 客户端库,为 AI Agent - 📜 **Credential**: 安全的凭证管理 - 🔧 **Model**: 模型服务和代理管理 - 📦 **Sandbox**: 代码解释器和浏览器沙箱 +- 🧰 **ToolSet**: OpenAPI / MCP 工具集管理 - 🌐 **Server**: OpenAI 兼容的 HTTP 服务器 - 🔌 **Integration**: Mastra 框架集成 ## 安装 ```bash -npm install @alicloud/agentrun-sdk +npm install @agentrun/sdk ``` ## 快速开始 @@ -24,13 +25,13 @@ npm install @alicloud/agentrun-sdk SDK 支持从环境变量或代码中配置: ```typescript -import { Config } from '@alicloud/agentrun-sdk'; +import { Config } from '@agentrun/sdk'; // 从环境变量读取配置 -// AGENTRUN_ACCESS_KEY_ID -// AGENTRUN_ACCESS_KEY_SECRET -// AGENTRUN_ACCOUNT_ID -// AGENTRUN_REGION (默认: cn-hangzhou) +// AGENTRUN_ACCESS_KEY_ID (回退到 ALIBABA_CLOUD_ACCESS_KEY_ID) +// AGENTRUN_ACCESS_KEY_SECRET (回退到 ALIBABA_CLOUD_ACCESS_KEY_SECRET) +// AGENTRUN_ACCOUNT_ID (回退到 FC_ACCOUNT_ID) +// AGENTRUN_REGION (回退到 FC_REGION,默认 cn-hangzhou) const config = new Config(); // 或者直接传入配置 @@ -45,27 +46,36 @@ const config = new Config({ ### Agent Runtime ```typescript -import { AgentRuntime, AgentRuntimeLanguage } from '@alicloud/agentrun-sdk'; +import { + AgentRuntime, + AgentRuntimeLanguage, + codeFromFile, +} from '@agentrun/sdk'; // 创建 Agent Runtime const runtime = await AgentRuntime.create({ - agentRuntimeName: 'my-agent', - codeConfiguration: { - language: AgentRuntimeLanguage.NODEJS18, - command: ['node', 'index.js'], - zipFile: 'base64-encoded-zip', + input: { + agentRuntimeName: 'my-agent', + codeConfiguration: await codeFromFile( + AgentRuntimeLanguage.NODEJS18, + ['node', 'index.js'], + './my-agent-code' + ), + port: 9000, + cpu: 2, + memory: 4096, }, }); -// 等待就绪 -await runtime.waitUntilReady(); +// 等待就绪 (READY 或 *_FAILED) +await runtime.waitUntilReadyOrFailed(); // 创建端点 const endpoint = await runtime.createEndpoint({ - agentRuntimeEndpointName: 'default', + input: { agentRuntimeEndpointName: 'default' }, }); -await endpoint.waitUntilReady(); +await endpoint.waitUntilReadyOrFailed(); console.log('Endpoint URL:', endpoint.endpointPublicUrl); // 删除 @@ -75,26 +85,31 @@ await runtime.delete(); ### Sandbox ```typescript -import { SandboxClient, TemplateType } from '@alicloud/agentrun-sdk'; +import { SandboxClient, Template, TemplateType } from '@agentrun/sdk'; const client = new SandboxClient(); // 创建模板 -const template = await client.createTemplate({ - templateName: 'my-template', - templateType: TemplateType.CODE_INTERPRETER, +const template = await Template.create({ + input: { + templateName: 'my-template', + templateType: TemplateType.CODE_INTERPRETER, + }, }); -await template.waitUntilReady(); +await template.waitUntilReadyOrFailed(); // 创建沙箱 -const sandbox = await client.createCodeInterpreterSandbox( - template.templateName! -); +const sandbox = await client.createCodeInterpreterSandbox({ + templateName: template.templateName!, +}); await sandbox.waitUntilRunning(); +await sandbox.waitUntilReadyOrFailed(); -// 执行代码 (需要数据 API 支持) -// const result = await sandbox.executeCode('print("Hello!")'); +// 执行代码 +const ctx = await sandbox.context.create(); +const result = await ctx.execute({ code: "print('Hello!')" }); +console.log(result); // 删除 await sandbox.delete(); @@ -109,15 +124,15 @@ await template.delete(); | **Credential** | 凭证管理 | | **Model** | 模型服务和代理管理 | | **Sandbox** | 沙箱环境管理 (代码解释器、浏览器) | +| **ToolSet** | OpenAPI / MCP 工具集管理 | +| **Server** | OpenAI 兼容的 HTTP 服务器 | +| **Integration** | Mastra 等第三方框架集成 | ## 示例 -运行示例: +`examples/` 目录下提供了各模块的端到端示例: ```bash -# 快速开始 - 启动 Agent 服务器 -npm run example:quick-start - # Agent Runtime 示例 npm run example:agent-runtime @@ -128,6 +143,14 @@ npm run example:credential npm run example:sandbox ``` +其他可直接运行的示例(用 `npx tsx` 启动): + +```bash +npx tsx examples/model.ts +npx tsx examples/toolset.ts +npx tsx examples/mastra.ts +``` + ## 开发 ```bash @@ -156,13 +179,18 @@ npm run format:fix # 同时运行格式化和lint修复 ## 环境变量 -| 变量 | 描述 | 默认值 | -| ---------------------------- | ------------------------ | ------------- | -| `AGENTRUN_ACCESS_KEY_ID` | 阿里云 Access Key ID | - | -| `AGENTRUN_ACCESS_KEY_SECRET` | 阿里云 Access Key Secret | - | -| `AGENTRUN_ACCOUNT_ID` | 阿里云账号 ID | - | -| `AGENTRUN_REGION` | 区域 ID | `cn-hangzhou` | -| `AGENTRUN_TIMEOUT` | API 超时时间 (毫秒) | `600000` | +| 变量 | 描述 | 默认值 | +| ---------------------------- | -------------------------------------------------------------------- | ------------- | +| `AGENTRUN_ACCESS_KEY_ID` | 阿里云 Access Key ID(回退到 `ALIBABA_CLOUD_ACCESS_KEY_ID`) | - | +| `AGENTRUN_ACCESS_KEY_SECRET` | 阿里云 Access Key Secret(回退到 `ALIBABA_CLOUD_ACCESS_KEY_SECRET`) | - | +| `AGENTRUN_SECURITY_TOKEN` | STS 临时安全令牌(回退到 `ALIBABA_CLOUD_SECURITY_TOKEN`) | - | +| `AGENTRUN_ACCOUNT_ID` | 阿里云账号 ID(回退到 `FC_ACCOUNT_ID`) | - | +| `AGENTRUN_REGION` | 区域 ID(回退到 `FC_REGION`) | `cn-hangzhou` | +| `AGENTRUN_CONTROL_ENDPOINT` | 自定义控制面 API 端点 | 区域默认值 | +| `AGENTRUN_DATA_ENDPOINT` | 自定义数据面 API 端点 | 区域默认值 | +| `DEVS_ENDPOINT` | 自定义 DevS API 端点 | 区域默认值 | + +> 超时和读超时通过 `new Config({ timeout, readTimeout })` 在代码中配置(单位:毫秒),不通过环境变量读取。 ## 兼容性 diff --git a/src/agent-runtime/endpoint.ts b/src/agent-runtime/endpoint.ts index 514070b..1ec5202 100644 --- a/src/agent-runtime/endpoint.ts +++ b/src/agent-runtime/endpoint.ts @@ -157,7 +157,7 @@ export class AgentRuntimeEndpoint extends ResourceBase implements AgentRuntimeEn return await AgentRuntimeEndpoint.get({ agentRuntimeId: this.agentRuntimeId!, endpointId: this.agentRuntimeEndpointId!, - config: params?.config, + config: params?.config ?? this._config, }); }; diff --git a/src/credential/client.ts b/src/credential/client.ts index 1fab832..9fbbdd1 100644 --- a/src/credential/client.ts +++ b/src/credential/client.ts @@ -84,7 +84,7 @@ export class CredentialClient { config: cfg, }); - return new Credential(result); + return new Credential(result, cfg); } catch (error) { if (error instanceof HTTPError) { throw error.toResourceError('Credential', params?.input?.credentialName); @@ -106,7 +106,7 @@ export class CredentialClient { config: cfg, }); - return new Credential(result); + return new Credential(result, cfg); } catch (error) { if (error instanceof HTTPError) { throw error.toResourceError('Credential', params?.name); @@ -165,7 +165,7 @@ export class CredentialClient { config: cfg, }); - return new Credential(result as any); + return new Credential(result as any, cfg); } catch (error) { if (error instanceof HTTPError) { throw error.toResourceError('Credential', params?.name); @@ -187,7 +187,7 @@ export class CredentialClient { credentialName: name, config: cfg, }); - return new Credential(result as any); + return new Credential(result as any, cfg); } catch (error) { if (error instanceof HTTPError) { throw error.toResourceError('Credential', params?.name); diff --git a/src/model/client.ts b/src/model/client.ts index 065f0a9..f499da9 100644 --- a/src/model/client.ts +++ b/src/model/client.ts @@ -80,9 +80,7 @@ export class ModelClient { input: createInput, config: cfg, }); - const proxy = new ModelProxy(); - Object.assign(proxy, result); - return proxy; + return new ModelProxy(result, cfg); } else { // 处理 ModelServiceCreateInput const modelServiceInput = input as ModelServiceCreateInput; @@ -95,9 +93,7 @@ export class ModelClient { input: createInput, config: cfg, }); - const service = new ModelService(); - Object.assign(service, result); - return service; + return new ModelService(result, cfg); } } catch (e) { if (e instanceof HTTPError) { @@ -136,9 +132,7 @@ export class ModelClient { modelProxyName: name, config: cfg, }); - const proxy = new ModelProxy(); - Object.assign(proxy, result); - return proxy; + return new ModelProxy(result, cfg); } catch (e) { if (e instanceof HTTPError) { error = e; @@ -159,9 +153,7 @@ export class ModelClient { modelServiceName: name, config: cfg, }); - const service = new ModelService(); - Object.assign(service, result); - return service; + return new ModelService(result, cfg); } catch (e) { if (e instanceof HTTPError) { throw e.toResourceError('Model', name); @@ -208,9 +200,7 @@ export class ModelClient { input: updateInput, config: cfg, }); - const proxy = new ModelProxy(); - Object.assign(proxy, result); - return proxy; + return new ModelProxy(result, cfg); } catch (e) { if (e instanceof HTTPError) { throw e.toResourceError('Model', name); @@ -231,9 +221,7 @@ export class ModelClient { input: updateInput, config: cfg, }); - const service = new ModelService(); - Object.assign(service, result); - return service; + return new ModelService(result, cfg); } catch (e) { if (e instanceof HTTPError) { throw e.toResourceError('Model', name); @@ -268,9 +256,7 @@ export class ModelClient { modelProxyName: name, config: cfg, }); - const proxy = new ModelProxy(); - Object.assign(proxy, result); - return proxy; + return new ModelProxy(result, cfg); } catch (e) { if (e instanceof HTTPError) { error = e; @@ -291,9 +277,7 @@ export class ModelClient { modelServiceName: name, config: cfg, }); - const service = new ModelService(); - Object.assign(service, result); - return service; + return new ModelService(result, cfg); } catch (e) { if (e instanceof HTTPError) { throw e.toResourceError('Model', name); @@ -328,11 +312,7 @@ export class ModelClient { input: request, config: cfg, }); - return (result.items || []).map(item => { - const proxy = new ModelProxy(); - Object.assign(proxy, item); - return proxy; - }); + return (result.items || []).map(item => new ModelProxy(item, cfg)); } else { // 处理 ModelServiceListInput 或无参数(默认列出 ModelService) const modelServiceInput = (input ?? {}) as ModelServiceListInput; @@ -345,11 +325,7 @@ export class ModelClient { input: request, config: cfg, }); - return (result.items || []).map(item => { - const service = new ModelService(); - Object.assign(service, item); - return service; - }); + return (result.items || []).map(item => new ModelService(item, cfg)); } }; } diff --git a/src/model/model-proxy.ts b/src/model/model-proxy.ts index 54a93ec..434dddb 100644 --- a/src/model/model-proxy.ts +++ b/src/model/model-proxy.ts @@ -8,7 +8,7 @@ import * as _ from 'lodash'; import { Config } from '../utils/config'; -import { listAllResourcesFunction, ResourceBase } from '../utils/resource'; +import { listAllResourcesFunction, ResourceBase, updateObjectProperties } from '../utils/resource'; import { ModelAPI, ModelInfo } from './api/model-api'; import { @@ -56,11 +56,17 @@ export class ModelProxy private modelApi: ModelAPI; - constructor() { + constructor(data?: any, config?: Config) { super(); this.modelApi = new ModelAPI(this.modelInfo); this.completion = this.modelApi.completion; this.embedding = this.modelApi.embedding; + if (data) { + updateObjectProperties(this, data); + } + if (config) { + this._config = config; + } } completion: (typeof ModelAPI)['prototype']['completion']; @@ -183,7 +189,7 @@ export class ModelProxy const result = await ModelProxy.update({ name: this.modelProxyName, input, - config, + config: config ?? this._config, }); this.updateSelf(result); @@ -203,7 +209,7 @@ export class ModelProxy return await ModelProxy.delete({ name: this.modelProxyName, - config: params?.config, + config: params?.config ?? this._config, }); }; @@ -220,7 +226,7 @@ export class ModelProxy const result = await ModelProxy.get({ name: this.modelProxyName, - config: params?.config, + config: params?.config ?? this._config, }); this.updateSelf(result); diff --git a/src/model/model-service.ts b/src/model/model-service.ts index 18b5b4f..4106937 100644 --- a/src/model/model-service.ts +++ b/src/model/model-service.ts @@ -6,7 +6,7 @@ */ import { Config } from '../utils/config'; -import { listAllResourcesFunction, ResourceBase } from '../utils/resource'; +import { listAllResourcesFunction, ResourceBase, updateObjectProperties } from '../utils/resource'; import { ModelAPI } from './api/model-api'; import { @@ -48,11 +48,17 @@ export class ModelService modelType?: ModelServiceImmutableProps['modelType']; private modelApi: ModelAPI; - constructor() { + constructor(data?: any, config?: Config) { super(); this.modelApi = new ModelAPI(this.modelInfo); this.completion = this.modelApi.completion; this.embedding = this.modelApi.embedding; + if (data) { + updateObjectProperties(this, data); + } + if (config) { + this._config = config; + } } completion: (typeof ModelAPI)['prototype']['completion']; @@ -173,7 +179,7 @@ export class ModelService const result = await ModelService.update({ name: this.modelServiceName, input, - config, + config: config ?? this._config, }); this.updateSelf(result); @@ -193,7 +199,7 @@ export class ModelService return await ModelService.delete({ name: this.modelServiceName, - config: params?.config, + config: params?.config ?? this._config, }); }; @@ -210,7 +216,7 @@ export class ModelService const result = await ModelService.get({ name: this.modelServiceName, - config: params?.config, + config: params?.config ?? this._config, }); this.updateSelf(result); diff --git a/src/sandbox/api/control.ts b/src/sandbox/api/control.ts index 85d80aa..c0653ff 100644 --- a/src/sandbox/api/control.ts +++ b/src/sandbox/api/control.ts @@ -273,9 +273,12 @@ export class SandboxControlAPI extends ControlAPI { const { input, headers, config } = params; try { - const client = this.getClient(config); + const cfg = Config.withConfigs(this.config, config); + const client = this.getClient(cfg); + // createSandbox should fail fast (default 30s) but honor an explicit + // readTimeout from the caller's Config when provided. const runtime = new $Util.RuntimeOptions({ - readTimeout: 30000, + readTimeout: cfg.readTimeoutOr(30000), }); const response = await client.createSandboxWithOptions( diff --git a/src/sandbox/api/sandbox-data.ts b/src/sandbox/api/sandbox-data.ts index 1f11f92..a3d7ab0 100644 --- a/src/sandbox/api/sandbox-data.ts +++ b/src/sandbox/api/sandbox-data.ts @@ -63,7 +63,7 @@ export class SandboxDataAPI { config?: Config; }): Promise { const { sandboxId, templateName, config } = params; - const cfg = Config.withConfigs(config, this.config); + const cfg = Config.withConfigs(this.config, config); const cacheKey = (sandboxId || templateName)!; const cachedToken = this.accessTokenMap.get(cacheKey); @@ -424,6 +424,7 @@ export class SandboxDataAPI { return this.post({ path: '/', data, + config: params.config, }); }; @@ -436,7 +437,7 @@ export class SandboxDataAPI { config: params.config, }); - return this.delete({ path: '/' }); + return this.delete({ path: '/', config: params.config }); }; /** @@ -448,7 +449,7 @@ export class SandboxDataAPI { config: params.config, }); - return this.post({ path: '/stop' }); + return this.post({ path: '/stop', config: params.config }); }; /** @@ -460,6 +461,6 @@ export class SandboxDataAPI { config: params.config, }); - return this.get({ path: '/' }); + return this.get({ path: '/', config: params.config }); }; } diff --git a/src/sandbox/sandbox.ts b/src/sandbox/sandbox.ts index 7941e70..c8e5b0c 100644 --- a/src/sandbox/sandbox.ts +++ b/src/sandbox/sandbox.ts @@ -282,7 +282,7 @@ export class Sandbox extends ResourceBase implements SandboxData { // Extract data and create Sandbox instance const data = result.data || {}; - const baseSandbox = Sandbox.fromInnerObject(data as any, config); + const baseSandbox = Sandbox.fromInnerObject(data as any, cfg); // If templateType is specified, return the appropriate subclass if (templateType) { @@ -291,25 +291,25 @@ export class Sandbox extends ResourceBase implements SandboxData { case TemplateType.CODE_INTERPRETER: { const { CodeInterpreterSandbox } = await import('./code-interpreter-sandbox'); // Pass baseSandbox instead of raw data - const sandbox = new CodeInterpreterSandbox(baseSandbox, config); + const sandbox = new CodeInterpreterSandbox(baseSandbox, cfg); return sandbox; } case TemplateType.BROWSER: { const { BrowserSandbox } = await import('./browser-sandbox'); // Pass baseSandbox instead of raw data - const sandbox = new BrowserSandbox(baseSandbox, config); + const sandbox = new BrowserSandbox(baseSandbox, cfg); return sandbox; } case TemplateType.AIO: { const { AioSandbox } = await import('./aio-sandbox'); // Pass baseSandbox instead of raw data - const sandbox = new AioSandbox(baseSandbox, config); + const sandbox = new AioSandbox(baseSandbox, cfg); return sandbox; } case TemplateType.CUSTOM: { const { CustomSandbox } = await import('./custom-sandbox'); // Pass baseSandbox instead of raw data - const sandbox = new CustomSandbox(baseSandbox, config); + const sandbox = new CustomSandbox(baseSandbox, cfg); return sandbox; } } diff --git a/src/sandbox/template.ts b/src/sandbox/template.ts index d7fd83a..476b46e 100644 --- a/src/sandbox/template.ts +++ b/src/sandbox/template.ts @@ -163,7 +163,7 @@ export class Template extends ResourceBase implements TemplateData { get = async (params: { config?: Config } = {}): Promise