@oh-my-pi/pi-coding-agent 15.10.9 → 15.10.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 +117 -0
- package/dist/cli.js +23087 -0
- package/dist/tokenizers.linux-x64-gnu-xcjh3jwk.node +0 -0
- package/dist/types/async/job-manager.d.ts +18 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/dry-balance-cli.d.ts +1 -1
- package/dist/types/cli/gallery-cli.d.ts +1 -1
- package/dist/types/cli/gallery-fixtures/types.d.ts +1 -1
- package/dist/types/cli/usage-cli.d.ts +72 -0
- package/dist/types/commands/launch.d.ts +1 -1
- package/dist/types/commands/read.d.ts +1 -1
- package/dist/types/commands/usage.d.ts +25 -0
- package/dist/types/config/append-only-context-mode.d.ts +2 -1
- package/dist/types/config/model-discovery.d.ts +55 -0
- package/dist/types/config/model-registry.d.ts +20 -219
- package/dist/types/config/model-resolver.d.ts +16 -10
- package/dist/types/config/model-roles.d.ts +28 -0
- package/dist/types/config/models-config-schema.d.ts +523 -42
- package/dist/types/config/models-config.d.ts +385 -0
- package/dist/types/config/settings-schema.d.ts +12 -16
- package/dist/types/config/settings.d.ts +1 -1
- package/dist/types/debug/log-viewer.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +1 -1
- package/dist/types/debug/terminal-info.d.ts +0 -1
- package/dist/types/eval/backend.d.ts +0 -2
- package/dist/types/eval/idle-timeout.d.ts +0 -4
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/types.d.ts +3 -3
- package/dist/types/hindsight/mental-models.d.ts +17 -8
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/lsp/edits.d.ts +9 -0
- package/dist/types/lsp/index.d.ts +2 -2
- package/dist/types/lsp/types.d.ts +2 -0
- package/dist/types/lsp/utils.d.ts +3 -0
- package/dist/types/mcp/json-rpc.d.ts +5 -0
- package/dist/types/mnemopi/state.d.ts +11 -1
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/bash-execution.d.ts +1 -1
- package/dist/types/modes/components/copy-selector.d.ts +1 -1
- package/dist/types/modes/components/dynamic-border.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-list.d.ts +1 -1
- package/dist/types/modes/components/extensions/inspector-panel.d.ts +1 -1
- package/dist/types/modes/components/footer.d.ts +1 -1
- package/dist/types/modes/components/hook-editor.d.ts +5 -0
- package/dist/types/modes/components/hook-input.d.ts +4 -0
- package/dist/types/modes/components/hook-selector.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-review-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-observer-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/component.d.ts +1 -1
- package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
- package/dist/types/modes/components/transcript-container.d.ts +31 -26
- package/dist/types/modes/components/tree-selector.d.ts +1 -1
- package/dist/types/modes/components/user-message-selector.d.ts +1 -1
- package/dist/types/modes/components/user-message.d.ts +2 -1
- package/dist/types/modes/components/visual-truncate.d.ts +1 -1
- package/dist/types/modes/components/welcome.d.ts +19 -3
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/auth-broker-config.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +1 -1
- package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
- package/dist/types/ssh/connection-manager.d.ts +8 -0
- package/dist/types/task/discovery.d.ts +1 -2
- package/dist/types/task/parallel.d.ts +2 -2
- package/dist/types/task/worktree.d.ts +2 -0
- package/dist/types/tiny/title-client.d.ts +1 -1
- package/dist/types/tools/ask.d.ts +4 -0
- package/dist/types/tools/conflict-detect.d.ts +16 -0
- package/dist/types/tools/github-cache.d.ts +7 -0
- package/dist/types/tools/sqlite-reader.d.ts +3 -0
- package/dist/types/tools/todo.d.ts +2 -0
- package/dist/types/tui/output-block.d.ts +3 -3
- package/dist/types/utils/changelog.d.ts +8 -0
- package/dist/types/web/scrapers/readthedocs.d.ts +3 -0
- package/dist/types/web/scrapers/types.d.ts +12 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -1
- package/dist/types/web/search/providers/gemini.d.ts +1 -1
- package/examples/extensions/tools.ts +5 -4
- package/package.json +14 -11
- package/scripts/build-binary.ts +18 -23
- package/scripts/bundle-dist.ts +81 -0
- package/scripts/{dev-launch → omp} +1 -1
- package/scripts/{dev-launch-preload.ts → omp.ts} +1 -1
- package/src/async/job-manager.ts +57 -3
- package/src/autoresearch/dashboard.ts +1 -1
- package/src/autoresearch/prompt-setup.md +6 -6
- package/src/autoresearch/prompt.md +6 -6
- package/src/capability/fs.ts +10 -0
- package/src/cli/args.ts +1 -1
- package/src/cli/auth-gateway-cli.ts +1 -3
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/gallery-fixtures/fs.ts +1 -1
- package/src/cli/gallery-fixtures/types.ts +5 -1
- package/src/cli/list-models.ts +7 -12
- package/src/cli/usage-cli.ts +603 -0
- package/src/cli-commands.ts +1 -0
- package/src/cli.ts +69 -5
- package/src/commands/complete.ts +1 -1
- package/src/commands/launch.ts +1 -1
- package/src/commands/read.ts +6 -3
- package/src/commands/usage.ts +35 -0
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/model-selection.ts +1 -1
- package/src/config/append-only-context-mode.ts +6 -12
- package/src/config/model-discovery.ts +554 -0
- package/src/config/model-registry.ts +308 -1025
- package/src/config/model-resolver.ts +113 -156
- package/src/config/model-roles.ts +74 -0
- package/src/config/models-config-schema.ts +57 -8
- package/src/config/models-config.ts +129 -0
- package/src/config/settings-schema.ts +18 -14
- package/src/config/settings.ts +37 -1
- package/src/dap/client.ts +124 -37
- package/src/dap/session.ts +259 -158
- package/src/debug/log-viewer.ts +1 -1
- package/src/debug/raw-sse.ts +1 -1
- package/src/debug/terminal-info.ts +0 -3
- package/src/edit/diff.ts +95 -18
- package/src/edit/hashline/block-resolver.ts +20 -1
- package/src/edit/hashline/diff.ts +36 -1
- package/src/edit/hashline/execute.ts +8 -2
- package/src/edit/index.ts +16 -1
- package/src/edit/modes/patch.ts +52 -0
- package/src/edit/modes/replace.ts +56 -22
- package/src/edit/notebook.ts +22 -2
- package/src/edit/renderer.ts +36 -10
- package/src/eval/__tests__/completion-bridge.test.ts +1 -1
- package/src/eval/backend.ts +0 -2
- package/src/eval/completion-bridge.ts +2 -1
- package/src/eval/idle-timeout.ts +2 -9
- package/src/eval/js/context-manager.ts +6 -8
- package/src/eval/js/executor.ts +6 -2
- package/src/eval/js/index.ts +0 -2
- package/src/eval/js/shared/helpers.ts +5 -6
- package/src/eval/js/shared/local-module-loader.ts +1 -1
- package/src/eval/js/shared/prelude.txt +62 -1
- package/src/eval/js/shared/rewrite-imports.ts +49 -23
- package/src/eval/js/shared/runtime.ts +1 -1
- package/src/eval/py/index.ts +0 -2
- package/src/eval/py/kernel.ts +19 -0
- package/src/eval/py/runner.py +107 -3
- package/src/exec/bash-executor.ts +3 -1
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +3 -1
- package/src/extensibility/extensions/types.ts +3 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +20 -3
- package/src/hindsight/mental-models.ts +59 -12
- package/src/hindsight/state.ts +6 -1
- package/src/internal-urls/artifact-protocol.ts +11 -2
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/internal-urls/issue-pr-protocol.ts +12 -5
- package/src/internal-urls/router.ts +1 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/lib/xai-http.ts +1 -1
- package/src/lsp/client.ts +118 -38
- package/src/lsp/clients/biome-client.ts +101 -39
- package/src/lsp/edits.ts +143 -95
- package/src/lsp/index.ts +31 -22
- package/src/lsp/render.ts +1 -1
- package/src/lsp/types.ts +2 -0
- package/src/lsp/utils.ts +28 -10
- package/src/main.ts +165 -17
- package/src/mcp/json-rpc.ts +35 -5
- package/src/mcp/transports/stdio.ts +7 -1
- package/src/memories/index.ts +2 -1
- package/src/mnemopi/backend.ts +25 -3
- package/src/mnemopi/state.ts +38 -2
- package/src/modes/components/agent-dashboard.ts +10 -7
- package/src/modes/components/assistant-message.ts +19 -13
- package/src/modes/components/bash-execution.ts +1 -1
- package/src/modes/components/copy-selector.ts +1 -1
- package/src/modes/components/diff.ts +13 -2
- package/src/modes/components/dynamic-border.ts +12 -3
- package/src/modes/components/extensions/extension-dashboard.ts +8 -5
- package/src/modes/components/extensions/extension-list.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +1 -1
- package/src/modes/components/footer.ts +1 -1
- package/src/modes/components/history-search.ts +1 -1
- package/src/modes/components/hook-editor.ts +8 -0
- package/src/modes/components/hook-input.ts +8 -0
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/model-selector.ts +66 -54
- package/src/modes/components/plan-review-overlay.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +2 -2
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/settings-selector.ts +5 -1
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/tiny-title-download-progress.ts +1 -1
- package/src/modes/components/transcript-container.ts +373 -141
- package/src/modes/components/tree-selector.ts +3 -3
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +17 -5
- package/src/modes/components/visual-truncate.ts +1 -1
- package/src/modes/components/welcome.ts +108 -26
- package/src/modes/controllers/command-controller.ts +10 -3
- package/src/modes/controllers/event-controller.ts +73 -49
- package/src/modes/controllers/input-controller.ts +5 -5
- package/src/modes/controllers/mcp-command-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +1 -5
- package/src/modes/controllers/streaming-reveal.ts +85 -18
- package/src/modes/interactive-mode.ts +5 -19
- package/src/modes/setup-wizard/scenes/glyph.ts +1 -1
- package/src/modes/setup-wizard/scenes/providers.ts +1 -1
- package/src/modes/setup-wizard/scenes/sign-in.ts +1 -1
- package/src/modes/setup-wizard/scenes/theme.ts +1 -1
- package/src/modes/setup-wizard/scenes/types.ts +1 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +1 -1
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/types.ts +2 -1
- package/src/prompts/agents/explore.md +2 -2
- package/src/prompts/agents/librarian.md +1 -2
- package/src/prompts/agents/oracle.md +1 -1
- package/src/prompts/agents/plan.md +5 -5
- package/src/prompts/agents/task.md +5 -5
- package/src/prompts/ci-green-request.md +5 -7
- package/src/prompts/goals/goal-budget-limit.md +2 -2
- package/src/prompts/goals/goal-continuation.md +4 -4
- package/src/prompts/goals/goal-mode-active.md +1 -1
- package/src/prompts/memories/read-path.md +1 -1
- package/src/prompts/memories/stage_one_system.md +2 -2
- package/src/prompts/review-custom-request.md +1 -1
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/auto-continue.md +1 -1
- package/src/prompts/system/background-tan-dispatch.md +1 -1
- package/src/prompts/system/btw-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +13 -1
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/eager-todo.md +2 -2
- package/src/prompts/system/irc-incoming.md +1 -1
- package/src/prompts/system/manual-continue.md +1 -1
- package/src/prompts/system/omfg-user.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +9 -9
- package/src/prompts/system/plan-mode-active.md +4 -4
- package/src/prompts/system/plan-mode-subagent.md +4 -5
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +1 -1
- package/src/prompts/system/project-prompt.md +2 -2
- package/src/prompts/system/subagent-system-prompt.md +4 -4
- package/src/prompts/system/system-prompt.md +15 -26
- package/src/prompts/system/title-system.md +2 -2
- package/src/prompts/system/ttsr-tool-reminder.md +1 -1
- package/src/prompts/system/workflow-notice.md +1 -1
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +2 -2
- package/src/prompts/tools/bash.md +8 -10
- package/src/prompts/tools/browser.md +7 -7
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/eval.md +3 -3
- package/src/prompts/tools/find.md +0 -1
- package/src/prompts/tools/github.md +8 -7
- package/src/prompts/tools/goal.md +1 -1
- package/src/prompts/tools/image-gen.md +1 -1
- package/src/prompts/tools/inspect-image-system.md +1 -1
- package/src/prompts/tools/irc.md +15 -15
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/read.md +3 -4
- package/src/prompts/tools/recall.md +1 -1
- package/src/prompts/tools/reflect.md +1 -1
- package/src/prompts/tools/render-mermaid.md +2 -2
- package/src/prompts/tools/replace.md +4 -10
- package/src/prompts/tools/rewind.md +2 -2
- package/src/prompts/tools/search-tool-bm25.md +1 -9
- package/src/prompts/tools/search.md +0 -1
- package/src/prompts/tools/ssh.md +0 -4
- package/src/prompts/tools/task.md +2 -3
- package/src/prompts/tools/todo.md +6 -2
- package/src/sdk.ts +23 -10
- package/src/session/agent-session.ts +44 -10
- package/src/session/auth-broker-config.ts +30 -1
- package/src/session/session-manager.ts +2 -2
- package/src/session/streaming-output.ts +23 -2
- package/src/slash-commands/builtin-registry.ts +20 -0
- package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
- package/src/ssh/connection-manager.ts +27 -0
- package/src/task/commands.ts +2 -1
- package/src/task/discovery.ts +17 -24
- package/src/task/executor.ts +61 -53
- package/src/task/index.ts +137 -60
- package/src/task/parallel.ts +3 -3
- package/src/task/render.ts +2 -2
- package/src/task/worktree.ts +64 -56
- package/src/thinking.ts +2 -1
- package/src/tiny/title-client.ts +32 -14
- package/src/tools/archive-reader.ts +30 -2
- package/src/tools/ask.ts +104 -21
- package/src/tools/ast-edit.ts +25 -5
- package/src/tools/auto-generated-guard.ts +20 -3
- package/src/tools/bash-interactive.ts +27 -7
- package/src/tools/bash.ts +54 -13
- package/src/tools/browser/launch.ts +11 -2
- package/src/tools/browser/readable.ts +19 -2
- package/src/tools/browser/registry.ts +4 -1
- package/src/tools/browser/render.ts +2 -2
- package/src/tools/browser/tab-supervisor.ts +55 -16
- package/src/tools/conflict-detect.ts +50 -4
- package/src/tools/debug.ts +1 -1
- package/src/tools/eval-render.ts +5 -5
- package/src/tools/eval.ts +0 -2
- package/src/tools/fetch.ts +33 -10
- package/src/tools/gh-cache-invalidation.ts +63 -8
- package/src/tools/gh-renderer.ts +1 -1
- package/src/tools/gh.ts +172 -29
- package/src/tools/github-cache.ts +70 -6
- package/src/tools/image-gen.ts +3 -9
- package/src/tools/irc.ts +5 -1
- package/src/tools/job.ts +1 -1
- package/src/tools/read.ts +202 -61
- package/src/tools/render-utils.ts +3 -3
- package/src/tools/resolve.ts +1 -1
- package/src/tools/search.ts +92 -29
- package/src/tools/sqlite-reader.ts +17 -5
- package/src/tools/ssh.ts +8 -8
- package/src/tools/todo.ts +51 -12
- package/src/tools/write.ts +118 -18
- package/src/tui/output-block.ts +4 -4
- package/src/utils/changelog.ts +27 -1
- package/src/utils/file-mentions.ts +2 -1
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +1 -1
- package/src/web/scrapers/twitter.ts +2 -1
- package/src/web/scrapers/types.ts +87 -8
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/scrapers/youtube.ts +6 -1
- package/src/web/search/index.ts +1 -1
- package/src/web/search/providers/anthropic.ts +8 -2
- package/src/web/search/providers/codex.ts +2 -1
- package/src/web/search/providers/gemini.ts +2 -3
- package/src/web/search/render.ts +8 -6
- package/dist/types/config/model-equivalence.d.ts +0 -24
- package/dist/types/config/model-id-affixes.d.ts +0 -12
- package/dist/types/config/model-provider-priority.d.ts +0 -1
- package/dist/types/exec/idle-timeout-watchdog.d.ts +0 -18
- package/src/config/model-equivalence.ts +0 -875
- package/src/config/model-id-affixes.ts +0 -81
- package/src/config/model-provider-priority.ts +0 -56
- package/src/exec/idle-timeout-watchdog.ts +0 -126
package/src/prompts/tools/irc.md
CHANGED
|
@@ -4,30 +4,30 @@ Sends short text messages to other live agents in this process and receives thei
|
|
|
4
4
|
- The main agent is addressable as `Main`. Subagents reuse their task id (e.g. `AuthLoader`, or `AuthLoader-2` when the name repeats).
|
|
5
5
|
- `op: "list"` returns the current set of visible peers. Use it before sending if you are not sure who is live.
|
|
6
6
|
- `op: "send"` delivers `message` to `to`. `to` may be a specific id or `"all"` to broadcast.
|
|
7
|
-
-
|
|
8
|
-
- The exchange (
|
|
7
|
+
- Replies are generated on a side channel that does not wait for the recipient's main loop, so it is safe to IRC an agent that is mid tool call.
|
|
8
|
+
- The exchange (question + auto-reply) is injected into the recipient's history; they see it on their next turn and can follow up.
|
|
9
9
|
</instruction>
|
|
10
10
|
|
|
11
11
|
<when_to_use>
|
|
12
12
|
You SHOULD reach for `irc` proactively when continuing alone is wasteful or wrong. When in doubt, prefer messaging.
|
|
13
|
-
- **Unexpected state.**
|
|
14
|
-
- **Blocked by another agent.** A peer holds the file/branch/resource you need,
|
|
15
|
-
- **Decision points outside your scope.** A genuine fork
|
|
16
|
-
- **Coordination opportunities.**
|
|
13
|
+
- **Unexpected state.** The task did not describe what you found — missing file, config contradicting the assignment, API or tool behaving differently than told. DM `Main` (or the spawning agent) instead of guessing.
|
|
14
|
+
- **Blocked by another agent.** A peer holds the file/branch/resource you need, started the change you are about to make, or owns a decision you depend on. DM that peer (or broadcast to discover who) before duplicating work.
|
|
15
|
+
- **Decision points outside your scope.** A genuine fork the assignment did not pre-decide (e.g. which of two viable APIs, whether to refactor adjacent code). Ask the requester rather than picking unilaterally.
|
|
16
|
+
- **Coordination opportunities.** A peer's in-flight work would benefit from yours, or vice-versa.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
NEVER use `irc` for: routine progress updates, things a tool call can verify, or questions already answered by your assignment / repo / docs.
|
|
19
19
|
</when_to_use>
|
|
20
20
|
|
|
21
21
|
<etiquette>
|
|
22
22
|
These rules apply to both sending and replying.
|
|
23
|
-
- **Plain prose only.**
|
|
24
|
-
- **
|
|
25
|
-
- **Use IRC, not terminal tools, to learn about peers.**
|
|
26
|
-
- **One round-trip is enough.** Replies arrive synchronously when the recipient is reachable.
|
|
27
|
-
- **Stay terse.** A DM is a chat message, not a memo. One question per send
|
|
28
|
-
- **Address peers by id.** Use the exact id from `op: "list"` (e.g. `AuthLoader`, `Main`).
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
23
|
+
- **Plain prose only.** NEVER send structured JSON status payloads (e.g. `{"type":"task_completed",…}`). Write a normal sentence: "Done with the auth refactor — left a TODO in `src/server/auth.ts` for the rate limiter."
|
|
24
|
+
- **NEVER quote the message you are replying to.** Lead with the answer.
|
|
25
|
+
- **Use IRC, not terminal tools, to learn about peers.** NEVER `grep` artifacts, read other sessions' JSONL files, or shell-poke to figure out what another agent is doing. DM them.
|
|
26
|
+
- **One round-trip is enough.** Replies arrive synchronously when the recipient is reachable. NEVER follow up with "did you get my message?". If `delivered` is empty or the result was `failed`, the peer is unavailable — move on or report the blocker; NEVER retry in a loop.
|
|
27
|
+
- **Stay terse.** A DM is a chat message, not a memo. One question per send. Share file paths and artifacts via `local://` / `memory://` / `artifact://` URLs instead of pasting blobs.
|
|
28
|
+
- **Address peers by id.** Use the exact id from `op: "list"` (e.g. `AuthLoader`, `Main`). NEVER invent friendly names.
|
|
29
|
+
- **NEVER IRC for things a tool would answer.** If a `read`, `grep`, or build command resolves the question, do that first.
|
|
30
|
+
- **Answer incoming IRC messages before continuing.** Address the question directly; do not repeat it back to the user.
|
|
31
31
|
</etiquette>
|
|
32
32
|
|
|
33
33
|
<output>
|
package/src/prompts/tools/lsp.md
CHANGED
|
@@ -37,6 +37,6 @@ Interacts with Language Server Protocol servers for code intelligence.
|
|
|
37
37
|
|
|
38
38
|
<critical>
|
|
39
39
|
- You MUST use `lsp` for symbol-aware operations (rename, find references, go to definition/implementation, code actions) whenever a language server is available — it is safer and more accurate than text-based alternatives.
|
|
40
|
-
- You NEVER perform cross-file renames with `ast_edit`, `sed`,
|
|
41
|
-
-
|
|
40
|
+
- You NEVER perform cross-file renames with `ast_edit`, `sed`, or manual edits when `lsp` `rename` can do it. Text-based renames miss shadowing, re-exports, and usages in other files.
|
|
41
|
+
- You SHOULD use `lsp` `code_actions` for imports, quick-fixes, and refactors the language server already knows how to apply.
|
|
42
42
|
</critical>
|
|
@@ -5,7 +5,7 @@ Patches files given diff hunks. Primary tool for existing-file edits.
|
|
|
5
5
|
- `@@` — bare header when context lines unique
|
|
6
6
|
- `@@ $ANCHOR` — anchor copied verbatim from file (full line or unique substring)
|
|
7
7
|
**Anchor Selection:**
|
|
8
|
-
1.
|
|
8
|
+
1. Prefer bare `@@` when context lines alone are unique; otherwise choose highly specific anchor copied from file:
|
|
9
9
|
- full function signature
|
|
10
10
|
- class declaration
|
|
11
11
|
- unique string literal/error message
|
|
@@ -47,7 +47,7 @@ Returns success/failure; on failure, error message indicates:
|
|
|
47
47
|
- You NEVER use anchors as comments (no line numbers, location labels, placeholders like `@@ @@`)
|
|
48
48
|
- You NEVER place new lines outside the intended block
|
|
49
49
|
- If edit fails or breaks structure, you MUST re-read the file and produce a new patch from current content — you NEVER retry the same diff
|
|
50
|
-
- NEVER use edit to fix indentation, whitespace, or reformat code. Formatting is a single command run once at the end (`bun fmt`, `cargo fmt`, `prettier
|
|
50
|
+
- NEVER use edit to fix indentation, whitespace, or reformat code. Formatting is a single command run once at the end (`bun fmt`, `cargo fmt`, `prettier --write`, etc.) — not N individual edits. If you see inconsistent indentation after an edit, leave it; the formatter will fix all of it in one pass.
|
|
51
51
|
</critical>
|
|
52
52
|
|
|
53
53
|
<examples>
|
|
@@ -8,7 +8,7 @@ Read files, directories, archives, SQLite databases, images, documents, internal
|
|
|
8
8
|
|
|
9
9
|
## Parameters
|
|
10
10
|
|
|
11
|
-
- `path` — required. Local path, internal URI (`skill://`, `agent://`, `artifact://`, `memory://`, `rule://`, `local://`, `vault://`, `mcp://`), or URL. Append `:<sel>` for line ranges, raw mode, or special modes (e.g. `src/foo.ts:50-200`, `src/foo.ts:raw`, `db.sqlite:users:42`).
|
|
11
|
+
- `path` — required. Local path, internal URI (`skill://`, `agent://`, `artifact://`, `memory://`, `rule://`, `local://`, `vault://`, `mcp://`, `omp://`, `issue://`, `pr://`), or URL. Append `:<sel>` for line ranges, raw mode, or special modes (e.g. `src/foo.ts:50-200`, `src/foo.ts:raw`, `db.sqlite:users:42`).
|
|
12
12
|
|
|
13
13
|
## Selectors
|
|
14
14
|
|
|
@@ -74,12 +74,11 @@ For `.sqlite`, `.sqlite3`, `.db`, `.db3`:
|
|
|
74
74
|
|
|
75
75
|
# Internal URIs
|
|
76
76
|
|
|
77
|
-
`skill://<name>`, `agent://<id>`, `artifact://<id>`, `memory://root`, `rule://<name>`, `local://<name>.md`, `vault://<vault>/<path>`, `mcp://<uri>` resolve transparently and accept the same line selectors as filesystem paths. Use `artifact://<id>` to recover full output that a previous bash/eval/tool result spilled or truncated.
|
|
77
|
+
`skill://<name>`, `agent://<id>`, `artifact://<id>`, `memory://root`, `rule://<name>`, `local://<name>.md`, `vault://<vault>/<path>`, `mcp://<uri>`, `omp://<doc>.md`, `issue://<N>`, and `pr://<N>` resolve transparently and accept the same line selectors as filesystem paths. Use `artifact://<id>` to recover full output that a previous bash/eval/tool result spilled or truncated.
|
|
78
78
|
|
|
79
79
|
<critical>
|
|
80
80
|
- You MUST use `read` for every file, directory, archive, and URL inspection. `cat`, `head`, `tail`, `less`, `more`, `ls`, `tar`, `unzip`, `curl`, `wget` are FORBIDDEN — any such bash call is a bug, regardless of how short or convenient it looks.
|
|
81
81
|
- You MUST prefer `read` over a browser/puppeteer tool for URL content; only reach for a browser when `read` cannot deliver reasonable content.
|
|
82
82
|
- For line ranges, append the selector to `path` (`path="src/foo.ts:50-200"`, `path="src/foo.ts:50+150"`). NEVER substitute `sed -n`, `awk NR`, or `head`/`tail` pipelines.
|
|
83
|
-
- Summary footer
|
|
84
|
-
- You MAY combine selectors with URL reads and internal URIs; both paginate the cached resolved output.
|
|
83
|
+
- Summary footer names ranges to re-read? Re-issue ONLY the ranges you need via the multi-range selector. NEVER guess what's inside `..` / `…` markers — they carry no content.
|
|
85
84
|
</critical>
|
|
@@ -2,4 +2,4 @@ Search long-term memory for relevant information. Returns raw matching entries r
|
|
|
2
2
|
|
|
3
3
|
Use proactively — before answering questions about past conversations, user preferences, project decisions, or any topic where prior context would help accuracy. When in doubt, recall first.
|
|
4
4
|
|
|
5
|
-
Prefer `recall` when you need specific facts or entries. Use `reflect` instead when you need a
|
|
5
|
+
Prefer `recall` when you need specific facts or entries. Use `reflect` instead when you need a synthesized answer across many memories.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Generate a
|
|
1
|
+
Generate a synthesized answer by reasoning over long-term memory. Unlike `recall`, `reflect` blends relevant memories into a coherent response.
|
|
2
2
|
|
|
3
3
|
Use for open-ended questions spanning many stored facts: "What do you know about this user?", "Summarize project decisions.", "What are my preferences for X?"
|
|
4
4
|
|
|
@@ -3,7 +3,7 @@ Convert Mermaid graph source into ASCII diagram output.
|
|
|
3
3
|
Parameters:
|
|
4
4
|
- `mermaid` (required): Mermaid graph text to render.
|
|
5
5
|
- `config` (optional): JSON render configuration (spacing and layout options).
|
|
6
|
+
|
|
6
7
|
Behavior:
|
|
7
8
|
- Returns ASCII diagram text.
|
|
8
|
-
- Saves full output to `artifact://<id
|
|
9
|
-
- Returns error when Mermaid input invalid or rendering fails.
|
|
9
|
+
- Saves full output to `artifact://<id>`.
|
|
@@ -16,21 +16,15 @@ Returns success/failure status. On success, file modified in place with replacem
|
|
|
16
16
|
</critical>
|
|
17
17
|
|
|
18
18
|
<bash-alternatives>
|
|
19
|
-
Replace
|
|
19
|
+
Replace is content-addressed — you identify *what* to change by its text.
|
|
20
20
|
|
|
21
|
-
For
|
|
21
|
+
For pattern-addressed bulk changes, bash is more efficient:
|
|
22
22
|
|
|
23
23
|
|Operation|Command|
|
|
24
24
|
|---|---|
|
|
25
|
-
|Append to file|`cat >> file <<'EOF'`…`EOF`|
|
|
26
|
-
|Prepend to file|`{ cat - file; } <<'EOF' > tmp && mv tmp file`|
|
|
27
|
-
|Delete lines N-M|`sed -i 'N,Md' file`|
|
|
28
|
-
|Insert after line N|`sed -i 'Na\text' file`|
|
|
29
25
|
|Regex replace|`sd 'pattern' 'replacement' file`|
|
|
30
26
|
|Bulk replace across files|`sd 'pattern' 'replacement' **/*.ts`|
|
|
31
|
-
|Copy lines N-M to another file|`sed -n 'N,Mp' src >> dest`|
|
|
32
|
-
|Move lines N-M to another file|`sed -n 'N,Mp' src >> dest && sed -i 'N,Md' src`|
|
|
33
27
|
|
|
34
|
-
Use Replace when _content itself_ identifies location.
|
|
35
|
-
|
|
28
|
+
Use Replace when _content itself_ identifies location; use `ast_edit` for structure-aware codemods.
|
|
29
|
+
NEVER use `sed -i`/`perl -i`/heredoc redirection for edits — those calls are blocked; use this tool or `write`.
|
|
36
30
|
</bash-alternatives>
|
|
@@ -3,9 +3,9 @@ End an active checkpoint. Rewind context to it, replacing intermediate explorati
|
|
|
3
3
|
Call immediately after `checkpoint`-started investigative work.
|
|
4
4
|
|
|
5
5
|
Requirements:
|
|
6
|
-
- `report` is REQUIRED and
|
|
6
|
+
- `report` is REQUIRED and MUST be concise, factual, and actionable.
|
|
7
7
|
- Include key findings, decisions, and any unresolved risks.
|
|
8
|
-
-
|
|
8
|
+
- AVOID raw scratch logs unless essential.
|
|
9
9
|
- You MUST call this before yielding if a checkpoint is active.
|
|
10
10
|
|
|
11
11
|
Behavior:
|
|
@@ -15,21 +15,13 @@ Input:
|
|
|
15
15
|
- `limit` — optional maximum number of tools to return and activate (default `8`)
|
|
16
16
|
|
|
17
17
|
Behavior:
|
|
18
|
-
- Searches hidden tool metadata using BM25-style relevance ranking
|
|
19
18
|
- Matches against tool name, label, server name, description/summary, and input schema keys
|
|
20
19
|
- Activates the top matching tools for the rest of the current session
|
|
21
20
|
- Repeated searches add to the active tool set; they do not remove earlier selections
|
|
22
21
|
- Newly activated tools become available before the next model call in the same overall turn
|
|
23
22
|
|
|
24
23
|
Notes:
|
|
25
|
-
Start with `limit` 5–10 if unsure.
|
|
26
|
-
- `query` is matched against tool metadata fields:
|
|
27
|
-
- `name`
|
|
28
|
-
- `label`
|
|
29
|
-
- `server_name` (MCP tools)
|
|
30
|
-
- `mcp_tool_name` (MCP tools)
|
|
31
|
-
- `description` / `summary`
|
|
32
|
-
- input schema property keys (`schema_keys`)
|
|
24
|
+
- Start with `limit` 5–10 if unsure.
|
|
33
25
|
|
|
34
26
|
Not for repository/file/code search. Tool discovery only.
|
|
35
27
|
|
|
@@ -20,6 +20,5 @@ Searches files using powerful regex matching.
|
|
|
20
20
|
<critical>
|
|
21
21
|
- You MUST use the built-in `search` tool for any content search. NEVER shell out to `grep`, `rg`, `ripgrep`, `ag`, `ack`, `git grep`, `awk`, `sed`-for-search, or any other CLI search via Bash — even for a single match, even "just to check quickly", even piped through other commands.
|
|
22
22
|
- Bash `grep`/`rg` loses `.gitignore` semantics, bypasses result limits, and wastes tokens. The `search` tool is faster, structured, and already wired into the workspace — there is no scenario where Bash search is preferable.
|
|
23
|
-
- If you catch yourself typing `grep`, `rg`, or `| grep` in a Bash command, stop and re-issue the lookup through the `search` tool instead.
|
|
24
23
|
- If the search is open-ended, requiring multiple rounds, you MUST use the Task tool with the explore subagent instead of chaining `search` calls yourself.
|
|
25
24
|
</critical>
|
package/src/prompts/tools/ssh.md
CHANGED
|
@@ -31,10 +31,9 @@ Subagents have no conversation history. Every fact, file path, and direction the
|
|
|
31
31
|
|
|
32
32
|
<rules>
|
|
33
33
|
- **Maximize batch width.** Spawn the widest parallel set the work decomposes into. NEVER spawn a single-task batch for divisible work, or defer work that could have been concurrent.
|
|
34
|
-
-
|
|
35
|
-
- **Subagents do not verify, lint, or format.** Every assignment MUST instruct the subagent to skip all gates and formatters. You run them once at the end across the union of changed files — avoids redundant runs and racing formatter passes.
|
|
34
|
+
- **Subagents do not verify, lint, or format.** Every assignment MUST instruct the subagent to skip all gates, formatters, and project-wide build/test/lint. You run them once at the end across the union of changed files — avoids redundant runs and racing formatter passes.
|
|
36
35
|
- No globs, no "update all", no package-wide scope. Fan out.
|
|
37
|
-
-
|
|
36
|
+
- NEVER slow down or serialize because tasks might overlap on some files. Agents resolve collisions among themselves in real time.
|
|
38
37
|
- Pass large payloads via `local://<path>` URIs, not inline. {{#if contextEnabled}} (other than the context){{/if}}
|
|
39
38
|
{{#if contextEnabled}}- Put shared constraints in `context` once; do not duplicate across assignments.{{/if}}
|
|
40
39
|
- Prefer agents that investigate **and** edit in one pass; only spin a read-only discovery step when affected files are genuinely unknown.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Manages a phased task list. Pass `ops`: a flat array of operations.
|
|
4
4
|
The next pending task is auto-promoted to `in_progress` after each completion.
|
|
5
|
-
Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, and `
|
|
5
|
+
Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, `note`, and `view`. `pending` is a task status, not an `op`; leave not-yet-started tasks implicit in `init`/`append` lists.
|
|
6
6
|
|
|
7
7
|
## Operations
|
|
8
8
|
|
|
@@ -12,9 +12,10 @@ Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, an
|
|
|
12
12
|
|`start`|`task`|Mark in progress|
|
|
13
13
|
|`done`|`task` or `phase`|Mark completed|
|
|
14
14
|
|`drop`|`task` or `phase`|Mark abandoned|
|
|
15
|
-
|`rm`|`task` or `phase
|
|
15
|
+
|`rm`|`task` or `phase` (optional)|Remove task or phase's tasks; omit both to clear the entire list|
|
|
16
16
|
|`append`|`phase`, `items: string[]`|Append tasks to `phase`; lazily creates phase|
|
|
17
17
|
|`note`|`task`, `text`|Append a note to a task. Reminders for future-you only.|
|
|
18
|
+
|`view`|—|Read-only: echo the current list without modifying it|
|
|
18
19
|
|
|
19
20
|
## Anatomy
|
|
20
21
|
- **Task content**: 5–10 words, what is being done, not how. Used as the task identifier — unique.
|
|
@@ -25,6 +26,7 @@ Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, an
|
|
|
25
26
|
- Complete phases in order.
|
|
26
27
|
- On blockers, `append` a new task to the active phase to unblock yourself, or `drop`.
|
|
27
28
|
- `task` and `phase` fields reference content/name verbatim; keep them stable once introduced.
|
|
29
|
+
- Lost track of exact task text? `view` echoes the full list — NEVER guess content from memory; a mismatched `task` string is an error.
|
|
28
30
|
|
|
29
31
|
## When to create a list
|
|
30
32
|
- Task requires 3+ distinct steps
|
|
@@ -35,6 +37,8 @@ Allowed `op` values are only `init`, `start`, `done`, `drop`, `rm`, `append`, an
|
|
|
35
37
|
<examples>
|
|
36
38
|
# Initial setup (multi-phase)
|
|
37
39
|
`{"ops":[{"op":"init","list":[{"phase":"Foundation","items":["Scaffold crate","Wire workspace"]},{"phase":"Auth","items":["Port credential store","Wire OAuth providers"]},{"phase":"Verification","items":["Run cargo test"]}]}]}`
|
|
40
|
+
# View current state (read-only)
|
|
41
|
+
`{"ops":[{"op":"view"}]}`
|
|
38
42
|
# Initial setup (single phase)
|
|
39
43
|
`{"ops":[{"op":"init","list":[{"phase":"Implementation","items":["Apply fix","Run tests"]}]}]}`
|
|
40
44
|
# Complete one task
|
package/src/sdk.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
getOpenAICodexTransportDetails,
|
|
20
20
|
prewarmOpenAICodexResponses,
|
|
21
21
|
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
22
|
+
import { DEFAULT_MODEL_PER_PROVIDER } from "@oh-my-pi/pi-catalog/provider-models";
|
|
22
23
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
23
24
|
import {
|
|
24
25
|
$env,
|
|
@@ -41,7 +42,6 @@ import { createApiKeyResolver } from "./config/api-key-resolver";
|
|
|
41
42
|
import { shouldEnableAppendOnlyContext } from "./config/append-only-context-mode";
|
|
42
43
|
import { ModelRegistry } from "./config/model-registry";
|
|
43
44
|
import {
|
|
44
|
-
defaultModelPerProvider,
|
|
45
45
|
formatModelString,
|
|
46
46
|
getModelMatchPreferences,
|
|
47
47
|
parseModelPattern,
|
|
@@ -531,11 +531,18 @@ function resolveSnapshotTtlMs(): number {
|
|
|
531
531
|
* override to re-mint access tokens when needed.
|
|
532
532
|
*/
|
|
533
533
|
export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir()): Promise<AuthStorage> {
|
|
534
|
-
const
|
|
534
|
+
const brokerConfigPromise = resolveAuthBrokerConfig();
|
|
535
|
+
const cachePath = getAuthBrokerSnapshotCachePath();
|
|
536
|
+
// Warm the encrypted snapshot cache into the page cache while the broker
|
|
537
|
+
// config resolves (it may shell out for a `!command` token). Decryption
|
|
538
|
+
// needs the resolved token, so the real cache read cannot start earlier.
|
|
539
|
+
void Bun.file(cachePath)
|
|
540
|
+
.arrayBuffer()
|
|
541
|
+
.catch(() => undefined);
|
|
542
|
+
const brokerConfig = await brokerConfigPromise;
|
|
535
543
|
if (brokerConfig) {
|
|
536
544
|
const client = new AuthBrokerClient({ url: brokerConfig.url, token: brokerConfig.token });
|
|
537
545
|
const ttlMs = resolveSnapshotTtlMs();
|
|
538
|
-
const cachePath = getAuthBrokerSnapshotCachePath();
|
|
539
546
|
const persist =
|
|
540
547
|
ttlMs > 0
|
|
541
548
|
? (snapshot: SnapshotResponse): void => {
|
|
@@ -1730,7 +1737,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1730
1737
|
// the winning provider (e.g. anthropic's claude-3-5-sonnet-20240620)
|
|
1731
1738
|
// instead of the intended provider default (claude-sonnet-4-6). Mirrors
|
|
1732
1739
|
// findInitialModel's precedence.
|
|
1733
|
-
for (const [provider, defaultId] of Object.entries(
|
|
1740
|
+
for (const [provider, defaultId] of Object.entries(DEFAULT_MODEL_PER_PROVIDER)) {
|
|
1734
1741
|
const preferred = fallbackCandidates.find(
|
|
1735
1742
|
candidate => candidate.provider === provider && candidate.id === defaultId,
|
|
1736
1743
|
);
|
|
@@ -2342,7 +2349,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2342
2349
|
}
|
|
2343
2350
|
|
|
2344
2351
|
if (model?.api === "openai-codex-responses") {
|
|
2345
|
-
|
|
2352
|
+
// `.api` equality doesn't narrow the generic; the guard makes this cast sound.
|
|
2353
|
+
const codexModel = model as Model<"openai-codex-responses">;
|
|
2346
2354
|
const codexTransport = getOpenAICodexTransportDetails(codexModel, {
|
|
2347
2355
|
sessionId: providerSessionId,
|
|
2348
2356
|
baseUrl: codexModel.baseUrl,
|
|
@@ -2373,12 +2381,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2373
2381
|
}
|
|
2374
2382
|
|
|
2375
2383
|
// Start LSP warmup in the background so startup does not block on language server initialization.
|
|
2376
|
-
//
|
|
2377
|
-
//
|
|
2378
|
-
//
|
|
2379
|
-
//
|
|
2384
|
+
// With `lsp.lazy` (the default) the warmup is skipped: recognized servers are still discovered and
|
|
2385
|
+
// surfaced in the UI as "available", but cold-start on first use — the lsp tool or an edit/write
|
|
2386
|
+
// touching a matching file type — through `getOrCreateClient`.
|
|
2387
|
+
// Print/script invocations (`hasUI=false`) skip it regardless: they don't render the warmup status
|
|
2388
|
+
// indicator AND typically finish before LSP servers would have stabilized — warming them just spends
|
|
2389
|
+
// CPU parsing big `initialize` responses concurrently with the LLM stream consumer, jittering
|
|
2390
|
+
// perceived latency.
|
|
2380
2391
|
let lspServers: CreateAgentSessionResult["lspServers"];
|
|
2381
|
-
if (enableLsp && options.hasUI && settings.get("lsp.
|
|
2392
|
+
if (enableLsp && options.hasUI && settings.get("lsp.lazy")) {
|
|
2393
|
+
lspServers = discoverStartupLspServers(cwd, "available");
|
|
2394
|
+
} else if (enableLsp && options.hasUI) {
|
|
2382
2395
|
lspServers = discoverStartupLspServers(cwd);
|
|
2383
2396
|
if (lspServers.length > 0) {
|
|
2384
2397
|
void (async () => {
|
|
@@ -79,14 +79,14 @@ import {
|
|
|
79
79
|
clearAnthropicFastModeFallback,
|
|
80
80
|
deriveClaudeDeviceId,
|
|
81
81
|
Effort,
|
|
82
|
-
getSupportedEfforts,
|
|
83
82
|
isContextOverflow,
|
|
84
83
|
isUsageLimitError,
|
|
85
|
-
modelsAreEqual,
|
|
86
84
|
parseRateLimitReason,
|
|
87
85
|
resolveServiceTier,
|
|
88
86
|
streamSimple,
|
|
89
87
|
} from "@oh-my-pi/pi-ai";
|
|
88
|
+
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
89
|
+
import { modelsAreEqual } from "@oh-my-pi/pi-catalog/models";
|
|
90
90
|
import { countTokens, MacOSPowerAssertion } from "@oh-my-pi/pi-natives";
|
|
91
91
|
import {
|
|
92
92
|
extractRetryHint,
|
|
@@ -105,7 +105,7 @@ import { classifyDifficulty } from "../auto-thinking/classifier";
|
|
|
105
105
|
import { reset as resetCapabilities } from "../capability";
|
|
106
106
|
import type { Rule } from "../capability/rule";
|
|
107
107
|
import { shouldEnableAppendOnlyContext } from "../config/append-only-context-mode";
|
|
108
|
-
import {
|
|
108
|
+
import type { ModelRegistry } from "../config/model-registry";
|
|
109
109
|
import {
|
|
110
110
|
extractExplicitThinkingSelector,
|
|
111
111
|
formatModelSelectorValue,
|
|
@@ -115,6 +115,7 @@ import {
|
|
|
115
115
|
type ResolvedModelRoleValue,
|
|
116
116
|
resolveModelRoleValue,
|
|
117
117
|
} from "../config/model-resolver";
|
|
118
|
+
import { MODEL_ROLE_IDS } from "../config/model-roles";
|
|
118
119
|
import { expandPromptTemplate, type PromptTemplate } from "../config/prompt-templates";
|
|
119
120
|
import type { Settings, SkillsSettings } from "../config/settings";
|
|
120
121
|
import { onAppendOnlyModeChanged } from "../config/settings";
|
|
@@ -287,6 +288,20 @@ export type AgentSessionEventListener = (event: AgentSessionEvent) => void;
|
|
|
287
288
|
export type AsyncJobSnapshotItem = Pick<AsyncJob, "id" | "type" | "status" | "label" | "startTime">;
|
|
288
289
|
|
|
289
290
|
const EMPTY_STOP_MAX_RETRIES = 3;
|
|
291
|
+
const RETRY_BACKOFF_MAX_DELAY_MS = 8_000;
|
|
292
|
+
const RETRY_BACKOFF_JITTER_RATIO = 0.25;
|
|
293
|
+
|
|
294
|
+
function calculateRetryBackoffDelayMs(baseDelayMs: number, attempt: number): number {
|
|
295
|
+
const cappedDelayMs = Math.min(Math.max(0, baseDelayMs) * 2 ** Math.max(0, attempt - 1), RETRY_BACKOFF_MAX_DELAY_MS);
|
|
296
|
+
const jitter = 1 - Math.random() * RETRY_BACKOFF_JITTER_RATIO;
|
|
297
|
+
return cappedDelayMs * jitter;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Slack added past a sibling credential's block expiry before retrying, so
|
|
302
|
+
* the next getApiKey lands after the block has actually lapsed.
|
|
303
|
+
*/
|
|
304
|
+
const SIBLING_UNBLOCK_BUFFER_MS = 1_000;
|
|
290
305
|
const NON_WHITESPACE_RE = /\S/;
|
|
291
306
|
|
|
292
307
|
function hasNonWhitespace(value: string): boolean {
|
|
@@ -8307,13 +8322,16 @@ export class AgentSession {
|
|
|
8307
8322
|
|
|
8308
8323
|
const errorMessage = message.errorMessage || "Unknown error";
|
|
8309
8324
|
const parsedRetryAfterMs = this.#parseRetryAfterMsFromError(errorMessage);
|
|
8310
|
-
let delayMs = retrySettings.baseDelayMs
|
|
8325
|
+
let delayMs = calculateRetryBackoffDelayMs(retrySettings.baseDelayMs, this.#retryAttempt);
|
|
8311
8326
|
let switchedCredential = false;
|
|
8312
8327
|
let switchedModel = false;
|
|
8328
|
+
// Set when a usage-limit error pinned the wait to credential
|
|
8329
|
+
// availability — suppresses the generic retry-after bump below.
|
|
8330
|
+
let usageLimitWaitMs: number | undefined;
|
|
8313
8331
|
|
|
8314
8332
|
if (this.model && isUsageLimitError(errorMessage)) {
|
|
8315
8333
|
const retryAfterMs = parsedRetryAfterMs ?? calculateRateLimitBackoffMs(parseRateLimitReason(errorMessage));
|
|
8316
|
-
const
|
|
8334
|
+
const outcome = await this.#modelRegistry.authStorage.markUsageLimitReached(
|
|
8317
8335
|
this.model.provider,
|
|
8318
8336
|
this.sessionId,
|
|
8319
8337
|
{
|
|
@@ -8321,12 +8339,28 @@ export class AgentSession {
|
|
|
8321
8339
|
baseUrl: this.model.baseUrl,
|
|
8322
8340
|
},
|
|
8323
8341
|
);
|
|
8324
|
-
if (switched) {
|
|
8342
|
+
if (outcome.switched) {
|
|
8325
8343
|
switchedCredential = true;
|
|
8326
8344
|
delayMs = 0;
|
|
8327
|
-
} else
|
|
8328
|
-
// No
|
|
8329
|
-
|
|
8345
|
+
} else {
|
|
8346
|
+
// No sibling credential is usable right now. Wait for whichever
|
|
8347
|
+
// comes first: the provider's retry-after window for the current
|
|
8348
|
+
// account, or the earliest moment a temporarily blocked sibling
|
|
8349
|
+
// frees up (e.g. a 60s post-401 block or a 5-min usage-probe
|
|
8350
|
+
// block) — the next attempt's getApiKey re-ranks and picks it up.
|
|
8351
|
+
// Without this, one short-lived sibling block escalates a
|
|
8352
|
+
// recoverable situation into the provider's multi-hour wait and
|
|
8353
|
+
// trips the fail-fast cap below.
|
|
8354
|
+
usageLimitWaitMs = retryAfterMs;
|
|
8355
|
+
if (outcome.retryAtMs !== undefined) {
|
|
8356
|
+
const siblingWaitMs = Math.max(0, outcome.retryAtMs - Date.now()) + SIBLING_UNBLOCK_BUFFER_MS;
|
|
8357
|
+
if (siblingWaitMs < usageLimitWaitMs) {
|
|
8358
|
+
usageLimitWaitMs = siblingWaitMs;
|
|
8359
|
+
}
|
|
8360
|
+
}
|
|
8361
|
+
if (usageLimitWaitMs > delayMs) {
|
|
8362
|
+
delayMs = usageLimitWaitMs;
|
|
8363
|
+
}
|
|
8330
8364
|
}
|
|
8331
8365
|
}
|
|
8332
8366
|
|
|
@@ -8338,7 +8372,7 @@ export class AgentSession {
|
|
|
8338
8372
|
}
|
|
8339
8373
|
if (switchedModel) {
|
|
8340
8374
|
delayMs = 0;
|
|
8341
|
-
} else if (parsedRetryAfterMs && parsedRetryAfterMs > delayMs) {
|
|
8375
|
+
} else if (usageLimitWaitMs === undefined && parsedRetryAfterMs && parsedRetryAfterMs > delayMs) {
|
|
8342
8376
|
delayMs = parsedRetryAfterMs;
|
|
8343
8377
|
}
|
|
8344
8378
|
}
|
|
@@ -65,13 +65,42 @@ async function readConfigYaml(): Promise<ConfigSnapshot> {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Process-lifetime memo for {@link resolveAuthBrokerConfig}. Keyed on the env
|
|
70
|
+
* inputs (plus agent dir, which decides which config.yml is read) so tests
|
|
71
|
+
* that flip `OMP_AUTH_BROKER_*` between cases still observe the change, while
|
|
72
|
+
* repeated resolution within one CLI invocation (startup, subagent sessions)
|
|
73
|
+
* skips the config.yml read and any `!command` token resolution.
|
|
74
|
+
*/
|
|
75
|
+
let cachedConfigKey: string | null = null;
|
|
76
|
+
let cachedConfigPromise: Promise<AuthBrokerClientConfig | null> | null = null;
|
|
77
|
+
|
|
68
78
|
/**
|
|
69
79
|
* Read broker configuration. Returns null when the URL is missing
|
|
70
80
|
* (broker disabled — local store is used). Throws when URL is set but no
|
|
71
81
|
* token is available — the caller cannot fall back silently because the
|
|
72
82
|
* user explicitly asked to use the broker.
|
|
83
|
+
*
|
|
84
|
+
* Successful resolutions (including "no broker configured") are memoized for
|
|
85
|
+
* the process lifetime; failures are not, so a missing token can be fixed and
|
|
86
|
+
* retried. Concurrent callers share one in-flight resolution.
|
|
73
87
|
*/
|
|
74
|
-
export
|
|
88
|
+
export function resolveAuthBrokerConfig(): Promise<AuthBrokerClientConfig | null> {
|
|
89
|
+
const key = `${process.env.OMP_AUTH_BROKER_URL ?? ""}\u0000${process.env.OMP_AUTH_BROKER_TOKEN ?? ""}\u0000${getAgentDir()}`;
|
|
90
|
+
if (cachedConfigPromise && cachedConfigKey === key) return cachedConfigPromise;
|
|
91
|
+
const promise = resolveAuthBrokerConfigUncached();
|
|
92
|
+
cachedConfigKey = key;
|
|
93
|
+
cachedConfigPromise = promise;
|
|
94
|
+
promise.catch(() => {
|
|
95
|
+
if (cachedConfigPromise === promise) {
|
|
96
|
+
cachedConfigPromise = null;
|
|
97
|
+
cachedConfigKey = null;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return promise;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function resolveAuthBrokerConfigUncached(): Promise<AuthBrokerClientConfig | null> {
|
|
75
104
|
const envUrl = process.env.OMP_AUTH_BROKER_URL;
|
|
76
105
|
const envToken = process.env.OMP_AUTH_BROKER_TOKEN;
|
|
77
106
|
|
|
@@ -1516,10 +1516,10 @@ class NdjsonFileWriter {
|
|
|
1516
1516
|
}
|
|
1517
1517
|
}
|
|
1518
1518
|
|
|
1519
|
-
/** Get recent sessions for display in welcome screen */
|
|
1519
|
+
/** Get recent sessions for display in welcome screen (which reserves WELCOME_SESSION_SLOTS rows) */
|
|
1520
1520
|
export async function getRecentSessions(
|
|
1521
1521
|
sessionDir: string,
|
|
1522
|
-
limit =
|
|
1522
|
+
limit = 4,
|
|
1523
1523
|
storage: SessionStorage = new FileSessionStorage(),
|
|
1524
1524
|
): Promise<RecentSessionInfo[]> {
|
|
1525
1525
|
const sessions = await getSortedSessions(sessionDir, storage);
|
|
@@ -650,6 +650,7 @@ export class OutputSink {
|
|
|
650
650
|
#sawData = false;
|
|
651
651
|
#truncated = false;
|
|
652
652
|
#lastChunkTime = 0;
|
|
653
|
+
#pendingChunk = "";
|
|
653
654
|
|
|
654
655
|
// Per-line column cap streaming state (persists across `push` calls so a
|
|
655
656
|
// long line split across chunks still trips the same trigger).
|
|
@@ -701,14 +702,20 @@ export class OutputSink {
|
|
|
701
702
|
push(chunk: string): void {
|
|
702
703
|
chunk = sanitizeWithOptionalSixelPassthrough(chunk, sanitizeText);
|
|
703
704
|
|
|
704
|
-
// Throttled onChunk:
|
|
705
|
+
// Throttled onChunk: coalesce chunks arriving inside the throttle window
|
|
706
|
+
// and flush the buffered concatenation on the next eligible tick (plus a
|
|
707
|
+
// final flush in dump()) so the preview never has silent gaps.
|
|
705
708
|
// Live preview gets the raw (pre-cap) chunk so the TUI never lags behind
|
|
706
709
|
// what reached the sink — the column cap is for the persisted LLM view.
|
|
707
710
|
if (this.#onChunk) {
|
|
708
711
|
const now = Date.now();
|
|
709
712
|
if (now - this.#lastChunkTime >= this.#chunkThrottleMs) {
|
|
710
713
|
this.#lastChunkTime = now;
|
|
711
|
-
this.#
|
|
714
|
+
const merged = this.#pendingChunk + chunk;
|
|
715
|
+
this.#pendingChunk = "";
|
|
716
|
+
this.#onChunk(merged);
|
|
717
|
+
} else {
|
|
718
|
+
this.#pendingChunk += chunk;
|
|
712
719
|
}
|
|
713
720
|
}
|
|
714
721
|
|
|
@@ -880,6 +887,11 @@ export class OutputSink {
|
|
|
880
887
|
const sink = Bun.file(this.#artifactPath).writer();
|
|
881
888
|
this.#file = { path: this.#artifactPath, artifactId: this.#artifactId, sink };
|
|
882
889
|
|
|
890
|
+
// Head-retained bytes precede the rolling tail buffer in the capture.
|
|
891
|
+
if (this.#head.length > 0) {
|
|
892
|
+
sink.write(this.#head);
|
|
893
|
+
}
|
|
894
|
+
|
|
883
895
|
// Flush existing buffer to file BEFORE it gets trimmed further.
|
|
884
896
|
if (this.#buffer.length > 0) {
|
|
885
897
|
sink.write(this.#buffer);
|
|
@@ -946,10 +958,19 @@ export class OutputSink {
|
|
|
946
958
|
this.#columnEllipsisAdded = false;
|
|
947
959
|
this.#columnDroppedBytes = 0;
|
|
948
960
|
this.#columnTruncatedLines = 0;
|
|
961
|
+
this.#pendingChunk = "";
|
|
949
962
|
}
|
|
950
963
|
|
|
951
964
|
async dump(notice?: string): Promise<OutputSummary> {
|
|
952
965
|
const noticeLine = notice ? `[${notice}]\n` : "";
|
|
966
|
+
|
|
967
|
+
// Flush any chunk still held back by the throttle so the live preview
|
|
968
|
+
// ends with the complete stream.
|
|
969
|
+
if (this.#onChunk && this.#pendingChunk.length > 0) {
|
|
970
|
+
const pending = this.#pendingChunk;
|
|
971
|
+
this.#pendingChunk = "";
|
|
972
|
+
this.#onChunk(pending);
|
|
973
|
+
}
|
|
953
974
|
const totalLines = this.#sawData ? this.#totalLines + 1 : 0;
|
|
954
975
|
|
|
955
976
|
if (this.#file) await this.#file.sink.end();
|
|
@@ -30,6 +30,7 @@ import { createMarketplaceManager } from "./helpers/marketplace-manager";
|
|
|
30
30
|
import { handleMcpAcp } from "./helpers/mcp";
|
|
31
31
|
import { commandConsumed, errorMessage, parseSlashCommand, parseSubcommand, usage } from "./helpers/parse";
|
|
32
32
|
import { handleSshAcp } from "./helpers/ssh";
|
|
33
|
+
import { launchStatsDashboard, parseStatsDashboardArgs } from "./helpers/stats-dashboard";
|
|
33
34
|
import { handleTodoAcp } from "./helpers/todo";
|
|
34
35
|
import { buildUsageReportText } from "./helpers/usage-report";
|
|
35
36
|
import { parseMarketplaceInstallArgs, parsePluginScopeArgs } from "./marketplace-install-parser";
|
|
@@ -542,6 +543,25 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
542
543
|
runtime.ctx.editor.setText("");
|
|
543
544
|
},
|
|
544
545
|
},
|
|
546
|
+
{
|
|
547
|
+
name: "stats",
|
|
548
|
+
description: "Launch the local stats dashboard",
|
|
549
|
+
inlineHint: "[--port <port>]",
|
|
550
|
+
allowArgs: true,
|
|
551
|
+
handle: async (command, runtime) => {
|
|
552
|
+
const parsed = parseStatsDashboardArgs(command.args);
|
|
553
|
+
if ("error" in parsed) return usage(parsed.error, runtime);
|
|
554
|
+
|
|
555
|
+
await runtime.output("Syncing session files...");
|
|
556
|
+
try {
|
|
557
|
+
const result = await launchStatsDashboard(parsed);
|
|
558
|
+
await runtime.output(result.message);
|
|
559
|
+
} catch (error) {
|
|
560
|
+
await runtime.output(`Stats dashboard failed: ${errorMessage(error)}`);
|
|
561
|
+
}
|
|
562
|
+
return commandConsumed();
|
|
563
|
+
},
|
|
564
|
+
},
|
|
545
565
|
{
|
|
546
566
|
name: "changelog",
|
|
547
567
|
description: "Show changelog entries",
|