@roll-agent/sdk 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,14 +19,24 @@ export declare function resolveAgentLogLevel(explicit?: LogLevel): LogLevel;
19
19
  export declare function defineAgent(definition: AgentDefinition, options?: DefineAgentOptions): RunnableAgent;
20
20
  /** 将单个 tool 注册到 MCP Server */
21
21
  export declare function registerTool(server: McpServer, tool: AnyToolDefinition, ctx: AgentContext): void;
22
- type McpTextToolResult = {
22
+ export type ToolResultImage = {
23
+ readonly data: string;
24
+ readonly mimeType: string;
25
+ };
26
+ type McpToolContentBlock = {
27
+ type: "text";
28
+ text: string;
29
+ } | {
30
+ type: "image";
31
+ data: string;
32
+ mimeType: string;
33
+ };
34
+ type McpToolResult = {
23
35
  isError?: true;
24
- content: [
25
- {
26
- type: "text";
27
- text: string;
28
- }
29
- ];
36
+ content: [{
37
+ type: "text";
38
+ text: string;
39
+ }, ...McpToolContentBlock[]];
30
40
  };
31
- export declare function executeToolForMcp(tool: AnyToolDefinition, ctx: AgentContext, params: Record<string, unknown>, signal?: AbortSignal): Promise<McpTextToolResult>;
41
+ export declare function executeToolForMcp(tool: AnyToolDefinition, ctx: AgentContext, params: Record<string, unknown>, signal?: AbortSignal): Promise<McpToolResult>;
32
42
  export {};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { defineAgent } from "./define-agent.ts";
2
- export type { DefineAgentOptions } from "./define-agent.ts";
2
+ export type { DefineAgentOptions, ToolResultImage } from "./define-agent.ts";
3
3
  export { defineTool } from "./define-tool.ts";
4
4
  export { createAgentLogger } from "./context.ts";
5
5
  export type { AgentContext, AgentLogger, AgentLLM, LogLevel } from "./context.ts";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{createServer as e}from"node:http";import{randomUUID as n}from"node:crypto";import{McpServer as t}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as o}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as r}from"@modelcontextprotocol/sdk/server/streamableHttp.js";var s={debug:0,info:1,warn:2,error:3};function i(e,n="info"){const t=s[n],o=(n,o)=>{if(s[n]<t)return;const r=(new Date).toISOString(),i=n.toUpperCase().padEnd(5);console.error(`${r} [${i}] [${e}] ${o}`)};return{debug:e=>o("debug",e),info:e=>o("info",e),warn:e=>o("warn",e),error:e=>o("error",e)}}import{z as a}from"zod";var c=8;function f(e){let n=e;for(let e=0;e<c;e+=1)if(n instanceof a.ZodEffects)n=n.innerType();else if(n instanceof a.ZodOptional||n instanceof a.ZodNullable||n instanceof a.ZodBranded||n instanceof a.ZodReadonly)n=n.unwrap();else if(n instanceof a.ZodDefault)n=n.removeDefault();else{if(!(n instanceof a.ZodCatch))return n;n=n.removeCatch()}return n}async function l(e,n){const t=await e.safeParseAsync(n);if(!t.success)throw new Error(`Tool input validation failed: ${d(t.error)}`);return t.data}function d(e){return e.issues.map(e=>{const n=e.path.join(".");return n.length>0?`${n}: ${e.message}`:e.message}).join("; ")}var u=class extends Error{payload;constructor(e){super(e.message),this.name="StructuredToolError",this.payload=e}};function p(e){return e instanceof u||e instanceof Error&&"payload"in e&&y(e.payload)}function y(e){if("object"!=typeof e||null===e||Array.isArray(e))return!1;const n=e,t=n.details;return"string"==typeof n.code&&"string"==typeof n.message&&(void 0===t||"object"==typeof t&&null!==t&&!Array.isArray(t))}var m="roll/resourceHints";function w(e){return e??g()??"info"}function g(){const e=process.env.ROLL_AGENT_LOG_LEVEL;if("debug"===e||"info"===e||"warn"===e||"error"===e)return e}function h(e,n,t){return{llm:{generateText:async e=>{try{const n=v((await t.server.createMessage({messages:[{role:"user",content:{type:"text",text:e}}],maxTokens:1024})).content);if(void 0===n)throw new Error("Sampling response did not include text content");return n}catch(e){throw new Error("LLM sampling unavailable. Ensure roll-core client enables sampling capability.",{cause:e})}}},logger:i(e,n)}}function v(e){if("object"==typeof e&&null!==e&&"type"in e&&"text"===e.type&&"text"in e){const n=e.text;return"string"==typeof n?n:void 0}if(Array.isArray(e))for(const n of e){const e=v(n);if(void 0!==e)return e}}function S(e,n={}){return{...e,listen:async t=>{const o=t?.transport??{type:"stdio"},r=w(n.logLevel);"http"===o.type?await $(e,r,o.port,o.host,n.onShutdown):await T(e,r,n.onShutdown)}}}function x(e){let n;const t=t=>{n??=e(t).catch(()=>{process.exit(1)})};process.once("SIGTERM",()=>{t("SIGTERM")}),process.once("SIGINT",()=>{t("SIGINT")})}async function T(e,n,r){const s=new t({name:e.name,version:"0.0.1"}),i=h(e.name,n,s);for(const n of e.tools)E(s,n,i);const a=new o;await s.connect(a),i.logger.info("MCP Server running on stdio");x(async e=>{i.logger.info(`${e} received, shutting down...`),r&&await r(),await s.close(),process.exit(0)})}async function $(o,s,a,c,f){const l=i(o.name,s),d=new Map,u=e(async(e,i)=>{if("/mcp"!==new URL(e.url??"/",`http://${e.headers.host??"localhost"}`).pathname)return i.writeHead(404,{"Content-Type":"application/json"}),void i.end(JSON.stringify({error:"Not found"}));const a="string"==typeof e.headers["mcp-session-id"]?e.headers["mcp-session-id"]:void 0;if(a){const n=d.get(a);if(n){try{await n.transport.handleRequest(e,i)}catch(e){l.error(`Error handling request for session ${a}: ${String(e)}`),i.headersSent||(i.writeHead(500,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Internal server error"})))}return}return i.writeHead(404,{"Content-Type":"application/json"}),void i.end(JSON.stringify({error:"Session not found"}))}try{const a=new r({sessionIdGenerator:()=>n()}),c=new t({name:o.name,version:"0.0.1"}),f=h(o.name,s,c);for(const e of o.tools)E(c,e,f);a.onclose=()=>{const e=a.sessionId;e&&(d.delete(e),l.info(`Session ${e} closed`))},a.onerror=e=>{l.error(`Transport error (session ${a.sessionId??"unknown"}): ${e.message}`)},await c.connect(a),await a.handleRequest(e,i),a.sessionId&&d.set(a.sessionId,{transport:a,server:c})}catch(e){l.error(`Error creating new session: ${String(e)}`),i.headersSent||(i.writeHead(500,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Failed to create session"})))}});u.on("error",e=>{l.error(`HTTP server error: ${e.message}`)});const p=c??"127.0.0.1";u.listen(a,p,()=>{l.info(`MCP Server running on http://${p}:${a}/mcp`)});x(async e=>{l.info(`${e} received, shutting down HTTP server...`),await new Promise(e=>{u.close(()=>e())});const n=[];for(const[,e]of d)n.push(e.server.close());await Promise.all(n),d.clear(),f&&await f(),process.exit(0)})}function E(e,n,t){const o={...n._meta??{},...n.resourceHints&&n.resourceHints.length>0?{[m]:n.resourceHints}:{}};e.registerTool(n.name,{description:n.description,inputSchema:f(n.input),...n.annotations?{annotations:n.annotations}:{},...Object.keys(o).length>0?{_meta:o}:{}},async(e,o)=>await b(n,t,e,o.signal))}async function b(e,n,t,o){const r=await l(e.input,t),s=void 0===o?n:{...n,signal:o};try{const n=await e.execute(r,s);return{content:[{type:"text",text:JSON.stringify(n)}]}}catch(e){if(p(e))return{isError:!0,content:[{type:"text",text:JSON.stringify(e.payload)}]};throw e}}function j(e){return e}var I={read:"read",write:"write"},H={file:"file",browserSession:"browser-session",conversation:"conversation",custom:"custom"};export{u as StructuredToolError,I as TOOL_RESOURCE_ACCESS_MODES,H as TOOL_RESOURCE_HINT_KINDS,i as createAgentLogger,S as defineAgent,j as defineTool,p as isStructuredToolError};
1
+ import{createServer as e}from"node:http";import{randomUUID as n}from"node:crypto";import{McpServer as t}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as r}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as o}from"@modelcontextprotocol/sdk/server/streamableHttp.js";var s={debug:0,info:1,warn:2,error:3};function i(e,n="info"){const t=s[n],r=(n,r)=>{if(s[n]<t)return;const o=(new Date).toISOString(),i=n.toUpperCase().padEnd(5);console.error(`${o} [${i}] [${e}] ${r}`)};return{debug:e=>r("debug",e),info:e=>r("info",e),warn:e=>r("warn",e),error:e=>r("error",e)}}import{z as a}from"zod";var c=8;function l(e){let n=e;for(let e=0;e<c;e+=1)if(n instanceof a.ZodEffects)n=n.innerType();else if(n instanceof a.ZodOptional||n instanceof a.ZodNullable||n instanceof a.ZodBranded||n instanceof a.ZodReadonly)n=n.unwrap();else if(n instanceof a.ZodDefault)n=n.removeDefault();else{if(!(n instanceof a.ZodCatch))return n;n=n.removeCatch()}return n}async function p(e,n){const t=await e.safeParseAsync(n);if(!t.success)throw new Error(`Tool input validation failed: ${f(t.error)}`);return t.data}function f(e){return e.issues.map(e=>{const n=e.path.join(".");return n.length>0?`${n}: ${e.message}`:e.message}).join("; ")}var d=class extends Error{payload;constructor(e){super(e.message),this.name="StructuredToolError",this.payload=e}};function u(e){return e instanceof d||e instanceof Error&&"payload"in e&&y(e.payload)}function y(e){if("object"!=typeof e||null===e||Array.isArray(e))return!1;const n=e,t=n.details;return"string"==typeof n.code&&"string"==typeof n.message&&(void 0===t||"object"==typeof t&&null!==t&&!Array.isArray(t))}var m="roll/resourceHints";function g(e){return e??w()??"info"}function w(){const e=process.env.ROLL_AGENT_LOG_LEVEL;if("debug"===e||"info"===e||"warn"===e||"error"===e)return e}function h(e,n,t){return{llm:{generateText:async e=>{try{const n=v((await t.server.createMessage({messages:[{role:"user",content:{type:"text",text:e}}],maxTokens:1024})).content);if(void 0===n)throw new Error("Sampling response did not include text content");return n}catch(e){throw new Error("LLM sampling unavailable. Ensure roll-core client enables sampling capability.",{cause:e})}}},logger:i(e,n)}}function v(e){if("object"==typeof e&&null!==e&&"type"in e&&"text"===e.type&&"text"in e){const n=e.text;return"string"==typeof n?n:void 0}if(Array.isArray(e))for(const n of e){const e=v(n);if(void 0!==e)return e}}function S(e,n={}){return{...e,listen:async t=>{const r=t?.transport??{type:"stdio"},o=g(n.logLevel);"http"===r.type?await $(e,o,r.port,r.host,n.onShutdown):await x(e,o,n.onShutdown)}}}function T(e){let n;const t=t=>{n??=e(t).catch(()=>{process.exit(1)})};process.once("SIGTERM",()=>{t("SIGTERM")}),process.once("SIGINT",()=>{t("SIGINT")})}async function x(e,n,o){const s=new t({name:e.name,version:"0.0.1"}),i=h(e.name,n,s);for(const n of e.tools)b(s,n,i);const a=new r;await s.connect(a),i.logger.info("MCP Server running on stdio");T(async e=>{i.logger.info(`${e} received, shutting down...`),o&&await o(),await s.close(),process.exit(0)})}async function $(r,s,a,c,l){const p=i(r.name,s),f=new Map,d=e(async(e,i)=>{if("/mcp"!==new URL(e.url??"/",`http://${e.headers.host??"localhost"}`).pathname)return i.writeHead(404,{"Content-Type":"application/json"}),void i.end(JSON.stringify({error:"Not found"}));const a="string"==typeof e.headers["mcp-session-id"]?e.headers["mcp-session-id"]:void 0;if(a){const n=f.get(a);if(n){try{await n.transport.handleRequest(e,i)}catch(e){p.error(`Error handling request for session ${a}: ${String(e)}`),i.headersSent||(i.writeHead(500,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Internal server error"})))}return}return i.writeHead(404,{"Content-Type":"application/json"}),void i.end(JSON.stringify({error:"Session not found"}))}try{const a=new o({sessionIdGenerator:()=>n()}),c=new t({name:r.name,version:"0.0.1"}),l=h(r.name,s,c);for(const e of r.tools)b(c,e,l);a.onclose=()=>{const e=a.sessionId;e&&(f.delete(e),p.info(`Session ${e} closed`))},a.onerror=e=>{p.error(`Transport error (session ${a.sessionId??"unknown"}): ${e.message}`)},await c.connect(a),await a.handleRequest(e,i),a.sessionId&&f.set(a.sessionId,{transport:a,server:c})}catch(e){p.error(`Error creating new session: ${String(e)}`),i.headersSent||(i.writeHead(500,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Failed to create session"})))}});d.on("error",e=>{p.error(`HTTP server error: ${e.message}`)});const u=c??"127.0.0.1";d.listen(a,u,()=>{p.info(`MCP Server running on http://${u}:${a}/mcp`)});T(async e=>{p.info(`${e} received, shutting down HTTP server...`),await new Promise(e=>{d.close(()=>e())});const n=[];for(const[,e]of f)n.push(e.server.close());await Promise.all(n),f.clear(),l&&await l(),process.exit(0)})}function b(e,n,t){const r={...n._meta??{},...n.resourceHints&&n.resourceHints.length>0?{[m]:n.resourceHints}:{}};e.registerTool(n.name,{description:n.description,inputSchema:l(n.input),...n.annotations?{annotations:n.annotations}:{},...Object.keys(r).length>0?{_meta:r}:{}},async(e,r)=>await j(n,t,e,r.signal))}function E(e){if("object"!=typeof e||null===e||Array.isArray(e))return{payload:e,images:[]};const n=e,t=n.mcpImages;if(!Array.isArray(t))return{payload:e,images:[]};const r=t.filter(e=>"object"==typeof e&&null!==e&&"string"==typeof e.data&&"string"==typeof e.mimeType),{mcpImages:o,...s}=n;return{payload:s,images:r}}async function j(e,n,t,r){const o=await p(e.input,t),s=void 0===r?n:{...n,signal:r};try{const n=await e.execute(o,s),{payload:t,images:r}=E(n);return{content:[{type:"text",text:JSON.stringify(t)},...r.map(e=>({type:"image",data:e.data,mimeType:e.mimeType}))]}}catch(e){if(u(e))return{isError:!0,content:[{type:"text",text:JSON.stringify(e.payload)}]};throw e}}function I(e){return e}var A={read:"read",write:"write"},H={file:"file",browserSession:"browser-session",conversation:"conversation",custom:"custom"};export{d as StructuredToolError,A as TOOL_RESOURCE_ACCESS_MODES,H as TOOL_RESOURCE_HINT_KINDS,i as createAgentLogger,S as defineAgent,I as defineTool,u as isStructuredToolError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roll-agent/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,7 @@
26
26
  "node": ">=22.6.0"
27
27
  },
28
28
  "dependencies": {
29
- "@modelcontextprotocol/sdk": "^1.12.0",
29
+ "@modelcontextprotocol/sdk": "^1.30.0",
30
30
  "zod": "^3.25.76"
31
31
  },
32
32
  "devDependencies": {