@code-yeongyu/senpi 2026.7.16 → 2026.7.17-3
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 +81 -0
- package/dist/core/dynamic-prompt/build.d.ts +7 -0
- package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
- package/dist/core/dynamic-prompt/build.js +5 -0
- package/dist/core/dynamic-prompt/build.js.map +1 -1
- package/dist/core/dynamic-prompt/workstation.d.ts +35 -0
- package/dist/core/dynamic-prompt/workstation.d.ts.map +1 -0
- package/dist/core/dynamic-prompt/workstation.js +81 -0
- package/dist/core/dynamic-prompt/workstation.js.map +1 -0
- package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts +6 -2
- package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/anthropic-web-search/index.js +73 -5
- package/dist/core/extensions/builtin/anthropic-web-search/index.js.map +1 -1
- package/dist/core/extensions/builtin/goal/command-registration.d.ts +1 -0
- package/dist/core/extensions/builtin/goal/command-registration.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/command-registration.js +4 -5
- package/dist/core/extensions/builtin/goal/command-registration.js.map +1 -1
- package/dist/core/extensions/builtin/goal/elapsed-ticker.d.ts +43 -0
- package/dist/core/extensions/builtin/goal/elapsed-ticker.d.ts.map +1 -0
- package/dist/core/extensions/builtin/goal/elapsed-ticker.js +58 -0
- package/dist/core/extensions/builtin/goal/elapsed-ticker.js.map +1 -0
- package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/index.js +39 -14
- package/dist/core/extensions/builtin/goal/index.js.map +1 -1
- package/dist/core/extensions/builtin/goal/tool-registration.d.ts +1 -0
- package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/tool-registration.js +3 -4
- package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
- package/dist/core/extensions/builtin/goal/ui.d.ts +2 -2
- package/dist/core/extensions/builtin/goal/ui.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/ui.js +8 -4
- package/dist/core/extensions/builtin/goal/ui.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/policy.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/policy.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/status.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/status.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tier-b.d.ts +3 -3
- package/dist/core/extensions/builtin/mcp/expose/tier-b.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tier-b.js +10 -10
- package/dist/core/extensions/builtin/mcp/expose/tier-b.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tool-search.d.ts +3 -3
- package/dist/core/extensions/builtin/mcp/expose/tool-search.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tool-search.js +14 -14
- package/dist/core/extensions/builtin/mcp/expose/tool-search.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/index.js +5 -5
- package/dist/core/extensions/builtin/mcp/index.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts +2 -2
- package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.js +2 -2
- package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.2.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.2.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.3-codex.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.3-codex.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.4.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.4.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-6.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-6.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-7.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-7.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts +3 -0
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +14 -0
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.js +13 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
- package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js +2 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts +27 -0
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +60 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js.map +1 -1
- package/dist/core/extensions/types.d.ts +5 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-config.d.ts +5 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +1 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution-renderer.js +1 -0
- package/dist/modes/interactive/components/tool-execution-renderer.js.map +1 -1
- package/docs/AGENTS.md +70 -0
- package/docs/mcp.md +5 -5
- package/docs/settings.md +1 -1
- package/examples/AGENTS.md +3 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +49 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +59 -19
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +68 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +6 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +6 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/README.md +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +58 -7
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +25 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +70 -131
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +26 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js +36 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +0 -21
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +20 -38
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts +0 -110
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js +0 -90
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -0
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.d.ts +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.js +171 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ExtensionContext } from "../../types.ts";
|
|
2
|
+
import type { Goal } from "./types.ts";
|
|
3
|
+
/** Footer live-elapsed refresh cadence while a goal is actively pursued. */
|
|
4
|
+
export declare const GOAL_ELAPSED_TICK_INTERVAL_MS = 1000;
|
|
5
|
+
/** Renders the goal footer segment for the current live elapsed second count. */
|
|
6
|
+
export type GoalElapsedRender = (ctx: ExtensionContext, goal: Goal, liveElapsedSeconds: number) => void;
|
|
7
|
+
export interface GoalElapsedTickerOptions {
|
|
8
|
+
readonly render: GoalElapsedRender;
|
|
9
|
+
/** Injectable clock for tests; defaults to Date.now. */
|
|
10
|
+
readonly now?: () => number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Live elapsed seconds for an actively pursued goal: the committed
|
|
14
|
+
* `timeUsedSeconds` plus whole seconds since the current measurement window
|
|
15
|
+
* opened. Mirrors the rounding in `accountCurrentAgentTurn` so the footer never
|
|
16
|
+
* disagrees with what the next turn commits.
|
|
17
|
+
*/
|
|
18
|
+
export declare function goalLiveElapsedSeconds(goal: Goal, measuredFromMilliseconds: number, nowMilliseconds: number): number;
|
|
19
|
+
/**
|
|
20
|
+
* Drives a once-per-second footer refresh while a goal is active so the
|
|
21
|
+
* "Pursuing goal (…)" elapsed time advances live instead of freezing between
|
|
22
|
+
* usage-accounting checkpoints. The interval is unref'd so it never keeps the
|
|
23
|
+
* process alive.
|
|
24
|
+
*/
|
|
25
|
+
export declare class GoalElapsedTicker {
|
|
26
|
+
private readonly render;
|
|
27
|
+
private readonly now;
|
|
28
|
+
private intervalId;
|
|
29
|
+
private ctx;
|
|
30
|
+
private goal;
|
|
31
|
+
private measuredFromMilliseconds;
|
|
32
|
+
constructor(options: GoalElapsedTickerOptions);
|
|
33
|
+
get running(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Point the ticker at the current goal and measurement window, render once
|
|
36
|
+
* immediately, and start the interval if it is not already running.
|
|
37
|
+
*/
|
|
38
|
+
sync(ctx: ExtensionContext, goal: Goal, measuredFromMilliseconds: number): void;
|
|
39
|
+
/** Stop the interval and drop the retained context/goal snapshot. */
|
|
40
|
+
stop(): void;
|
|
41
|
+
private tick;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=elapsed-ticker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elapsed-ticker.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/elapsed-ticker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,4EAA4E;AAC5E,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD,iFAAiF;AACjF,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,KAAK,IAAI,CAAC;AAExG,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,wDAAwD;IACxD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,wBAAwB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAGpH;AAED;;;;;GAKG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,GAAG,CAA+B;IAC1C,OAAO,CAAC,IAAI,CAAmB;IAC/B,OAAO,CAAC,wBAAwB,CAAK;IAErC,YAAY,OAAO,EAAE,wBAAwB,EAG5C;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;OAGG;IACH,IAAI,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAS9E;IAED,qEAAqE;IACrE,IAAI,IAAI,IAAI,CAOX;IAED,OAAO,CAAC,IAAI;CAIZ"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Footer live-elapsed refresh cadence while a goal is actively pursued. */
|
|
2
|
+
export const GOAL_ELAPSED_TICK_INTERVAL_MS = 1000;
|
|
3
|
+
/**
|
|
4
|
+
* Live elapsed seconds for an actively pursued goal: the committed
|
|
5
|
+
* `timeUsedSeconds` plus whole seconds since the current measurement window
|
|
6
|
+
* opened. Mirrors the rounding in `accountCurrentAgentTurn` so the footer never
|
|
7
|
+
* disagrees with what the next turn commits.
|
|
8
|
+
*/
|
|
9
|
+
export function goalLiveElapsedSeconds(goal, measuredFromMilliseconds, nowMilliseconds) {
|
|
10
|
+
const elapsedSeconds = Math.max(0, Math.round((nowMilliseconds - measuredFromMilliseconds) / 1000));
|
|
11
|
+
return goal.timeUsedSeconds + elapsedSeconds;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Drives a once-per-second footer refresh while a goal is active so the
|
|
15
|
+
* "Pursuing goal (…)" elapsed time advances live instead of freezing between
|
|
16
|
+
* usage-accounting checkpoints. The interval is unref'd so it never keeps the
|
|
17
|
+
* process alive.
|
|
18
|
+
*/
|
|
19
|
+
export class GoalElapsedTicker {
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.measuredFromMilliseconds = 0;
|
|
22
|
+
this.render = options.render;
|
|
23
|
+
this.now = options.now ?? Date.now;
|
|
24
|
+
}
|
|
25
|
+
get running() {
|
|
26
|
+
return this.intervalId !== undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Point the ticker at the current goal and measurement window, render once
|
|
30
|
+
* immediately, and start the interval if it is not already running.
|
|
31
|
+
*/
|
|
32
|
+
sync(ctx, goal, measuredFromMilliseconds) {
|
|
33
|
+
this.ctx = ctx;
|
|
34
|
+
this.goal = goal;
|
|
35
|
+
this.measuredFromMilliseconds = measuredFromMilliseconds;
|
|
36
|
+
this.tick();
|
|
37
|
+
if (this.intervalId !== undefined)
|
|
38
|
+
return;
|
|
39
|
+
const handle = setInterval(() => this.tick(), GOAL_ELAPSED_TICK_INTERVAL_MS);
|
|
40
|
+
handle.unref();
|
|
41
|
+
this.intervalId = handle;
|
|
42
|
+
}
|
|
43
|
+
/** Stop the interval and drop the retained context/goal snapshot. */
|
|
44
|
+
stop() {
|
|
45
|
+
if (this.intervalId !== undefined) {
|
|
46
|
+
clearInterval(this.intervalId);
|
|
47
|
+
this.intervalId = undefined;
|
|
48
|
+
}
|
|
49
|
+
this.ctx = undefined;
|
|
50
|
+
this.goal = undefined;
|
|
51
|
+
}
|
|
52
|
+
tick() {
|
|
53
|
+
if (this.ctx === undefined || this.goal === undefined)
|
|
54
|
+
return;
|
|
55
|
+
this.render(this.ctx, this.goal, goalLiveElapsedSeconds(this.goal, this.measuredFromMilliseconds, this.now()));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=elapsed-ticker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elapsed-ticker.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/elapsed-ticker.ts"],"names":[],"mappings":"AAGA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC;AAWlD;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAU,EAAE,wBAAgC,EAAE,eAAuB;IAC3G,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,eAAe,GAAG,wBAAwB,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACpG,OAAO,IAAI,CAAC,eAAe,GAAG,cAAc,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,iBAAiB;IAQ7B,YAAY,OAAiC;QAFrC,6BAAwB,GAAG,CAAC,CAAC;QAGpC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,GAAqB,EAAE,IAAU,EAAE,wBAAgC;QACvE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,wBAAwB,GAAG,wBAAwB,CAAC;QACzD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;YAAE,OAAO;QAC1C,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,6BAA6B,CAAC,CAAC;QAC7E,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;IAC1B,CAAC;IAED,qEAAqE;IACrE,IAAI;QACH,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACnC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;IACvB,CAAC;IAEO,IAAI;QACX,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO;QAC9D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,sBAAsB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,wBAAwB,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAChH,CAAC;CACD","sourcesContent":["import type { ExtensionContext } from \"../../types.ts\";\nimport type { Goal } from \"./types.ts\";\n\n/** Footer live-elapsed refresh cadence while a goal is actively pursued. */\nexport const GOAL_ELAPSED_TICK_INTERVAL_MS = 1000;\n\n/** Renders the goal footer segment for the current live elapsed second count. */\nexport type GoalElapsedRender = (ctx: ExtensionContext, goal: Goal, liveElapsedSeconds: number) => void;\n\nexport interface GoalElapsedTickerOptions {\n\treadonly render: GoalElapsedRender;\n\t/** Injectable clock for tests; defaults to Date.now. */\n\treadonly now?: () => number;\n}\n\n/**\n * Live elapsed seconds for an actively pursued goal: the committed\n * `timeUsedSeconds` plus whole seconds since the current measurement window\n * opened. Mirrors the rounding in `accountCurrentAgentTurn` so the footer never\n * disagrees with what the next turn commits.\n */\nexport function goalLiveElapsedSeconds(goal: Goal, measuredFromMilliseconds: number, nowMilliseconds: number): number {\n\tconst elapsedSeconds = Math.max(0, Math.round((nowMilliseconds - measuredFromMilliseconds) / 1000));\n\treturn goal.timeUsedSeconds + elapsedSeconds;\n}\n\n/**\n * Drives a once-per-second footer refresh while a goal is active so the\n * \"Pursuing goal (…)\" elapsed time advances live instead of freezing between\n * usage-accounting checkpoints. The interval is unref'd so it never keeps the\n * process alive.\n */\nexport class GoalElapsedTicker {\n\tprivate readonly render: GoalElapsedRender;\n\tprivate readonly now: () => number;\n\tprivate intervalId: NodeJS.Timeout | undefined;\n\tprivate ctx: ExtensionContext | undefined;\n\tprivate goal: Goal | undefined;\n\tprivate measuredFromMilliseconds = 0;\n\n\tconstructor(options: GoalElapsedTickerOptions) {\n\t\tthis.render = options.render;\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\tget running(): boolean {\n\t\treturn this.intervalId !== undefined;\n\t}\n\n\t/**\n\t * Point the ticker at the current goal and measurement window, render once\n\t * immediately, and start the interval if it is not already running.\n\t */\n\tsync(ctx: ExtensionContext, goal: Goal, measuredFromMilliseconds: number): void {\n\t\tthis.ctx = ctx;\n\t\tthis.goal = goal;\n\t\tthis.measuredFromMilliseconds = measuredFromMilliseconds;\n\t\tthis.tick();\n\t\tif (this.intervalId !== undefined) return;\n\t\tconst handle = setInterval(() => this.tick(), GOAL_ELAPSED_TICK_INTERVAL_MS);\n\t\thandle.unref();\n\t\tthis.intervalId = handle;\n\t}\n\n\t/** Stop the interval and drop the retained context/goal snapshot. */\n\tstop(): void {\n\t\tif (this.intervalId !== undefined) {\n\t\t\tclearInterval(this.intervalId);\n\t\t\tthis.intervalId = undefined;\n\t\t}\n\t\tthis.ctx = undefined;\n\t\tthis.goal = undefined;\n\t}\n\n\tprivate tick(): void {\n\t\tif (this.ctx === undefined || this.goal === undefined) return;\n\t\tthis.render(this.ctx, this.goal, goalLiveElapsedSeconds(this.goal, this.measuredFromMilliseconds, this.now()));\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AA2BrE,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAkL5D"}
|
|
@@ -3,6 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
import { getAgentDir } from "../../../../config.js";
|
|
4
4
|
import { registerGoalCommand } from "./command-registration.js";
|
|
5
5
|
import { shouldQueueGoalContinuationAfterAgentEnd, shouldQueueGoalContinuationWhenIdle } from "./continuation.js";
|
|
6
|
+
import { GoalElapsedTicker } from "./elapsed-ticker.js";
|
|
6
7
|
import { formatGoalForTool, goalStatusLabel } from "./format.js";
|
|
7
8
|
import { buildContinuationPrompt } from "./prompt.js";
|
|
8
9
|
import { accountGoalUsage, readGoal, updateGoal } from "./store.js";
|
|
@@ -18,11 +19,24 @@ export default function goalExtension(pi) {
|
|
|
18
19
|
let agentTurnInProgress = false;
|
|
19
20
|
let agentGoalAccounting = null;
|
|
20
21
|
let completedThisTurnGoalId = null;
|
|
22
|
+
const goalTicker = new GoalElapsedTicker({
|
|
23
|
+
render: (renderCtx, renderGoal, live) => {
|
|
24
|
+
try {
|
|
25
|
+
updateGoalUi(renderCtx, renderGoal, live);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error instanceof Error && error.message.startsWith(STALE_EXTENSION_CONTEXT_ERROR_PREFIX))
|
|
29
|
+
return;
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
});
|
|
21
34
|
registerGoalTools(pi, {
|
|
22
35
|
goalStoreRef,
|
|
23
36
|
accountCurrentAgentTurn,
|
|
24
37
|
beginAgentGoalAccounting,
|
|
25
38
|
markGoalCompletedThisTurn,
|
|
39
|
+
refreshGoalUi,
|
|
26
40
|
});
|
|
27
41
|
registerGoalCommand(pi, {
|
|
28
42
|
goalStoreRef,
|
|
@@ -31,6 +45,7 @@ export default function goalExtension(pi) {
|
|
|
31
45
|
stopAgentGoalAccounting,
|
|
32
46
|
clearAgentGoalAccounting,
|
|
33
47
|
queueGoalContinuation,
|
|
48
|
+
refreshGoalUi,
|
|
34
49
|
});
|
|
35
50
|
pi.on("session_start", async (event, ctx) => {
|
|
36
51
|
const goal = await readGoal(goalStoreRef(ctx));
|
|
@@ -40,7 +55,7 @@ export default function goalExtension(pi) {
|
|
|
40
55
|
else {
|
|
41
56
|
clearAgentGoalAccounting();
|
|
42
57
|
}
|
|
43
|
-
|
|
58
|
+
refreshGoalUi(ctx, goal);
|
|
44
59
|
if (await maybePromptResumePausedGoal(pi, ctx, event.reason, goal)) {
|
|
45
60
|
return;
|
|
46
61
|
}
|
|
@@ -70,7 +85,7 @@ export default function goalExtension(pi) {
|
|
|
70
85
|
else {
|
|
71
86
|
clearAgentGoalAccounting();
|
|
72
87
|
}
|
|
73
|
-
|
|
88
|
+
refreshGoalUiBestEffort(ctx, goal);
|
|
74
89
|
if (goal?.status === "active" &&
|
|
75
90
|
!ctx.signal?.aborted &&
|
|
76
91
|
shouldQueueGoalContinuationAfterAgentEnd(goal, ctx.hasPendingMessages(), event.messages)) {
|
|
@@ -82,6 +97,7 @@ export default function goalExtension(pi) {
|
|
|
82
97
|
await accountCurrentAgentTurn(ctx, EMPTY_USAGE, "active");
|
|
83
98
|
}
|
|
84
99
|
clearAgentGoalAccounting();
|
|
100
|
+
goalTicker.stop();
|
|
85
101
|
});
|
|
86
102
|
async function maybePromptResumePausedGoal(pi, ctx, sessionStartReason, goal) {
|
|
87
103
|
if (!isResumeOfPausedGoal(ctx, sessionStartReason, goal)) {
|
|
@@ -95,7 +111,7 @@ export default function goalExtension(pi) {
|
|
|
95
111
|
return true;
|
|
96
112
|
const resumed = await updateGoal(goalStoreRef(ctx), { status: "active" });
|
|
97
113
|
beginAgentGoalAccounting(resumed);
|
|
98
|
-
|
|
114
|
+
refreshGoalUi(ctx, resumed);
|
|
99
115
|
ctx.ui.notify(`Goal ${goalStatusLabel(resumed.status)}\n${formatGoalForTool(resumed)}`, "info");
|
|
100
116
|
queueGoalContinuation(pi, ctx, resumed);
|
|
101
117
|
return true;
|
|
@@ -125,6 +141,26 @@ export default function goalExtension(pi) {
|
|
|
125
141
|
agentGoalAccounting = null;
|
|
126
142
|
completedThisTurnGoalId = null;
|
|
127
143
|
}
|
|
144
|
+
function refreshGoalUi(ctx, goal) {
|
|
145
|
+
const accounting = agentGoalAccounting;
|
|
146
|
+
if (ctx.hasUI && goal?.status === "active" && accounting?.goalId === goal.id) {
|
|
147
|
+
goalTicker.sync(ctx, goal, accounting.measuredFromMilliseconds);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
goalTicker.stop();
|
|
151
|
+
updateGoalUi(ctx, goal);
|
|
152
|
+
}
|
|
153
|
+
function refreshGoalUiBestEffort(ctx, goal) {
|
|
154
|
+
try {
|
|
155
|
+
refreshGoalUi(ctx, goal);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error instanceof Error && error.message.startsWith(STALE_EXTENSION_CONTEXT_ERROR_PREFIX)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
128
164
|
async function accountCurrentAgentTurn(ctx, usage, mode) {
|
|
129
165
|
const accounting = agentGoalAccounting;
|
|
130
166
|
const ref = goalStoreRef(ctx);
|
|
@@ -142,17 +178,6 @@ export default function goalExtension(pi) {
|
|
|
142
178
|
return goal;
|
|
143
179
|
}
|
|
144
180
|
}
|
|
145
|
-
function updateGoalUiBestEffort(ctx, goal) {
|
|
146
|
-
try {
|
|
147
|
-
updateGoalUi(ctx, goal);
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
if (error instanceof Error && error.message.startsWith(STALE_EXTENSION_CONTEXT_ERROR_PREFIX)) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
throw error;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
181
|
function isResumeOfPausedGoal(ctx, sessionStartReason, goal) {
|
|
157
182
|
return (sessionStartReason === "resume" &&
|
|
158
183
|
goal?.status === "paused" &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../../../../config.ts\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { registerGoalCommand } from \"./command-registration.ts\";\nimport { shouldQueueGoalContinuationAfterAgentEnd, shouldQueueGoalContinuationWhenIdle } from \"./continuation.ts\";\nimport { formatGoalForTool, goalStatusLabel } from \"./format.ts\";\nimport { buildContinuationPrompt } from \"./prompt.ts\";\nimport { accountGoalUsage, readGoal, updateGoal } from \"./store.ts\";\nimport { registerGoalTools } from \"./tool-registration.ts\";\nimport type { Goal, GoalAccountingMode, GoalStoreRef, TokenUsageSnapshot } from \"./types.ts\";\nimport { isRecord } from \"./types.ts\";\nimport { updateGoalUi } from \"./ui.ts\";\n\nconst GOAL_CONTINUATION_MESSAGE_TYPE = \"goal-continuation\";\nconst RESUME_GOAL_CHOICE = \"Resume goal\";\nconst LEAVE_GOAL_PAUSED_CHOICE = \"Leave paused\";\nconst EMPTY_USAGE: TokenUsageSnapshot = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 };\nconst STALE_EXTENSION_CONTEXT_ERROR_PREFIX = \"This extension ctx is stale after session replacement or reload.\";\n\ntype AssistantUsageMessage = {\n\trole: \"assistant\";\n\tusage: Record<string, unknown>;\n};\ntype AgentGoalAccounting = {\n\tgoalId: string;\n\tmeasuredFromMilliseconds: number;\n};\n\nexport default function goalExtension(pi: ExtensionAPI): void {\n\tlet agentTurnInProgress = false;\n\tlet agentGoalAccounting: AgentGoalAccounting | null = null;\n\tlet completedThisTurnGoalId: string | null = null;\n\n\tregisterGoalTools(pi, {\n\t\tgoalStoreRef,\n\t\taccountCurrentAgentTurn,\n\t\tbeginAgentGoalAccounting,\n\t\tmarkGoalCompletedThisTurn,\n\t});\n\tregisterGoalCommand(pi, {\n\t\tgoalStoreRef,\n\t\taccountCurrentAgentTurn,\n\t\tbeginAgentGoalAccounting,\n\t\tstopAgentGoalAccounting,\n\t\tclearAgentGoalAccounting,\n\t\tqueueGoalContinuation,\n\t});\n\n\tpi.on(\"session_start\", async (event, ctx) => {\n\t\tconst goal = await readGoal(goalStoreRef(ctx));\n\t\tif (goal?.status === \"active\") {\n\t\t\tbeginAgentGoalAccounting(goal);\n\t\t} else {\n\t\t\tclearAgentGoalAccounting();\n\t\t}\n\t\tupdateGoalUi(ctx, goal);\n\t\tif (await maybePromptResumePausedGoal(pi, ctx, event.reason, goal)) {\n\t\t\treturn;\n\t\t}\n\t\tif (shouldQueueGoalContinuationWhenIdle(goal, ctx.isIdle(), ctx.hasPendingMessages())) {\n\t\t\tqueueHiddenGoalPrompt(pi, buildContinuationPrompt(goal));\n\t\t}\n\t});\n\n\tpi.on(\"agent_start\", async (_event, ctx) => {\n\t\tagentTurnInProgress = true;\n\t\tcompletedThisTurnGoalId = null;\n\t\tconst goal = await readGoal(goalStoreRef(ctx));\n\t\tif (goal?.status === \"active\") {\n\t\t\tbeginAgentGoalAccounting(goal);\n\t\t} else {\n\t\t\tagentGoalAccounting = null;\n\t\t}\n\t});\n\n\tpi.on(\"agent_end\", async (event, ctx) => {\n\t\tconst mode: GoalAccountingMode = completedThisTurnGoalId === null ? \"active\" : \"activeOrComplete\";\n\t\tconst goal = await accountCurrentAgentTurn(ctx, collectAssistantUsage(event.messages), mode);\n\t\tagentTurnInProgress = false;\n\t\tcompletedThisTurnGoalId = null;\n\t\tif (goal?.status === \"active\") {\n\t\t\tbeginAgentGoalAccounting(goal);\n\t\t} else {\n\t\t\tclearAgentGoalAccounting();\n\t\t}\n\t\tupdateGoalUiBestEffort(ctx, goal);\n\t\tif (\n\t\t\tgoal?.status === \"active\" &&\n\t\t\t!ctx.signal?.aborted &&\n\t\t\tshouldQueueGoalContinuationAfterAgentEnd(goal, ctx.hasPendingMessages(), event.messages)\n\t\t) {\n\t\t\tqueueHiddenGoalPrompt(pi, buildContinuationPrompt(goal));\n\t\t}\n\t});\n\n\tpi.on(\"session_shutdown\", async (_event, ctx) => {\n\t\tif (agentGoalAccounting !== null) {\n\t\t\tawait accountCurrentAgentTurn(ctx, EMPTY_USAGE, \"active\");\n\t\t}\n\t\tclearAgentGoalAccounting();\n\t});\n\n\tasync function maybePromptResumePausedGoal(\n\t\tpi: ExtensionAPI,\n\t\tctx: ExtensionContext,\n\t\tsessionStartReason: string,\n\t\tgoal: Goal | null,\n\t): Promise<boolean> {\n\t\tif (!isResumeOfPausedGoal(ctx, sessionStartReason, goal)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst choice = await ctx.ui.select(`Resume paused goal?\\nGoal: ${goal.objective}`, [\n\t\t\tRESUME_GOAL_CHOICE,\n\t\t\tLEAVE_GOAL_PAUSED_CHOICE,\n\t\t]);\n\t\tif (choice !== RESUME_GOAL_CHOICE) return true;\n\n\t\tconst resumed = await updateGoal(goalStoreRef(ctx), { status: \"active\" });\n\t\tbeginAgentGoalAccounting(resumed);\n\t\tupdateGoalUi(ctx, resumed);\n\t\tctx.ui.notify(`Goal ${goalStatusLabel(resumed.status)}\\n${formatGoalForTool(resumed)}`, \"info\");\n\t\tqueueGoalContinuation(pi, ctx, resumed);\n\t\treturn true;\n\t}\n\n\tfunction beginAgentGoalAccounting(goal: Goal): void {\n\t\tif (goal.status !== \"active\") return;\n\t\tif (agentGoalAccounting?.goalId === goal.id) return;\n\t\tagentGoalAccounting = { goalId: goal.id, measuredFromMilliseconds: Date.now() };\n\t}\n\n\tfunction markGoalCompletedThisTurn(goal: Goal): void {\n\t\tif (!agentTurnInProgress) return;\n\t\tcompletedThisTurnGoalId = goal.id;\n\t\tagentGoalAccounting = { goalId: goal.id, measuredFromMilliseconds: Date.now() };\n\t}\n\n\tfunction stopAgentGoalAccounting(goalId: string): void {\n\t\tif (agentGoalAccounting?.goalId === goalId) {\n\t\t\tagentGoalAccounting = null;\n\t\t}\n\t\tif (completedThisTurnGoalId === goalId) {\n\t\t\tcompletedThisTurnGoalId = null;\n\t\t}\n\t}\n\n\tfunction clearAgentGoalAccounting(): void {\n\t\tagentGoalAccounting = null;\n\t\tcompletedThisTurnGoalId = null;\n\t}\n\n\tasync function accountCurrentAgentTurn(\n\t\tctx: ExtensionContext,\n\t\tusage: TokenUsageSnapshot,\n\t\tmode: GoalAccountingMode,\n\t): Promise<Goal | null> {\n\t\tconst accounting = agentGoalAccounting;\n\t\tconst ref = goalStoreRef(ctx);\n\t\tif (accounting === null) return readGoal(ref);\n\n\t\tconst now = Date.now();\n\t\tconst elapsedSeconds = Math.max(0, Math.round((now - accounting.measuredFromMilliseconds) / 1000));\n\t\tconst goal = await accountGoalUsage(ref, usage, elapsedSeconds, mode, accounting.goalId);\n\t\tif (goal?.id === accounting.goalId) {\n\t\t\tagentGoalAccounting = { goalId: accounting.goalId, measuredFromMilliseconds: now };\n\t\t} else {\n\t\t\tclearAgentGoalAccounting();\n\t\t}\n\t\treturn goal;\n\t}\n}\n\nfunction updateGoalUiBestEffort(ctx: ExtensionContext, goal: Goal | null): void {\n\ttry {\n\t\tupdateGoalUi(ctx, goal);\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.startsWith(STALE_EXTENSION_CONTEXT_ERROR_PREFIX)) {\n\t\t\treturn;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction isResumeOfPausedGoal(ctx: ExtensionContext, sessionStartReason: string, goal: Goal | null): goal is Goal {\n\treturn (\n\t\tsessionStartReason === \"resume\" &&\n\t\tgoal?.status === \"paused\" &&\n\t\tctx.hasUI &&\n\t\tctx.isIdle() &&\n\t\t!ctx.hasPendingMessages()\n\t);\n}\n\nfunction queueGoalContinuation(pi: ExtensionAPI, ctx: ExtensionContext, goal: Goal): void {\n\tif (shouldQueueGoalContinuationWhenIdle(goal, ctx.isIdle(), ctx.hasPendingMessages())) {\n\t\tqueueHiddenGoalPrompt(pi, buildContinuationPrompt(goal));\n\t}\n}\n\nfunction queueHiddenGoalPrompt(pi: ExtensionAPI, content: string): void {\n\tpi.sendMessage(\n\t\t{ customType: GOAL_CONTINUATION_MESSAGE_TYPE, content, display: false },\n\t\t{ triggerTurn: true, deliverAs: \"followUp\" },\n\t);\n}\n\nfunction goalStoreRef(ctx: ExtensionContext): GoalStoreRef {\n\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\tconst baseDir =\n\t\tsessionFile === undefined\n\t\t\t? join(getAgentDir(), \"extensions\", \"goal\", \"no-session\", cwdStoreKey(ctx.cwd))\n\t\t\t: join(ctx.sessionManager.getSessionDir(), \"extensions\", \"goal\");\n\n\treturn {\n\t\tbaseDir,\n\t\tthreadId: ctx.sessionManager.getSessionId(),\n\t};\n}\n\nfunction cwdStoreKey(cwd: string): string {\n\treturn createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 24);\n}\n\nfunction collectAssistantUsage(messages: unknown[]): TokenUsageSnapshot {\n\tconst usage: TokenUsageSnapshot = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 };\n\tfor (const message of messages) {\n\t\tif (!isAssistantUsageMessage(message)) continue;\n\t\tusage.input += numericUsageField(message.usage, \"input\");\n\t\tusage.output += numericUsageField(message.usage, \"output\");\n\t\tusage.cacheRead += numericUsageField(message.usage, \"cacheRead\");\n\t\tusage.cacheWrite += numericUsageField(message.usage, \"cacheWrite\");\n\t\tusage.totalTokens += numericUsageField(message.usage, \"totalTokens\");\n\t}\n\treturn usage;\n}\n\nfunction isAssistantUsageMessage(message: unknown): message is AssistantUsageMessage {\n\tif (!isRecord(message)) return false;\n\treturn message.role === \"assistant\" && isRecord(message.usage);\n}\n\nfunction numericUsageField(usage: Record<string, unknown>, key: string): number {\n\tconst value = usage[key];\n\treturn typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport { getAgentDir } from \"../../../../config.ts\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { registerGoalCommand } from \"./command-registration.ts\";\nimport { shouldQueueGoalContinuationAfterAgentEnd, shouldQueueGoalContinuationWhenIdle } from \"./continuation.ts\";\nimport { GoalElapsedTicker } from \"./elapsed-ticker.ts\";\nimport { formatGoalForTool, goalStatusLabel } from \"./format.ts\";\nimport { buildContinuationPrompt } from \"./prompt.ts\";\nimport { accountGoalUsage, readGoal, updateGoal } from \"./store.ts\";\nimport { registerGoalTools } from \"./tool-registration.ts\";\nimport type { Goal, GoalAccountingMode, GoalStoreRef, TokenUsageSnapshot } from \"./types.ts\";\nimport { isRecord } from \"./types.ts\";\nimport { updateGoalUi } from \"./ui.ts\";\n\nconst GOAL_CONTINUATION_MESSAGE_TYPE = \"goal-continuation\";\nconst RESUME_GOAL_CHOICE = \"Resume goal\";\nconst LEAVE_GOAL_PAUSED_CHOICE = \"Leave paused\";\nconst EMPTY_USAGE: TokenUsageSnapshot = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 };\nconst STALE_EXTENSION_CONTEXT_ERROR_PREFIX = \"This extension ctx is stale after session replacement or reload.\";\n\ntype AssistantUsageMessage = {\n\trole: \"assistant\";\n\tusage: Record<string, unknown>;\n};\ntype AgentGoalAccounting = {\n\tgoalId: string;\n\tmeasuredFromMilliseconds: number;\n};\n\nexport default function goalExtension(pi: ExtensionAPI): void {\n\tlet agentTurnInProgress = false;\n\tlet agentGoalAccounting: AgentGoalAccounting | null = null;\n\tlet completedThisTurnGoalId: string | null = null;\n\n\tconst goalTicker = new GoalElapsedTicker({\n\t\trender: (renderCtx, renderGoal, live) => {\n\t\t\ttry {\n\t\t\t\tupdateGoalUi(renderCtx, renderGoal, live);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && error.message.startsWith(STALE_EXTENSION_CONTEXT_ERROR_PREFIX)) return;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t});\n\n\tregisterGoalTools(pi, {\n\t\tgoalStoreRef,\n\t\taccountCurrentAgentTurn,\n\t\tbeginAgentGoalAccounting,\n\t\tmarkGoalCompletedThisTurn,\n\t\trefreshGoalUi,\n\t});\n\tregisterGoalCommand(pi, {\n\t\tgoalStoreRef,\n\t\taccountCurrentAgentTurn,\n\t\tbeginAgentGoalAccounting,\n\t\tstopAgentGoalAccounting,\n\t\tclearAgentGoalAccounting,\n\t\tqueueGoalContinuation,\n\t\trefreshGoalUi,\n\t});\n\n\tpi.on(\"session_start\", async (event, ctx) => {\n\t\tconst goal = await readGoal(goalStoreRef(ctx));\n\t\tif (goal?.status === \"active\") {\n\t\t\tbeginAgentGoalAccounting(goal);\n\t\t} else {\n\t\t\tclearAgentGoalAccounting();\n\t\t}\n\t\trefreshGoalUi(ctx, goal);\n\t\tif (await maybePromptResumePausedGoal(pi, ctx, event.reason, goal)) {\n\t\t\treturn;\n\t\t}\n\t\tif (shouldQueueGoalContinuationWhenIdle(goal, ctx.isIdle(), ctx.hasPendingMessages())) {\n\t\t\tqueueHiddenGoalPrompt(pi, buildContinuationPrompt(goal));\n\t\t}\n\t});\n\n\tpi.on(\"agent_start\", async (_event, ctx) => {\n\t\tagentTurnInProgress = true;\n\t\tcompletedThisTurnGoalId = null;\n\t\tconst goal = await readGoal(goalStoreRef(ctx));\n\t\tif (goal?.status === \"active\") {\n\t\t\tbeginAgentGoalAccounting(goal);\n\t\t} else {\n\t\t\tagentGoalAccounting = null;\n\t\t}\n\t});\n\n\tpi.on(\"agent_end\", async (event, ctx) => {\n\t\tconst mode: GoalAccountingMode = completedThisTurnGoalId === null ? \"active\" : \"activeOrComplete\";\n\t\tconst goal = await accountCurrentAgentTurn(ctx, collectAssistantUsage(event.messages), mode);\n\t\tagentTurnInProgress = false;\n\t\tcompletedThisTurnGoalId = null;\n\t\tif (goal?.status === \"active\") {\n\t\t\tbeginAgentGoalAccounting(goal);\n\t\t} else {\n\t\t\tclearAgentGoalAccounting();\n\t\t}\n\t\trefreshGoalUiBestEffort(ctx, goal);\n\t\tif (\n\t\t\tgoal?.status === \"active\" &&\n\t\t\t!ctx.signal?.aborted &&\n\t\t\tshouldQueueGoalContinuationAfterAgentEnd(goal, ctx.hasPendingMessages(), event.messages)\n\t\t) {\n\t\t\tqueueHiddenGoalPrompt(pi, buildContinuationPrompt(goal));\n\t\t}\n\t});\n\n\tpi.on(\"session_shutdown\", async (_event, ctx) => {\n\t\tif (agentGoalAccounting !== null) {\n\t\t\tawait accountCurrentAgentTurn(ctx, EMPTY_USAGE, \"active\");\n\t\t}\n\t\tclearAgentGoalAccounting();\n\t\tgoalTicker.stop();\n\t});\n\n\tasync function maybePromptResumePausedGoal(\n\t\tpi: ExtensionAPI,\n\t\tctx: ExtensionContext,\n\t\tsessionStartReason: string,\n\t\tgoal: Goal | null,\n\t): Promise<boolean> {\n\t\tif (!isResumeOfPausedGoal(ctx, sessionStartReason, goal)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst choice = await ctx.ui.select(`Resume paused goal?\\nGoal: ${goal.objective}`, [\n\t\t\tRESUME_GOAL_CHOICE,\n\t\t\tLEAVE_GOAL_PAUSED_CHOICE,\n\t\t]);\n\t\tif (choice !== RESUME_GOAL_CHOICE) return true;\n\n\t\tconst resumed = await updateGoal(goalStoreRef(ctx), { status: \"active\" });\n\t\tbeginAgentGoalAccounting(resumed);\n\t\trefreshGoalUi(ctx, resumed);\n\t\tctx.ui.notify(`Goal ${goalStatusLabel(resumed.status)}\\n${formatGoalForTool(resumed)}`, \"info\");\n\t\tqueueGoalContinuation(pi, ctx, resumed);\n\t\treturn true;\n\t}\n\n\tfunction beginAgentGoalAccounting(goal: Goal): void {\n\t\tif (goal.status !== \"active\") return;\n\t\tif (agentGoalAccounting?.goalId === goal.id) return;\n\t\tagentGoalAccounting = { goalId: goal.id, measuredFromMilliseconds: Date.now() };\n\t}\n\n\tfunction markGoalCompletedThisTurn(goal: Goal): void {\n\t\tif (!agentTurnInProgress) return;\n\t\tcompletedThisTurnGoalId = goal.id;\n\t\tagentGoalAccounting = { goalId: goal.id, measuredFromMilliseconds: Date.now() };\n\t}\n\n\tfunction stopAgentGoalAccounting(goalId: string): void {\n\t\tif (agentGoalAccounting?.goalId === goalId) {\n\t\t\tagentGoalAccounting = null;\n\t\t}\n\t\tif (completedThisTurnGoalId === goalId) {\n\t\t\tcompletedThisTurnGoalId = null;\n\t\t}\n\t}\n\n\tfunction clearAgentGoalAccounting(): void {\n\t\tagentGoalAccounting = null;\n\t\tcompletedThisTurnGoalId = null;\n\t}\n\n\tfunction refreshGoalUi(ctx: ExtensionContext, goal: Goal | null): void {\n\t\tconst accounting = agentGoalAccounting;\n\t\tif (ctx.hasUI && goal?.status === \"active\" && accounting?.goalId === goal.id) {\n\t\t\tgoalTicker.sync(ctx, goal, accounting.measuredFromMilliseconds);\n\t\t\treturn;\n\t\t}\n\t\tgoalTicker.stop();\n\t\tupdateGoalUi(ctx, goal);\n\t}\n\n\tfunction refreshGoalUiBestEffort(ctx: ExtensionContext, goal: Goal | null): void {\n\t\ttry {\n\t\t\trefreshGoalUi(ctx, goal);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(STALE_EXTENSION_CONTEXT_ERROR_PREFIX)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync function accountCurrentAgentTurn(\n\t\tctx: ExtensionContext,\n\t\tusage: TokenUsageSnapshot,\n\t\tmode: GoalAccountingMode,\n\t): Promise<Goal | null> {\n\t\tconst accounting = agentGoalAccounting;\n\t\tconst ref = goalStoreRef(ctx);\n\t\tif (accounting === null) return readGoal(ref);\n\n\t\tconst now = Date.now();\n\t\tconst elapsedSeconds = Math.max(0, Math.round((now - accounting.measuredFromMilliseconds) / 1000));\n\t\tconst goal = await accountGoalUsage(ref, usage, elapsedSeconds, mode, accounting.goalId);\n\t\tif (goal?.id === accounting.goalId) {\n\t\t\tagentGoalAccounting = { goalId: accounting.goalId, measuredFromMilliseconds: now };\n\t\t} else {\n\t\t\tclearAgentGoalAccounting();\n\t\t}\n\t\treturn goal;\n\t}\n}\n\nfunction isResumeOfPausedGoal(ctx: ExtensionContext, sessionStartReason: string, goal: Goal | null): goal is Goal {\n\treturn (\n\t\tsessionStartReason === \"resume\" &&\n\t\tgoal?.status === \"paused\" &&\n\t\tctx.hasUI &&\n\t\tctx.isIdle() &&\n\t\t!ctx.hasPendingMessages()\n\t);\n}\n\nfunction queueGoalContinuation(pi: ExtensionAPI, ctx: ExtensionContext, goal: Goal): void {\n\tif (shouldQueueGoalContinuationWhenIdle(goal, ctx.isIdle(), ctx.hasPendingMessages())) {\n\t\tqueueHiddenGoalPrompt(pi, buildContinuationPrompt(goal));\n\t}\n}\n\nfunction queueHiddenGoalPrompt(pi: ExtensionAPI, content: string): void {\n\tpi.sendMessage(\n\t\t{ customType: GOAL_CONTINUATION_MESSAGE_TYPE, content, display: false },\n\t\t{ triggerTurn: true, deliverAs: \"followUp\" },\n\t);\n}\n\nfunction goalStoreRef(ctx: ExtensionContext): GoalStoreRef {\n\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\tconst baseDir =\n\t\tsessionFile === undefined\n\t\t\t? join(getAgentDir(), \"extensions\", \"goal\", \"no-session\", cwdStoreKey(ctx.cwd))\n\t\t\t: join(ctx.sessionManager.getSessionDir(), \"extensions\", \"goal\");\n\n\treturn {\n\t\tbaseDir,\n\t\tthreadId: ctx.sessionManager.getSessionId(),\n\t};\n}\n\nfunction cwdStoreKey(cwd: string): string {\n\treturn createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 24);\n}\n\nfunction collectAssistantUsage(messages: unknown[]): TokenUsageSnapshot {\n\tconst usage: TokenUsageSnapshot = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 };\n\tfor (const message of messages) {\n\t\tif (!isAssistantUsageMessage(message)) continue;\n\t\tusage.input += numericUsageField(message.usage, \"input\");\n\t\tusage.output += numericUsageField(message.usage, \"output\");\n\t\tusage.cacheRead += numericUsageField(message.usage, \"cacheRead\");\n\t\tusage.cacheWrite += numericUsageField(message.usage, \"cacheWrite\");\n\t\tusage.totalTokens += numericUsageField(message.usage, \"totalTokens\");\n\t}\n\treturn usage;\n}\n\nfunction isAssistantUsageMessage(message: unknown): message is AssistantUsageMessage {\n\tif (!isRecord(message)) return false;\n\treturn message.role === \"assistant\" && isRecord(message.usage);\n}\n\nfunction numericUsageField(usage: Record<string, unknown>, key: string): number {\n\tconst value = usage[key];\n\treturn typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n"]}
|
|
@@ -5,6 +5,7 @@ export type GoalToolRegistrationDeps = {
|
|
|
5
5
|
readonly accountCurrentAgentTurn: (ctx: ExtensionContext, usage: TokenUsageSnapshot, mode: GoalAccountingMode) => Promise<Goal | null>;
|
|
6
6
|
readonly beginAgentGoalAccounting: (goal: Goal) => void;
|
|
7
7
|
readonly markGoalCompletedThisTurn: (goal: Goal) => void;
|
|
8
|
+
readonly refreshGoalUi: (ctx: ExtensionContext, goal: Goal | null) => void;
|
|
8
9
|
};
|
|
9
10
|
export declare function registerGoalTools(pi: ExtensionAPI, deps: GoalToolRegistrationDeps): void;
|
|
10
11
|
//# sourceMappingURL=tool-registration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-registration.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/tool-registration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGtF,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-registration.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/tool-registration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGtF,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAO7F,MAAM,MAAM,wBAAwB,GAAG;IACtC,QAAQ,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,YAAY,CAAC;IAC/D,QAAQ,CAAC,uBAAuB,EAAE,CACjC,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,kBAAkB,EACzB,IAAI,EAAE,kBAAkB,KACpB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAC1B,QAAQ,CAAC,wBAAwB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACxD,QAAQ,CAAC,yBAAyB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACzD,QAAQ,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3E,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,wBAAwB,GAAG,IAAI,CAuExF"}
|
|
@@ -2,7 +2,6 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { formatGoalToolResponse } from "./format.js";
|
|
3
3
|
import { createGoal, readGoal, updateGoal } from "./store.js";
|
|
4
4
|
import { COMPLETABLE_GOAL_STATUS_VALUES } from "./types.js";
|
|
5
|
-
import { updateGoalUi } from "./ui.js";
|
|
6
5
|
const EMPTY_USAGE = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 };
|
|
7
6
|
export function registerGoalTools(pi, deps) {
|
|
8
7
|
pi.registerTool({
|
|
@@ -21,7 +20,7 @@ export function registerGoalTools(pi, deps) {
|
|
|
21
20
|
}
|
|
22
21
|
const goal = await createGoal(ref, params.objective);
|
|
23
22
|
deps.beginAgentGoalAccounting(goal);
|
|
24
|
-
|
|
23
|
+
deps.refreshGoalUi(ctx, goal);
|
|
25
24
|
return toolText(formatGoalToolResponse(goal));
|
|
26
25
|
},
|
|
27
26
|
});
|
|
@@ -41,7 +40,7 @@ export function registerGoalTools(pi, deps) {
|
|
|
41
40
|
await deps.accountCurrentAgentTurn(ctx, EMPTY_USAGE, "active");
|
|
42
41
|
const goal = await updateGoal(deps.goalStoreRef(ctx), { status: "complete" });
|
|
43
42
|
deps.markGoalCompletedThisTurn(goal);
|
|
44
|
-
|
|
43
|
+
deps.refreshGoalUi(ctx, goal);
|
|
45
44
|
return toolText(formatGoalToolResponse(goal));
|
|
46
45
|
},
|
|
47
46
|
});
|
|
@@ -52,7 +51,7 @@ export function registerGoalTools(pi, deps) {
|
|
|
52
51
|
parameters: Type.Object({}, { additionalProperties: false }),
|
|
53
52
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
54
53
|
const goal = await readGoal(deps.goalStoreRef(ctx));
|
|
55
|
-
|
|
54
|
+
deps.refreshGoalUi(ctx, goal);
|
|
56
55
|
return toolText(formatGoalToolResponse(goal));
|
|
57
56
|
},
|
|
58
57
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-registration.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/tool-registration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE9D,OAAO,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-registration.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/tool-registration.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type } from \"typebox\";\nimport type { AgentToolResult, ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { formatGoalToolResponse } from \"./format.ts\";\nimport { createGoal, readGoal, updateGoal } from \"./store.ts\";\nimport type { Goal, GoalAccountingMode, GoalStoreRef, TokenUsageSnapshot } from \"./types.ts\";\nimport { COMPLETABLE_GOAL_STATUS_VALUES } from \"./types.ts\";\n\nconst EMPTY_USAGE: TokenUsageSnapshot = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 };\n\ntype GoalToolResult = AgentToolResult<Record<string, never>>;\n\nexport type GoalToolRegistrationDeps = {\n\treadonly goalStoreRef: (ctx: ExtensionContext) => GoalStoreRef;\n\treadonly accountCurrentAgentTurn: (\n\t\tctx: ExtensionContext,\n\t\tusage: TokenUsageSnapshot,\n\t\tmode: GoalAccountingMode,\n\t) => Promise<Goal | null>;\n\treadonly beginAgentGoalAccounting: (goal: Goal) => void;\n\treadonly markGoalCompletedThisTurn: (goal: Goal) => void;\n\treadonly refreshGoalUi: (ctx: ExtensionContext, goal: Goal | null) => void;\n};\n\nexport function registerGoalTools(pi: ExtensionAPI, deps: GoalToolRegistrationDeps): void {\n\tpi.registerTool({\n\t\tname: \"create_goal\",\n\t\tlabel: \"Create Goal\",\n\t\tdescription:\n\t\t\t\"Create a goal only when explicitly requested by the user or system/developer instructions; do not infer goals from ordinary tasks.\\nFails if a goal already exists; use update_goal only for status.\",\n\t\tparameters: Type.Object(\n\t\t\t{\n\t\t\t\tobjective: Type.String({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Required. The concrete objective to start pursuing. This starts a new active goal only when no goal is currently defined; if a goal already exists, this tool fails.\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{ additionalProperties: false },\n\t\t),\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n\t\t\tconst ref = deps.goalStoreRef(ctx);\n\t\t\tif ((await readGoal(ref)) !== null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"cannot create a new goal because this thread already has a goal; use update_goal only when the existing goal is complete\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst goal = await createGoal(ref, params.objective);\n\t\t\tdeps.beginAgentGoalAccounting(goal);\n\t\t\tdeps.refreshGoalUi(ctx, goal);\n\t\t\treturn toolText(formatGoalToolResponse(goal));\n\t\t},\n\t});\n\n\tpi.registerTool({\n\t\tname: \"update_goal\",\n\t\tlabel: \"Update Goal\",\n\t\tdescription:\n\t\t\t\"Update the existing goal.\\nUse this tool only to mark the goal achieved.\\nSet status to `complete` only when the objective has actually been achieved and no required work remains.\\nDo not mark a goal complete merely because you are stopping work.\\nYou cannot use this tool to pause or resume a goal; those status changes are controlled by the user or system.\\nWhen marking the goal achieved with status `complete`, report the final elapsed time and token usage from the tool result to the user.\",\n\t\tparameters: Type.Object(\n\t\t\t{\n\t\t\t\tstatus: Type.Union(\n\t\t\t\t\tCOMPLETABLE_GOAL_STATUS_VALUES.map((status) => Type.Literal(status)),\n\t\t\t\t\t{\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Required. Set to complete only when the objective is achieved and no required work remains.\",\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t},\n\t\t\t{ additionalProperties: false },\n\t\t),\n\t\tasync execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n\t\t\tif (params.status !== \"complete\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"update_goal can only mark the existing goal complete; pause and resume are controlled by the user or system\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait deps.accountCurrentAgentTurn(ctx, EMPTY_USAGE, \"active\");\n\t\t\tconst goal = await updateGoal(deps.goalStoreRef(ctx), { status: \"complete\" });\n\t\t\tdeps.markGoalCompletedThisTurn(goal);\n\t\t\tdeps.refreshGoalUi(ctx, goal);\n\t\t\treturn toolText(formatGoalToolResponse(goal));\n\t\t},\n\t});\n\n\tpi.registerTool({\n\t\tname: \"get_goal\",\n\t\tlabel: \"Get Goal\",\n\t\tdescription: \"Get the current goal for this thread, including status, token and elapsed-time usage.\",\n\t\tparameters: Type.Object({}, { additionalProperties: false }),\n\t\tasync execute(_toolCallId, _params, _signal, _onUpdate, ctx) {\n\t\t\tconst goal = await readGoal(deps.goalStoreRef(ctx));\n\t\t\tdeps.refreshGoalUi(ctx, goal);\n\t\t\treturn toolText(formatGoalToolResponse(goal));\n\t\t},\n\t});\n}\n\nfunction toolText(text: string): GoalToolResult {\n\treturn { content: [{ type: \"text\" as const, text }], details: {} };\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExtensionContext } from "../../types.ts";
|
|
2
2
|
import type { Goal } from "./types.ts";
|
|
3
3
|
export declare const STATUS_KEY = "goal";
|
|
4
|
-
export declare function updateGoalUi(ctx: ExtensionContext, goal: Goal | null): void;
|
|
5
|
-
export declare function goalStatusText(goal: Goal): string;
|
|
4
|
+
export declare function updateGoalUi(ctx: ExtensionContext, goal: Goal | null, liveElapsedSeconds?: number): void;
|
|
5
|
+
export declare function goalStatusText(goal: Goal, liveElapsedSeconds?: number): string;
|
|
6
6
|
//# sourceMappingURL=ui.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAO,MAAM,UAAU,SAAS,CAAC;AAEjC,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAGxG;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,CAe9E"}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { formatGoalElapsedSeconds } from "./format.js";
|
|
2
2
|
export const STATUS_KEY = "goal";
|
|
3
|
-
export function updateGoalUi(ctx, goal) {
|
|
3
|
+
export function updateGoalUi(ctx, goal, liveElapsedSeconds) {
|
|
4
4
|
if (!ctx.hasUI)
|
|
5
5
|
return;
|
|
6
|
-
ctx.ui.setStatus(STATUS_KEY, goal === null ? undefined : goalStatusText(goal));
|
|
6
|
+
ctx.ui.setStatus(STATUS_KEY, goal === null ? undefined : goalStatusText(goal, liveElapsedSeconds));
|
|
7
7
|
}
|
|
8
|
-
export function goalStatusText(goal) {
|
|
8
|
+
export function goalStatusText(goal, liveElapsedSeconds) {
|
|
9
9
|
switch (goal.status) {
|
|
10
|
-
case "active":
|
|
10
|
+
case "active": {
|
|
11
|
+
if (liveElapsedSeconds !== undefined) {
|
|
12
|
+
return `Pursuing goal (${formatGoalElapsedSeconds(liveElapsedSeconds)})`;
|
|
13
|
+
}
|
|
11
14
|
return goal.timeUsedSeconds > 0
|
|
12
15
|
? `Pursuing goal (${formatGoalElapsedSeconds(goal.timeUsedSeconds)})`
|
|
13
16
|
: "Pursuing goal";
|
|
17
|
+
}
|
|
14
18
|
case "paused":
|
|
15
19
|
return "Goal paused (/goal resume)";
|
|
16
20
|
case "complete":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/ui.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAGvD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AAEjC,MAAM,UAAU,YAAY,CAAC,GAAqB,EAAE,IAAiB;
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/ui.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAGvD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AAEjC,MAAM,UAAU,YAAY,CAAC,GAAqB,EAAE,IAAiB,EAAE,kBAA2B;IACjG,IAAI,CAAC,GAAG,CAAC,KAAK;QAAE,OAAO;IACvB,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAU,EAAE,kBAA2B;IACrE,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,QAAQ,EAAE,CAAC;YACf,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;gBACtC,OAAO,kBAAkB,wBAAwB,CAAC,kBAAkB,CAAC,GAAG,CAAC;YAC1E,CAAC;YACD,OAAO,IAAI,CAAC,eAAe,GAAG,CAAC;gBAC9B,CAAC,CAAC,kBAAkB,wBAAwB,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG;gBACrE,CAAC,CAAC,eAAe,CAAC;QACpB,CAAC;QACD,KAAK,QAAQ;YACZ,OAAO,4BAA4B,CAAC;QACrC,KAAK,UAAU;YACd,OAAO,eAAe,CAAC;IACzB,CAAC;AACF,CAAC","sourcesContent":["import type { ExtensionContext } from \"../../types.ts\";\nimport { formatGoalElapsedSeconds } from \"./format.ts\";\nimport type { Goal } from \"./types.ts\";\n\nexport const STATUS_KEY = \"goal\";\n\nexport function updateGoalUi(ctx: ExtensionContext, goal: Goal | null, liveElapsedSeconds?: number): void {\n\tif (!ctx.hasUI) return;\n\tctx.ui.setStatus(STATUS_KEY, goal === null ? undefined : goalStatusText(goal, liveElapsedSeconds));\n}\n\nexport function goalStatusText(goal: Goal, liveElapsedSeconds?: number): string {\n\tswitch (goal.status) {\n\t\tcase \"active\": {\n\t\t\tif (liveElapsedSeconds !== undefined) {\n\t\t\t\treturn `Pursuing goal (${formatGoalElapsedSeconds(liveElapsedSeconds)})`;\n\t\t\t}\n\t\t\treturn goal.timeUsedSeconds > 0\n\t\t\t\t? `Pursuing goal (${formatGoalElapsedSeconds(goal.timeUsedSeconds)})`\n\t\t\t\t: \"Pursuing goal\";\n\t\t}\n\t\tcase \"paused\":\n\t\t\treturn \"Goal paused (/goal resume)\";\n\t\tcase \"complete\":\n\t\t\treturn \"Goal achieved\";\n\t}\n}\n"]}
|
|
@@ -3,7 +3,7 @@ export declare const ANTHROPIC_TOOL_SEARCH_NAME = "tool_search";
|
|
|
3
3
|
/** Anthropic caps a request at 10k tools; beyond that native search is invalid. */
|
|
4
4
|
export declare const ANTHROPIC_MAX_TOOLS = 10000;
|
|
5
5
|
export interface AnthropicNativeInjectionConfig {
|
|
6
|
-
/** Never defer this tool (our custom
|
|
6
|
+
/** Never defer this tool (our custom tool_search), and it is non-deferrable. */
|
|
7
7
|
readonly searchToolName?: string;
|
|
8
8
|
/** True for MCP catalog tools eligible for deferral. */
|
|
9
9
|
readonly isDeferrable: (toolName: string) => boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-search.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/native-search.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,0BAA0B,mCAAmC,CAAC;AAC3E,eAAO,MAAM,0BAA0B,gBAAgB,CAAC;AACxD,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,MAAM,WAAW,8BAA8B;IAC9C
|
|
1
|
+
{"version":3,"file":"native-search.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/native-search.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,0BAA0B,mCAAmC,CAAC;AAC3E,eAAO,MAAM,0BAA0B,gBAAgB,CAAC;AACxD,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,MAAM,WAAW,8BAA8B;IAC9C,gFAAgF;IAChF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,wDAAwD;IACxD,QAAQ,CAAC,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;CACrD;AAMD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC3C,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,8BAA8B,GACpC,OAAO,CAUT;AAaD;6EAC6E;AAC7E,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAE7G;AAED,MAAM,WAAW,0BAA2B,SAAQ,8BAA8B;IACjF,+EAA+E;IAC/E,OAAO,IAAI,OAAO,CAAC;IACnB,gEAAgE;IAChE,UAAU,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;GAKG;AACH,qBAAa,gCAAgC;;IAM5C,YAAY,IAAI,EAAE,0BAA0B,EAE3C;IAED,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAMrE;IAED,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAMvC;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAElC;CACD"}
|
|
@@ -85,7 +85,7 @@ export class AnthropicNativeToolSearchAdapter {
|
|
|
85
85
|
return;
|
|
86
86
|
this.#disabled = true;
|
|
87
87
|
this.#fallbackReason =
|
|
88
|
-
"Anthropic returned 400 for native tool-search; disabled it and fell back to local
|
|
88
|
+
"Anthropic returned 400 for native tool-search; disabled it and fell back to local tool_search for this session.";
|
|
89
89
|
this.#deps.onFallback?.(this.#fallbackReason);
|
|
90
90
|
}
|
|
91
91
|
get disabled() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-search.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/native-search.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"native-search.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/native-search.ts"],"names":[],"mappings":"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","sourcesContent":["// Native provider tool-search adapters (todo 33 — Anthropic half).\n//\n// Gated on the todo-29 spike verdict: Anthropic Messages is GO-pure-extension —\n// server_tool_use / tool_search_tool_result blocks round-trip pi-ai's\n// parse->persist->re-serialise cycle untouched (native-search-spike.md), so this\n// adapter injects request-side fields via the extension before_provider_request\n// event ONLY (the sole ExtensionAPI payload surface) with no pi-ai change.\n//\n// It injects Anthropic's native `tool_search_tool_bm25_20251119` tool and marks\n// deferrable MCP tools `defer_loading:true`, honouring the API HARD RULES, and\n// auto-falls-back to local Tier-B on a 400. The OpenAI half is deferred\n// (spike = GO-with-ai-seam; see native-search-spike.md).\n\nexport const ANTHROPIC_TOOL_SEARCH_TYPE = \"tool_search_tool_bm25_20251119\";\nexport const ANTHROPIC_TOOL_SEARCH_NAME = \"tool_search\";\n/** Anthropic caps a request at 10k tools; beyond that native search is invalid. */\nexport const ANTHROPIC_MAX_TOOLS = 10000;\n\nexport interface AnthropicNativeInjectionConfig {\n\t/** Never defer this tool (our custom tool_search), and it is non-deferrable. */\n\treadonly searchToolName?: string;\n\t/** True for MCP catalog tools eligible for deferral. */\n\treadonly isDeferrable: (toolName: string) => boolean;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\n/**\n * Pure payload transform. Adds exactly one native tool-search tool (idempotent)\n * and sets `defer_loading:true` on eligible MCP tools, enforcing the HARD RULES:\n * never defer the search tool, never combine defer_loading with cache_control\n * (400), keep >=1 non-deferred tool (the native search tool guarantees this),\n * and skip entirely above the 10k tool cap.\n */\nexport function addAnthropicNativeToolSearch(\n\tapi: string | undefined,\n\tpayload: unknown,\n\tconfig: AnthropicNativeInjectionConfig,\n): unknown {\n\tif (api !== \"anthropic-messages\" || !isRecord(payload)) return payload;\n\tconst tools = Array.isArray(payload.tools) ? payload.tools : [];\n\tif (tools.length > ANTHROPIC_MAX_TOOLS) return payload;\n\tconst deferred = tools.map((tool) => maybeDefer(tool, config));\n\tconst hasSearchTool = deferred.some((tool) => isRecord(tool) && tool.type === ANTHROPIC_TOOL_SEARCH_TYPE);\n\tconst nextTools = hasSearchTool\n\t\t? deferred\n\t\t: [...deferred, { type: ANTHROPIC_TOOL_SEARCH_TYPE, name: ANTHROPIC_TOOL_SEARCH_NAME }];\n\treturn { ...payload, tools: nextTools };\n}\n\nfunction maybeDefer(tool: unknown, config: AnthropicNativeInjectionConfig): unknown {\n\tif (!isRecord(tool)) return tool;\n\tconst name = typeof tool.name === \"string\" ? tool.name : undefined;\n\tif (name === undefined) return tool; // server/native tools are type-based, never deferred\n\tif (name === config.searchToolName) return tool; // never defer the search tool\n\tif (!config.isDeferrable(name)) return tool; // non-MCP tools untouched\n\tif (\"cache_control\" in tool) return tool; // never defer_loading + cache_control (400)\n\tif (tool.defer_loading === true) return tool; // idempotent\n\treturn { ...tool, defer_loading: true };\n}\n\n/** `tool_reference` blocks emitted inside a tool_result so the API expands the\n * referenced (deferred) tools — the cache-prefix-safe custom-search path. */\nexport function buildToolReferenceBlocks(names: readonly string[]): { type: \"tool_reference\"; name: string }[] {\n\treturn names.map((name) => ({ type: \"tool_reference\", name }));\n}\n\nexport interface AnthropicNativeAdapterDeps extends AnthropicNativeInjectionConfig {\n\t/** Resolved config gate (nativeToolSearch auto|true AND provider supports). */\n\tenabled(): boolean;\n\t/** Invoked once when a 400 forces the local-search fallback. */\n\tonFallback?(reason: string): void;\n}\n\n/**\n * Stateful adapter driving the before_provider_request injection and the\n * after_provider_response 400 detector. Once a 400 lands on a request we\n * injected, native search is disabled for the rest of the session and the\n * extension falls back to local Tier-B (which is always registered).\n */\nexport class AnthropicNativeToolSearchAdapter {\n\t#disabled = false;\n\t#injectedLastRequest = false;\n\t#fallbackReason: string | null = null;\n\treadonly #deps: AnthropicNativeAdapterDeps;\n\n\tconstructor(deps: AnthropicNativeAdapterDeps) {\n\t\tthis.#deps = deps;\n\t}\n\n\tapplyBeforeRequest(api: string | undefined, payload: unknown): unknown {\n\t\tthis.#injectedLastRequest = false;\n\t\tif (this.#disabled || !this.#deps.enabled()) return payload;\n\t\tconst next = addAnthropicNativeToolSearch(api, payload, this.#deps);\n\t\tthis.#injectedLastRequest = next !== payload;\n\t\treturn next;\n\t}\n\n\tnoteResponseStatus(status: number): void {\n\t\tif (status !== 400 || !this.#injectedLastRequest || this.#disabled) return;\n\t\tthis.#disabled = true;\n\t\tthis.#fallbackReason =\n\t\t\t\"Anthropic returned 400 for native tool-search; disabled it and fell back to local tool_search for this session.\";\n\t\tthis.#deps.onFallback?.(this.#fallbackReason);\n\t}\n\n\tget disabled(): boolean {\n\t\treturn this.#disabled;\n\t}\n\n\tget fallbackReason(): string | null {\n\t\treturn this.#fallbackReason;\n\t}\n}\n"]}
|
|
@@ -33,7 +33,7 @@ export function computeMcpExposurePolicy(entries, config, settings) {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
// Tier-B search mode: register the full catalog but keep only directTools
|
|
36
|
-
// active;
|
|
36
|
+
// active; tool_search promotes the rest on demand.
|
|
37
37
|
if (config.exposure === "search") {
|
|
38
38
|
return searchResult(filteredEntries, directEntries, "explicit");
|
|
39
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/policy.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAC;AAelC,MAAM,iBAAiB,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAEpD,MAAM,UAAU,wBAAwB,CACvC,OAAuC,EACvC,MAAuB,EACvB,QAAqB;IAErB,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACrG,MAAM,aAAa,GAAG,UAAU,CAAC,0BAA0B,CAAC,eAAe,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IAClG,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO;YACN,aAAa,EAAE,EAAE;YACjB,eAAe;YACf,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,UAAU;YAClB,iBAAiB,EAAE,EAAE;YACrB,QAAQ,EAAE,CAAC,cAAc,UAAU,CAAC,OAAO,CAAC,+DAA+D,CAAC;SAC5G,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QACjC,OAAO,YAAY,CAAC,eAAe,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,YAAY,CAAC,eAAe,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;IACnE,CAAC;IACD,yEAAyE;IACzE,0EAA0E;IAC1E,+EAA+E;IAC/E,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO;YACN,aAAa,EAAE,EAAE;YACjB,eAAe;YACf,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,UAAU;YAClB,iBAAiB,EAAE,EAAE;YACrB,QAAQ,EAAE,EAAE;SACZ,CAAC;IACH,CAAC;IACD,0EAA0E;IAC1E,
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/mcp/expose/policy.ts"],"names":[],"mappings":"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","sourcesContent":["import picomatch from \"picomatch\";\nimport type { McpToolCatalogEntry } from \"../catalog.ts\";\nimport type { McpServerConfig, McpSettings } from \"../config-schema.ts\";\n\nexport interface McpExposurePolicyResult {\n\treadonly activeEntries: McpToolCatalogEntry[];\n\treadonly filteredEntries: McpToolCatalogEntry[];\n\treadonly mode: \"direct\" | \"search\" | \"proxy\";\n\treadonly reason: \"explicit\" | \"threshold\" | \"directTools\";\n\treadonly registeredEntries: McpToolCatalogEntry[];\n\treadonly warnings: string[];\n}\n\ntype ToolMatcher = (toolName: string) => boolean;\n\nconst PICOMATCH_OPTIONS = { bash: true, dot: true };\n\nexport function computeMcpExposurePolicy(\n\tentries: readonly McpToolCatalogEntry[],\n\tconfig: McpServerConfig,\n\tsettings: McpSettings,\n): McpExposurePolicyResult {\n\tconst filteredEntries = stableSort(entries.filter((entry) => passesToolFilters(entry.tool, config)));\n\tconst directEntries = stableSort(entriesMatchingDirectTools(filteredEntries, config.directTools));\n\tif (filteredEntries.length === 0) {\n\t\treturn {\n\t\t\tactiveEntries: [],\n\t\t\tfilteredEntries,\n\t\t\tmode: \"direct\",\n\t\t\treason: \"explicit\",\n\t\t\tregisteredEntries: [],\n\t\t\twarnings: [`MCP server ${serverName(entries)} has 0 exposed tools after includeTools/excludeTools filters.`],\n\t\t};\n\t}\n\n\tif (config.directTools === true) {\n\t\treturn directResult(filteredEntries, filteredEntries, \"directTools\");\n\t}\n\tif (config.exposure === \"direct\") {\n\t\treturn directResult(filteredEntries, filteredEntries, \"explicit\");\n\t}\n\t// Tier-C proxy mode (todo 38): per-server OPT-IN only. The whole catalog\n\t// stays behind a single gateway tool; nothing registers directly and auto\n\t// never selects this mode (SPEC §5: -27.3pp GSM8K structured-output evidence).\n\tif (config.exposure === \"proxy\") {\n\t\treturn {\n\t\t\tactiveEntries: [],\n\t\t\tfilteredEntries,\n\t\t\tmode: \"proxy\",\n\t\t\treason: \"explicit\",\n\t\t\tregisteredEntries: [],\n\t\t\twarnings: [],\n\t\t};\n\t}\n\t// Tier-B search mode: register the full catalog but keep only directTools\n\t// active; tool_search promotes the rest on demand.\n\tif (config.exposure === \"search\") {\n\t\treturn searchResult(filteredEntries, directEntries, \"explicit\");\n\t}\n\tif (filteredEntries.length <= (settings.searchThreshold ?? 10)) {\n\t\treturn directResult(filteredEntries, filteredEntries, \"threshold\");\n\t}\n\treturn searchResult(filteredEntries, directEntries, \"threshold\");\n}\n\nfunction searchResult(\n\tfilteredEntries: readonly McpToolCatalogEntry[],\n\tdirectEntries: readonly McpToolCatalogEntry[],\n\treason: McpExposurePolicyResult[\"reason\"],\n): McpExposurePolicyResult {\n\treturn {\n\t\tactiveEntries: stableSort(directEntries),\n\t\tfilteredEntries: stableSort(filteredEntries),\n\t\tmode: \"search\",\n\t\treason,\n\t\tregisteredEntries: stableSort(filteredEntries),\n\t\twarnings: [],\n\t};\n}\n\nfunction directResult(\n\tfilteredEntries: readonly McpToolCatalogEntry[],\n\tactiveEntries: readonly McpToolCatalogEntry[],\n\treason: McpExposurePolicyResult[\"reason\"],\n): McpExposurePolicyResult {\n\treturn {\n\t\tactiveEntries: stableSort(activeEntries),\n\t\tfilteredEntries: stableSort(filteredEntries),\n\t\tmode: \"direct\",\n\t\treason,\n\t\tregisteredEntries: stableSort(activeEntries),\n\t\twarnings: [],\n\t};\n}\n\nfunction passesToolFilters(toolName: string, config: McpServerConfig): boolean {\n\tconst include = compileMatchers(config.includeTools);\n\tconst exclude = compileMatchers(config.excludeTools);\n\tconst included = include.length === 0 || include.some((isMatch) => isMatch(toolName));\n\tif (!included) return false;\n\treturn !exclude.some((isMatch) => isMatch(toolName));\n}\n\nfunction entriesMatchingDirectTools(\n\tentries: readonly McpToolCatalogEntry[],\n\tdirectTools: McpServerConfig[\"directTools\"],\n): McpToolCatalogEntry[] {\n\tif (directTools === true) return stableSort(entries);\n\tif (!Array.isArray(directTools) || directTools.length === 0) return [];\n\tconst matchers = compileMatchers(directTools);\n\treturn stableSort(entries.filter((entry) => matchers.some((isMatch) => isMatch(entry.tool))));\n}\n\nfunction compileMatchers(patterns: readonly string[] | undefined): ToolMatcher[] {\n\treturn (patterns ?? []).map((pattern) => safeMatcher(pattern));\n}\n\nfunction safeMatcher(pattern: string): ToolMatcher {\n\ttry {\n\t\treturn picomatch(pattern, PICOMATCH_OPTIONS);\n\t} catch {\n\t\treturn (toolName) => toolName === pattern;\n\t}\n}\n\nfunction stableSort(entries: readonly McpToolCatalogEntry[]): McpToolCatalogEntry[] {\n\treturn [...entries].sort(\n\t\t(left, right) => left.server.localeCompare(right.server) || left.tool.localeCompare(right.tool),\n\t);\n}\n\nfunction serverName(entries: readonly McpToolCatalogEntry[]): string {\n\treturn entries[0]?.server ?? \"<unknown>\";\n}\n"]}
|
|
@@ -6,7 +6,7 @@ export function getMcpCatalogExposureStatus(catalog, serverConfig, settings) {
|
|
|
6
6
|
}
|
|
7
7
|
// Report the total exposed tools; in search mode note how many are active now.
|
|
8
8
|
const hint = policy.mode === "search"
|
|
9
|
-
? `search mode: ${policy.activeEntries.length} active now, ${policy.registeredEntries.length} searchable via
|
|
9
|
+
? `search mode: ${policy.activeEntries.length} active now, ${policy.registeredEntries.length} searchable via tool_search`
|
|
10
10
|
: undefined;
|
|
11
11
|
return { hint, toolCount: policy.registeredEntries.length, mode: policy.mode };
|
|
12
12
|
}
|