@selesai/code 0.9.9 → 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 +11 -0
- 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 +99 -39
- 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/copy-turn.test.ts +24 -1
- package/dist/extensions/copy-turn.ts +6 -1
- package/dist/extensions/handoff-new.test.ts +15 -2
- package/dist/extensions/handoff-new.ts +44 -30
- 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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@selesai/code` will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.9.11] - 2026-08-25
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Pi-compatible automatic skill discovery.** Skills under `~/.agents/skills/` and project/ancestor `.agents/skills/` directories, plus automatic skills from `.pi/skills/` and the Selesai agent skill directory, are now enabled by default — matching the Pi coding agent. Explicit `skills` patterns still control overrides and exclusions.
|
|
9
|
+
|
|
10
|
+
## [0.9.10] - 2026-08-25
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Handoff from RPC hosts.** `/handoff-new` now generates and starts a child session in RPC/non-TUI hosts such as VS Code instead of requiring the terminal loader.
|
|
14
|
+
- **Terminal copy markers.** The `copy-turn` extension now adds its `/cp` markers only in the TUI, preventing terminal-only transcript rows from leaking into RPC host conversations and handoffs.
|
|
15
|
+
|
|
5
16
|
## [0.9.9] - 2026-08-25
|
|
6
17
|
|
|
7
18
|
### Fixed
|
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) => {
|
|
@@ -350,10 +353,9 @@ export class AgentSession {
|
|
|
350
353
|
if (this._autoHandoffTriggered)
|
|
351
354
|
return;
|
|
352
355
|
this._autoHandoffTriggered = true;
|
|
353
|
-
// handoff-
|
|
354
|
-
//
|
|
355
|
-
//
|
|
356
|
-
// reliable. Default "print" only applies before extensions are bound.
|
|
356
|
+
// Auto-handoff is TUI-only: it runs at agent_settled, and headless/print
|
|
357
|
+
// modes should not churn sessions on their own. The handoff-new command
|
|
358
|
+
// itself now also works in non-TUI modes (direct generation, no loader).
|
|
357
359
|
if (this._extensionMode !== "tui")
|
|
358
360
|
return;
|
|
359
361
|
const command = this._extensionRunner.getCommand("handoff-new");
|
|
@@ -1436,16 +1438,17 @@ export class AgentSession {
|
|
|
1436
1438
|
* Validates that auth is configured, saves to session and settings.
|
|
1437
1439
|
* @throws Error if no auth is configured for the model
|
|
1438
1440
|
*/
|
|
1439
|
-
async setModel(model) {
|
|
1441
|
+
async setModel(model, options = {}) {
|
|
1440
1442
|
if (!(await this._modelRuntime.checkAuth(model.provider))) {
|
|
1441
1443
|
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
|
1442
1444
|
}
|
|
1443
1445
|
const previousModel = this.model;
|
|
1444
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1446
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(model);
|
|
1445
1447
|
this.agent.state.model = model;
|
|
1446
1448
|
this.sessionManager.appendModelChange(model.provider, model.id);
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
+
if (options.persist) {
|
|
1450
|
+
this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
1451
|
+
}
|
|
1449
1452
|
this.setThinkingLevel(thinkingLevel);
|
|
1450
1453
|
await this._emitModelSelect(model, previousModel, "set");
|
|
1451
1454
|
}
|
|
@@ -1455,13 +1458,13 @@ export class AgentSession {
|
|
|
1455
1458
|
* @param direction - "forward" (default) or "backward"
|
|
1456
1459
|
* @returns The new model info, or undefined if only one model available
|
|
1457
1460
|
*/
|
|
1458
|
-
async cycleModel(direction = "forward") {
|
|
1461
|
+
async cycleModel(direction = "forward", options = {}) {
|
|
1459
1462
|
if (this._scopedModels.length > 0) {
|
|
1460
|
-
return this._cycleScopedModel(direction);
|
|
1463
|
+
return this._cycleScopedModel(direction, options);
|
|
1461
1464
|
}
|
|
1462
|
-
return this._cycleAvailableModel(direction);
|
|
1465
|
+
return this._cycleAvailableModel(direction, options);
|
|
1463
1466
|
}
|
|
1464
|
-
async _cycleScopedModel(direction) {
|
|
1467
|
+
async _cycleScopedModel(direction, options) {
|
|
1465
1468
|
const checks = await Promise.all(this._scopedModels.map(async (scoped) => ({
|
|
1466
1469
|
scoped,
|
|
1467
1470
|
auth: await this._modelRuntime.checkAuth(scoped.model.provider),
|
|
@@ -1476,11 +1479,13 @@ export class AgentSession {
|
|
|
1476
1479
|
const len = scopedModels.length;
|
|
1477
1480
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1478
1481
|
const next = scopedModels[nextIndex];
|
|
1479
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
|
|
1482
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(next.model, next.thinkingLevel);
|
|
1480
1483
|
// Apply model
|
|
1481
1484
|
this.agent.state.model = next.model;
|
|
1482
1485
|
this.sessionManager.appendModelChange(next.model.provider, next.model.id);
|
|
1483
|
-
|
|
1486
|
+
if (options.persist) {
|
|
1487
|
+
this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
|
|
1488
|
+
}
|
|
1484
1489
|
// Apply thinking level.
|
|
1485
1490
|
// - Explicit scoped model thinking level overrides current session level
|
|
1486
1491
|
// - Undefined scoped model thinking level inherits the current session preference
|
|
@@ -1489,7 +1494,7 @@ export class AgentSession {
|
|
|
1489
1494
|
await this._emitModelSelect(next.model, currentModel, "cycle");
|
|
1490
1495
|
return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
|
|
1491
1496
|
}
|
|
1492
|
-
async _cycleAvailableModel(direction) {
|
|
1497
|
+
async _cycleAvailableModel(direction, options) {
|
|
1493
1498
|
const availableModels = await this._modelRuntime.getAvailable();
|
|
1494
1499
|
if (availableModels.length <= 1)
|
|
1495
1500
|
return undefined;
|
|
@@ -1500,10 +1505,12 @@ export class AgentSession {
|
|
|
1500
1505
|
const len = availableModels.length;
|
|
1501
1506
|
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
|
1502
1507
|
const nextModel = availableModels[nextIndex];
|
|
1503
|
-
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
|
1508
|
+
const thinkingLevel = this._getThinkingLevelForModelSwitch(nextModel);
|
|
1504
1509
|
this.agent.state.model = nextModel;
|
|
1505
1510
|
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
|
1506
|
-
|
|
1511
|
+
if (options.persist) {
|
|
1512
|
+
this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
|
|
1513
|
+
}
|
|
1507
1514
|
// Re-clamp thinking level for new model's capabilities
|
|
1508
1515
|
this.setThinkingLevel(thinkingLevel);
|
|
1509
1516
|
await this._emitModelSelect(nextModel, currentModel, "cycle");
|
|
@@ -1517,18 +1524,18 @@ export class AgentSession {
|
|
|
1517
1524
|
* Clamps to model capabilities based on available thinking levels.
|
|
1518
1525
|
* Saves to session and settings only if the level actually changes.
|
|
1519
1526
|
*/
|
|
1520
|
-
setThinkingLevel(level) {
|
|
1527
|
+
setThinkingLevel(level, options = {}) {
|
|
1521
1528
|
const availableLevels = this.getAvailableThinkingLevels();
|
|
1522
1529
|
const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);
|
|
1523
1530
|
// Only persist if actually changing
|
|
1524
1531
|
const previousLevel = this.agent.state.thinkingLevel;
|
|
1525
1532
|
const isChanging = effectiveLevel !== previousLevel;
|
|
1526
1533
|
this.agent.state.thinkingLevel = effectiveLevel;
|
|
1534
|
+
if (options.persist) {
|
|
1535
|
+
this.settingsManager.setDefaultThinkingLevel(level);
|
|
1536
|
+
}
|
|
1527
1537
|
if (isChanging) {
|
|
1528
1538
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
1529
|
-
if (this.supportsThinking() || effectiveLevel !== "off") {
|
|
1530
|
-
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
|
1531
|
-
}
|
|
1532
1539
|
this._emit({ type: "thinking_level_changed", level: effectiveLevel });
|
|
1533
1540
|
void this._extensionRunner.emit({
|
|
1534
1541
|
type: "thinking_level_select",
|
|
@@ -1541,14 +1548,14 @@ export class AgentSession {
|
|
|
1541
1548
|
* Cycle to next thinking level.
|
|
1542
1549
|
* @returns New level, or undefined if model doesn't support thinking
|
|
1543
1550
|
*/
|
|
1544
|
-
cycleThinkingLevel() {
|
|
1551
|
+
cycleThinkingLevel(options = {}) {
|
|
1545
1552
|
if (!this.supportsThinking())
|
|
1546
1553
|
return undefined;
|
|
1547
1554
|
const levels = this.getAvailableThinkingLevels();
|
|
1548
1555
|
const currentIndex = levels.indexOf(this.thinkingLevel);
|
|
1549
1556
|
const nextIndex = (currentIndex + 1) % levels.length;
|
|
1550
1557
|
const nextLevel = levels[nextIndex];
|
|
1551
|
-
this.setThinkingLevel(nextLevel);
|
|
1558
|
+
this.setThinkingLevel(nextLevel, options);
|
|
1552
1559
|
return nextLevel;
|
|
1553
1560
|
}
|
|
1554
1561
|
/**
|
|
@@ -1557,7 +1564,7 @@ export class AgentSession {
|
|
|
1557
1564
|
*/
|
|
1558
1565
|
getAvailableThinkingLevels() {
|
|
1559
1566
|
if (!this.model)
|
|
1560
|
-
return
|
|
1567
|
+
return [...THINKING_LEVEL_OPTIONS];
|
|
1561
1568
|
return getSupportedThinkingLevels(this.model);
|
|
1562
1569
|
}
|
|
1563
1570
|
/**
|
|
@@ -1566,14 +1573,16 @@ export class AgentSession {
|
|
|
1566
1573
|
supportsThinking() {
|
|
1567
1574
|
return !!this.model?.reasoning;
|
|
1568
1575
|
}
|
|
1569
|
-
_getThinkingLevelForModelSwitch(explicitLevel) {
|
|
1576
|
+
_getThinkingLevelForModelSwitch(targetModel, explicitLevel) {
|
|
1570
1577
|
if (explicitLevel !== undefined) {
|
|
1571
1578
|
return explicitLevel;
|
|
1572
1579
|
}
|
|
1573
|
-
if (
|
|
1574
|
-
|
|
1580
|
+
if (targetModel) {
|
|
1581
|
+
const perModel = this.settingsManager.getModelThinkingLevel(targetModel.provider, targetModel.id);
|
|
1582
|
+
if (perModel !== undefined)
|
|
1583
|
+
return perModel;
|
|
1575
1584
|
}
|
|
1576
|
-
return this.thinkingLevel;
|
|
1585
|
+
return this.settingsManager.getDefaultThinkingLevel() ?? this.thinkingLevel ?? DEFAULT_THINKING_LEVEL;
|
|
1577
1586
|
}
|
|
1578
1587
|
_clampThinkingLevel(level, _availableLevels) {
|
|
1579
1588
|
return this.model ? clampThinkingLevel(this.model, level) : "off";
|
|
@@ -1711,13 +1720,21 @@ export class AgentSession {
|
|
|
1711
1720
|
catch (error) {
|
|
1712
1721
|
const message = error instanceof Error ? error.message : String(error);
|
|
1713
1722
|
const aborted = message === "Compaction cancelled" || (error instanceof Error && error.name === "AbortError");
|
|
1723
|
+
const errorMessage = aborted ? undefined : `Compaction failed: ${message}`;
|
|
1714
1724
|
this._emit({
|
|
1715
1725
|
type: "compaction_end",
|
|
1716
1726
|
reason: "manual",
|
|
1717
1727
|
result: undefined,
|
|
1718
1728
|
aborted,
|
|
1719
1729
|
willRetry: false,
|
|
1720
|
-
errorMessage
|
|
1730
|
+
errorMessage,
|
|
1731
|
+
});
|
|
1732
|
+
await this._emitSessionCompactFailed({
|
|
1733
|
+
reason: "manual",
|
|
1734
|
+
errorMessage,
|
|
1735
|
+
aborted,
|
|
1736
|
+
willRetry: false,
|
|
1737
|
+
fromExtension: false,
|
|
1721
1738
|
});
|
|
1722
1739
|
throw error;
|
|
1723
1740
|
}
|
|
@@ -1836,6 +1853,7 @@ export class AgentSession {
|
|
|
1836
1853
|
async _runAutoCompaction(reason, willRetry) {
|
|
1837
1854
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1838
1855
|
let started = false;
|
|
1856
|
+
let fromExtension = false;
|
|
1839
1857
|
try {
|
|
1840
1858
|
if (!this.model) {
|
|
1841
1859
|
return false;
|
|
@@ -1858,7 +1876,6 @@ export class AgentSession {
|
|
|
1858
1876
|
this._autoCompactionAbortController = new AbortController();
|
|
1859
1877
|
started = true;
|
|
1860
1878
|
let extensionCompaction;
|
|
1861
|
-
let fromExtension = false;
|
|
1862
1879
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
1863
1880
|
const extensionResult = (await this._extensionRunner.emit({
|
|
1864
1881
|
type: "session_before_compact",
|
|
@@ -1877,6 +1894,7 @@ export class AgentSession {
|
|
|
1877
1894
|
aborted: true,
|
|
1878
1895
|
willRetry: false,
|
|
1879
1896
|
});
|
|
1897
|
+
await this._emitSessionCompactFailed({ reason, aborted: true, willRetry: false, fromExtension: false });
|
|
1880
1898
|
return false;
|
|
1881
1899
|
}
|
|
1882
1900
|
if (extensionResult?.compaction) {
|
|
@@ -1914,6 +1932,7 @@ export class AgentSession {
|
|
|
1914
1932
|
aborted: true,
|
|
1915
1933
|
willRetry: false,
|
|
1916
1934
|
});
|
|
1935
|
+
await this._emitSessionCompactFailed({ reason, aborted: true, willRetry: false, fromExtension });
|
|
1917
1936
|
return false;
|
|
1918
1937
|
}
|
|
1919
1938
|
this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
|
|
@@ -1956,15 +1975,23 @@ export class AgentSession {
|
|
|
1956
1975
|
catch (error) {
|
|
1957
1976
|
const errorMessage = error instanceof Error ? error.message : "compaction failed";
|
|
1958
1977
|
if (started) {
|
|
1978
|
+
const formattedErrorMessage = reason === "overflow"
|
|
1979
|
+
? `Context overflow recovery failed: ${errorMessage}`
|
|
1980
|
+
: `Auto-compaction failed: ${errorMessage}`;
|
|
1959
1981
|
this._emit({
|
|
1960
1982
|
type: "compaction_end",
|
|
1961
1983
|
reason,
|
|
1962
1984
|
result: undefined,
|
|
1963
1985
|
aborted: false,
|
|
1964
1986
|
willRetry: false,
|
|
1965
|
-
errorMessage:
|
|
1966
|
-
|
|
1967
|
-
|
|
1987
|
+
errorMessage: formattedErrorMessage,
|
|
1988
|
+
});
|
|
1989
|
+
await this._emitSessionCompactFailed({
|
|
1990
|
+
reason,
|
|
1991
|
+
errorMessage: formattedErrorMessage,
|
|
1992
|
+
aborted: false,
|
|
1993
|
+
willRetry: false,
|
|
1994
|
+
fromExtension,
|
|
1968
1995
|
});
|
|
1969
1996
|
}
|
|
1970
1997
|
return false;
|
|
@@ -2188,6 +2215,39 @@ export class AgentSession {
|
|
|
2188
2215
|
},
|
|
2189
2216
|
});
|
|
2190
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
|
+
}
|
|
2191
2251
|
_refreshToolRegistry(options) {
|
|
2192
2252
|
const previousRegistryNames = new Set(this._toolRegistry.keys());
|
|
2193
2253
|
const previousActiveToolNames = this.getActiveToolNames();
|
|
@@ -2292,6 +2352,7 @@ export class AgentSession {
|
|
|
2292
2352
|
bash: { commandPrefix: shellCommandPrefix, shellPath },
|
|
2293
2353
|
});
|
|
2294
2354
|
this._baseToolDefinitions = new Map(Object.entries(baseToolDefinitions).map(([name, tool]) => [name, tool]));
|
|
2355
|
+
this._baseToolDefinitions.set("tool_catalog", this._createToolCatalogDefinition());
|
|
2295
2356
|
const extensionsResult = this._resourceLoader.getExtensions();
|
|
2296
2357
|
if (options.flagValues) {
|
|
2297
2358
|
for (const [name, value] of options.flagValues) {
|
|
@@ -2306,7 +2367,7 @@ export class AgentSession {
|
|
|
2306
2367
|
this._applyExtensionBindings(this._extensionRunner);
|
|
2307
2368
|
const defaultActiveToolNames = this._baseToolsOverride
|
|
2308
2369
|
? Object.keys(this._baseToolsOverride)
|
|
2309
|
-
: ["read", "bash", "edit", "write"];
|
|
2370
|
+
: ["read", "bash", "edit", "write", "tool_catalog"];
|
|
2310
2371
|
const baseActiveToolNames = options.activeToolNames ?? defaultActiveToolNames;
|
|
2311
2372
|
this._refreshToolRegistry({
|
|
2312
2373
|
activeToolNames: baseActiveToolNames,
|
|
@@ -2323,7 +2384,6 @@ export class AgentSession {
|
|
|
2323
2384
|
this._buildRuntime({
|
|
2324
2385
|
activeToolNames: this.getActiveToolNames(),
|
|
2325
2386
|
flagValues: previousFlagValues,
|
|
2326
|
-
includeAllExtensionTools: true,
|
|
2327
2387
|
});
|
|
2328
2388
|
const hasBindings = this._extensionUIContext ||
|
|
2329
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.
|