@roll-agent/runtime 0.20.1 → 0.21.0
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
import{lstatSync as e,readdirSync as
|
|
1
|
+
import{lstatSync as e,readdirSync as n,readlinkSync as o,realpathSync as t,statSync as r}from"node:fs";import{inlineAcyclicLocalJsonSchemaReferences as i}from"@roll-agent/core/tool-runtime/json-schema-refs";import{basename as s,dirname as a,isAbsolute as c,resolve as u}from"node:path";import{jsonSchema as l,tool as f}from"ai";import{preflightToolCall as d}from"@roll-agent/core/tool-runtime/preflight";import{ToolRegistry as p}from"./naming.js";import{TOOL_OUTCOME_KINDS as m,failedToolResult as v,toolResultToModelOutput as g}from"./normalize-result.js";import{TOOL_RESOURCE_ACCESS_MODES as h,TOOL_RESOURCE_HINT_KINDS as y,executeCoordinatedTool as S}from"./tool-execution-coordinator.js";import{executeWithToolApproval as $}from"./tool-approval-continuation.js";export const ROLL_RESOURCE_HINTS_META_KEY="roll/resourceHints";function b(e,n){const o=new Map;for(const t of[...e??[],...n])o.set(`${t.path}\0${t.ref}`,t);return[...o.values()]}function w(e){return"object"!=typeof e||null===e||Array.isArray(e)?{}:e}function C(e){return`参数校验失败: ${e.map(e=>e.message).join("; ")}`}function N(e){return!0===e?.readOnlyHint&&!0!==e.destructiveHint?h.read:h.write}function k(e){return"string"==typeof e||"number"==typeof e?[e]:Array.isArray(e)&&0!==e.length&&e.every(e=>"string"==typeof e||"number"==typeof e)?e:void 0}const A=256,O=new Map;function j(e,n){for(let o=0;o<e.length;o+=1){const t=e.charCodeAt(o),r=t>=65&&t<=90?String.fromCharCode(t+32):t>=97&&t<=122?String.fromCharCode(t-32):void 0;if(void 0===r)continue;const i=`${e.slice(0,o)}${r}${e.slice(o+1)}`;if(!n.has(i))return i}}function x(e){return"object"==typeof e&&null!==e&&"code"in e?e.code:void 0}function T(n,o,t){const r=j(o,t);if(void 0!==r)try{const t=e(u(n,o)),i=e(u(n,r));return t.dev===i.dev&&t.ino===i.ino}catch(e){const n=x(e);return"ENOENT"!==n&&"ENOTDIR"!==n&&void 0}}function I(e,n){if(O.size>=A){const e=O.keys().next().value;void 0!==e&&O.delete(e)}return O.set(e,n),n}function L(o){const t=O.get(o);if(void 0!==t)return t;let r;try{r=e(o).dev}catch{return I(o,!0)}let i=o;for(;;){const t=O.get(i);if(void 0!==t)return I(o,t);try{const e=n(i),t=new Set(e);for(const n of e){const e=T(i,n,t);if(void 0!==e)return I(i,e),I(o,e)}}catch{}const s=a(i);if(s===i)break;try{if(e(s).dev!==r)break}catch{break}i=s}return I(o,!0)}function E(e){let n=e.normalize("NFC");for(let e=0;e<8;e+=1){const e=n.toUpperCase().toLowerCase().normalize("NFC");if(e===n)return n;n=e}return n}function M(e,n){try{const o=r(e,{bigint:!0}),t=n.map(e=>E(e));return`file-unresolved-alias:${o.dev.toString()}:${o.ino.toString()}:${JSON.stringify(t)}`}catch{return}}function R(n,r=new Set){let i=n;const c=[];for(;;)try{const e=t.native(i),n=c.reverse().map(e=>e.normalize("NFC"));if(0===n.length)return{path:e};const o=L(e),r=u(e,...o?n.map(e=>e.toLowerCase()):n),s=o?M(e,n):void 0;return{path:r,...void 0===s?{}:{unresolvedAliasKey:s}}}catch{try{if(e(i).isSymbolicLink()&&!r.has(i)){const e=new Set(r);e.add(i);const n=o(i);return R(u(a(i),n,...[...c].reverse()),e)}}catch{}const t=a(i);if(t===i)return{path:n};c.push(s(i)),i=t}}function z(e){try{const n=r(e,{bigint:!0});return`file-inode:${n.dev.toString()}:${n.ino.toString()}`}catch{return}}function H(e,n,o){const t=String(n).trim();if(0!==t.length)switch(e.kind){case y.file:{if(!c(t)&&void 0===o)return;const e=R(u(o??"/",t)),n=z(e.path);return[`file:${e.path}`,...void 0===e.unresolvedAliasKey?[]:[e.unresolvedAliasKey],...void 0===n?[]:[n]]}case y.browserSession:return[`browser-session:${t}`];case y.conversation:return[`conversation:${t}`];case y.custom:{const n=e.namespace?.trim();return n?[`${n}:${t}`]:void 0}}}function K(e,n,o,t,r){const i=N(t),s=w(o),a=[{key:`agent:${e}`,mode:i}],c=[];for(const e of r??[]){if(!Object.hasOwn(s,e.field))continue;const o=k(s[e.field]);if(void 0===o)return a;for(const t of o){const o=H(e,t,n);if(void 0===o||0===o.length)return a;c.push(...o.map(n=>({key:n,mode:e.mode??i})))}}return 0===c.length?a:[{key:`agent:${e}`,mode:h.read},...c]}export async function gateToolCall(e,n,o,t,r,i){if(!e.policy)return;const s=e.policy.check({agentName:n,toolName:o,input:t,...r?{annotations:r}:{}});if("deny"===s.action)return v(m.policyDenied,"策略拒绝执行"+(s.reason?`: ${s.reason}`:""),s.reason?{reason:s.reason}:{});if("confirm"===s.action){const r=i?.memoryKey;if(void 0!==r&&e.approvalMemory?.isGranted(r))return;const a=await e.requestApproval({agentName:n,toolName:o,input:t,reason:!1===i?.includePolicyReason?void 0:s.reason,...void 0!==i?.explanation?{explanation:i.explanation}:{},...void 0!==i?.diff?{diff:i.diff}:{},...void 0!==r&&void 0!==i?.sessionGrantLabel?{sessionGrantLabel:i.sessionGrantLabel}:{}});if(!a.approved)return v(m.userRejected,"已取消执行"+(a.reason?`: ${a.reason}`:""),a.reason?{reason:a.reason}:{});void 0!==r&&"session"===a.scope&&e.approvalMemory?.grant(r)}}export function buildAgentToolset(e,n,o=new p){const t={},r={};for(const s of e){const{client:e,agentName:a,agentSource:c,transport:u,runtimeOwnership:p,resourceBaseDir:h}=s;for(const{tool:y,annotations:N,resourceHints:k}of s.tools){const s=i(y.inputSchema),A=b(y.schemaIssues,s.unresolved),O={...y,inputSchema:s.schema,...A.length>0?{schemaIssues:A}:{}},j=o.register(a,O.name,{...c?{agentSource:c}:{},...u?{transport:u}:{},...p?{runtimeOwnership:p}:{},...N?{annotations:N}:{}});A.length>0&&(r[j]=A);const x={prepare:async e=>{const o=w(e),t=d(O,o);return t.ok?gateToolCall(n,a,O.name,o,N):v(m.invalidInput,C(t.issues),{raw:t.issues})},resources:e=>K(a,h,e,N,k)};n.coordinator?.register(j,x),t[j]=f({description:O.description??`${O.name} (via ${a})`,inputSchema:l(O.inputSchema),toModelOutput:({output:e})=>g(e),execute:async(o,t)=>{const r=w(o);return S(n.coordinator,x,j,t.toolCallId,r,t.abortSignal,async()=>{const o=t.abortSignal?{signal:t.abortSignal}:void 0;return $({input:r,agentName:a,agentTool:O,annotations:N,ctx:n,signal:t.abortSignal,call:async n=>await e.callTool({name:O.name,arguments:n},void 0,o)})})}})}}return{tools:t,registry:o,schemaIssuesByToolId:r}}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentTool } from "@roll-agent/core/types/agent";
|
|
2
|
+
import type { ToolAnnotations } from "../types/policy.ts";
|
|
3
|
+
import type { ToolBridgeContext } from "./build-tools.ts";
|
|
4
|
+
import { type NormalizedToolResult } from "./normalize-result.ts";
|
|
5
|
+
/** Only a producer's explicit pre-effect challenge can continue, once, after real user approval. */
|
|
6
|
+
export declare function executeWithToolApproval(options: {
|
|
7
|
+
input: Record<string, unknown>;
|
|
8
|
+
agentName: string;
|
|
9
|
+
agentTool: AgentTool;
|
|
10
|
+
annotations: ToolAnnotations | undefined;
|
|
11
|
+
ctx: ToolBridgeContext;
|
|
12
|
+
signal: AbortSignal | undefined;
|
|
13
|
+
call: (input: Record<string, unknown>) => Promise<unknown>;
|
|
14
|
+
}): Promise<NormalizedToolResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z as t}from"zod";import{preflightToolCall as e}from"@roll-agent/core/tool-runtime/preflight";import{createToolResult as r,failedToolResult as o,normalizeToolResult as n,TOOL_OUTCOME_KINDS as a}from"./normalize-result.js";const i=t.object({id:t.string().min(1).max(256)}).strict(),s=t.object({code:t.literal("needs_confirmation"),details:t.object({executionState:t.literal("not_executed"),approvalRequest:t.object({id:t.string().min(1).max(256),tool:t.string().min(1).max(256),expiresAt:t.string().datetime(),summary:t.string().max(2e3).optional(),retryInput:t.union([t.object({scriptApproval:i}).strict(),t.object({toolActionApproval:i}).strict()])})})});function c(e,r){const o=t.object({isError:t.literal(!0),content:t.array(t.object({type:t.literal("text"),text:t.string().max(65536)})).length(1)}).safeParse(e);if(!o.success)return;let n;try{n=JSON.parse(o.data.content[0].text)}catch{return}const a=s.safeParse(n);if(!a.success)return;const i=a.data.details.approvalRequest,c="scriptApproval"in i.retryInput?i.retryInput.scriptApproval:i.retryInput.toolActionApproval;return i.tool!==r||c.id!==i.id||Date.parse(i.expiresAt)<=Date.now()?void 0:i}function l(){return r({kind:a.cancelled,executionState:"not_executed"},"已取消审批;工具未执行操作")}async function u(t,e){if(void 0===e)return t;if(e.aborted)return;let r=()=>{};const o=new Promise(t=>{r=()=>t(void 0),e.addEventListener("abort",r,{once:!0})});try{return await Promise.race([t,o])}finally{e.removeEventListener("abort",r)}}export async function executeWithToolApproval(t){if(t.signal?.aborted)return l();const r=structuredClone(t.input),i=await t.call(structuredClone(r)),s=c(i,t.agentTool.name);if(void 0===s)return n(i);if(t.signal?.aborted)return l();const p={...structuredClone(r),...s.retryInput};if(!e(t.agentTool,p).ok)return n(i);const d=structuredClone(r);delete d.scriptApproval,delete d.toolActionApproval;const m=await u(t.ctx.requestApproval({agentName:t.agentName,toolName:t.agentTool.name,input:d,reason:"tool_requested_confirmation",explanation:s.summary??"工具尚未执行操作;仅批准本次完整参数,不自动重放已执行步骤。"}),t.signal);if(t.signal?.aborted||void 0===m)return l();if(!m.approved)return o(a.userRejected,"用户拒绝本次操作;工具未执行操作");if(Date.parse(s.expiresAt)<=Date.now())return n(i);const f=t.ctx.policy?.check({agentName:t.agentName,toolName:t.agentTool.name,input:structuredClone(p),...void 0===t.annotations?{}:{annotations:t.annotations}});return"deny"===f?.action?o(a.policyDenied,"审批期间策略已改变,未执行操作"):t.signal?.aborted?l():n(await t.call(p))}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roll-agent/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"zod": "^3.25.76"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@roll-agent/core": "0.38.
|
|
38
|
+
"@roll-agent/core": "0.38.3",
|
|
39
39
|
"@types/node": "^22.0.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|