@sema-agent/core 1.451.0 → 2.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/dist/agents/agent-transcript-tool.d.ts +15 -0
- package/dist/agents/agent-transcript-tool.js +122 -0
- package/dist/agents/cascade.js +5 -8
- package/dist/agents/observer.js +3 -0
- package/dist/agents/repair-loop.d.ts +1 -1
- package/dist/agents/repair-loop.js +1 -1
- package/dist/agents/retain-ledger.d.ts +60 -0
- package/dist/agents/retain-ledger.js +225 -0
- package/dist/agents/roster-store.d.ts +1 -0
- package/dist/agents/roster-store.js +9 -0
- package/dist/agents/send-message-tool.d.ts +41 -0
- package/dist/agents/send-message-tool.js +469 -0
- package/dist/agents/subagent.d.ts +33 -108
- package/dist/agents/subagent.js +40 -813
- package/dist/agents/teacher.d.ts +0 -1
- package/dist/agents/teacher.js +0 -9
- package/dist/bin/sema-tb.js +3 -3
- package/dist/brain/anthropic.js +15 -40
- package/dist/brain/openai.js +15 -40
- package/dist/brain/reasoning.d.ts +1 -1
- package/dist/brain/stream-engine.js +2 -2
- package/dist/brain/stream-shared.d.ts +17 -0
- package/dist/brain/stream-shared.js +50 -0
- package/dist/brain/timeout.d.ts +1 -1
- package/dist/brain/timeout.js +1 -1
- package/dist/config/catalog.js +1 -3
- package/dist/config/defaults.d.ts +6 -0
- package/dist/config/defaults.js +6 -0
- package/dist/core/ask-question.d.ts +1 -1
- package/dist/core/ask-question.js +5 -5
- package/dist/core/background-agent-store.d.ts +2 -0
- package/dist/core/background-agent-store.js +5 -1
- package/dist/core/background-shell.d.ts +1 -1
- package/dist/core/checkpoint-store.d.ts +0 -1
- package/dist/core/exec-gate.d.ts +1 -1
- package/dist/core/exec-output-tail.d.ts +19 -1
- package/dist/core/exec-output-tail.js +44 -5
- package/dist/core/file-snapshot-store.d.ts +1 -1
- package/dist/core/fs-write-gate-policy.d.ts +1 -1
- package/dist/core/git-worktree-env.d.ts +1 -1
- package/dist/core/hooks.d.ts +1 -1
- package/dist/core/image-downsample.d.ts +44 -0
- package/dist/core/image-downsample.js +97 -0
- package/dist/core/lsp-session.d.ts +1 -0
- package/dist/core/lsp-session.js +24 -6
- package/dist/core/lsp.d.ts +11 -1
- package/dist/core/lsp.js +63 -6
- package/dist/core/mailbox-store.d.ts +3 -2
- package/dist/core/mailbox-store.js +19 -4
- package/dist/core/mcp.d.ts +3 -45
- package/dist/core/mcp.js +2 -97
- package/dist/core/media-byte-cap.d.ts +1 -1
- package/dist/core/memory-recall.d.ts +0 -12
- package/dist/core/memory-recall.js +0 -222
- package/dist/core/memory.d.ts +0 -6
- package/dist/core/memory.js +0 -88
- package/dist/core/message-utils.d.ts +1 -1
- package/dist/core/oracle-isolation.d.ts +1 -1
- package/dist/core/remote-env.d.ts +1 -1
- package/dist/core/roles.d.ts +1 -1
- package/dist/core/runner/active-skill-scope.d.ts +1 -1
- package/dist/core/runner/assemble-result.d.ts +0 -2
- package/dist/core/runner/memory-consolidation.d.ts +1 -1
- package/dist/core/runner/prepare-memory.d.ts +16 -0
- package/dist/core/runner/prepare-memory.js +191 -0
- package/dist/core/runner/prepare-task.d.ts +4 -28
- package/dist/core/runner/prepare-task.js +29 -208
- package/dist/core/runner/prompt-suggestions.d.ts +1 -1
- package/dist/core/runner/runtask.d.ts +2 -3
- package/dist/core/runner/runtask.js +337 -529
- package/dist/core/runner/session-rule-policy.d.ts +1 -1
- package/dist/core/runner/synthetic-tools.d.ts +5 -5
- package/dist/core/runner/synthetic-tools.js +4 -4
- package/dist/core/runner/tool-disclosure.d.ts +3 -3
- package/dist/core/runner/tool-disclosure.js +2 -2
- package/dist/core/runner/tool-output-projection.d.ts +6 -0
- package/dist/core/runner/tool-output-projection.js +81 -0
- package/dist/core/runtime.d.ts +1 -1
- package/dist/core/scheduler.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/session-reconcile.d.ts +1 -1
- package/dist/core/session-reconcile.js +5 -2
- package/dist/core/session-store.d.ts +2 -1
- package/dist/core/session-store.js +2 -1
- package/dist/core/session.d.ts +0 -1
- package/dist/core/task-notification.d.ts +1 -0
- package/dist/core/task-registry-agent.d.ts +115 -0
- package/dist/core/task-registry-agent.js +1163 -0
- package/dist/core/task-registry-monitor.d.ts +13 -0
- package/dist/core/task-registry-monitor.js +347 -0
- package/dist/core/task-registry-shared.d.ts +294 -0
- package/dist/core/task-registry-shared.js +271 -0
- package/dist/core/task-registry-workflow.d.ts +5 -0
- package/dist/core/task-registry-workflow.js +143 -0
- package/dist/core/task-registry.d.ts +54 -213
- package/dist/core/task-registry.js +190 -1766
- package/dist/core/task-tool-shape.d.ts +32 -0
- package/dist/core/task-tool-shape.js +83 -0
- package/dist/core/tool-policy.d.ts +1 -2
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +2 -2
- package/dist/core/tool-result-store.js +3 -3
- package/dist/core/tools.d.ts +7 -3
- package/dist/core/tools.js +3 -8
- package/dist/core/trace.d.ts +2 -2
- package/dist/core/types.d.ts +1 -29
- package/dist/core/workflow-journal-store.d.ts +2 -0
- package/dist/core/workflow-journal-store.js +14 -0
- package/dist/core/workflow-run-store-contract.d.ts +1 -1
- package/dist/core/workflow-run-store-contract.js +19 -19
- package/dist/engine/execution-env/node-execution-env.d.ts +14 -0
- package/dist/engine/execution-env/node-execution-env.js +184 -44
- package/dist/engine/lsp/frame-decoder.d.ts +1 -1
- package/dist/engine/lsp/frame-decoder.js +1 -1
- package/dist/engine/lsp/node-lsp-manager.d.ts +4 -2
- package/dist/engine/lsp/node-lsp-manager.js +22 -5
- package/dist/engine/lsp/stdio-lsp-transport.d.ts +1 -1
- package/dist/engine/lsp/stdio-lsp-transport.js +19 -8
- package/dist/index.d.ts +18 -16
- package/dist/index.js +15 -13
- package/dist/internal/harness-types.d.ts +7 -0
- package/dist/internal/harness-types.js +1 -0
- package/dist/internal/harness.d.ts +1 -7
- package/dist/internal/harness.js +1 -0
- package/dist/orchestration/goal.js +2 -2
- package/dist/orchestration/run-workflow-tool.d.ts +2 -1
- package/dist/orchestration/run-workflow-tool.js +29 -6
- package/dist/orchestration/workflow-types.d.ts +193 -0
- package/dist/orchestration/workflow-types.js +54 -0
- package/dist/orchestration/workflow.d.ts +3 -184
- package/dist/orchestration/workflow.js +87 -64
- package/dist/prompt-assembly/assemble.d.ts +3 -3
- package/dist/prompt-assembly/assemble.js +0 -16
- package/dist/prompt-assembly/explain.d.ts +1 -1
- package/dist/prompt-assembly/tool-catalog.d.ts +1 -1
- package/dist/prompts/default.d.ts +1 -6
- package/dist/prompts/default.js +3 -11
- package/dist/scenarios/env.d.ts +1 -1
- package/dist/scenarios/full-body.d.ts +0 -3
- package/dist/scenarios/full-body.js +0 -2
- package/dist/stores/cc/mailbox-store.js +6 -1
- package/dist/stores/file/background-agent-store.d.ts +2 -15
- package/dist/stores/file/background-agent-store.js +33 -102
- package/dist/stores/file/checkpoint-store.d.ts +1 -14
- package/dist/stores/file/checkpoint-store.js +47 -119
- package/dist/stores/file/file-snapshot-store.d.ts +1 -1
- package/dist/stores/file/mailbox-store.d.ts +1 -1
- package/dist/stores/file/mailbox-store.js +9 -7
- package/dist/stores/file/shared-ledger.d.ts +35 -0
- package/dist/stores/file/shared-ledger.js +94 -0
- package/dist/stores/file/workflow-run-store.d.ts +1 -14
- package/dist/stores/file/workflow-run-store.js +24 -93
- package/dist/tools/fs/bash-readonly-classifier.d.ts +8 -0
- package/dist/tools/fs/bash-readonly-classifier.js +166 -0
- package/dist/tools/fs/encoding.d.ts +5 -0
- package/dist/tools/fs/encoding.js +6 -0
- package/dist/tools/fs/fs-bash.d.ts +31 -0
- package/dist/tools/fs/fs-bash.js +672 -0
- package/dist/tools/fs/fs-pdf.d.ts +22 -0
- package/dist/tools/fs/fs-pdf.js +236 -0
- package/dist/tools/fs/fs-read.d.ts +8 -0
- package/dist/tools/fs/fs-read.js +286 -0
- package/dist/tools/fs/fs-search-tools.d.ts +5 -0
- package/dist/tools/fs/fs-search-tools.js +173 -0
- package/dist/tools/fs/fs-shared.d.ts +55 -0
- package/dist/tools/fs/fs-shared.js +144 -0
- package/dist/tools/fs/fs-write.d.ts +8 -0
- package/dist/tools/fs/fs-write.js +423 -0
- package/dist/tools/fs/index.d.ts +12 -65
- package/dist/tools/fs/index.js +26 -2026
- package/dist/tools/fs/notebook.d.ts +43 -0
- package/dist/tools/fs/notebook.js +141 -0
- package/dist/tools/fs/pdf.d.ts +1 -1
- package/dist/tools/fs/repo-map.d.ts +3 -3
- package/dist/tools/fs/repo-map.js +3 -3
- package/dist/tools/fs/safety.d.ts +1 -1
- package/dist/tools/fs/search.d.ts +1 -1
- package/dist/tools/fs/search.js +141 -12
- package/dist/tools/gitea-issue.js +4 -2
- package/dist/tools/monitor.d.ts +1 -1
- package/dist/tools/monitor.js +12 -8
- package/dist/tools/scheduler-tools.d.ts +1 -1
- package/dist/tools/scheduler-tools.js +16 -16
- package/dist/tools/task-list.js +34 -12
- package/dist/tools/web.d.ts +4 -2
- package/dist/tools/web.js +106 -20
- package/dist/tools/worktree.d.ts +1 -1
- package/dist/tools/worktree.js +14 -14
- package/package.json +1 -1
- package/dist/core/dynamic-recall.d.ts +0 -32
- package/dist/core/dynamic-recall.js +0 -76
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare function isNotebookPath(p: string): boolean;
|
|
2
|
+
export declare const NOTEBOOK_CELL_OUTPUT_POINTER_CHARS = 10000;
|
|
3
|
+
export declare const NOTEBOOK_OUTPUT_TEXT_CLIP = 10000;
|
|
4
|
+
export declare const NOTEBOOK_IMAGE_BASE64_BUDGET = 262144;
|
|
5
|
+
export interface NotebookOutputImage {
|
|
6
|
+
image_data: string;
|
|
7
|
+
media_type: "image/png" | "image/jpeg";
|
|
8
|
+
}
|
|
9
|
+
export interface NotebookOutput {
|
|
10
|
+
output_type: string;
|
|
11
|
+
text?: string;
|
|
12
|
+
image?: NotebookOutputImage;
|
|
13
|
+
}
|
|
14
|
+
export interface NotebookCell {
|
|
15
|
+
cell_id: string;
|
|
16
|
+
cellType: string;
|
|
17
|
+
source: string;
|
|
18
|
+
language?: string;
|
|
19
|
+
execution_count?: number;
|
|
20
|
+
outputs?: NotebookOutput[];
|
|
21
|
+
}
|
|
22
|
+
export type ParsedNotebook = {
|
|
23
|
+
ok: true;
|
|
24
|
+
cells: NotebookCell[];
|
|
25
|
+
} | {
|
|
26
|
+
ok: false;
|
|
27
|
+
reason: "json" | "shape";
|
|
28
|
+
};
|
|
29
|
+
export declare function parseNotebookCells(text: string, notebookPath: string): ParsedNotebook;
|
|
30
|
+
export interface NotebookRender {
|
|
31
|
+
blocks: Array<{
|
|
32
|
+
type: "text";
|
|
33
|
+
text: string;
|
|
34
|
+
} | {
|
|
35
|
+
type: "image";
|
|
36
|
+
data: string;
|
|
37
|
+
mimeType: string;
|
|
38
|
+
}>;
|
|
39
|
+
textChars: number;
|
|
40
|
+
imageChars: number;
|
|
41
|
+
}
|
|
42
|
+
export declare function renderNotebookCells(cells: readonly NotebookCell[], imageBase64Budget: number): NotebookRender;
|
|
43
|
+
export declare function stripNotebookImageData(cell: NotebookCell): NotebookCell;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { imageMagicMatches } from "./safety.js";
|
|
2
|
+
export function isNotebookPath(p) {
|
|
3
|
+
return p.toLowerCase().endsWith(".ipynb");
|
|
4
|
+
}
|
|
5
|
+
export const NOTEBOOK_CELL_OUTPUT_POINTER_CHARS = 10_000;
|
|
6
|
+
export const NOTEBOOK_OUTPUT_TEXT_CLIP = 10_000;
|
|
7
|
+
export const NOTEBOOK_IMAGE_BASE64_BUDGET = 262_144;
|
|
8
|
+
function joinedText(v) {
|
|
9
|
+
if (v === undefined || v === null)
|
|
10
|
+
return "";
|
|
11
|
+
return Array.isArray(v) ? v.join("") : String(v);
|
|
12
|
+
}
|
|
13
|
+
function clipOutputText(s) {
|
|
14
|
+
if (s.length <= NOTEBOOK_OUTPUT_TEXT_CLIP)
|
|
15
|
+
return s;
|
|
16
|
+
const droppedLines = s.slice(NOTEBOOK_OUTPUT_TEXT_CLIP).split("\n").length;
|
|
17
|
+
return `${s.slice(0, NOTEBOOK_OUTPUT_TEXT_CLIP)}\n\n… [${droppedLines} lines truncated] …`;
|
|
18
|
+
}
|
|
19
|
+
function imageFromData(data) {
|
|
20
|
+
if (data === undefined)
|
|
21
|
+
return undefined;
|
|
22
|
+
for (const mime of ["image/png", "image/jpeg"]) {
|
|
23
|
+
const v = data[mime];
|
|
24
|
+
if (typeof v !== "string")
|
|
25
|
+
continue;
|
|
26
|
+
const stripped = v.replace(/\s/g, "");
|
|
27
|
+
if (!imageMagicMatches(Buffer.from(stripped, "base64"), mime))
|
|
28
|
+
return undefined;
|
|
29
|
+
return { image_data: stripped, media_type: mime };
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
function mapOutput(raw) {
|
|
34
|
+
if (raw === null || typeof raw !== "object")
|
|
35
|
+
return undefined;
|
|
36
|
+
const o = raw;
|
|
37
|
+
switch (o.output_type) {
|
|
38
|
+
case "stream":
|
|
39
|
+
return { output_type: "stream", text: clipOutputText(joinedText(o.text)) };
|
|
40
|
+
case "execute_result":
|
|
41
|
+
case "display_data": {
|
|
42
|
+
const data = o.data !== null && typeof o.data === "object" ? o.data : undefined;
|
|
43
|
+
const image = imageFromData(data);
|
|
44
|
+
return { output_type: o.output_type, text: clipOutputText(joinedText(data?.["text/plain"])), ...(image ? { image } : {}) };
|
|
45
|
+
}
|
|
46
|
+
case "error": {
|
|
47
|
+
const tb = Array.isArray(o.traceback) ? o.traceback.join("\n") : "";
|
|
48
|
+
return { output_type: "error", text: clipOutputText(`${joinedText(o.ename)}: ${joinedText(o.evalue)}\n${tb}`) };
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function parseNotebookCells(text, notebookPath) {
|
|
55
|
+
let nb;
|
|
56
|
+
try {
|
|
57
|
+
nb = JSON.parse(text);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return { ok: false, reason: "json" };
|
|
61
|
+
}
|
|
62
|
+
const top = nb;
|
|
63
|
+
const rawCells = top?.cells;
|
|
64
|
+
if (!Array.isArray(rawCells) || rawCells.some((c) => c === null || typeof c !== "object")) {
|
|
65
|
+
return { ok: false, reason: "shape" };
|
|
66
|
+
}
|
|
67
|
+
const language = typeof top?.metadata?.language_info?.name === "string" ? top.metadata.language_info.name : "python";
|
|
68
|
+
const cells = rawCells.map((raw, i) => {
|
|
69
|
+
const c = raw;
|
|
70
|
+
const cellType = typeof c.cell_type === "string" ? c.cell_type : "code";
|
|
71
|
+
const cell = {
|
|
72
|
+
cell_id: typeof c.id === "string" ? c.id : `cell-${i}`,
|
|
73
|
+
cellType,
|
|
74
|
+
source: joinedText(c.source),
|
|
75
|
+
};
|
|
76
|
+
if (cellType === "code") {
|
|
77
|
+
cell.language = language;
|
|
78
|
+
if (typeof c.execution_count === "number" && c.execution_count)
|
|
79
|
+
cell.execution_count = c.execution_count;
|
|
80
|
+
if (Array.isArray(c.outputs) && c.outputs.length > 0) {
|
|
81
|
+
const mapped = c.outputs.map(mapOutput).filter((o) => o !== undefined);
|
|
82
|
+
let sum = 0;
|
|
83
|
+
let over = false;
|
|
84
|
+
for (const o of mapped) {
|
|
85
|
+
sum += (o.text?.length ?? 0) + (o.image?.image_data.length ?? 0);
|
|
86
|
+
if (sum > NOTEBOOK_CELL_OUTPUT_POINTER_CHARS) {
|
|
87
|
+
over = true;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
cell.outputs = over
|
|
92
|
+
? [{ output_type: "stream", text: `Outputs are too large to include. Use Bash with: cat "${notebookPath}" | jq '.cells[${i}].outputs'` }]
|
|
93
|
+
: mapped;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return cell;
|
|
97
|
+
});
|
|
98
|
+
return { ok: true, cells };
|
|
99
|
+
}
|
|
100
|
+
export function renderNotebookCells(cells, imageBase64Budget) {
|
|
101
|
+
const blocks = [];
|
|
102
|
+
let imageChars = 0;
|
|
103
|
+
const pushText = (t) => {
|
|
104
|
+
const last = blocks[blocks.length - 1];
|
|
105
|
+
if (last !== undefined && last.type === "text")
|
|
106
|
+
last.text += `\n${t}`;
|
|
107
|
+
else
|
|
108
|
+
blocks.push({ type: "text", text: t });
|
|
109
|
+
};
|
|
110
|
+
for (const cell of cells) {
|
|
111
|
+
const tags = [];
|
|
112
|
+
if (cell.cellType !== "code")
|
|
113
|
+
tags.push(`<cell_type>${cell.cellType}</cell_type>`);
|
|
114
|
+
if (cell.language !== undefined && cell.language !== "python" && cell.cellType === "code")
|
|
115
|
+
tags.push(`<language>${cell.language}</language>`);
|
|
116
|
+
pushText(`<cell id="${cell.cell_id}">${tags.join("")}${cell.source}</cell id="${cell.cell_id}">`);
|
|
117
|
+
for (const o of cell.outputs ?? []) {
|
|
118
|
+
if (o.text !== undefined && o.text !== "")
|
|
119
|
+
pushText(`\n${o.text}`);
|
|
120
|
+
if (o.image !== undefined) {
|
|
121
|
+
if (imageChars + o.image.image_data.length > imageBase64Budget) {
|
|
122
|
+
pushText("[image output omitted: notebook image budget exceeded]");
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
imageChars += o.image.image_data.length;
|
|
126
|
+
blocks.push({ type: "image", data: o.image.image_data, mimeType: o.image.media_type });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const textChars = blocks.reduce((n, b) => n + (b.type === "text" ? b.text.length : 0), 0);
|
|
132
|
+
return { blocks, textChars, imageChars };
|
|
133
|
+
}
|
|
134
|
+
export function stripNotebookImageData(cell) {
|
|
135
|
+
if (cell.outputs === undefined)
|
|
136
|
+
return cell;
|
|
137
|
+
return {
|
|
138
|
+
...cell,
|
|
139
|
+
outputs: cell.outputs.map((o) => o.image === undefined ? o : { ...o, image: { ...o.image, image_data: `[${o.image.image_data.length} base64 chars omitted]` } }),
|
|
140
|
+
};
|
|
141
|
+
}
|
package/dist/tools/fs/pdf.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExecutionEnv } from "../../internal/harness.js";
|
|
1
|
+
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
2
|
export declare const PDF_MAX_PAGES_PER_READ = 20;
|
|
3
3
|
export declare const PDF_INLINE_PAGE_THRESHOLD = 10;
|
|
4
4
|
export declare const PDF_TARGET_RAW_SIZE: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentTool } from "../../internal/harness.js";
|
|
2
|
-
import type { ExecutionEnv } from "../../internal/harness.js";
|
|
1
|
+
import type { AgentTool } from "../../internal/harness-types.js";
|
|
2
|
+
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
3
3
|
export declare function extractSymbols(text: string): string[];
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function createRepoMapTool(env: ExecutionEnv, rootCanonical: string, additionalRoots?: readonly string[]): AgentTool;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
|
-
import { defineTool } from "../../core/tools.js";
|
|
2
|
+
import { defineTool, errorResult } from "../../core/tools.js";
|
|
3
3
|
import { resolveKey, violationText } from "./safety.js";
|
|
4
4
|
import { buildIgnore, walk, walkIsPartial } from "./search.js";
|
|
5
5
|
const DEFAULT_MAX_CHARS = 16_000;
|
|
@@ -79,7 +79,7 @@ function rankEntries(a, b) {
|
|
|
79
79
|
return b.symbols.length - a.symbols.length;
|
|
80
80
|
return a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0;
|
|
81
81
|
}
|
|
82
|
-
export function
|
|
82
|
+
export function createRepoMapTool(env, rootCanonical, additionalRoots) {
|
|
83
83
|
return defineTool({
|
|
84
84
|
name: "RepoMap",
|
|
85
85
|
contract: { contractId: "core.repo_map@1", implementationRevision: "1" },
|
|
@@ -101,7 +101,7 @@ export function makeRepoMapTool(env, rootCanonical, additionalRoots) {
|
|
|
101
101
|
if (a.path !== undefined) {
|
|
102
102
|
const r = await resolveKey(env, rootCanonical, a.path, signal, rootCanonical, additionalRoots);
|
|
103
103
|
if (!r.ok)
|
|
104
|
-
return violationText("RepoMap", r.violation);
|
|
104
|
+
return errorResult(violationText("RepoMap", r.violation));
|
|
105
105
|
start = r.key;
|
|
106
106
|
}
|
|
107
107
|
const maxChars = Math.max(1, Math.floor(a.max_chars ?? DEFAULT_MAX_CHARS));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExecutionEnv } from "../../internal/harness.js";
|
|
1
|
+
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
2
|
export declare function fileArgPath(args: unknown): string | undefined;
|
|
3
3
|
export declare function writeTargetPath(canonicalName: string, args: unknown): string | undefined;
|
|
4
4
|
export interface ReadEntry {
|
package/dist/tools/fs/search.js
CHANGED
|
@@ -76,7 +76,7 @@ export function splitAbsoluteGlobPattern(pattern) {
|
|
|
76
76
|
export function shellQuote(s) {
|
|
77
77
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
78
78
|
}
|
|
79
|
-
function globTokenToRegExp(token, anchored,
|
|
79
|
+
function globTokenToRegExp(token, anchored, glob = false) {
|
|
80
80
|
const charToRe = (ch) => ch === "*" ? "[^/]*" : ch === "?" ? "[^/]" : ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
81
81
|
let re = "";
|
|
82
82
|
for (let i = 0; i < token.length; i++) {
|
|
@@ -93,7 +93,7 @@ function globTokenToRegExp(token, anchored, braces = false) {
|
|
|
93
93
|
}
|
|
94
94
|
else if (c === "?")
|
|
95
95
|
re += "[^/]";
|
|
96
|
-
else if (
|
|
96
|
+
else if (glob && c === "{") {
|
|
97
97
|
const close = token.indexOf("}", i);
|
|
98
98
|
if (close > i + 1) {
|
|
99
99
|
const alts = token.slice(i + 1, close).split(",").map((alt) => [...alt].map(charToRe).join(""));
|
|
@@ -103,11 +103,52 @@ function globTokenToRegExp(token, anchored, braces = false) {
|
|
|
103
103
|
else
|
|
104
104
|
re += "\\{";
|
|
105
105
|
}
|
|
106
|
+
else if (glob && c === "[") {
|
|
107
|
+
let j = i + 1;
|
|
108
|
+
let neg = false;
|
|
109
|
+
if (token[j] === "!" || token[j] === "^") {
|
|
110
|
+
neg = true;
|
|
111
|
+
j++;
|
|
112
|
+
}
|
|
113
|
+
const bodyStart = j;
|
|
114
|
+
if (token[j] === "]")
|
|
115
|
+
j++;
|
|
116
|
+
const close = token.indexOf("]", j);
|
|
117
|
+
let cls;
|
|
118
|
+
if (close !== -1) {
|
|
119
|
+
const body = token.slice(bodyStart, close).replace(/[\\[\]]/g, "\\$&").replace(/\//g, "");
|
|
120
|
+
cls = `[${neg ? "^/" : ""}${body}]`;
|
|
121
|
+
try {
|
|
122
|
+
new RegExp(cls);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
cls = undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (cls !== undefined) {
|
|
129
|
+
re += cls;
|
|
130
|
+
i = close;
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
re += "\\[";
|
|
134
|
+
}
|
|
106
135
|
else
|
|
107
136
|
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
108
137
|
}
|
|
109
138
|
return new RegExp(`${anchored ? "^" : "(^|/)"}${re}$`);
|
|
110
139
|
}
|
|
140
|
+
function normalizeGlobToken(token) {
|
|
141
|
+
let t = token;
|
|
142
|
+
while (t.startsWith("./"))
|
|
143
|
+
t = t.slice(2);
|
|
144
|
+
return t.replace(/^\/+/, "");
|
|
145
|
+
}
|
|
146
|
+
function globIsAnchored(token) {
|
|
147
|
+
let t = token;
|
|
148
|
+
while (t.startsWith("./"))
|
|
149
|
+
t = t.slice(2);
|
|
150
|
+
return t.includes("/");
|
|
151
|
+
}
|
|
111
152
|
export function gitignoreMatcher(content) {
|
|
112
153
|
const rules = content
|
|
113
154
|
.split(/\r?\n/)
|
|
@@ -736,9 +777,9 @@ export async function jsGrep(env, root, p, signal, guards) {
|
|
|
736
777
|
return p.path || r === abs ? r : `./${r}`;
|
|
737
778
|
};
|
|
738
779
|
if (p.glob) {
|
|
739
|
-
const globRes = splitGlobParam(p.glob).map((g) => globTokenToRegExp(g,
|
|
780
|
+
const globRes = splitGlobParam(p.glob).map((g) => globTokenToRegExp(normalizeGlobToken(g), globIsAnchored(g), true));
|
|
740
781
|
if (globRes.length > 0)
|
|
741
|
-
files = files.filter((f) => globRes.some((re) => re.test(rel(f))));
|
|
782
|
+
files = files.filter((f) => globRes.some((re) => re.test(rel(f).replace(/\\/g, "/"))));
|
|
742
783
|
}
|
|
743
784
|
let typeNote = "";
|
|
744
785
|
if (p.type) {
|
|
@@ -863,8 +904,8 @@ export async function jsGrep(env, root, p, signal, guards) {
|
|
|
863
904
|
totalContent += fileCount;
|
|
864
905
|
if (fileCount > 0) {
|
|
865
906
|
totalFiles++;
|
|
866
|
-
if (mode === "files_with_matches"
|
|
867
|
-
fileMatches.push(
|
|
907
|
+
if (mode === "files_with_matches")
|
|
908
|
+
fileMatches.push(f);
|
|
868
909
|
else if (mode === "count" && counts.length < collectCap)
|
|
869
910
|
counts.push(`${relOut(f)}:${fileCount}`);
|
|
870
911
|
}
|
|
@@ -888,7 +929,14 @@ export async function jsGrep(env, root, p, signal, guards) {
|
|
|
888
929
|
const paged = (arr) => (off > 0 ? arr.slice(off, off + cap) : arr);
|
|
889
930
|
const offNote = off > 0 ? `\n[offset ${off}]` : "";
|
|
890
931
|
if (mode === "files_with_matches") {
|
|
891
|
-
const
|
|
932
|
+
const haveMtimes = fileMatches.length > 0 && fileMatches.every((f) => walked.mtimes.has(f));
|
|
933
|
+
const sortedFileMatches = haveMtimes
|
|
934
|
+
? fileMatches
|
|
935
|
+
.map((f) => ({ r: relOut(f), m: walked.mtimes.get(f) }))
|
|
936
|
+
.sort((a, b) => b.m - a.m || (a.r < b.r ? -1 : a.r > b.r ? 1 : 0))
|
|
937
|
+
.map((x) => x.r)
|
|
938
|
+
: fileMatches.map(relOut).sort();
|
|
939
|
+
const body = sortedFileMatches.slice(off, off + cap);
|
|
892
940
|
return body.length === 0
|
|
893
941
|
? NO_MATCHES + offNote + typeNote + caveat
|
|
894
942
|
: body.join("\n") + (totalFiles > off + cap ? `\n…[capped at ${cap} of ${totalFiles}]` : "") + offNote + typeNote + caveat;
|
|
@@ -921,6 +969,25 @@ export function detectRipgrep(env) {
|
|
|
921
969
|
}
|
|
922
970
|
return cached;
|
|
923
971
|
}
|
|
972
|
+
async function sortRgFilesByMtime(env, root, stdout, signal) {
|
|
973
|
+
const paths = stdout.split("\n").filter((l) => l.length > 0);
|
|
974
|
+
if (paths.length === 0)
|
|
975
|
+
return stdout;
|
|
976
|
+
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
977
|
+
const toAbs = (p) => {
|
|
978
|
+
const stripped = p.startsWith("./") ? p.slice(2) : p;
|
|
979
|
+
return stripped.startsWith("/") || /^[A-Za-z]:[\\/]/.test(stripped) ? stripped : `${rootPrefix}${stripped}`;
|
|
980
|
+
};
|
|
981
|
+
const infos = await Promise.all(paths.map((p) => env.fileInfo(toAbs(p), signal)));
|
|
982
|
+
const withMtime = paths.map((p, i) => {
|
|
983
|
+
const r = infos[i];
|
|
984
|
+
return { p, m: r.ok && typeof r.value.mtimeMs === "number" ? r.value.mtimeMs : undefined };
|
|
985
|
+
});
|
|
986
|
+
const sorted = withMtime.every((x) => x.m !== undefined)
|
|
987
|
+
? [...withMtime].sort((a, b) => b.m - a.m || (a.p < b.p ? -1 : a.p > b.p ? 1 : 0))
|
|
988
|
+
: [...withMtime].sort((a, b) => (a.p < b.p ? -1 : a.p > b.p ? 1 : 0));
|
|
989
|
+
return sorted.map((x) => x.p).join("\n");
|
|
990
|
+
}
|
|
924
991
|
function formatRgStdout(stdout, p, caveat = "") {
|
|
925
992
|
const cap = p.head_limit === 0 ? Infinity : Math.max(1, Math.floor(p.head_limit ?? GREP_DEFAULT_CAP));
|
|
926
993
|
const off = Math.max(0, Math.floor(p.offset ?? 0));
|
|
@@ -1003,7 +1070,8 @@ export async function rgGrepDetailed(env, root, p, signal) {
|
|
|
1003
1070
|
}
|
|
1004
1071
|
return jsGrepFallback(env, root, p, signal, `exited with code ${exitCode} and produced no output`);
|
|
1005
1072
|
}
|
|
1006
|
-
|
|
1073
|
+
const orderedStdout = mode === "files_with_matches" ? await sortRgFilesByMtime(env, root, stdout, signal) : stdout;
|
|
1074
|
+
return { text: formatRgStdout(orderedStdout, p) };
|
|
1007
1075
|
}
|
|
1008
1076
|
export async function runGrepDetailed(env, root, p, signal) {
|
|
1009
1077
|
if (await detectRipgrep(env))
|
|
@@ -1018,16 +1086,74 @@ export async function runGlob(env, root, pattern, opts = {}, signal) {
|
|
|
1018
1086
|
}
|
|
1019
1087
|
export async function runGlobDetailed(env, root, pattern, opts = {}, signal) {
|
|
1020
1088
|
const t0 = Date.now();
|
|
1021
|
-
const
|
|
1089
|
+
const baseIgnore = await buildIgnore(env, root, signal);
|
|
1022
1090
|
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
1023
1091
|
const start = opts.path ? (opts.path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(opts.path) ? opts.path : `${rootPrefix}${opts.path}`) : root;
|
|
1092
|
+
const pat = normalizeGlobToken(pattern);
|
|
1093
|
+
const anchored = globIsAnchored(pattern);
|
|
1094
|
+
const re = globTokenToRegExp(pat, anchored, true);
|
|
1095
|
+
const startPrefix = start.replace(/[\\/]+$/, "") + (start.includes("\\") ? "\\" : "/");
|
|
1096
|
+
const startRelPrefix = startPrefix.startsWith(rootPrefix) ? startPrefix.slice(rootPrefix.length) : startPrefix;
|
|
1097
|
+
const toStartRel = (p) => {
|
|
1098
|
+
const s = p.startsWith(startPrefix)
|
|
1099
|
+
? p.slice(startPrefix.length)
|
|
1100
|
+
: startRelPrefix.length > 0 && p.startsWith(startRelPrefix)
|
|
1101
|
+
? p.slice(startRelPrefix.length)
|
|
1102
|
+
: p;
|
|
1103
|
+
return s.replace(/\\/g, "/");
|
|
1104
|
+
};
|
|
1105
|
+
const patternSegs = pat.split("/");
|
|
1106
|
+
const groupSpansSlash = /\{[^}]*\/[^}]*\}|\[[^\]]*\/[^\]]*\]/.test(pat);
|
|
1107
|
+
const prunable = anchored && !groupSpansSlash;
|
|
1108
|
+
const firstStarStar = patternSegs.findIndex((s) => s.includes("**"));
|
|
1109
|
+
const starStarIdx = firstStarStar === -1 ? Infinity : firstStarStar;
|
|
1110
|
+
const segRes = prunable ? patternSegs.map((s) => globTokenToRegExp(s, true, true)) : [];
|
|
1111
|
+
const isLiteralSeg = (s) => s.length > 0 && !/[*?[{]/.test(s);
|
|
1112
|
+
const literalAt = prunable ? patternSegs.map((s) => (isLiteralSeg(s) ? s : undefined)) : [];
|
|
1113
|
+
const literalAfterStarStar = new Set(prunable ? patternSegs.filter((s, i) => i > starStarIdx && isLiteralSeg(s)) : []);
|
|
1114
|
+
const mayContainMatch = (dirRel) => {
|
|
1115
|
+
if (!prunable)
|
|
1116
|
+
return true;
|
|
1117
|
+
const d = dirRel.split("/");
|
|
1118
|
+
if (d.length >= patternSegs.length && starStarIdx === Infinity)
|
|
1119
|
+
return false;
|
|
1120
|
+
const lim = Math.min(d.length, starStarIdx);
|
|
1121
|
+
for (let i = 0; i < lim; i++)
|
|
1122
|
+
if (!segRes[i].test(d[i]))
|
|
1123
|
+
return false;
|
|
1124
|
+
return true;
|
|
1125
|
+
};
|
|
1126
|
+
const explicitlyNamed = (sr) => {
|
|
1127
|
+
if (!prunable)
|
|
1128
|
+
return false;
|
|
1129
|
+
const segs = sr.split("/");
|
|
1130
|
+
const k = segs.length - 1;
|
|
1131
|
+
return k < starStarIdx ? literalAt[k] === segs[k] : literalAfterStarStar.has(segs[k]);
|
|
1132
|
+
};
|
|
1133
|
+
let ignoredDirs = 0;
|
|
1134
|
+
const rescued = [];
|
|
1135
|
+
const ignore = (relPath, isDir) => {
|
|
1136
|
+
const sr = toStartRel(relPath);
|
|
1137
|
+
if (isDir && !mayContainMatch(sr))
|
|
1138
|
+
return true;
|
|
1139
|
+
if (explicitlyNamed(sr)) {
|
|
1140
|
+
if (isDir && baseIgnore(relPath, true))
|
|
1141
|
+
rescued.push(sr + "/");
|
|
1142
|
+
return false;
|
|
1143
|
+
}
|
|
1144
|
+
if (rescued.length > 0 && rescued.some((r) => sr.startsWith(r)))
|
|
1145
|
+
return false;
|
|
1146
|
+
const ig = baseIgnore(relPath, isDir);
|
|
1147
|
+
if (ig && isDir)
|
|
1148
|
+
ignoredDirs++;
|
|
1149
|
+
return ig;
|
|
1150
|
+
};
|
|
1024
1151
|
const walked = await walk(env, root, start, ignore, signal);
|
|
1025
1152
|
const caveat = walkCaveat(walked, false);
|
|
1026
1153
|
const files = [...walked.files, ...walked.nameOnly];
|
|
1027
|
-
const re = globTokenToRegExp(pattern, false, true);
|
|
1028
1154
|
const rel = (abs) => (abs.startsWith(rootPrefix) ? abs.slice(rootPrefix.length) : abs);
|
|
1029
1155
|
const cap = Math.max(1, Math.floor(opts.max ?? 500));
|
|
1030
|
-
const matchedAbs = files.filter((f) => re.test(
|
|
1156
|
+
const matchedAbs = files.filter((f) => re.test(toStartRel(f)) || (!anchored && re.test(basename(f))));
|
|
1031
1157
|
const haveMtimes = matchedAbs.length > 0 && matchedAbs.every((f) => walked.mtimes.has(f));
|
|
1032
1158
|
const matchedAll = haveMtimes
|
|
1033
1159
|
? matchedAbs
|
|
@@ -1044,6 +1170,9 @@ export async function runGlobDetailed(env, root, pattern, opts = {}, signal) {
|
|
|
1044
1170
|
: countIsComplete
|
|
1045
1171
|
? `\n(Showing ${matched.length} of ${totalMatches} matching files; ${totalMatches - matched.length} more are not listed. Narrow the pattern or path to see the rest.)`
|
|
1046
1172
|
: `\n(Showing the first ${matched.length} files; there are more than ${totalMatches} matches. Narrow the pattern or path to see the rest.)`;
|
|
1047
|
-
const
|
|
1173
|
+
const ignoreNote = matched.length === 0 && ignoredDirs > 0
|
|
1174
|
+
? `\n[note: ${ignoredDirs} ignored director${ignoredDirs === 1 ? "y was" : "ies were"} not searched (dependency/build/VCS trees and .gitignore) — name a directory in the pattern (e.g. "dist/**") or pass \`path\` to include it]`
|
|
1175
|
+
: "";
|
|
1176
|
+
const text = matched.length === 0 ? "No files matched." + ignoreNote + caveat : matched.join("\n") + capNote + caveat;
|
|
1048
1177
|
return { text, filenames: matched, numFiles: matched.length, truncated, durationMs: Date.now() - t0, totalMatches, countIsComplete };
|
|
1049
1178
|
}
|
|
@@ -23,7 +23,7 @@ export function createGiteaIssueTool(opts) {
|
|
|
23
23
|
const a = args;
|
|
24
24
|
const title = String(a.title ?? "").trim();
|
|
25
25
|
if (!title) {
|
|
26
|
-
return { content: "Issue not created: a non-empty title is required.", details: { error: "empty title" } };
|
|
26
|
+
return { content: "Issue not created: a non-empty title is required.", details: { error: "empty title" }, isError: true };
|
|
27
27
|
}
|
|
28
28
|
const modelLabels = opts.allowModelLabels && Array.isArray(a.labels) ? a.labels : [];
|
|
29
29
|
const labels = [...new Set([...(opts.defaultLabels ?? []), ...modelLabels])];
|
|
@@ -43,13 +43,14 @@ export function createGiteaIssueTool(opts) {
|
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
45
45
|
const msg = e instanceof Error ? e.message : String(e);
|
|
46
|
-
return { content: `Issue not created: request failed (${msg}).`, details: { error: msg } };
|
|
46
|
+
return { content: `Issue not created: request failed (${msg}).`, details: { error: msg }, isError: true };
|
|
47
47
|
}
|
|
48
48
|
if (!res.ok) {
|
|
49
49
|
const detail = await res.text().catch(() => "");
|
|
50
50
|
return {
|
|
51
51
|
content: `Issue not created: Gitea returned HTTP ${res.status}. ${detail.slice(0, 300)}`,
|
|
52
52
|
details: { status: res.status },
|
|
53
|
+
isError: true,
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
const PARSE_FAILED = Symbol("json-parse-failed");
|
|
@@ -60,6 +61,7 @@ export function createGiteaIssueTool(opts) {
|
|
|
60
61
|
content: `Issue request returned HTTP ${res.status} but the response body was not a valid issue ` +
|
|
61
62
|
`(no number) — the issue may NOT have been created; verify before retrying.`,
|
|
62
63
|
details: { status: res.status, parsed: parsed === PARSE_FAILED ? "unparseable" : "no-number" },
|
|
64
|
+
isError: true,
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
const issue = parsed;
|
package/dist/tools/monitor.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentTool, ExecutionEnv } from "../internal/harness.js";
|
|
1
|
+
import type { AgentTool, ExecutionEnv } from "../internal/harness-types.js";
|
|
2
2
|
import { type MonitorTimers, type TaskRegistry } from "../core/task-registry.js";
|
|
3
3
|
import type { TaskNotificationPayload } from "../core/task-notification.js";
|
|
4
4
|
export interface MonitorToolOptions {
|
package/dist/tools/monitor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
|
-
import { defineTool } from "../core/tools.js";
|
|
2
|
+
import { defineTool, errorResult } from "../core/tools.js";
|
|
3
3
|
import { hasBackgroundShell } from "../core/background-shell.js";
|
|
4
4
|
import { MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, } from "../core/task-registry.js";
|
|
5
5
|
const MONITOR_DESCRIPTION = "Run a shell command in the background and watch its stdout as a stream of events.\n" +
|
|
@@ -11,8 +11,9 @@ const MONITOR_DESCRIPTION = "Run a shell command in the background and watch its
|
|
|
11
11
|
"- stderr does NOT trigger notifications, but it is captured — read it any time with TaskOutput(task_id), " +
|
|
12
12
|
"which also serves the full re-readable stdout spool.\n" +
|
|
13
13
|
"- A monitor that produces too many events is stopped automatically (the stop notification says why).\n" +
|
|
14
|
-
"- Set persistent: true for a session-resident watch with no timeout;
|
|
15
|
-
"
|
|
14
|
+
"- Set persistent: true for a session-resident watch with no watch timeout of its own; it still ends when " +
|
|
15
|
+
"the execution environment's background time budget expires, when you stop it with TaskStop(task_id), or " +
|
|
16
|
+
"when the session is released.\n" +
|
|
16
17
|
"- After starting a monitor you do not need to poll — end your turn if nothing else is pending; events will " +
|
|
17
18
|
"reach you as notifications.\n" +
|
|
18
19
|
"- Use this for logs, dev servers, build watchers, or any wait-for-a-condition loop (e.g. `tail -f app.log`, " +
|
|
@@ -44,14 +45,14 @@ export function createMonitorTool(env, opts) {
|
|
|
44
45
|
description: `How long the watch may run before it is killed, in milliseconds (default ${MONITOR_DEFAULT_TIMEOUT_MS}, max ${MONITOR_MAX_TIMEOUT_MS}). Ignored when persistent is true.`,
|
|
45
46
|
})),
|
|
46
47
|
persistent: Type.Optional(Type.Boolean({
|
|
47
|
-
description: "Set to true for a session-resident monitor with no timeout (default false). It keeps watching until you stop it with TaskStop or the session ends.",
|
|
48
|
+
description: "Set to true for a session-resident monitor with no watch timeout of its own (default false). It keeps watching until the execution environment's background time budget expires, until you stop it with TaskStop, or until the session ends.",
|
|
48
49
|
})),
|
|
49
50
|
}),
|
|
50
51
|
effect: "write",
|
|
51
52
|
execute: async (args, ctx) => {
|
|
52
53
|
const { command, description, timeout_ms, persistent } = args;
|
|
53
54
|
if (!hasBackgroundShell(env)) {
|
|
54
|
-
return "Error (Monitor): this environment does not support background processes.";
|
|
55
|
+
return errorResult("Error (Monitor): this environment does not support background processes.");
|
|
55
56
|
}
|
|
56
57
|
const isPersistent = persistent === true;
|
|
57
58
|
const timeoutMs = Math.min(MONITOR_MAX_TIMEOUT_MS, Math.max(1, Math.floor(timeout_ms ?? MONITOR_DEFAULT_TIMEOUT_MS)));
|
|
@@ -60,7 +61,7 @@ export function createMonitorTool(env, opts) {
|
|
|
60
61
|
...(isPersistent ? {} : { timeout: Math.ceil(timeoutMs / 1000) + 5 }),
|
|
61
62
|
});
|
|
62
63
|
if (!spawn.ok)
|
|
63
|
-
return `Error (Monitor): ${spawn.error.message}
|
|
64
|
+
return errorResult(`Error (Monitor): ${spawn.error.message}`);
|
|
64
65
|
const sessionScoped = isPersistent && opts.sessionId !== undefined;
|
|
65
66
|
const owner = sessionScoped ? opts.sessionId : (ctx.taskId ?? opts.owner);
|
|
66
67
|
const scope = ctx.principal ?? opts.scope;
|
|
@@ -85,10 +86,13 @@ export function createMonitorTool(env, opts) {
|
|
|
85
86
|
}
|
|
86
87
|
catch (e) {
|
|
87
88
|
await env.killBackground(spawn.value.shellId).catch(() => undefined);
|
|
88
|
-
return `Error (Monitor): the watch process was started but could not be registered (${e instanceof Error ? e.message : String(e)}); it has been terminated
|
|
89
|
+
return errorResult(`Error (Monitor): the watch process was started but could not be registered (${e instanceof Error ? e.message : String(e)}); it has been terminated.`);
|
|
89
90
|
}
|
|
91
|
+
const bgTimeout = env.backgroundCapabilities.defaultBgTimeoutSec;
|
|
90
92
|
const lifetime = isPersistent
|
|
91
|
-
?
|
|
93
|
+
? typeof bgTimeout === "number"
|
|
94
|
+
? `It is persistent: no watch timeout of its own, but the execution environment kills background processes after ${bgTimeout}s; it runs until then, until you stop it, or until the session ends.`
|
|
95
|
+
: "It is persistent: no watch timeout of its own, but the execution environment's background time budget still applies; it runs until then, until you stop it, or until the session ends."
|
|
92
96
|
: `It will be killed after ${timeoutMs}ms if still running.`;
|
|
93
97
|
return onNotify !== undefined
|
|
94
98
|
? `Monitoring in background; task_id=${taskId}. Each stdout line becomes a notification event (lines within ` +
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentTool, ExecutionEnv } from "../internal/harness.js";
|
|
1
|
+
import type { AgentTool, ExecutionEnv } from "../internal/harness-types.js";
|
|
2
2
|
export declare const SCHEDULE_WAKEUP_TOOL_NAME = "ScheduleWakeup";
|
|
3
3
|
export declare const AUTONOMOUS_LOOP_SENTINEL = "<<autonomous-loop>>";
|
|
4
4
|
export declare const AUTONOMOUS_LOOP_DYNAMIC_SENTINEL = "<<autonomous-loop-dynamic>>";
|