@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
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Automatically detects OAuth requirements from MCP server responses
|
|
5
5
|
* and extracts authentication endpoints.
|
|
6
6
|
*/
|
|
7
|
+
import * as AIError from "@oh-my-pi/pi-ai/error";
|
|
7
8
|
import type { FetchImpl } from "@oh-my-pi/pi-ai/types";
|
|
8
9
|
|
|
9
10
|
export interface OAuthEndpoints {
|
|
@@ -23,8 +24,8 @@ export interface AuthDetectionResult {
|
|
|
23
24
|
message?: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
function
|
|
27
|
-
const match =
|
|
27
|
+
export function extractMcpAuthServerUrl(error: Error, serverUrl?: string): string | undefined {
|
|
28
|
+
const match = error.message.match(/Mcp-Auth-Server:\s*([^;\]\s]+)/i);
|
|
28
29
|
if (!match?.[1]) return undefined;
|
|
29
30
|
|
|
30
31
|
try {
|
|
@@ -34,32 +35,6 @@ function parseMcpAuthServerUrl(errorMessage: string, serverUrl?: string): string
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
export function extractMcpAuthServerUrl(error: Error, serverUrl?: string): string | undefined {
|
|
38
|
-
return parseMcpAuthServerUrl(error.message, serverUrl);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Detect if an error indicates authentication is required.
|
|
43
|
-
* Checks for common auth error patterns.
|
|
44
|
-
*/
|
|
45
|
-
export function detectAuthError(error: Error): boolean {
|
|
46
|
-
const errorMsg = error.message.toLowerCase();
|
|
47
|
-
|
|
48
|
-
// Check for HTTP auth status codes
|
|
49
|
-
if (
|
|
50
|
-
errorMsg.includes("401") ||
|
|
51
|
-
errorMsg.includes("403") ||
|
|
52
|
-
errorMsg.includes("unauthorized") ||
|
|
53
|
-
errorMsg.includes("forbidden") ||
|
|
54
|
-
errorMsg.includes("authentication required") ||
|
|
55
|
-
errorMsg.includes("authentication failed")
|
|
56
|
-
) {
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
38
|
/**
|
|
64
39
|
* Extract OAuth endpoints from error response.
|
|
65
40
|
* Looks for WWW-Authenticate header format or JSON error bodies.
|
|
@@ -200,7 +175,8 @@ export function extractOAuthEndpoints(error: Error): OAuthEndpoints | null {
|
|
|
200
175
|
* Returns structured info about what auth is needed.
|
|
201
176
|
*/
|
|
202
177
|
export function analyzeAuthError(error: Error, serverUrl?: string): AuthDetectionResult {
|
|
203
|
-
|
|
178
|
+
// No auth required unless the error carries an HTTP auth status / auth-failure phrasing.
|
|
179
|
+
if (!AIError.is(AIError.classify(error), AIError.Flag.AuthFailed)) {
|
|
204
180
|
return { requiresAuth: false };
|
|
205
181
|
}
|
|
206
182
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Implements JSON-RPC 2.0 over HTTP POST with optional SSE streaming.
|
|
5
5
|
* Based on MCP spec 2025-03-26.
|
|
6
6
|
*/
|
|
7
|
+
import * as AIError from "@oh-my-pi/pi-ai/error";
|
|
7
8
|
import { logger, readSseJson, Snowflake } from "@oh-my-pi/pi-utils";
|
|
8
9
|
import type {
|
|
9
10
|
JsonRpcError,
|
|
@@ -186,7 +187,8 @@ export class HttpTransport implements MCPTransport {
|
|
|
186
187
|
return await this.#executeRequest<T>(method, params, options);
|
|
187
188
|
} catch (error) {
|
|
188
189
|
// Retry once on auth failure if onAuthError is wired
|
|
189
|
-
|
|
190
|
+
const status = error instanceof Error ? AIError.status(error) : undefined;
|
|
191
|
+
if (this.onAuthError && (status === 401 || status === 403)) {
|
|
190
192
|
const newHeaders = await this.onAuthError();
|
|
191
193
|
if (newHeaders) {
|
|
192
194
|
// Persist refreshed headers so subsequent requests use them directly
|
package/src/mnemopi/backend.ts
CHANGED
|
@@ -511,10 +511,10 @@ async function resolveMnemopiProviderOptions(
|
|
|
511
511
|
}
|
|
512
512
|
|
|
513
513
|
try {
|
|
514
|
-
const resolved = resolveRoleSelection(["smol"], settings, modelRegistry.getAvailable(), modelRegistry);
|
|
514
|
+
const resolved = resolveRoleSelection(["tiny", "smol"], settings, modelRegistry.getAvailable(), modelRegistry);
|
|
515
515
|
const model = resolved?.model;
|
|
516
516
|
if (!model) {
|
|
517
|
-
logger.warn("Mnemopi: llmMode=smol but no smol model resolved; continuing without LLM.");
|
|
517
|
+
logger.warn("Mnemopi: llmMode=smol but no tiny/smol model resolved; continuing without LLM.");
|
|
518
518
|
return base;
|
|
519
519
|
}
|
|
520
520
|
return {
|
|
@@ -2014,7 +2014,7 @@ export class AcpAgent implements Agent {
|
|
|
2014
2014
|
}
|
|
2015
2015
|
}
|
|
2016
2016
|
}
|
|
2017
|
-
if (notifications.length === 0 && message.errorMessage && !isSilentAbort(message
|
|
2017
|
+
if (notifications.length === 0 && message.errorMessage && !isSilentAbort(message)) {
|
|
2018
2018
|
notifications.push({
|
|
2019
2019
|
sessionId,
|
|
2020
2020
|
update: {
|
|
@@ -581,11 +581,11 @@ export class AssistantMessageComponent extends Container {
|
|
|
581
581
|
if (content.type === "toolCall") return false;
|
|
582
582
|
}
|
|
583
583
|
if (this.#toolImagesByCallId.size > 0) return false;
|
|
584
|
-
if (message.stopReason === "aborted" && shouldRenderAbortReason(message
|
|
584
|
+
if (message.stopReason === "aborted" && shouldRenderAbortReason(message)) return false;
|
|
585
585
|
if (message.stopReason === "error" && !this.#errorPinned) return false;
|
|
586
586
|
if (
|
|
587
587
|
message.errorMessage &&
|
|
588
|
-
shouldRenderAbortReason(message
|
|
588
|
+
shouldRenderAbortReason(message) &&
|
|
589
589
|
message.stopReason !== "aborted" &&
|
|
590
590
|
message.stopReason !== "error"
|
|
591
591
|
)
|
|
@@ -779,8 +779,8 @@ export class AssistantMessageComponent extends Container {
|
|
|
779
779
|
// But only if there are no tool calls (tool execution components will show the error)
|
|
780
780
|
const hasToolCalls = message.content.some(c => c.type === "toolCall");
|
|
781
781
|
if (!hasToolCalls) {
|
|
782
|
-
if (message.stopReason === "aborted" && shouldRenderAbortReason(message
|
|
783
|
-
const abortMessage = resolveAbortLabel(message
|
|
782
|
+
if (message.stopReason === "aborted" && shouldRenderAbortReason(message)) {
|
|
783
|
+
const abortMessage = resolveAbortLabel(message);
|
|
784
784
|
if (hasVisibleContent) {
|
|
785
785
|
this.#contentContainer.addChild(new Spacer(1));
|
|
786
786
|
} else {
|
|
@@ -793,7 +793,7 @@ export class AssistantMessageComponent extends Container {
|
|
|
793
793
|
}
|
|
794
794
|
if (
|
|
795
795
|
message.errorMessage &&
|
|
796
|
-
shouldRenderAbortReason(message
|
|
796
|
+
shouldRenderAbortReason(message) &&
|
|
797
797
|
message.stopReason !== "aborted" &&
|
|
798
798
|
message.stopReason !== "error"
|
|
799
799
|
) {
|
|
@@ -200,7 +200,6 @@ export class StatusLineComponent implements Component {
|
|
|
200
200
|
#autoCompactEnabled: boolean = true;
|
|
201
201
|
#hookStatuses: Map<string, string> = new Map();
|
|
202
202
|
#subagentCount: number = 0;
|
|
203
|
-
#subagentHubHint: string | undefined;
|
|
204
203
|
#sessionStartTime: number = Date.now();
|
|
205
204
|
#planModeStatus: { enabled: boolean; paused: boolean } | null = null;
|
|
206
205
|
#loopModeStatus: { enabled: boolean } | null = null;
|
|
@@ -306,12 +305,6 @@ export class StatusLineComponent implements Component {
|
|
|
306
305
|
this.#subagentCount = count;
|
|
307
306
|
}
|
|
308
307
|
|
|
309
|
-
/** Hub key label shown in the forced running-subagents badge. */
|
|
310
|
-
setSubagentHubHint(hint: string | undefined): void {
|
|
311
|
-
const trimmed = hint?.trim();
|
|
312
|
-
this.#subagentHubHint = trimmed ? trimmed : undefined;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
308
|
/** Active subagent count as currently displayed (collab state mirroring). */
|
|
316
309
|
get subagentCount(): number {
|
|
317
310
|
return this.#subagentCount;
|
|
@@ -925,8 +918,7 @@ export class StatusLineComponent implements Component {
|
|
|
925
918
|
#subagentBadgeText(): string | undefined {
|
|
926
919
|
if (this.#subagentCount === 0) return undefined;
|
|
927
920
|
const noun = this.#subagentCount === 1 ? "agent" : "agents";
|
|
928
|
-
|
|
929
|
-
return theme.fg("statusLineSubagents", `${theme.icon.agents} ${this.#subagentCount} ${noun} running${hubHint}`);
|
|
921
|
+
return theme.fg("statusLineSubagents", `${theme.icon.agents} ${this.#subagentCount} ${noun}`);
|
|
930
922
|
}
|
|
931
923
|
|
|
932
924
|
#buildStatusLine(width: number): string {
|
|
@@ -21,7 +21,7 @@ function withIcon(icon: string, text: string): string {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function stripDisplayRoot(pwd: string): string {
|
|
24
|
-
for (const root of [
|
|
24
|
+
for (const root of [path.join(os.homedir(), "Projects"), "/work"]) {
|
|
25
25
|
const relative = relativePathWithinRoot(root, pwd);
|
|
26
26
|
if (relative) return relative;
|
|
27
27
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
2
|
-
import
|
|
2
|
+
import * as AIError from "@oh-my-pi/pi-ai/error";
|
|
3
|
+
import { getStreamingPartialJson } from "@oh-my-pi/pi-ai/utils/block-symbols";
|
|
3
4
|
import { type Component, Loader, TERMINAL } from "@oh-my-pi/pi-tui";
|
|
4
5
|
import { INTENT_FIELD } from "@oh-my-pi/pi-wire";
|
|
5
6
|
import { extractTextContent } from "../../commit/utils";
|
|
@@ -609,9 +610,9 @@ export class EventController {
|
|
|
609
610
|
// reveal (write/edit/bash previews grow smoothly when a slow provider
|
|
610
611
|
// delivers large batches); once it closes, the final args render
|
|
611
612
|
// as-is — mirroring how assistant text snaps at message_end.
|
|
612
|
-
const partialJson = "partialJson" in content ? content.partialJson : undefined;
|
|
613
613
|
let renderArgs: Record<string, unknown>;
|
|
614
|
-
|
|
614
|
+
const partialJson = getStreamingPartialJson(content);
|
|
615
|
+
if (partialJson) {
|
|
615
616
|
renderArgs = this.#toolArgsReveal.setTarget(
|
|
616
617
|
content.id,
|
|
617
618
|
partialJson,
|
|
@@ -697,7 +698,7 @@ export class EventController {
|
|
|
697
698
|
this.#toolArgsReveal.flushAll();
|
|
698
699
|
let errorMessage: string | undefined;
|
|
699
700
|
const aborted = this.ctx.streamingMessage.stopReason === "aborted";
|
|
700
|
-
const silentlyAborted = aborted && isSilentAbort(this.ctx.streamingMessage
|
|
701
|
+
const silentlyAborted = aborted && isSilentAbort(this.ctx.streamingMessage);
|
|
701
702
|
const ttsrSilenced = aborted && this.ctx.viewSession.isTtsrAbortPending;
|
|
702
703
|
if (aborted && !silentlyAborted && !ttsrSilenced) {
|
|
703
704
|
// Resolve the operator-facing label: a user-interrupt (Esc) abort
|
|
@@ -707,7 +708,7 @@ export class EventController {
|
|
|
707
708
|
// AgentSession.#handleAgentEvent already stamped SILENT_ABORT_MARKER for
|
|
708
709
|
// the plan-compact transition before this controller ran, so reaching
|
|
709
710
|
// this branch implies the abort was NOT a silent internal transition.
|
|
710
|
-
errorMessage = resolveAbortLabel(this.ctx.streamingMessage
|
|
711
|
+
errorMessage = resolveAbortLabel(this.ctx.streamingMessage, this.ctx.viewSession.retryAttempt);
|
|
711
712
|
this.ctx.streamingMessage.errorMessage = errorMessage;
|
|
712
713
|
}
|
|
713
714
|
if (silentlyAborted || ttsrSilenced) {
|
|
@@ -759,11 +760,7 @@ export class EventController {
|
|
|
759
760
|
// above the editor so it survives transcript scroll. Cleared at the next
|
|
760
761
|
// turn's agent_start. Suppress the transcript's inline `Error: …` line for
|
|
761
762
|
// the same message while pinned so the error isn't rendered twice.
|
|
762
|
-
if (
|
|
763
|
-
event.message.stopReason === "error" &&
|
|
764
|
-
event.message.errorMessage &&
|
|
765
|
-
!isSilentAbort(event.message.errorMessage)
|
|
766
|
-
) {
|
|
763
|
+
if (event.message.stopReason === "error" && event.message.errorMessage && !isSilentAbort(event.message)) {
|
|
767
764
|
this.#lastAssistantComponent?.setErrorPinned(true);
|
|
768
765
|
this.#pinnedErrorComponent = this.#lastAssistantComponent;
|
|
769
766
|
this.ctx.showPinnedError(event.message.errorMessage);
|
|
@@ -1157,7 +1154,7 @@ export class EventController {
|
|
|
1157
1154
|
async #handleAutoRetryStart(event: Extract<AgentSessionEvent, { type: "auto_retry_start" }>): Promise<void> {
|
|
1158
1155
|
this.#stopWorkingLoader();
|
|
1159
1156
|
this.ctx.statusContainer.clear();
|
|
1160
|
-
if (event.
|
|
1157
|
+
if (AIError.is(event.errorId, AIError.Flag.ThinkingLoop)) {
|
|
1161
1158
|
// The retry path drops the failed assistant from runtime context. Do not
|
|
1162
1159
|
// restore its inline Error row; just unpin the fixed-region banner so the
|
|
1163
1160
|
// retry UI is the visible state.
|
|
@@ -858,11 +858,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
858
858
|
this.#observerRegistry.subscribeToEventBus(this.#eventBus);
|
|
859
859
|
}
|
|
860
860
|
this.#observerRegistry.setMainSession(this.sessionManager.getSessionFile() ?? undefined);
|
|
861
|
-
this.statusLine.setSubagentHubHint(
|
|
862
|
-
this.keybindings.getDisplayString("app.agents.hub") ||
|
|
863
|
-
this.keybindings.getDisplayString("app.session.observe") ||
|
|
864
|
-
undefined,
|
|
865
|
-
);
|
|
866
861
|
this.syncRunningSubagentBadge();
|
|
867
862
|
this.#observerRegistry.onChange(() => {
|
|
868
863
|
this.syncRunningSubagentBadge();
|
package/src/modes/print-mode.ts
CHANGED
|
@@ -83,7 +83,7 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
|
|
|
83
83
|
// Check for error/aborted — skip silent-abort (plan-mode compaction transition)
|
|
84
84
|
if (
|
|
85
85
|
(assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") &&
|
|
86
|
-
!isSilentAbort(assistantMsg
|
|
86
|
+
!isSilentAbort(assistantMsg)
|
|
87
87
|
) {
|
|
88
88
|
const errorLine = sanitizeText(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);
|
|
89
89
|
// Flush before this hard exit — it bypasses the awaited postmortem.quit()
|
|
@@ -146,11 +146,11 @@ export function resolveAssistantErrorMessage(
|
|
|
146
146
|
message: AssistantAgentMessage,
|
|
147
147
|
retryAttempt = 0,
|
|
148
148
|
): { hasErrorStop: boolean; errorMessage: string | null } {
|
|
149
|
-
const isAbortedSilently = message.stopReason === "aborted" && isSilentAbort(message
|
|
149
|
+
const isAbortedSilently = message.stopReason === "aborted" && isSilentAbort(message);
|
|
150
150
|
const hasErrorStop = !isAbortedSilently && (message.stopReason === "aborted" || message.stopReason === "error");
|
|
151
151
|
const errorMessage = hasErrorStop
|
|
152
152
|
? message.stopReason === "aborted"
|
|
153
|
-
? resolveAbortLabel(message
|
|
153
|
+
? resolveAbortLabel(message, retryAttempt)
|
|
154
154
|
: message.errorMessage || "Error"
|
|
155
155
|
: null;
|
|
156
156
|
return { hasErrorStop, errorMessage };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { AssistantMessage, ImageContent, Message, Usage } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import { getStreamingPartialJson } from "@oh-my-pi/pi-ai/utils/block-symbols";
|
|
3
4
|
import { type Component, Spacer, Text, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
4
5
|
import type { AdvisorMessageDetails } from "../../advisor";
|
|
5
6
|
import { COLLAB_PROMPT_MESSAGE_TYPE, type CollabPromptDetails } from "../../collab/protocol";
|
|
@@ -409,10 +410,10 @@ export class UiHelpers {
|
|
|
409
410
|
readGroup?.seal();
|
|
410
411
|
readGroup = null;
|
|
411
412
|
const tool = this.ctx.viewSession.getToolByName(content.name);
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
413
|
+
const partialJson = getStreamingPartialJson(content);
|
|
414
|
+
const renderArgs = partialJson
|
|
415
|
+
? { ...content.arguments, __partialJson: partialJson }
|
|
416
|
+
: content.arguments;
|
|
416
417
|
const component = new ToolExecutionComponent(
|
|
417
418
|
content.name,
|
|
418
419
|
renderArgs,
|
package/src/sdk.ts
CHANGED
|
@@ -8,14 +8,7 @@ import {
|
|
|
8
8
|
filterProviderReplayMessages,
|
|
9
9
|
type ThinkingLevel,
|
|
10
10
|
} from "@oh-my-pi/pi-agent-core";
|
|
11
|
-
import {
|
|
12
|
-
type Context,
|
|
13
|
-
type CredentialDisabledEvent,
|
|
14
|
-
type Message,
|
|
15
|
-
type Model,
|
|
16
|
-
type SimpleStreamOptions,
|
|
17
|
-
streamSimple,
|
|
18
|
-
} from "@oh-my-pi/pi-ai";
|
|
11
|
+
import type { Context, CredentialDisabledEvent, Message, Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
|
|
19
12
|
import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
|
|
20
13
|
import {
|
|
21
14
|
getOpenAICodexTransportDetails,
|
|
@@ -49,7 +42,7 @@ import {
|
|
|
49
42
|
resolveModelRoleValue,
|
|
50
43
|
} from "./config/model-resolver";
|
|
51
44
|
import { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from "./config/prompt-templates";
|
|
52
|
-
import { Settings, type SkillsSettings
|
|
45
|
+
import { Settings, type SkillsSettings } from "./config/settings";
|
|
53
46
|
import { CursorExecHandlers } from "./cursor";
|
|
54
47
|
import "./discovery";
|
|
55
48
|
import { initializeWithSettings } from "./discovery";
|
|
@@ -125,6 +118,7 @@ import {
|
|
|
125
118
|
import { clampProviderContextImages } from "./session/provider-image-budget";
|
|
126
119
|
import { getRestorableSessionModels } from "./session/session-context";
|
|
127
120
|
import { SessionManager } from "./session/session-manager";
|
|
121
|
+
import { createSettingsAwareStreamFn } from "./session/settings-stream-fn";
|
|
128
122
|
import { SnapcompactInlineTransformer } from "./session/snapcompact-inline";
|
|
129
123
|
import { createSnapcompactSavingsRecorder } from "./session/snapcompact-savings-journal";
|
|
130
124
|
import { closeAllConnections } from "./ssh/connection-manager";
|
|
@@ -975,6 +969,7 @@ function createCustomToolsExtension(tools: CustomTool[]): ExtensionFactory {
|
|
|
975
969
|
maxAttempts: event.maxAttempts,
|
|
976
970
|
delayMs: event.delayMs,
|
|
977
971
|
errorMessage: event.errorMessage,
|
|
972
|
+
errorId: event.errorId,
|
|
978
973
|
},
|
|
979
974
|
ctx,
|
|
980
975
|
),
|
|
@@ -2536,6 +2531,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2536
2531
|
// One-shot launch-latency marker: fired the first time the loop dispatches
|
|
2537
2532
|
// a chat request to the provider transport. See onFirstChatDispatch.
|
|
2538
2533
|
let notifyFirstChatDispatch = options.onFirstChatDispatch;
|
|
2534
|
+
// Shared, settings-aware stream wrapper used by both the main agent and
|
|
2535
|
+
// the advisor (via AgentSessionConfig.streamFn). Keeps OpenRouter
|
|
2536
|
+
// sticky-routing variants, antigravity endpoint routing, in-flight caps,
|
|
2537
|
+
// and the loop guard consistent across every agent the session drives.
|
|
2538
|
+
const settingsAwareStreamFn = createSettingsAwareStreamFn(settings);
|
|
2539
2539
|
agent = new Agent({
|
|
2540
2540
|
initialState: {
|
|
2541
2541
|
systemPrompt,
|
|
@@ -2586,23 +2586,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2586
2586
|
});
|
|
2587
2587
|
}
|
|
2588
2588
|
}
|
|
2589
|
-
|
|
2590
|
-
const openrouterVariant =
|
|
2591
|
-
openrouterRoutingPreset && openrouterRoutingPreset !== "default" ? openrouterRoutingPreset : undefined;
|
|
2592
|
-
const antigravityEndpointMode = settings.get("providers.antigravityEndpoint");
|
|
2593
|
-
return streamSimple(streamModel, context, {
|
|
2594
|
-
...streamOptions,
|
|
2595
|
-
openrouterVariant: streamOptions?.openrouterVariant ?? openrouterVariant,
|
|
2596
|
-
antigravityEndpointMode: streamOptions?.antigravityEndpointMode ?? antigravityEndpointMode,
|
|
2597
|
-
maxInFlightRequests: validateProviderMaxInFlightRequests(
|
|
2598
|
-
streamOptions?.maxInFlightRequests ?? settings.get("providers.maxInFlightRequests"),
|
|
2599
|
-
),
|
|
2600
|
-
loopGuard: {
|
|
2601
|
-
enabled: settings.get("model.loopGuard.enabled"),
|
|
2602
|
-
checkAssistantContent: settings.get("model.loopGuard.checkAssistantContent"),
|
|
2603
|
-
...streamOptions?.loopGuard,
|
|
2604
|
-
},
|
|
2605
|
-
});
|
|
2589
|
+
return settingsAwareStreamFn(streamModel, context, streamOptions);
|
|
2606
2590
|
},
|
|
2607
2591
|
cursorExecHandlers,
|
|
2608
2592
|
transformToolCallArguments: (args, _toolName) => {
|
|
@@ -2718,8 +2702,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2718
2702
|
toolRegistry,
|
|
2719
2703
|
builtInToolNames: builtInRegistryToolNames,
|
|
2720
2704
|
transformContext,
|
|
2705
|
+
transformProviderContext,
|
|
2721
2706
|
onPayload,
|
|
2722
2707
|
onResponse,
|
|
2708
|
+
advisorStreamFn: settingsAwareStreamFn,
|
|
2723
2709
|
convertToLlm: convertToLlmFinal,
|
|
2724
2710
|
rebuildSystemPrompt,
|
|
2725
2711
|
reloadSshTool,
|