@botbotgo/runtime 1.0.0 → 1.0.2
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/.github/workflows/release.yml +65 -0
- package/config/examples/runtime.yaml +14 -0
- package/config/examples/tool.yaml +1 -1
- package/dist/config/resolveRuntimeConfig.d.ts +3 -1
- package/dist/config/resolveRuntimeConfig.d.ts.map +1 -1
- package/dist/config/resolveRuntimeConfig.js +2 -0
- package/dist/config/resolveRuntimeConfig.js.map +1 -1
- package/dist/config/resources.d.ts +17 -0
- package/dist/config/resources.d.ts.map +1 -1
- package/dist/config/resources.js.map +1 -1
- package/dist/runtime/bootstrap/runtimeFactory.d.ts.map +1 -1
- package/dist/runtime/bootstrap/runtimeFactory.js +4 -0
- package/dist/runtime/bootstrap/runtimeFactory.js.map +1 -1
- package/dist/runtime/execution/agentRunExecutor.d.ts +1 -0
- package/dist/runtime/execution/agentRunExecutor.d.ts.map +1 -1
- package/dist/runtime/execution/agentRunExecutor.js +3 -0
- package/dist/runtime/execution/agentRunExecutor.js.map +1 -1
- package/dist/runtime/execution/agentRunExecutor.types.d.ts +2 -0
- package/dist/runtime/execution/agentRunExecutor.types.d.ts.map +1 -1
- package/dist/runtime/middleware/agentToolMiddleware.d.ts +2 -0
- package/dist/runtime/middleware/agentToolMiddleware.d.ts.map +1 -1
- package/dist/runtime/middleware/agentToolMiddleware.js +17 -4
- package/dist/runtime/middleware/agentToolMiddleware.js.map +1 -1
- package/dist/runtime/middleware/commandPolicy.d.ts +2 -1
- package/dist/runtime/middleware/commandPolicy.d.ts.map +1 -1
- package/dist/runtime/middleware/commandPolicy.js +14 -11
- package/dist/runtime/middleware/commandPolicy.js.map +1 -1
- package/dist/runtime/middleware/frameworkPrompt.d.ts.map +1 -1
- package/dist/runtime/middleware/frameworkPrompt.js +2 -3
- package/dist/runtime/middleware/frameworkPrompt.js.map +1 -1
- package/dist/runtime/middleware/toolArgsNormalizer.d.ts +1 -0
- package/dist/runtime/middleware/toolArgsNormalizer.d.ts.map +1 -1
- package/dist/runtime/middleware/toolArgsNormalizer.js +32 -0
- package/dist/runtime/middleware/toolArgsNormalizer.js.map +1 -1
- package/dist/runtime/middleware/toolCallGuard.d.ts +3 -1
- package/dist/runtime/middleware/toolCallGuard.d.ts.map +1 -1
- package/dist/runtime/middleware/toolCallGuard.js +24 -4
- package/dist/runtime/middleware/toolCallGuard.js.map +1 -1
- package/dist/runtime/middleware/types.d.ts +2 -0
- package/dist/runtime/middleware/types.d.ts.map +1 -1
- package/dist/runtime/middleware/types.js.map +1 -1
- package/dist/runtime/runtimeService.d.ts +2 -0
- package/dist/runtime/runtimeService.d.ts.map +1 -1
- package/dist/runtime/runtimeService.js +1 -0
- package/dist/runtime/runtimeService.js.map +1 -1
- package/dist/runtime/stream/runArtifacts.d.ts.map +1 -1
- package/dist/runtime/stream/runArtifacts.js +3 -1
- package/dist/runtime/stream/runArtifacts.js.map +1 -1
- package/dist/state/runState.d.ts +1 -0
- package/dist/state/runState.d.ts.map +1 -1
- package/dist/state/runState.js +18 -1
- package/dist/state/runState.js.map +1 -1
- package/dist/state/workspaceState.d.ts +2 -0
- package/dist/state/workspaceState.d.ts.map +1 -1
- package/dist/state/workspaceState.js +12 -10
- package/dist/state/workspaceState.js.map +1 -1
- package/example/config/model.yaml +2 -2
- package/example/config/runtime.yaml +19 -1
- package/example/package.json +0 -1
- package/package.json +1 -1
- package/src/config/resolveRuntimeConfig.ts +5 -0
- package/src/config/resources.ts +19 -0
- package/src/runtime/bootstrap/runtimeFactory.ts +7 -0
- package/src/runtime/execution/agentRunExecutor.ts +3 -0
- package/src/runtime/execution/agentRunExecutor.types.ts +2 -0
- package/src/runtime/middleware/agentToolMiddleware.ts +19 -3
- package/src/runtime/middleware/commandPolicy.ts +22 -10
- package/src/runtime/middleware/frameworkPrompt.ts +2 -3
- package/src/runtime/middleware/toolArgsNormalizer.ts +36 -0
- package/src/runtime/middleware/toolCallGuard.ts +37 -3
- package/src/runtime/middleware/types.ts +2 -0
- package/src/runtime/runtimeService.ts +3 -0
- package/src/runtime/stream/runArtifacts.ts +3 -1
- package/src/state/runState.ts +19 -1
- package/src/state/workspaceState.ts +19 -11
- package/test/unit/config/loader.test.ts +10 -0
- package/test/unit/runtime/agentToolMiddleware.test.ts +51 -0
- package/test/unit/runtime/toolArgsNormalizer.test.ts +34 -0
- package/test/unit/runtime/toolCallGuard.test.ts +71 -0
- package/test/unit/runtime/workspaceState.test.ts +94 -0
- package/example/.tsbuildinfo +0 -1
- package/example/build/.tsbuildinfo +0 -1
- package/example/serve-output.mjs +0 -52
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaceState.js","sourceRoot":"","sources":["../../src/state/workspaceState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAsB,wBAAwB,EAAsB,MAAM,eAAe,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,0BAA0B,EAA6B,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"workspaceState.js","sourceRoot":"","sources":["../../src/state/workspaceState.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,10 @@ spec:
|
|
|
10
10
|
- key: companyReportHtml
|
|
11
11
|
path: output/company-report.html
|
|
12
12
|
|
|
13
|
+
# Resume interrupted runs by default so repeated invocations can continue
|
|
14
|
+
# from .agent/run-state.json instead of restarting from scratch.
|
|
15
|
+
resumeInterruptedRun: true
|
|
16
|
+
|
|
13
17
|
# Workspace state persisted under the example root.
|
|
14
18
|
stateDirName: .agent
|
|
15
19
|
legacyOutputState: true
|
|
@@ -23,7 +27,7 @@ spec:
|
|
|
23
27
|
|
|
24
28
|
# Execution limits tuned for a skill-driven report run.
|
|
25
29
|
executeTimeoutMs: 60000
|
|
26
|
-
llmIdleTimeoutMs:
|
|
30
|
+
llmIdleTimeoutMs: 300000
|
|
27
31
|
heartbeatIntervalMs: 5000
|
|
28
32
|
backend:
|
|
29
33
|
type: local_shell
|
|
@@ -36,6 +40,20 @@ spec:
|
|
|
36
40
|
malformedToolCallMaxRetries: 0
|
|
37
41
|
idleTimeoutMaxRetries: 1
|
|
38
42
|
|
|
43
|
+
# Middleware guardrails can be tuned here without code changes.
|
|
44
|
+
middleware:
|
|
45
|
+
forbidScriptSourceRead: true
|
|
46
|
+
forbidAbsolutePathsOutsideWorkspace: true
|
|
47
|
+
commandPolicy:
|
|
48
|
+
blockFuzzyLsProbes: true
|
|
49
|
+
blockShellWrappedSkillScripts: true
|
|
50
|
+
blockChmodX: true
|
|
51
|
+
blockShellDashLc: true
|
|
52
|
+
blockDirectNetworkFetch: true
|
|
53
|
+
blockReportgenPipe: true
|
|
54
|
+
blockShellFileRedirection: true
|
|
55
|
+
blockAbsolutePathsOutsideWorkspace: true
|
|
56
|
+
|
|
39
57
|
# Fine-grained event toggles. Prefer this over eventLogLevel when you need
|
|
40
58
|
# explicit control over which runtime events are printed.
|
|
41
59
|
debug:
|
package/example/package.json
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"build": "tsc --incremental --tsBuildInfoFile .tsbuildinfo",
|
|
9
9
|
"start": "node --import tsx index.ts",
|
|
10
10
|
"start:prod": "npm --prefix .. run build && npm run build && node dist/index.js",
|
|
11
|
-
"report:serve": "node serve-output.mjs",
|
|
12
11
|
"dev": "tsx index.ts",
|
|
13
12
|
"test": "npm run build"
|
|
14
13
|
},
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import type {
|
|
8
8
|
AgentBackendConfigSpec,
|
|
9
9
|
AgentRuntimeConfigResource,
|
|
10
|
+
AgentRuntimeMiddlewareSpec,
|
|
10
11
|
KnownResource,
|
|
11
12
|
MemoryConfigResource,
|
|
12
13
|
} from "./resources.js";
|
|
@@ -48,6 +49,7 @@ export interface ResolvedAgentRuntimeConfig {
|
|
|
48
49
|
key: string;
|
|
49
50
|
path: string;
|
|
50
51
|
}>;
|
|
52
|
+
resumeInterruptedRun?: boolean;
|
|
51
53
|
stateDirName?: string;
|
|
52
54
|
legacyOutputState?: boolean;
|
|
53
55
|
executeTimeoutMs?: number;
|
|
@@ -60,6 +62,7 @@ export interface ResolvedAgentRuntimeConfig {
|
|
|
60
62
|
malformedToolCallMaxRetries?: number;
|
|
61
63
|
idleTimeoutMaxRetries?: number;
|
|
62
64
|
heartbeatIntervalMs?: number;
|
|
65
|
+
middleware?: AgentRuntimeMiddlewareSpec;
|
|
63
66
|
debug?: {
|
|
64
67
|
run?: boolean;
|
|
65
68
|
workspace?: boolean;
|
|
@@ -127,6 +130,7 @@ function resolveStore(s: MemoryConfigResource["spec"]["memory"]["thread"]): Memo
|
|
|
127
130
|
function resolveRuntime(s: AgentRuntimeConfigResource["spec"]): ResolvedAgentRuntimeConfig {
|
|
128
131
|
return {
|
|
129
132
|
artifacts: s.artifacts,
|
|
133
|
+
resumeInterruptedRun: s.resumeInterruptedRun,
|
|
130
134
|
stateDirName: s.stateDirName,
|
|
131
135
|
legacyOutputState: s.legacyOutputState,
|
|
132
136
|
executeTimeoutMs: s.executeTimeoutMs,
|
|
@@ -139,6 +143,7 @@ function resolveRuntime(s: AgentRuntimeConfigResource["spec"]): ResolvedAgentRun
|
|
|
139
143
|
malformedToolCallMaxRetries: s.malformedToolCallMaxRetries,
|
|
140
144
|
idleTimeoutMaxRetries: s.idleTimeoutMaxRetries,
|
|
141
145
|
heartbeatIntervalMs: s.heartbeatIntervalMs,
|
|
146
|
+
middleware: s.middleware,
|
|
142
147
|
debug: s.debug,
|
|
143
148
|
eventLogLevel: s.eventLogLevel,
|
|
144
149
|
};
|
package/src/config/resources.ts
CHANGED
|
@@ -95,11 +95,29 @@ export interface AgentBackendConfigSpec {
|
|
|
95
95
|
maxOutputBytes?: number;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
export interface AgentRuntimeCommandPolicySpec {
|
|
99
|
+
blockFuzzyLsProbes?: boolean;
|
|
100
|
+
blockShellWrappedSkillScripts?: boolean;
|
|
101
|
+
blockChmodX?: boolean;
|
|
102
|
+
blockShellDashLc?: boolean;
|
|
103
|
+
blockDirectNetworkFetch?: boolean;
|
|
104
|
+
blockReportgenPipe?: boolean;
|
|
105
|
+
blockShellFileRedirection?: boolean;
|
|
106
|
+
blockAbsolutePathsOutsideWorkspace?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface AgentRuntimeMiddlewareSpec {
|
|
110
|
+
forbidScriptSourceRead?: boolean;
|
|
111
|
+
forbidAbsolutePathsOutsideWorkspace?: boolean;
|
|
112
|
+
commandPolicy?: AgentRuntimeCommandPolicySpec;
|
|
113
|
+
}
|
|
114
|
+
|
|
98
115
|
export interface AgentRuntimeConfigSpec {
|
|
99
116
|
artifacts?: Array<{
|
|
100
117
|
key: string;
|
|
101
118
|
path: string;
|
|
102
119
|
}>;
|
|
120
|
+
resumeInterruptedRun?: boolean;
|
|
103
121
|
stateDirName?: string;
|
|
104
122
|
legacyOutputState?: boolean;
|
|
105
123
|
executeTimeoutMs?: number;
|
|
@@ -112,6 +130,7 @@ export interface AgentRuntimeConfigSpec {
|
|
|
112
130
|
malformedToolCallMaxRetries?: number;
|
|
113
131
|
idleTimeoutMaxRetries?: number;
|
|
114
132
|
heartbeatIntervalMs?: number;
|
|
133
|
+
middleware?: AgentRuntimeMiddlewareSpec;
|
|
115
134
|
debug?: {
|
|
116
135
|
run?: boolean;
|
|
117
136
|
workspace?: boolean;
|
|
@@ -69,6 +69,7 @@ export class AgentRuntimeFactory {
|
|
|
69
69
|
defaultEmptyRunMaxRetries: runtimeDeps.defaultEmptyRunMaxRetries,
|
|
70
70
|
defaultMalformedToolCallMaxRetries: runtimeDeps.defaultMalformedToolCallMaxRetries,
|
|
71
71
|
defaultIdleTimeoutMaxRetries: runtimeDeps.defaultIdleTimeoutMaxRetries,
|
|
72
|
+
defaultResumeInterruptedRun: runtimeDeps.defaultResumeInterruptedRun,
|
|
72
73
|
defaultHeartbeatIntervalMs: runtimeDeps.defaultHeartbeatIntervalMs,
|
|
73
74
|
defaultIdleTimeoutMs: runtimeDeps.defaultIdleTimeoutMs,
|
|
74
75
|
artifactValidator: runtimeDeps.artifactValidator,
|
|
@@ -109,6 +110,7 @@ export class AgentRuntimeFactory {
|
|
|
109
110
|
executeTimeoutMs: runtimeDeps.executeTimeoutMs,
|
|
110
111
|
blockTaskTool: runtimeDeps.blockTaskTool,
|
|
111
112
|
allowedToolNames: runtimeDeps.allowedToolNames,
|
|
113
|
+
policy: runtimeDeps.middleware,
|
|
112
114
|
logger: runtimeDeps.logger,
|
|
113
115
|
persistTodos: workspace.persistTodos.bind(workspace),
|
|
114
116
|
humanLoop: runtimeDeps.humanLoop,
|
|
@@ -170,10 +172,13 @@ class RuntimeOptionsResolver {
|
|
|
170
172
|
this.options.malformedToolCallMaxRetries ?? runtimeConfig.malformedToolCallMaxRetries,
|
|
171
173
|
defaultIdleTimeoutMaxRetries:
|
|
172
174
|
this.options.idleTimeoutMaxRetries ?? runtimeConfig.idleTimeoutMaxRetries,
|
|
175
|
+
defaultResumeInterruptedRun:
|
|
176
|
+
this.options.resumeInterruptedRun ?? runtimeConfig.resumeInterruptedRun,
|
|
173
177
|
defaultHeartbeatIntervalMs:
|
|
174
178
|
this.options.heartbeatIntervalMs ?? runtimeConfig.heartbeatIntervalMs,
|
|
175
179
|
defaultIdleTimeoutMs:
|
|
176
180
|
this.options.idleTimeoutMs ?? runtimeConfig.llmIdleTimeoutMs,
|
|
181
|
+
middleware: runtimeConfig.middleware,
|
|
177
182
|
};
|
|
178
183
|
}
|
|
179
184
|
|
|
@@ -207,6 +212,8 @@ interface ResolvedRuntimeOptions {
|
|
|
207
212
|
defaultEmptyRunMaxRetries: number | undefined;
|
|
208
213
|
defaultMalformedToolCallMaxRetries: number | undefined;
|
|
209
214
|
defaultIdleTimeoutMaxRetries: number | undefined;
|
|
215
|
+
defaultResumeInterruptedRun: boolean | undefined;
|
|
210
216
|
defaultHeartbeatIntervalMs: number | undefined;
|
|
211
217
|
defaultIdleTimeoutMs: number | undefined;
|
|
218
|
+
middleware: ResolvedAgentRuntimeConfig["middleware"];
|
|
212
219
|
}
|
|
@@ -22,6 +22,7 @@ export class AgentRunExecutor {
|
|
|
22
22
|
private readonly defaultEmptyRunMaxRetries?: number;
|
|
23
23
|
private readonly defaultMalformedToolCallMaxRetries?: number;
|
|
24
24
|
private readonly defaultIdleTimeoutMaxRetries?: number;
|
|
25
|
+
private readonly defaultResumeInterruptedRun?: boolean;
|
|
25
26
|
private readonly defaultHeartbeatIntervalMs?: number;
|
|
26
27
|
private readonly defaultIdleTimeoutMs?: number;
|
|
27
28
|
private readonly artifactValidator?: ConstructorParams["artifactValidator"];
|
|
@@ -35,6 +36,7 @@ export class AgentRunExecutor {
|
|
|
35
36
|
this.defaultEmptyRunMaxRetries = params.defaultEmptyRunMaxRetries;
|
|
36
37
|
this.defaultMalformedToolCallMaxRetries = params.defaultMalformedToolCallMaxRetries;
|
|
37
38
|
this.defaultIdleTimeoutMaxRetries = params.defaultIdleTimeoutMaxRetries;
|
|
39
|
+
this.defaultResumeInterruptedRun = params.defaultResumeInterruptedRun;
|
|
38
40
|
this.defaultHeartbeatIntervalMs = params.defaultHeartbeatIntervalMs;
|
|
39
41
|
this.defaultIdleTimeoutMs = params.defaultIdleTimeoutMs;
|
|
40
42
|
this.artifactValidator = params.artifactValidator;
|
|
@@ -91,6 +93,7 @@ export class AgentRunExecutor {
|
|
|
91
93
|
|
|
92
94
|
const run = await this.workspace.prepareRun({
|
|
93
95
|
prompt: effectivePrompt,
|
|
96
|
+
resumeInterruptedRun: params.resumeInterruptedRun ?? this.defaultResumeInterruptedRun ?? true,
|
|
94
97
|
fallbackThreadId: params.fallbackThreadId,
|
|
95
98
|
resumeHint:
|
|
96
99
|
params.resumeHint ??
|
|
@@ -2,6 +2,7 @@ import type { DrainAgentStreamOptions } from "../stream/agentStream.js";
|
|
|
2
2
|
import type { AgentWorkspaceState } from "../../state/workspaceState.js";
|
|
3
3
|
|
|
4
4
|
export interface AgentRuntimeRunOptions<TChunk> {
|
|
5
|
+
resumeInterruptedRun?: boolean;
|
|
5
6
|
resumeHint?: string;
|
|
6
7
|
fallbackThreadId?: string;
|
|
7
8
|
malformedToolCallMaxRetries?: number;
|
|
@@ -28,6 +29,7 @@ export interface ConstructorParams {
|
|
|
28
29
|
defaultEmptyRunMaxRetries?: number;
|
|
29
30
|
defaultMalformedToolCallMaxRetries?: number;
|
|
30
31
|
defaultIdleTimeoutMaxRetries?: number;
|
|
32
|
+
defaultResumeInterruptedRun?: boolean;
|
|
31
33
|
defaultHeartbeatIntervalMs?: number;
|
|
32
34
|
defaultIdleTimeoutMs?: number;
|
|
33
35
|
artifactValidator?: AgentRuntimeRunOptions<unknown>["artifactValidator"];
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
CreateAgentToolMiddlewareOptions,
|
|
12
12
|
ToolArgs,
|
|
13
13
|
} from "./types.js";
|
|
14
|
+
import type { AgentRuntimeMiddlewareSpec } from "../../config/resources.js";
|
|
14
15
|
|
|
15
16
|
export class AgentToolMiddlewareFactory {
|
|
16
17
|
private readonly rootDir: string;
|
|
@@ -22,6 +23,7 @@ export class AgentToolMiddlewareFactory {
|
|
|
22
23
|
private readonly executeTimeoutMs: number;
|
|
23
24
|
private readonly blockTaskTool: boolean;
|
|
24
25
|
private readonly allowedToolNames?: string[];
|
|
26
|
+
private readonly policy?: AgentRuntimeMiddlewareSpec;
|
|
25
27
|
private readonly logger: (message: string) => void;
|
|
26
28
|
private readonly persistTodos?: (todos: unknown[]) => Promise<void> | void;
|
|
27
29
|
private readonly humanLoop?: CreateAgentToolMiddlewareOptions["humanLoop"];
|
|
@@ -39,6 +41,7 @@ export class AgentToolMiddlewareFactory {
|
|
|
39
41
|
this.executeTimeoutMs = options.executeTimeoutMs ?? 60_000;
|
|
40
42
|
this.blockTaskTool = options.blockTaskTool ?? false;
|
|
41
43
|
this.allowedToolNames = options.allowedToolNames?.filter((name) => typeof name === "string" && name.trim().length > 0);
|
|
44
|
+
this.policy = options.policy;
|
|
42
45
|
this.logger = options.logger ?? (() => {});
|
|
43
46
|
this.persistTodos = options.persistTodos;
|
|
44
47
|
this.humanLoop = options.humanLoop;
|
|
@@ -74,14 +77,15 @@ export class AgentToolMiddlewareFactory {
|
|
|
74
77
|
const toolCallId = toolRequest.toolCall.id;
|
|
75
78
|
|
|
76
79
|
if (this.blockTaskTool && name === "task") {
|
|
80
|
+
const error = "Error: Do not use the task tool. Use execute(), write_file(), and read_file() directly.";
|
|
77
81
|
this.events?.emit({
|
|
78
82
|
name: "agent.runtime2.tool.call.blocked",
|
|
79
83
|
from: "agent-runtime2.middleware",
|
|
80
84
|
to: name,
|
|
81
|
-
payload: { toolCallId, reason: "task_tool_disabled" },
|
|
85
|
+
payload: { toolCallId, reason: "task_tool_disabled", error },
|
|
82
86
|
});
|
|
83
87
|
return new this.ToolMessage({
|
|
84
|
-
content:
|
|
88
|
+
content: error,
|
|
85
89
|
tool_call_id: toolCallId ?? "blocked",
|
|
86
90
|
});
|
|
87
91
|
}
|
|
@@ -95,13 +99,15 @@ export class AgentToolMiddlewareFactory {
|
|
|
95
99
|
this.rootDir,
|
|
96
100
|
this.allowedToolNames,
|
|
97
101
|
Object.values(this.skillPathMap),
|
|
102
|
+
this.policy,
|
|
98
103
|
);
|
|
99
104
|
if (blocked) {
|
|
105
|
+
const error = this.extractToolMessageContent(blocked);
|
|
100
106
|
this.events?.emit({
|
|
101
107
|
name: "agent.runtime2.tool.call.blocked",
|
|
102
108
|
from: "agent-runtime2.middleware",
|
|
103
109
|
to: name,
|
|
104
|
-
payload: { toolCallId, args, reason: "policy_violation" },
|
|
110
|
+
payload: { toolCallId, args, reason: "policy_violation", error },
|
|
105
111
|
});
|
|
106
112
|
return blocked;
|
|
107
113
|
}
|
|
@@ -326,4 +332,14 @@ export class AgentToolMiddlewareFactory {
|
|
|
326
332
|
}
|
|
327
333
|
this.logger(`[tool] ${name}`);
|
|
328
334
|
}
|
|
335
|
+
|
|
336
|
+
private extractToolMessageContent(value: unknown): string | undefined {
|
|
337
|
+
if (!value || typeof value !== "object") {
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
const candidate = value as { content?: unknown };
|
|
341
|
+
return typeof candidate.content === "string" && candidate.content.trim()
|
|
342
|
+
? candidate.content.trim()
|
|
343
|
+
: undefined;
|
|
344
|
+
}
|
|
329
345
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentRuntimeCommandPolicySpec } from "../../config/resources.js";
|
|
1
2
|
import type { ToolMessageConstructorLike, ToolMessageLike } from "./types.js";
|
|
2
3
|
|
|
3
4
|
export class CommandPolicy {
|
|
@@ -7,34 +8,45 @@ export class CommandPolicy {
|
|
|
7
8
|
ToolMessage: ToolMessageConstructorLike,
|
|
8
9
|
rootDir: string,
|
|
9
10
|
allowedPathPrefixes: string[] = [],
|
|
11
|
+
policy?: AgentRuntimeCommandPolicySpec,
|
|
10
12
|
): ToolMessageLike | null {
|
|
11
|
-
const message = this.getViolationMessage(command, rootDir, allowedPathPrefixes);
|
|
13
|
+
const message = this.getViolationMessage(command, rootDir, allowedPathPrefixes, policy);
|
|
12
14
|
return message ? new ToolMessage({ content: message, tool_call_id: toolCallId ?? "execute" }) : null;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
private static getViolationMessage(
|
|
16
|
-
|
|
17
|
+
private static getViolationMessage(
|
|
18
|
+
command: string,
|
|
19
|
+
rootDir: string,
|
|
20
|
+
allowedPathPrefixes: string[],
|
|
21
|
+
policy?: AgentRuntimeCommandPolicySpec,
|
|
22
|
+
): string | null {
|
|
23
|
+
if (policy?.blockFuzzyLsProbes !== false && /\bls\b/.test(command) && command.includes("?")) {
|
|
17
24
|
return "Error: Do not run fuzzy ls probes with unknown paths. Continue with known workflow commands.";
|
|
18
25
|
}
|
|
19
|
-
if (
|
|
26
|
+
if (
|
|
27
|
+
policy?.blockShellWrappedSkillScripts !== false
|
|
28
|
+
&& (/\bbash\b/i.test(command) || /\/bin\/bash\b/i.test(command) || /\bzsh\b/i.test(command))
|
|
29
|
+
&& command.includes("/scripts/")
|
|
30
|
+
) {
|
|
20
31
|
return "Error: Do not wrap skill scripts with `bash`. Execute the script path directly.";
|
|
21
32
|
}
|
|
22
|
-
if (/\bchmod\s+\+x\b/i.test(command)) {
|
|
33
|
+
if (policy?.blockChmodX !== false && /\bchmod\s+\+x\b/i.test(command)) {
|
|
23
34
|
return "Error: Do not run chmod +x. Use direct execution of the target command or script.";
|
|
24
35
|
}
|
|
25
|
-
if (/\b(?:ba)?sh\s+-lc\b/i.test(command)) {
|
|
36
|
+
if (policy?.blockShellDashLc !== false && /\b(?:ba)?sh\s+-lc\b/i.test(command)) {
|
|
26
37
|
return "Error: Do not wrap command execution with shell -lc. Execute the target command directly.";
|
|
27
38
|
}
|
|
28
|
-
if (/\b(curl|wget)\b/i.test(command)) {
|
|
39
|
+
if (policy?.blockDirectNetworkFetch !== false && /\b(curl|wget)\b/i.test(command)) {
|
|
29
40
|
return "Error: Do not execute direct network fetch commands. Use provided scripts/tools and then write results with write_file/edit_file.";
|
|
30
41
|
}
|
|
31
|
-
if (/\|\s*reportgen\b/i.test(command)) {
|
|
42
|
+
if (policy?.blockReportgenPipe !== false && /\|\s*reportgen\b/i.test(command)) {
|
|
32
43
|
return "Error: Do not pipe output to ad-hoc generators. Use write_file/edit_file for artifact generation.";
|
|
33
44
|
}
|
|
34
|
-
if (/(^|[\s;|&])(?:echo|cat|printf)[^|&;]*>\s*[^\s]+/i.test(command)) {
|
|
45
|
+
if (policy?.blockShellFileRedirection !== false && /(^|[\s;|&])(?:echo|cat|printf)[^|&;]*>\s*[^\s]+/i.test(command)) {
|
|
35
46
|
return "Error: Do not write files via shell redirection in execute. Use write_file/edit_file tools.";
|
|
36
47
|
}
|
|
37
|
-
return
|
|
48
|
+
return (policy?.blockAbsolutePathsOutsideWorkspace !== false)
|
|
49
|
+
&& this.containsAbsolutePathOutsideWorkspace(command, rootDir, allowedPathPrefixes)
|
|
38
50
|
? "Error: Do not execute commands with absolute paths outside workspace root. Use workspace-relative paths only."
|
|
39
51
|
: null;
|
|
40
52
|
}
|
|
@@ -37,9 +37,8 @@ export class FrameworkPrompt {
|
|
|
37
37
|
if (skillEntries.length === 1) {
|
|
38
38
|
baseRules.push("- Because only one skill is active, `${SKILL_PATH}` also resolves to that skill directory.");
|
|
39
39
|
}
|
|
40
|
-
baseRules.push("- `${SKILL_PATH...}` is only for skill-owned
|
|
41
|
-
baseRules.push("-
|
|
42
|
-
baseRules.push("- If a SKILL provides an explicit script command using `${SKILL_PATH...}` and `${WORKSPACE}`, execute that command directly instead of exploring the skill directory first.");
|
|
40
|
+
baseRules.push("- `${SKILL_PATH...}` is only for exact skill-owned files explicitly required by the active SKILL.");
|
|
41
|
+
baseRules.push("- If a SKILL provides an explicit script command using `${SKILL_PATH...}` and `${WORKSPACE}`, execute that command directly without exploring the skill directory.");
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
const frameworkPrompt = baseRules.join("\n");
|
|
@@ -72,6 +72,12 @@ export class ToolArgsNormalizer {
|
|
|
72
72
|
for (const key of TOOL_PATH_ARG_KEYS) {
|
|
73
73
|
const value = nextArgs[key];
|
|
74
74
|
if (!this.shouldNormalizePath(value)) {
|
|
75
|
+
if (typeof value === "string") {
|
|
76
|
+
const normalizedRelative = this.normalizeWorkspaceRelativePath(rootDir, value);
|
|
77
|
+
if (normalizedRelative !== value) {
|
|
78
|
+
nextArgs = { ...nextArgs, [key]: normalizedRelative };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
75
81
|
continue;
|
|
76
82
|
}
|
|
77
83
|
if (this.isResolvableAbsolutePath(rootDir, value)) {
|
|
@@ -192,6 +198,10 @@ export class ToolArgsNormalizer {
|
|
|
192
198
|
if (!this.looksLikeRelativePath(value) || value.startsWith("./") || value.startsWith("../")) {
|
|
193
199
|
return value;
|
|
194
200
|
}
|
|
201
|
+
const normalizedRelative = this.normalizeWorkspaceRelativePath(rootDir, value);
|
|
202
|
+
if (normalizedRelative !== value) {
|
|
203
|
+
return normalizedRelative;
|
|
204
|
+
}
|
|
195
205
|
if (existsSync(resolve(rootDir, value))) {
|
|
196
206
|
return value;
|
|
197
207
|
}
|
|
@@ -211,6 +221,32 @@ export class ToolArgsNormalizer {
|
|
|
211
221
|
return value.includes("/") && !value.startsWith("/") && !value.startsWith("~") && !value.startsWith("-");
|
|
212
222
|
}
|
|
213
223
|
|
|
224
|
+
private static normalizeWorkspaceRelativePath(rootDir: string, value: string): string {
|
|
225
|
+
const normalizedValue = value.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
226
|
+
if (!this.looksLikeRelativePath(normalizedValue)) {
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const rootSegments = rootDir.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
231
|
+
const valueSegments = normalizedValue.split("/").filter(Boolean);
|
|
232
|
+
if (valueSegments.length < 2 || rootSegments.length < 2) {
|
|
233
|
+
return value;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
for (let index = 0; index <= rootSegments.length - 2; index += 1) {
|
|
237
|
+
const suffixSegments = rootSegments.slice(index);
|
|
238
|
+
if (valueSegments.length <= suffixSegments.length) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const matches = suffixSegments.every((segment, suffixIndex) => valueSegments[suffixIndex] === segment);
|
|
242
|
+
if (matches) {
|
|
243
|
+
return valueSegments.slice(suffixSegments.length).join("/");
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return value;
|
|
248
|
+
}
|
|
249
|
+
|
|
214
250
|
private static quoteCommandPart(value: string): string {
|
|
215
251
|
return /^[A-Za-z0-9_./:@=-]+$/.test(value)
|
|
216
252
|
? value
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentRuntimeMiddlewareSpec } from "../../config/resources.js";
|
|
1
2
|
import { CommandPolicy } from "./commandPolicy.js";
|
|
2
3
|
import { ToolArgsNormalizer } from "./toolArgsNormalizer.js";
|
|
3
4
|
import { TOOL_PATH_ARG_KEYS, type ToolArgs, type ToolMessageConstructorLike, type ToolMessageLike } from "./types.js";
|
|
@@ -11,6 +12,7 @@ export class ToolCallGuard {
|
|
|
11
12
|
rootDir: string,
|
|
12
13
|
allowedToolNames?: string[],
|
|
13
14
|
allowedPathPrefixes: string[] = [],
|
|
15
|
+
policy?: AgentRuntimeMiddlewareSpec,
|
|
14
16
|
): ToolMessageLike | null {
|
|
15
17
|
if (allowedToolNames?.length && !this.isToolAllowed(name, allowedToolNames)) {
|
|
16
18
|
return new ToolMessage({
|
|
@@ -18,20 +20,40 @@ export class ToolCallGuard {
|
|
|
18
20
|
tool_call_id: toolCallId ?? name,
|
|
19
21
|
});
|
|
20
22
|
}
|
|
21
|
-
if (
|
|
23
|
+
if (
|
|
24
|
+
policy?.forbidScriptSourceRead !== false
|
|
25
|
+
&& (name === "read_file" || name === "edit_file")
|
|
26
|
+
&& this.isScriptSourcePath(args, rootDir)
|
|
27
|
+
) {
|
|
22
28
|
return new ToolMessage({
|
|
23
29
|
content: "Error: Do not inspect script source files unless the user explicitly asks for script code.",
|
|
24
30
|
tool_call_id: toolCallId ?? name,
|
|
25
31
|
});
|
|
26
32
|
}
|
|
27
|
-
if (this.
|
|
33
|
+
if ((name === "read_file" || name === "edit_file") && this.isInternalStatePath(args, rootDir)) {
|
|
34
|
+
return new ToolMessage({
|
|
35
|
+
content: "Error: Do not inspect internal runtime state files under .agent/. Follow the SKILL workflow instead.",
|
|
36
|
+
tool_call_id: toolCallId ?? name,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (
|
|
40
|
+
policy?.forbidAbsolutePathsOutsideWorkspace !== false
|
|
41
|
+
&& this.hasAbsolutePathArgOutsideWorkspace(args, rootDir, allowedPathPrefixes)
|
|
42
|
+
) {
|
|
28
43
|
return new ToolMessage({
|
|
29
44
|
content: "Error: Do not use absolute filesystem paths outside workspace root. Use workspace-relative paths only.",
|
|
30
45
|
tool_call_id: toolCallId ?? name,
|
|
31
46
|
});
|
|
32
47
|
}
|
|
33
48
|
if (name === "execute" && typeof args.command === "string") {
|
|
34
|
-
return CommandPolicy.maybeBlockExecuteCommand(
|
|
49
|
+
return CommandPolicy.maybeBlockExecuteCommand(
|
|
50
|
+
args.command,
|
|
51
|
+
toolCallId,
|
|
52
|
+
ToolMessage,
|
|
53
|
+
rootDir,
|
|
54
|
+
allowedPathPrefixes,
|
|
55
|
+
policy?.commandPolicy,
|
|
56
|
+
);
|
|
35
57
|
}
|
|
36
58
|
return null;
|
|
37
59
|
}
|
|
@@ -70,4 +92,16 @@ export class ToolCallGuard {
|
|
|
70
92
|
ToolArgsNormalizer.resolveScriptSourcePath(rootDir, value).includes("/scripts/");
|
|
71
93
|
});
|
|
72
94
|
}
|
|
95
|
+
|
|
96
|
+
private static isInternalStatePath(args: ToolArgs, rootDir: string): boolean {
|
|
97
|
+
const normalizedRoot = rootDir.replace(/\\/g, "/");
|
|
98
|
+
return TOOL_PATH_ARG_KEYS.some((key) => {
|
|
99
|
+
const value = args[key];
|
|
100
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const resolved = ToolArgsNormalizer.resolveScriptSourcePath(rootDir, value);
|
|
104
|
+
return resolved === `${normalizedRoot}/.agent` || resolved.startsWith(`${normalizedRoot}/.agent/`);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
73
107
|
}
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
HumanLoopService,
|
|
3
3
|
HumanLoopToolPolicy,
|
|
4
4
|
} from "../human-loop/humanLoop.js";
|
|
5
|
+
import type { AgentRuntimeMiddlewareSpec } from "../../config/resources.js";
|
|
5
6
|
|
|
6
7
|
export const TOOL_PATH_ARG_KEYS = ["file_path", "path"] as const;
|
|
7
8
|
export const MAX_LS_ENTRIES = 200;
|
|
@@ -80,6 +81,7 @@ export interface CreateAgentToolMiddlewareOptions {
|
|
|
80
81
|
executeTimeoutMs?: number;
|
|
81
82
|
blockTaskTool?: boolean;
|
|
82
83
|
allowedToolNames?: string[];
|
|
84
|
+
policy?: AgentRuntimeMiddlewareSpec;
|
|
83
85
|
logger?: (message: string) => void;
|
|
84
86
|
persistTodos?: (todos: unknown[]) => Promise<void> | void;
|
|
85
87
|
humanLoop?: HumanLoopService;
|
|
@@ -43,6 +43,7 @@ export interface CreateAgentRuntimeOptions
|
|
|
43
43
|
emptyRunMaxRetries?: number;
|
|
44
44
|
malformedToolCallMaxRetries?: number;
|
|
45
45
|
idleTimeoutMaxRetries?: number;
|
|
46
|
+
resumeInterruptedRun?: boolean;
|
|
46
47
|
heartbeatIntervalMs?: number;
|
|
47
48
|
idleTimeoutMs?: number;
|
|
48
49
|
artifactValidator?: (context: {
|
|
@@ -104,6 +105,7 @@ export class AgentRuntimeService implements AgentRuntime {
|
|
|
104
105
|
defaultEmptyRunMaxRetries?: number;
|
|
105
106
|
defaultMalformedToolCallMaxRetries?: number;
|
|
106
107
|
defaultIdleTimeoutMaxRetries?: number;
|
|
108
|
+
defaultResumeInterruptedRun?: boolean;
|
|
107
109
|
defaultHeartbeatIntervalMs?: number;
|
|
108
110
|
defaultIdleTimeoutMs?: number;
|
|
109
111
|
artifactValidator?: CreateAgentRuntimeOptions["artifactValidator"];
|
|
@@ -130,6 +132,7 @@ export class AgentRuntimeService implements AgentRuntime {
|
|
|
130
132
|
defaultEmptyRunMaxRetries: params.defaultEmptyRunMaxRetries,
|
|
131
133
|
defaultMalformedToolCallMaxRetries: params.defaultMalformedToolCallMaxRetries,
|
|
132
134
|
defaultIdleTimeoutMaxRetries: params.defaultIdleTimeoutMaxRetries,
|
|
135
|
+
defaultResumeInterruptedRun: params.defaultResumeInterruptedRun,
|
|
133
136
|
defaultHeartbeatIntervalMs: params.defaultHeartbeatIntervalMs,
|
|
134
137
|
defaultIdleTimeoutMs: params.defaultIdleTimeoutMs,
|
|
135
138
|
artifactValidator: params.artifactValidator,
|
|
@@ -27,7 +27,9 @@ export class RunArtifactService {
|
|
|
27
27
|
todosFile: string,
|
|
28
28
|
trackedArtifactFiles: string[],
|
|
29
29
|
): string[] {
|
|
30
|
-
|
|
30
|
+
void runStateFile;
|
|
31
|
+
void todosFile;
|
|
32
|
+
return trackedArtifactFiles
|
|
31
33
|
.map((file) => relative(rootDir, file))
|
|
32
34
|
.filter(Boolean);
|
|
33
35
|
}
|
package/src/state/runState.ts
CHANGED
|
@@ -71,12 +71,30 @@ export class AgentRunStateStore {
|
|
|
71
71
|
|
|
72
72
|
public buildResumePrompt(basePrompt: string, previousState: AgentRunState | null, resumeHint: string): string {
|
|
73
73
|
if (previousState?.status !== "running") return basePrompt;
|
|
74
|
-
|
|
74
|
+
const checkpoint = {
|
|
75
|
+
threadId: previousState.threadId,
|
|
76
|
+
stepCount: previousState.stepCount,
|
|
77
|
+
lastSummary: previousState.lastSummary?.trim() || "n/a",
|
|
78
|
+
artifacts: this.summarizeArtifacts(previousState.artifacts),
|
|
79
|
+
rules: [
|
|
80
|
+
"Do not read .agent/*",
|
|
81
|
+
"Do not re-read existing outputs unless verification is required",
|
|
82
|
+
],
|
|
83
|
+
resumeHint: resumeHint.trim() || undefined,
|
|
84
|
+
};
|
|
85
|
+
return `${basePrompt}\n\nRESUME_CHECKPOINT\n${JSON.stringify(checkpoint, null, 2)}`;
|
|
75
86
|
}
|
|
76
87
|
|
|
77
88
|
public getThreadId(previousState: AgentRunState | null, fallbackThreadId: string): string {
|
|
78
89
|
return previousState?.status === "running" ? previousState.threadId : fallbackThreadId;
|
|
79
90
|
}
|
|
91
|
+
|
|
92
|
+
private summarizeArtifacts(artifacts: Record<string, unknown>): Record<string, "ready" | "missing"> | undefined {
|
|
93
|
+
const entries = Object.entries(artifacts)
|
|
94
|
+
.filter(([key]) => /Present$/.test(key))
|
|
95
|
+
.map(([key, value]) => [key.replace(/Present$/, ""), value === true ? "ready" : "missing"] as const);
|
|
96
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
97
|
+
}
|
|
80
98
|
}
|
|
81
99
|
|
|
82
100
|
export function createAgentRunStateStore(options: CreateAgentRunStateStoreOptions) {
|