@oh-my-pi/pi-coding-agent 15.1.8 → 15.2.1
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 +52 -1
- package/dist/types/cli/update-cli.d.ts +18 -0
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/eval/py/kernel.d.ts +6 -0
- package/dist/types/goals/state.d.ts +1 -1
- package/dist/types/goals/tools/goal-tool.d.ts +4 -0
- package/dist/types/hashline/parser.d.ts +6 -2
- package/dist/types/internal-urls/memory-protocol.d.ts +6 -0
- package/dist/types/main.d.ts +25 -1
- package/dist/types/modes/theme/shimmer.d.ts +27 -0
- package/dist/types/slash-commands/helpers/format.d.ts +4 -1
- package/dist/types/tools/ast-edit.d.ts +3 -0
- package/dist/types/tools/ast-grep.d.ts +3 -0
- package/dist/types/tools/find.d.ts +3 -0
- package/dist/types/tools/search.d.ts +3 -0
- package/dist/types/tui/file-list.d.ts +6 -0
- package/dist/types/tui/hyperlink.d.ts +42 -0
- package/dist/types/tui/index.d.ts +1 -0
- package/dist/types/utils/tool-choice.d.ts +2 -1
- package/dist/types/web/search/providers/utils.d.ts +27 -1
- package/package.json +7 -7
- package/src/cli/update-cli.ts +78 -36
- package/src/config/model-registry.ts +23 -12
- package/src/config/settings-schema.ts +12 -0
- package/src/config/settings.ts +28 -5
- package/src/edit/renderer.ts +5 -3
- package/src/eval/py/executor.ts +12 -1
- package/src/eval/py/kernel.ts +24 -8
- package/src/extensibility/plugins/legacy-pi-compat.ts +2 -2
- package/src/goals/runtime.ts +9 -3
- package/src/goals/state.ts +1 -1
- package/src/goals/tools/goal-tool.ts +12 -2
- package/src/hashline/diff.ts +1 -1
- package/src/hashline/execute.ts +2 -2
- package/src/hashline/parser.ts +87 -12
- package/src/internal-urls/memory-protocol.ts +1 -1
- package/src/main.ts +13 -2
- package/src/modes/interactive-mode.ts +29 -1
- package/src/modes/theme/shimmer.ts +79 -0
- package/src/prompts/agents/oracle.md +15 -16
- package/src/prompts/tools/goal.md +7 -2
- package/src/session/agent-session.ts +12 -75
- package/src/slash-commands/helpers/format.ts +23 -3
- package/src/task/executor.ts +115 -19
- package/src/tools/ast-edit.ts +39 -6
- package/src/tools/ast-grep.ts +38 -6
- package/src/tools/find.ts +13 -2
- package/src/tools/read.ts +46 -6
- package/src/tools/search.ts +447 -265
- package/src/tui/file-list.ts +10 -2
- package/src/tui/hyperlink.ts +126 -0
- package/src/tui/index.ts +1 -0
- package/src/utils/tool-choice.ts +7 -7
- package/src/web/kagi.ts +2 -2
- package/src/web/parallel.ts +3 -3
- package/src/web/search/index.ts +20 -9
- package/src/web/search/providers/anthropic.ts +4 -2
- package/src/web/search/providers/brave.ts +4 -2
- package/src/web/search/providers/codex.ts +4 -1
- package/src/web/search/providers/exa.ts +4 -1
- package/src/web/search/providers/gemini.ts +4 -1
- package/src/web/search/providers/jina.ts +4 -2
- package/src/web/search/providers/kagi.ts +5 -1
- package/src/web/search/providers/kimi.ts +4 -2
- package/src/web/search/providers/parallel.ts +5 -1
- package/src/web/search/providers/perplexity.ts +7 -2
- package/src/web/search/providers/searxng.ts +4 -1
- package/src/web/search/providers/synthetic.ts +4 -2
- package/src/web/search/providers/tavily.ts +4 -2
- package/src/web/search/providers/utils.ts +63 -1
- package/src/web/search/providers/zai.ts +4 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getAgentDbPath } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import { AgentStorage } from "../../../session/agent-storage";
|
|
3
|
-
import type
|
|
3
|
+
import { SearchProviderError, type SearchProviderId, type SearchSource } from "../../../web/search/types";
|
|
4
4
|
import { dateToAgeSeconds } from "../utils";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -49,6 +49,36 @@ export async function isApiKeyAvailable(findApiKey: () => string | null | Promis
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Default hard ceiling for a single web-search round-trip. 60s tolerates
|
|
54
|
+
* legitimate slow LLM-mediated responses (anthropic web_search_20250305,
|
|
55
|
+
* perplexity, gemini, codex) while still guaranteeing the session unfreezes
|
|
56
|
+
* within a minute if Bun's `AbortSignal` fails to propagate on Windows.
|
|
57
|
+
*
|
|
58
|
+
* Pure search APIs (brave, exa, jina, tavily, searxng, synthetic, zai)
|
|
59
|
+
* settle far faster in practice; reusing the same ceiling keeps the wiring
|
|
60
|
+
* uniform without compromising correctness.
|
|
61
|
+
*/
|
|
62
|
+
export const SEARCH_HARD_TIMEOUT_MS = 60_000;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Compose a caller-supplied {@link AbortSignal} with a hard timeout so an
|
|
66
|
+
* outbound `fetch()` is guaranteed to settle within `ms` even when the
|
|
67
|
+
* runtime fails to propagate cancellation to the underlying transport.
|
|
68
|
+
*
|
|
69
|
+
* Bun's WinHTTP backend on Windows is known to ignore `AbortSignal` once a
|
|
70
|
+
* TCP/TLS connection stalls (oven-sh/bun#15275, oven-sh/bun#18536); without
|
|
71
|
+
* this safety net a stalled web-search request freezes the entire session
|
|
72
|
+
* because the user's Esc is never delivered to the native layer.
|
|
73
|
+
*
|
|
74
|
+
* @param signal - Caller cancellation signal, if any.
|
|
75
|
+
* @param ms - Hard timeout in milliseconds. Defaults to {@link SEARCH_HARD_TIMEOUT_MS}.
|
|
76
|
+
*/
|
|
77
|
+
export function withHardTimeout(signal: AbortSignal | undefined, ms: number = SEARCH_HARD_TIMEOUT_MS): AbortSignal {
|
|
78
|
+
const timeout = AbortSignal.timeout(ms);
|
|
79
|
+
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
80
|
+
}
|
|
81
|
+
|
|
52
82
|
/**
|
|
53
83
|
* Map a provider's raw source list to the unified SearchSource shape,
|
|
54
84
|
* clamped to the requested result count and annotated with ageSeconds.
|
|
@@ -70,3 +100,35 @@ export function toSearchSources(
|
|
|
70
100
|
ageSeconds: dateToAgeSeconds(source.publishedDate),
|
|
71
101
|
}));
|
|
72
102
|
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Quota/auth signals across providers. Telemetry on 15.1.7/15.1.8 showed users
|
|
106
|
+
* hitting credit-exhaustion and 401/402/403 responses that were surfaced as
|
|
107
|
+
* raw HTTP error text. Map those into compact, provider-tagged messages so
|
|
108
|
+
* the orchestrator can chain-advance cleanly and the final summary stays
|
|
109
|
+
* legible when every provider rejects the request.
|
|
110
|
+
*
|
|
111
|
+
* Returns `null` when the response does not match a known quota/auth signal,
|
|
112
|
+
* leaving the caller to throw its provider-specific fallback error.
|
|
113
|
+
*/
|
|
114
|
+
const CREDIT_BODY_PATTERN = /credits?\s*(?:exhausted|exceeded)|quota|insufficient/i;
|
|
115
|
+
|
|
116
|
+
export function classifyProviderHttpError(
|
|
117
|
+
provider: SearchProviderId,
|
|
118
|
+
status: number,
|
|
119
|
+
body: string,
|
|
120
|
+
): SearchProviderError | null {
|
|
121
|
+
if (CREDIT_BODY_PATTERN.test(body)) {
|
|
122
|
+
return new SearchProviderError(provider, `${provider}: credits exhausted`, status);
|
|
123
|
+
}
|
|
124
|
+
if (status === 402) {
|
|
125
|
+
return new SearchProviderError(provider, `${provider}: 402 credits exhausted`, status);
|
|
126
|
+
}
|
|
127
|
+
if (status === 401) {
|
|
128
|
+
return new SearchProviderError(provider, `${provider}: 401 unauthorized`, status);
|
|
129
|
+
}
|
|
130
|
+
if (status === 403) {
|
|
131
|
+
return new SearchProviderError(provider, `${provider}: 403 forbidden`, status);
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
@@ -11,7 +11,7 @@ import { SearchProviderError } from "../../../web/search/types";
|
|
|
11
11
|
import { dateToAgeSeconds } from "../utils";
|
|
12
12
|
import type { SearchParams } from "./base";
|
|
13
13
|
import { SearchProvider } from "./base";
|
|
14
|
-
import { findCredential, isApiKeyAvailable } from "./utils";
|
|
14
|
+
import { classifyProviderHttpError, findCredential, isApiKeyAvailable, withHardTimeout } from "./utils";
|
|
15
15
|
|
|
16
16
|
const ZAI_MCP_URL = "https://api.z.ai/api/mcp/web_search_prime/mcp";
|
|
17
17
|
const ZAI_TOOL_NAME = "web_search_prime";
|
|
@@ -73,11 +73,13 @@ async function callZaiTool(apiKey: string, args: Record<string, unknown>, signal
|
|
|
73
73
|
arguments: args,
|
|
74
74
|
},
|
|
75
75
|
}),
|
|
76
|
-
signal,
|
|
76
|
+
signal: withHardTimeout(signal),
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
if (!response.ok) {
|
|
80
80
|
const errorText = await response.text();
|
|
81
|
+
const classified = classifyProviderHttpError("zai", response.status, errorText);
|
|
82
|
+
if (classified) throw classified;
|
|
81
83
|
throw new SearchProviderError("zai", `Z.AI MCP error (${response.status}): ${errorText}`, response.status);
|
|
82
84
|
}
|
|
83
85
|
|