@sema-agent/core 3.0.0 → 4.0.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/CHANGELOG.md +2345 -0
- package/dist/agents/cascade.d.ts +2 -1
- package/dist/agents/cascade.js +31 -32
- package/dist/agents/cumulative-stats.d.ts +29 -0
- package/dist/agents/cumulative-stats.js +29 -0
- package/dist/agents/observer.d.ts +4 -0
- package/dist/agents/observer.js +11 -10
- package/dist/agents/repair-loop.js +27 -19
- package/dist/agents/retain-ledger.d.ts +2 -0
- package/dist/agents/retain-ledger.js +6 -5
- package/dist/agents/roster-store.js +3 -5
- package/dist/agents/subagent.js +66 -64
- package/dist/agents/teacher.d.ts +1 -9
- package/dist/agents/teacher.js +21 -24
- package/dist/agents/verify.js +15 -14
- package/dist/brain/anthropic.js +24 -21
- package/dist/brain/openai.js +24 -21
- package/dist/brain/stream-engine.js +5 -2
- package/dist/brain/stream-shared.d.ts +1 -0
- package/dist/brain/stream-shared.js +14 -0
- package/dist/brain/terminal-cause.d.ts +4 -0
- package/dist/brain/terminal-cause.js +12 -0
- package/dist/brain/tool-call-id.d.ts +1 -0
- package/dist/brain/tool-call-id.js +3 -0
- package/dist/brain/tool-call-repair.js +2 -1
- package/dist/core/auto-compaction.js +16 -25
- package/dist/core/background-agent-store.d.ts +22 -22
- package/dist/core/background-agent-store.js +19 -23
- package/dist/core/checkpoint-store.d.ts +6 -13
- package/dist/core/checkpoint-store.js +11 -5
- package/dist/core/file-snapshot-store.d.ts +8 -0
- package/dist/core/file-snapshot-store.js +4 -3
- package/dist/core/hooks.d.ts +3 -1
- package/dist/core/hooks.js +8 -18
- package/dist/core/lsp.js +4 -3
- package/dist/core/mailbox-store.d.ts +7 -10
- package/dist/core/mcp.d.ts +7 -10
- package/dist/core/mcp.js +7 -3
- package/dist/core/memory-engine/engine.d.ts +0 -1
- package/dist/core/memory-engine/engine.js +24 -34
- package/dist/core/memory-engine/file-backend.d.ts +1 -2
- package/dist/core/memory-engine/file-backend.js +25 -36
- package/dist/core/memory-engine/layout.d.ts +8 -0
- package/dist/core/memory-engine/layout.js +60 -4
- package/dist/core/memory-engine/scope-contract.js +9 -3
- package/dist/core/memory-engine/types.d.ts +1 -1
- package/dist/core/runner/active-skill-scope.d.ts +0 -1
- package/dist/core/runner/active-skill-scope.js +1 -15
- package/dist/core/runner/assemble-result.d.ts +2 -7
- package/dist/core/runner/assemble-result.js +3 -4
- package/dist/core/runner/compaction-call-options.d.ts +7 -0
- package/dist/core/runner/compaction-call-options.js +30 -0
- package/dist/core/runner/prepare-task.d.ts +6 -23
- package/dist/core/runner/prepare-task.js +20 -53
- package/dist/core/runner/runtask.d.ts +1 -0
- package/dist/core/runner/runtask.js +65 -156
- package/dist/core/runner/session-rule-policy.js +4 -1
- package/dist/core/runner/teardown-bounded.d.ts +7 -0
- package/dist/core/runner/teardown-bounded.js +36 -0
- package/dist/core/runner/tool-disclosure.d.ts +2 -5
- package/dist/core/runner/turn-attachments.d.ts +5 -15
- package/dist/core/runner/turn-attachments.js +1 -1
- package/dist/core/safe-notify.d.ts +17 -0
- package/dist/core/safe-notify.js +59 -0
- package/dist/core/sensitive-path-policy.js +2 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/stub-env.d.ts +2 -6
- package/dist/core/surrogate-safe-slice.d.ts +4 -0
- package/dist/core/surrogate-safe-slice.js +18 -0
- package/dist/core/task-registry-monitor.js +8 -13
- package/dist/core/task-registry-shared.d.ts +22 -0
- package/dist/core/task-registry-shared.js +16 -0
- package/dist/core/task-registry.d.ts +1 -0
- package/dist/core/task-registry.js +40 -57
- package/dist/core/tool-errors.js +5 -4
- package/dist/core/tool-name-aliases.js +2 -1
- package/dist/core/tool-policy.js +10 -5
- package/dist/core/tool-result-store.d.ts +1 -0
- package/dist/core/tool-result-store.js +17 -1
- package/dist/core/trace.d.ts +2 -9
- package/dist/core/types.d.ts +15 -12
- package/dist/core/untrusted-egress.js +7 -5
- package/dist/core/workflow-journal-store.d.ts +9 -20
- package/dist/core/workflow-run-store.d.ts +11 -10
- package/dist/core/workflow-run-store.js +22 -16
- package/dist/engine/compaction/utils.js +4 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +2 -24
- package/dist/engine/harness/agent-harness.d.ts +1 -0
- package/dist/engine/harness/agent-harness.js +13 -33
- package/dist/engine/harness/types.d.ts +29 -67
- package/dist/engine/llm/types.d.ts +1 -1
- package/dist/engine/loop/agent-loop.js +11 -4
- package/dist/engine/loop/types.d.ts +11 -9
- package/dist/engine/session/memory-repo.d.ts +2 -6
- package/dist/engine/session/session.d.ts +5 -30
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/internal/harness-types.d.ts +3 -1
- package/dist/orchestration/run-spec.js +7 -4
- package/dist/orchestration/run-workflow-tool.js +3 -35
- package/dist/orchestration/workflow.d.ts +3 -11
- package/dist/orchestration/workflow.js +164 -204
- package/dist/prompt-assembly/tool-catalog.d.ts +10 -9
- package/dist/prompt-assembly/turn-snapshot.d.ts +2 -5
- package/dist/stores/file/background-agent-store.d.ts +3 -12
- package/dist/stores/file/background-agent-store.js +3 -41
- package/dist/stores/file/checkpoint-store.js +6 -6
- package/dist/stores/file/mailbox-store.d.ts +2 -6
- package/dist/stores/file/session-policy-store.js +15 -1
- package/dist/stores/file/session-store.d.ts +2 -6
- package/dist/stores/file/workflow-journal-store.d.ts +3 -11
- package/dist/stores/file/workflow-run-store.d.ts +3 -7
- package/dist/stores/file/workflow-run-store.js +4 -17
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -0
- package/dist/tools/fs/bash-readonly-classifier.js +60 -25
- package/dist/tools/fs/fs-bash.js +324 -96
- package/dist/tools/fs/fs-pdf.d.ts +2 -12
- package/dist/tools/fs/fs-shared.js +2 -2
- package/dist/tools/fs/notebook.d.ts +2 -5
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +43 -14
- package/dist/tools/fs/search.js +5 -5
- package/dist/tools/monitor.d.ts +1 -0
- package/dist/tools/monitor.js +7 -5
- package/dist/tools/worktree.d.ts +2 -7
- package/dist/tools/worktree.js +3 -1
- package/package.json +6 -2
|
@@ -21,22 +21,27 @@ export declare class WorkflowRunStoreError extends Error {
|
|
|
21
21
|
readonly code: "workflow_run.already_exists";
|
|
22
22
|
constructor(code: "workflow_run.already_exists", message: string);
|
|
23
23
|
}
|
|
24
|
+
export interface WorkflowRunListByScopeOptions {
|
|
25
|
+
status?: WorkflowRunStatus;
|
|
26
|
+
limit?: number;
|
|
27
|
+
session?: string;
|
|
28
|
+
}
|
|
24
29
|
export interface WorkflowRunStore {
|
|
25
30
|
put(id: string, run: WorkflowRun): Promise<void>;
|
|
26
31
|
get(id: string): Promise<WorkflowRun | null>;
|
|
27
32
|
update(id: string, scope: string, run: WorkflowRun, expect?: {
|
|
28
33
|
rev: number;
|
|
29
34
|
}): Promise<boolean>;
|
|
30
|
-
listByScope(scope: string, opts?:
|
|
31
|
-
status?: WorkflowRunStatus;
|
|
32
|
-
limit?: number;
|
|
33
|
-
session?: string;
|
|
34
|
-
}): Promise<WorkflowRunSummary[]>;
|
|
35
|
+
listByScope(scope: string, opts?: WorkflowRunListByScopeOptions): Promise<WorkflowRunSummary[]>;
|
|
35
36
|
reap(scope: string, now: number, opts?: {
|
|
36
37
|
maxAgeMs?: number;
|
|
37
38
|
keep?: number;
|
|
38
39
|
}): Promise<number>;
|
|
39
40
|
}
|
|
41
|
+
export declare function nextWorkflowRunOnUpdate(cur: WorkflowRun | undefined, id: string, scope: string, run: WorkflowRun, expect?: {
|
|
42
|
+
rev: number;
|
|
43
|
+
}): WorkflowRun | null;
|
|
44
|
+
export declare function queryWorkflowRuns(runs: Iterable<WorkflowRun>, scope: string, opts?: WorkflowRunListByScopeOptions): WorkflowRunSummary[];
|
|
40
45
|
export declare class InMemoryWorkflowRunStore implements WorkflowRunStore {
|
|
41
46
|
private runs;
|
|
42
47
|
put(id: string, run: WorkflowRun): Promise<void>;
|
|
@@ -44,11 +49,7 @@ export declare class InMemoryWorkflowRunStore implements WorkflowRunStore {
|
|
|
44
49
|
update(id: string, scope: string, run: WorkflowRun, expect?: {
|
|
45
50
|
rev: number;
|
|
46
51
|
}): Promise<boolean>;
|
|
47
|
-
listByScope(scope: string, opts?:
|
|
48
|
-
status?: WorkflowRunStatus;
|
|
49
|
-
limit?: number;
|
|
50
|
-
session?: string;
|
|
51
|
-
}): Promise<WorkflowRunSummary[]>;
|
|
52
|
+
listByScope(scope: string, opts?: WorkflowRunListByScopeOptions): Promise<WorkflowRunSummary[]>;
|
|
52
53
|
reap(scope: string, now: number, opts?: {
|
|
53
54
|
maxAgeMs?: number;
|
|
54
55
|
keep?: number;
|
|
@@ -28,6 +28,25 @@ export class WorkflowRunStoreError extends Error {
|
|
|
28
28
|
this.name = "WorkflowRunStoreError";
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
export function nextWorkflowRunOnUpdate(cur, id, scope, run, expect) {
|
|
32
|
+
if (!cur || cur.scope !== scope)
|
|
33
|
+
return null;
|
|
34
|
+
if (expect !== undefined && (cur.rev ?? 0) !== expect.rev)
|
|
35
|
+
return null;
|
|
36
|
+
const next = structuredClone(run);
|
|
37
|
+
next.id = id;
|
|
38
|
+
next.scope = scope;
|
|
39
|
+
next.rev = (cur.rev ?? 0) + 1;
|
|
40
|
+
return next;
|
|
41
|
+
}
|
|
42
|
+
export function queryWorkflowRuns(runs, scope, opts) {
|
|
43
|
+
const rows = [...runs].filter((r) => r.scope === scope &&
|
|
44
|
+
(opts?.status === undefined || r.status === opts.status) &&
|
|
45
|
+
(opts?.session === undefined || r.originatingSessionId === opts.session));
|
|
46
|
+
rows.sort((a, b) => b.createdAt - a.createdAt);
|
|
47
|
+
const limited = opts?.limit !== undefined ? rows.slice(0, Math.max(0, opts.limit)) : rows;
|
|
48
|
+
return limited.map(summarizeWorkflowRun);
|
|
49
|
+
}
|
|
31
50
|
export class InMemoryWorkflowRunStore {
|
|
32
51
|
runs = new Map();
|
|
33
52
|
async put(id, run) {
|
|
@@ -44,27 +63,14 @@ export class InMemoryWorkflowRunStore {
|
|
|
44
63
|
return run ? structuredClone(run) : null;
|
|
45
64
|
}
|
|
46
65
|
async update(id, scope, run, expect) {
|
|
47
|
-
const
|
|
48
|
-
if (!
|
|
66
|
+
const next = nextWorkflowRunOnUpdate(this.runs.get(id), id, scope, run, expect);
|
|
67
|
+
if (!next)
|
|
49
68
|
return false;
|
|
50
|
-
}
|
|
51
|
-
if (expect !== undefined && (cur.rev ?? 0) !== expect.rev) {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
const next = structuredClone(run);
|
|
55
|
-
next.id = id;
|
|
56
|
-
next.scope = scope;
|
|
57
|
-
next.rev = (cur.rev ?? 0) + 1;
|
|
58
69
|
this.runs.set(id, next);
|
|
59
70
|
return true;
|
|
60
71
|
}
|
|
61
72
|
async listByScope(scope, opts) {
|
|
62
|
-
|
|
63
|
-
(opts?.status === undefined || r.status === opts.status) &&
|
|
64
|
-
(opts?.session === undefined || r.originatingSessionId === opts.session));
|
|
65
|
-
rows.sort((a, b) => b.createdAt - a.createdAt);
|
|
66
|
-
const limited = opts?.limit !== undefined ? rows.slice(0, Math.max(0, opts.limit)) : rows;
|
|
67
|
-
return limited.map(summarizeWorkflowRun);
|
|
73
|
+
return queryWorkflowRuns(this.runs.values(), scope, opts);
|
|
68
74
|
}
|
|
69
75
|
async reap(scope, now, opts) {
|
|
70
76
|
if (opts?.maxAgeMs === undefined && opts?.keep === undefined)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { normalizeLlmMessageContent } from "../harness/messages.js";
|
|
2
|
+
import { sliceHeadSafe } from "../../core/surrogate-safe-slice.js";
|
|
2
3
|
import { cutEnginePrefix, cutEngineSegments, flattenableUserText } from "../../core/untrusted-text.js";
|
|
3
4
|
import { fileArgPath } from "../../tools/fs/safety.js";
|
|
4
5
|
export function createFileOps() {
|
|
@@ -287,11 +288,12 @@ function truncateForSummary(text, maxChars) {
|
|
|
287
288
|
let keep = maxChars;
|
|
288
289
|
let out = "";
|
|
289
290
|
for (let i = 0; i < 4; i++) {
|
|
290
|
-
|
|
291
|
+
const kept = sliceHeadSafe(text, keep);
|
|
292
|
+
out = `${kept}\n\n[... ${text.length - kept.length} more characters truncated]`;
|
|
291
293
|
if (out.length <= maxChars)
|
|
292
294
|
break;
|
|
293
295
|
if (keep === 0)
|
|
294
|
-
return maxChars >= 1 ? `${text
|
|
296
|
+
return maxChars >= 1 ? `${sliceHeadSafe(text, maxChars - 1)}…` : "";
|
|
295
297
|
keep = Math.max(0, keep - (out.length - maxChars));
|
|
296
298
|
}
|
|
297
299
|
return out.length < text.length ? out : text;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ExecutionEnv, ExecutionError, FileError, type FileInfo, type Result } from "../harness/types.js";
|
|
1
|
+
import { type ExecResult, type ExecutionEnv, ExecutionError, type ExecutionEnvExecOptions, FileError, type FileInfo, type Result } from "../harness/types.js";
|
|
2
2
|
import type { BackgroundShellCapability, BackgroundShellId, BackgroundPoll, BackgroundSpawnOptions } from "../../core/background-shell.js";
|
|
3
3
|
import { BackgroundShellError } from "../../core/background-shell.js";
|
|
4
4
|
import type { SchedulerCapability, ScheduledIntent, SchedulerContext, ScheduledTaskId, ScheduledTaskSummary } from "../../core/scheduler.js";
|
|
@@ -54,29 +54,7 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
|
|
|
54
54
|
list(ctx: SchedulerContext): Promise<Result<ScheduledTaskSummary[], SchedulerError>>;
|
|
55
55
|
absolutePath(path: string): Promise<Result<string, FileError>>;
|
|
56
56
|
joinPath(parts: string[]): Promise<Result<string, FileError>>;
|
|
57
|
-
exec(command: string, options?:
|
|
58
|
-
cwd?: string;
|
|
59
|
-
env?: Record<string, string>;
|
|
60
|
-
timeout?: number;
|
|
61
|
-
abortSignal?: AbortSignal;
|
|
62
|
-
onStdout?: (chunk: string) => void;
|
|
63
|
-
onStderr?: (chunk: string) => void;
|
|
64
|
-
detachSignal?: AbortSignal;
|
|
65
|
-
onSpawn?: (handle: {
|
|
66
|
-
pid: number;
|
|
67
|
-
kill: () => void;
|
|
68
|
-
}) => void;
|
|
69
|
-
onDetachAdopted?: () => void;
|
|
70
|
-
autoBackgroundOnTimeout?: boolean;
|
|
71
|
-
}): Promise<Result<{
|
|
72
|
-
stdout: string;
|
|
73
|
-
stderr: string;
|
|
74
|
-
exitCode: number;
|
|
75
|
-
detached?: {
|
|
76
|
-
shellId: string;
|
|
77
|
-
cause?: "timeout";
|
|
78
|
-
};
|
|
79
|
-
}, ExecutionError>>;
|
|
57
|
+
exec(command: string, options?: ExecutionEnvExecOptions): Promise<Result<ExecResult, ExecutionError>>;
|
|
80
58
|
readTextFile(path: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
81
59
|
readTextLines(path: string, options?: {
|
|
82
60
|
maxLines?: number;
|
|
@@ -92,6 +92,7 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
|
|
|
92
92
|
images?: ImageContent[];
|
|
93
93
|
} & UserMessageProvenance): Promise<AssistantMessage>;
|
|
94
94
|
private static emptyInjection;
|
|
95
|
+
private enqueueInjection;
|
|
95
96
|
steer(text: string, options?: {
|
|
96
97
|
images?: ImageContent[];
|
|
97
98
|
} & UserMessageProvenance): Promise<void>;
|
|
@@ -478,14 +478,7 @@ export class AgentHarness {
|
|
|
478
478
|
details: result.details,
|
|
479
479
|
isError,
|
|
480
480
|
});
|
|
481
|
-
return patch
|
|
482
|
-
? {
|
|
483
|
-
content: patch.content,
|
|
484
|
-
details: patch.details,
|
|
485
|
-
isError: patch.isError,
|
|
486
|
-
terminate: patch.terminate,
|
|
487
|
-
}
|
|
488
|
-
: undefined;
|
|
481
|
+
return patch;
|
|
489
482
|
},
|
|
490
483
|
prepareNextTurn: async () => {
|
|
491
484
|
await this.flushPendingSessionWrites();
|
|
@@ -725,42 +718,29 @@ export class AgentHarness {
|
|
|
725
718
|
static emptyInjection(text, options) {
|
|
726
719
|
return text.trim().length === 0 && (options?.images === undefined || options.images.length === 0);
|
|
727
720
|
}
|
|
721
|
+
async enqueueInjection(queue, text, options) {
|
|
722
|
+
if (AgentHarness.emptyInjection(text, options))
|
|
723
|
+
return;
|
|
724
|
+
const m = createUserMessage(text, options?.images, options);
|
|
725
|
+
if (options?.enginePayload !== undefined)
|
|
726
|
+
engineNotePayloads.set(m, options.enginePayload);
|
|
727
|
+
queue.push(m);
|
|
728
|
+
await this.emitQueueUpdate();
|
|
729
|
+
}
|
|
728
730
|
async steer(text, options) {
|
|
729
731
|
if (this.phase === "idle") {
|
|
730
732
|
throw new AgentHarnessError("invalid_state", "Cannot steer while idle");
|
|
731
733
|
}
|
|
732
|
-
|
|
733
|
-
return;
|
|
734
|
-
{
|
|
735
|
-
const m = createUserMessage(text, options?.images, options);
|
|
736
|
-
if (options?.enginePayload !== undefined)
|
|
737
|
-
engineNotePayloads.set(m, options.enginePayload);
|
|
738
|
-
this.steerQueue.push(m);
|
|
739
|
-
}
|
|
740
|
-
await this.emitQueueUpdate();
|
|
734
|
+
await this.enqueueInjection(this.steerQueue, text, options);
|
|
741
735
|
}
|
|
742
736
|
async followUp(text, options) {
|
|
743
737
|
if (this.phase === "idle") {
|
|
744
738
|
throw new AgentHarnessError("invalid_state", "Cannot follow up while idle");
|
|
745
739
|
}
|
|
746
|
-
|
|
747
|
-
return;
|
|
748
|
-
{
|
|
749
|
-
const m = createUserMessage(text, options?.images, options);
|
|
750
|
-
if (options?.enginePayload !== undefined)
|
|
751
|
-
engineNotePayloads.set(m, options.enginePayload);
|
|
752
|
-
this.followUpQueue.push(m);
|
|
753
|
-
}
|
|
754
|
-
await this.emitQueueUpdate();
|
|
740
|
+
await this.enqueueInjection(this.followUpQueue, text, options);
|
|
755
741
|
}
|
|
756
742
|
async nextTurn(text, options) {
|
|
757
|
-
|
|
758
|
-
return;
|
|
759
|
-
const m = createUserMessage(text, options?.images, options);
|
|
760
|
-
if (options?.enginePayload !== undefined)
|
|
761
|
-
engineNotePayloads.set(m, options.enginePayload);
|
|
762
|
-
this.nextTurnQueue.push(m);
|
|
763
|
-
await this.emitQueueUpdate();
|
|
743
|
+
await this.enqueueInjection(this.nextTurnQueue, text, options);
|
|
764
744
|
}
|
|
765
745
|
async appendMessage(message) {
|
|
766
746
|
try {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { PromptEpochDescriptor } from "../../prompt-assembly/epoch.js";
|
|
1
2
|
import type { DocumentContent, ImageContent, Model, SimpleStreamOptions, TextContent, Transport } from "../llm/index.js";
|
|
2
|
-
import type { AgentEvent, AgentMessage, AgentTool, QueueMode, ThinkingLevel } from "../loop/types.js";
|
|
3
|
+
import type { AfterToolCallResult, AgentEvent, AgentMessage, AgentTool, BeforeToolCallResult, QueueMode, ThinkingLevel } from "../loop/types.js";
|
|
3
4
|
import type { AgentCoreRuntimeDeps } from "../loop/runtime-deps.js";
|
|
4
5
|
export type Result<TValue, TError> = {
|
|
5
6
|
ok: true;
|
|
@@ -129,16 +130,17 @@ export interface FileSystem {
|
|
|
129
130
|
}): Promise<Result<string, FileError>>;
|
|
130
131
|
cleanup(): Promise<void>;
|
|
131
132
|
}
|
|
133
|
+
export interface ExecResult {
|
|
134
|
+
stdout: string;
|
|
135
|
+
stderr: string;
|
|
136
|
+
exitCode: number;
|
|
137
|
+
detached?: {
|
|
138
|
+
shellId: string;
|
|
139
|
+
cause?: "timeout";
|
|
140
|
+
};
|
|
141
|
+
}
|
|
132
142
|
export interface Shell {
|
|
133
|
-
exec(command: string, options?: ExecutionEnvExecOptions): Promise<Result<
|
|
134
|
-
stdout: string;
|
|
135
|
-
stderr: string;
|
|
136
|
-
exitCode: number;
|
|
137
|
-
detached?: {
|
|
138
|
-
shellId: string;
|
|
139
|
-
cause?: "timeout";
|
|
140
|
-
};
|
|
141
|
-
}, ExecutionError>>;
|
|
143
|
+
exec(command: string, options?: ExecutionEnvExecOptions): Promise<Result<ExecResult, ExecutionError>>;
|
|
142
144
|
cleanup(): Promise<void>;
|
|
143
145
|
}
|
|
144
146
|
export interface ExecutionEnv extends FileSystem, Shell {
|
|
@@ -195,15 +197,8 @@ export interface LeafEntry extends SessionTreeEntryBase {
|
|
|
195
197
|
type: "leaf";
|
|
196
198
|
targetId: string | null;
|
|
197
199
|
}
|
|
198
|
-
export interface PromptEpochEntry extends SessionTreeEntryBase {
|
|
200
|
+
export interface PromptEpochEntry extends SessionTreeEntryBase, PromptEpochDescriptor {
|
|
199
201
|
type: "prompt_epoch";
|
|
200
|
-
epoch: number;
|
|
201
|
-
artifactDigest: string;
|
|
202
|
-
packId: string;
|
|
203
|
-
assemblyApi: number;
|
|
204
|
-
activatedBy: "session_start" | "compaction" | "legacy_migration";
|
|
205
|
-
centerArtifactDigest?: string;
|
|
206
|
-
sourceRevision?: string;
|
|
207
202
|
}
|
|
208
203
|
export interface AnnouncedListingEntry extends SessionTreeEntryBase {
|
|
209
204
|
type: "announced_listing";
|
|
@@ -211,28 +206,22 @@ export interface AnnouncedListingEntry extends SessionTreeEntryBase {
|
|
|
211
206
|
skills?: string[];
|
|
212
207
|
models?: string[];
|
|
213
208
|
}
|
|
214
|
-
export interface
|
|
215
|
-
|
|
209
|
+
export interface ActiveWorktreeSession {
|
|
210
|
+
worktreeDir: string;
|
|
211
|
+
originalCwd: string;
|
|
212
|
+
baseSha: string;
|
|
213
|
+
entered?: boolean;
|
|
214
|
+
}
|
|
215
|
+
export interface WorkspaceState {
|
|
216
216
|
taskRoot: string;
|
|
217
217
|
handsCwd?: string;
|
|
218
|
-
activeWorktree?:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
entered?: boolean;
|
|
223
|
-
};
|
|
218
|
+
activeWorktree?: ActiveWorktreeSession;
|
|
219
|
+
}
|
|
220
|
+
export interface WorkspaceStateEntry extends SessionTreeEntryBase, WorkspaceState {
|
|
221
|
+
type: "workspace_state";
|
|
224
222
|
}
|
|
225
223
|
export declare const WORKSPACE_STATE_MAX_PATH_CHARS = 4096;
|
|
226
|
-
export declare function normalizeWorkspaceState(value: unknown):
|
|
227
|
-
taskRoot: string;
|
|
228
|
-
handsCwd?: string;
|
|
229
|
-
activeWorktree?: {
|
|
230
|
-
worktreeDir: string;
|
|
231
|
-
originalCwd: string;
|
|
232
|
-
baseSha: string;
|
|
233
|
-
entered?: boolean;
|
|
234
|
-
};
|
|
235
|
-
} | undefined;
|
|
224
|
+
export declare function normalizeWorkspaceState(value: unknown): WorkspaceState | undefined;
|
|
236
225
|
export declare const ANNOUNCED_LISTING_MAX_NAMES = 500;
|
|
237
226
|
export declare const ANNOUNCED_LISTING_MAX_NAME_CHARS = 200;
|
|
238
227
|
export declare function normalizeCompactionStateCarrier(v: unknown): {
|
|
@@ -331,26 +320,8 @@ export interface Session<TMetadata extends SessionMetadata = SessionMetadata> {
|
|
|
331
320
|
skills?: string[];
|
|
332
321
|
models?: string[];
|
|
333
322
|
} | undefined>;
|
|
334
|
-
appendWorkspaceState(state:
|
|
335
|
-
|
|
336
|
-
handsCwd?: string;
|
|
337
|
-
activeWorktree?: {
|
|
338
|
-
worktreeDir: string;
|
|
339
|
-
originalCwd: string;
|
|
340
|
-
baseSha: string;
|
|
341
|
-
entered?: boolean;
|
|
342
|
-
};
|
|
343
|
-
}): Promise<string>;
|
|
344
|
-
getWorkspaceState(): Promise<{
|
|
345
|
-
taskRoot: string;
|
|
346
|
-
handsCwd?: string;
|
|
347
|
-
activeWorktree?: {
|
|
348
|
-
worktreeDir: string;
|
|
349
|
-
originalCwd: string;
|
|
350
|
-
baseSha: string;
|
|
351
|
-
entered?: boolean;
|
|
352
|
-
};
|
|
353
|
-
} | undefined>;
|
|
323
|
+
appendWorkspaceState(state: WorkspaceState): Promise<string>;
|
|
324
|
+
getWorkspaceState(): Promise<WorkspaceState | undefined>;
|
|
354
325
|
getPromptEpoch?(): Promise<import("../../prompt-assembly/epoch.js").PromptEpochDescriptor | undefined>;
|
|
355
326
|
}
|
|
356
327
|
export interface SessionCreateOptions {
|
|
@@ -487,17 +458,8 @@ export interface BeforeProviderRequestResult {
|
|
|
487
458
|
export interface BeforeProviderPayloadResult {
|
|
488
459
|
payload: unknown;
|
|
489
460
|
}
|
|
490
|
-
export
|
|
491
|
-
|
|
492
|
-
reason?: string;
|
|
493
|
-
updatedInput?: unknown;
|
|
494
|
-
}
|
|
495
|
-
export interface ToolResultPatch {
|
|
496
|
-
content?: Array<TextContent | ImageContent | DocumentContent>;
|
|
497
|
-
details?: unknown;
|
|
498
|
-
isError?: boolean;
|
|
499
|
-
terminate?: boolean;
|
|
500
|
-
}
|
|
461
|
+
export type ToolCallResult = BeforeToolCallResult;
|
|
462
|
+
export type ToolResultPatch = AfterToolCallResult;
|
|
501
463
|
export interface SessionBeforeCompactResult {
|
|
502
464
|
cancel?: boolean;
|
|
503
465
|
compaction?: CompactResult;
|
|
@@ -143,7 +143,7 @@ export interface AssistantMessage {
|
|
|
143
143
|
usageMissing?: true;
|
|
144
144
|
stopReason: StopReason;
|
|
145
145
|
errorMessage?: string;
|
|
146
|
-
errorKind?: "length_empty";
|
|
146
|
+
errorKind?: "length_empty" | "degenerate" | "walltime_cutoff";
|
|
147
147
|
partialFinalized?: true;
|
|
148
148
|
repetition?: {
|
|
149
149
|
cut?: RepetitionEvent;
|
|
@@ -647,10 +647,16 @@ function partitionToolCalls(toolCalls, tools) {
|
|
|
647
647
|
}
|
|
648
648
|
return batches;
|
|
649
649
|
}
|
|
650
|
+
function resolveToolConcurrency(configured) {
|
|
651
|
+
if (configured === undefined)
|
|
652
|
+
return 10;
|
|
653
|
+
return Number.isFinite(configured) ? Math.max(1, Math.floor(configured)) : 1;
|
|
654
|
+
}
|
|
650
655
|
async function runCapped(thunks, limit) {
|
|
651
656
|
const results = new Array(thunks.length);
|
|
652
657
|
let next = 0;
|
|
653
|
-
const
|
|
658
|
+
const width = Number.isFinite(limit) ? Math.max(1, Math.min(limit, thunks.length)) : 1;
|
|
659
|
+
const workers = Array.from({ length: width }, async () => {
|
|
654
660
|
while (next < thunks.length) {
|
|
655
661
|
const i = next++;
|
|
656
662
|
results[i] = await thunks[i]();
|
|
@@ -660,7 +666,7 @@ async function runCapped(thunks, limit) {
|
|
|
660
666
|
return results;
|
|
661
667
|
}
|
|
662
668
|
async function executeToolCallsPartitioned(currentContext, assistantMessage, toolCalls, config, signal, emit, executor) {
|
|
663
|
-
const cap = config.maxToolConcurrency
|
|
669
|
+
const cap = resolveToolConcurrency(config.maxToolConcurrency);
|
|
664
670
|
const allFinalized = [];
|
|
665
671
|
const messages = [];
|
|
666
672
|
let engineCutSeen = false;
|
|
@@ -798,7 +804,7 @@ class StreamToolExecutor {
|
|
|
798
804
|
this.signal?.aborted ||
|
|
799
805
|
partialAssistant === null ||
|
|
800
806
|
!isBatchSafeToolCall(findToolByName(this.context.tools, toolCall.name), toolCall) ||
|
|
801
|
-
this.inFlight >= (this.config.maxToolConcurrency
|
|
807
|
+
this.inFlight >= resolveToolConcurrency(this.config.maxToolConcurrency) ||
|
|
802
808
|
this.entries.has(toolCall.id)) {
|
|
803
809
|
this.barrier = true;
|
|
804
810
|
return;
|
|
@@ -927,7 +933,8 @@ function prepareToolCallArguments(tool, toolCall) {
|
|
|
927
933
|
async function prepareToolCall(currentContext, assistantMessage, toolCall, config, signal) {
|
|
928
934
|
const tool = findToolByName(currentContext.tools, toolCall.name);
|
|
929
935
|
if (!tool) {
|
|
930
|
-
const
|
|
936
|
+
const tombstoneEntry = Object.hasOwn(TOMBSTONED_TOOLS, toolCall.name) ? TOMBSTONED_TOOLS[toolCall.name] : undefined;
|
|
937
|
+
const tombstone = typeof tombstoneEntry === "string" ? tombstoneEntry : undefined;
|
|
931
938
|
if (tombstone !== undefined) {
|
|
932
939
|
return {
|
|
933
940
|
kind: "immediate",
|
|
@@ -74,21 +74,23 @@ export interface LoopRecoveryOptions {
|
|
|
74
74
|
hasLiveWriteoutWindow?: () => boolean;
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
|
+
export interface ToolCutInfo {
|
|
78
|
+
toolCallId: string;
|
|
79
|
+
toolName: string;
|
|
80
|
+
elapsedMs: number;
|
|
81
|
+
settled: Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
export interface LoopToolDeadline {
|
|
84
|
+
deadlineMs: () => number | undefined;
|
|
85
|
+
onCut?: (info: ToolCutInfo) => void;
|
|
86
|
+
}
|
|
77
87
|
export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
78
88
|
model: Model;
|
|
79
89
|
recovery?: LoopRecoveryOptions;
|
|
80
90
|
maxTokensPerCall?: () => number | undefined;
|
|
81
91
|
callDeadlineMsPerCall?: () => number | undefined;
|
|
82
92
|
stallTimeoutsPerCall?: () => import("../llm/types.js").StallTimeouts | undefined;
|
|
83
|
-
toolDeadline?:
|
|
84
|
-
deadlineMs: () => number | undefined;
|
|
85
|
-
onCut?: (info: {
|
|
86
|
-
toolCallId: string;
|
|
87
|
-
toolName: string;
|
|
88
|
-
elapsedMs: number;
|
|
89
|
-
settled: Promise<void>;
|
|
90
|
-
}) => void;
|
|
91
|
-
};
|
|
93
|
+
toolDeadline?: LoopToolDeadline;
|
|
92
94
|
maxToolConcurrency?: number;
|
|
93
95
|
streamingToolExecution?: boolean;
|
|
94
96
|
convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Session, type SessionMetadata, type SessionRepo, type SessionTreeEntry } from "../harness/types.js";
|
|
1
|
+
import { type Session, type SessionForkOptions, type SessionMetadata, type SessionRepo, type SessionTreeEntry } from "../harness/types.js";
|
|
2
2
|
export declare class InMemorySessionRepo implements SessionRepo<SessionMetadata, {
|
|
3
3
|
id?: string;
|
|
4
4
|
}> {
|
|
@@ -9,11 +9,7 @@ export declare class InMemorySessionRepo implements SessionRepo<SessionMetadata,
|
|
|
9
9
|
open(metadata: SessionMetadata): Promise<Session>;
|
|
10
10
|
list(): Promise<SessionMetadata[]>;
|
|
11
11
|
delete(metadata: SessionMetadata): Promise<void>;
|
|
12
|
-
fork(sourceMetadata: SessionMetadata, options:
|
|
13
|
-
entryId?: string;
|
|
14
|
-
position?: "before" | "at";
|
|
15
|
-
id?: string;
|
|
16
|
-
}): Promise<Session>;
|
|
12
|
+
fork(sourceMetadata: SessionMetadata, options: SessionForkOptions): Promise<Session>;
|
|
17
13
|
exportEntries(sessionId: string): Promise<SessionTreeEntry[]>;
|
|
18
14
|
importEntries(sessionId: string, owner: string | undefined, entries: SessionTreeEntry[]): Promise<void>;
|
|
19
15
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ImageContent, TextContent } from "../llm/index.js";
|
|
2
2
|
import type { AgentMessage } from "../loop/types.js";
|
|
3
|
-
import type { Session, SessionContext, SessionMetadata, SessionStorage, SessionTreeEntry } from "../harness/types.js";
|
|
3
|
+
import type { Session, SessionContext, SessionMetadata, SessionStorage, SessionTreeEntry, WorkspaceState } from "../harness/types.js";
|
|
4
4
|
import type { BuildContextOptions } from "../harness/types.js";
|
|
5
|
+
import type { PromptEpochDescriptor } from "../../prompt-assembly/epoch.js";
|
|
5
6
|
export declare function buildSessionContext(pathEntries: SessionTreeEntry[], opts?: BuildContextOptions): SessionContext;
|
|
6
7
|
export declare class StoredSession<TMetadata extends SessionMetadata = SessionMetadata> implements Session<TMetadata> {
|
|
7
8
|
private storage;
|
|
@@ -19,40 +20,14 @@ export declare class StoredSession<TMetadata extends SessionMetadata = SessionMe
|
|
|
19
20
|
appendMessage(message: AgentMessage): Promise<string>;
|
|
20
21
|
appendThinkingLevelChange(thinkingLevel: string): Promise<string>;
|
|
21
22
|
appendModelChange(provider: string, modelId: string): Promise<string>;
|
|
22
|
-
appendPromptEpoch(descriptor:
|
|
23
|
-
epoch: number;
|
|
24
|
-
artifactDigest: string;
|
|
25
|
-
packId: string;
|
|
26
|
-
assemblyApi: number;
|
|
27
|
-
activatedBy: "session_start" | "compaction" | "legacy_migration";
|
|
28
|
-
centerArtifactDigest?: string;
|
|
29
|
-
sourceRevision?: string;
|
|
30
|
-
}): Promise<string>;
|
|
23
|
+
appendPromptEpoch(descriptor: PromptEpochDescriptor): Promise<string>;
|
|
31
24
|
appendAnnouncedListing(snapshot: {
|
|
32
25
|
agents?: readonly string[];
|
|
33
26
|
skills?: readonly string[];
|
|
34
27
|
models?: readonly string[];
|
|
35
28
|
}): Promise<string>;
|
|
36
|
-
appendWorkspaceState(state:
|
|
37
|
-
|
|
38
|
-
handsCwd?: string;
|
|
39
|
-
activeWorktree?: {
|
|
40
|
-
worktreeDir: string;
|
|
41
|
-
originalCwd: string;
|
|
42
|
-
baseSha: string;
|
|
43
|
-
entered?: boolean;
|
|
44
|
-
};
|
|
45
|
-
}): Promise<string>;
|
|
46
|
-
getWorkspaceState(): Promise<{
|
|
47
|
-
taskRoot: string;
|
|
48
|
-
handsCwd?: string;
|
|
49
|
-
activeWorktree?: {
|
|
50
|
-
worktreeDir: string;
|
|
51
|
-
originalCwd: string;
|
|
52
|
-
baseSha: string;
|
|
53
|
-
entered?: boolean;
|
|
54
|
-
};
|
|
55
|
-
} | undefined>;
|
|
29
|
+
appendWorkspaceState(state: WorkspaceState): Promise<string>;
|
|
30
|
+
getWorkspaceState(): Promise<WorkspaceState | undefined>;
|
|
56
31
|
getAnnouncedListing(): Promise<{
|
|
57
32
|
agents?: string[];
|
|
58
33
|
skills?: string[];
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export { assembleCodeTools, type CodeToolsConfig, CODE_ROLE } from "./scenarios/
|
|
|
14
14
|
export { capAggregateToolResults, AGGREGATE_TOOL_RESULT_BUDGET_CHARS, DEFAULT_BUDGET_EXEMPT_TOOLS, type AggregateBudgetOptions, } from "./core/tool-result-budget.js";
|
|
15
15
|
export { capAggregateMediaBytes, AGGREGATE_MEDIA_BUDGET_BYTES, type MediaStripInfo } from "./core/media-byte-cap.js";
|
|
16
16
|
export { createAskUserQuestionTool, createDurableQuestionPolicy, QUESTION_AWAITS_RESUME, type OnQuestion, type AskQuestion, type AskQuestionOption, type AskQuestionRequest, type QuestionAnswer, type QuestionAnswerItem, } from "./core/ask-question.js";
|
|
17
|
-
export { createLspTool, gitCheckIgnoreFilter, LSP_OPERATIONS, LSP_FAILURE_BRAND, brandLspFailure, lspFailureOf, type LspNoneReason, type LspOperation, type LspServerManager, type LspSession, type LspResult, type LspLocation, type LspSymbolInfo, type LspRequestParams, type LspToolOptions, type LspTransport, type LspReadText, } from "./core/lsp.js";
|
|
17
|
+
export { createLspTool, gitCheckIgnoreFilter, LSP_OPERATIONS, LSP_FAILURE_BRAND, brandLspFailure, lspFailureOf, SharedAbortScope, settleOnAbort, type LspNoneReason, type LspOperation, type LspServerManager, type LspSession, type LspResult, type LspLocation, type LspSymbolInfo, type LspRequestParams, type LspToolOptions, type LspTransport, type LspReadText, } from "./core/lsp.js";
|
|
18
18
|
export { buildRequest, parseResult, callHierarchyMethod, pathToUri } from "./core/lsp-protocol.js";
|
|
19
19
|
export { TransportLspSession, type SessionWarmup } from "./core/lsp-session.js";
|
|
20
20
|
export { LspDiagnosticsRegistry, formatDiagnosticsBlock, formatDiagnosticsSummary, type LspDiagnostic, type LspFileDiagnostics, } from "./core/lsp-diagnostics.js";
|
|
@@ -27,6 +27,7 @@ export { BrainError, classifyHttp, type BrainErrorCode } from "./brain/errors.js
|
|
|
27
27
|
export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
|
|
28
28
|
export type { RepetitionEvent, RepetitionInspection } from "./brain/repetition.js";
|
|
29
29
|
export { computeCostMicroUsd, modelCostToPricing, type ModelPricing, type TokenCounts, } from "./core/pricing.js";
|
|
30
|
+
export { cacheFamilyOf, promptTokensOf, uncachedInputTokensOf, type CacheFamily } from "./core/runner/usage-accounting.js";
|
|
30
31
|
export { emitTrace, type TraceEvent, type TracerHook } from "./core/trace.js";
|
|
31
32
|
export { InMemoryStrategyStore, type StrategyStore, type StoredStrategy } from "./core/strategy-store.js";
|
|
32
33
|
export { createSqlTool, validateReadOnlySql, type SqlToolOptions } from "./tools/sql.js";
|
|
@@ -56,6 +57,7 @@ export { getShellConfig, isWslBashLauncher } from "./engine/execution-env/node-e
|
|
|
56
57
|
export { isSecretEnvKey, scrubSecretEnv } from "./core/secret-env.js";
|
|
57
58
|
export { MAX_EXEC_OUTPUT_BYTES, RollingTailBuffer, markTruncated } from "./core/exec-output-tail.js";
|
|
58
59
|
export type { ExecutionEnv, FileInfo, Result, FileErrorCode, ExecutionErrorCode } from "./internal/harness.js";
|
|
60
|
+
export type { ExecResult } from "./internal/harness.js";
|
|
59
61
|
export { RemoteExecutionError, hasDestroy, isRemoteExecutionEnv, isSuspendable, isIsolated, missingRestoreSurface, isRetryableRemoteErrorCode, RETRYABLE_REMOTE_ERROR_CODES, } from "./core/remote-env.js";
|
|
60
62
|
export { withRetry } from "./core/with-retry.js";
|
|
61
63
|
export type { RetryPolicy, RetryResult } from "./core/with-retry.js";
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ export { assembleCodeTools, CODE_ROLE } from "./scenarios/full-body.js";
|
|
|
12
12
|
export { capAggregateToolResults, AGGREGATE_TOOL_RESULT_BUDGET_CHARS, DEFAULT_BUDGET_EXEMPT_TOOLS, } from "./core/tool-result-budget.js";
|
|
13
13
|
export { capAggregateMediaBytes, AGGREGATE_MEDIA_BUDGET_BYTES } from "./core/media-byte-cap.js";
|
|
14
14
|
export { createAskUserQuestionTool, createDurableQuestionPolicy, QUESTION_AWAITS_RESUME, } from "./core/ask-question.js";
|
|
15
|
-
export { createLspTool, gitCheckIgnoreFilter, LSP_OPERATIONS, LSP_FAILURE_BRAND, brandLspFailure, lspFailureOf, } from "./core/lsp.js";
|
|
15
|
+
export { createLspTool, gitCheckIgnoreFilter, LSP_OPERATIONS, LSP_FAILURE_BRAND, brandLspFailure, lspFailureOf, SharedAbortScope, settleOnAbort, } from "./core/lsp.js";
|
|
16
16
|
export { buildRequest, parseResult, callHierarchyMethod, pathToUri } from "./core/lsp-protocol.js";
|
|
17
17
|
export { TransportLspSession } from "./core/lsp-session.js";
|
|
18
18
|
export { LspDiagnosticsRegistry, formatDiagnosticsBlock, formatDiagnosticsSummary, } from "./core/lsp-diagnostics.js";
|
|
@@ -24,6 +24,7 @@ export { selectModel, selectModelOrThrow } from "./core/select-model.js";
|
|
|
24
24
|
export { BrainError, classifyHttp } from "./brain/errors.js";
|
|
25
25
|
export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
|
|
26
26
|
export { computeCostMicroUsd, modelCostToPricing, } from "./core/pricing.js";
|
|
27
|
+
export { cacheFamilyOf, promptTokensOf, uncachedInputTokensOf } from "./core/runner/usage-accounting.js";
|
|
27
28
|
export { emitTrace } from "./core/trace.js";
|
|
28
29
|
export { InMemoryStrategyStore } from "./core/strategy-store.js";
|
|
29
30
|
export { createSqlTool, validateReadOnlySql } from "./tools/sql.js";
|
|
@@ -3,5 +3,7 @@ export type { InvokedSkillRetention } from "../engine/compaction/utils.js";
|
|
|
3
3
|
export type { AgentCoreRuntimeDeps } from "../engine/loop/runtime-deps.js";
|
|
4
4
|
export type { AgentMessage, AgentTool, AgentToolResult, AgentToolUpdateCallback, ThinkingLevel, ToolExecutionMode, } from "../engine/loop/types.js";
|
|
5
5
|
export type { AgentHarnessEvent, CompactionSettings, ExecutionEnv, ExecutionErrorCode, FileErrorCode, FileInfo, Result, Session, SessionMetadata, SessionRepo, SessionStorage, SessionTreeEntry, Skill, } from "../engine/harness/types.js";
|
|
6
|
-
export type { ExecutionEnvExecOptions } from "../engine/harness/types.js";
|
|
6
|
+
export type { ExecutionEnvExecOptions, ExecResult } from "../engine/harness/types.js";
|
|
7
7
|
export type { SessionWriteOptions, CompactionEntry } from "../engine/harness/types.js";
|
|
8
|
+
export type { ActiveWorktreeSession, WorkspaceState } from "../engine/harness/types.js";
|
|
9
|
+
export type { SessionForkOptions } from "../engine/harness/types.js";
|
|
@@ -4,8 +4,10 @@ import { isAbsolute, resolve, sep } from "node:path";
|
|
|
4
4
|
import { combinePolicies } from "../core/tool-policy.js";
|
|
5
5
|
import { delimitUntrusted } from "../core/untrusted-text.js";
|
|
6
6
|
import { isDurablePause } from "../agents/suspend-guard.js";
|
|
7
|
+
import { isAbsolutePathForm, writeTargetPath } from "../tools/fs/safety.js";
|
|
8
|
+
import { canonicalToolName } from "../core/tool-name-aliases.js";
|
|
7
9
|
import { captureBaseline, resolveFrozenPaths, restoreFrozenPaths, runOracle, snapshotFrozenPaths, specError, } from "../core/spec-contract.js";
|
|
8
|
-
const WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
10
|
+
const WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"].map(canonicalToolName));
|
|
9
11
|
const CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32";
|
|
10
12
|
const pathKey = (p) => {
|
|
11
13
|
let n = p.replace(/\\/g, "/");
|
|
@@ -17,13 +19,14 @@ function frozenDenyPolicy(rootDir, frozenResolved) {
|
|
|
17
19
|
const frozen = new Set(frozenResolved.map(pathKey));
|
|
18
20
|
return {
|
|
19
21
|
check(req) {
|
|
20
|
-
|
|
22
|
+
const toolName = canonicalToolName(req.toolName);
|
|
23
|
+
if (!WRITE_TOOLS.has(toolName))
|
|
21
24
|
return { action: "allow" };
|
|
22
25
|
const args = req.args;
|
|
23
|
-
const raw =
|
|
26
|
+
const raw = writeTargetPath(toolName, args);
|
|
24
27
|
if (typeof raw !== "string" || raw.length === 0)
|
|
25
28
|
return { action: "allow" };
|
|
26
|
-
const absForm =
|
|
29
|
+
const absForm = isAbsolutePathForm(raw);
|
|
27
30
|
const abs = pathKey(absForm ? raw : resolve(rootDir, raw));
|
|
28
31
|
if (frozen.has(abs)) {
|
|
29
32
|
return { action: "deny", reason: `${raw} is part of the frozen specification surface (read-only).` };
|