@oh-my-pi/pi-coding-agent 16.5.0 → 16.5.2
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 +91 -0
- package/dist/cli.js +3556 -3504
- package/dist/types/advisor/advise-tool.d.ts +12 -1
- package/dist/types/advisor/runtime.d.ts +41 -1
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/update-cli.d.ts +4 -1
- package/dist/types/cli/usage-cli.d.ts +3 -0
- package/dist/types/cli/usage-error.d.ts +4 -0
- package/dist/types/config/api-key-resolver.d.ts +2 -2
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/model-resolver.d.ts +8 -1
- package/dist/types/config/models-config.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/discovery/substitute-plugin-root.d.ts +22 -0
- package/dist/types/eval/__tests__/process-entry-import.test.d.ts +1 -0
- package/dist/types/eval/backend.d.ts +3 -3
- package/dist/types/eval/bridge-timeout.d.ts +9 -1
- package/dist/types/eval/js/context-manager.d.ts +5 -3
- package/dist/types/eval/js/process-entry.d.ts +6 -0
- package/dist/types/eval/js/worker-core.d.ts +15 -1
- package/dist/types/eval/py/spawn-options.d.ts +10 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +3 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -1
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/extensibility/extensions/wrapper.d.ts +3 -6
- package/dist/types/extensibility/plugins/bun-git-cache.d.ts +3 -0
- package/dist/types/goals/guided-setup.d.ts +12 -0
- package/dist/types/internal-urls/history-protocol.d.ts +3 -2
- package/dist/types/internal-urls/memory-protocol.d.ts +6 -7
- package/dist/types/internal-urls/registry-helpers.d.ts +19 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/oauth-flow.d.ts +2 -0
- package/dist/types/modes/components/__tests__/dynamic-border.test.d.ts +1 -0
- package/dist/types/modes/components/agent-hub.d.ts +10 -0
- package/dist/types/modes/components/dynamic-border.d.ts +5 -3
- package/dist/types/modes/components/login-dialog.d.ts +2 -0
- package/dist/types/modes/components/mcp-add-wizard.d.ts +1 -0
- package/dist/types/modes/components/read-tool-group.d.ts +0 -2
- package/dist/types/modes/components/transcript-container.d.ts +3 -2
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/magic-keyword-boundary.d.ts +9 -0
- package/dist/types/modes/orchestrate.d.ts +1 -1
- package/dist/types/modes/rpc/host-tools.d.ts +2 -0
- package/dist/types/modes/rpc/rpc-mode.d.ts +26 -6
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/ultrathink.d.ts +1 -1
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +12 -0
- package/dist/types/modes/workflow.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +6 -0
- package/dist/types/session/exit-diagnostics.d.ts +11 -0
- package/dist/types/session/messages.d.ts +15 -0
- package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +11 -0
- package/dist/types/subprocess/worker-client.d.ts +6 -0
- package/dist/types/tools/bash-skill-urls.d.ts +1 -0
- package/dist/types/tools/grep.d.ts +0 -2
- package/dist/types/tools/read.d.ts +0 -4
- package/dist/types/web/search/provider.d.ts +10 -3
- package/dist/types/web/search/providers/codex.d.ts +5 -4
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +917 -42
- package/src/advisor/advise-tool.ts +17 -1
- package/src/advisor/runtime.ts +270 -67
- package/src/autolearn/controller.ts +15 -3
- package/src/autoresearch/dashboard.ts +2 -2
- package/src/cli/args.ts +12 -0
- package/src/cli/auth-broker-cli.ts +30 -11
- package/src/cli/auth-gateway-cli.ts +5 -1
- package/src/cli/config-cli.ts +15 -3
- package/src/cli/dry-balance-cli.ts +14 -4
- package/src/cli/flag-tables.ts +21 -7
- package/src/cli/update-cli.ts +62 -11
- package/src/cli/usage-cli.ts +58 -5
- package/src/cli/usage-error.ts +7 -0
- package/src/cli.ts +23 -1
- package/src/commands/acp.ts +11 -2
- package/src/commands/launch.ts +12 -3
- package/src/commands/token.ts +3 -1
- package/src/config/api-key-resolver.ts +12 -3
- package/src/config/config-file.ts +30 -12
- package/src/config/model-registry.ts +7 -7
- package/src/config/model-resolver.ts +21 -7
- package/src/config/models-config.ts +1 -1
- package/src/config/settings-schema.ts +10 -0
- package/src/cursor.ts +2 -0
- package/src/discovery/claude-plugins.ts +9 -3
- package/src/discovery/omp-plugins.ts +6 -2
- package/src/discovery/substitute-plugin-root.ts +32 -0
- package/src/eval/__tests__/agent-bridge.test.ts +19 -14
- package/src/eval/__tests__/bridge-timeout.test.ts +106 -0
- package/src/eval/__tests__/js-context-manager.test.ts +158 -1
- package/src/eval/__tests__/kernel-spawn.test.ts +12 -0
- package/src/eval/__tests__/prelude-agent.test.ts +20 -0
- package/src/eval/__tests__/process-entry-import.test.ts +27 -0
- package/src/eval/agent-bridge.ts +121 -116
- package/src/eval/backend.ts +3 -3
- package/src/eval/bridge-timeout.ts +20 -2
- package/src/eval/executor-base.ts +85 -7
- package/src/eval/jl/kernel.ts +2 -1
- package/src/eval/js/context-manager.ts +109 -32
- package/src/eval/js/process-entry.ts +27 -0
- package/src/eval/js/shared/runtime.ts +1 -1
- package/src/eval/js/worker-core.ts +70 -9
- package/src/eval/js/worker-entry.ts +1 -1
- package/src/eval/py/__tests__/prelude.test.ts +72 -0
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/prelude.py +28 -1
- package/src/eval/py/spawn-options.ts +13 -0
- package/src/eval/py/tool-bridge.ts +13 -14
- package/src/eval/rb/kernel.ts +2 -1
- package/src/exec/bash-executor.ts +30 -43
- package/src/extensibility/custom-tools/types.ts +3 -0
- package/src/extensibility/extensions/runner.ts +3 -0
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/extensibility/extensions/wrapper.ts +18 -18
- package/src/extensibility/plugins/bun-git-cache.ts +91 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +32 -16
- package/src/extensibility/plugins/manager.ts +28 -7
- package/src/goals/guided-setup.ts +29 -1
- package/src/internal-urls/history-protocol.ts +95 -15
- package/src/internal-urls/memory-protocol.ts +13 -9
- package/src/internal-urls/registry-helpers.ts +50 -1
- package/src/launch/broker.ts +38 -25
- package/src/lsp/client.ts +7 -1
- package/src/main.ts +29 -0
- package/src/mcp/oauth-discovery.ts +20 -1
- package/src/mcp/oauth-flow.ts +3 -1
- package/src/mcp/tool-bridge.ts +57 -6
- package/src/modes/components/__tests__/dynamic-border.test.ts +55 -0
- package/src/modes/components/agent-dashboard.ts +2 -2
- package/src/modes/components/agent-hub.ts +15 -2
- package/src/modes/components/agent-transcript-viewer.ts +2 -2
- package/src/modes/components/chat-transcript-builder.ts +26 -4
- package/src/modes/components/dynamic-border.ts +9 -6
- package/src/modes/components/extensions/extension-list.ts +2 -2
- package/src/modes/components/hook-selector.ts +10 -4
- package/src/modes/components/login-dialog.ts +5 -0
- package/src/modes/components/mcp-add-wizard.ts +5 -0
- package/src/modes/components/plan-review-overlay.ts +11 -11
- package/src/modes/components/read-tool-group.ts +1 -8
- package/src/modes/components/status-line/component.ts +10 -1
- package/src/modes/components/transcript-container.ts +110 -7
- package/src/modes/controllers/command-controller.ts +12 -4
- package/src/modes/controllers/event-controller.ts +80 -15
- package/src/modes/controllers/input-controller.ts +4 -2
- package/src/modes/controllers/mcp-command-controller.ts +6 -7
- package/src/modes/controllers/selector-controller.ts +24 -5
- package/src/modes/controllers/todo-command-controller.ts +18 -14
- package/src/modes/interactive-mode.ts +7 -3
- package/src/modes/magic-keyword-boundary.ts +23 -0
- package/src/modes/orchestrate.ts +6 -5
- package/src/modes/print-mode.ts +9 -0
- package/src/modes/prompt-action-autocomplete.ts +6 -1
- package/src/modes/rpc/host-tools.ts +15 -0
- package/src/modes/rpc/rpc-mode.ts +123 -48
- package/src/modes/types.ts +1 -1
- package/src/modes/ultrathink.ts +6 -5
- package/src/modes/utils/transcript-render-helpers.ts +54 -0
- package/src/modes/utils/ui-helpers.ts +27 -1
- package/src/modes/workflow.ts +6 -5
- package/src/prompts/advisor/system.md +1 -0
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/grep.md +1 -2
- package/src/prompts/tools/read.md +2 -4
- package/src/sdk.ts +61 -34
- package/src/session/agent-session.ts +283 -39
- package/src/session/exit-diagnostics.ts +108 -0
- package/src/session/messages.test.ts +66 -0
- package/src/session/messages.ts +37 -0
- package/src/session/streaming-output.ts +40 -12
- package/src/slash-commands/helpers/active-oauth-account.ts +22 -2
- package/src/slash-commands/helpers/logout.ts +23 -3
- package/src/slash-commands/helpers/usage-report.ts +14 -2
- package/src/subprocess/worker-client.ts +9 -2
- package/src/system-prompt.test.ts +36 -0
- package/src/system-prompt.ts +1 -1
- package/src/task/executor.ts +8 -0
- package/src/task/render.test.ts +36 -0
- package/src/task/render.ts +55 -43
- package/src/tools/bash-skill-urls.ts +4 -1
- package/src/tools/bash.ts +1 -0
- package/src/tools/browser/registry.ts +17 -3
- package/src/tools/eval.ts +14 -9
- package/src/tools/gh.ts +3 -1
- package/src/tools/grep.ts +5 -45
- package/src/tools/path-utils.ts +7 -1
- package/src/tools/read.ts +23 -74
- package/src/tools/write.ts +82 -9
- package/src/tools/yield.ts +29 -1
- package/src/utils/title-generator.ts +10 -6
- package/src/web/search/index.ts +39 -22
- package/src/web/search/provider.ts +33 -16
- package/src/web/search/providers/codex.ts +68 -21
- package/src/web/search/providers/perplexity-auth.ts +20 -11
- package/src/web/search/providers/perplexity.ts +14 -2
package/src/modes/workflow.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import workflowNoticeTemplate from "../prompts/system/workflow-notice.md" with { type: "text" };
|
|
3
3
|
import { createGradientHighlighter, type KeywordHighlighter } from "./gradient-highlight";
|
|
4
|
+
import { magicKeywordRegex } from "./magic-keyword-boundary";
|
|
4
5
|
import { keywordInProse } from "./markdown-prose";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -10,13 +11,13 @@ import { keywordInProse } from "./markdown-prose";
|
|
|
10
11
|
* amber→green gradient ({@link highlightWorkflow}); submitting a message that
|
|
11
12
|
* mentions it appends a hidden workflow notice that steers the model to author
|
|
12
13
|
* a deterministic multi-subagent workflow through the active task schema.
|
|
13
|
-
* Matching is
|
|
14
|
+
* Matching is prose-delimited and case-sensitive (lowercase only) —
|
|
14
15
|
* "workflowz" triggers, but "workflowzed", "Workflowz", and "workflowz.ts"
|
|
15
16
|
* never do.
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
|
-
// Detection: lowercase keyword flanked by whitespace or a string edge.
|
|
19
|
-
const WORKFLOW_WORD =
|
|
19
|
+
// Detection: lowercase keyword flanked by prose punctuation, whitespace, or a string edge.
|
|
20
|
+
const WORKFLOW_WORD = magicKeywordRegex("workflowz");
|
|
20
21
|
|
|
21
22
|
/** WORKFLOW_NOTICE is the default hidden notice for sessions with batched task calls enabled. */
|
|
22
23
|
export const WORKFLOW_NOTICE: string = renderWorkflowNotice({ taskBatch: true });
|
|
@@ -28,7 +29,7 @@ export function renderWorkflowNotice({ taskBatch }: { taskBatch: boolean }): str
|
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Whether `text` contains the standalone keyword "workflowz"
|
|
31
|
-
* (lowercase,
|
|
32
|
+
* (lowercase, prose-delimited) in prose — never inside a code block, inline
|
|
32
33
|
* code span, or XML/HTML section.
|
|
33
34
|
*/
|
|
34
35
|
export function containsWorkflow(text: string): boolean {
|
|
@@ -42,7 +43,7 @@ export function containsWorkflow(text: string): boolean {
|
|
|
42
43
|
*/
|
|
43
44
|
export const highlightWorkflow: KeywordHighlighter = createGradientHighlighter({
|
|
44
45
|
probe: /workflowz/,
|
|
45
|
-
highlight:
|
|
46
|
+
highlight: magicKeywordRegex("workflowz", "g"),
|
|
46
47
|
stops: 14,
|
|
47
48
|
hue: t => 30 + t * 120,
|
|
48
49
|
});
|
|
@@ -28,6 +28,7 @@ Keep exploration lean:
|
|
|
28
28
|
- NEVER restate information the agent already has, including errors they have seen.
|
|
29
29
|
- Examples: type errors, LSP diagnostics, failed builds, failing tests, lint.
|
|
30
30
|
- NEVER repeat advice you already gave, and NEVER send the same advice twice; give the agent room to act on prior advice before raising the same theme again.
|
|
31
|
+
- When an update heading is tagged `[in progress — more steps follow]`, the agent is mid-turn and has not finished yet. Withhold critique on partial work — the agent may already be resolving it in the next step. Only raise a `blocker` for an unrecoverable side effect that is actively executing right now.
|
|
31
32
|
- NEVER nitpick about things user stated they are okay with. You are the advocate for the user.
|
|
32
33
|
- You are user-aligned: treat the user's word as truth, their frustration as justified, their stated requirements as binding.
|
|
33
34
|
</communication>
|
|
@@ -57,6 +57,7 @@ Special URLs for internal resources; with most FS/bash tools they auto-resolve t
|
|
|
57
57
|
- `memory://root`: project memory summary
|
|
58
58
|
{{/if}}
|
|
59
59
|
- `agent://<id>`: agent output artifact; `/<path>` extracts a JSON field
|
|
60
|
+
- `history://<id>`: read-only markdown transcript of an agent (live, parked, or released); bare `history://` lists all agents. Serves any agent whose session file persists on disk, not just registered peers.
|
|
60
61
|
- `artifact://<id>`: artifact content
|
|
61
62
|
- `local://<name>.md`: plan artifacts or shared content for subagents
|
|
62
63
|
{{#if hasObsidian}}
|
|
@@ -10,7 +10,7 @@ Fields:
|
|
|
10
10
|
- `language` — {{#if py}}`"py"` IPython kernel{{/if}}{{#ifAll py js}}, {{/ifAll}}{{#if js}}`"js"` persistent JavaScript VM{{/if}}{{#if rb}}{{#ifAny py js}}, {{/ifAny}}`"rb"` persistent Ruby kernel{{/if}}{{#if jl}}{{#ifAny py js rb}}, {{/ifAny}}`"jl"` persistent Julia kernel{{/if}}.
|
|
11
11
|
- `code` — cell body, verbatim. Newlines/quotes JSON-encoded; no fences, no headers.
|
|
12
12
|
- `title` (optional) — short transcript label (e.g. `"imports"`).
|
|
13
|
-
- `timeout` (optional) — seconds. Raise only for heavy compute or long non-agent tool calls.
|
|
13
|
+
- `timeout` (optional) — seconds; `0` disables the cell timeout. Raise only for heavy compute or long non-agent tool calls.
|
|
14
14
|
- `reset` (optional) — wipe this language's kernel first.{{#ifAll py js}} Per-language: a `py` reset never touches the JS VM.{{/ifAll}}
|
|
15
15
|
|
|
16
16
|
{{#if py}}Live event loop: use top-level `await` directly; `asyncio.run(…)` raises "cannot be called from a running event loop".{{/if}}
|
|
@@ -28,7 +28,7 @@ display(value) → None
|
|
|
28
28
|
print(value, ...) → None
|
|
29
29
|
Text output.
|
|
30
30
|
read(path, offset?=1, limit?=None) → str
|
|
31
|
-
File
|
|
31
|
+
File/resource text; offset/limit = 1-indexed lines. `local://…` works everywhere; Python/JS also accept top-level `read` URI schemes.
|
|
32
32
|
write(path, content) → str
|
|
33
33
|
Write file (creates parents) → resolved path. `local://…` persists across turns/subagents.
|
|
34
34
|
env(key?=None, value?=None) → str | None | dict
|
|
@@ -2,8 +2,7 @@ Greps files using regex.
|
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
4
|
- Supports Rust regex and PCRE2 syntax.
|
|
5
|
-
- `path`: SHOULD scope to a known path (e.g. `src`); pass several as a delimited list (`src; tests`).
|
|
6
|
-
- Literal colon filename + line range? Use `selector` (e.g. `{"path":"test:1-2","selector":"1-2"}`), not recursive `path:"test:1-2:1-2"`.
|
|
5
|
+
- `path`: SHOULD scope to a known path (e.g. `src`); pass several as a delimited list (`src; tests`). Append a line selector to one file path (e.g. `src/foo.ts:50-100`); selectors never choose the search root.
|
|
7
6
|
- Cross-line patterns detected from literal `\n` or `\\n` in `pattern`.
|
|
8
7
|
</instruction>
|
|
9
8
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Read files, directories, archives, SQLite, images, documents, internal resources, and web URLs via `path
|
|
1
|
+
Read files, directories, archives, SQLite, images, documents, internal resources, and web URLs via `path`.
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
4
|
- SHOULD parallelize independent reads.
|
|
@@ -7,8 +7,7 @@ Read files, directories, archives, SQLite, images, documents, internal resources
|
|
|
7
7
|
|
|
8
8
|
## Parameters
|
|
9
9
|
|
|
10
|
-
- `path` — required. Local path, internal URI (`skill://`, `agent://`, `artifact://`, `memory://`, `rule://`, `local://`, `vault://`, `mcp://`, `omp://`, `issue://`, `pr://`, `ssh://`), or URL.
|
|
11
|
-
- `selector` — optional selector without leading `:` (e.g. `"50-200"`, `"raw"`, `"raw:50-100"`, `"conflicts"`). Use when `path` contains literal colons: `{"path":"test:1-2","selector":"1-2"}`.
|
|
10
|
+
- `path` — required. Local path, internal URI (`skill://`, `agent://`, `artifact://`, `memory://`, `rule://`, `local://`, `vault://`, `mcp://`, `omp://`, `issue://`, `pr://`, `ssh://`), or URL. Append `:<sel>` for ranges/modes (e.g. `src/foo.ts:50-200`, `src/foo.ts:raw`, `db.sqlite:users:42`).
|
|
12
11
|
|
|
13
12
|
## Selectors
|
|
14
13
|
|
|
@@ -73,6 +72,5 @@ All URI schemes take the same line selectors. `artifact://<id>` recovers spilled
|
|
|
73
72
|
`ssh://host/<absolute-path>` reads a remote text file (UTF-8, ≤1 MiB) or lists a directory one level deep, on a pre-configured SSH host or `~/.ssh/config` alias; `ssh://host/` lists the remote root and bare `ssh://` lists the configured hosts. Files are also writable via `write` and searchable via `search`; a directory only lists (`search` refuses a directory, `write` refuses to overwrite one). A literal `:`, `?`, or `#` in the remote path must be percent-encoded (`%3A`/`%3F`/`%23`) — a trailing `:sel` is read as a line selector, and `?`/`#` start a URL query/fragment. Requires a POSIX login shell (`sh`/`bash`/`zsh`); a Windows host or a non-POSIX shell (fish, csh/tcsh) is rejected — use the `ssh` tool there.
|
|
74
73
|
|
|
75
74
|
<critical>
|
|
76
|
-
- Literal colon filename + selector? Use `selector`, not recursive `path:"file:sel:sel"`.
|
|
77
75
|
- Summary footer names elided ranges? Re-issue ONLY those ranges. NEVER guess `..`/`…` content.
|
|
78
76
|
</critical>
|
package/src/sdk.ts
CHANGED
|
@@ -112,10 +112,12 @@ import {
|
|
|
112
112
|
import { AgentSession, type PlanYolo, type Prewalk } from "./session/agent-session";
|
|
113
113
|
import { discoverAuthStorage as discoverAuthStorageFromConfig } from "./session/auth-broker-config";
|
|
114
114
|
import type { AuthStorage } from "./session/auth-storage";
|
|
115
|
+
import { createInterruptedTurnAbortMessage } from "./session/exit-diagnostics";
|
|
115
116
|
import {
|
|
116
117
|
type CustomMessage,
|
|
117
118
|
convertToLlm,
|
|
118
119
|
LSP_LATE_DIAGNOSTIC_MESSAGE_TYPE,
|
|
120
|
+
replaceLlmImagesWithText,
|
|
119
121
|
USER_INTERRUPT_LABEL,
|
|
120
122
|
wrapSteeringForModel,
|
|
121
123
|
} from "./session/messages";
|
|
@@ -864,6 +866,7 @@ function createCustomToolContext(ctx: ExtensionContext): CustomToolContext {
|
|
|
864
866
|
isIdle: ctx.isIdle,
|
|
865
867
|
hasQueuedMessages: ctx.hasPendingMessages,
|
|
866
868
|
abort: ctx.abort,
|
|
869
|
+
localProtocolOptions: ctx.localProtocolOptions,
|
|
867
870
|
};
|
|
868
871
|
}
|
|
869
872
|
|
|
@@ -1271,11 +1274,19 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1271
1274
|
}
|
|
1272
1275
|
const secretsEnabled = obfuscator?.hasSecrets() === true;
|
|
1273
1276
|
|
|
1274
|
-
//
|
|
1275
|
-
|
|
1277
|
+
// An abnormal process exit after a non-terminal message tail is durable
|
|
1278
|
+
// evidence that the old process can no longer finish that turn. Preserve the
|
|
1279
|
+
// partial transcript and append one terminal aborted assistant record before
|
|
1280
|
+
// rebuilding runtime context. The helper is idempotent once that record exists.
|
|
1281
|
+
let existingBranch = logger.time("getSessionBranch", () => sessionManager.getBranch());
|
|
1282
|
+
const interruptedTurnAbort = createInterruptedTurnAbortMessage(existingBranch);
|
|
1283
|
+
if (interruptedTurnAbort) {
|
|
1284
|
+
sessionManager.appendMessage(interruptedTurnAbort);
|
|
1285
|
+
existingBranch = logger.time("getRecoveredSessionBranch", () => sessionManager.getBranch());
|
|
1286
|
+
}
|
|
1287
|
+
let existingSession = logger.time("loadSessionContext", () =>
|
|
1276
1288
|
deobfuscateSessionContext(sessionManager.buildSessionContext(), obfuscator),
|
|
1277
1289
|
);
|
|
1278
|
-
const existingBranch = logger.time("getSessionBranch", () => sessionManager.getBranch());
|
|
1279
1290
|
const hasExistingSession = existingBranch.length > 0;
|
|
1280
1291
|
const hasThinkingEntry = existingBranch.some(entry => entry.type === "thinking_level_change");
|
|
1281
1292
|
const hasServiceTierEntry = existingBranch.some(entry => entry.type === "service_tier_change");
|
|
@@ -1816,10 +1827,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1816
1827
|
// to mirror the AsyncJobManager ownership rule.
|
|
1817
1828
|
if (mcpManager && !options.parentTaskPrefix) MCPManager.setInstance(mcpManager);
|
|
1818
1829
|
|
|
1819
|
-
// Add image tools when
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1830
|
+
// Add image tools when generation is enabled and either no explicit tool
|
|
1831
|
+
// whitelist was given or it names `generate_image`. Unlike built-in tools
|
|
1832
|
+
// (filtered in `createTools`), custom tools are force-activated via
|
|
1833
|
+
// `alwaysInclude` below, so an explicit `--no-tools`/whitelist must be
|
|
1834
|
+
// honored here or image-gen would leak past every filter (issue #5305).
|
|
1835
|
+
const imageGenRequested = !options.toolNames || options.toolNames.includes("generate_image");
|
|
1836
|
+
if (settings.get("generate_image.enabled") && imageGenRequested) {
|
|
1837
|
+
const imageGenTools = await logger.time("getImageGenTools", () => getImageGenTools(modelRegistry, model));
|
|
1838
|
+
if (imageGenTools.length > 0) {
|
|
1839
|
+
customTools.push(...(imageGenTools as unknown as CustomTool[]));
|
|
1840
|
+
}
|
|
1823
1841
|
}
|
|
1824
1842
|
|
|
1825
1843
|
if (settings.get("speechgen.enabled")) {
|
|
@@ -2166,6 +2184,24 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2166
2184
|
}
|
|
2167
2185
|
}
|
|
2168
2186
|
|
|
2187
|
+
// A first-turn user tail has no assistant metadata to copy. Once startup
|
|
2188
|
+
// has selected its final model, use that model to terminate the
|
|
2189
|
+
// interrupted turn before the live agent consumes the restored context.
|
|
2190
|
+
if (model) {
|
|
2191
|
+
const selectedModelAbort = createInterruptedTurnAbortMessage(existingBranch, {
|
|
2192
|
+
api: model.api,
|
|
2193
|
+
provider: model.provider,
|
|
2194
|
+
model: model.id,
|
|
2195
|
+
});
|
|
2196
|
+
if (selectedModelAbort) {
|
|
2197
|
+
sessionManager.appendMessage(selectedModelAbort);
|
|
2198
|
+
existingBranch = logger.time("getRecoveredUserTailBranch", () => sessionManager.getBranch());
|
|
2199
|
+
existingSession = logger.time("loadRecoveredUserTailContext", () =>
|
|
2200
|
+
deobfuscateSessionContext(sessionManager.buildSessionContext(), obfuscator),
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2169
2205
|
// Discover custom commands (TypeScript slash commands)
|
|
2170
2206
|
const customCommandsResult: CustomCommandsLoadResult = options.disableExtensionDiscovery
|
|
2171
2207
|
? { commands: [], errors: [] }
|
|
@@ -2191,6 +2227,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2191
2227
|
modelRegistry,
|
|
2192
2228
|
() => (hasSession ? createSessionMemoryRuntimeContext(session, agentDir, cwd) : undefined),
|
|
2193
2229
|
settings,
|
|
2230
|
+
localProtocolOptions,
|
|
2194
2231
|
);
|
|
2195
2232
|
|
|
2196
2233
|
credentialDisabledTarget = extensionRunner;
|
|
@@ -2209,6 +2246,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2209
2246
|
session.abort({ reason: USER_INTERRUPT_LABEL });
|
|
2210
2247
|
},
|
|
2211
2248
|
settings,
|
|
2249
|
+
localProtocolOptions,
|
|
2212
2250
|
autoApprove: options.autoApprove ?? false,
|
|
2213
2251
|
});
|
|
2214
2252
|
const toolContextStore = new ToolContextStore(getSessionContext);
|
|
@@ -2618,36 +2656,25 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2618
2656
|
|
|
2619
2657
|
const slashCommands = await slashCommandsPromise;
|
|
2620
2658
|
|
|
2621
|
-
//
|
|
2659
|
+
// Keep image blocks off the wire when they'd be rejected: either the user
|
|
2660
|
+
// disabled images (`images.blockImages`) or the active model has no vision
|
|
2661
|
+
// support. The latter covers switching from a vision model to a text-only
|
|
2662
|
+
// one mid-session — historical image blocks would otherwise be replayed to
|
|
2663
|
+
// a provider that 400s on them (#5400). Read both dynamically so a `/model`
|
|
2664
|
+
// switch or setting change takes effect on the next turn.
|
|
2622
2665
|
const convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {
|
|
2623
2666
|
const converted = convertToLlm(messages);
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
return converted;
|
|
2667
|
+
if (settings.get("images.blockImages")) {
|
|
2668
|
+
return replaceLlmImagesWithText(converted, "Image reading is disabled.");
|
|
2627
2669
|
}
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
.map(c =>
|
|
2637
|
-
c.type === "image" ? { type: "text" as const, text: "Image reading is disabled." } : c,
|
|
2638
|
-
)
|
|
2639
|
-
.filter((c, i, arr) => {
|
|
2640
|
-
// Dedupe consecutive "Image reading is disabled." texts
|
|
2641
|
-
if (!(c.type === "text" && c.text === "Image reading is disabled." && i > 0)) return true;
|
|
2642
|
-
const prev = arr[i - 1];
|
|
2643
|
-
return !(prev.type === "text" && prev.text === "Image reading is disabled.");
|
|
2644
|
-
});
|
|
2645
|
-
return { ...msg, content: filteredContent };
|
|
2646
|
-
}
|
|
2647
|
-
}
|
|
2648
|
-
}
|
|
2649
|
-
return msg;
|
|
2650
|
-
});
|
|
2670
|
+
const activeModel = agent?.state.model ?? model;
|
|
2671
|
+
if (activeModel && !activeModel.input.includes("image")) {
|
|
2672
|
+
return replaceLlmImagesWithText(
|
|
2673
|
+
converted,
|
|
2674
|
+
"[image omitted: the active model does not support image input]",
|
|
2675
|
+
);
|
|
2676
|
+
}
|
|
2677
|
+
return converted;
|
|
2651
2678
|
};
|
|
2652
2679
|
|
|
2653
2680
|
// Final convertToLlm: live provider replay drops API-level refusal errors,
|