@selesai/code 0.9.10 → 0.9.11
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 +260 -255
- package/dist/cli/args.js +13 -2
- package/dist/cli/args.test.js +8 -0
- package/dist/cli/credential-print.js +4 -4
- package/dist/cli.js +0 -0
- package/dist/core/agent-session-auto-handoff.test.js +24 -1
- package/dist/core/agent-session.d.ts +11 -4
- package/dist/core/agent-session.js +96 -35
- package/dist/core/compaction/branch-summarization.js +30 -30
- package/dist/core/compaction/compaction.js +81 -81
- package/dist/core/compaction/utils.js +2 -2
- package/dist/core/defaults.d.ts +1 -0
- package/dist/core/defaults.js +9 -0
- package/dist/core/export-html/template.css +1066 -1066
- package/dist/core/export-html/template.html +55 -55
- package/dist/core/export-html/template.js +1864 -1864
- package/dist/core/export-html/vendor/highlight.min.js +1212 -1212
- package/dist/core/export-html/vendor/marked.min.js +78 -78
- package/dist/core/extensions/loader.js +108 -35
- package/dist/core/extensions/loader.test.d.ts +1 -0
- package/dist/core/extensions/loader.test.js +21 -0
- package/dist/core/extensions/types.d.ts +12 -2
- package/dist/core/keybindings.d.ts +2 -2
- package/dist/core/messages.js +7 -7
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.js +10 -4
- package/dist/core/package-manager.js +4 -4
- package/dist/core/sdk.d.ts +5 -5
- package/dist/core/sdk.js +16 -4
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.js +22 -0
- package/dist/core/tools/bash.d.ts +18 -1
- package/dist/core/tools/bash.js +41 -23
- package/dist/core/tools/index.d.ts +4 -1
- package/dist/core/tools/index.js +9 -1
- package/dist/core/tools/powershell.d.ts +15 -0
- package/dist/core/tools/powershell.js +38 -0
- package/dist/core/tools/powershell.test.d.ts +1 -0
- package/dist/core/tools/powershell.test.js +20 -0
- package/dist/extensions/context-compaction-reminder.test.ts +82 -82
- package/dist/extensions/context-compaction-reminder.ts +28 -28
- package/dist/extensions/pi-intercom/LICENSE +21 -21
- package/dist/extensions/pi-intercom/broker/client.test.ts +83 -83
- package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -387
- package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -114
- package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -153
- package/dist/extensions/pi-intercom/broker/paths.ts +134 -134
- package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -34
- package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -21
- package/dist/extensions/pi-intercom/cwd.test.ts +40 -40
- package/dist/extensions/pi-intercom/cwd.ts +31 -31
- package/dist/extensions/pi-intercom/extension-api.ts +44 -44
- package/dist/extensions/pi-intercom/format-context.test.ts +31 -31
- package/dist/extensions/pi-intercom/format-context.ts +32 -32
- package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -66
- package/dist/extensions/pi-intercom/ui/compose.ts +143 -143
- package/dist/extensions/pi-intercom/ui/session-list.ts +166 -166
- package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +286 -286
- package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +108 -108
- package/dist/extensions/pi-powerline-footer/separators.ts +57 -57
- package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +47 -47
- package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +39 -39
- package/dist/extensions/pi-powerline-footer/theme.example.json +24 -24
- package/dist/extensions/pi-powerline-footer/theme.json +12 -12
- package/dist/extensions/pi-powerline-footer/tps.ts +345 -345
- package/dist/extensions/pi-rewind-hook/README.md +245 -245
- package/dist/extensions/pi-rewind-hook/index.ts +1445 -1445
- package/dist/extensions/pi-rewind-hook/package.json +29 -29
- package/dist/extensions/pi-subagents/install.mjs +0 -0
- package/dist/extensions/pi-web-agent/package.json +31 -31
- package/dist/extensions/pi-web-agent/src/backends/config.ts +205 -205
- package/dist/extensions/pi-web-agent/src/backends/doctor.ts +136 -136
- package/dist/extensions/pi-web-agent/src/backends/factory.ts +152 -152
- package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +25 -25
- package/dist/extensions/pi-web-agent/src/cache/ttl-cache.ts +28 -28
- package/dist/extensions/pi-web-agent/src/changelog-notice.ts +136 -136
- package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +946 -946
- package/dist/extensions/pi-web-agent/src/extension.ts +126 -126
- package/dist/extensions/pi-web-agent/src/extract/readability.ts +118 -118
- package/dist/extensions/pi-web-agent/src/fetch/browser-resolution.ts +199 -199
- package/dist/extensions/pi-web-agent/src/fetch/firecrawl-fetch.ts +100 -100
- package/dist/extensions/pi-web-agent/src/fetch/headless-fetch.ts +117 -117
- package/dist/extensions/pi-web-agent/src/fetch/http-fetch.ts +67 -67
- package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +60 -60
- package/dist/extensions/pi-web-agent/src/orchestration/candidate-selector.ts +50 -50
- package/dist/extensions/pi-web-agent/src/orchestration/direct-url.ts +52 -52
- package/dist/extensions/pi-web-agent/src/orchestration/evidence-quality.ts +105 -105
- package/dist/extensions/pi-web-agent/src/orchestration/evidence-ranker.ts +45 -45
- package/dist/extensions/pi-web-agent/src/orchestration/index.ts +28 -28
- package/dist/extensions/pi-web-agent/src/orchestration/query-planner.ts +47 -47
- package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +376 -376
- package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +64 -64
- package/dist/extensions/pi-web-agent/src/orchestration/research-worker.ts +181 -181
- package/dist/extensions/pi-web-agent/src/orchestration/source-profile.ts +101 -101
- package/dist/extensions/pi-web-agent/src/orchestration/stop-decider.ts +81 -81
- package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +210 -210
- package/dist/extensions/pi-web-agent/src/presentation/config.ts +75 -75
- package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +61 -61
- package/dist/extensions/pi-web-agent/src/presentation/fetch-presentation.ts +54 -54
- package/dist/extensions/pi-web-agent/src/presentation/search-presentation.ts +41 -41
- package/dist/extensions/pi-web-agent/src/presentation/select-view.ts +20 -20
- package/dist/extensions/pi-web-agent/src/presentation/types.ts +63 -63
- package/dist/extensions/pi-web-agent/src/search/brave.ts +114 -114
- package/dist/extensions/pi-web-agent/src/search/duckduckgo.ts +72 -72
- package/dist/extensions/pi-web-agent/src/search/searxng.ts +96 -96
- package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +71 -71
- package/dist/extensions/pi-web-agent/src/tools/web-fetch-headless.ts +31 -31
- package/dist/extensions/pi-web-agent/src/tools/web-fetch.ts +31 -31
- package/dist/extensions/pi-web-agent/src/tools/web-search.ts +157 -157
- package/dist/extensions/pi-web-agent/src/types.ts +88 -88
- package/dist/extensions/ponytail/package.json +8 -8
- package/dist/extensions/question/batch.ts +103 -103
- package/dist/extensions/question/constants.ts +30 -30
- package/dist/extensions/question/helpers.ts +58 -58
- package/dist/extensions/question/navigation.ts +14 -14
- package/dist/extensions/question/package.json +19 -19
- package/dist/extensions/question/schemas.ts +43 -43
- package/dist/extensions/question/selection-mode.ts +46 -46
- package/dist/extensions/question/shortcuts.ts +44 -44
- package/dist/extensions/question/types.ts +132 -132
- package/dist/extensions/test-resolve-hook-impl.mjs +6 -6
- package/dist/extensions/test-resolve-hook.mjs +6 -6
- package/dist/extensions/web-agent-onboarding.ts +222 -222
- package/dist/extensions/workflow/package.json +17 -17
- package/dist/package-manager-cli.js +71 -71
- package/dist/rpc-entry.js +0 -0
- package/dist/skills/agent-browser/SKILL.md +52 -52
- package/dist/skills/batch-grill-me/SKILL.md +19 -19
- package/dist/skills/grill-me/SKILL.md +10 -10
- package/dist/skills/handoff/SKILL.md +16 -16
- package/dist/skills/handoff-text/SKILL.md +14 -14
- package/dist/skills/implanger/SKILL.md +69 -69
- package/dist/skills/improve-codebase/REFERENCE.md +78 -78
- package/dist/skills/improve-codebase/SKILL.md +178 -178
- package/dist/skills/planger/SKILL.md +166 -166
- package/dist/skills/ponytail/SKILL.md +116 -116
- package/dist/skills/ponytail-audit/SKILL.md +42 -42
- package/dist/skills/ponytail-debt/SKILL.md +45 -45
- package/dist/skills/ponytail-gain/SKILL.md +51 -51
- package/dist/skills/ponytail-help/SKILL.md +70 -70
- package/dist/skills/ponytail-review/SKILL.md +58 -58
- package/dist/skills/selesai-handoff/SKILL.md +20 -20
- package/dist/skills/workflow-creation/SKILL.md +73 -73
- package/dist/themes/powerline-footer/theme.json +33 -33
- package/dist/utils/shell.d.ts +3 -0
- package/dist/utils/shell.js +17 -5
- package/docs/compaction.md +396 -396
- package/docs/containerization.md +111 -111
- package/docs/development.md +71 -71
- package/docs/docs.json +164 -164
- package/docs/environment-variables.md +86 -86
- package/docs/index.md +83 -83
- package/docs/json.md +82 -82
- package/docs/models.md +502 -502
- package/docs/packages.md +227 -227
- package/docs/plans/subagent-delegation/phase-0-correctness.md +264 -264
- package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +485 -485
- package/docs/plans/subagent-delegation/phase-2-context-controls.md +281 -281
- package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +361 -361
- package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +380 -380
- package/docs/prompt-templates.md +95 -95
- package/docs/providers.md +293 -293
- package/docs/sdk.md +1144 -1143
- package/docs/security.md +59 -59
- package/docs/session-format.md +414 -414
- package/docs/sessions.md +145 -145
- package/docs/shared-host-extensions.md +109 -109
- package/docs/shell-aliases.md +13 -13
- package/docs/skills.md +231 -231
- package/docs/terminal-setup.md +142 -142
- package/docs/termux.md +127 -127
- package/docs/themes.md +295 -295
- package/docs/tmux.md +63 -63
- package/docs/tui.md +927 -927
- package/docs/windows.md +17 -17
- package/examples/README.md +25 -25
- package/examples/extensions/README.md +211 -211
- package/examples/extensions/auto-commit-on-exit.ts +49 -49
- package/examples/extensions/bash-spawn-hook.ts +30 -30
- package/examples/extensions/bookmark.ts +50 -50
- package/examples/extensions/border-status-editor.ts +150 -150
- package/examples/extensions/built-in-tool-renderer.ts +249 -249
- package/examples/extensions/claude-rules.ts +86 -86
- package/examples/extensions/commands.ts +72 -72
- package/examples/extensions/confirm-destructive.ts +59 -59
- package/examples/extensions/custom-compaction.ts +130 -130
- package/examples/extensions/custom-footer.ts +64 -64
- package/examples/extensions/custom-header.ts +73 -73
- package/examples/extensions/custom-provider-anthropic/index.ts +610 -610
- package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -24
- package/examples/extensions/custom-provider-anthropic/package.json +19 -19
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +404 -404
- package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -16
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -82
- package/examples/extensions/dirty-repo-guard.ts +56 -56
- package/examples/extensions/doom-overlay/README.md +46 -46
- package/examples/extensions/doom-overlay/doom/build/doom.js +21 -21
- package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
- package/examples/extensions/doom-overlay/doom/build.sh +152 -152
- package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -72
- package/examples/extensions/doom-overlay/doom-component.ts +132 -132
- package/examples/extensions/doom-overlay/doom-engine.ts +173 -173
- package/examples/extensions/doom-overlay/doom-keys.ts +104 -104
- package/examples/extensions/doom-overlay/index.ts +74 -74
- package/examples/extensions/doom-overlay/wad-finder.ts +51 -51
- package/examples/extensions/dynamic-resources/SKILL.md +8 -8
- package/examples/extensions/dynamic-resources/dynamic.json +79 -79
- package/examples/extensions/dynamic-resources/dynamic.md +5 -5
- package/examples/extensions/dynamic-resources/index.ts +15 -15
- package/examples/extensions/dynamic-tools.ts +74 -74
- package/examples/extensions/event-bus.ts +43 -43
- package/examples/extensions/file-trigger.ts +41 -41
- package/examples/extensions/git-checkpoint.ts +53 -53
- package/examples/extensions/git-merge-and-resolve.ts +115 -115
- package/examples/extensions/github-issue-autocomplete.ts +185 -185
- package/examples/extensions/gondolin/index.ts +531 -531
- package/examples/extensions/gondolin/package-lock.json +185 -185
- package/examples/extensions/gondolin/package.json +19 -19
- package/examples/extensions/handoff.ts +199 -199
- package/examples/extensions/hello.ts +26 -26
- package/examples/extensions/hidden-thinking-label.ts +53 -53
- package/examples/extensions/inline-bash.ts +94 -94
- package/examples/extensions/input-transform-streaming.ts +39 -39
- package/examples/extensions/input-transform.ts +43 -43
- package/examples/extensions/interactive-shell.ts +196 -196
- package/examples/extensions/mac-system-theme.ts +47 -47
- package/examples/extensions/message-renderer.ts +59 -59
- package/examples/extensions/minimal-mode.ts +426 -426
- package/examples/extensions/modal-editor.ts +85 -85
- package/examples/extensions/model-status.ts +31 -31
- package/examples/extensions/notify.ts +55 -55
- package/examples/extensions/overlay-qa-tests.ts +1450 -1450
- package/examples/extensions/overlay-test.ts +153 -153
- package/examples/extensions/permission-gate.ts +34 -34
- package/examples/extensions/pirate.ts +47 -47
- package/examples/extensions/plan-mode/README.md +66 -66
- package/examples/extensions/plan-mode/index.ts +390 -390
- package/examples/extensions/plan-mode/utils.ts +168 -168
- package/examples/extensions/preset.ts +436 -436
- package/examples/extensions/project-trust.ts +64 -64
- package/examples/extensions/prompt-customizer.ts +97 -97
- package/examples/extensions/protected-paths.ts +30 -30
- package/examples/extensions/provider-payload.ts +18 -18
- package/examples/extensions/qna.ts +122 -122
- package/examples/extensions/question.ts +285 -285
- package/examples/extensions/questionnaire.ts +448 -448
- package/examples/extensions/rainbow-editor.ts +88 -88
- package/examples/extensions/reload-runtime.ts +37 -37
- package/examples/extensions/rpc-demo.ts +118 -118
- package/examples/extensions/sandbox/index.ts +321 -321
- package/examples/extensions/sandbox/package-lock.json +92 -92
- package/examples/extensions/sandbox/package.json +19 -19
- package/examples/extensions/send-user-message.ts +97 -97
- package/examples/extensions/session-name.ts +27 -27
- package/examples/extensions/shutdown-command.ts +63 -63
- package/examples/extensions/snake.ts +343 -343
- package/examples/extensions/space-invaders.ts +560 -560
- package/examples/extensions/ssh.ts +220 -220
- package/examples/extensions/status-line.ts +32 -32
- package/examples/extensions/structured-output.ts +65 -65
- package/examples/extensions/subagent/README.md +175 -175
- package/examples/extensions/subagent/agents/planner.md +37 -37
- package/examples/extensions/subagent/agents/reviewer.md +35 -35
- package/examples/extensions/subagent/agents/scout.md +50 -50
- package/examples/extensions/subagent/agents/worker.md +24 -24
- package/examples/extensions/subagent/agents.ts +126 -126
- package/examples/extensions/subagent/index.ts +1015 -1015
- package/examples/extensions/subagent/prompts/implement-and-review.md +10 -10
- package/examples/extensions/subagent/prompts/implement.md +10 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -9
- package/examples/extensions/summarize.ts +209 -209
- package/examples/extensions/system-prompt-header.ts +17 -17
- package/examples/extensions/tic-tac-toe.ts +1008 -1008
- package/examples/extensions/timed-confirm.ts +70 -70
- package/examples/extensions/titlebar-spinner.ts +58 -58
- package/examples/extensions/todo.ts +297 -297
- package/examples/extensions/tool-override.ts +144 -144
- package/examples/extensions/tools.ts +146 -146
- package/examples/extensions/trigger-compact.ts +50 -50
- package/examples/extensions/truncated-tool.ts +195 -195
- package/examples/extensions/widget-placement.ts +9 -9
- package/examples/extensions/with-deps/index.ts +32 -32
- package/examples/extensions/with-deps/package-lock.json +31 -31
- package/examples/extensions/with-deps/package.json +22 -22
- package/examples/extensions/working-indicator.ts +123 -123
- package/examples/extensions/working-message-test.ts +25 -25
- package/examples/rpc-extension-ui.ts +632 -632
- package/examples/sdk/01-minimal.ts +26 -26
- package/examples/sdk/02-custom-model.ts +53 -53
- package/examples/sdk/03-custom-prompt.ts +75 -75
- package/examples/sdk/04-skills.ts +55 -55
- package/examples/sdk/05-tools.ts +48 -48
- package/examples/sdk/06-extensions.ts +99 -99
- package/examples/sdk/07-context-files.ts +47 -47
- package/examples/sdk/08-prompt-templates.ts +51 -51
- package/examples/sdk/09-api-keys-and-oauth.ts +52 -52
- package/examples/sdk/10-settings.ts +53 -53
- package/examples/sdk/11-sessions.ts +52 -52
- package/examples/sdk/12-full-control.ts +79 -79
- package/examples/sdk/13-session-runtime.ts +67 -67
- package/examples/sdk/README.md +144 -144
- package/package.json +4 -4
package/dist/cli/args.js
CHANGED
|
@@ -16,7 +16,18 @@ export function parseArgs(args) {
|
|
|
16
16
|
};
|
|
17
17
|
for (let i = 0; i < args.length; i++) {
|
|
18
18
|
const arg = args[i];
|
|
19
|
-
if (arg === "--
|
|
19
|
+
if (arg === "--") {
|
|
20
|
+
for (const positionalArg of args.slice(i + 1)) {
|
|
21
|
+
if (positionalArg.startsWith("@")) {
|
|
22
|
+
result.fileArgs.push(positionalArg.slice(1));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
result.messages.push(positionalArg);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
else if (arg === "--help" || arg === "-h") {
|
|
20
31
|
result.help = true;
|
|
21
32
|
}
|
|
22
33
|
else if (arg === "--version" || arg === "-v") {
|
|
@@ -269,7 +280,7 @@ ${chalk.bold("Options:")}
|
|
|
269
280
|
--models <patterns> Comma-separated model patterns for Ctrl+P cycling
|
|
270
281
|
Supports globs (anthropic/*, *sonnet*) and fuzzy matching
|
|
271
282
|
--no-tools, -nt Disable all tools by default (built-in and extension)
|
|
272
|
-
--no-builtin-tools, -nbt Disable built-in tools
|
|
283
|
+
--no-builtin-tools, -nbt Disable built-in tools and enable extension/custom tools
|
|
273
284
|
--tools, -t <tools> Comma-separated allowlist of tool names to enable
|
|
274
285
|
Applies to built-in, extension, and custom tools
|
|
275
286
|
--exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable
|
package/dist/cli/args.test.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
2
|
import { parseArgs } from "./args.js";
|
|
3
|
+
describe("parseArgs end-of-options delimiter", () => {
|
|
4
|
+
test("treats remaining arguments as messages and @files", () => {
|
|
5
|
+
const result = parseArgs(["--no-session", "--", "--provider", "openai", "-c", "@prompt.md"]);
|
|
6
|
+
expect(result.noSession).toBe(true);
|
|
7
|
+
expect(result.messages).toEqual(["--provider", "openai", "-c"]);
|
|
8
|
+
expect(result.fileArgs).toEqual(["prompt.md"]);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
3
11
|
describe("parseArgs --use-theme", () => {
|
|
4
12
|
test("parses --use-theme with a theme name", () => {
|
|
5
13
|
const result = parseArgs(["--use-theme", "nord-border", "hello"]);
|
|
@@ -7,10 +7,10 @@ export function isCredentialPrintHelp(args) {
|
|
|
7
7
|
return (args[0] === "auth" && (args[1] === undefined || args[1] === "help" || args[1] === "--help" || args[1] === "-h"));
|
|
8
8
|
}
|
|
9
9
|
export function printCredentialPrintHelp() {
|
|
10
|
-
console.log(`Usage:
|
|
11
|
-
${APP_NAME} auth print-api-key --model <model> [--provider <provider>]
|
|
12
|
-
${APP_NAME} auth print-bearer-token --model <model> [--provider <provider>] [--min-expiry <duration>]
|
|
13
|
-
|
|
10
|
+
console.log(`Usage:
|
|
11
|
+
${APP_NAME} auth print-api-key --model <model> [--provider <provider>]
|
|
12
|
+
${APP_NAME} auth print-bearer-token --model <model> [--provider <provider>] [--min-expiry <duration>]
|
|
13
|
+
|
|
14
14
|
Prints the configured credential alone on stdout. Provider inference uses configured credentials; specify --provider to select explicitly. Bearer tokens have a 30-minute minimum expiry by default. --min-expiry accepts ms, s, m, or h (for example, 30m).`);
|
|
15
15
|
}
|
|
16
16
|
/** Parse the auth command surface before normal startup. */
|
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { Type } from "typebox";
|
|
2
3
|
import { AgentSession } from "./agent-session.js";
|
|
3
4
|
import { SettingsManager } from "./settings-manager.js";
|
|
4
|
-
function createMockSession({ enabled, threshold = 128_000, tokens, mode = "tui", command, }) {
|
|
5
|
+
function createMockSession({ enabled, threshold = 128_000, tokens, mode = "tui", command, customTools, allowedToolNames, }) {
|
|
5
6
|
const settings = SettingsManager.inMemory({
|
|
6
7
|
autoHandoff: { enabled, thresholdTokens: threshold },
|
|
7
8
|
});
|
|
@@ -45,13 +46,35 @@ function createMockSession({ enabled, threshold = 128_000, tokens, mode = "tui",
|
|
|
45
46
|
settingsManager: settings,
|
|
46
47
|
cwd: "/tmp",
|
|
47
48
|
resourceLoader: resourceLoader,
|
|
49
|
+
customTools,
|
|
48
50
|
modelRuntime: modelRegistry,
|
|
51
|
+
allowedToolNames,
|
|
49
52
|
});
|
|
50
53
|
session._extensionRunner = extensionRunner;
|
|
51
54
|
session._extensionMode = mode;
|
|
52
55
|
session.getContextUsage = () => tokens === null ? null : { tokens, contextWindow: 200_000, percent: tokens / 200_000 };
|
|
53
56
|
return { session, getCommand, createCommandContext, handler, emitError, settings };
|
|
54
57
|
}
|
|
58
|
+
describe("AgentSession tools", () => {
|
|
59
|
+
const customTool = {
|
|
60
|
+
name: "custom",
|
|
61
|
+
label: "Custom",
|
|
62
|
+
description: "A custom tool",
|
|
63
|
+
parameters: Type.Object({}),
|
|
64
|
+
execute: async () => ({ content: [{ type: "text", text: "ok" }], details: undefined }),
|
|
65
|
+
};
|
|
66
|
+
it("keeps custom tools inactive by default but activates explicitly allowed ones", () => {
|
|
67
|
+
const defaults = createMockSession({ enabled: false, tokens: null, customTools: [customTool] });
|
|
68
|
+
expect(defaults.session.getActiveToolNames()).not.toContain("custom");
|
|
69
|
+
const allowed = createMockSession({
|
|
70
|
+
enabled: false,
|
|
71
|
+
tokens: null,
|
|
72
|
+
customTools: [customTool],
|
|
73
|
+
allowedToolNames: ["custom"],
|
|
74
|
+
});
|
|
75
|
+
expect(allowed.session.getActiveToolNames()).toEqual(["custom"]);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
55
78
|
describe("AgentSession auto handoff", () => {
|
|
56
79
|
it("invokes handoff-new once when enabled and threshold reached in tui mode", async () => {
|
|
57
80
|
const command = { handler: vi.fn() };
|
|
@@ -172,6 +172,11 @@ export interface PromptOptions {
|
|
|
172
172
|
preflightResult?: (success: boolean) => void;
|
|
173
173
|
}
|
|
174
174
|
/** Result from cycleModel() */
|
|
175
|
+
/** Options for model and thinking mutations. */
|
|
176
|
+
export interface ModelMutationOptions {
|
|
177
|
+
/** Persist the value to global defaults. Defaults to session-only. */
|
|
178
|
+
persist?: boolean;
|
|
179
|
+
}
|
|
175
180
|
export interface ModelCycleResult {
|
|
176
181
|
model: Model<any>;
|
|
177
182
|
thinkingLevel: ThinkingLevel;
|
|
@@ -265,6 +270,7 @@ export declare class AgentSession {
|
|
|
265
270
|
/** Emit an event to all listeners */
|
|
266
271
|
private _emit;
|
|
267
272
|
private _emitQueueUpdate;
|
|
273
|
+
private _emitSessionCompactFailed;
|
|
268
274
|
private _getIdleWaitPromise;
|
|
269
275
|
private _resolveIdleWaitIfIdle;
|
|
270
276
|
private _emitAgentSettled;
|
|
@@ -478,14 +484,14 @@ export declare class AgentSession {
|
|
|
478
484
|
* Validates that auth is configured, saves to session and settings.
|
|
479
485
|
* @throws Error if no auth is configured for the model
|
|
480
486
|
*/
|
|
481
|
-
setModel(model: Model<any
|
|
487
|
+
setModel(model: Model<any>, options?: ModelMutationOptions): Promise<void>;
|
|
482
488
|
/**
|
|
483
489
|
* Cycle to next/previous model.
|
|
484
490
|
* Uses scoped models (from --models flag) if available, otherwise all available models.
|
|
485
491
|
* @param direction - "forward" (default) or "backward"
|
|
486
492
|
* @returns The new model info, or undefined if only one model available
|
|
487
493
|
*/
|
|
488
|
-
cycleModel(direction?: "forward" | "backward"): Promise<ModelCycleResult | undefined>;
|
|
494
|
+
cycleModel(direction?: "forward" | "backward", options?: ModelMutationOptions): Promise<ModelCycleResult | undefined>;
|
|
489
495
|
private _cycleScopedModel;
|
|
490
496
|
private _cycleAvailableModel;
|
|
491
497
|
/**
|
|
@@ -493,12 +499,12 @@ export declare class AgentSession {
|
|
|
493
499
|
* Clamps to model capabilities based on available thinking levels.
|
|
494
500
|
* Saves to session and settings only if the level actually changes.
|
|
495
501
|
*/
|
|
496
|
-
setThinkingLevel(level: ThinkingLevel): void;
|
|
502
|
+
setThinkingLevel(level: ThinkingLevel, options?: ModelMutationOptions): void;
|
|
497
503
|
/**
|
|
498
504
|
* Cycle to next thinking level.
|
|
499
505
|
* @returns New level, or undefined if model doesn't support thinking
|
|
500
506
|
*/
|
|
501
|
-
cycleThinkingLevel(): ThinkingLevel | undefined;
|
|
507
|
+
cycleThinkingLevel(options?: ModelMutationOptions): ThinkingLevel | undefined;
|
|
502
508
|
/**
|
|
503
509
|
* Get available thinking levels for current model.
|
|
504
510
|
* The provider will clamp to what the specific model supports internally.
|
|
@@ -552,6 +558,7 @@ export declare class AgentSession {
|
|
|
552
558
|
private _applyExtensionBindings;
|
|
553
559
|
private _refreshCurrentModelFromRegistry;
|
|
554
560
|
private _bindExtensionCore;
|
|
561
|
+
private _createToolCatalogDefinition;
|
|
555
562
|
private _refreshToolRegistry;
|
|
556
563
|
private _buildRuntime;
|
|
557
564
|
reload(options?: {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
16
16
|
import { basename, dirname } from "node:path";
|
|
17
|
+
import { Type } from "typebox";
|
|
17
18
|
import { contentText } from "@earendil-works/pi-ai";
|
|
18
19
|
import { clampThinkingLevel, cleanupSessionResources, getSupportedThinkingLevels, isContextOverflow, isRetryableAssistantError, modelsAreEqual, resetApiProviders, streamSimple, } from "@earendil-works/pi-ai/compat";
|
|
19
20
|
import { getThemeByName, theme } from "../modes/interactive/theme/theme.js";
|
|
@@ -24,7 +25,7 @@ import { normalizeAssistantThinkingTags } from "../utils/thinking-tags.js";
|
|
|
24
25
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
25
26
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
26
27
|
import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
|
|
27
|
-
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
28
|
+
import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "./defaults.js";
|
|
28
29
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
29
30
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
30
31
|
import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
@@ -82,8 +83,6 @@ function estimateMessagesTokens(messages) {
|
|
|
82
83
|
// ============================================================================
|
|
83
84
|
// Constants
|
|
84
85
|
// ============================================================================
|
|
85
|
-
/** Standard thinking levels */
|
|
86
|
-
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high"];
|
|
87
86
|
// ============================================================================
|
|
88
87
|
// AgentSession Class
|
|
89
88
|
// ============================================================================
|
|
@@ -168,7 +167,6 @@ export class AgentSession {
|
|
|
168
167
|
this._installAgentNextTurnRefresh();
|
|
169
168
|
this._buildRuntime({
|
|
170
169
|
activeToolNames: this._initialActiveToolNames,
|
|
171
|
-
includeAllExtensionTools: true,
|
|
172
170
|
});
|
|
173
171
|
}
|
|
174
172
|
get modelRuntime() {
|
|
@@ -307,6 +305,11 @@ export class AgentSession {
|
|
|
307
305
|
followUp: [...this._followUpMessages],
|
|
308
306
|
});
|
|
309
307
|
}
|
|
308
|
+
async _emitSessionCompactFailed(event) {
|
|
309
|
+
if (this._extensionRunner.hasHandlers("session_compact_failed")) {
|
|
310
|
+
await this._extensionRunner.emit({ type: "session_compact_failed", ...event });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
310
313
|
_getIdleWaitPromise() {
|
|
311
314
|
if (!this._idleWaitPromise) {
|
|
312
315
|
this._idleWaitPromise = new Promise((resolve) => {
|
|
@@ -1435,16 +1438,17 @@ export class AgentSession {
|
|
|
1435
1438
|
* Validates that auth is configured, saves to session and settings.
|
|
1436
1439
|
* @throws Error if no auth is configured for the model
|
|
1437
1440
|
*/
|
|
1438
|
-
async setModel(model) {
|
|
1441
|
+
async setModel(model, options = {}) {
|
|
1439
1442
|
if (!(await this._modelRuntime.checkAuth(model.provider))) {
|
|
1440
1443
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
1441
1444
|
}
|
|
1442
1445
|
const previousModel = this.model;
|
|
1443
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1446
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(model);
|
|
1444
1447
|
this.agent.state.model = model;
|
|
1445
1448
|
this.sessionManager.appendModelChange(model.provider, model.id);
|
|
1446
|
-
|
|
1447
|
-
|
|
1449
|
+
if (options.persist) {
|
|
1450
|
+
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
1451
|
+
}
|
|
1448
1452
|
this.setThinkingLevel(thinkingLevel);
|
|
1449
1453
|
await this._emitModelSelect(model, previousModel, "set");
|
|
1450
1454
|
}
|
|
@@ -1454,13 +1458,13 @@ export class AgentSession {
|
|
|
1454
1458
|
* @param direction - "forward" (default) or "backward"
|
|
1455
1459
|
* @returns The new model info, or undefined if only one model available
|
|
1456
1460
|
*/
|
|
1457
|
-
async cycleModel(direction = "forward") {
|
|
1461
|
+
async cycleModel(direction = "forward", options = {}) {
|
|
1458
1462
|
if (this._scopedModels.length > 0) {
|
|
1459
|
-
return this._cycleScopedModel(direction);
|
|
1463
|
+
return this._cycleScopedModel(direction, options);
|
|
1460
1464
|
}
|
|
1461
|
-
return this._cycleAvailableModel(direction);
|
|
1465
|
+
return this._cycleAvailableModel(direction, options);
|
|
1462
1466
|
}
|
|
1463
|
-
async _cycleScopedModel(direction) {
|
|
1467
|
+
async _cycleScopedModel(direction, options) {
|
|
1464
1468
|
const checks = await Promise.all(this._scopedModels.map(async (scoped) => ({
|
|
1465
1469
|
scoped,
|
|
1466
1470
|
auth: await this._modelRuntime.checkAuth(scoped.model.provider),
|
|
@@ -1475,11 +1479,13 @@ export class AgentSession {
|
|
|
1475
1479
|
const len = scopedModels.length;
|
|
1476
1480
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1477
1481
|
const next = scopedModels[nextIndex];
|
|
1478
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
|
|
1482
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.model, next.thinkingLevel);
|
|
1479
1483
|
// Apply model
|
|
1480
1484
|
this.agent.state.model = next.model;
|
|
1481
1485
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
1482
|
-
|
|
1486
|
+
if (options.persist) {
|
|
1487
|
+
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
1488
|
+
}
|
|
1483
1489
|
// Apply thinking level.
|
|
1484
1490
|
// - Explicit scoped model thinking level overrides current session level
|
|
1485
1491
|
// - Undefined scoped model thinking level inherits the current session preference
|
|
@@ -1488,7 +1494,7 @@ export class AgentSession {
|
|
|
1488
1494
|
await this._emitModelSelect(next.model, currentModel, "cycle");
|
|
1489
1495
|
return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
|
|
1490
1496
|
}
|
|
1491
|
-
async _cycleAvailableModel(direction) {
|
|
1497
|
+
async _cycleAvailableModel(direction, options) {
|
|
1492
1498
|
const availableModels = await this._modelRuntime.getAvailable();
|
|
1493
1499
|
if (availableModels.length <= 1)
|
|
1494
1500
|
return undefined;
|
|
@@ -1499,10 +1505,12 @@ export class AgentSession {
|
|
|
1499
1505
|
const len = availableModels.length;
|
|
1500
1506
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1501
1507
|
const nextModel = availableModels[nextIndex];
|
|
1502
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1508
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(nextModel);
|
|
1503
1509
|
this.agent.state.model = nextModel;
|
|
1504
1510
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
1505
|
-
|
|
1511
|
+
if (options.persist) {
|
|
1512
|
+
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
1513
|
+
}
|
|
1506
1514
|
// Re-clamp thinking level for new model's capabilities
|
|
1507
1515
|
this.setThinkingLevel(thinkingLevel);
|
|
1508
1516
|
await this._emitModelSelect(nextModel, currentModel, "cycle");
|
|
@@ -1516,18 +1524,18 @@ export class AgentSession {
|
|
|
1516
1524
|
* Clamps to model capabilities based on available thinking levels.
|
|
1517
1525
|
* Saves to session and settings only if the level actually changes.
|
|
1518
1526
|
*/
|
|
1519
|
-
setThinkingLevel(level) {
|
|
1527
|
+
setThinkingLevel(level, options = {}) {
|
|
1520
1528
|
const availableLevels = this.getAvailableThinkingLevels();
|
|
1521
1529
|
const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);
|
|
1522
1530
|
// Only persist if actually changing
|
|
1523
1531
|
const previousLevel = this.agent.state.thinkingLevel;
|
|
1524
1532
|
const isChanging = effectiveLevel !== previousLevel;
|
|
1525
1533
|
this.agent.state.thinkingLevel = effectiveLevel;
|
|
1534
|
+
if (options.persist) {
|
|
1535
|
+
this.settingsManager.setDefaultThinkingLevel(level);
|
|
1536
|
+
}
|
|
1526
1537
|
if (isChanging) {
|
|
1527
1538
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
1528
|
-
if (this.supportsThinking() || effectiveLevel !== "off") {
|
|
1529
|
-
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
|
1530
|
-
}
|
|
1531
1539
|
this._emit({ type: "thinking_level_changed", level: effectiveLevel });
|
|
1532
1540
|
void this._extensionRunner.emit({
|
|
1533
1541
|
type: "thinking_level_select",
|
|
@@ -1540,14 +1548,14 @@ export class AgentSession {
|
|
|
1540
1548
|
* Cycle to next thinking level.
|
|
1541
1549
|
* @returns New level, or undefined if model doesn't support thinking
|
|
1542
1550
|
*/
|
|
1543
|
-
cycleThinkingLevel() {
|
|
1551
|
+
cycleThinkingLevel(options = {}) {
|
|
1544
1552
|
if (!this.supportsThinking())
|
|
1545
1553
|
return undefined;
|
|
1546
1554
|
const levels = this.getAvailableThinkingLevels();
|
|
1547
1555
|
const currentIndex = levels.indexOf(this.thinkingLevel);
|
|
1548
1556
|
const nextIndex = (currentIndex + 1) % levels.length;
|
|
1549
1557
|
const nextLevel = levels[nextIndex];
|
|
1550
|
-
this.setThinkingLevel(nextLevel);
|
|
1558
|
+
this.setThinkingLevel(nextLevel, options);
|
|
1551
1559
|
return nextLevel;
|
|
1552
1560
|
}
|
|
1553
1561
|
/**
|
|
@@ -1556,7 +1564,7 @@ export class AgentSession {
|
|
|
1556
1564
|
*/
|
|
1557
1565
|
getAvailableThinkingLevels() {
|
|
1558
1566
|
if (!this.model)
|
|
1559
|
-
return
|
|
1567
|
+
return [...THINKING_LEVEL_OPTIONS];
|
|
1560
1568
|
return getSupportedThinkingLevels(this.model);
|
|
1561
1569
|
}
|
|
1562
1570
|
/**
|
|
@@ -1565,14 +1573,16 @@ export class AgentSession {
|
|
|
1565
1573
|
supportsThinking() {
|
|
1566
1574
|
return !!this.model?.reasoning;
|
|
1567
1575
|
}
|
|
1568
|
-
_getThinkingLevelForModelSwitch(explicitLevel) {
|
|
1576
|
+
_getThinkingLevelForModelSwitch(targetModel, explicitLevel) {
|
|
1569
1577
|
if (explicitLevel !== undefined) {
|
|
1570
1578
|
return explicitLevel;
|
|
1571
1579
|
}
|
|
1572
|
-
if (
|
|
1573
|
-
|
|
1580
|
+
if (targetModel) {
|
|
1581
|
+
const perModel = this.settingsManager.getModelThinkingLevel(targetModel.provider, targetModel.id);
|
|
1582
|
+
if (perModel !== undefined)
|
|
1583
|
+
return perModel;
|
|
1574
1584
|
}
|
|
1575
|
-
return this.thinkingLevel;
|
|
1585
|
+
return this.settingsManager.getDefaultThinkingLevel() ?? this.thinkingLevel ?? DEFAULT_THINKING_LEVEL;
|
|
1576
1586
|
}
|
|
1577
1587
|
_clampThinkingLevel(level, _availableLevels) {
|
|
1578
1588
|
return this.model ? clampThinkingLevel(this.model, level) : "off";
|
|
@@ -1710,13 +1720,21 @@ export class AgentSession {
|
|
|
1710
1720
|
catch (error) {
|
|
1711
1721
|
const message = error instanceof Error ? error.message : String(error);
|
|
1712
1722
|
const aborted = message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
|
|
1723
|
+
const errorMessage = aborted ? undefined : `Compaction failed: ${message}`;
|
|
1713
1724
|
this._emit({
|
|
1714
1725
|
type: "compaction_end",
|
|
1715
1726
|
reason: "manual",
|
|
1716
1727
|
result: undefined,
|
|
1717
1728
|
aborted,
|
|
1718
1729
|
willRetry: false,
|
|
1719
|
-
errorMessage
|
|
1730
|
+
errorMessage,
|
|
1731
|
+
});
|
|
1732
|
+
await this._emitSessionCompactFailed({
|
|
1733
|
+
reason: "manual",
|
|
1734
|
+
errorMessage,
|
|
1735
|
+
aborted,
|
|
1736
|
+
willRetry: false,
|
|
1737
|
+
fromExtension: false,
|
|
1720
1738
|
});
|
|
1721
1739
|
throw error;
|
|
1722
1740
|
}
|
|
@@ -1835,6 +1853,7 @@ export class AgentSession {
|
|
|
1835
1853
|
async _runAutoCompaction(reason, willRetry) {
|
|
1836
1854
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1837
1855
|
let started = false;
|
|
1856
|
+
let fromExtension = false;
|
|
1838
1857
|
try {
|
|
1839
1858
|
if (!this.model) {
|
|
1840
1859
|
return false;
|
|
@@ -1857,7 +1876,6 @@ export class AgentSession {
|
|
|
1857
1876
|
this._autoCompactionAbortController = new AbortController();
|
|
1858
1877
|
started = true;
|
|
1859
1878
|
let extensionCompaction;
|
|
1860
|
-
let fromExtension = false;
|
|
1861
1879
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
1862
1880
|
const extensionResult = (await this._extensionRunner.emit({
|
|
1863
1881
|
type: "session_before_compact",
|
|
@@ -1876,6 +1894,7 @@ export class AgentSession {
|
|
|
1876
1894
|
aborted: true,
|
|
1877
1895
|
willRetry: false,
|
|
1878
1896
|
});
|
|
1897
|
+
await this._emitSessionCompactFailed({ reason, aborted: true, willRetry: false, fromExtension: false });
|
|
1879
1898
|
return false;
|
|
1880
1899
|
}
|
|
1881
1900
|
if (extensionResult?.compaction) {
|
|
@@ -1913,6 +1932,7 @@ export class AgentSession {
|
|
|
1913
1932
|
aborted: true,
|
|
1914
1933
|
willRetry: false,
|
|
1915
1934
|
});
|
|
1935
|
+
await this._emitSessionCompactFailed({ reason, aborted: true, willRetry: false, fromExtension });
|
|
1916
1936
|
return false;
|
|
1917
1937
|
}
|
|
1918
1938
|
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
@@ -1955,15 +1975,23 @@ export class AgentSession {
|
|
|
1955
1975
|
catch (error) {
|
|
1956
1976
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
1957
1977
|
if (started) {
|
|
1978
|
+
const formattedErrorMessage = reason === "overflow"
|
|
1979
|
+
? `Context overflow recovery failed: ${errorMessage}`
|
|
1980
|
+
: `Auto-compaction failed: ${errorMessage}`;
|
|
1958
1981
|
this._emit({
|
|
1959
1982
|
type: "compaction_end",
|
|
1960
1983
|
reason,
|
|
1961
1984
|
result: undefined,
|
|
1962
1985
|
aborted: false,
|
|
1963
1986
|
willRetry: false,
|
|
1964
|
-
errorMessage:
|
|
1965
|
-
|
|
1966
|
-
|
|
1987
|
+
errorMessage: formattedErrorMessage,
|
|
1988
|
+
});
|
|
1989
|
+
await this._emitSessionCompactFailed({
|
|
1990
|
+
reason,
|
|
1991
|
+
errorMessage: formattedErrorMessage,
|
|
1992
|
+
aborted: false,
|
|
1993
|
+
willRetry: false,
|
|
1994
|
+
fromExtension,
|
|
1967
1995
|
});
|
|
1968
1996
|
}
|
|
1969
1997
|
return false;
|
|
@@ -2187,6 +2215,39 @@ export class AgentSession {
|
|
|
2187
2215
|
},
|
|
2188
2216
|
});
|
|
2189
2217
|
}
|
|
2218
|
+
_createToolCatalogDefinition() {
|
|
2219
|
+
return {
|
|
2220
|
+
name: "tool_catalog",
|
|
2221
|
+
label: "Tool catalog",
|
|
2222
|
+
description: "Discover inactive tools by capability or activate named tools. Activated tools are available on the next turn.",
|
|
2223
|
+
parameters: Type.Object({
|
|
2224
|
+
query: Type.Optional(Type.String({ description: "Capability or tool name to search for" })),
|
|
2225
|
+
activate: Type.Optional(Type.Array(Type.String({ minLength: 1 }), { description: "Exact inactive tool names to activate" })),
|
|
2226
|
+
}),
|
|
2227
|
+
execute: async (_toolCallId, params) => {
|
|
2228
|
+
const query = params.query?.trim().toLowerCase();
|
|
2229
|
+
const active = new Set(this.getActiveToolNames());
|
|
2230
|
+
const requested = Array.isArray(params.activate)
|
|
2231
|
+
? Array.from(new Set(params.activate.filter((name) => typeof name === "string")))
|
|
2232
|
+
: [];
|
|
2233
|
+
const available = Array.from(this._toolDefinitions.values()).filter(({ definition }) => definition.name !== "tool_catalog");
|
|
2234
|
+
const known = new Set(available.map(({ definition }) => definition.name));
|
|
2235
|
+
const unknown = requested.filter((name) => !known.has(name));
|
|
2236
|
+
const activate = requested.filter((name) => known.has(name));
|
|
2237
|
+
if (activate.length > 0)
|
|
2238
|
+
this.setActiveToolsByName([...active, ...activate]);
|
|
2239
|
+
const matches = available
|
|
2240
|
+
.filter(({ definition }) => !query || `${definition.name} ${definition.description}`.toLowerCase().includes(query))
|
|
2241
|
+
.map(({ definition }) => `- ${definition.name}: ${definition.description}`);
|
|
2242
|
+
const result = [
|
|
2243
|
+
activate.length > 0 ? `Activated: ${activate.join(", ")}. They are available on the next turn.` : undefined,
|
|
2244
|
+
unknown.length > 0 ? `Unknown or unavailable: ${unknown.join(", ")}.` : undefined,
|
|
2245
|
+
matches.length > 0 ? `Available tools:\n${matches.join("\n")}` : query ? "No matching tools." : "No additional tools available.",
|
|
2246
|
+
].filter(Boolean).join("\n\n");
|
|
2247
|
+
return { content: [{ type: "text", text: result }], details: { activated: activate, unknown } };
|
|
2248
|
+
},
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2190
2251
|
_refreshToolRegistry(options) {
|
|
2191
2252
|
const previousRegistryNames = new Set(this._toolRegistry.keys());
|
|
2192
2253
|
const previousActiveToolNames = this.getActiveToolNames();
|
|
@@ -2291,6 +2352,7 @@ export class AgentSession {
|
|
|
2291
2352
|
bash: { commandPrefix: shellCommandPrefix, shellPath },
|
|
2292
2353
|
});
|
|
2293
2354
|
this._baseToolDefinitions = new Map(Object.entries(baseToolDefinitions).map(([name, tool]) => [name, tool]));
|
|
2355
|
+
this._baseToolDefinitions.set("tool_catalog", this._createToolCatalogDefinition());
|
|
2294
2356
|
const extensionsResult = this._resourceLoader.getExtensions();
|
|
2295
2357
|
if (options.flagValues) {
|
|
2296
2358
|
for (const [name, value] of options.flagValues) {
|
|
@@ -2305,7 +2367,7 @@ export class AgentSession {
|
|
|
2305
2367
|
this._applyExtensionBindings(this._extensionRunner);
|
|
2306
2368
|
const defaultActiveToolNames = this._baseToolsOverride
|
|
2307
2369
|
? Object.keys(this._baseToolsOverride)
|
|
2308
|
-
: ["read", "bash", "edit", "write"];
|
|
2370
|
+
: ["read", "bash", "edit", "write", "tool_catalog"];
|
|
2309
2371
|
const baseActiveToolNames = options.activeToolNames ?? defaultActiveToolNames;
|
|
2310
2372
|
this._refreshToolRegistry({
|
|
2311
2373
|
activeToolNames: baseActiveToolNames,
|
|
@@ -2322,7 +2384,6 @@ export class AgentSession {
|
|
|
2322
2384
|
this._buildRuntime({
|
|
2323
2385
|
activeToolNames: this.getActiveToolNames(),
|
|
2324
2386
|
flagValues: previousFlagValues,
|
|
2325
|
-
includeAllExtensionTools: true,
|
|
2326
2387
|
});
|
|
2327
2388
|
const hasBindings = this._extensionUIContext ||
|
|
2328
2389
|
this._extensionCommandContextActions ||
|
|
@@ -146,37 +146,37 @@ export function prepareBranchEntries(entries, tokenBudget = 0) {
|
|
|
146
146
|
// ============================================================================
|
|
147
147
|
// Summary Generation
|
|
148
148
|
// ============================================================================
|
|
149
|
-
const BRANCH_SUMMARY_PREAMBLE = `The user explored a different conversation branch before returning here.
|
|
150
|
-
Summary of that exploration:
|
|
151
|
-
|
|
149
|
+
const BRANCH_SUMMARY_PREAMBLE = `The user explored a different conversation branch before returning here.
|
|
150
|
+
Summary of that exploration:
|
|
151
|
+
|
|
152
152
|
`;
|
|
153
|
-
const BRANCH_SUMMARY_PROMPT = `Create a structured summary of this conversation branch for context when returning later.
|
|
154
|
-
|
|
155
|
-
Use this EXACT format:
|
|
156
|
-
|
|
157
|
-
## Goal
|
|
158
|
-
[What was the user trying to accomplish in this branch?]
|
|
159
|
-
|
|
160
|
-
## Constraints & Preferences
|
|
161
|
-
- [Any constraints, preferences, or requirements mentioned]
|
|
162
|
-
- [Or "(none)" if none were mentioned]
|
|
163
|
-
|
|
164
|
-
## Progress
|
|
165
|
-
### Done
|
|
166
|
-
- [x] [Completed tasks/changes]
|
|
167
|
-
|
|
168
|
-
### In Progress
|
|
169
|
-
- [ ] [Work that was started but not finished]
|
|
170
|
-
|
|
171
|
-
### Blocked
|
|
172
|
-
- [Issues preventing progress, if any]
|
|
173
|
-
|
|
174
|
-
## Key Decisions
|
|
175
|
-
- **[Decision]**: [Brief rationale]
|
|
176
|
-
|
|
177
|
-
## Next Steps
|
|
178
|
-
1. [What should happen next to continue this work]
|
|
179
|
-
|
|
153
|
+
const BRANCH_SUMMARY_PROMPT = `Create a structured summary of this conversation branch for context when returning later.
|
|
154
|
+
|
|
155
|
+
Use this EXACT format:
|
|
156
|
+
|
|
157
|
+
## Goal
|
|
158
|
+
[What was the user trying to accomplish in this branch?]
|
|
159
|
+
|
|
160
|
+
## Constraints & Preferences
|
|
161
|
+
- [Any constraints, preferences, or requirements mentioned]
|
|
162
|
+
- [Or "(none)" if none were mentioned]
|
|
163
|
+
|
|
164
|
+
## Progress
|
|
165
|
+
### Done
|
|
166
|
+
- [x] [Completed tasks/changes]
|
|
167
|
+
|
|
168
|
+
### In Progress
|
|
169
|
+
- [ ] [Work that was started but not finished]
|
|
170
|
+
|
|
171
|
+
### Blocked
|
|
172
|
+
- [Issues preventing progress, if any]
|
|
173
|
+
|
|
174
|
+
## Key Decisions
|
|
175
|
+
- **[Decision]**: [Brief rationale]
|
|
176
|
+
|
|
177
|
+
## Next Steps
|
|
178
|
+
1. [What should happen next to continue this work]
|
|
179
|
+
|
|
180
180
|
Keep each section concise. Preserve exact file paths, function names, and error messages.`;
|
|
181
181
|
/**
|
|
182
182
|
* Generate a summary of abandoned branch entries.
|