@roll-agent/runtime 0.4.0 → 0.6.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/bash/classifier/compound.d.ts +3 -0
- package/dist/bash/classifier/compound.js +1 -0
- package/dist/bash/classifier/dangerous.d.ts +1 -0
- package/dist/bash/classifier/dangerous.js +1 -0
- package/dist/bash/classifier/flag-audit.d.ts +3 -0
- package/dist/bash/classifier/flag-audit.js +1 -0
- package/dist/bash/classifier/git-audit.d.ts +2 -0
- package/dist/bash/classifier/git-audit.js +1 -0
- package/dist/bash/classifier/index.d.ts +3 -0
- package/dist/bash/classifier/index.js +1 -0
- package/dist/bash/classifier/lookup-key.d.ts +1 -0
- package/dist/bash/classifier/lookup-key.js +1 -0
- package/dist/bash/classifier/path-audit.d.ts +3 -0
- package/dist/bash/classifier/path-audit.js +1 -0
- package/dist/bash/classifier/safe-list.d.ts +1 -0
- package/dist/bash/classifier/safe-list.js +1 -0
- package/dist/bash/classifier/tokenize.d.ts +10 -0
- package/dist/bash/classifier/tokenize.js +1 -0
- package/dist/bash/classifier/types.d.ts +2 -0
- package/dist/bash/classifier/types.js +1 -0
- package/dist/bash/clean-env.d.ts +8 -0
- package/dist/bash/clean-env.js +1 -0
- package/dist/bash/exec.d.ts +22 -0
- package/dist/bash/exec.js +1 -0
- package/dist/bash/format-result.d.ts +31 -0
- package/dist/bash/format-result.js +1 -0
- package/dist/bash/kill.d.ts +3 -0
- package/dist/bash/kill.js +1 -0
- package/dist/bash/output-buffer.d.ts +23 -0
- package/dist/bash/output-buffer.js +1 -0
- package/dist/bash/profile.d.ts +43 -0
- package/dist/bash/profile.js +1 -0
- package/dist/bash/session/head-tail-buffer.d.ts +17 -0
- package/dist/bash/session/head-tail-buffer.js +1 -0
- package/dist/bash/session/session-exec.d.ts +2 -0
- package/dist/bash/session/session-exec.js +1 -0
- package/dist/bash/session/session-manager.d.ts +33 -0
- package/dist/bash/session/session-manager.js +1 -0
- package/dist/bash/session/types.d.ts +39 -0
- package/dist/bash/session/types.js +1 -0
- package/dist/bash/session/yield-loop.d.ts +2 -0
- package/dist/bash/session/yield-loop.js +1 -0
- package/dist/bash/shell.d.ts +6 -0
- package/dist/bash/shell.js +1 -0
- package/dist/bash/truncate.d.ts +6 -0
- package/dist/bash/truncate.js +1 -0
- package/dist/bash/workdir.d.ts +1 -0
- package/dist/bash/workdir.js +1 -0
- package/dist/engine/agent-session.d.ts +46 -3
- package/dist/engine/agent-session.js +1 -1
- package/dist/engine/conversation-engine.d.ts +33 -2
- package/dist/engine/conversation-engine.js +1 -1
- package/dist/engine/system-prompt.d.ts +18 -0
- package/dist/engine/system-prompt.js +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -1
- package/dist/server/protocol.d.ts +8 -0
- package/dist/server/protocol.js +1 -1
- package/dist/server/runtime-server.js +1 -1
- package/dist/tool-bridge/agent-install-tool.d.ts +27 -0
- package/dist/tool-bridge/agent-install-tool.js +1 -0
- package/dist/tool-bridge/bash-tool.d.ts +45 -0
- package/dist/tool-bridge/bash-tool.js +1 -0
- package/dist/tool-bridge/build-tools.d.ts +2 -0
- package/dist/tool-bridge/build-tools.js +1 -1
- package/dist/tool-bridge/session-exec-tool.d.ts +52 -0
- package/dist/tool-bridge/session-exec-tool.js +1 -0
- package/dist/tool-bridge/skill-tool.d.ts +1 -1
- package/dist/tool-bridge/skill-tool.js +1 -1
- package/dist/types/cancellation.d.ts +12 -0
- package/dist/types/cancellation.js +1 -0
- package/dist/types/command-classification.d.ts +8 -0
- package/dist/types/command-classification.js +1 -0
- package/dist/types/events.d.ts +12 -0
- package/package.json +2 -2
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { LanguageModelV4, SharedV4ProviderOptions } from "@ai-sdk/provider";
|
|
2
2
|
import { McpClientManager } from "@roll-agent/core/mcp/client-manager";
|
|
3
|
+
import { resolveAgentCatalog } from "@roll-agent/core/registry/catalog-discovery";
|
|
4
|
+
import { installAgent } from "@roll-agent/core/registry/install";
|
|
3
5
|
import type { RollConfig } from "@roll-agent/core/config/schema";
|
|
4
6
|
import type { RegisteredAgent } from "@roll-agent/core/types/agent";
|
|
5
7
|
import { type SkillLibrary } from "@roll-agent/core/skills/library";
|
|
6
8
|
import type { AgentToolSource } from "../tool-bridge/build-tools.ts";
|
|
7
9
|
import type { ToolPolicy } from "../types/policy.ts";
|
|
8
10
|
import type { ThreadStore } from "../store/thread-store.ts";
|
|
9
|
-
import { AgentSession } from "./agent-session.ts";
|
|
11
|
+
import { AgentSession, type SessionAgentRefresh } from "./agent-session.ts";
|
|
12
|
+
import { resolveShellProfile, type ShellProfile } from "../bash/profile.ts";
|
|
10
13
|
export type EnsureAgentReady = (agent: RegisteredAgent, env: Readonly<Record<string, string>> | undefined) => Promise<void>;
|
|
11
14
|
export interface ConversationEngineOptions {
|
|
12
15
|
readonly config: RollConfig;
|
|
@@ -23,6 +26,11 @@ export interface ConversationEngineOptions {
|
|
|
23
26
|
readonly onAgentBootstrapIssue?: (issue: AgentBootstrapIssue) => void;
|
|
24
27
|
readonly skillLibrary?: SkillLibrary | null;
|
|
25
28
|
readonly onSkillLibraryIssue?: (message: string) => void;
|
|
29
|
+
readonly sessionExecEnabled?: boolean;
|
|
30
|
+
readonly shellProfile?: ShellProfile | null;
|
|
31
|
+
readonly resolveShellProfileFn?: typeof resolveShellProfile;
|
|
32
|
+
readonly installAgentFn?: typeof installAgent;
|
|
33
|
+
readonly resolveCatalogFn?: typeof resolveAgentCatalog;
|
|
26
34
|
}
|
|
27
35
|
export interface CreateSessionInput {
|
|
28
36
|
readonly title?: string;
|
|
@@ -42,7 +50,7 @@ export declare class ConversationEngine {
|
|
|
42
50
|
private readonly store;
|
|
43
51
|
private readonly policy;
|
|
44
52
|
private readonly maxSteps;
|
|
45
|
-
private
|
|
53
|
+
private providerOptions;
|
|
46
54
|
private readonly ensureAgentReady;
|
|
47
55
|
private readonly debugEvents;
|
|
48
56
|
private readonly explicitAgents;
|
|
@@ -51,13 +59,36 @@ export declare class ConversationEngine {
|
|
|
51
59
|
private readonly explicitSkillLibrary;
|
|
52
60
|
private readonly onSkillLibraryIssue;
|
|
53
61
|
private readonly onAgentBootstrapIssue;
|
|
62
|
+
private readonly sessionExecEnabled;
|
|
63
|
+
private readonly explicitShellProfile;
|
|
64
|
+
private readonly resolveShellProfileFn;
|
|
65
|
+
private readonly installAgentFn;
|
|
66
|
+
private readonly resolveCatalogFn;
|
|
54
67
|
private ready;
|
|
68
|
+
private refreshChain;
|
|
69
|
+
private resolvedCatalog;
|
|
70
|
+
private shellProfileResolution;
|
|
71
|
+
private shellUnsupportedWarned;
|
|
72
|
+
private shellSessionUnsupportedWarned;
|
|
55
73
|
constructor(options: ConversationEngineOptions);
|
|
56
74
|
createSession(input?: CreateSessionInput): Promise<AgentSession>;
|
|
57
75
|
resumeSession(threadId: string): Promise<AgentSession>;
|
|
76
|
+
private resolveRuntimeShellProfile;
|
|
77
|
+
private resolveShellSettings;
|
|
78
|
+
private resolveSessionExecSettings;
|
|
58
79
|
private buildSession;
|
|
80
|
+
private syncProviderOptions;
|
|
59
81
|
private ensureReady;
|
|
60
82
|
private bootstrap;
|
|
83
|
+
private connectAgentSource;
|
|
84
|
+
prepareAgentRefresh(agent: RegisteredAgent): Promise<SessionAgentRefresh>;
|
|
85
|
+
private runAgentRefresh;
|
|
86
|
+
private composeSystemPrompt;
|
|
87
|
+
private agentInstallEnabled;
|
|
88
|
+
private currentCatalog;
|
|
89
|
+
private resolveAgentOnboardingInfo;
|
|
90
|
+
private resolveAgentInstallBinding;
|
|
91
|
+
private installCatalogAgent;
|
|
61
92
|
private resolveSkillLibrary;
|
|
62
93
|
private resolveModel;
|
|
63
94
|
private resolveProviderName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{McpClientManager as t}from"@roll-agent/core/mcp/client-manager";import{createProviderModel as i}from"@roll-agent/core/llm/providers";import{AgentStore as s}from"@roll-agent/core/registry/store";import{resolveTransportWithDevSpawnSpec as r}from"@roll-agent/core/registry/dev-spawn";import{getAgentPid as o,startAgent as n,waitForAgentReady as l}from"@roll-agent/core/registry/process-manager";import{normalizeListedTools as a}from"@roll-agent/core/cli/utils/agent-tools";import{getAgentEnv as c}from"@roll-agent/core/config/helpers";import{createSkillLibrary as d}from"@roll-agent/core/skills/library";import{AgentSession as p}from"./agent-session.js";import{resolveContextWindow as h}from"./context-window.js";import{buildChatSystemPrompt as u}from"./system-prompt.js";const m=80;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 i={};return"readOnlyHint"in t&&"boolean"==typeof t.readOnlyHint&&(i.readOnlyHint=t.readOnlyHint),"destructiveHint"in t&&"boolean"==typeof t.destructiveHint&&(i.destructiveHint=t.destructiveHint),void 0===i.readOnlyHint&&void 0===i.destructiveHint?void 0:i}async function y(e,t,i){"core-managed"===e.runtime.ownership&&(void 0===o(t,e.skill.name)&&n(e,t,i),await l(e))}export class ConversationEngine{config;clientManager;store;policy;maxSteps;providerOptions;ensureAgentReady;debugEvents;explicitAgents;explicitModel;explicitSources;explicitSkillLibrary;onSkillLibraryIssue;onAgentBootstrapIssue;ready;constructor(e){this.config=e.config,this.clientManager=e.clientManager??new t,this.store=e.store,this.policy=e.policy,this.maxSteps=e.maxSteps??m,this.providerOptions=e.providerOptions,this.ensureAgentReady=e.ensureAgentReady??((e,t)=>y(e,this.config.agents.dataDir,t)),this.debugEvents=e.debugEvents??!1,this.explicitAgents=e.agents,this.explicitModel=e.model,this.explicitSources=e.sources,this.explicitSkillLibrary=e.skillLibrary,this.onSkillLibraryIssue=e.onSkillLibraryIssue,this.onAgentBootstrapIssue=e.onAgentBootstrapIssue}async createSession(t={}){const i=await this.ensureReady(),s=this.store?this.store.createThread({...t.title?{title:t.title}:{},model:this.resolveModelName()}):e();return this.buildSession(i,s,[])}async resumeSession(e){if(!this.store)throw new Error("resumeSession requires a ThreadStore");if(!this.store.hasThread(e))throw new Error(`Thread "${e}" 不存在`);const t=await this.ensureReady();return this.buildSession(t,e,this.store.getMessages(e))}buildSession(e,t,i){const s=this.store,r=h(this.resolveModelName(),this.config.runtime.contextWindow),o=e.skillLibrary?.list()??[],n=o.length>0?e.skillLibrary:void 0,l=u({skills:o});return new p({id:t,model:e.model,sources:e.sources,systemPrompt:l,...n?{skillLibrary:n}:{},maxSteps:this.maxSteps,compaction:this.config.runtime.compaction,turnTimeoutMs:this.config.runtime.turnTimeoutMs,debugEvents:this.debugEvents,...this.providerOptions?{providerOptions:this.providerOptions}:{},...void 0!==r?{contextWindow:r}:{},...this.policy?{policy:this.policy}:{},initialMessages:i,...s?{onPersist:e=>s.appendMessages(t,e),onReplace:e=>s.replaceMessages(t,e)}:{}})}ensureReady(){return this.ready||(this.ready=this.bootstrap()),this.ready}async bootstrap(){const e=this.explicitModel??this.resolveModel();if(this.explicitSources)return{model:e,sources:this.explicitSources,...this.explicitSkillLibrary?{skillLibrary:this.explicitSkillLibrary}:{}};const t=this.explicitAgents??new s(this.config.agents.dataDir).list(),i=[];for(const s of t)try{const t=r(s),o=c(this.config,s.skill.name);await this.ensureAgentReady(s,o);const n=await this.clientManager.connect(s.skill.name,t,s.installPath,{samplingModel:e,...o?{env:o}:{}}),l=(await n.listTools()).tools,d=a(l).map((e,t)=>({tool:e,annotations:g(l[t])}));i.push({agentName:s.skill.name,client:n,tools:d})}catch(e){this.onAgentBootstrapIssue?.({agentName:s.skill.name,message:e instanceof Error?e.message:String(e)})}const o=this.resolveSkillLibrary(t);return{model:e,sources:i,...o?{skillLibrary:o}:{}}}resolveSkillLibrary(e){if(null!==this.explicitSkillLibrary)return void 0!==this.explicitSkillLibrary?this.explicitSkillLibrary:d({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 i(e,t,s.apiKey,s.baseUrl)}resolveProviderName(){return this.config.runtime.provider??this.config.llm.defaultProvider}resolveModelName(){return this.config.runtime.model??this.config.llm.defaultModel}async getContextSummary(){const e=await this.ensureReady();return{agentCount:e.sources.length,toolCount:e.sources.reduce((e,t)=>e+t.tools.length,0),skillCount:e.skillLibrary?.list().length??0}}async dispose(){await this.clientManager.disconnectAll()}}
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{McpClientManager as t}from"@roll-agent/core/mcp/client-manager";import{createProviderModel as s}from"@roll-agent/core/llm/providers";import{AgentStore as i}from"@roll-agent/core/registry/store";import{resolveTransportWithDevSpawnSpec as o}from"@roll-agent/core/registry/dev-spawn";import{getAgentPid as r,startAgent as n,waitForAgentReady as l}from"@roll-agent/core/registry/process-manager";import{normalizeListedTools as a}from"@roll-agent/core/cli/utils/agent-tools";import{getAgentEnv as c}from"@roll-agent/core/config/helpers";import{catalogPackageSpec as h,getAgentCatalog as p}from"@roll-agent/core/registry/catalog";import{resolveAgentCatalog as m}from"@roll-agent/core/registry/catalog-discovery";import{installAgent as d}from"@roll-agent/core/registry/install";import{createSkillLibrary as g}from"@roll-agent/core/skills/library";import{AGENT_INSTALL_TOOL_ID as u}from"../tool-bridge/agent-install-tool.js";import{AgentSession as f}from"./agent-session.js";import{resolveContextWindow as y}from"./context-window.js";import{buildChatSystemPrompt as v}from"./system-prompt.js";import{BASH_TOOL_ID as S,POWERSHELL_TOOL_ID as b}from"../tool-bridge/bash-tool.js";import{EXEC_COMMAND_ID as x,EXEC_POLL_ID as w}from"../tool-bridge/session-exec-tool.js";import{unknownCommandClassifier as k}from"../types/command-classification.js";import{resolveShellProfile as C}from"../bash/profile.js";const M=80;function A(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 P(e){return"retry"===e.type?`安装遇到网络问题,${Math.round(e.delayMs/1e3)}s 后重试(第 ${e.attempt+1} 次)...`:"warn"===e.type?`警告:${e.message}`:e.message}async function E(e,t,s){"core-managed"===e.runtime.ownership&&(void 0===r(t,e.skill.name)&&n(e,t,s),await l(e))}export class ConversationEngine{config;clientManager;store;policy;maxSteps;providerOptions;ensureAgentReady;debugEvents;explicitAgents;explicitModel;explicitSources;explicitSkillLibrary;onSkillLibraryIssue;onAgentBootstrapIssue;sessionExecEnabled;explicitShellProfile;resolveShellProfileFn;installAgentFn;resolveCatalogFn;ready;refreshChain=Promise.resolve();resolvedCatalog;shellProfileResolution;shellUnsupportedWarned=!1;shellSessionUnsupportedWarned=!1;constructor(e){this.config=e.config,this.clientManager=e.clientManager??new t,this.store=e.store,this.policy=e.policy,this.maxSteps=e.maxSteps??M,this.providerOptions=e.providerOptions,this.ensureAgentReady=e.ensureAgentReady??((e,t)=>E(e,this.config.agents.dataDir,t)),this.debugEvents=e.debugEvents??!1,this.sessionExecEnabled=e.sessionExecEnabled??!0,this.explicitShellProfile=e.shellProfile,this.resolveShellProfileFn=e.resolveShellProfileFn??C,this.explicitAgents=e.agents,this.explicitModel=e.model,this.explicitSources=e.sources,this.explicitSkillLibrary=e.skillLibrary,this.onSkillLibraryIssue=e.onSkillLibraryIssue,this.onAgentBootstrapIssue=e.onAgentBootstrapIssue,this.installAgentFn=e.installAgentFn??d,this.resolveCatalogFn=e.resolveCatalogFn??m}async createSession(t={}){const s=await this.ensureReady(),i=this.store?this.store.createThread({...t.title?{title:t.title}:{},model:this.resolveModelName()}):e();return this.buildSession(s,i,[])}async resumeSession(e){if(!this.store)throw new Error("resumeSession requires a ThreadStore");if(!this.store.hasThread(e))throw new Error(`Thread "${e}" 不存在`);const t=await this.ensureReady();return this.buildSession(t,e,this.store.getMessages(e))}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:process.env}));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){const t=this.config.runtime.shell;return{workdir:process.cwd(),defaultTimeoutMs:t.defaultTimeoutMs,maxTimeoutMs:t.maxTimeoutMs,turnTimeoutMs:this.config.runtime.turnTimeoutMs,maxCaptureBytes:t.maxCaptureBytes,maxModelOutputChars:t.maxModelOutputChars,profile:e}}resolveSessionExecSettings(e){if(!this.sessionExecEnabled)return;const t=this.config.runtime.shell;if(t.enabled&&t.session.enabled){if(e.supportsSessionExec)return{workdir:process.cwd(),profile:e,maxSessions:t.session.maxSessions,defaultYieldMs:t.session.defaultYieldMs,maxOutputTokens:t.session.maxOutputTokens,bufferCapacity:t.maxCaptureBytes};this.shellSessionUnsupportedWarned||(this.shellSessionUnsupportedWarned=!0,process.stderr.write("roll chat: Windows 原生 session exec 暂未支持,已跳过 roll__exec_command / roll__exec_poll\n"))}}buildSession(e,t,s){const i=this.store,o=y(this.resolveModelName(),this.config.runtime.contextWindow),r=e.skillLibrary?.list()??[],n=r.length>0?e.skillLibrary:void 0,l=this.resolveRuntimeShellProfile(),a=l?this.resolveShellSettings(l):void 0,c=l?this.resolveSessionExecSettings(l):void 0,h=l?l.supportsSafeCommandClassification&&this.config.runtime.shell.autoApproveSafe?l:k:void 0,p=this.composeSystemPrompt(r,e.sources.length,l,c),m=this.resolveAgentInstallBinding();return new f({id:t,model:e.model,sources:e.sources,systemPrompt:p,...n?{skillLibrary:n}:{},...a?{bash:a}:{},...h?{bashClassifier:h}:{},...c?{bashSession:c}:{},...m?{agentInstall:m}:{},maxSteps:this.maxSteps,compaction:this.config.runtime.compaction,turnTimeoutMs:this.config.runtime.turnTimeoutMs,debugEvents:this.debugEvents,...this.providerOptions?{providerOptions:this.providerOptions}:{},onProviderOptionsChange:e=>this.syncProviderOptions(e),...void 0!==o?{contextWindow:o}:{},...this.policy?{policy:this.policy}:{},initialMessages:s,...i?{onPersist:e=>i.appendMessages(t,e),onReplace:e=>i.replaceMessages(t,e)}:{}})}syncProviderOptions(e){this.providerOptions=e,this.clientManager.setSamplingProviderOptions(e)}ensureReady(){return this.ready||(this.ready=this.bootstrap()),this.ready}async bootstrap(){const e=this.explicitModel??this.resolveModel();if(this.explicitSources)return{model:e,sources:this.explicitSources,...this.explicitSkillLibrary?{skillLibrary:this.explicitSkillLibrary}:{}};const t=this.explicitAgents??new i(this.config.agents.dataDir).list();this.agentInstallEnabled()&&(this.resolvedCatalog=await this.resolveCatalogFn(this.config,{allowNetwork:!1,...this.config.install.registry?{registry:this.config.install.registry}:{}}));const s=[];for(const i of t)try{s.push(await this.connectAgentSource(i,e))}catch(e){this.onAgentBootstrapIssue?.({agentName:i.skill.name,message:e instanceof Error?e.message:String(e)})}const o=this.resolveSkillLibrary(t);return{model:e,sources:s,...o?{skillLibrary:o}:{}}}async connectAgentSource(e,t){const s=o(e),i=c(this.config,e.skill.name);await this.ensureAgentReady(e,i);const r=await this.clientManager.connect(e.skill.name,s,e.installPath,{samplingModel:t,...this.providerOptions?{samplingProviderOptions:this.providerOptions}:{},...i?{env:i}:{}}),n=(await r.listTools()).tools,l=a(n).map((e,t)=>({tool:e,annotations:A(n[t])}));return{agentName:e.skill.name,client:r,tools:l}}async prepareAgentRefresh(e){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,t.model),o=[...t.sources.filter(e=>e.agentName!==s.agentName),s],r=this.explicitAgents??new i(this.config.agents.dataDir).list(),n=this.resolveSkillLibrary(r);this.ready=Promise.resolve({model:t.model,sources:o,...n?{skillLibrary:n}:{}});const l=n?.list()??[],a=n&&l.length>0?n:void 0,c=this.resolveRuntimeShellProfile(),h=c?this.resolveSessionExecSettings(c):void 0;return{source:s,...a?{skillLibrary:a}:{},systemPrompt:this.composeSystemPrompt(l,o.length,c,h)}}composeSystemPrompt(e,t,s,i){const o=this.resolveAgentOnboardingInfo();return v({skills:e,...s?{shellToolId:"powershell"===s.toolName?b:S,shellHints:s.systemPromptHints()}:{},...i?{sessionExecToolIds:{command:x,poll:w}}:{},agentCount:t,...o?{agentOnboarding:o}:{}})}agentInstallEnabled(){return void 0===this.explicitSources&&void 0===this.explicitAgents}currentCatalog(){return this.resolvedCatalog??p(this.config)}resolveAgentOnboardingInfo(){if(!this.agentInstallEnabled())return;const e=this.currentCatalog();return 0!==e.length?{installToolId:u,catalog: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:h(s),skipBrowserSetup:!0,autoStart:!0,expectedSkillName:s.skillName},{agentsConfig:this.config.agents,installConfig:this.config.install,getStartEnv:e=>c(this.config,e),report:e=>t(P(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,l={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:l};try{return{outcome:l,refresh:await this.prepareAgentRefresh(o)}}catch(e){return t(`接入新 Agent 失败:${e instanceof Error?e.message:String(e)}`),{outcome:l}}}resolveSkillLibrary(e){if(null!==this.explicitSkillLibrary)return void 0!==this.explicitSkillLibrary?this.explicitSkillLibrary:g({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.config.runtime.provider??this.config.llm.defaultProvider}resolveModelName(){return this.config.runtime.model??this.config.llm.defaultModel}async getContextSummary(){const e=await this.ensureReady();return{agentCount:e.sources.length,toolCount:e.sources.reduce((e,t)=>e+t.tools.length,0),skillCount:e.skillLibrary?.list().length??0}}async dispose(){await this.clientManager.disconnectAll()}}
|
|
@@ -2,8 +2,26 @@ export interface SkillPromptSummary {
|
|
|
2
2
|
readonly name: string;
|
|
3
3
|
readonly description: string;
|
|
4
4
|
}
|
|
5
|
+
export interface SessionExecToolIds {
|
|
6
|
+
readonly command: string;
|
|
7
|
+
readonly poll: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AgentOnboardingCatalogEntry {
|
|
10
|
+
readonly shortName: string;
|
|
11
|
+
readonly description: string;
|
|
12
|
+
}
|
|
13
|
+
export interface AgentOnboardingPromptInfo {
|
|
14
|
+
readonly installToolId: string;
|
|
15
|
+
readonly catalog: readonly AgentOnboardingCatalogEntry[];
|
|
16
|
+
}
|
|
5
17
|
export interface BuildChatSystemPromptOptions {
|
|
6
18
|
readonly skills?: readonly SkillPromptSummary[];
|
|
7
19
|
readonly skillToolId?: string;
|
|
20
|
+
readonly bashToolId?: string;
|
|
21
|
+
readonly shellToolId?: string;
|
|
22
|
+
readonly shellHints?: readonly string[];
|
|
23
|
+
readonly sessionExecToolIds?: SessionExecToolIds;
|
|
24
|
+
readonly agentCount?: number;
|
|
25
|
+
readonly agentOnboarding?: AgentOnboardingPromptInfo;
|
|
8
26
|
}
|
|
9
27
|
export declare function buildChatSystemPrompt(options?: BuildChatSystemPromptOptions): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SKILL_TOOL_ID as n}from"../tool-bridge/skill-tool.js";const
|
|
1
|
+
import{SKILL_TOOL_ID as n}from"../tool-bridge/skill-tool.js";const o=240,e="你是花卷 Roll 的会话助手,运行在 roll chat 里。";function t(n){return e+(n?"你通过已注册 Agent 提供的工具(MCP)观察和操作外部世界,并有一个内建 shell 工具可以在本机执行命令。":"你通过已注册 Agent 提供的工具(MCP)观察和操作外部世界;你没有独立的文件系统或 shell,工具就是你的全部执行手段。")}const l=["# 工具使用纪律","- 一切对外部世界的读取和操作都必须通过真实的工具调用完成。绝不虚构工具调用或其结果,也不要用文本描述来代替真正的调用。","- 只有当本会话中出现了对应的成功工具结果,才能说某个操作已完成。没有调用过工具,就如实说明尚未执行。","- 批量任务(例如给多个人回复)必须逐项执行:每一项都真实调用工具、等到结果后再处理下一项;最后按真实结果逐项汇报成功、失败或未执行,不要掩盖失败。","- 工具返回错误时,如实报告错误内容,再决定重试、换方案或向用户求助。不要把失败说成成功,也不要凭空猜测答案。","- 需要确认的工具调用被用户拒绝时,尊重用户的决定,不要换个方式绕过。"].join("\n"),i=["# 任务推进","- 接到任务后持续推进,直到完成或真正被阻塞,不要停在分析或计划阶段。个别工具调用失败不代表任务失败,先尝试自行恢复。","- 除非用户明确只要建议或分析,否则默认用户希望你实际执行。","- 多步任务先用一两句话说明打算怎么做,然后逐步执行,不要把计划本身当成结果。"].join("\n"),s=["# 输出","- 你可以用 thinking/reasoning 做内部推理,但给用户看的最终回复必须写入普通 text 输出通道,不要只写在 reasoning 里。","- 工具调用完成后,在 text 通道给出简洁结论;最终回复不要重复,也不要复述用户输入。","- 像可靠的同事一样汇报:先结论,后必要细节,保持简洁。"].join("\n");function r(n,o){return n.length<=o?n:`${n.slice(0,o-1)}…`}function a(n,e){return["# Skills",`以下是可用的技能说明书(skill)。当任务涉及某个 skill 的领域时,先调用 ${e} 工具(传 name)加载它的完整内容,按其中的流程和约束行事;skill 中的指导优先于你的默认做法。`,n.map(n=>`- ${n.name}: ${r(n.description.replace(/\s+/g," ").trim(),o)}`).join("\n"),"加载结果中的 SKILL_ROOT 是该 skill 的 canonical absolute root。正文里的 scripts/、references/ 等相对路径一律相对 SKILL_ROOT 解析;执行脚本时把 workdir 设为 SKILL_ROOT,不要再搜索 .roll、.claude、.agents 或其它目录猜路径。",`skill 正文提到 references/ 下的文件时,可再次调用 ${e} 并传 reference 参数读取对应文件。`].join("\n")}function c(n){return["# Agent 安装","当前没有任何已注册的子 Agent,对外部系统的操作能力受限。可安装的官方 Agent:",n.catalog.map(n=>`- ${n.shortName}: ${r(n.description.replace(/\s+/g," ").trim(),o)}`).join("\n"),`当用户的需求涉及上述 Agent 的能力时,先说明它的用途并征得用户同意,再调用 ${n.installToolId} 安装(安装会执行 npm install,用户还需在界面上二次确认)。新 Agent 的工具从下一轮对话开始可用。`,"绝不在用户未明确同意的情况下自行安装。"].join("\n")}function g(n,o,e){const t=o?[`- 预计跑几十秒以上的命令(构建、批处理脚本)不要用 ${n}(会被单轮超时杀掉),改用 ${o.command} 后台执行。`,`- ${o.command} 未结束时会返回 session_id;用 ${o.poll}(chars 留空)轮询进度直到拿到退出码,需要中断时 chars 传 "\\u0003"。`]:["- 预计耗时较长的命令(如构建、脚本)要显式调大 timeout_ms。"];return["# Shell 工具",`- 需要在本机执行命令时调用 ${n};用 workdir 参数指定工作目录,不要在 command 里用 cd。`,...e.map(n=>`- ${n}`),"- 输出会被截断,优先用精确过滤或预览命令,而不是全量 dump 大文件。","- 优先使用只读命令;有副作用或破坏性的命令可能需要用户确认,被拒绝时不要绕过。",...t].join("\n")}export function buildChatSystemPrompt(o={}){const e=o.shellToolId??o.bashToolId,r=[t(void 0!==e),l,i];0===o.agentCount&&void 0!==o.agentOnboarding&&o.agentOnboarding.catalog.length>0&&r.push(c(o.agentOnboarding));const d=o.skills??[];return d.length>0&&r.push(a(d,o.skillToolId??n)),void 0!==e&&r.push(g(e,o.sessionExecToolIds,o.shellHints??[])),r.push(s),r.join("\n\n")}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export { compactMessages, findTurnBoundaries, SUMMARY_PREFIX, SUMMARY_ACK, } fro
|
|
|
7
7
|
export type { CompactionInput, CompactionResult } from "./engine/compactor.ts";
|
|
8
8
|
export { buildAgentToolset } from "./tool-bridge/build-tools.ts";
|
|
9
9
|
export type { AgentToolSource, SourceTool, ApprovalRequest, ToolBridgeContext, BuiltToolset, } from "./tool-bridge/build-tools.ts";
|
|
10
|
+
export type { SessionBashSettings } from "./tool-bridge/bash-tool.ts";
|
|
11
|
+
export { type CommandClassifier, type CommandClassification, COMMAND_CLASSIFICATIONS, unknownCommandClassifier, } from "./types/command-classification.ts";
|
|
12
|
+
export { ruleBasedClassifier } from "./bash/classifier/index.ts";
|
|
13
|
+
export { buildPowerShellEncodedCommand, resolveShellProfile, SHELL_PROFILE_IDS, SHELL_TOOL_NAMES, } from "./bash/profile.ts";
|
|
14
|
+
export type { ShellProfile, ShellProfileId, ShellKillOptions, ShellProfileResolutionDeps, ShellProfileResolutionResult, ShellSpawnSpec, ShellToolName, } from "./bash/profile.ts";
|
|
15
|
+
export { buildSessionExecToolset, EXEC_COMMAND_ID, EXEC_POLL_ID, type SessionExecSettings, } from "./tool-bridge/session-exec-tool.ts";
|
|
10
16
|
export { ToolRegistry } from "./tool-bridge/naming.ts";
|
|
11
17
|
export type { ToolRoute } from "./tool-bridge/naming.ts";
|
|
12
18
|
export { normalizeToolResult } from "./tool-bridge/normalize-result.ts";
|
|
@@ -24,3 +30,5 @@ export { createStdioConnection } from "./server/transport/stdio.ts";
|
|
|
24
30
|
export { RpcMethod, EVENT_NOTIFICATION, isRequest } from "./server/protocol.ts";
|
|
25
31
|
export type { JsonRpcConnection, JsonRpcMessage, JsonRpcRequest, JsonRpcNotification, JsonRpcId, } from "./server/protocol.ts";
|
|
26
32
|
export type { SessionEvent, SessionEventStage, SessionTokenUsage, ContextCompactionReason, ContextCompactionStrategy, } from "./types/events.ts";
|
|
33
|
+
export { SESSION_CANCELLATION_REASONS, USER_CANCELLATION_ABORT_REASON, } from "./types/cancellation.ts";
|
|
34
|
+
export type { SessionCancellationReason } from "./types/cancellation.ts";
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{ConversationEngine}from"./engine/conversation-engine.js";export{AgentSession}from"./engine/agent-session.js";export{resolveContextWindow,lookupContextWindow}from"./engine/context-window.js";export{compactMessages,findTurnBoundaries,SUMMARY_PREFIX,SUMMARY_ACK}from"./engine/compactor.js";export{buildAgentToolset}from"./tool-bridge/build-tools.js";export{ToolRegistry}from"./tool-bridge/naming.js";export{normalizeToolResult}from"./tool-bridge/normalize-result.js";export{ThreadStore,defaultThreadsDir,expandTilde}from"./store/thread-store.js";export{DefaultToolPolicy}from"./policy/default-policy.js";export{ConfigurableToolPolicy}from"./policy/configurable-policy.js";export{ApprovalGate}from"./approval/approval-gate.js";export{RuntimeServer}from"./server/runtime-server.js";export{createStdioConnection}from"./server/transport/stdio.js";export{RpcMethod,EVENT_NOTIFICATION,isRequest}from"./server/protocol.js";
|
|
1
|
+
export{ConversationEngine}from"./engine/conversation-engine.js";export{AgentSession}from"./engine/agent-session.js";export{resolveContextWindow,lookupContextWindow}from"./engine/context-window.js";export{compactMessages,findTurnBoundaries,SUMMARY_PREFIX,SUMMARY_ACK}from"./engine/compactor.js";export{buildAgentToolset}from"./tool-bridge/build-tools.js";export{COMMAND_CLASSIFICATIONS,unknownCommandClassifier}from"./types/command-classification.js";export{ruleBasedClassifier}from"./bash/classifier/index.js";export{buildPowerShellEncodedCommand,resolveShellProfile,SHELL_PROFILE_IDS,SHELL_TOOL_NAMES}from"./bash/profile.js";export{buildSessionExecToolset,EXEC_COMMAND_ID,EXEC_POLL_ID}from"./tool-bridge/session-exec-tool.js";export{ToolRegistry}from"./tool-bridge/naming.js";export{normalizeToolResult}from"./tool-bridge/normalize-result.js";export{ThreadStore,defaultThreadsDir,expandTilde}from"./store/thread-store.js";export{DefaultToolPolicy}from"./policy/default-policy.js";export{ConfigurableToolPolicy}from"./policy/configurable-policy.js";export{ApprovalGate}from"./approval/approval-gate.js";export{RuntimeServer}from"./server/runtime-server.js";export{createStdioConnection}from"./server/transport/stdio.js";export{RpcMethod,EVENT_NOTIFICATION,isRequest}from"./server/protocol.js";export{SESSION_CANCELLATION_REASONS,USER_CANCELLATION_ABORT_REASON}from"./types/cancellation.js";
|
|
@@ -38,6 +38,7 @@ export declare const RpcMethod: {
|
|
|
38
38
|
readonly Approve: "session.approve";
|
|
39
39
|
readonly Reject: "session.reject";
|
|
40
40
|
readonly Abort: "session.abort";
|
|
41
|
+
readonly Close: "session.close";
|
|
41
42
|
readonly Messages: "session.messages";
|
|
42
43
|
readonly Compact: "session.compact";
|
|
43
44
|
};
|
|
@@ -96,6 +97,13 @@ export declare const abortParamsSchema: z.ZodObject<{
|
|
|
96
97
|
}, {
|
|
97
98
|
sessionId: string;
|
|
98
99
|
}>;
|
|
100
|
+
export declare const closeParamsSchema: z.ZodObject<{
|
|
101
|
+
sessionId: z.ZodString;
|
|
102
|
+
}, "strip", z.ZodTypeAny, {
|
|
103
|
+
sessionId: string;
|
|
104
|
+
}, {
|
|
105
|
+
sessionId: string;
|
|
106
|
+
}>;
|
|
99
107
|
export declare const messagesParamsSchema: z.ZodObject<{
|
|
100
108
|
sessionId: z.ZodString;
|
|
101
109
|
}, "strip", z.ZodTypeAny, {
|
package/dist/server/protocol.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as s}from"zod";export const RpcMethod={Create:"session.create",Resume:"session.resume",Send:"session.send",Approve:"session.approve",Reject:"session.reject",Abort:"session.abort",Messages:"session.messages",Compact:"session.compact"};export const EVENT_NOTIFICATION="session.event";export const createParamsSchema=s.object({title:s.string().optional()});export const resumeParamsSchema=s.object({threadId:s.string()});export const sendParamsSchema=s.object({sessionId:s.string(),input:s.string()});export const approveParamsSchema=s.object({sessionId:s.string(),approvalId:s.string()});export const rejectParamsSchema=s.object({sessionId:s.string(),approvalId:s.string(),reason:s.string().optional()});export const abortParamsSchema=s.object({sessionId:s.string()});export const messagesParamsSchema=s.object({sessionId:s.string()});export const compactParamsSchema=s.object({sessionId:s.string()});export function isRequest(s){return"method"in s&&"id"in s}
|
|
1
|
+
import{z as s}from"zod";export const RpcMethod={Create:"session.create",Resume:"session.resume",Send:"session.send",Approve:"session.approve",Reject:"session.reject",Abort:"session.abort",Close:"session.close",Messages:"session.messages",Compact:"session.compact"};export const EVENT_NOTIFICATION="session.event";export const createParamsSchema=s.object({title:s.string().optional()});export const resumeParamsSchema=s.object({threadId:s.string()});export const sendParamsSchema=s.object({sessionId:s.string(),input:s.string()});export const approveParamsSchema=s.object({sessionId:s.string(),approvalId:s.string()});export const rejectParamsSchema=s.object({sessionId:s.string(),approvalId:s.string(),reason:s.string().optional()});export const abortParamsSchema=s.object({sessionId:s.string()});export const closeParamsSchema=s.object({sessionId:s.string()});export const messagesParamsSchema=s.object({sessionId:s.string()});export const compactParamsSchema=s.object({sessionId:s.string()});export function isRequest(s){return"method"in s&&"id"in s}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EVENT_NOTIFICATION as s,RpcMethod as e,abortParamsSchema as n,approveParamsSchema as t,
|
|
1
|
+
import{EVENT_NOTIFICATION as s,RpcMethod as e,abortParamsSchema as n,approveParamsSchema as t,closeParamsSchema as o,compactParamsSchema as r,createParamsSchema as i,isRequest as a,messagesParamsSchema as c,rejectParamsSchema as d,resumeParamsSchema as p,sendParamsSchema as h}from"./protocol.js";function u(s){return s instanceof Error?s.message:String(s)}export class RuntimeServer{engine;connection;sessions=new Map;constructor(s,e){this.engine=s,this.connection=e,this.connection.onMessage(s=>this.handleMessage(s))}abortAll(){for(const s of this.sessions.values())s.abort();this.sessions.clear()}handleMessage(s){a(s)&&this.dispatch(s).then(e=>{this.connection.send({jsonrpc:"2.0",id:s.id,result:e})}).catch(e=>{this.connection.send({jsonrpc:"2.0",id:s.id,error:{code:-32e3,message:u(e)}})})}requireSession(s){const e=this.sessions.get(s);if(!e)throw new Error(`Session "${s}" 不存在`);return e}async dispatch(a){switch(a.method){case e.Create:{const s=i.parse(a.params),e=await this.engine.createSession(s.title?{title:s.title}:{});return this.sessions.set(e.id,e),{sessionId:e.id}}case e.Resume:{const s=p.parse(a.params),e=await this.engine.resumeSession(s.threadId);return this.sessions.set(e.id,e),{sessionId:e.id}}case e.Send:{const e=h.parse(a.params),n=this.requireSession(e.sessionId);for await(const t of n.send(e.input))this.connection.send({jsonrpc:"2.0",method:s,params:{sessionId:e.sessionId,event:t}});return{status:"completed"}}case e.Approve:{const s=t.parse(a.params);return{resolved:this.requireSession(s.sessionId).approve(s.approvalId)}}case e.Reject:{const s=d.parse(a.params);return{resolved:this.requireSession(s.sessionId).reject(s.approvalId,s.reason)}}case e.Abort:{const s=n.parse(a.params);return{ok:!0,cancelled:this.requireSession(s.sessionId).cancel()}}case e.Close:{const s=o.parse(a.params);return this.requireSession(s.sessionId).abort(),this.sessions.delete(s.sessionId),{closed:!0}}case e.Messages:{const s=c.parse(a.params);return{messages:this.requireSession(s.sessionId).getMessages()}}case e.Compact:{const e=r.parse(a.params),n=this.requireSession(e.sessionId);for await(const t of n.compact("manual"))this.connection.send({jsonrpc:"2.0",method:s,params:{sessionId:e.sessionId,event:t}});return{status:"completed"}}default:throw new Error(`Unknown method: ${a.method}`)}}}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import type { ToolBridgeContext } from "./build-tools.ts";
|
|
3
|
+
import type { ToolRegistry } from "./naming.ts";
|
|
4
|
+
export declare const AGENT_INSTALL_TOOL_AGENT_NAME = "roll";
|
|
5
|
+
export declare const AGENT_INSTALL_TOOL_NAME = "agent_install";
|
|
6
|
+
export declare const AGENT_INSTALL_TOOL_ID = "roll__agent_install";
|
|
7
|
+
export interface AgentInstallToolCatalogEntry {
|
|
8
|
+
readonly shortName: string;
|
|
9
|
+
readonly description: string;
|
|
10
|
+
}
|
|
11
|
+
export type AgentInstallToolOutcome = {
|
|
12
|
+
readonly ok: true;
|
|
13
|
+
readonly agentName: string;
|
|
14
|
+
readonly version?: string;
|
|
15
|
+
readonly missingEnv: readonly string[];
|
|
16
|
+
readonly retryCommand?: string;
|
|
17
|
+
readonly refreshApplied: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
readonly ok: false;
|
|
20
|
+
readonly message: string;
|
|
21
|
+
readonly retryCommand?: string;
|
|
22
|
+
};
|
|
23
|
+
export interface AgentInstallToolDeps {
|
|
24
|
+
readonly catalog: readonly AgentInstallToolCatalogEntry[];
|
|
25
|
+
readonly install: (shortName: string, report: (line: string) => void) => Promise<AgentInstallToolOutcome>;
|
|
26
|
+
}
|
|
27
|
+
export declare function buildAgentInstallToolset(deps: AgentInstallToolDeps, registry: ToolRegistry, ctx: ToolBridgeContext): ToolSet;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{tool as n}from"ai";import{z as t}from"zod";export const AGENT_INSTALL_TOOL_AGENT_NAME="roll";export const AGENT_INSTALL_TOOL_NAME="agent_install";export const AGENT_INSTALL_TOOL_ID="roll__agent_install";function e(n,t){const e=t.length>0?`\n\n安装日志:\n${t.join("\n")}`:"";if(!n.ok){const t=n.retryCommand?`\n可在终端重试:${n.retryCommand}`:"";return{output:`安装失败:${n.message}${t}${e}`,isError:!0}}const o=n.version?` v${n.version}`:"",r=n.refreshApplied?"新工具将从下一轮对话开始可用。":"当前会话不会自动接入本次安装的版本,请让用户重新运行 roll chat 后使用。",a=n.missingEnv.length>0?`\n缺少必填环境变量:${n.missingEnv.join(", ")}。请让用户在终端运行 \`roll config setup agent ${n.agentName}\` 完成配置。`:"",i=n.retryCommand?`\n浏览器运行时已跳过安装,请让用户在终端补跑:${n.retryCommand}`:"";return{output:`已安装并注册 Agent "${n.agentName}"${o}。${r}${a}${i}${e}`,isError:!1}}export function buildAgentInstallToolset(o,r,a){const i=o.catalog.map(n=>n.shortName),[s,...l]=i;if(void 0===s)return{};const c=r.register("roll","agent_install"),m=t.object({agent:t.enum([s,...l]).describe(`要安装的官方 Agent 短名(可选:${i.join("、")})`)});return{[c]:n({description:`安装并注册一个官方子 Agent(执行 npm install,需要用户确认,可能耗时较长)。可安装:${o.catalog.map(n=>`${n.shortName}(${n.description})`).join(";")}`,inputSchema:m,execute:async n=>{const t=a.policy?.check({agentName:"roll",toolName:"agent_install",input:n,annotations:{destructiveHint:!0}});if("deny"===t?.action)return{output:"策略拒绝执行"+(t.reason?`: ${t.reason}`:""),isError:!0};const r=await a.requestApproval({agentName:"roll",toolName:"agent_install",input:n,reason:`将执行 npm install 并注册子 Agent "${n.agent}"`});if(!r.approved)return{output:"已取消执行"+(r.reason?`: ${r.reason}`:""),isError:!0};const i=[];return e(await o.install(n.agent,n=>i.push(n)),i)}})}}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { SessionEvent } from "../types/events.ts";
|
|
4
|
+
import { type CommandClassifier } from "../types/command-classification.ts";
|
|
5
|
+
import { runBashCommand } from "../bash/exec.ts";
|
|
6
|
+
import type { ShellProfile } from "../bash/profile.ts";
|
|
7
|
+
import { type ToolBridgeContext } from "./build-tools.ts";
|
|
8
|
+
import { ToolRegistry } from "./naming.ts";
|
|
9
|
+
export declare const BASH_TOOL_AGENT_NAME = "roll";
|
|
10
|
+
export declare const BASH_TOOL_NAME = "bash";
|
|
11
|
+
export declare const BASH_TOOL_ID = "roll__bash";
|
|
12
|
+
export declare const POWERSHELL_TOOL_NAME = "powershell";
|
|
13
|
+
export declare const POWERSHELL_TOOL_ID = "roll__powershell";
|
|
14
|
+
export interface SessionBashSettings {
|
|
15
|
+
readonly workdir: string;
|
|
16
|
+
readonly defaultTimeoutMs: number;
|
|
17
|
+
readonly maxTimeoutMs: number;
|
|
18
|
+
readonly turnTimeoutMs: number;
|
|
19
|
+
readonly maxCaptureBytes: number;
|
|
20
|
+
readonly maxModelOutputChars: number;
|
|
21
|
+
readonly profile: ShellProfile;
|
|
22
|
+
}
|
|
23
|
+
export interface BashToolContext extends ToolBridgeContext {
|
|
24
|
+
readonly emitEvent?: (event: SessionEvent) => void;
|
|
25
|
+
}
|
|
26
|
+
export interface BashToolDeps {
|
|
27
|
+
readonly classifier?: CommandClassifier;
|
|
28
|
+
readonly exec?: typeof runBashCommand;
|
|
29
|
+
}
|
|
30
|
+
declare const bashToolInputSchema: z.ZodObject<{
|
|
31
|
+
command: z.ZodString;
|
|
32
|
+
workdir: z.ZodOptional<z.ZodString>;
|
|
33
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
command: string;
|
|
36
|
+
workdir?: string | undefined;
|
|
37
|
+
timeout_ms?: number | undefined;
|
|
38
|
+
}, {
|
|
39
|
+
command: string;
|
|
40
|
+
workdir?: string | undefined;
|
|
41
|
+
timeout_ms?: number | undefined;
|
|
42
|
+
}>;
|
|
43
|
+
export type BashToolInput = z.infer<typeof bashToolInputSchema>;
|
|
44
|
+
export declare function buildBashToolset(settings: SessionBashSettings, registry: ToolRegistry, ctx: BashToolContext, deps?: BashToolDeps): ToolSet;
|
|
45
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{resolve as o}from"node:path";import{tool as t}from"ai";import{z as r}from"zod";import{CLASSIFICATION_ANNOTATIONS as e}from"../types/command-classification.js";import{runBashCommand as i}from"../bash/exec.js";import{formatBashResult as s}from"../bash/format-result.js";import{isWithinWorkdirRoot as a}from"../bash/workdir.js";import{gateToolCall as n}from"./build-tools.js";import{ToolRegistry as l}from"./naming.js";export const BASH_TOOL_AGENT_NAME="roll";export const BASH_TOOL_NAME="bash";export const BASH_TOOL_ID="roll__bash";export const POWERSHELL_TOOL_NAME="powershell";export const POWERSHELL_TOOL_ID="roll__powershell";const m=256,c=4096,u=r.object({command:r.string().min(1).describe("要执行的 shell 命令(单字符串,由当前 shell 后端执行)"),workdir:r.string().min(1).optional().describe("工作目录绝对路径,默认为 roll chat 当前目录。不要在 command 里用 cd,改用本字段"),timeout_ms:r.number().int().min(1).max(6e5).optional().describe("超时毫秒数。默认 10000,上限受 maxTimeoutMs 与 turnTimeoutMs 约束;长脚本请显式调大")});function p(o,t,r){const e=o.emitEvent;if(!e)return;let i=0;return(o,s)=>{if(i>=m)return;i+=1;const a=s.length>c?s.slice(0,c):s;e({type:"tool-output-delta",toolCallId:t,agentName:"roll",toolName:r,stream:o,delta:a})}}async function d(o,t,r,e){if(o.policy)return n(o,"roll",t,r,e);const i=await o.requestApproval({agentName:"roll",toolName:t,input:r,reason:"shell 命令需确认"});return i.approved?void 0:{output:"已取消执行"+(i.reason?`: ${i.reason}`:""),isError:!0}}export function buildBashToolset(r,n,l,m={}){const c=r.profile.toolName,f=n.register("roll",c),h=m.classifier??r.profile,_=m.exec??i;return{[f]:t({description:"在当前 shell 后端中执行一条命令并返回输出。命令继承 roll 进程的全部环境变量。总是用 workdir 参数设置工作目录,不要用 cd。",inputSchema:u,execute:async(t,i)=>{const n=o(r.workdir,t.workdir??"."),m=Math.min(t.timeout_ms??r.defaultTimeoutMs,r.maxTimeoutMs,r.turnTimeoutMs),u=a(r.workdir,n)?h.classify(t.command,n):"unknown",f=e[u],x={command:t.command,workdir:n,timeout_ms:m},b=await d(l,c,x,f);if(b)return b;const w=p(l,i.toolCallId,c),O=await _({command:t.command,workdir:n,timeoutMs:m,maxCaptureBytes:r.maxCaptureBytes,profile:r.profile,env:process.env,...i.abortSignal?{abortSignal:i.abortSignal}:{},...w?{onDelta:w}:{}});return s({result:O,maxModelOutputChars:r.maxModelOutputChars})}})}}
|
|
@@ -4,6 +4,7 @@ import type { AgentTool } from "@roll-agent/core/types/agent";
|
|
|
4
4
|
import type { ApprovalDecision } from "../approval/approval-gate.ts";
|
|
5
5
|
import type { ToolAnnotations, ToolPolicy } from "../types/policy.ts";
|
|
6
6
|
import { ToolRegistry } from "./naming.ts";
|
|
7
|
+
import { type NormalizedToolResult } from "./normalize-result.ts";
|
|
7
8
|
export interface SourceTool {
|
|
8
9
|
readonly tool: AgentTool;
|
|
9
10
|
readonly annotations: ToolAnnotations | undefined;
|
|
@@ -27,4 +28,5 @@ export interface BuiltToolset {
|
|
|
27
28
|
readonly tools: ToolSet;
|
|
28
29
|
readonly registry: ToolRegistry;
|
|
29
30
|
}
|
|
31
|
+
export declare function gateToolCall(ctx: ToolBridgeContext, agentName: string, toolName: string, input: Record<string, unknown>, annotations: ToolAnnotations | undefined): Promise<NormalizedToolResult | undefined>;
|
|
30
32
|
export declare function buildAgentToolset(sources: readonly AgentToolSource[], ctx: ToolBridgeContext, registry?: ToolRegistry): BuiltToolset;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsonSchema as o,tool as t}from"ai";import{preflightToolCall as n}from"@roll-agent/core/tool-runtime/preflight";import{ToolRegistry as r}from"./naming.js";import{normalizeToolResult as e}from"./normalize-result.js";function a(o){return"object"!=typeof o||null===o||Array.isArray(o)?{}:o}function i(o){return`参数校验失败: ${o.map(o=>o.message).join("; ")}`}async function
|
|
1
|
+
import{jsonSchema as o,tool as t}from"ai";import{preflightToolCall as n}from"@roll-agent/core/tool-runtime/preflight";import{ToolRegistry as r}from"./naming.js";import{normalizeToolResult as e}from"./normalize-result.js";function a(o){return"object"!=typeof o||null===o||Array.isArray(o)?{}:o}function i(o){return`参数校验失败: ${o.map(o=>o.message).join("; ")}`}export async function gateToolCall(o,t,n,r,e){if(!o.policy)return;const a=o.policy.check({agentName:t,toolName:n,input:r,...e?{annotations:e}:{}});if("deny"===a.action)return{output:"策略拒绝执行"+(a.reason?`: ${a.reason}`:""),isError:!0};if("confirm"===a.action){const e=await o.requestApproval({agentName:t,toolName:n,input:r,reason:a.reason});if(!e.approved)return{output:"已取消执行"+(e.reason?`: ${e.reason}`:""),isError:!0}}}export function buildAgentToolset(s,c,l=new r){const u={};for(const r of s){const{client:s,agentName:m}=r;for(const{tool:p,annotations:f}of r.tools){u[l.register(m,p.name)]=t({description:p.description??`${p.name} (via ${m})`,inputSchema:o(p.inputSchema),execute:async(o,t)=>{const r=a(o),l=n(p,r);if(!l.ok)return{output:i(l.issues),isError:!0};const u=await gateToolCall(c,m,p.name,r,f);if(u)return u;const g=t.abortSignal?{signal:t.abortSignal}:void 0,y=await s.callTool({name:p.name,arguments:r},void 0,g);return e(y)}})}}return{tools:u,registry:l}}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { type CommandClassifier } from "../types/command-classification.ts";
|
|
4
|
+
import { type SessionManager } from "../bash/session/session-manager.ts";
|
|
5
|
+
import type { BashToolContext } from "./bash-tool.ts";
|
|
6
|
+
import { ToolRegistry } from "./naming.ts";
|
|
7
|
+
export declare const EXEC_AGENT_NAME = "roll";
|
|
8
|
+
export declare const EXEC_COMMAND_NAME = "exec_command";
|
|
9
|
+
export declare const EXEC_POLL_NAME = "exec_poll";
|
|
10
|
+
export declare const EXEC_COMMAND_ID = "roll__exec_command";
|
|
11
|
+
export declare const EXEC_POLL_ID = "roll__exec_poll";
|
|
12
|
+
export interface SessionExecSettings {
|
|
13
|
+
readonly workdir: string;
|
|
14
|
+
readonly defaultYieldMs: number;
|
|
15
|
+
readonly maxOutputTokens: number;
|
|
16
|
+
}
|
|
17
|
+
export interface SessionExecDeps {
|
|
18
|
+
readonly classifier?: CommandClassifier;
|
|
19
|
+
}
|
|
20
|
+
declare const execCommandInputSchema: z.ZodObject<{
|
|
21
|
+
command: z.ZodString;
|
|
22
|
+
workdir: z.ZodOptional<z.ZodString>;
|
|
23
|
+
yield_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
max_output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
command: string;
|
|
27
|
+
workdir?: string | undefined;
|
|
28
|
+
yield_time_ms?: number | undefined;
|
|
29
|
+
max_output_tokens?: number | undefined;
|
|
30
|
+
}, {
|
|
31
|
+
command: string;
|
|
32
|
+
workdir?: string | undefined;
|
|
33
|
+
yield_time_ms?: number | undefined;
|
|
34
|
+
max_output_tokens?: number | undefined;
|
|
35
|
+
}>;
|
|
36
|
+
declare const execPollInputSchema: z.ZodObject<{
|
|
37
|
+
session_id: z.ZodNumber;
|
|
38
|
+
chars: z.ZodDefault<z.ZodString>;
|
|
39
|
+
yield_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
session_id: number;
|
|
42
|
+
chars: string;
|
|
43
|
+
yield_time_ms?: number | undefined;
|
|
44
|
+
}, {
|
|
45
|
+
session_id: number;
|
|
46
|
+
yield_time_ms?: number | undefined;
|
|
47
|
+
chars?: string | undefined;
|
|
48
|
+
}>;
|
|
49
|
+
export type ExecCommandInput = z.infer<typeof execCommandInputSchema>;
|
|
50
|
+
export type ExecPollInput = z.infer<typeof execPollInputSchema>;
|
|
51
|
+
export declare function buildSessionExecToolset(settings: SessionExecSettings, manager: SessionManager, registry: ToolRegistry, ctx: BashToolContext, deps?: SessionExecDeps): ToolSet;
|
|
52
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as e}from"node:fs";import{resolve as t}from"node:path";import{performance as o}from"node:perf_hooks";import{tool as i}from"ai";import{z as n}from"zod";import{CLASSIFICATION_ANNOTATIONS as r,unknownCommandClassifier as s}from"../types/command-classification.js";import{isWithinWorkdirRoot as l}from"../bash/workdir.js";import{SessionCapError as a}from"../bash/session/session-manager.js";import{pollUntilDeadline as c}from"../bash/session/yield-loop.js";import{gateToolCall as m}from"./build-tools.js";import{ToolRegistry as d}from"./naming.js";import{isUserCancellationSignal as u}from"../types/cancellation.js";export const EXEC_AGENT_NAME="roll";export const EXEC_COMMAND_NAME="exec_command";export const EXEC_POLL_NAME="exec_poll";export const EXEC_COMMAND_ID="roll__exec_command";export const EXEC_POLL_ID="roll__exec_poll";const p=String.fromCharCode(3),_=250,f=3e4,x=5e3,h=3e5,E=8192,g=4096,b=4,k=n.object({command:n.string().min(1).describe("要在后台会话中执行的 shell 命令(单字符串)"),workdir:n.string().min(1).optional().describe("工作目录绝对路径,默认 roll chat 当前目录,不要用 cd"),yield_time_ms:n.number().int().min(_).max(f).optional().describe("本次等待输出的毫秒数(默认 10000,范围 250-30000);未结束会返回 session_id 供 exec_poll 续查"),max_output_tokens:n.number().int().min(256).max(5e4).optional().describe("本次返回输出的 token 预算")}),C=n.object({session_id:n.number().int().describe("exec_command 返回的会话 id"),chars:n.string().default("").describe('留空表示纯轮询进度;"\\u0003"(Ctrl-C) 表示中断该会话;不支持其它交互输入'),yield_time_ms:n.number().int().min(x).max(h).optional().describe("空轮询等待的毫秒数(默认 10000,范围 5000-300000)")});function w(e,t,o){return Math.min(Math.max(e,t),o)}function y(e,t,o){const i=e.emitEvent;if(!i)return;let n=0;return(e,r)=>{if(n>=E)return;n+=1;const s=r.length>g?r.slice(0,g):r;i({type:"tool-output-delta",toolCallId:t,agentName:"roll",toolName:o,stream:e,delta:s})}}async function M(e,t,o){if(e.policy)return m(e,"roll","exec_command",t,o);const i=await e.requestApproval({agentName:"roll",toolName:"exec_command",input:t,reason:"shell 命令需确认"});return i.approved?void 0:{output:"已取消执行"+(i.reason?`: ${i.reason}`:""),isError:!0}}function S(e){const t=["running"===e.kind?`Session: ${String(e.sessionId)} (running)`:`Exit code: ${String(e.exitCode)}`,`Wall time: ${(e.wallTimeMs/1e3).toFixed(1)} s`];e.omitted>0&&t.push(`(省略中间 ${String(e.omitted)} 字符)`);const o=e.output.length>0?`\n\n${e.output}`:"";return{output:t.join("\n")+o,isError:"exited"===e.kind&&0!==e.exitCode}}function j(e,t,o){if(void 0===e)return()=>{};const i=()=>{u(e)&&o.get(t.id)===t&&t.profile.killTree(t.child.pid,"interrupt").then(()=>t.waitExit()).then(()=>o.delete(t.id)).catch(()=>{})};return e.addEventListener("abort",i,{once:!0}),e.aborted&&i(),()=>e.removeEventListener("abort",i)}export function buildSessionExecToolset(n,m,d,u,E={}){const g=d.register("roll","exec_command"),b=d.register("roll","exec_poll"),N=E.classifier??s;return{[g]:i({description:"在后台会话中执行一条命令,等待一段时间后返回输出。若命令未结束会返回 session_id,用 exec_poll 续查进度、读取退出码。适合运行时间超过单轮预算的长脚本。命令继承 roll 进程的环境变量。",inputSchema:k,execute:async(i,s)=>{const d=t(n.workdir,i.workdir??".");if(!e(d))return{output:`工作目录不存在: ${d}`,isError:!0};const p=w(i.yield_time_ms??n.defaultYieldMs,_,f),x=l(n.workdir,d)?N.classify(i.command,d):"unknown",h=r[x],E={command:i.command,workdir:d,yield_time_ms:p},g=await M(u,E,h);if(g)return g;const b=4*(i.max_output_tokens??n.maxOutputTokens),k=y(u,s.toolCallId,"exec_command");let C;try{C=m.spawn({command:i.command,workdir:d,...k?{onDelta:k}:{}})}catch(e){return{output:e instanceof a?e.message:`无法启动会话: ${String(e)}`,isError:!0}}const $=j(s.abortSignal,C,m),v=await c(C,o.now()+p,b).finally($);return"exited"===v.kind&&m.delete(C.id),S(v)}}),[b]:i({description:'轮询或中断一个 exec_command 会话。session_id 为 exec_command 返回的 id;chars 留空表示纯轮询进度,"\\u0003" 表示发送 Ctrl-C 中断。返回最新输出,进程结束时返回退出码。',inputSchema:C,execute:async(e,t)=>{const i=m.get(e.session_id);if(!i)return{output:`会话 ${String(e.session_id)} 不存在或已结束`,isError:!0};if(e.chars===p)i.profile.killTree(i.child.pid,"interrupt").catch(()=>{});else if(""!==e.chars)return{output:"pipe 会话不支持交互输入(仅支持空 chars 轮询或 Ctrl-C \\u0003 中断)",isError:!0};const r=y(u,t.toolCallId,"exec_poll");r&&(i.onDelta=r);const s=w(e.yield_time_ms??Math.max(n.defaultYieldMs,x),x,h),l=4*n.maxOutputTokens,a=j(t.abortSignal,i,m),d=await c(i,o.now()+s,l).finally(a);return"exited"===d.kind&&m.delete(e.session_id),S(d)}})}}
|
|
@@ -18,4 +18,4 @@ declare const skillToolInputSchema: z.ZodObject<{
|
|
|
18
18
|
}>;
|
|
19
19
|
export type SkillToolInput = z.infer<typeof skillToolInputSchema>;
|
|
20
20
|
export declare function executeSkillTool(library: SkillLibrary, input: SkillToolInput): NormalizedToolResult;
|
|
21
|
-
export declare function buildSkillToolset(library: SkillLibrary, registry: ToolRegistry): ToolSet;
|
|
21
|
+
export declare function buildSkillToolset(library: SkillLibrary | (() => SkillLibrary), registry: ToolRegistry): ToolSet;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{tool as e}from"ai";import{z as r}from"zod";import{SKILL_TOOL_ID as n}from"@roll-agent/core/skills/library";export const SKILL_TOOL_AGENT_NAME="roll";export const SKILL_TOOL_NAME="skill";export{n as SKILL_TOOL_ID};const
|
|
1
|
+
import{tool as e}from"ai";import{z as r}from"zod";import{SKILL_TOOL_ID as n}from"@roll-agent/core/skills/library";export const SKILL_TOOL_AGENT_NAME="roll";export const SKILL_TOOL_NAME="skill";export{n as SKILL_TOOL_ID};const o=6e4,t=r.object({name:r.string().min(1).describe("要加载的 skill 名称(见 system prompt 中的 Skills 目录)"),reference:r.string().min(1).optional().describe("可选:加载该 skill 的 references/ 下的某个文件,传相对路径如 references/workflows.md")});function i(e){return e.length<=o?e:`${e.slice(0,o)}\n\n[内容过长已截断,共 ${String(e.length)} 字符]`}function l(e,r){return void 0===e?r:[`SKILL_ROOT=${e}`,"这是该 skill 的 canonical absolute root。所有 scripts/、references/ 和其它相对路径必须相对 SKILL_ROOT 解析;执行脚本时将 workdir 设为 SKILL_ROOT,不要搜索其它 skill 目录。","",r].join("\n")}function s(e,r){return{output:`skill "${r}" 不存在。可用 skill: ${e.list().map(e=>e.name).join(", ")}`,isError:!0}}function c(e,r){const n=e.load(r);if(!n)return s(e,r);const o=n.referencePaths.length>0?`\n\n可用 references(传 reference 参数加载):\n${n.referencePaths.map(e=>`- ${e}`).join("\n")}`:"";return{output:l(n.skillRoot,`${i(n.content)}${o}`),isError:!1}}function u(e,r,n){if(!e.list().some(e=>e.name===r))return s(e,r);const o=void 0===e.loadReferenceDocument?void 0:e.loadReferenceDocument(r,n),t=void 0===e.loadReferenceDocument?e.loadReference(r,n):o?.content;return void 0===t?{output:`skill "${r}" 中不存在 reference "${n}"(仅支持 skill 目录内 references/ 下的文件)`,isError:!0}:{output:l(o?.skillRoot,i(t)),isError:!1}}export function executeSkillTool(e,r){return void 0!==r.reference?u(e,r.name,r.reference):c(e,r.name)}export function buildSkillToolset(r,n){const o="function"==typeof r?r:()=>r,i=n.register("roll","skill");return{[i]:e({description:"加载一个 skill(技能说明书)的完整内容,或其 references/ 下的文件。执行涉及某个 skill 领域的任务前,先用它读取流程与约束。",inputSchema:t,execute:e=>executeSkillTool(o(),e)})}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const SESSION_CANCELLATION_REASONS: {
|
|
2
|
+
readonly user: "user";
|
|
3
|
+
readonly timeout: "timeout";
|
|
4
|
+
readonly runtime: "runtime";
|
|
5
|
+
};
|
|
6
|
+
export type SessionCancellationReason = (typeof SESSION_CANCELLATION_REASONS)[keyof typeof SESSION_CANCELLATION_REASONS];
|
|
7
|
+
export declare const USER_CANCELLATION_ABORT_REASON = "roll:user-cancelled";
|
|
8
|
+
export declare const RUNTIME_CANCELLATION_ABORT_REASON = "roll:runtime-aborted";
|
|
9
|
+
export declare const TURN_TIMEOUT_ABORT_REASON = "roll:turn-timeout";
|
|
10
|
+
export declare function isTurnTimeoutAbortReason(reason: unknown): boolean;
|
|
11
|
+
export declare function isTimeoutAbortReason(reason: unknown): boolean;
|
|
12
|
+
export declare function isUserCancellationSignal(signal: AbortSignal | undefined): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SESSION_CANCELLATION_REASONS={user:"user",timeout:"timeout",runtime:"runtime"};export const USER_CANCELLATION_ABORT_REASON="roll:user-cancelled";export const RUNTIME_CANCELLATION_ABORT_REASON="roll:runtime-aborted";export const TURN_TIMEOUT_ABORT_REASON="roll:turn-timeout";export function isTurnTimeoutAbortReason(t){return"roll:turn-timeout"===t}export function isTimeoutAbortReason(t){return isTurnTimeoutAbortReason(t)||t instanceof DOMException&&"TimeoutError"===t.name}export function isUserCancellationSignal(t){return!0===t?.aborted&&"roll:user-cancelled"===t.reason}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ToolAnnotations } from "./policy.ts";
|
|
2
|
+
export declare const COMMAND_CLASSIFICATIONS: readonly ["known-safe", "dangerous", "unknown"];
|
|
3
|
+
export type CommandClassification = (typeof COMMAND_CLASSIFICATIONS)[number];
|
|
4
|
+
export interface CommandClassifier {
|
|
5
|
+
classify(command: string, workdir: string): CommandClassification;
|
|
6
|
+
}
|
|
7
|
+
export declare const unknownCommandClassifier: CommandClassifier;
|
|
8
|
+
export declare const CLASSIFICATION_ANNOTATIONS: Record<CommandClassification, ToolAnnotations>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const COMMAND_CLASSIFICATIONS=["known-safe","dangerous","unknown"];export const unknownCommandClassifier={classify:()=>"unknown"};export const CLASSIFICATION_ANNOTATIONS={"known-safe":{readOnlyHint:!0},dangerous:{destructiveHint:!0},unknown:{destructiveHint:!0}};
|
package/dist/types/events.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SessionCancellationReason } from "./cancellation.ts";
|
|
1
2
|
export interface SessionTokenUsage {
|
|
2
3
|
readonly inputTokens?: number;
|
|
3
4
|
readonly outputTokens?: number;
|
|
@@ -34,6 +35,13 @@ export type SessionEvent = {
|
|
|
34
35
|
readonly toolName: string;
|
|
35
36
|
readonly output: unknown;
|
|
36
37
|
readonly isError: boolean;
|
|
38
|
+
} | {
|
|
39
|
+
readonly type: "tool-output-delta";
|
|
40
|
+
readonly toolCallId: string;
|
|
41
|
+
readonly agentName: string;
|
|
42
|
+
readonly toolName: string;
|
|
43
|
+
readonly stream: "stdout" | "stderr";
|
|
44
|
+
readonly delta: string;
|
|
37
45
|
} | {
|
|
38
46
|
readonly type: "confirmation-required";
|
|
39
47
|
readonly approvalId: string;
|
|
@@ -64,6 +72,10 @@ export type SessionEvent = {
|
|
|
64
72
|
readonly kept: number;
|
|
65
73
|
readonly truncatedTools?: number;
|
|
66
74
|
readonly beforeInputTokens?: number;
|
|
75
|
+
} | {
|
|
76
|
+
readonly type: "turn-cancelled";
|
|
77
|
+
readonly reason: SessionCancellationReason;
|
|
78
|
+
readonly message: string;
|
|
67
79
|
} | {
|
|
68
80
|
readonly type: "error";
|
|
69
81
|
readonly stage: SessionEventStage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roll-agent/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^22.0.0",
|
|
36
|
-
"@roll-agent/core": "0.
|
|
36
|
+
"@roll-agent/core": "0.17.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && node ../../scripts/obfuscate.mjs",
|