@dreb/coding-agent 2.16.0 → 2.18.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/README.md +7 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +3 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +12 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/index.d.ts +11 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +17 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/subagent.d.ts +6 -0
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +28 -3
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/tools/suggest-next.d.ts +19 -0
- package/dist/core/tools/suggest-next.d.ts.map +1 -0
- package/dist/core/tools/suggest-next.js +72 -0
- package/dist/core/tools/suggest-next.js.map +1 -0
- package/dist/core/tools/tmp-read.d.ts.map +1 -1
- package/dist/core/tools/tmp-read.js +14 -1
- package/dist/core/tools/tmp-read.js.map +1 -1
- package/dist/core/tools/wait.d.ts +40 -0
- package/dist/core/tools/wait.d.ts.map +1 -0
- package/dist/core/tools/wait.js +87 -0
- package/dist/core/tools/wait.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +13 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/extensions.md +2 -2
- package/docs/json.md +2 -1
- package/docs/rpc.md +30 -0
- package/docs/session.md +24 -0
- package/docs/tui.md +8 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tmp-read.js","sourceRoot":"","sources":["../../../src/core/tools/tmp-read.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAwB,MAAM,WAAW,CAAC;AAE3E,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,WAAW,GAAG,MAAM,CAAC;AAE3B
|
|
1
|
+
{"version":3,"file":"tmp-read.js","sourceRoot":"","sources":["../../../src/core/tools/tmp-read.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAwB,MAAM,WAAW,CAAC;AAE3E,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,WAAW,GAAG,MAAM,CAAC;AAE3B,0EAA0E;AAC1E,iFAAiF;AACjF,IAAI,qBAA6B,CAAC;AAClC,IAAI,CAAC;IACJ,qBAAqB,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;AACtD,CAAC;AAAC,MAAM,CAAC;IACR,qBAAqB,GAAG,cAAc,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,YAAoB,EAAW;IAClD,OAAO,CACN,YAAY,KAAK,cAAc;QAC/B,YAAY,CAAC,UAAU,CAAC,GAAG,cAAc,GAAG,CAAC;QAC7C,YAAY,KAAK,qBAAqB;QACtC,YAAY,CAAC,UAAU,CAAC,GAAG,qBAAqB,GAAG,CAAC,CACpD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,2BAA2B,CAAC,OAAyB,EAA4B;IAChG,sDAAsD;IACtD,MAAM,KAAK,GAAG,wBAAwB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAE7D,OAAO;QACN,GAAG,KAAK;QACR,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,+BAA+B,KAAK,CAAC,WAAW,EAAE;QAC/D,aAAa,EAAE,4BAA4B;QAC3C,gBAAgB,EAAE;YACjB,4EAA0E;YAC1E,wEAAwE;SACxE;QAED,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE;YACxD,iFAAiF;YACjF,qFAAmF;YACnF,4EAA4E;YAC5E,sEAAsE;YACtE,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;YACtE,IAAI,QAAgB,CAAC;YACrB,IAAI,CAAC;gBACJ,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC;YAAC,MAAM,CAAC;gBACR,iFAA+E;gBAC/E,QAAQ,GAAG,OAAO,CAAC;YACpB,CAAC;YACD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3B,OAAO;oBACN,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,iFAAiF,QAAQ,EAAE;yBACjG;qBACD;oBACD,OAAO,EAAE,SAAS;iBAClB,CAAC;YACH,CAAC;YAED,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QAAA,CAChE;KACD,CAAC;AAAA,CACF","sourcesContent":["/**\n * tmp-read — A path-restricted read tool that only allows access to /tmp.\n *\n * Used by the Sandbox agent to enforce filesystem isolation. Unlike the\n * regular read tool where /tmp is merely a system-prompt suggestion,\n * this tool rejects any path that resolves outside /tmp at the tool level.\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { resolve as normalizePath } from \"node:path\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport { createReadToolDefinition, type ReadToolOptions } from \"./read.js\";\n\nconst ALLOWED_PREFIX = \"/tmp\";\nconst SANDBOX_CWD = \"/tmp\";\n\n// On macOS, /tmp is a symlink to /private/tmp. Resolve it once at startup\n// so that realpathSync results (which follow symlinks) can be correctly matched.\nlet resolvedAllowedPrefix: string;\ntry {\n\tresolvedAllowedPrefix = realpathSync(ALLOWED_PREFIX);\n} catch {\n\tresolvedAllowedPrefix = ALLOWED_PREFIX;\n}\n\n/**\n * Check whether a resolved absolute path is under /tmp.\n * Handles exact \"/tmp\" match and \"/tmp/...\" paths, rejects \"/tmpevil\" etc.\n * Also handles macOS where /tmp resolves to /private/tmp.\n */\nfunction isUnderTmp(absolutePath: string): boolean {\n\treturn (\n\t\tabsolutePath === ALLOWED_PREFIX ||\n\t\tabsolutePath.startsWith(`${ALLOWED_PREFIX}/`) ||\n\t\tabsolutePath === resolvedAllowedPrefix ||\n\t\tabsolutePath.startsWith(`${resolvedAllowedPrefix}/`)\n\t);\n}\n\nexport function createTmpReadToolDefinition(options?: ReadToolOptions): ToolDefinition<any, any> {\n\t// Create a real read tool definition anchored to /tmp\n\tconst inner = createReadToolDefinition(SANDBOX_CWD, options);\n\n\treturn {\n\t\t...inner,\n\t\tname: \"tmp_read\",\n\t\tlabel: \"tmp_read\",\n\t\tdescription: `Read files under /tmp only. ${inner.description}`,\n\t\tpromptSnippet: \"Read files under /tmp only\",\n\t\tpromptGuidelines: [\n\t\t\t\"tmp_read can ONLY read files under /tmp/ — all other paths are rejected.\",\n\t\t\t\"Use relative paths (resolved against /tmp) or absolute /tmp/... paths.\",\n\t\t],\n\n\t\tasync execute(toolCallId, params, signal, onUpdate, ctx) {\n\t\t\t// Validate the path resolves under /tmp BEFORE delegating to the real read tool.\n\t\t\t// normalizePath collapses \"..\" components (e.g. /tmp/../etc/passwd → /etc/passwd).\n\t\t\t// realpathSync dereferences symlinks so /tmp/evil -> /etc/passwd is caught.\n\t\t\t// Falls back to lexical check if the file doesn't exist yet (ENOENT).\n\t\t\tconst lexical = normalizePath(resolveToCwd(params.path, SANDBOX_CWD));\n\t\t\tlet resolved: string;\n\t\t\ttry {\n\t\t\t\tresolved = realpathSync(lexical);\n\t\t\t} catch {\n\t\t\t\t// File doesn't exist — use lexical path (read will fail with ENOENT naturally)\n\t\t\t\tresolved = lexical;\n\t\t\t}\n\t\t\tif (!isUnderTmp(resolved)) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Error: Access denied. tmp_read can only read files under /tmp. Resolved path: ${resolved}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn inner.execute(toolCallId, params, signal, onUpdate, ctx);\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wait tool — explicit no-op for models that don't know how to end a turn.
|
|
3
|
+
*
|
|
4
|
+
* Some models (notably Kimi) invent useless `bash` calls to simulate waiting.
|
|
5
|
+
* This tool gives them a sanctioned no-op action that cleanly ends the turn.
|
|
6
|
+
*/
|
|
7
|
+
import { type Static } from "@sinclair/typebox";
|
|
8
|
+
import type { ToolDefinition } from "../extensions/types.js";
|
|
9
|
+
/** Minimal shape of a running background agent (avoids importing from subagent.ts to prevent circular deps). */
|
|
10
|
+
export interface WaitAgentInfo {
|
|
11
|
+
agentId: string;
|
|
12
|
+
agentType: string;
|
|
13
|
+
taskSummary: string;
|
|
14
|
+
}
|
|
15
|
+
export interface WaitToolDetails {
|
|
16
|
+
reason: string | undefined;
|
|
17
|
+
runningAgents: readonly WaitAgentInfo[];
|
|
18
|
+
}
|
|
19
|
+
export interface WaitToolOptions {
|
|
20
|
+
/** Returns currently running background agents. Injected by the factory to avoid circular imports. */
|
|
21
|
+
getRunningAgents?: () => readonly WaitAgentInfo[];
|
|
22
|
+
}
|
|
23
|
+
declare const waitSchema: import("@sinclair/typebox").TObject<{
|
|
24
|
+
reason: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
25
|
+
}>;
|
|
26
|
+
export type WaitToolInput = Static<typeof waitSchema>;
|
|
27
|
+
export declare function formatWaitCall(args: {
|
|
28
|
+
reason?: string;
|
|
29
|
+
} | undefined, theme: any): string;
|
|
30
|
+
export declare function formatWaitResult(result: {
|
|
31
|
+
content: Array<{
|
|
32
|
+
type: string;
|
|
33
|
+
text?: string;
|
|
34
|
+
}>;
|
|
35
|
+
details?: WaitToolDetails;
|
|
36
|
+
}, theme: any): string;
|
|
37
|
+
export declare const waitToolDefinition: ToolDefinition<typeof waitSchema, WaitToolDetails | undefined>;
|
|
38
|
+
export declare function createWaitToolDefinition(options?: WaitToolOptions): ToolDefinition<typeof waitSchema, WaitToolDetails | undefined>;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=wait.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../../src/core/tools/wait.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAK7D,gHAAgH;AAChH,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,aAAa,EAAE,SAAS,aAAa,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC/B,sGAAsG;IACtG,gBAAgB,CAAC,EAAE,MAAM,SAAS,aAAa,EAAE,CAAC;CAClD;AAKD,QAAA,MAAM,UAAU;;EAMd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAKtD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EAAE,KAAK,EAAE,GAAG,GAAG,MAAM,CAMxF;AAED,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACtF,KAAK,EAAE,GAAG,GACR,MAAM,CAOR;AAKD,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAsC7F,CAAC;AAOF,wBAAgB,wBAAwB,CACvC,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAiBhE","sourcesContent":["/**\n * Wait tool — explicit no-op for models that don't know how to end a turn.\n *\n * Some models (notably Kimi) invent useless `bash` calls to simulate waiting.\n * This tool gives them a sanctioned no-op action that cleanly ends the turn.\n */\n\nimport { Text } from \"@dreb/tui\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\n\n// ============================================================================\n// Types\n\n/** Minimal shape of a running background agent (avoids importing from subagent.ts to prevent circular deps). */\nexport interface WaitAgentInfo {\n\tagentId: string;\n\tagentType: string;\n\ttaskSummary: string;\n}\n\nexport interface WaitToolDetails {\n\treason: string | undefined;\n\trunningAgents: readonly WaitAgentInfo[];\n}\n\nexport interface WaitToolOptions {\n\t/** Returns currently running background agents. Injected by the factory to avoid circular imports. */\n\tgetRunningAgents?: () => readonly WaitAgentInfo[];\n}\n\n// ============================================================================\n// Schema\n\nconst waitSchema = Type.Object({\n\treason: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Optional reason for waiting (e.g. 'background subagent still running')\",\n\t\t}),\n\t),\n});\n\nexport type WaitToolInput = Static<typeof waitSchema>;\n\n// ============================================================================\n// Render helpers\n\nexport function formatWaitCall(args: { reason?: string } | undefined, theme: any): string {\n\tconst reason = args?.reason;\n\tif (reason) {\n\t\treturn `${theme.fg(\"toolTitle\", theme.bold(\"wait\"))} ${theme.fg(\"muted\", reason)}`;\n\t}\n\treturn theme.fg(\"toolTitle\", theme.bold(\"wait\"));\n}\n\nexport function formatWaitResult(\n\tresult: { content: Array<{ type: string; text?: string }>; details?: WaitToolDetails },\n\ttheme: any,\n): string {\n\tconst agents = result.details?.runningAgents ?? [];\n\tif (agents.length > 0) {\n\t\tconst agentList = agents.map((a) => `${a.agentId.slice(0, 12)} ${a.agentType}`).join(\", \");\n\t\treturn theme.fg(\"muted\", `→ doing nothing (waiting on: ${agentList})`);\n\t}\n\treturn theme.fg(\"muted\", \"→ doing nothing — no subagents running\");\n}\n\n// ============================================================================\n// Tool definition (singleton — no cwd or callback dependencies)\n\nexport const waitToolDefinition: ToolDefinition<typeof waitSchema, WaitToolDetails | undefined> = {\n\tname: \"wait\",\n\tlabel: \"wait\",\n\tdescription:\n\t\t\"Do nothing and end your turn. Use this when you are explicitly told to wait, or when background subagents are running and you have no other work to do.\",\n\n\tparameters: waitSchema,\n\n\tpromptSnippet: \"Do nothing and end your turn (use when waiting for background work to complete)\",\n\n\tpromptGuidelines: [\n\t\t\"Use `wait` only when explicitly told to wait, or when background subagents are still running and you have no other work to do\",\n\t\t\"Do NOT use `wait` as a general-purpose delay or sleep — it returns immediately\",\n\t\t\"If you need to wait for something, call `wait` once — do not loop or call it repeatedly\",\n\t],\n\n\tasync execute(_toolCallId, params: WaitToolInput, _signal?, _onUpdate?, _ctx?) {\n\t\tconst reason = params.reason?.trim() || undefined;\n\t\tconst text = reason ? `Waiting: ${reason}` : \"Waiting…\";\n\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\tdetails: { reason, runningAgents: [] as WaitAgentInfo[] },\n\t\t\tendTurn: true,\n\t\t};\n\t},\n\n\trenderCall(args, theme, context) {\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\ttext.setText(formatWaitCall(args, theme));\n\t\treturn text;\n\t},\n\n\trenderResult(result, _options, theme, context) {\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\ttext.setText(formatWaitResult(result as any, theme));\n\t\treturn text;\n\t},\n};\n\n// ============================================================================\n// Factory — accepts optional getRunningAgents callback to show background agent\n// status in the result. The callback is injected here (rather than imported from\n// subagent.ts) to avoid a circular dependency through model-resolver → args → index.\n\nexport function createWaitToolDefinition(\n\toptions?: WaitToolOptions,\n): ToolDefinition<typeof waitSchema, WaitToolDetails | undefined> {\n\tif (!options?.getRunningAgents) return waitToolDefinition;\n\n\treturn {\n\t\t...waitToolDefinition,\n\t\tasync execute(_toolCallId, params: WaitToolInput, _signal?, _onUpdate?, _ctx?) {\n\t\t\tconst reason = params.reason?.trim() || undefined;\n\t\t\tconst runningAgents = options.getRunningAgents!();\n\t\t\tconst text = reason ? `Waiting: ${reason}` : \"Waiting…\";\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\t\tdetails: { reason, runningAgents },\n\t\t\t\tendTurn: true,\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wait tool — explicit no-op for models that don't know how to end a turn.
|
|
3
|
+
*
|
|
4
|
+
* Some models (notably Kimi) invent useless `bash` calls to simulate waiting.
|
|
5
|
+
* This tool gives them a sanctioned no-op action that cleanly ends the turn.
|
|
6
|
+
*/
|
|
7
|
+
import { Text } from "@dreb/tui";
|
|
8
|
+
import { Type } from "@sinclair/typebox";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Schema
|
|
11
|
+
const waitSchema = Type.Object({
|
|
12
|
+
reason: Type.Optional(Type.String({
|
|
13
|
+
description: "Optional reason for waiting (e.g. 'background subagent still running')",
|
|
14
|
+
})),
|
|
15
|
+
});
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Render helpers
|
|
18
|
+
export function formatWaitCall(args, theme) {
|
|
19
|
+
const reason = args?.reason;
|
|
20
|
+
if (reason) {
|
|
21
|
+
return `${theme.fg("toolTitle", theme.bold("wait"))} ${theme.fg("muted", reason)}`;
|
|
22
|
+
}
|
|
23
|
+
return theme.fg("toolTitle", theme.bold("wait"));
|
|
24
|
+
}
|
|
25
|
+
export function formatWaitResult(result, theme) {
|
|
26
|
+
const agents = result.details?.runningAgents ?? [];
|
|
27
|
+
if (agents.length > 0) {
|
|
28
|
+
const agentList = agents.map((a) => `${a.agentId.slice(0, 12)} ${a.agentType}`).join(", ");
|
|
29
|
+
return theme.fg("muted", `→ doing nothing (waiting on: ${agentList})`);
|
|
30
|
+
}
|
|
31
|
+
return theme.fg("muted", "→ doing nothing — no subagents running");
|
|
32
|
+
}
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Tool definition (singleton — no cwd or callback dependencies)
|
|
35
|
+
export const waitToolDefinition = {
|
|
36
|
+
name: "wait",
|
|
37
|
+
label: "wait",
|
|
38
|
+
description: "Do nothing and end your turn. Use this when you are explicitly told to wait, or when background subagents are running and you have no other work to do.",
|
|
39
|
+
parameters: waitSchema,
|
|
40
|
+
promptSnippet: "Do nothing and end your turn (use when waiting for background work to complete)",
|
|
41
|
+
promptGuidelines: [
|
|
42
|
+
"Use `wait` only when explicitly told to wait, or when background subagents are still running and you have no other work to do",
|
|
43
|
+
"Do NOT use `wait` as a general-purpose delay or sleep — it returns immediately",
|
|
44
|
+
"If you need to wait for something, call `wait` once — do not loop or call it repeatedly",
|
|
45
|
+
],
|
|
46
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
47
|
+
const reason = params.reason?.trim() || undefined;
|
|
48
|
+
const text = reason ? `Waiting: ${reason}` : "Waiting…";
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text }],
|
|
51
|
+
details: { reason, runningAgents: [] },
|
|
52
|
+
endTurn: true,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
renderCall(args, theme, context) {
|
|
56
|
+
const text = context.lastComponent ?? new Text("", 0, 0);
|
|
57
|
+
text.setText(formatWaitCall(args, theme));
|
|
58
|
+
return text;
|
|
59
|
+
},
|
|
60
|
+
renderResult(result, _options, theme, context) {
|
|
61
|
+
const text = context.lastComponent ?? new Text("", 0, 0);
|
|
62
|
+
text.setText(formatWaitResult(result, theme));
|
|
63
|
+
return text;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Factory — accepts optional getRunningAgents callback to show background agent
|
|
68
|
+
// status in the result. The callback is injected here (rather than imported from
|
|
69
|
+
// subagent.ts) to avoid a circular dependency through model-resolver → args → index.
|
|
70
|
+
export function createWaitToolDefinition(options) {
|
|
71
|
+
if (!options?.getRunningAgents)
|
|
72
|
+
return waitToolDefinition;
|
|
73
|
+
return {
|
|
74
|
+
...waitToolDefinition,
|
|
75
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
76
|
+
const reason = params.reason?.trim() || undefined;
|
|
77
|
+
const runningAgents = options.getRunningAgents();
|
|
78
|
+
const text = reason ? `Waiting: ${reason}` : "Waiting…";
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text }],
|
|
81
|
+
details: { reason, runningAgents },
|
|
82
|
+
endTurn: true,
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=wait.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait.js","sourceRoot":"","sources":["../../../src/core/tools/wait.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Wait tool — explicit no-op for models that don't know how to end a turn.\n *\n * Some models (notably Kimi) invent useless `bash` calls to simulate waiting.\n * This tool gives them a sanctioned no-op action that cleanly ends the turn.\n */\n\nimport { Text } from \"@dreb/tui\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\n\n// ============================================================================\n// Types\n\n/** Minimal shape of a running background agent (avoids importing from subagent.ts to prevent circular deps). */\nexport interface WaitAgentInfo {\n\tagentId: string;\n\tagentType: string;\n\ttaskSummary: string;\n}\n\nexport interface WaitToolDetails {\n\treason: string | undefined;\n\trunningAgents: readonly WaitAgentInfo[];\n}\n\nexport interface WaitToolOptions {\n\t/** Returns currently running background agents. Injected by the factory to avoid circular imports. */\n\tgetRunningAgents?: () => readonly WaitAgentInfo[];\n}\n\n// ============================================================================\n// Schema\n\nconst waitSchema = Type.Object({\n\treason: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Optional reason for waiting (e.g. 'background subagent still running')\",\n\t\t}),\n\t),\n});\n\nexport type WaitToolInput = Static<typeof waitSchema>;\n\n// ============================================================================\n// Render helpers\n\nexport function formatWaitCall(args: { reason?: string } | undefined, theme: any): string {\n\tconst reason = args?.reason;\n\tif (reason) {\n\t\treturn `${theme.fg(\"toolTitle\", theme.bold(\"wait\"))} ${theme.fg(\"muted\", reason)}`;\n\t}\n\treturn theme.fg(\"toolTitle\", theme.bold(\"wait\"));\n}\n\nexport function formatWaitResult(\n\tresult: { content: Array<{ type: string; text?: string }>; details?: WaitToolDetails },\n\ttheme: any,\n): string {\n\tconst agents = result.details?.runningAgents ?? [];\n\tif (agents.length > 0) {\n\t\tconst agentList = agents.map((a) => `${a.agentId.slice(0, 12)} ${a.agentType}`).join(\", \");\n\t\treturn theme.fg(\"muted\", `→ doing nothing (waiting on: ${agentList})`);\n\t}\n\treturn theme.fg(\"muted\", \"→ doing nothing — no subagents running\");\n}\n\n// ============================================================================\n// Tool definition (singleton — no cwd or callback dependencies)\n\nexport const waitToolDefinition: ToolDefinition<typeof waitSchema, WaitToolDetails | undefined> = {\n\tname: \"wait\",\n\tlabel: \"wait\",\n\tdescription:\n\t\t\"Do nothing and end your turn. Use this when you are explicitly told to wait, or when background subagents are running and you have no other work to do.\",\n\n\tparameters: waitSchema,\n\n\tpromptSnippet: \"Do nothing and end your turn (use when waiting for background work to complete)\",\n\n\tpromptGuidelines: [\n\t\t\"Use `wait` only when explicitly told to wait, or when background subagents are still running and you have no other work to do\",\n\t\t\"Do NOT use `wait` as a general-purpose delay or sleep — it returns immediately\",\n\t\t\"If you need to wait for something, call `wait` once — do not loop or call it repeatedly\",\n\t],\n\n\tasync execute(_toolCallId, params: WaitToolInput, _signal?, _onUpdate?, _ctx?) {\n\t\tconst reason = params.reason?.trim() || undefined;\n\t\tconst text = reason ? `Waiting: ${reason}` : \"Waiting…\";\n\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\tdetails: { reason, runningAgents: [] as WaitAgentInfo[] },\n\t\t\tendTurn: true,\n\t\t};\n\t},\n\n\trenderCall(args, theme, context) {\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\ttext.setText(formatWaitCall(args, theme));\n\t\treturn text;\n\t},\n\n\trenderResult(result, _options, theme, context) {\n\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\ttext.setText(formatWaitResult(result as any, theme));\n\t\treturn text;\n\t},\n};\n\n// ============================================================================\n// Factory — accepts optional getRunningAgents callback to show background agent\n// status in the result. The callback is injected here (rather than imported from\n// subagent.ts) to avoid a circular dependency through model-resolver → args → index.\n\nexport function createWaitToolDefinition(\n\toptions?: WaitToolOptions,\n): ToolDefinition<typeof waitSchema, WaitToolDetails | undefined> {\n\tif (!options?.getRunningAgents) return waitToolDefinition;\n\n\treturn {\n\t\t...waitToolDefinition,\n\t\tasync execute(_toolCallId, params: WaitToolInput, _signal?, _onUpdate?, _ctx?) {\n\t\t\tconst reason = params.reason?.trim() || undefined;\n\t\t\tconst runningAgents = options.getRunningAgents!();\n\t\t\tconst text = reason ? `Waiting: ${reason}` : \"Waiting…\";\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\t\tdetails: { reason, runningAgents },\n\t\t\t\tendTurn: true,\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
|