@oh-my-pi/pi-coding-agent 16.2.1 → 16.2.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 +23 -0
- package/dist/cli.js +2648 -2662
- package/dist/types/advisor/runtime.d.ts +15 -1
- package/dist/types/config/model-roles.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +32 -12
- package/dist/types/discovery/omp-extension-roots.d.ts +3 -3
- package/dist/types/edit/index.d.ts +18 -0
- package/dist/types/edit/streaming.d.ts +30 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -0
- package/dist/types/extensibility/shared-events.d.ts +1 -0
- package/dist/types/mcp/oauth-discovery.d.ts +0 -11
- package/dist/types/modes/components/status-line/component.d.ts +0 -2
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +26 -2
- package/dist/types/session/messages.d.ts +6 -7
- package/dist/types/session/settings-stream-fn.d.ts +21 -0
- package/dist/types/session/turn-persistence.d.ts +88 -0
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +196 -0
- package/src/advisor/runtime.ts +65 -2
- package/src/auto-thinking/classifier.ts +2 -2
- package/src/config/model-resolver.ts +5 -1
- package/src/config/model-roles.ts +3 -3
- package/src/config/settings-schema.ts +30 -8
- package/src/discovery/omp-extension-roots.ts +38 -13
- package/src/edit/index.ts +21 -0
- package/src/edit/streaming.ts +170 -0
- package/src/extensibility/custom-tools/types.ts +1 -0
- package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +18 -1
- package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +59 -2
- package/src/extensibility/plugins/manager.ts +74 -4
- package/src/extensibility/shared-events.ts +1 -0
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/mcp/oauth-discovery.ts +5 -29
- package/src/mcp/transports/http.ts +3 -1
- package/src/mnemopi/backend.ts +2 -2
- package/src/modes/acp/acp-agent.ts +1 -1
- package/src/modes/components/assistant-message.ts +5 -5
- package/src/modes/components/status-line/component.ts +1 -9
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/controllers/event-controller.ts +8 -11
- package/src/modes/interactive-mode.ts +0 -5
- package/src/modes/print-mode.ts +1 -1
- package/src/modes/utils/transcript-render-helpers.ts +2 -2
- package/src/modes/utils/ui-helpers.ts +5 -4
- package/src/sdk.ts +12 -26
- package/src/session/agent-session.ts +319 -219
- package/src/session/messages.ts +20 -12
- package/src/session/session-persistence.ts +1 -2
- package/src/session/settings-stream-fn.ts +49 -0
- package/src/session/turn-persistence.ts +142 -0
- package/src/session/unexpected-stop-classifier.ts +2 -2
- package/src/slash-commands/helpers/mcp.ts +2 -1
- package/src/tiny/models.ts +8 -6
- package/src/tiny/text.ts +14 -7
- package/src/tools/image-gen.ts +2 -1
- package/src/tools/tts.ts +2 -1
- package/src/utils/title-generator.ts +1 -1
- package/src/web/search/providers/tavily.ts +36 -19
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import { type SecretObfuscator } from "../secrets/obfuscator";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Minimal slice of `Agent` the runtime drives — satisfied by pi-agent-core
|
|
5
|
+
* `Agent`. `state.error` mirrors `Agent.state.error`: provider/stream failures
|
|
6
|
+
* the loop catches internally never reject `prompt()`, so the runtime reads
|
|
7
|
+
* this field after every prompt to detect a failed turn.
|
|
8
|
+
*/
|
|
4
9
|
export interface AdvisorAgent {
|
|
5
10
|
prompt(input: string): Promise<void>;
|
|
6
11
|
abort(reason?: unknown): void;
|
|
7
12
|
reset(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Drop messages appended past `count`. Called after a failed `prompt()` so a
|
|
15
|
+
* retry doesn't replay the failed user batch + synthetic assistant-error
|
|
16
|
+
* turn `Agent.#runLoop` records on its internal state.
|
|
17
|
+
*/
|
|
18
|
+
rollbackTo?(count: number): void;
|
|
8
19
|
readonly state: {
|
|
9
20
|
messages: AgentMessage[];
|
|
21
|
+
error?: string;
|
|
10
22
|
};
|
|
11
23
|
}
|
|
12
24
|
export interface AdvisorRuntimeHost {
|
|
@@ -33,6 +45,8 @@ export interface AdvisorRuntimeHost {
|
|
|
33
45
|
* one that routes `advise()` results back to the primary.
|
|
34
46
|
*/
|
|
35
47
|
beginAdvisorUpdate?(): void;
|
|
48
|
+
/** Surface a non-recovering advisor failure to the host UI without adding model-visible context. */
|
|
49
|
+
notifyFailure?(error: unknown): void;
|
|
36
50
|
}
|
|
37
51
|
export declare class AdvisorRuntime {
|
|
38
52
|
#private;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { type ThemeColor } from "../modes/theme/theme";
|
|
5
5
|
import type { Settings } from "./settings";
|
|
6
|
-
export type ModelRole = "default" | "smol" | "slow" | "vision" | "plan" | "designer" | "commit" | "
|
|
6
|
+
export type ModelRole = "default" | "smol" | "slow" | "vision" | "plan" | "designer" | "commit" | "tiny" | "task" | "advisor";
|
|
7
7
|
export interface ModelRoleInfo {
|
|
8
8
|
tag?: string;
|
|
9
9
|
name: string;
|
|
@@ -1198,6 +1198,30 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
1198
1198
|
}];
|
|
1199
1199
|
};
|
|
1200
1200
|
};
|
|
1201
|
+
readonly textVerbosity: {
|
|
1202
|
+
readonly type: "enum";
|
|
1203
|
+
readonly values: readonly ["low", "medium", "high"];
|
|
1204
|
+
readonly default: "high";
|
|
1205
|
+
readonly ui: {
|
|
1206
|
+
readonly tab: "model";
|
|
1207
|
+
readonly group: "Sampling";
|
|
1208
|
+
readonly label: "Text Verbosity";
|
|
1209
|
+
readonly description: "OpenAI Responses and Codex response verbosity (low, medium, or high)";
|
|
1210
|
+
readonly options: readonly [{
|
|
1211
|
+
readonly value: "low";
|
|
1212
|
+
readonly label: "Low";
|
|
1213
|
+
readonly description: "Prefer concise responses";
|
|
1214
|
+
}, {
|
|
1215
|
+
readonly value: "medium";
|
|
1216
|
+
readonly label: "Medium";
|
|
1217
|
+
readonly description: "Balance brevity and detail";
|
|
1218
|
+
}, {
|
|
1219
|
+
readonly value: "high";
|
|
1220
|
+
readonly label: "High";
|
|
1221
|
+
readonly description: "Prefer detailed responses (default)";
|
|
1222
|
+
}];
|
|
1223
|
+
};
|
|
1224
|
+
};
|
|
1201
1225
|
readonly serviceTier: {
|
|
1202
1226
|
readonly type: "enum";
|
|
1203
1227
|
readonly values: readonly ["none", "auto", "default", "flex", "scale", "priority", "openai-only", "claude-only"];
|
|
@@ -2080,7 +2104,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
2080
2104
|
};
|
|
2081
2105
|
readonly "tools.format": {
|
|
2082
2106
|
readonly type: "enum";
|
|
2083
|
-
readonly values: readonly ["auto", "native", "glm", "hermes", "kimi", "xml", "anthropic", "deepseek", "harmony", "
|
|
2107
|
+
readonly values: readonly ["auto", "native", "glm", "hermes", "kimi", "xml", "anthropic", "deepseek", "harmony", "qwen3", "gemini", "gemma", "minimax"];
|
|
2084
2108
|
readonly default: "auto";
|
|
2085
2109
|
readonly ui: {
|
|
2086
2110
|
readonly tab: "context";
|
|
@@ -2123,10 +2147,6 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
2123
2147
|
readonly value: "harmony";
|
|
2124
2148
|
readonly label: "Harmony";
|
|
2125
2149
|
readonly description: "Use Harmony-style in-band tool calls.";
|
|
2126
|
-
}, {
|
|
2127
|
-
readonly value: "pi";
|
|
2128
|
-
readonly label: "Pi";
|
|
2129
|
-
readonly description: "Use the Pi owned dialect (compact sigil-delimited tool calls).";
|
|
2130
2150
|
}, {
|
|
2131
2151
|
readonly value: "qwen3";
|
|
2132
2152
|
readonly label: "Qwen3";
|
|
@@ -2532,7 +2552,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
2532
2552
|
readonly tab: "memory";
|
|
2533
2553
|
readonly group: "Mnemopi";
|
|
2534
2554
|
readonly label: "Mnemopi LLM Mode";
|
|
2535
|
-
readonly description: "Use no LLM, the
|
|
2555
|
+
readonly description: "Use no LLM, the online tiny model (the TINY role from /models, else pi/smol), or a remote OpenAI-compatible endpoint";
|
|
2536
2556
|
readonly condition: "mnemopiActive";
|
|
2537
2557
|
readonly options: readonly [{
|
|
2538
2558
|
readonly value: "none";
|
|
@@ -2540,8 +2560,8 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
2540
2560
|
readonly description: "Disable Mnemopi LLM-backed extraction";
|
|
2541
2561
|
}, {
|
|
2542
2562
|
readonly value: "smol";
|
|
2543
|
-
readonly label: "
|
|
2544
|
-
readonly description: "Use the
|
|
2563
|
+
readonly label: "Online (tiny)";
|
|
2564
|
+
readonly description: "Use the online tiny model (the TINY role from /models, else pi/smol)";
|
|
2545
2565
|
}, {
|
|
2546
2566
|
readonly value: "remote";
|
|
2547
2567
|
readonly label: "Remote";
|
|
@@ -4607,7 +4627,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
4607
4627
|
readonly tab: "providers";
|
|
4608
4628
|
readonly group: "Tiny Model";
|
|
4609
4629
|
readonly label: "Tiny Model";
|
|
4610
|
-
readonly description: "Session-title model: online pi/smol by default, or a local on-device model";
|
|
4630
|
+
readonly description: "Session-title model: online (the TINY role from /models, else pi/smol) by default, or a local on-device model";
|
|
4611
4631
|
readonly options: ({
|
|
4612
4632
|
value: "online";
|
|
4613
4633
|
label: string;
|
|
@@ -4763,7 +4783,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
4763
4783
|
readonly tab: "memory";
|
|
4764
4784
|
readonly group: "General";
|
|
4765
4785
|
readonly label: "Memory Model";
|
|
4766
|
-
readonly description: "Mnemopi LLM for fact extraction + consolidation: online (smol/remote) by default, or a local on-device model";
|
|
4786
|
+
readonly description: "Mnemopi LLM for fact extraction + consolidation: online (the TINY role from /models, else smol/remote) by default, or a local on-device model";
|
|
4767
4787
|
readonly condition: "mnemopiActive";
|
|
4768
4788
|
readonly options: ({
|
|
4769
4789
|
value: "online";
|
|
@@ -4784,7 +4804,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
4784
4804
|
readonly tab: "model";
|
|
4785
4805
|
readonly group: "Thinking";
|
|
4786
4806
|
readonly label: "Auto Thinking Model";
|
|
4787
|
-
readonly description: "Difficulty classifier for the `auto` thinking level: online smol by default, or a local on-device model";
|
|
4807
|
+
readonly description: "Difficulty classifier for the `auto` thinking level: online (the TINY role from /models, else smol) by default, or a local on-device model";
|
|
4788
4808
|
readonly condition: "autoThinkingActive";
|
|
4789
4809
|
readonly options: ({
|
|
4790
4810
|
value: "online";
|
|
@@ -4815,7 +4835,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
4815
4835
|
readonly tab: "providers";
|
|
4816
4836
|
readonly group: "Tiny Model";
|
|
4817
4837
|
readonly label: "Unexpected Stop Model";
|
|
4818
|
-
readonly description: "Classifier for unexpected-stop detection: online smol by default, or a local on-device model.";
|
|
4838
|
+
readonly description: "Classifier for unexpected-stop detection: online (the TINY role from /models, else smol) by default, or a local on-device model.";
|
|
4819
4839
|
readonly condition: "unexpectedStopDetection";
|
|
4820
4840
|
readonly options: ({
|
|
4821
4841
|
value: "online";
|
|
@@ -31,9 +31,9 @@ export declare function getInjectedOmpExtensionCliRoots(): readonly OmpExtension
|
|
|
31
31
|
* 1. CLI roots injected via {@link injectOmpExtensionCliRoots}
|
|
32
32
|
* 2. Project `<cwd>/.omp/settings.json#extensions`
|
|
33
33
|
* 3. User `~/.omp/agent/settings.json#extensions`
|
|
34
|
-
* 4. Enabled plugins installed under `<plugins>/node_modules/` (
|
|
35
|
-
* `omp install <pkg>` / `omp plugin install` / `omp plugin link`)
|
|
36
|
-
*
|
|
34
|
+
* 4. Enabled npm/link plugins installed under `<plugins>/node_modules/` (for
|
|
35
|
+
* `omp install <pkg>` / `omp plugin install` / `omp plugin link`). Marketplace
|
|
36
|
+
* installs are loaded by the `claude-plugins` provider and are excluded here.
|
|
37
37
|
* Only entries that resolve to a directory on disk are returned; file
|
|
38
38
|
* entrypoints contribute zero sub-discovery surface and are filtered out.
|
|
39
39
|
* Installed-plugin enumeration failures (missing lockfile, unreadable
|
|
@@ -60,5 +60,23 @@ export declare class EditTool implements AgentTool<TInput> {
|
|
|
60
60
|
* mode-specific patch grammar.
|
|
61
61
|
*/
|
|
62
62
|
matcherDigest(args: unknown): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Project the streamed args onto their target file paths so path-scoped
|
|
65
|
+
* stream matchers (e.g. TTSR `tool:edit(*.ts)` globs) match hashline and
|
|
66
|
+
* apply_patch edits even though the path lives in the wire payload (a
|
|
67
|
+
* section header / envelope marker) rather than a top-level argument.
|
|
68
|
+
*/
|
|
69
|
+
matcherPaths(args: unknown): readonly string[] | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Per-file projection of the streamed args, splitting multi-section
|
|
72
|
+
* hashline / multi-hunk apply_patch payloads into one (path, digest) entry
|
|
73
|
+
* per touched file. Path-scoped stream matchers (TTSR) then evaluate each
|
|
74
|
+
* file in isolation, so a `tool:edit(*.ts)` rule never fires on text that
|
|
75
|
+
* actually belongs to a sibling Markdown hunk.
|
|
76
|
+
*/
|
|
77
|
+
matcherEntries(args: unknown): readonly {
|
|
78
|
+
path: string;
|
|
79
|
+
digest: string;
|
|
80
|
+
}[] | undefined;
|
|
63
81
|
execute(_toolCallId: string, params: EditParams, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>, context?: AgentToolContext): Promise<AgentToolResult<EditToolDetails, TInput>>;
|
|
64
82
|
}
|
|
@@ -35,6 +35,16 @@ export interface StreamingDiffContext {
|
|
|
35
35
|
*/
|
|
36
36
|
isStreaming?: boolean;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Per-file projection of a streamed edit payload. Pairs one target file path
|
|
40
|
+
* with the digest of only the lines added to that file, so path-scoped stream
|
|
41
|
+
* matchers (TTSR) evaluate each file in isolation — a `tool:edit(*.ts)` rule
|
|
42
|
+
* never fires on text that actually belongs to a sibling `README.md` hunk.
|
|
43
|
+
*/
|
|
44
|
+
export interface EditMatcherEntry {
|
|
45
|
+
readonly path: string;
|
|
46
|
+
readonly digest: string;
|
|
47
|
+
}
|
|
38
48
|
export interface EditStreamingStrategy<Args = unknown> {
|
|
39
49
|
/**
|
|
40
50
|
* Return the args restricted to edits that are "complete enough" to
|
|
@@ -60,6 +70,26 @@ export interface EditStreamingStrategy<Args = unknown> {
|
|
|
60
70
|
* args don't yet carry any content.
|
|
61
71
|
*/
|
|
62
72
|
matcherDigest(args: Args): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Surface the target file paths a (potentially partial) call would touch,
|
|
75
|
+
* so path-scoped stream matchers (e.g. TTSR `tool:edit(*.ts)` globs) match
|
|
76
|
+
* even when the path is not a top-level argument but lives inside the wire
|
|
77
|
+
* payload — `hashline` section headers, `apply_patch` envelope markers.
|
|
78
|
+
* Returns `undefined` (or an empty list) when no paths are recoverable.
|
|
79
|
+
*/
|
|
80
|
+
matcherPaths(args: Args): readonly string[] | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Per-file projection of the (potentially partial) args: one entry per
|
|
83
|
+
* touched file pairing the path with the digest of only the lines added to
|
|
84
|
+
* that file. Multi-file payloads (multi-section hashline / multi-hunk
|
|
85
|
+
* apply_patch) MUST split here so callers can evaluate each file under its
|
|
86
|
+
* own path scope instead of leaking added lines from one file into the
|
|
87
|
+
* other's match context. Same-path sections / hunks are merged into one
|
|
88
|
+
* entry. Returns `undefined` (or empty) when no per-file split is
|
|
89
|
+
* recoverable yet — the caller falls back to {@link matcherDigest} +
|
|
90
|
+
* {@link matcherPaths}.
|
|
91
|
+
*/
|
|
92
|
+
matcherEntries(args: Args): readonly EditMatcherEntry[] | undefined;
|
|
63
93
|
}
|
|
64
94
|
/**
|
|
65
95
|
* Given an edits array parsed from partial JSON, drop the last entry when the
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP OAuth Auto-Discovery
|
|
3
|
-
*
|
|
4
|
-
* Automatically detects OAuth requirements from MCP server responses
|
|
5
|
-
* and extracts authentication endpoints.
|
|
6
|
-
*/
|
|
7
1
|
import type { FetchImpl } from "@oh-my-pi/pi-ai/types";
|
|
8
2
|
export interface OAuthEndpoints {
|
|
9
3
|
authorizationUrl: string;
|
|
@@ -21,11 +15,6 @@ export interface AuthDetectionResult {
|
|
|
21
15
|
message?: string;
|
|
22
16
|
}
|
|
23
17
|
export declare function extractMcpAuthServerUrl(error: Error, serverUrl?: string): string | undefined;
|
|
24
|
-
/**
|
|
25
|
-
* Detect if an error indicates authentication is required.
|
|
26
|
-
* Checks for common auth error patterns.
|
|
27
|
-
*/
|
|
28
|
-
export declare function detectAuthError(error: Error): boolean;
|
|
29
18
|
/**
|
|
30
19
|
* Extract OAuth endpoints from error response.
|
|
31
20
|
* Looks for WWW-Authenticate header format or JSON error bodies.
|
|
@@ -14,8 +14,6 @@ export declare class StatusLineComponent implements Component {
|
|
|
14
14
|
getEffectiveSettingsForTest(): EffectiveStatusLineSettings;
|
|
15
15
|
setAutoCompactEnabled(enabled: boolean): void;
|
|
16
16
|
setSubagentCount(count: number): void;
|
|
17
|
-
/** Hub key label shown in the forced running-subagents badge. */
|
|
18
|
-
setSubagentHubHint(hint: string | undefined): void;
|
|
19
17
|
/** Active subagent count as currently displayed (collab state mirroring). */
|
|
20
18
|
get subagentCount(): number;
|
|
21
19
|
setSessionStartTime(time: number): void;
|
package/dist/types/sdk.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AgentTelemetryConfig, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
|
-
import {
|
|
2
|
+
import type { Model } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
|
|
4
4
|
import { type Rule } from "./capability/rule";
|
|
5
5
|
import { ModelRegistry } from "./config/model-registry";
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* Modes use this class and add their own I/O layer on top.
|
|
14
14
|
*/
|
|
15
15
|
import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
16
|
-
import { Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, ThinkingLevel, type ToolChoiceDirective } from "@oh-my-pi/pi-agent-core";
|
|
16
|
+
import { Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, type StreamFn, ThinkingLevel, type ToolChoiceDirective } from "@oh-my-pi/pi-agent-core";
|
|
17
17
|
import { type CompactionResult, type ShakeConfig } from "@oh-my-pi/pi-agent-core/compaction";
|
|
18
|
-
import type { AssistantMessage, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
|
|
18
|
+
import type { AssistantMessage, Context, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
|
|
19
19
|
import { Effort } from "@oh-my-pi/pi-ai";
|
|
20
20
|
import { type AsyncJob, type AsyncJobDeliveryState, AsyncJobManager } from "../async";
|
|
21
21
|
import type { Rule } from "../capability/rule";
|
|
@@ -72,6 +72,7 @@ export type AgentSessionEvent = AgentEvent | {
|
|
|
72
72
|
maxAttempts: number;
|
|
73
73
|
delayMs: number;
|
|
74
74
|
errorMessage: string;
|
|
75
|
+
errorId?: number;
|
|
75
76
|
} | {
|
|
76
77
|
type: "auto_retry_end";
|
|
77
78
|
success: boolean;
|
|
@@ -160,6 +161,21 @@ export interface AgentSessionConfig {
|
|
|
160
161
|
builtInToolNames?: Iterable<string>;
|
|
161
162
|
/** Current session pre-LLM message transform pipeline */
|
|
162
163
|
transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => AgentMessage[] | Promise<AgentMessage[]>;
|
|
164
|
+
/**
|
|
165
|
+
* Per-request transform applied after `convertToLlm` and before the
|
|
166
|
+
* provider call. Used for snapcompact, secret obfuscation, and image
|
|
167
|
+
* clamping. When supplied via {@link createAgentSession}, the advisor agent
|
|
168
|
+
* inherits this so its requests undergo the same shaping as the main turn.
|
|
169
|
+
*/
|
|
170
|
+
transformProviderContext?: (context: Context, model: Model) => Context | Promise<Context>;
|
|
171
|
+
/**
|
|
172
|
+
* Stream wrapper passed to the advisor agent so its requests apply the
|
|
173
|
+
* session's `providers.openrouterVariant`, `providers.antigravityEndpoint`,
|
|
174
|
+
* `providers.maxInFlightRequests`, and `model.loopGuard.*` settings —
|
|
175
|
+
* keeping OpenRouter sticky-routing / response caching consistent with the
|
|
176
|
+
* main agent. Defaults to plain `streamSimple` when omitted.
|
|
177
|
+
*/
|
|
178
|
+
advisorStreamFn?: StreamFn;
|
|
163
179
|
/** Provider payload hook used by the active session request path */
|
|
164
180
|
onPayload?: SimpleStreamOptions["onPayload"];
|
|
165
181
|
/** Provider response hook used by the active session request path */
|
|
@@ -1253,6 +1269,14 @@ export declare class AgentSession {
|
|
|
1253
1269
|
* not merely the setting. Drives the status-line badge and `/dump advisor`.
|
|
1254
1270
|
*/
|
|
1255
1271
|
isAdvisorActive(): boolean;
|
|
1272
|
+
/**
|
|
1273
|
+
* The live advisor `Agent`, or `undefined` when no advisor runtime is
|
|
1274
|
+
* attached. Surfaced for diagnostics (`/dump advisor` already serializes
|
|
1275
|
+
* its transcript via {@link formatAdvisorHistoryAsText}) and so callers can
|
|
1276
|
+
* verify the advisor inherits the session's provider-shaping options
|
|
1277
|
+
* (`streamFn`, `promptCacheKey`, `providerSessionState`, ...).
|
|
1278
|
+
*/
|
|
1279
|
+
getAdvisorAgent(): Agent | undefined;
|
|
1256
1280
|
/**
|
|
1257
1281
|
* Return structured advisor stats for the status command and TUI panel.
|
|
1258
1282
|
*/
|
|
@@ -43,18 +43,17 @@ export interface SkillPromptDetails {
|
|
|
43
43
|
* #buildTranscriptLines`, `runPrintMode`, and `AcpAgent#replayAssistantMessage`
|
|
44
44
|
* (fallback error emission) read it via `isSilentAbort`. */
|
|
45
45
|
export declare const SILENT_ABORT_MARKER = "__omp.silent_abort__";
|
|
46
|
-
/** Type-guard for
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
export declare function isSilentAbort(errorMessage: string | undefined): boolean;
|
|
46
|
+
/** Type-guard for silent aborts. Renderers MUST call this helper so structured
|
|
47
|
+
* `errorId` and legacy persisted marker messages stay in lockstep. */
|
|
48
|
+
export declare function isSilentAbort(message: Pick<AssistantMessage, "errorId" | "errorMessage">): boolean;
|
|
50
49
|
/** Reason threaded through `AbortController.abort(reason)` when the user aborts
|
|
51
50
|
* the turn with Esc (see `AgentSession.abort`). The agent keeps it on the
|
|
52
51
|
* aborted assistant message's `errorMessage` so queued follow-ups/tool-result
|
|
53
52
|
* placeholders can distinguish a deliberate interrupt from a bare lifecycle
|
|
54
53
|
* abort, but interactive renderers suppress this redundant transcript line. */
|
|
55
54
|
export declare const USER_INTERRUPT_LABEL = "Interrupted by user";
|
|
56
|
-
export declare function isUserInterruptAbort(
|
|
57
|
-
export declare function shouldRenderAbortReason(
|
|
55
|
+
export declare function isUserInterruptAbort(message: Pick<AssistantMessage, "errorId" | "errorMessage">): boolean;
|
|
56
|
+
export declare function shouldRenderAbortReason(message: Pick<AssistantMessage, "errorId" | "errorMessage">): boolean;
|
|
58
57
|
/** Sentinel `errorMessage` the agent stamps on any abort that carried no custom
|
|
59
58
|
* reason (bare `abort()`). Renderers treat it as "no specific reason given". */
|
|
60
59
|
export declare const GENERIC_ABORT_SENTINEL = "Request was aborted";
|
|
@@ -63,7 +62,7 @@ export declare const GENERIC_ABORT_SENTINEL = "Request was aborted";
|
|
|
63
62
|
* no threaded reason fall back to the retry-aware generic label. Call
|
|
64
63
|
* `shouldRenderAbortReason` before rendering when user interrupts should stay
|
|
65
64
|
* visually quiet. */
|
|
66
|
-
export declare function resolveAbortLabel(
|
|
65
|
+
export declare function resolveAbortLabel(message: Pick<AssistantMessage, "errorId" | "errorMessage">, retryAttempt?: number): string;
|
|
67
66
|
/** Extract the optional `__queueChipText` field from a CustomMessage's
|
|
68
67
|
* `details` blob. Safe over `unknown`; returns undefined when the field is
|
|
69
68
|
* absent or non-string. */
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings-aware stream wrapper shared by the main agent (sdk.ts) and the
|
|
3
|
+
* advisor agent (AgentSession.#buildAdvisorRuntime).
|
|
4
|
+
*
|
|
5
|
+
* Reads OpenRouter / Antigravity routing variants, Responses-family text
|
|
6
|
+
* verbosity, per-provider in-flight caps, and the loop guard out of `Settings`
|
|
7
|
+
* per request, layering them onto whatever options the caller passed. Before
|
|
8
|
+
* this helper existed, advisor turns called bare `streamSimple` while the main
|
|
9
|
+
* turn went through an inline closure that read these settings — so an advisor on
|
|
10
|
+
* OpenRouter never saw `providers.openrouterVariant`, breaking sticky routing
|
|
11
|
+
* and OpenRouter response-cache hits across advisor calls.
|
|
12
|
+
*/
|
|
13
|
+
import type { StreamFn } from "@oh-my-pi/pi-agent-core";
|
|
14
|
+
import { type Settings } from "../config/settings";
|
|
15
|
+
/**
|
|
16
|
+
* Build a {@link StreamFn} that reads provider routing/guard settings from
|
|
17
|
+
* `settings` per call and forwards to `base` (defaults to `streamSimple`).
|
|
18
|
+
*
|
|
19
|
+
* Caller-supplied `streamOptions` always win — the helper only fills holes.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createSettingsAwareStreamFn(settings: Settings, base?: StreamFn): StreamFn;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers that share one cheap, structural identity for messages — both during
|
|
3
|
+
* incremental persistence and for the mid-run-compaction ordering check.
|
|
4
|
+
*
|
|
5
|
+
* Previously `AgentSession` carried two near-duplicate routines
|
|
6
|
+
* (`#sessionMessagesReferToSameTurn` + `#messageValueSignature`) that
|
|
7
|
+
* reconstructed the branch path on every check (O(n²) `unshift`) and
|
|
8
|
+
* `JSON.stringify`-compared the full message content on every pairwise hit.
|
|
9
|
+
* Long-running sessions with many subagents fired this thousands of times per
|
|
10
|
+
* minute and froze the TUI loop (see issue #3629). The persistence key already
|
|
11
|
+
* encodes a stable logical identity — timestamp + role-specific discriminators
|
|
12
|
+
* — so the structural compare is now the rare collision tiebreaker (e.g. two
|
|
13
|
+
* provider responses at the same millisecond with `undefined` responseId),
|
|
14
|
+
* not the load-bearing check.
|
|
15
|
+
*
|
|
16
|
+
* The helpers here keep that identity in one place and expose the planner so
|
|
17
|
+
* the persistence-ordering logic is unit-testable without standing up an
|
|
18
|
+
* `AgentSession`.
|
|
19
|
+
*/
|
|
20
|
+
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
21
|
+
/**
|
|
22
|
+
* Stable identity for messages that pass through {@link AgentSession}'s
|
|
23
|
+
* incremental persistence path.
|
|
24
|
+
*
|
|
25
|
+
* The discriminators chosen per role are precisely the fields that uniquely
|
|
26
|
+
* identify a single logical message instance:
|
|
27
|
+
*
|
|
28
|
+
* - `assistant` — timestamp + provider + model + responseId + stopReason
|
|
29
|
+
* (responseId is the canonical provider-side id when available; the rest
|
|
30
|
+
* disambiguate when it is not, e.g. local/dev models).
|
|
31
|
+
* - `toolResult` — timestamp + toolCallId + toolName (toolCallId is unique
|
|
32
|
+
* per execution; toolName guards against synthetic reuse).
|
|
33
|
+
* - `user` / `developer` — timestamp + attribution (attribution distinguishes
|
|
34
|
+
* user-typed vs hook-injected at the same wall-clock millisecond).
|
|
35
|
+
* - `fileMention` — timestamp.
|
|
36
|
+
*
|
|
37
|
+
* Returns `undefined` for message roles that are not persisted through this
|
|
38
|
+
* path (e.g. `hookMessage`, `custom`, `bashExecution`) — those follow other
|
|
39
|
+
* append paths in `SessionManager`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function sessionMessagePersistenceKey(message: AgentMessage): string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Slow-path content equality check used when two messages collide on
|
|
44
|
+
* {@link sessionMessagePersistenceKey}. Only the role's content fields are
|
|
45
|
+
* compared (no timestamps, no metadata) because the key already pinned all of
|
|
46
|
+
* those down.
|
|
47
|
+
*
|
|
48
|
+
* Most calls into the persistence path never reach this — keys are unique
|
|
49
|
+
* enough in production that the snapshot lookup short-circuits at the key
|
|
50
|
+
* level. Restoring the structural compare here preserves the pre-#3629
|
|
51
|
+
* contract that two messages with the same metadata BUT different content are
|
|
52
|
+
* distinct (e.g. two assistant turns with `undefined` responseId emitted in
|
|
53
|
+
* the same wall-clock millisecond, which is exactly how the in-memory test
|
|
54
|
+
* harness crafts streamed responses).
|
|
55
|
+
*/
|
|
56
|
+
export declare function sameMessageContent(left: AgentMessage, right: AgentMessage): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Outcome of {@link planTurnPersistence}.
|
|
59
|
+
*
|
|
60
|
+
* `ok` lists the turn-message indices that still need to be appended (in
|
|
61
|
+
* order). `out-of-order` reports the first message whose later sibling is
|
|
62
|
+
* already persisted — the caller bails so it does not silently splice a
|
|
63
|
+
* stale message between newer entries on the live branch.
|
|
64
|
+
*/
|
|
65
|
+
export type TurnPersistencePlan = {
|
|
66
|
+
kind: "ok";
|
|
67
|
+
toPersist: readonly number[];
|
|
68
|
+
} | {
|
|
69
|
+
kind: "out-of-order";
|
|
70
|
+
messageIndex: number;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Decide what to do with a turn's messages relative to what's already on the
|
|
74
|
+
* branch, in a single pass over the pre-computed keys.
|
|
75
|
+
*
|
|
76
|
+
* @param turnKeys persistence keys for each turn message, in the order the
|
|
77
|
+
* agent loop emitted them. `undefined` slots represent messages with no
|
|
78
|
+
* persistence key (skipped silently).
|
|
79
|
+
* @param persistedKeys the snapshot of persistence keys currently on the
|
|
80
|
+
* branch (built once per call from {@link sessionMessagePersistenceKey} for
|
|
81
|
+
* each persisted message entry).
|
|
82
|
+
*
|
|
83
|
+
* The check is O(n²) over turn messages — but `n` here is the size of one
|
|
84
|
+
* turn (a handful of tool results), not the size of the branch. That's the
|
|
85
|
+
* point of this refactor: the expensive O(branch) work happens exactly once,
|
|
86
|
+
* inside the caller's snapshot loop, not per-comparison.
|
|
87
|
+
*/
|
|
88
|
+
export declare function planTurnPersistence(turnKeys: readonly (string | undefined)[], persistedKeys: ReadonlySet<string>): TurnPersistencePlan;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "16.2.
|
|
4
|
+
"version": "16.2.2",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
"@agentclientprotocol/sdk": "0.25.0",
|
|
56
56
|
"@babel/parser": "^7.29.7",
|
|
57
57
|
"@mozilla/readability": "^0.6.0",
|
|
58
|
-
"@oh-my-pi/hashline": "16.2.
|
|
59
|
-
"@oh-my-pi/omp-stats": "16.2.
|
|
60
|
-
"@oh-my-pi/pi-agent-core": "16.2.
|
|
61
|
-
"@oh-my-pi/pi-ai": "16.2.
|
|
62
|
-
"@oh-my-pi/pi-catalog": "16.2.
|
|
63
|
-
"@oh-my-pi/pi-mnemopi": "16.2.
|
|
64
|
-
"@oh-my-pi/pi-natives": "16.2.
|
|
65
|
-
"@oh-my-pi/pi-tui": "16.2.
|
|
66
|
-
"@oh-my-pi/pi-utils": "16.2.
|
|
67
|
-
"@oh-my-pi/pi-wire": "16.2.
|
|
68
|
-
"@oh-my-pi/snapcompact": "16.2.
|
|
58
|
+
"@oh-my-pi/hashline": "16.2.2",
|
|
59
|
+
"@oh-my-pi/omp-stats": "16.2.2",
|
|
60
|
+
"@oh-my-pi/pi-agent-core": "16.2.2",
|
|
61
|
+
"@oh-my-pi/pi-ai": "16.2.2",
|
|
62
|
+
"@oh-my-pi/pi-catalog": "16.2.2",
|
|
63
|
+
"@oh-my-pi/pi-mnemopi": "16.2.2",
|
|
64
|
+
"@oh-my-pi/pi-natives": "16.2.2",
|
|
65
|
+
"@oh-my-pi/pi-tui": "16.2.2",
|
|
66
|
+
"@oh-my-pi/pi-utils": "16.2.2",
|
|
67
|
+
"@oh-my-pi/pi-wire": "16.2.2",
|
|
68
|
+
"@oh-my-pi/snapcompact": "16.2.2",
|
|
69
69
|
"@opentelemetry/api": "^1.9.1",
|
|
70
70
|
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
71
71
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
|