@roll-agent/runtime 0.24.0 → 0.25.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.
- package/dist/engine/agent-session.d.ts +8 -3
- package/dist/engine/agent-session.js +1 -1
- package/dist/engine/cancelled-turn-recovery.d.ts +2 -2
- package/dist/engine/capability-manifest.d.ts +1 -0
- package/dist/engine/capability-manifest.js +1 -1
- package/dist/engine/compaction-checkpoint.d.ts +136 -136
- package/dist/engine/compaction-semantic-state.d.ts +84 -84
- package/dist/engine/conversation-engine.js +1 -1
- package/dist/engine/explicit-skill-context.d.ts +2 -2
- package/dist/engine/observation-projection.d.ts +27 -0
- package/dist/engine/observation-projection.js +1 -0
- package/dist/engine/observation-readback.d.ts +6 -0
- package/dist/engine/observation-readback.js +1 -0
- package/dist/store/thread-origin.d.ts +8 -8
- package/dist/tool-bridge/build-tools.d.ts +4 -1
- package/dist/tool-bridge/build-tools.js +1 -1
- package/dist/tool-bridge/observation-recall-tool.d.ts +22 -0
- package/dist/tool-bridge/observation-recall-tool.js +1 -0
- package/dist/tool-bridge/schedule-create-input.d.ts +12 -12
- package/dist/tool-bridge/transcript-tool.d.ts +2 -2
- package/dist/types/cancellation.d.ts +2 -2
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{McpClientManager as t}from"@roll-agent/core/mcp/client-manager";import{createProviderModel as s,providerAcceptsToolSchemaIssues as i}from"@roll-agent/core/llm/providers";import{AgentStore as o}from"@roll-agent/core/registry/store";import{resolveTransportWithDevSpawnSpec as r}from"@roll-agent/core/registry/dev-spawn";import{getAgentPid as n,startAgent as a,waitForAgentReady as l}from"@roll-agent/core/registry/process-manager";import{acquireAgentUsageLease as c,getExitedAgentUsageNames as d}from"@roll-agent/core/registry/agent-usage-lease";import{formatToolSchemaIssue as h,formatAppOutputDiscoveryIssue as u,normalizeListedTools as p}from"@roll-agent/core/cli/utils/agent-tools";import{getAgentEnv as g}from"@roll-agent/core/config/helpers";import{catalogPackageSpec as m,getAgentCatalog as v}from"@roll-agent/core/registry/catalog";import{resolveAgentCatalog as f}from"@roll-agent/core/registry/catalog-discovery";import{installAgent as w}from"@roll-agent/core/registry/install";import{createSkillLibrary as y}from"@roll-agent/core/skills/library";import{ROLL_RESOURCE_HINTS_META_KEY as S}from"../tool-bridge/build-tools.js";import{TOOL_RESOURCE_ACCESS_MODES as C,TOOL_RESOURCE_HINT_KINDS as b}from"../tool-bridge/tool-execution-coordinator.js";import{AgentSession as x}from"./agent-session.js";import{resolveModelContextWindow as k}from"./context-window.js";import{createDefaultModelCatalog as A}from"./model-catalog-default.js";import{createWorkspaceInstructionsSource as O,parseWorkspaceInstructionsSetting as E}from"./workspace-instructions.js";import{CAPABILITY_HOST_MODES as P,shouldOfferAgentInstall as M,shouldOfferScheduleCreate as T}from"./capability-manifest.js";import{}from"../tool-bridge/bash-tool.js";import{unknownCommandClassifier as N}from"../types/command-classification.js";import{resolveShellProfile as I}from"../bash/profile.js";import{inspectGitVcsContext as L}from"./vcs-context.js";import{AGENT_BOOTSTRAP_MAX_CONCURRENCY as R,mapWithBoundedConcurrency as U}from"./agent-bootstrap.js";import{createToolLedgerGapRecoveryMessage as B}from"./cancelled-turn-recovery.js";const j=80,$="ConversationEngine is closing",F=3e4,D=6e4,W={connected:"connected",failed:"failed"};export function buildSessionExecSettings(e){const t=e.config.runtime.shell;return{workdir:process.cwd(),profile:e.profile,maxSessions:t.session.maxSessions,defaultYieldMs:t.session.defaultYieldMs,maxOutputTokens:t.session.maxOutputTokens,bufferCapacity:t.maxCaptureBytes,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}export function buildSessionBashSettings(e){const t=e.config.runtime.shell;return{workdir:process.cwd(),defaultTimeoutMs:t.defaultTimeoutMs,maxTimeoutMs:t.maxTimeoutMs,turnTimeoutMs:e.config.runtime.turnTimeoutMs,maxCaptureBytes:t.maxCaptureBytes,maxModelOutputChars:t.maxModelOutputChars,profile:e.profile,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}class AgentBootstrapTimeoutError extends Error{constructor(e){super(`Agent bootstrap timed out after ${String(e)}ms`),this.name="AgentBootstrapTimeoutError"}}class AgentBootstrapCleanupError extends AggregateError{cleanupErrors;constructor(e,t,s){const i=s.map(e=>e instanceof Error?e.message:String(e)).join("; ");super([t,...s],`Agent "${e}" bootstrap failed and resource cleanup also failed: ${i}`),this.name="AgentBootstrapCleanupError",this.cleanupErrors=s}}function H(){return new Error($)}function q(e){return e.reason??new Error("Operation aborted")}function V(e){if(!0===e?.aborted)throw q(e)}function _(e,t){return void 0===t?e:Math.max(1,Math.min(e,t-Date.now()))}function K(e){if(void 0!==e&&Date.now()>=e)throw new Error("Agent bootstrap deadline expired")}function Y(e){if("object"!=typeof e||null===e||!("annotations"in e))return;const t=e.annotations;if("object"!=typeof t||null===t)return;const s={};return"readOnlyHint"in t&&"boolean"==typeof t.readOnlyHint&&(s.readOnlyHint=t.readOnlyHint),"destructiveHint"in t&&"boolean"==typeof t.destructiveHint&&(s.destructiveHint=t.destructiveHint),void 0===s.readOnlyHint&&void 0===s.destructiveHint?void 0:s}function z(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function G(e){return Object.values(b).some(t=>t===e)}function J(e){return Object.values(C).some(t=>t===e)}function Q(e){return{hints:void 0,issue:e}}function X(e){if(!z(e)||!z(e._meta))return{hints:void 0,issue:void 0};if(!Object.hasOwn(e._meta,S))return{hints:void 0,issue:void 0};const t=e._meta[S];if(!Array.isArray(t))return Q("必须是数组");const s=[];for(const[e,i]of t.entries()){if(!z(i)||"string"!=typeof i.field||0===i.field.trim().length||"string"!=typeof i.kind||!G(i.kind)||void 0!==i.mode&&("string"!=typeof i.mode||!J(i.mode))||void 0!==i.namespace&&"string"!=typeof i.namespace||i.kind===b.custom&&("string"!=typeof i.namespace||0===i.namespace.trim().length))return Q(`第 ${String(e+1)} 项字段无效`);const t=i.kind===b.custom&&"string"==typeof i.namespace?i.namespace.trim():void 0;s.push({field:i.field.trim(),kind:i.kind,...void 0!==i.mode?{mode:i.mode}:{},...void 0!==t?{namespace:t}:{}})}return{hints:s.length>0?s:void 0,issue:void 0}}function Z(e){return"retry"===e.type?`安装遇到网络问题,${Math.round(e.delayMs/1e3)}s 后重试(第 ${e.attempt+1} 次)...`:"warn"===e.type?`警告:${e.message}`:e.message}async function ee(e,t,s,i){V(i),"core-managed"===e.runtime.ownership&&(void 0===n(t,e.skill.name)&&a(e,t,s),await l(e,{...i?{signal:i}:{}}))}function te(e){if(null===e.workspaceInstructions)return;if(void 0!==e.workspaceInstructions)return e.workspaceInstructions;const t=process.cwd();return O({cwd:t,setting:E(e.config.chat.instructions,t),...e.onWorkspaceInstructionsIssue?{onIssue:e.onWorkspaceInstructionsIssue}:{}})}export class ConversationEngine{config;clientManager;store;policy;fileToolsEnabled;maxSteps;providerOptions;modelOverride;modelNameOverride;providerNameOverride;switchingProviderName;modelCatalog;structuredOutputProviderOptions;structuredOutputReasoning;acquireAgentUsage;debugEvents;explicitAgents;explicitModel;explicitSources;explicitSkillLibrary;onSkillLibraryIssue;workspaceInstructions;onAgentBootstrapIssue;hostMode;scheduleTools;resolveDynamicCapabilityContext;sessionExecEnabled;explicitShellProfile;resolveShellProfileFn;installAgentFn;resolveCatalogFn;inspectVcsContext;shellEnv;onShellCommandSpawn;ready;refreshChain=Promise.resolve();resolvedCatalog;shellProfileResolution;shellUnsupportedWarned=!1;liveSessions=new Map;agentUsageLeases=new Map;shutdownController=new AbortController;disposePromise;closing=!1;constructor(e){this.config=e.config,this.clientManager=e.clientManager??new t,this.store=e.store,this.modelCatalog=e.modelCatalog??A(),this.policy=e.policy,this.fileToolsEnabled=e.fileToolsEnabled??!0,this.maxSteps=e.maxSteps??j,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.acquireAgentUsage=e.acquireAgentUsage??(e.ensureAgentReady?async(t,s,i)=>{await(e.ensureAgentReady?.(t,s,i))}:(e,t,s)=>this.acquireDefaultAgentUsage(e,t,s)),this.debugEvents=e.debugEvents??!1,this.hostMode=e.hostMode??P.embedded,this.scheduleTools=e.scheduleTools??void 0,this.resolveDynamicCapabilityContext=e.resolveDynamicCapabilityContext,this.sessionExecEnabled=e.sessionExecEnabled??!0,this.explicitShellProfile=e.shellProfile,this.resolveShellProfileFn=e.resolveShellProfileFn??I,this.explicitAgents=e.agents,this.explicitModel=e.model,this.explicitSources=e.sources,this.explicitSkillLibrary=e.skillLibrary,this.onSkillLibraryIssue=e.onSkillLibraryIssue,this.workspaceInstructions=te(e),this.onAgentBootstrapIssue=e.onAgentBootstrapIssue,this.installAgentFn=e.installAgentFn??w,this.resolveCatalogFn=e.resolveCatalogFn??f,this.inspectVcsContext=e.inspectVcsContext??L,this.shellEnv={...e.shellEnv??process.env},this.onShellCommandSpawn=e.onShellCommandSpawn}async acquireDefaultAgentUsage(e,t,s){const i=await c(e,this.config.agents.dataDir,t,{holderKind:"chat",startIfStopped:!0,...s?{signal:s}:{}});if(void 0!==i)return i;await ee(e,this.config.agents.dataDir,t,s)}async createSession(t={}){this.assertAcceptingSessions();const s=await this.ensureReady();this.assertAcceptingSessions();const i=this.store?this.store.createThread({...void 0===t.id?{}:{id:t.id},...void 0===t.origin?{}:{origin:t.origin},...t.title?{title:t.title}:{},model:this.resolveModelName()}):t.id??e();return this.buildSession(s,i,[])}async resumeSession(e){if(this.assertAcceptingSessions(),!this.store)throw new Error("resumeSession requires a ThreadStore");if("scheduled"===this.store.getThread(e)?.origin.kind)throw new Error("定时执行会话是只读记录;请基于该次运行创建新对话");const t=this.liveSessions.get(e);if(void 0!==t)return t;if(!this.store.hasThread(e))throw new Error(`Thread "${e}" 不存在`);const s=await this.ensureReady();this.assertAcceptingSessions();const i=this.liveSessions.get(e);if(void 0!==i)return i;this.recoverUncoveredToolExecutionContext(e);const o=this.store.loadSessionState(e);return this.buildSession(s,e,o.messages,o.checkpoint)}async forkSession(e,t={}){if(this.assertAcceptingSessions(),!this.store)throw new Error("forkSession requires a ThreadStore");const s=await this.ensureReady();this.assertAcceptingSessions();const i=this.store.forkSnapshot(e,{...t,model:this.resolveModelName()});try{this.recoverUncoveredToolExecutionContext(i);const e=this.store.loadSessionState(i);return this.buildSession(s,i,e.messages,e.checkpoint)}catch(e){throw this.store.deleteThread(i),e}}assertAcceptingSessions(){if(this.closing)throw H()}resolveRuntimeShellProfile(){if(!this.config.runtime.shell.enabled)return;if(void 0!==this.explicitShellProfile)return this.explicitShellProfile??void 0;void 0===this.shellProfileResolution&&(this.shellProfileResolution=this.resolveShellProfileFn({platform:process.platform,env:this.shellEnv}));const e=this.shellProfileResolution;if(e.supported)return e.profile;if(!this.shellUnsupportedWarned){this.shellUnsupportedWarned=!0;const t="pwsh-version-unsupported"===e.reason?"检测到的 pwsh 版本低于 7":"未检测到 PowerShell 7 (pwsh)";process.stderr.write(`roll chat: ${t},Windows 原生 shell 工具已跳过注册;可运行 winget install Microsoft.PowerShell\n`)}}resolveShellSettings(e){return buildSessionBashSettings({config:this.config,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}})}resolveSessionExecSettings(e){if(!this.sessionExecEnabled)return;const t=this.config.runtime.shell;return t.enabled&&t.session.enabled&&e.supportsSessionExec?buildSessionExecSettings({config:this.config,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}}):void 0}buildSession(e,t,s,i){const o=this.store,r=o?.getThread(t)?.derivedFrom,n=this.resolveContextWindowFor(this.resolveProviderName(),this.resolveModelName())?.window,a=(e.skillLibrary?.list()??[]).length>0?e.skillLibrary:void 0,l=this.resolveRuntimeShellProfile(),c=l?this.resolveShellSettings(l):void 0,d=this.fileToolsEnabled?{workdir:c?.workdir??process.cwd()}:void 0,h=l?this.resolveSessionExecSettings(l):void 0,u=l?l.supportsSafeCommandClassification&&this.config.runtime.shell.autoApproveSafe?l:N:void 0,p=M(this.hostMode)?this.resolveAgentInstallBinding():void 0,g=this.scheduleTools,m=this.composeCapabilityContext(e.sources.length,l),v=new x({id:t,model:this.activeModel(e),sources:e.sources,toolSchemaPolicy:this.toolSchemaPolicyFor(this.resolveProviderName()),onToolExcluded:e=>this.onAgentBootstrapIssue?.({agentName:e.agentName,message:`工具 "${e.toolName}" 的参数 schema 含当前 provider "${this.resolveToolSchemaProviderName()}" 无法接受的引用(${e.issues.map(e=>e.ref).join("、")}),已从本会话工具集移除`}),capabilityContext:m,resolveDynamicCapabilityContext:async e=>{const[t,s]=await Promise.all([this.inspectVcsContext(m.cwd),this.resolveDynamicCapabilityContext?.(e)??{}]),i=s.vcs??t;return{...s.ruleIds?{ruleIds:s.ruleIds}:{},...i?{vcs:i}:{},...s.origin?{origin:s.origin}:{}}},...a?{skillLibrary:a}:{},...this.workspaceInstructions?{workspaceInstructions:this.workspaceInstructions}:{},...d?{fileTools:d}:{},...c?{bash:c}:{},...u?{bashClassifier:u}:{},...h?{bashSession:h}:{},...p?{agentInstall:p}:{},...g?{schedules:{port:g,sessionCwd:m.cwd,includeCreate:T(this.hostMode)}}:{},maxSteps:this.maxSteps,compaction:this.config.runtime.compaction,turnTimeoutMs:this.config.runtime.turnTimeoutMs,debugEvents:this.debugEvents,...this.providerOptions?{providerOptions:this.providerOptions}:{},...this.structuredOutputProviderOptions?{structuredOutputProviderOptions:this.structuredOutputProviderOptions}:{},...this.structuredOutputReasoning?{structuredOutputReasoning:this.structuredOutputReasoning}:{},onProviderOptionsChange:e=>this.syncProviderOptions(e),...void 0!==n?{contextWindow:n}:{},...this.policy?{policy:this.policy}:{},initialMessages:s,...void 0!==r?{derivedFrom:r}:{},...i?{initialCheckpoint:i}:{},...o?{onPersist:(e,s)=>o.appendMessages(t,e,s),onReplace:e=>o.replaceMessages(t,e),onToolExecution:e=>o.appendToolExecution(t,e),listToolExecutions:e=>o.listToolExecutions(t,e),getToolExecution:e=>o.getToolExecution(t,e),recoverUncoveredToolExecutions:()=>this.recoverUncoveredToolExecutionContext(t),listTranscriptMessages:e=>o.listTranscriptMessages(t,e),commitCompaction:e=>o.commitCompaction(t,e),readCheckpointTranscript:e=>o.readCheckpointTranscript(t,e)}:{},onClose:()=>{this.liveSessions.get(t)===v&&this.liveSessions.delete(t)}});return this.liveSessions.set(t,v),v}recoverUncoveredToolExecutionContext(e){const t=this.store?.recoverUncoveredToolExecutions(e,B);return void 0===t?[]:[t]}syncProviderOptions(e){this.providerOptions=e,this.clientManager.setSamplingProviderOptions(e)}switchModel(e){this.assertAcceptingSessions();const t=this.resolveContextWindowFor(e.provider,e.modelName),s=t?.window,i={model:e.model,...void 0!==s?{contextWindow:s}:{},...e.providerOptions?{providerOptions:e.providerOptions}:{},...e.structuredOutputProviderOptions?{structuredOutputProviderOptions:e.structuredOutputProviderOptions}:{},...e.structuredOutputReasoning?{structuredOutputReasoning:e.structuredOutputReasoning}:{},toolSchemaPolicy:this.toolSchemaPolicyFor(e.provider)};for(const e of this.liveSessions.values())if(!e.canSwitchModel())throw new Error("存在正在生成回复的会话,稍后再切换模型");this.switchingProviderName=e.provider;try{for(const e of this.liveSessions.values())e.switchModel(i)}finally{this.switchingProviderName=void 0}this.modelOverride=e.model,this.modelNameOverride=e.modelName,this.providerNameOverride=e.provider,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.clientManager.setSamplingModel(e.model),this.clientManager.setSamplingProviderOptions(e.providerOptions);for(const t of this.liveSessions.keys())this.store?.updateModel(t,e.modelName);return t}ensureReady(){return this.assertAcceptingSessions(),this.ready||(this.ready=this.bootstrap()),this.ready}async bootstrap(){const e=Date.now(),t=this.explicitModel??this.resolveModel();if(this.explicitSources)return{model:t,sources:this.explicitSources,...this.explicitSkillLibrary?{skillLibrary:this.explicitSkillLibrary}:{}};const s=this.explicitAgents??new o(this.config.agents.dataDir).list(),i=this.config.runtime.agentBootstrap.timeoutMs,r=e+i,n=new AbortController,a=new AgentBootstrapTimeoutError(i);let l=!1;const c=()=>{n.signal.aborted||n.abort(q(this.shutdownController.signal))},d=()=>{!this.closing&&!n.signal.aborted&&Date.now()>=r&&(l=!0,n.abort(a))};this.shutdownController.signal.aborted?c():this.shutdownController.signal.addEventListener("abort",c,{once:!0});const h=setTimeout(()=>{this.closing||n.signal.aborted||(l=!0,n.abort(a))},Math.max(0,r-Date.now())),u=(e,t)=>({kind:W.failed,issues:[{agentName:e.skill.name,message:a.message},...void 0===t?[]:[{agentName:e.skill.name,message:t.message}]]});try{if(this.agentInstallEnabled())try{this.resolvedCatalog=await this.resolveCatalogFn(this.config,{allowNetwork:!1,signal:n.signal,...this.config.install.registry?{registry:this.config.install.registry}:{}})}catch(e){if(this.closing||this.shutdownController.signal.aborted)throw H();if(d(),!l)throw e}if(this.closing||this.shutdownController.signal.aborted)throw H();if(d(),0===s.length){const e=this.resolveSkillLibrary(s);return{model:t,sources:[],...e?{skillLibrary:e}:{}}}const e=await U(s,R,async e=>{const s=[],i=e=>{s.push(e)};try{d(),V(n.signal);const o=await this.connectAgentSource(e,t,i,{signal:n.signal,deadlineAt:r});return{kind:W.connected,source:o,issues:s}}catch(t){if(this.closing||this.shutdownController.signal.aborted)throw H();return d(),l?u(e,t instanceof AgentBootstrapCleanupError?t:void 0):(s.push({agentName:e.skill.name,message:t instanceof Error?t.message:String(t)}),{kind:W.failed,issues:s})}},{signal:n.signal,onSkipped:e=>u(e)});if(this.closing||this.shutdownController.signal.aborted)throw H();const i=[];for(const t of e){for(const e of t.issues)this.onAgentBootstrapIssue?.(e);t.kind===W.connected&&i.push(t.source)}const o=this.resolveSkillLibrary(s);return{model:t,sources:i,...o?{skillLibrary:o}:{}}}finally{clearTimeout(h),this.shutdownController.signal.removeEventListener("abort",c)}}async connectAgentSource(e,t,s=e=>this.onAgentBootstrapIssue?.(e),i={}){this.assertAcceptingSessions(),V(i.signal),K(i.deadlineAt);const o=r(e),n=g(this.config,e.skill.name),a=this.agentUsageLeases.get(e.skill.name);let l,c;try{l=void 0===a?await this.acquireAgentUsage(e,n,i.signal):void 0,this.assertAcceptingSessions(),V(i.signal),K(i.deadlineAt);const r={timeoutMs:_(F,i.deadlineAt),samplingModel:t,...this.providerOptions?{samplingProviderOptions:this.providerOptions}:{},...n?{env:n}:{},...i.signal?{signal:i.signal}:{}},d=this.clientManager.connectWithOwnership;c="function"==typeof d?await d.call(this.clientManager,e.skill.name,o,e.installPath,r):{client:await this.clientManager.connect(e.skill.name,o,e.installPath,r),commit:()=>{},rollback:async()=>{}},this.assertAcceptingSessions(),V(i.signal),K(i.deadlineAt);const g=(await c.client.listTools(void 0,{timeout:_(D,i.deadlineAt),...i.signal?{signal:i.signal}:{}})).tools;this.assertAcceptingSessions(),V(i.signal),K(i.deadlineAt);const m=p(g,{onAppOutputIssue:t=>s({agentName:e.skill.name,message:u(e.skill.name,t)}),onSchemaIssue:t=>s({agentName:e.skill.name,message:h(e.skill.name,t)})}).map((t,i)=>{const o=X(g[i]);return void 0!==o.issue&&s({agentName:e.skill.name,message:`Tool "${t.name}" 的 ${S} 无效(${o.issue}),已回退 Agent 级资源锁`}),{tool:t,annotations:Y(g[i]),...o.hints?{resourceHints:o.hints}:{}}});return c.commit(),void 0!==l&&this.agentUsageLeases.set(e.skill.name,l),{agentName:e.skill.name,client:c.client,tools:m,...e.source?{agentSource:e.source.type}:{},transport:o.type,runtimeOwnership:e.runtime.ownership,..."stdio"===o.type?{resourceBaseDir:e.installPath}:{}}}catch(t){const s=[];if(void 0!==c&&await c.rollback().catch(e=>{s.push(e)}),void 0!==l){const t=l;await t.release().catch(i=>{this.agentUsageLeases.set(e.skill.name,t),s.push(i)})}if(s.length>0)throw new AgentBootstrapCleanupError(e.skill.name,t,s);throw t}}async prepareAgentRefresh(e){this.assertAcceptingSessions();const t=this.refreshChain.then(()=>this.runAgentRefresh(e));return this.refreshChain=t.then(()=>{},()=>{}),t}async runAgentRefresh(e){const t=await this.ensureReady(),s=await this.connectAgentSource(e,this.activeModel(t),void 0,{signal:this.shutdownController.signal}),i=[...t.sources.filter(e=>e.agentName!==s.agentName),s],r=this.explicitAgents??new o(this.config.agents.dataDir).list(),n=this.resolveSkillLibrary(r);this.ready=Promise.resolve({model:this.activeModel(t),sources:i,...n?{skillLibrary:n}:{}});const a=n?.list()??[],l=n&&a.length>0?n:void 0,c=this.resolveRuntimeShellProfile();return{source:s,...l?{skillLibrary:l}:{},capabilityContext:this.composeCapabilityContext(i.length,c)}}composeCapabilityContext(e,t){const s=this.resolveAgentOnboardingInfo();return{profile:t?.toolName??"no-shell",hostMode:this.hostMode,cwd:process.cwd(),platform:process.platform,...t?{shellHints:t.systemPromptHints()}:{},agentCount:e,...s?{agentOnboardingCatalog:s}:{}}}agentInstallEnabled(){return void 0===this.explicitSources&&void 0===this.explicitAgents}currentCatalog(){return this.resolvedCatalog??v(this.config)}resolveAgentOnboardingInfo(){if(!this.agentInstallEnabled())return;const e=this.currentCatalog();return 0!==e.length?e.map(e=>({shortName:e.shortName,description:e.description})):void 0}resolveAgentInstallBinding(){if(!this.agentInstallEnabled())return;const e=this.currentCatalog();return 0!==e.length?{catalog:e.map(e=>({shortName:e.shortName,description:e.description})),install:(e,t)=>this.installCatalogAgent(e,t)}:void 0}async installCatalogAgent(e,t){const s=this.currentCatalog().find(t=>t.shortName===e);if(!s)return{outcome:{ok:!1,message:`未知的官方 Agent 短名: ${e}`}};const i=await this.installAgentFn({packageSpec:m(s),skipBrowserSetup:!0,autoStart:!1,expectedSkillName:s.skillName},{agentsConfig:this.config.agents,installConfig:this.config.install,getStartEnv:e=>g(this.config,e),report:e=>t(Z(e))});if(!i.ok)return{outcome:{ok:!1,message:i.message,...i.retryCommand?{retryCommand:i.retryCommand}:{}}};const o=i.agent,r="installed-package"===o.source?.type?o.source.installedVersion:void 0,n="core-managed"===o.runtime.ownership&&void 0!==o.runtime.setup?.playwright,a={ok:!0,agentName:o.skill.name,...r?{version:r}:{},missingEnv:(i.envReport?.missingRequired??[]).map(e=>e.name),...n?{retryCommand:`roll agent install ${s.shortName}`}:{},refreshApplied:!1};if((await this.ensureReady()).sources.some(e=>e.agentName===o.skill.name))return t(`Agent "${o.skill.name}" 本会话已接入旧版本连接,更新需重启 roll chat 生效。`),{outcome:a};try{return{outcome:a,refresh:await this.prepareAgentRefresh(o)}}catch(e){return t(`接入新 Agent 失败:${e instanceof Error?e.message:String(e)}`),{outcome:a}}}resolveSkillLibrary(e){if(null!==this.explicitSkillLibrary)return void 0!==this.explicitSkillLibrary?this.explicitSkillLibrary:y({agents:e,extraDirs:this.config.skills.dirs,...this.onSkillLibraryIssue?{onIssue:this.onSkillLibraryIssue}:{}})}resolveModel(){const e=this.resolveProviderName(),t=this.resolveModelName(),i=this.config.llm.providers[e];if(!i)throw new Error(`LLM provider "${e}" 未配置`);return s(e,t,i.apiKey,i.baseUrl)}resolveProviderName(){return this.providerNameOverride??this.config.runtime.provider??this.config.llm.defaultProvider}resolveContextWindowFor(e,t){return k({provider:e,model:t,...void 0!==this.config.runtime.contextWindow?{override:this.config.runtime.contextWindow}:{},catalog:this.modelCatalog})}resolveModelName(){return this.modelNameOverride??this.config.runtime.model??this.config.llm.defaultModel}toolSchemaPolicyFor(e){return t=>i(e,t)}resolveToolSchemaProviderName(){return this.switchingProviderName??this.resolveProviderName()}activeModel(e){return this.modelOverride??e.model}async getContextSummary(){const e=await this.ensureReady();this.assertAcceptingSessions();const t=this.workspaceInstructions?.current()?.path;return{agentCount:e.sources.length,toolCount:e.sources.reduce((e,t)=>e+t.tools.length,0),skillCount:e.skillLibrary?.list().length??0,...void 0!==t?{instructionsPath:t}:{}}}async releaseAgentUsageLeases(){const e=[...this.agentUsageLeases.entries()],t=await Promise.allSettled(e.map(async([e,t])=>{try{await t.release()}finally{this.agentUsageLeases.get(e)===t&&this.agentUsageLeases.delete(e)}}));for(const e of t)"rejected"===e.status&&process.stderr.write(`roll chat: Agent 使用租约释放失败: ${e.reason instanceof Error?e.reason.message:String(e.reason)}\n`)}async dispose(){if(void 0!==this.disposePromise)return this.disposePromise;this.closing=!0,this.shutdownController.abort(H());const e=Promise.allSettled([...this.ready?[this.ready]:[],this.refreshChain]).then(()=>{});return this.disposePromise=(async()=>{let t={failed:!1};try{await Promise.all([...this.liveSessions.values()].map(e=>e.close()))}catch(e){t={failed:!0,error:e}}this.liveSessions.clear(),await e;let s={failed:!1};try{await this.clientManager.disconnectAll(d(this.agentUsageLeases.values()))}catch(e){s={failed:!0,error:e}}if(await this.releaseAgentUsageLeases(),t.failed&&s.failed)throw new AggregateError([t.error,s.error],"ConversationEngine 关闭 session 与 MCP 连接均失败。");if(t.failed)throw t.error;if(s.failed)throw s.error})(),this.disposePromise}}
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{OBSERVATION_RETENTION_META_KEY as t,observationRetentionDeclarationSchema as s}from"@roll-agent/protocol/observation-retention";import{McpClientManager as i}from"@roll-agent/core/mcp/client-manager";import{createProviderModel as o,providerAcceptsToolSchemaIssues as r}from"@roll-agent/core/llm/providers";import{AgentStore as n}from"@roll-agent/core/registry/store";import{resolveTransportWithDevSpawnSpec as a}from"@roll-agent/core/registry/dev-spawn";import{getAgentPid as l,startAgent as c,waitForAgentReady as d}from"@roll-agent/core/registry/process-manager";import{acquireAgentUsageLease as h,getExitedAgentUsageNames as u}from"@roll-agent/core/registry/agent-usage-lease";import{formatToolSchemaIssue as p,formatAppOutputDiscoveryIssue as g,normalizeListedTools as m}from"@roll-agent/core/cli/utils/agent-tools";import{getAgentEnv as v}from"@roll-agent/core/config/helpers";import{catalogPackageSpec as f,getAgentCatalog as w}from"@roll-agent/core/registry/catalog";import{resolveAgentCatalog as y}from"@roll-agent/core/registry/catalog-discovery";import{installAgent as S}from"@roll-agent/core/registry/install";import{createSkillLibrary as b}from"@roll-agent/core/skills/library";import{ROLL_RESOURCE_HINTS_META_KEY as C}from"../tool-bridge/build-tools.js";import{TOOL_RESOURCE_ACCESS_MODES as k,TOOL_RESOURCE_HINT_KINDS as x}from"../tool-bridge/tool-execution-coordinator.js";import{AgentSession as A}from"./agent-session.js";import{resolveModelContextWindow as O}from"./context-window.js";import{createDefaultModelCatalog as E}from"./model-catalog-default.js";import{createWorkspaceInstructionsSource as P,parseWorkspaceInstructionsSetting as M}from"./workspace-instructions.js";import{CAPABILITY_HOST_MODES as T,shouldOfferAgentInstall as N,shouldOfferScheduleCreate as I}from"./capability-manifest.js";import{}from"../tool-bridge/bash-tool.js";import{unknownCommandClassifier as L}from"../types/command-classification.js";import{resolveShellProfile as R}from"../bash/profile.js";import{inspectGitVcsContext as U}from"./vcs-context.js";import{AGENT_BOOTSTRAP_MAX_CONCURRENCY as $,mapWithBoundedConcurrency as j}from"./agent-bootstrap.js";import{createToolLedgerGapRecoveryMessage as B}from"./cancelled-turn-recovery.js";const F=80,D="ConversationEngine is closing",W=3e4,H=6e4,q={connected:"connected",failed:"failed"};export function buildSessionExecSettings(e){const t=e.config.runtime.shell;return{workdir:process.cwd(),profile:e.profile,maxSessions:t.session.maxSessions,defaultYieldMs:t.session.defaultYieldMs,maxOutputTokens:t.session.maxOutputTokens,bufferCapacity:t.maxCaptureBytes,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}export function buildSessionBashSettings(e){const t=e.config.runtime.shell;return{workdir:process.cwd(),defaultTimeoutMs:t.defaultTimeoutMs,maxTimeoutMs:t.maxTimeoutMs,turnTimeoutMs:e.config.runtime.turnTimeoutMs,maxCaptureBytes:t.maxCaptureBytes,maxModelOutputChars:t.maxModelOutputChars,profile:e.profile,env:e.env,...e.onCommandSpawn?{onCommandSpawn:e.onCommandSpawn}:{}}}class AgentBootstrapTimeoutError extends Error{constructor(e){super(`Agent bootstrap timed out after ${String(e)}ms`),this.name="AgentBootstrapTimeoutError"}}class AgentBootstrapCleanupError extends AggregateError{cleanupErrors;constructor(e,t,s){const i=s.map(e=>e instanceof Error?e.message:String(e)).join("; ");super([t,...s],`Agent "${e}" bootstrap failed and resource cleanup also failed: ${i}`),this.name="AgentBootstrapCleanupError",this.cleanupErrors=s}}function _(){return new Error(D)}function V(e){return e.reason??new Error("Operation aborted")}function K(e){if(!0===e?.aborted)throw V(e)}function Y(e,t){return void 0===t?e:Math.max(1,Math.min(e,t-Date.now()))}function z(e){if(void 0!==e&&Date.now()>=e)throw new Error("Agent bootstrap deadline expired")}function G(e){if("object"!=typeof e||null===e||!("annotations"in e))return;const t=e.annotations;if("object"!=typeof t||null===t)return;const s={};return"readOnlyHint"in t&&"boolean"==typeof t.readOnlyHint&&(s.readOnlyHint=t.readOnlyHint),"destructiveHint"in t&&"boolean"==typeof t.destructiveHint&&(s.destructiveHint=t.destructiveHint),void 0===s.readOnlyHint&&void 0===s.destructiveHint?void 0:s}function J(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function Q(e){if(!J(e)||!J(e._meta))return{};if(!Object.hasOwn(e._meta,t))return{};const i=s.safeParse(e._meta[t]);return i.success?{declaration:i.data}:{issue:"声明字段无效"}}function X(e){return Object.values(x).some(t=>t===e)}function Z(e){return Object.values(k).some(t=>t===e)}function ee(e){return{hints:void 0,issue:e}}function te(e){if(!J(e)||!J(e._meta))return{hints:void 0,issue:void 0};if(!Object.hasOwn(e._meta,C))return{hints:void 0,issue:void 0};const t=e._meta[C];if(!Array.isArray(t))return ee("必须是数组");const s=[];for(const[e,i]of t.entries()){if(!J(i)||"string"!=typeof i.field||0===i.field.trim().length||"string"!=typeof i.kind||!X(i.kind)||void 0!==i.mode&&("string"!=typeof i.mode||!Z(i.mode))||void 0!==i.namespace&&"string"!=typeof i.namespace||i.kind===x.custom&&("string"!=typeof i.namespace||0===i.namespace.trim().length))return ee(`第 ${String(e+1)} 项字段无效`);const t=i.kind===x.custom&&"string"==typeof i.namespace?i.namespace.trim():void 0;s.push({field:i.field.trim(),kind:i.kind,...void 0!==i.mode?{mode:i.mode}:{},...void 0!==t?{namespace:t}:{}})}return{hints:s.length>0?s:void 0,issue:void 0}}function se(e){return"retry"===e.type?`安装遇到网络问题,${Math.round(e.delayMs/1e3)}s 后重试(第 ${e.attempt+1} 次)...`:"warn"===e.type?`警告:${e.message}`:e.message}async function ie(e,t,s,i){K(i),"core-managed"===e.runtime.ownership&&(void 0===l(t,e.skill.name)&&c(e,t,s),await d(e,{...i?{signal:i}:{}}))}function oe(e){if(null===e.workspaceInstructions)return;if(void 0!==e.workspaceInstructions)return e.workspaceInstructions;const t=process.cwd();return P({cwd:t,setting:M(e.config.chat.instructions,t),...e.onWorkspaceInstructionsIssue?{onIssue:e.onWorkspaceInstructionsIssue}:{}})}export class ConversationEngine{config;clientManager;store;policy;fileToolsEnabled;maxSteps;providerOptions;modelOverride;modelNameOverride;providerNameOverride;switchingProviderName;modelCatalog;structuredOutputProviderOptions;structuredOutputReasoning;acquireAgentUsage;debugEvents;explicitAgents;explicitModel;explicitSources;explicitSkillLibrary;onSkillLibraryIssue;workspaceInstructions;onAgentBootstrapIssue;hostMode;scheduleTools;resolveDynamicCapabilityContext;sessionExecEnabled;explicitShellProfile;resolveShellProfileFn;installAgentFn;resolveCatalogFn;inspectVcsContext;shellEnv;onShellCommandSpawn;ready;refreshChain=Promise.resolve();resolvedCatalog;shellProfileResolution;shellUnsupportedWarned=!1;liveSessions=new Map;agentUsageLeases=new Map;shutdownController=new AbortController;disposePromise;closing=!1;constructor(e){this.config=e.config,this.clientManager=e.clientManager??new i,this.store=e.store,this.modelCatalog=e.modelCatalog??E(),this.policy=e.policy,this.fileToolsEnabled=e.fileToolsEnabled??!0,this.maxSteps=e.maxSteps??F,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.acquireAgentUsage=e.acquireAgentUsage??(e.ensureAgentReady?async(t,s,i)=>{await(e.ensureAgentReady?.(t,s,i))}:(e,t,s)=>this.acquireDefaultAgentUsage(e,t,s)),this.debugEvents=e.debugEvents??!1,this.hostMode=e.hostMode??T.embedded,this.scheduleTools=e.scheduleTools??void 0,this.resolveDynamicCapabilityContext=e.resolveDynamicCapabilityContext,this.sessionExecEnabled=e.sessionExecEnabled??!0,this.explicitShellProfile=e.shellProfile,this.resolveShellProfileFn=e.resolveShellProfileFn??R,this.explicitAgents=e.agents,this.explicitModel=e.model,this.explicitSources=e.sources,this.explicitSkillLibrary=e.skillLibrary,this.onSkillLibraryIssue=e.onSkillLibraryIssue,this.workspaceInstructions=oe(e),this.onAgentBootstrapIssue=e.onAgentBootstrapIssue,this.installAgentFn=e.installAgentFn??S,this.resolveCatalogFn=e.resolveCatalogFn??y,this.inspectVcsContext=e.inspectVcsContext??U,this.shellEnv={...e.shellEnv??process.env},this.onShellCommandSpawn=e.onShellCommandSpawn}async acquireDefaultAgentUsage(e,t,s){const i=await h(e,this.config.agents.dataDir,t,{holderKind:"chat",startIfStopped:!0,...s?{signal:s}:{}});if(void 0!==i)return i;await ie(e,this.config.agents.dataDir,t,s)}async createSession(t={}){this.assertAcceptingSessions();const s=await this.ensureReady();this.assertAcceptingSessions();const i=this.store?this.store.createThread({...void 0===t.id?{}:{id:t.id},...void 0===t.origin?{}:{origin:t.origin},...t.title?{title:t.title}:{},model:this.resolveModelName()}):t.id??e();return this.buildSession(s,i,[])}async resumeSession(e){if(this.assertAcceptingSessions(),!this.store)throw new Error("resumeSession requires a ThreadStore");if("scheduled"===this.store.getThread(e)?.origin.kind)throw new Error("定时执行会话是只读记录;请基于该次运行创建新对话");const t=this.liveSessions.get(e);if(void 0!==t)return t;if(!this.store.hasThread(e))throw new Error(`Thread "${e}" 不存在`);const s=await this.ensureReady();this.assertAcceptingSessions();const i=this.liveSessions.get(e);if(void 0!==i)return i;this.recoverUncoveredToolExecutionContext(e);const o=this.store.loadSessionState(e);return this.buildSession(s,e,o.messages,o.checkpoint)}async forkSession(e,t={}){if(this.assertAcceptingSessions(),!this.store)throw new Error("forkSession requires a ThreadStore");const s=await this.ensureReady();this.assertAcceptingSessions();const i=this.store.forkSnapshot(e,{...t,model:this.resolveModelName()});try{this.recoverUncoveredToolExecutionContext(i);const e=this.store.loadSessionState(i);return this.buildSession(s,i,e.messages,e.checkpoint)}catch(e){throw this.store.deleteThread(i),e}}assertAcceptingSessions(){if(this.closing)throw _()}resolveRuntimeShellProfile(){if(!this.config.runtime.shell.enabled)return;if(void 0!==this.explicitShellProfile)return this.explicitShellProfile??void 0;void 0===this.shellProfileResolution&&(this.shellProfileResolution=this.resolveShellProfileFn({platform:process.platform,env:this.shellEnv}));const e=this.shellProfileResolution;if(e.supported)return e.profile;if(!this.shellUnsupportedWarned){this.shellUnsupportedWarned=!0;const t="pwsh-version-unsupported"===e.reason?"检测到的 pwsh 版本低于 7":"未检测到 PowerShell 7 (pwsh)";process.stderr.write(`roll chat: ${t},Windows 原生 shell 工具已跳过注册;可运行 winget install Microsoft.PowerShell\n`)}}resolveShellSettings(e){return buildSessionBashSettings({config:this.config,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}})}resolveSessionExecSettings(e){if(!this.sessionExecEnabled)return;const t=this.config.runtime.shell;return t.enabled&&t.session.enabled&&e.supportsSessionExec?buildSessionExecSettings({config:this.config,profile:e,env:this.shellEnv,...this.onShellCommandSpawn?{onCommandSpawn:this.onShellCommandSpawn}:{}}):void 0}buildSession(e,t,s,i){const o=this.store,r=o?.getThread(t)?.derivedFrom,n=this.resolveContextWindowFor(this.resolveProviderName(),this.resolveModelName())?.window,a=(e.skillLibrary?.list()??[]).length>0?e.skillLibrary:void 0,l=this.resolveRuntimeShellProfile(),c=l?this.resolveShellSettings(l):void 0,d=this.fileToolsEnabled?{workdir:c?.workdir??process.cwd()}:void 0,h=l?this.resolveSessionExecSettings(l):void 0,u=l?l.supportsSafeCommandClassification&&this.config.runtime.shell.autoApproveSafe?l:L:void 0,p=N(this.hostMode)?this.resolveAgentInstallBinding():void 0,g=this.scheduleTools,m=this.composeCapabilityContext(e.sources.length,l),v=new A({id:t,model:this.activeModel(e),sources:e.sources,toolSchemaPolicy:this.toolSchemaPolicyFor(this.resolveProviderName()),onToolExcluded:e=>this.onAgentBootstrapIssue?.({agentName:e.agentName,message:`工具 "${e.toolName}" 的参数 schema 含当前 provider "${this.resolveToolSchemaProviderName()}" 无法接受的引用(${e.issues.map(e=>e.ref).join("、")}),已从本会话工具集移除`}),capabilityContext:m,resolveDynamicCapabilityContext:async e=>{const[t,s]=await Promise.all([this.inspectVcsContext(m.cwd),this.resolveDynamicCapabilityContext?.(e)??{}]),i=s.vcs??t;return{...s.ruleIds?{ruleIds:s.ruleIds}:{},...i?{vcs:i}:{},...s.origin?{origin:s.origin}:{}}},...a?{skillLibrary:a}:{},...this.workspaceInstructions?{workspaceInstructions:this.workspaceInstructions}:{},...d?{fileTools:d}:{},...c?{bash:c}:{},...u?{bashClassifier:u}:{},...h?{bashSession:h}:{},...p?{agentInstall:p}:{},...g?{schedules:{port:g,sessionCwd:m.cwd,includeCreate:I(this.hostMode)}}:{},maxSteps:this.maxSteps,compaction:this.config.runtime.compaction,turnTimeoutMs:this.config.runtime.turnTimeoutMs,debugEvents:this.debugEvents,...this.providerOptions?{providerOptions:this.providerOptions}:{},...this.structuredOutputProviderOptions?{structuredOutputProviderOptions:this.structuredOutputProviderOptions}:{},...this.structuredOutputReasoning?{structuredOutputReasoning:this.structuredOutputReasoning}:{},onProviderOptionsChange:e=>this.syncProviderOptions(e),...void 0!==n?{contextWindow:n}:{},...this.policy?{policy:this.policy}:{},initialMessages:s,...void 0!==r?{derivedFrom:r}:{},...i?{initialCheckpoint:i}:{},...o?{onPersist:(e,s)=>o.appendMessages(t,e,s),onReplace:e=>o.replaceMessages(t,e),onToolExecution:e=>o.appendToolExecution(t,e),listToolExecutions:e=>o.listToolExecutions(t,e),getToolExecution:e=>o.getToolExecution(t,e),recoverUncoveredToolExecutions:()=>this.recoverUncoveredToolExecutionContext(t),listTranscriptMessages:e=>o.listTranscriptMessages(t,e),commitCompaction:e=>o.commitCompaction(t,e),readCheckpointTranscript:e=>o.readCheckpointTranscript(t,e)}:{},onClose:()=>{this.liveSessions.get(t)===v&&this.liveSessions.delete(t)}});return this.liveSessions.set(t,v),v}recoverUncoveredToolExecutionContext(e){const t=this.store?.recoverUncoveredToolExecutions(e,B);return void 0===t?[]:[t]}syncProviderOptions(e){this.providerOptions=e,this.clientManager.setSamplingProviderOptions(e)}switchModel(e){this.assertAcceptingSessions();const t=this.resolveContextWindowFor(e.provider,e.modelName),s=t?.window,i={model:e.model,...void 0!==s?{contextWindow:s}:{},...e.providerOptions?{providerOptions:e.providerOptions}:{},...e.structuredOutputProviderOptions?{structuredOutputProviderOptions:e.structuredOutputProviderOptions}:{},...e.structuredOutputReasoning?{structuredOutputReasoning:e.structuredOutputReasoning}:{},toolSchemaPolicy:this.toolSchemaPolicyFor(e.provider)};for(const e of this.liveSessions.values())if(!e.canSwitchModel())throw new Error("存在正在生成回复的会话,稍后再切换模型");this.switchingProviderName=e.provider;try{for(const e of this.liveSessions.values())e.switchModel(i)}finally{this.switchingProviderName=void 0}this.modelOverride=e.model,this.modelNameOverride=e.modelName,this.providerNameOverride=e.provider,this.providerOptions=e.providerOptions,this.structuredOutputProviderOptions=e.structuredOutputProviderOptions,this.structuredOutputReasoning=e.structuredOutputReasoning,this.clientManager.setSamplingModel(e.model),this.clientManager.setSamplingProviderOptions(e.providerOptions);for(const t of this.liveSessions.keys())this.store?.updateModel(t,e.modelName);return t}ensureReady(){return this.assertAcceptingSessions(),this.ready||(this.ready=this.bootstrap()),this.ready}async bootstrap(){const e=Date.now(),t=this.explicitModel??this.resolveModel();if(this.explicitSources)return{model:t,sources:this.explicitSources,...this.explicitSkillLibrary?{skillLibrary:this.explicitSkillLibrary}:{}};const s=this.explicitAgents??new n(this.config.agents.dataDir).list(),i=this.config.runtime.agentBootstrap.timeoutMs,o=e+i,r=new AbortController,a=new AgentBootstrapTimeoutError(i);let l=!1;const c=()=>{r.signal.aborted||r.abort(V(this.shutdownController.signal))},d=()=>{!this.closing&&!r.signal.aborted&&Date.now()>=o&&(l=!0,r.abort(a))};this.shutdownController.signal.aborted?c():this.shutdownController.signal.addEventListener("abort",c,{once:!0});const h=setTimeout(()=>{this.closing||r.signal.aborted||(l=!0,r.abort(a))},Math.max(0,o-Date.now())),u=(e,t)=>({kind:q.failed,issues:[{agentName:e.skill.name,message:a.message},...void 0===t?[]:[{agentName:e.skill.name,message:t.message}]]});try{if(this.agentInstallEnabled())try{this.resolvedCatalog=await this.resolveCatalogFn(this.config,{allowNetwork:!1,signal:r.signal,...this.config.install.registry?{registry:this.config.install.registry}:{}})}catch(e){if(this.closing||this.shutdownController.signal.aborted)throw _();if(d(),!l)throw e}if(this.closing||this.shutdownController.signal.aborted)throw _();if(d(),0===s.length){const e=this.resolveSkillLibrary(s);return{model:t,sources:[],...e?{skillLibrary:e}:{}}}const e=await j(s,$,async e=>{const s=[],i=e=>{s.push(e)};try{d(),K(r.signal);const n=await this.connectAgentSource(e,t,i,{signal:r.signal,deadlineAt:o});return{kind:q.connected,source:n,issues:s}}catch(t){if(this.closing||this.shutdownController.signal.aborted)throw _();return d(),l?u(e,t instanceof AgentBootstrapCleanupError?t:void 0):(s.push({agentName:e.skill.name,message:t instanceof Error?t.message:String(t)}),{kind:q.failed,issues:s})}},{signal:r.signal,onSkipped:e=>u(e)});if(this.closing||this.shutdownController.signal.aborted)throw _();const i=[];for(const t of e){for(const e of t.issues)this.onAgentBootstrapIssue?.(e);t.kind===q.connected&&i.push(t.source)}const n=this.resolveSkillLibrary(s);return{model:t,sources:i,...n?{skillLibrary:n}:{}}}finally{clearTimeout(h),this.shutdownController.signal.removeEventListener("abort",c)}}async connectAgentSource(e,s,i=e=>this.onAgentBootstrapIssue?.(e),o={}){this.assertAcceptingSessions(),K(o.signal),z(o.deadlineAt);const r=a(e),n=v(this.config,e.skill.name),l=this.agentUsageLeases.get(e.skill.name);let c,d;try{c=void 0===l?await this.acquireAgentUsage(e,n,o.signal):void 0,this.assertAcceptingSessions(),K(o.signal),z(o.deadlineAt);const a={timeoutMs:Y(W,o.deadlineAt),samplingModel:s,...this.providerOptions?{samplingProviderOptions:this.providerOptions}:{},...n?{env:n}:{},...o.signal?{signal:o.signal}:{}},h=this.clientManager.connectWithOwnership;d="function"==typeof h?await h.call(this.clientManager,e.skill.name,r,e.installPath,a):{client:await this.clientManager.connect(e.skill.name,r,e.installPath,a),commit:()=>{},rollback:async()=>{}},this.assertAcceptingSessions(),K(o.signal),z(o.deadlineAt);const u=(await d.client.listTools(void 0,{timeout:Y(H,o.deadlineAt),...o.signal?{signal:o.signal}:{}})).tools;this.assertAcceptingSessions(),K(o.signal),z(o.deadlineAt);const v=m(u,{onAppOutputIssue:t=>i({agentName:e.skill.name,message:g(e.skill.name,t)}),onSchemaIssue:t=>i({agentName:e.skill.name,message:p(e.skill.name,t)})}).map((s,o)=>{const r=te(u[o]),n=Q(u[o]);return n.issue&&i({agentName:e.skill.name,message:`Tool "${s.name}" 的 ${t} 无效(${n.issue}),观察历史保持原样`}),void 0!==r.issue&&i({agentName:e.skill.name,message:`Tool "${s.name}" 的 ${C} 无效(${r.issue}),已回退 Agent 级资源锁`}),{tool:s,annotations:G(u[o]),...r.hints?{resourceHints:r.hints}:{},...n.declaration?{observationRetention:n.declaration}:{}}});return d.commit(),void 0!==c&&this.agentUsageLeases.set(e.skill.name,c),{agentName:e.skill.name,client:d.client,tools:v,...e.source?{agentSource:e.source.type}:{},transport:r.type,runtimeOwnership:e.runtime.ownership,..."stdio"===r.type?{resourceBaseDir:e.installPath}:{}}}catch(t){const s=[];if(void 0!==d&&await d.rollback().catch(e=>{s.push(e)}),void 0!==c){const t=c;await t.release().catch(i=>{this.agentUsageLeases.set(e.skill.name,t),s.push(i)})}if(s.length>0)throw new AgentBootstrapCleanupError(e.skill.name,t,s);throw t}}async prepareAgentRefresh(e){this.assertAcceptingSessions();const t=this.refreshChain.then(()=>this.runAgentRefresh(e));return this.refreshChain=t.then(()=>{},()=>{}),t}async runAgentRefresh(e){const t=await this.ensureReady(),s=await this.connectAgentSource(e,this.activeModel(t),void 0,{signal:this.shutdownController.signal}),i=[...t.sources.filter(e=>e.agentName!==s.agentName),s],o=this.explicitAgents??new n(this.config.agents.dataDir).list(),r=this.resolveSkillLibrary(o);this.ready=Promise.resolve({model:this.activeModel(t),sources:i,...r?{skillLibrary:r}:{}});const a=r?.list()??[],l=r&&a.length>0?r:void 0,c=this.resolveRuntimeShellProfile();return{source:s,...l?{skillLibrary:l}:{},capabilityContext:this.composeCapabilityContext(i.length,c)}}composeCapabilityContext(e,t){const s=this.resolveAgentOnboardingInfo();return{profile:t?.toolName??"no-shell",hostMode:this.hostMode,cwd:process.cwd(),platform:process.platform,...t?{shellHints:t.systemPromptHints()}:{},agentCount:e,...s?{agentOnboardingCatalog:s}:{}}}agentInstallEnabled(){return void 0===this.explicitSources&&void 0===this.explicitAgents}currentCatalog(){return this.resolvedCatalog??w(this.config)}resolveAgentOnboardingInfo(){if(!this.agentInstallEnabled())return;const e=this.currentCatalog();return 0!==e.length?e.map(e=>({shortName:e.shortName,description:e.description})):void 0}resolveAgentInstallBinding(){if(!this.agentInstallEnabled())return;const e=this.currentCatalog();return 0!==e.length?{catalog:e.map(e=>({shortName:e.shortName,description:e.description})),install:(e,t)=>this.installCatalogAgent(e,t)}:void 0}async installCatalogAgent(e,t){const s=this.currentCatalog().find(t=>t.shortName===e);if(!s)return{outcome:{ok:!1,message:`未知的官方 Agent 短名: ${e}`}};const i=await this.installAgentFn({packageSpec:f(s),skipBrowserSetup:!0,autoStart:!1,expectedSkillName:s.skillName},{agentsConfig:this.config.agents,installConfig:this.config.install,getStartEnv:e=>v(this.config,e),report:e=>t(se(e))});if(!i.ok)return{outcome:{ok:!1,message:i.message,...i.retryCommand?{retryCommand:i.retryCommand}:{}}};const o=i.agent,r="installed-package"===o.source?.type?o.source.installedVersion:void 0,n="core-managed"===o.runtime.ownership&&void 0!==o.runtime.setup?.playwright,a={ok:!0,agentName:o.skill.name,...r?{version:r}:{},missingEnv:(i.envReport?.missingRequired??[]).map(e=>e.name),...n?{retryCommand:`roll agent install ${s.shortName}`}:{},refreshApplied:!1};if((await this.ensureReady()).sources.some(e=>e.agentName===o.skill.name))return t(`Agent "${o.skill.name}" 本会话已接入旧版本连接,更新需重启 roll chat 生效。`),{outcome:a};try{return{outcome:a,refresh:await this.prepareAgentRefresh(o)}}catch(e){return t(`接入新 Agent 失败:${e instanceof Error?e.message:String(e)}`),{outcome:a}}}resolveSkillLibrary(e){if(null!==this.explicitSkillLibrary)return void 0!==this.explicitSkillLibrary?this.explicitSkillLibrary:b({agents:e,extraDirs:this.config.skills.dirs,...this.onSkillLibraryIssue?{onIssue:this.onSkillLibraryIssue}:{}})}resolveModel(){const e=this.resolveProviderName(),t=this.resolveModelName(),s=this.config.llm.providers[e];if(!s)throw new Error(`LLM provider "${e}" 未配置`);return o(e,t,s.apiKey,s.baseUrl)}resolveProviderName(){return this.providerNameOverride??this.config.runtime.provider??this.config.llm.defaultProvider}resolveContextWindowFor(e,t){return O({provider:e,model:t,...void 0!==this.config.runtime.contextWindow?{override:this.config.runtime.contextWindow}:{},catalog:this.modelCatalog})}resolveModelName(){return this.modelNameOverride??this.config.runtime.model??this.config.llm.defaultModel}toolSchemaPolicyFor(e){return t=>r(e,t)}resolveToolSchemaProviderName(){return this.switchingProviderName??this.resolveProviderName()}activeModel(e){return this.modelOverride??e.model}async getContextSummary(){const e=await this.ensureReady();this.assertAcceptingSessions();const t=this.workspaceInstructions?.current()?.path;return{agentCount:e.sources.length,toolCount:e.sources.reduce((e,t)=>e+t.tools.length,0),skillCount:e.skillLibrary?.list().length??0,...void 0!==t?{instructionsPath:t}:{}}}async releaseAgentUsageLeases(){const e=[...this.agentUsageLeases.entries()],t=await Promise.allSettled(e.map(async([e,t])=>{try{await t.release()}finally{this.agentUsageLeases.get(e)===t&&this.agentUsageLeases.delete(e)}}));for(const e of t)"rejected"===e.status&&process.stderr.write(`roll chat: Agent 使用租约释放失败: ${e.reason instanceof Error?e.reason.message:String(e.reason)}\n`)}async dispose(){if(void 0!==this.disposePromise)return this.disposePromise;this.closing=!0,this.shutdownController.abort(_());const e=Promise.allSettled([...this.ready?[this.ready]:[],this.refreshChain]).then(()=>{});return this.disposePromise=(async()=>{let t={failed:!1};try{await Promise.all([...this.liveSessions.values()].map(e=>e.close()))}catch(e){t={failed:!0,error:e}}this.liveSessions.clear(),await e;let s={failed:!1};try{await this.clientManager.disconnectAll(u(this.agentUsageLeases.values()))}catch(e){s={failed:!0,error:e}}if(await this.releaseAgentUsageLeases(),t.failed&&s.failed)throw new AggregateError([t.error,s.error],"ConversationEngine 关闭 session 与 MCP 连接均失败。");if(t.failed)throw t.error;if(s.failed)throw s.error})(),this.disposePromise}}
|
|
@@ -58,8 +58,8 @@ export declare const explicitSkillCheckpointV1Schema: z.ZodReadonly<z.ZodObject<
|
|
|
58
58
|
}>[] | undefined;
|
|
59
59
|
}>>;
|
|
60
60
|
}, "strip", z.ZodTypeAny, {
|
|
61
|
-
version: 1;
|
|
62
61
|
kind: "explicit-skill";
|
|
62
|
+
version: 1;
|
|
63
63
|
snapshot: Readonly<{
|
|
64
64
|
userPrompt: string;
|
|
65
65
|
skillNames: string[];
|
|
@@ -70,8 +70,8 @@ export declare const explicitSkillCheckpointV1Schema: z.ZodReadonly<z.ZodObject<
|
|
|
70
70
|
}>[] | undefined;
|
|
71
71
|
}>;
|
|
72
72
|
}, {
|
|
73
|
-
version: 1;
|
|
74
73
|
kind: "explicit-skill";
|
|
74
|
+
version: 1;
|
|
75
75
|
snapshot: Readonly<{
|
|
76
76
|
userPrompt: string;
|
|
77
77
|
skillNames: string[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ModelMessage } from "ai";
|
|
2
|
+
import type { ObservationRetentionDeclaration } from "@roll-agent/protocol/observation-retention";
|
|
3
|
+
import type { ToolModelOutput } from "../tool-bridge/normalize-result.ts";
|
|
4
|
+
type JsonRecord = Record<string, unknown>;
|
|
5
|
+
export interface Observation {
|
|
6
|
+
readonly page: JsonRecord;
|
|
7
|
+
readonly snapshot: JsonRecord;
|
|
8
|
+
readonly identity: string;
|
|
9
|
+
readonly resource: string;
|
|
10
|
+
readonly complete: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Read only successful, fully structured observations. Errors and clipped JSON are untouched. */
|
|
13
|
+
export declare function observationFromMcpRaw(raw: unknown, declaration: ObservationRetentionDeclaration | undefined): Observation | undefined;
|
|
14
|
+
export declare function observationFromModelOutput(output: unknown): Observation | undefined;
|
|
15
|
+
/** Model-only output; SDK/MCP raw output and canonical step results are not changed. */
|
|
16
|
+
export declare function currentObservationModelOutput(raw: unknown, declaration: ObservationRetentionDeclaration | undefined): ToolModelOutput | undefined;
|
|
17
|
+
/** Complete original MCP content for canonical step persistence, including large snapshots. */
|
|
18
|
+
export declare function canonicalObservationOutput(raw: unknown, declaration: ObservationRetentionDeclaration | undefined): ToolModelOutput | undefined;
|
|
19
|
+
export interface ObservationProjectionOptions {
|
|
20
|
+
readonly declarations: ReadonlyMap<string, ObservationRetentionDeclaration>;
|
|
21
|
+
readonly resultId?: (toolCallId: string) => string | undefined;
|
|
22
|
+
readonly recallToolId?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Pure model-visible projection. It neither mutates input messages nor drops tool-result pairs. */
|
|
25
|
+
export declare function projectObservationMessages(messages: readonly ModelMessage[], options: ObservationProjectionOptions): ModelMessage[];
|
|
26
|
+
export declare function restoreCanonicalObservationOutputs(messages: readonly ModelMessage[], outputs: ReadonlyMap<string, ToolModelOutput>): ModelMessage[];
|
|
27
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=5e4,e=4e4;function r(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function n(t){return"string"==typeof t&&t.trim().length>0}function o(t){if(!r(t)||!r(t.page)||!r(t.snapshot))return;const e=t.snapshot;if(!n(e.browserInstance)||!n(e.pageId)||!n(e.documentId)||!Array.isArray(e.nodes)||!Array.isArray(e.refs)||!0!==e.truncated&&!1!==e.truncated)return;const o=Array.isArray(e.coverageWarnings)?e.coverageWarnings:[];return{page:t.page,snapshot:e,identity:JSON.stringify([e.browserInstance,e.pageId,e.documentId]),resource:JSON.stringify([e.browserInstance,e.pageId]),complete:!1===e.truncated&&!n(e.scope)&&0===o.length}}export function observationFromMcpRaw(t,e){if("browser-ax-snapshot"===e?.kind&&r(t)&&!0!==t.isError){if(r(t.structuredContent)){const e=o(t.structuredContent);if(e)return e}if(Array.isArray(t.content))for(const e of t.content)if(r(e)&&"text"===e.type&&"string"==typeof e.text)try{const t=o(JSON.parse(e.text));if(t)return t}catch{}}}export function observationFromModelOutput(t){if(r(t)){if("json"===t.type)return o(t.value);if("content"===t.type&&Array.isArray(t.value))for(const e of t.value)if(r(e)&&"text"===e.type&&"string"==typeof e.text)try{const t=o(JSON.parse(e.text));if(t)return t}catch{}}}function s(t,e,n,o=0){if("string"==typeof t){const r=Math.min(1024,Math.max(0,e-16));return t.length<=r?t:(n.truncated=!0,`${t.slice(0,r)}[省略]`)}if(null===t||"boolean"==typeof t)return t;if("number"==typeof t)return Number.isFinite(t)?t:null;if(o>=5)return n.truncated=!0,"[嵌套内容省略]";if(Array.isArray(t)){const r=[];for(const i of t.slice(0,24)){const t=s(i,e-JSON.stringify(r).length,n,o+1);if(JSON.stringify([...r,t]).length>e){n.truncated=!0;break}r.push(t)}return r.length<t.length&&(n.truncated=!0),r}if(r(t)){const r={},i=Object.entries(t).filter(([,t])=>void 0!==t);for(const[t,a]of i.slice(0,24)){const i=t.slice(0,128);i!==t&&(n.truncated=!0);const c=s(a,e-JSON.stringify(r).length,n,o+1);if(JSON.stringify({...r,[i]:c}).length>e){n.truncated=!0;break}r[i]=c}return Object.keys(r).length<i.length&&(n.truncated=!0),r}return n.truncated=!0,null}function i(t,e,n,o){if(!r(t))return o.omittedNodes+=1,void(o.truncated=!0);const{children:a,ref:c,...u}=t,d="string"==typeof c?e.get(c):void 0,l=d?Object.fromEntries(Object.entries(d).filter(([t,e])=>"ref"!==t&&void 0!==e&&(void 0===u[t]||JSON.stringify(u[t])!==JSON.stringify(e)))):void 0,f=s({...n||void 0===c?{}:{ref:c},...void 0!==u.role?{role:u.role}:{},...void 0!==u.name?{name:u.name}:{},...void 0!==u.frameId?{frameId:u.frameId}:{},...void 0!==u.depth?{depth:u.depth}:{},...u,...!n&&l&&Object.keys(l).length>0?{refDetails:l}:{}},2500,o);if(!r(f))return;const p=JSON.stringify(f).length+16;if(p>o.remaining)return o.omittedNodes+=1,void(o.truncated=!0);if(o.remaining-=p,Array.isArray(a)){const t=[];for(const r of a){const s=i(r,e,n,o);void 0!==s&&t.push(s)}if(t.length>0)return{...f,children:t}}return f}function a(o,a=!1,c){const u=o.snapshot,d={remaining:e,truncated:!1,omittedNodes:0},l=new Map;for(const t of u.refs)r(t)&&n(t.ref)&&l.set(t.ref,t);const f=u.nodes.flatMap(t=>{const e=i(t,l,a,d);return void 0===e?[]:[e]}),p=new Set,g=t=>{for(const e of t)r(e)&&(n(e.ref)&&p.add(e.ref),Array.isArray(e.children)&&g(e.children))};g(u.nodes);const y=a?[]:[...l].filter(([t])=>!p.has(t)).map(([,t])=>t).slice(0,16);!a&&y.length<[...l].filter(([t])=>!p.has(t)).length&&(d.truncated=!0);const{refs:h,nodes:m,...v}=u,I=s(o.page,2e3,d),O=s({snapshotId:u.snapshotId,browserInstance:u.browserInstance,pageId:u.pageId,documentId:u.documentId,scope:u.scope,truncated:u.truncated,coverageWarnings:u.coverageWarnings,...v},5e3,d),b=s(y,1e3,d),A={...c?{resultId:c}:{},page:I,snapshot:{...r(O)?O:{},nodes:f,...Array.isArray(b)&&b.length>0?{unmatchedRefs:b}:{},...a?{historicalEvidenceOnly:!0,refsAreStale:!0}:{},...d.truncated?{modelProjectionTruncated:!0,modelProjectionOmittedNodes:d.omittedNodes,modelProjectionWarning:"模型侧观察已省略部分内容;可按结果 ID 分页回查原始观察"}:{}}};for(;JSON.stringify(A).length>t&&f.length>0;)f.pop(),d.omittedNodes+=1,d.truncated=!0,Object.assign(A.snapshot,{modelProjectionTruncated:!0,modelProjectionOmittedNodes:d.omittedNodes,modelProjectionWarning:"模型侧观察已省略部分内容;可按结果 ID 分页回查原始观察"});return{type:"json",value:A}}export function currentObservationModelOutput(t,e){const r=observationFromMcpRaw(t,e);return r?a(r):void 0}export function canonicalObservationOutput(t,e){if(!observationFromMcpRaw(t,e)||!r(t))return;const n=r(t.structuredContent)?o(t.structuredContent):void 0,s=t.content;if(Array.isArray(s)){const e=s.flatMap(t=>r(t)&&"text"===t.type&&"string"==typeof t.text?[{type:"text",text:t.text}]:[]);if(e.length>0){if(!n)return{type:"content",value:e};try{if(JSON.stringify(JSON.parse(e[0]?.text??""))===JSON.stringify(t.structuredContent))return{type:"content",value:e}}catch{}}}return n?{type:"json",value:t.structuredContent}:void 0}export function projectObservationMessages(t,e){const r=new Set,n=new Map,o=new Set,s=[];let i,c=0,u=!1;for(const[e,r]of t.entries())"tool"===r.role?(u||(c+=1),s[e]=c,u=!0):u=!1;let d=!1;return[...t].reverse().map((c,u)=>{if("user"===c.role)return d=!0,c;if("tool"!==c.role)return c;const l=[...c.content].reverse().map(c=>{if("tool-result"!==c.type)return c;if(c.toolName===e.recallToolId){const e=s[t.length-1-u];return d||void 0===e||void 0!==i&&i!==e?{...c,output:{type:"text",value:"[历史观察回查;如需证据请按结果 ID 再次读取]"}}:(i=e,c)}if(!e.declarations.get(c.toolName))return c;const l=c.output,f=observationFromModelOutput(l);if(!f)return{...c,output:l};const p=n.get(f.resource);void 0===p&&n.set(f.resource,f.identity);const g=void 0!==p&&p!==f.identity,y=!r.has(f.identity);return y&&r.add(f.identity),y&&!g?(f.complete&&o.add(f.identity),{...c,output:a(f,!1,e.resultId?.(c.toolCallId))}):g||!f.complete||o.has(f.identity)?{...c,output:{type:"json",value:{historicalObservation:!0,refsAreStale:!0,...g?{documentStale:!0}:{},...e.resultId?.(c.toolCallId)?{resultId:e.resultId(c.toolCallId)}:{},snapshotId:"string"==typeof f.snapshot.snapshotId?f.snapshot.snapshotId:null,browserInstance:String(f.snapshot.browserInstance),pageId:String(f.snapshot.pageId),documentId:String(f.snapshot.documentId),scope:"string"==typeof f.snapshot.scope?f.snapshot.scope:null,truncated:!0===f.snapshot.truncated,coverageWarnings:Array.isArray(f.snapshot.coverageWarnings)?f.snapshot.coverageWarnings.filter(t=>"string"==typeof t):[]}}}:(o.add(f.identity),{...c,output:a(f,!0,e.resultId?.(c.toolCallId))})});return{...c,content:l.reverse()}}).reverse()}export function restoreCanonicalObservationOutputs(t,e){return t.map(t=>"tool"===t.role?{...t,content:t.content.map(t=>"tool-result"===t.type&&e.has(t.toolCallId)?{...t,output:e.get(t.toolCallId)}:t)}:t)}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ModelMessage } from "ai";
|
|
2
|
+
import type { ObservationRetentionDeclaration } from "@roll-agent/protocol/observation-retention";
|
|
3
|
+
import type { SequencedToolExecutionRecord } from "../store/thread-store.ts";
|
|
4
|
+
import type { ObservationRecallInput } from "../tool-bridge/observation-recall-tool.ts";
|
|
5
|
+
/** Result ID was already resolved against this thread's ledger by the caller. */
|
|
6
|
+
export declare function readObservationPage(input: ObservationRecallInput, record: SequencedToolExecutionRecord, messages: readonly ModelMessage[], declaration: ObservationRetentionDeclaration, allowActive?: boolean): unknown;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{redactSecretText as e}from"../tool-bridge/tool-execution-record.js";import{observationFromMcpRaw as t,observationFromModelOutput as r}from"./observation-projection.js";function o(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function n(t){return"string"==typeof t?e(t).slice(0,1e3):null}function a(e){const t=[],r=(e,n)=>{for(const a of e){if(!o(a))continue;const{children:e,ref:s,locator:l,...i}=a,d=t.length;t.push({parent:n,value:i}),Array.isArray(e)&&r(e,d)}};return r(e,null),t}function s(e,t){let o;for(const n of[...e].reverse())if("tool"===n.role)for(const e of[...n.content].reverse())if("tool-result"===e.type&&e.toolCallId===t.toolCallId){if(o)return;o=r(e.output)}return o}export function readObservationPage(r,o,l,i,d=!0){const c=d?s(l,o):void 0,u=c||"json"!==o.raw.encoding||!0===o.persistence?.fields.raw.truncated?void 0:t(o.raw.value,i),p=c??u;if(!p)return{resultId:r.resultId,complete:!1,reason:o.persistence?.fields.raw.truncated?"durable_payload_truncated":"json"!==o.raw.encoding?"durable_payload_diagnostic":"observation_payload_unavailable",refsAreStale:!0,nodes:[]};const f=a(p.snapshot.nodes),g=(r.afterNode??-1)+1,v=r.limit??8,y=f.slice(g,g+v).map((t,r)=>{const o=e(JSON.stringify(t.value));return{index:g+r,parent:t.parent,text:o.slice(0,1500),...o.length>1500?{nodeTruncated:!0}:{}}}),I=g+y.length<f.length?g+y.length-1:void 0,h=p.snapshot;return{resultId:r.resultId,complete:!0,source:c?"active_history":"durable_ledger",evidenceRedacted:void 0===c,refsAreStale:!0,snapshotId:n(h.snapshotId),browserInstance:n(h.browserInstance),pageId:n(h.pageId),documentId:n(h.documentId),scope:n(h.scope),truncated:h.truncated,coverageWarnings:Array.isArray(h.coverageWarnings)?h.coverageWarnings.slice(0,16).map(n):[],nodes:y,...void 0!==I?{nextAfterNode:I}:{},totalNodes:f.length}}
|
|
@@ -10,19 +10,19 @@ export declare const scheduledThreadOriginSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
10
10
|
scheduledFor: z.ZodString;
|
|
11
11
|
ledgerDir: z.ZodString;
|
|
12
12
|
}, "strict", z.ZodTypeAny, {
|
|
13
|
+
kind: "scheduled";
|
|
13
14
|
name: string;
|
|
14
15
|
cwd: string;
|
|
15
16
|
attempt: number;
|
|
16
|
-
kind: "scheduled";
|
|
17
17
|
scheduleId: string;
|
|
18
18
|
invocationId: string;
|
|
19
19
|
scheduledFor: string;
|
|
20
20
|
ledgerDir: string;
|
|
21
21
|
}, {
|
|
22
|
+
kind: "scheduled";
|
|
22
23
|
name: string;
|
|
23
24
|
cwd: string;
|
|
24
25
|
attempt: number;
|
|
25
|
-
kind: "scheduled";
|
|
26
26
|
scheduleId: string;
|
|
27
27
|
invocationId: string;
|
|
28
28
|
scheduledFor: string;
|
|
@@ -44,19 +44,19 @@ export declare const threadOriginSchema: z.ZodReadonly<z.ZodDiscriminatedUnion<"
|
|
|
44
44
|
scheduledFor: z.ZodString;
|
|
45
45
|
ledgerDir: z.ZodString;
|
|
46
46
|
}, "strict", z.ZodTypeAny, {
|
|
47
|
+
kind: "scheduled";
|
|
47
48
|
name: string;
|
|
48
49
|
cwd: string;
|
|
49
50
|
attempt: number;
|
|
50
|
-
kind: "scheduled";
|
|
51
51
|
scheduleId: string;
|
|
52
52
|
invocationId: string;
|
|
53
53
|
scheduledFor: string;
|
|
54
54
|
ledgerDir: string;
|
|
55
55
|
}, {
|
|
56
|
+
kind: "scheduled";
|
|
56
57
|
name: string;
|
|
57
58
|
cwd: string;
|
|
58
59
|
attempt: number;
|
|
59
|
-
kind: "scheduled";
|
|
60
60
|
scheduleId: string;
|
|
61
61
|
invocationId: string;
|
|
62
62
|
scheduledFor: string;
|
|
@@ -80,19 +80,19 @@ export declare const threadDerivedFromSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
80
80
|
scheduledFor: z.ZodString;
|
|
81
81
|
ledgerDir: z.ZodString;
|
|
82
82
|
}, "strict", z.ZodTypeAny, {
|
|
83
|
+
kind: "scheduled";
|
|
83
84
|
name: string;
|
|
84
85
|
cwd: string;
|
|
85
86
|
attempt: number;
|
|
86
|
-
kind: "scheduled";
|
|
87
87
|
scheduleId: string;
|
|
88
88
|
invocationId: string;
|
|
89
89
|
scheduledFor: string;
|
|
90
90
|
ledgerDir: string;
|
|
91
91
|
}, {
|
|
92
|
+
kind: "scheduled";
|
|
92
93
|
name: string;
|
|
93
94
|
cwd: string;
|
|
94
95
|
attempt: number;
|
|
95
|
-
kind: "scheduled";
|
|
96
96
|
scheduleId: string;
|
|
97
97
|
invocationId: string;
|
|
98
98
|
scheduledFor: string;
|
|
@@ -102,10 +102,10 @@ export declare const threadDerivedFromSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
102
102
|
}, "strict", z.ZodTypeAny, {
|
|
103
103
|
threadId: string;
|
|
104
104
|
origin: Readonly<{
|
|
105
|
+
kind: "scheduled";
|
|
105
106
|
name: string;
|
|
106
107
|
cwd: string;
|
|
107
108
|
attempt: number;
|
|
108
|
-
kind: "scheduled";
|
|
109
109
|
scheduleId: string;
|
|
110
110
|
invocationId: string;
|
|
111
111
|
scheduledFor: string;
|
|
@@ -117,10 +117,10 @@ export declare const threadDerivedFromSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
117
117
|
}, {
|
|
118
118
|
threadId: string;
|
|
119
119
|
origin: Readonly<{
|
|
120
|
+
kind: "scheduled";
|
|
120
121
|
name: string;
|
|
121
122
|
cwd: string;
|
|
122
123
|
attempt: number;
|
|
123
|
-
kind: "scheduled";
|
|
124
124
|
scheduleId: string;
|
|
125
125
|
invocationId: string;
|
|
126
126
|
scheduledFor: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type JsonSchemaRefIssue } from "@roll-agent/core/tool-runtime/json-schema-refs";
|
|
2
2
|
import { type ToolSet } from "ai";
|
|
3
3
|
import type { FileChangeDiff } from "@roll-agent/protocol";
|
|
4
|
+
import type { ObservationRetentionDeclaration } from "@roll-agent/protocol/observation-retention";
|
|
4
5
|
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
5
6
|
import type { AgentTool } from "@roll-agent/core/types/agent";
|
|
6
7
|
import type { SessionApprovalMemory } from "../approval/approval-memory.ts";
|
|
@@ -9,11 +10,13 @@ import type { ToolAnnotations, ToolPolicy } from "../types/policy.ts";
|
|
|
9
10
|
import { ToolRegistry, type ToolRouteMetadata } from "./naming.ts";
|
|
10
11
|
import { type NormalizedToolResult } from "./normalize-result.ts";
|
|
11
12
|
import { type ToolExecutionCoordinator, type ToolResourceHint } from "./tool-execution-coordinator.ts";
|
|
13
|
+
export { readExecutionTimeoutMs, ROLL_EXECUTION_TIMEOUT_META_KEY, } from "@roll-agent/core/tool-runtime/execution-timeout";
|
|
12
14
|
export declare const ROLL_RESOURCE_HINTS_META_KEY = "roll/resourceHints";
|
|
13
15
|
export interface SourceTool {
|
|
14
16
|
readonly tool: AgentTool;
|
|
15
17
|
readonly annotations: ToolAnnotations | undefined;
|
|
16
18
|
readonly resourceHints?: readonly ToolResourceHint[];
|
|
19
|
+
readonly observationRetention?: ObservationRetentionDeclaration;
|
|
17
20
|
}
|
|
18
21
|
export interface AgentToolSource {
|
|
19
22
|
readonly agentName: string;
|
|
@@ -52,7 +55,7 @@ export interface BuiltToolset {
|
|
|
52
55
|
readonly tools: ToolSet;
|
|
53
56
|
readonly registry: ToolRegistry;
|
|
54
57
|
readonly schemaIssuesByToolId: Readonly<Record<string, readonly JsonSchemaRefIssue[]>>;
|
|
58
|
+
readonly observationRetentionByToolId: ReadonlyMap<string, ObservationRetentionDeclaration>;
|
|
55
59
|
}
|
|
56
60
|
export declare function gateToolCall(ctx: ToolBridgeContext, agentName: string, toolName: string, input: Record<string, unknown>, annotations: ToolAnnotations | undefined, display?: ApprovalDisplayOptions): Promise<NormalizedToolResult | undefined>;
|
|
57
61
|
export declare function buildAgentToolset(sources: readonly AgentToolSource[], ctx: ToolBridgeContext, registry?: ToolRegistry): BuiltToolset;
|
|
58
|
-
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{lstatSync as
|
|
1
|
+
import{lstatSync as o,readdirSync as t,readlinkSync as e,realpathSync as n,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 p}from"@roll-agent/core/tool-runtime/preflight";import{readExecutionTimeoutMs as m,ROLL_EXECUTION_TIMEOUT_META_KEY as d}from"@roll-agent/core/tool-runtime/execution-timeout";import{ToolRegistry as v}from"./naming.js";import{TOOL_OUTCOME_KINDS as g,failedToolResult as y,toolResultToModelOutput as h}from"./normalize-result.js";import{TOOL_RESOURCE_ACCESS_MODES as S,TOOL_RESOURCE_HINT_KINDS as b,executeCoordinatedTool as $}from"./tool-execution-coordinator.js";import{executeWithToolApproval as w}from"./tool-approval-continuation.js";import{currentObservationModelOutput as O}from"../engine/observation-projection.js";export{readExecutionTimeoutMs,ROLL_EXECUTION_TIMEOUT_META_KEY}from"@roll-agent/core/tool-runtime/execution-timeout";export const ROLL_RESOURCE_HINTS_META_KEY="roll/resourceHints";function T(o,t){const e=new Map;for(const n of[...o??[],...t])e.set(`${n.path}\0${n.ref}`,n);return[...e.values()]}function C(o){return"object"!=typeof o||null===o||Array.isArray(o)?{}:o}function x(o){return`参数校验失败: ${o.map(o=>o.message).join("; ")}`}function N(o){return!0===o?.readOnlyHint&&!0!==o.destructiveHint?S.read:S.write}function E(o){return"string"==typeof o||"number"==typeof o?[o]:Array.isArray(o)&&0!==o.length&&o.every(o=>"string"==typeof o||"number"==typeof o)?o:void 0}const j=256,k=new Map;function A(o,t){for(let e=0;e<o.length;e+=1){const n=o.charCodeAt(e),r=n>=65&&n<=90?String.fromCharCode(n+32):n>=97&&n<=122?String.fromCharCode(n-32):void 0;if(void 0===r)continue;const i=`${o.slice(0,e)}${r}${o.slice(e+1)}`;if(!t.has(i))return i}}function I(o){return"object"==typeof o&&null!==o&&"code"in o?o.code:void 0}function M(t,e,n){const r=A(e,n);if(void 0!==r)try{const n=o(u(t,e)),i=o(u(t,r));return n.dev===i.dev&&n.ino===i.ino}catch(o){const t=I(o);return"ENOENT"!==t&&"ENOTDIR"!==t&&void 0}}function L(o,t){if(k.size>=j){const o=k.keys().next().value;void 0!==o&&k.delete(o)}return k.set(o,t),t}function R(e){const n=k.get(e);if(void 0!==n)return n;let r;try{r=o(e).dev}catch{return L(e,!0)}let i=e;for(;;){const n=k.get(i);if(void 0!==n)return L(e,n);try{const o=t(i),n=new Set(o);for(const t of o){const o=M(i,t,n);if(void 0!==o)return L(i,o),L(e,o)}}catch{}const s=a(i);if(s===i)break;try{if(o(s).dev!==r)break}catch{break}i=s}return L(e,!0)}function _(o){let t=o.normalize("NFC");for(let o=0;o<8;o+=1){const o=t.toUpperCase().toLowerCase().normalize("NFC");if(o===t)return t;t=o}return t}function K(o,t){try{const e=r(o,{bigint:!0}),n=t.map(o=>_(o));return`file-unresolved-alias:${e.dev.toString()}:${e.ino.toString()}:${JSON.stringify(n)}`}catch{return}}function z(t,r=new Set){let i=t;const c=[];for(;;)try{const o=n.native(i),t=c.reverse().map(o=>o.normalize("NFC"));if(0===t.length)return{path:o};const e=R(o),r=u(o,...e?t.map(o=>o.toLowerCase()):t),s=e?K(o,t):void 0;return{path:r,...void 0===s?{}:{unresolvedAliasKey:s}}}catch{try{if(o(i).isSymbolicLink()&&!r.has(i)){const o=new Set(r);o.add(i);const t=e(i);return z(u(a(i),t,...[...c].reverse()),o)}}catch{}const n=a(i);if(n===i)return{path:t};c.push(s(i)),i=n}}function H(o){try{const t=r(o,{bigint:!0});return`file-inode:${t.dev.toString()}:${t.ino.toString()}`}catch{return}}function G(o,t,e){const n=String(t).trim();if(0!==n.length)switch(o.kind){case b.file:{if(!c(n)&&void 0===e)return;const o=z(u(e??"/",n)),t=H(o.path);return[`file:${o.path}`,...void 0===o.unresolvedAliasKey?[]:[o.unresolvedAliasKey],...void 0===t?[]:[t]]}case b.browserSession:return[`browser-session:${n}`];case b.conversation:return[`conversation:${n}`];case b.custom:{const t=o.namespace?.trim();return t?[`${t}:${n}`]:void 0}}}function U(o,t,e,n,r){const i=N(n),s=C(e),a=[{key:`agent:${o}`,mode:i}],c=[];for(const o of r??[]){if(!Object.hasOwn(s,o.field))continue;const e=E(s[o.field]);if(void 0===e)return a;for(const n of e){const e=G(o,n,t);if(void 0===e||0===e.length)return a;c.push(...e.map(t=>({key:t,mode:o.mode??i})))}}return 0===c.length?a:[{key:`agent:${o}`,mode:S.read},...c]}export async function gateToolCall(o,t,e,n,r,i){if(!o.policy)return;const s=o.policy.check({agentName:t,toolName:e,input:n,...r?{annotations:r}:{}});if("deny"===s.action)return y(g.policyDenied,"策略拒绝执行"+(s.reason?`: ${s.reason}`:""),s.reason?{reason:s.reason}:{});if("confirm"===s.action){const r=i?.memoryKey;if(void 0!==r&&o.approvalMemory?.isGranted(r))return;const a=await o.requestApproval({agentName:t,toolName:e,input:n,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 y(g.userRejected,"已取消执行"+(a.reason?`: ${a.reason}`:""),a.reason?{reason:a.reason}:{});void 0!==r&&"session"===a.scope&&o.approvalMemory?.grant(r)}}export function buildAgentToolset(o,t,e=new v){const n={},r={},s=new Map;for(const a of o){const{client:o,agentName:c,agentSource:u,transport:v,runtimeOwnership:S,resourceBaseDir:b}=a;for(const{tool:N,annotations:E,resourceHints:j,observationRetention:k}of a.tools){const a=i(N.inputSchema),A=T(N.schemaIssues,a.unresolved),I={...N,inputSchema:a.schema,...A.length>0?{schemaIssues:A}:{}},M=e.register(c,I.name,{...u?{agentSource:u}:{},...v?{transport:v}:{},...S?{runtimeOwnership:S}:{},...E?{annotations:E}:{},...I.appOutput?{appOutput:I.appOutput}:{}});A.length>0&&(r[M]=A),k&&s.set(M,k);const L={prepare:async o=>{const e=C(o),n=p(I,e);return n.ok?gateToolCall(t,c,I.name,e,E):y(g.invalidInput,x(n.issues),{raw:n.issues})},resources:o=>U(c,b,o,E,j)};t.coordinator?.register(M,L),n[M]=f({description:I.description??`${I.name} (via ${c})`,inputSchema:l(I.inputSchema),toModelOutput:({output:o})=>o.outcome.kind===g.success?O(o.raw,k)??h(o):h(o),execute:async(e,n)=>{const r=C(e);return $(t.coordinator,L,M,n.toolCallId,r,n.abortSignal,async()=>{const e=m({[d]:I.executionTimeoutMs}),i=n.abortSignal||void 0!==e?{...n.abortSignal?{signal:n.abortSignal}:{},...void 0===e?{}:{timeout:e}}:void 0;return w({input:r,agentName:c,agentTool:I,annotations:E,ctx:t,signal:n.abortSignal,call:async t=>await o.callTool({name:I.name,arguments:t},void 0,i)})})}})}}return{tools:n,registry:e,schemaIssuesByToolId:r,observationRetentionByToolId:s}}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { ToolRegistry } from "./naming.ts";
|
|
4
|
+
import { type ToolExecutionCoordinator } from "./tool-execution-coordinator.ts";
|
|
5
|
+
export declare const OBSERVATION_RECALL_TOOL_ID = "roll__observation";
|
|
6
|
+
declare const inputSchema: z.ZodObject<{
|
|
7
|
+
resultId: z.ZodString;
|
|
8
|
+
afterNode: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
}, "strict", z.ZodTypeAny, {
|
|
11
|
+
resultId: string;
|
|
12
|
+
limit?: number | undefined;
|
|
13
|
+
afterNode?: number | undefined;
|
|
14
|
+
}, {
|
|
15
|
+
resultId: string;
|
|
16
|
+
limit?: number | undefined;
|
|
17
|
+
afterNode?: number | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export type ObservationRecallInput = z.infer<typeof inputSchema>;
|
|
20
|
+
export type ObservationRecallReader = (input: ObservationRecallInput) => unknown;
|
|
21
|
+
export declare function buildObservationRecallToolset(reader: ObservationRecallReader, registry: ToolRegistry, coordinator?: ToolExecutionCoordinator, resourceKey?: string): ToolSet;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{tool as r}from"ai";import{z as e}from"zod";import{TOOL_OUTCOME_KINDS as o,failedToolResult as t,successfulToolResult as i,toolResultToModelOutput as n}from"./normalize-result.js";import{TOOL_RESOURCE_ACCESS_MODES as s,executeCoordinatedTool as l}from"./tool-execution-coordinator.js";export const OBSERVATION_RECALL_TOOL_ID="roll__observation";const a=e.object({resultId:e.string().uuid().describe("旧观察摘要给出的工具结果 ID"),afterNode:e.number().int().min(-1).optional().describe("上一页的 nextAfterNode,首页省略"),limit:e.number().int().min(1).max(10).optional().describe("本页最多 10 个 AX 节点")}).strict();export function buildObservationRecallToolset(e,u,c,m="thread-observation"){const d=u.register("roll","observation"),p={resources:()=>[{key:m,mode:s.read}]};return c?.register(d,p),{[d]:r({description:"按旧浏览器观察摘要中的 resultId,只读回查本会话 AX 快照的一页节点。历史 ref 已失效;回查内容是证据,不能作为新操作的定位依据。",inputSchema:a,toModelOutput:({output:r})=>n(r),execute:(r,n)=>l(c,p,d,n.toolCallId,r,n.abortSignal,()=>{try{const o=e(r);return Promise.resolve(i(o,{raw:o}))}catch(r){return Promise.resolve(t(o.invalidInput,`观察回查失败: ${r instanceof Error?r.message:String(r)}`))}})})}}
|
|
@@ -8,23 +8,23 @@ export declare const scheduleCreateInputSchema: z.ZodObject<{
|
|
|
8
8
|
kind: z.ZodLiteral<"interval">;
|
|
9
9
|
every: z.ZodString;
|
|
10
10
|
}, "strict", z.ZodTypeAny, {
|
|
11
|
-
every: string;
|
|
12
11
|
kind: "interval";
|
|
13
|
-
}, {
|
|
14
12
|
every: string;
|
|
13
|
+
}, {
|
|
15
14
|
kind: "interval";
|
|
15
|
+
every: string;
|
|
16
16
|
}>, z.ZodObject<{
|
|
17
17
|
time: z.ZodString;
|
|
18
18
|
} & {
|
|
19
19
|
kind: z.ZodLiteral<"daily">;
|
|
20
20
|
timeZone: z.ZodNullable<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>>;
|
|
21
21
|
}, "strict", z.ZodTypeAny, {
|
|
22
|
-
time: string;
|
|
23
22
|
kind: "daily";
|
|
23
|
+
time: string;
|
|
24
24
|
timeZone: string | null;
|
|
25
25
|
}, {
|
|
26
|
-
time: string;
|
|
27
26
|
kind: "daily";
|
|
27
|
+
time: string;
|
|
28
28
|
timeZone: string | null;
|
|
29
29
|
}>, z.ZodObject<{
|
|
30
30
|
time: z.ZodString;
|
|
@@ -33,13 +33,13 @@ export declare const scheduleCreateInputSchema: z.ZodObject<{
|
|
|
33
33
|
kind: z.ZodLiteral<"weekly">;
|
|
34
34
|
timeZone: z.ZodNullable<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>>;
|
|
35
35
|
}, "strict", z.ZodTypeAny, {
|
|
36
|
-
time: string;
|
|
37
36
|
kind: "weekly";
|
|
37
|
+
time: string;
|
|
38
38
|
timeZone: string | null;
|
|
39
39
|
weekdays: number[];
|
|
40
40
|
}, {
|
|
41
|
-
time: string;
|
|
42
41
|
kind: "weekly";
|
|
42
|
+
time: string;
|
|
43
43
|
timeZone: string | null;
|
|
44
44
|
weekdays: number[];
|
|
45
45
|
}>]>;
|
|
@@ -55,15 +55,15 @@ export declare const scheduleCreateInputSchema: z.ZodObject<{
|
|
|
55
55
|
maxRun: string | null;
|
|
56
56
|
rounds: number | null;
|
|
57
57
|
recurrence: {
|
|
58
|
-
every: string;
|
|
59
58
|
kind: "interval";
|
|
59
|
+
every: string;
|
|
60
60
|
} | {
|
|
61
|
-
time: string;
|
|
62
61
|
kind: "daily";
|
|
62
|
+
time: string;
|
|
63
63
|
timeZone: string | null;
|
|
64
64
|
} | {
|
|
65
|
-
time: string;
|
|
66
65
|
kind: "weekly";
|
|
66
|
+
time: string;
|
|
67
67
|
timeZone: string | null;
|
|
68
68
|
weekdays: number[];
|
|
69
69
|
};
|
|
@@ -75,15 +75,15 @@ export declare const scheduleCreateInputSchema: z.ZodObject<{
|
|
|
75
75
|
maxRun: string | null;
|
|
76
76
|
rounds: number | null;
|
|
77
77
|
recurrence: {
|
|
78
|
-
every: string;
|
|
79
78
|
kind: "interval";
|
|
79
|
+
every: string;
|
|
80
80
|
} | {
|
|
81
|
-
time: string;
|
|
82
81
|
kind: "daily";
|
|
82
|
+
time: string;
|
|
83
83
|
timeZone: string | null;
|
|
84
84
|
} | {
|
|
85
|
-
time: string;
|
|
86
85
|
kind: "weekly";
|
|
86
|
+
time: string;
|
|
87
87
|
timeZone: string | null;
|
|
88
88
|
weekdays: number[];
|
|
89
89
|
};
|
|
@@ -14,13 +14,13 @@ declare const transcriptToolInputSchema: z.ZodObject<{
|
|
|
14
14
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
15
15
|
}, "strict", z.ZodTypeAny, {
|
|
16
16
|
checkpointId: string;
|
|
17
|
-
limit?: number | undefined;
|
|
18
17
|
kind?: "message" | "tool_execution" | undefined;
|
|
18
|
+
limit?: number | undefined;
|
|
19
19
|
afterSequence?: number | undefined;
|
|
20
20
|
}, {
|
|
21
21
|
checkpointId: string;
|
|
22
|
-
limit?: number | undefined;
|
|
23
22
|
kind?: "message" | "tool_execution" | undefined;
|
|
23
|
+
limit?: number | undefined;
|
|
24
24
|
afterSequence?: number | undefined;
|
|
25
25
|
}>;
|
|
26
26
|
export type TranscriptToolInput = z.infer<typeof transcriptToolInputSchema>;
|
|
@@ -11,13 +11,13 @@ export declare const turnCancellationMetadataV1Schema: z.ZodReadonly<z.ZodObject
|
|
|
11
11
|
kind: z.ZodLiteral<"turn-cancellation">;
|
|
12
12
|
reason: z.ZodEnum<["user", "timeout", "runtime"]>;
|
|
13
13
|
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
kind: "turn-cancellation";
|
|
14
15
|
version: 1;
|
|
15
16
|
reason: "runtime" | "user" | "timeout";
|
|
16
|
-
kind: "turn-cancellation";
|
|
17
17
|
}, {
|
|
18
|
+
kind: "turn-cancellation";
|
|
18
19
|
version: 1;
|
|
19
20
|
reason: "runtime" | "user" | "timeout";
|
|
20
|
-
kind: "turn-cancellation";
|
|
21
21
|
}>>;
|
|
22
22
|
export declare function createTurnCancellationMessage(content: string, reason: SessionCancellationReason): AssistantModelMessage;
|
|
23
23
|
export declare function readTurnCancellationReason(message: ModelMessage): SessionCancellationReason | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roll-agent/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@ai-sdk/provider": "^4.0.7",
|
|
30
30
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
31
|
-
"@roll-agent/protocol": "0.
|
|
31
|
+
"@roll-agent/protocol": "0.8.0",
|
|
32
32
|
"@vscode/ripgrep": "1.18.0",
|
|
33
33
|
"ai": "^7.0.65",
|
|
34
34
|
"yaml": "2.8.3",
|
|
35
35
|
"zod": "^3.25.76"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@roll-agent/core": "0.
|
|
38
|
+
"@roll-agent/core": "0.42.0",
|
|
39
39
|
"@types/node": "^22.0.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|