@oh-my-pi/pi-coding-agent 16.0.4 → 16.0.5

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/cli.js +341 -261
  3. package/dist/types/advisor/advise-tool.d.ts +9 -0
  4. package/dist/types/cli/args.d.ts +1 -0
  5. package/dist/types/cli/bench-cli.d.ts +6 -0
  6. package/dist/types/commands/launch.d.ts +3 -0
  7. package/dist/types/config/settings-schema.d.ts +91 -2
  8. package/dist/types/extensibility/extensions/runner.d.ts +5 -2
  9. package/dist/types/extensibility/extensions/types.d.ts +8 -7
  10. package/dist/types/extensibility/shared-events.d.ts +22 -1
  11. package/dist/types/main.d.ts +1 -0
  12. package/dist/types/modes/components/status-line/component.d.ts +1 -1
  13. package/dist/types/modes/components/status-line/context-thresholds.d.ts +0 -1
  14. package/dist/types/modes/rpc/rpc-types.d.ts +1 -1
  15. package/dist/types/modes/utils/context-usage.d.ts +12 -0
  16. package/dist/types/sdk.d.ts +3 -1
  17. package/dist/types/session/agent-session.d.ts +20 -0
  18. package/dist/types/session/session-persistence.d.ts +4 -0
  19. package/dist/types/tools/read.d.ts +1 -0
  20. package/dist/types/tui/code-cell.d.ts +2 -0
  21. package/dist/types/utils/image-vision-fallback.d.ts +28 -0
  22. package/dist/types/web/search/providers/base.d.ts +1 -0
  23. package/dist/types/web/search/providers/gemini.d.ts +1 -0
  24. package/package.json +12 -12
  25. package/src/advisor/__tests__/advisor.test.ts +59 -0
  26. package/src/advisor/advise-tool.ts +13 -0
  27. package/src/cli/args.ts +1 -0
  28. package/src/cli/bench-cli.ts +30 -7
  29. package/src/cli/flag-tables.ts +8 -0
  30. package/src/collab/host.ts +2 -2
  31. package/src/commands/launch.ts +3 -0
  32. package/src/config/settings-schema.ts +84 -2
  33. package/src/eval/py/runner.py +44 -0
  34. package/src/extensibility/extensions/runner.ts +20 -2
  35. package/src/extensibility/extensions/types.ts +16 -5
  36. package/src/extensibility/shared-events.ts +24 -0
  37. package/src/internal-urls/docs-index.generated.ts +7 -7
  38. package/src/main.ts +12 -5
  39. package/src/modes/components/branch-summary-message.ts +1 -0
  40. package/src/modes/components/collab-prompt-message.ts +9 -7
  41. package/src/modes/components/compaction-summary-message.ts +1 -0
  42. package/src/modes/components/custom-message.ts +1 -0
  43. package/src/modes/components/footer.ts +6 -5
  44. package/src/modes/components/hook-message.ts +1 -0
  45. package/src/modes/components/read-tool-group.ts +9 -3
  46. package/src/modes/components/skill-message.ts +1 -0
  47. package/src/modes/components/status-line/component.ts +131 -14
  48. package/src/modes/components/status-line/context-thresholds.ts +0 -1
  49. package/src/modes/components/todo-reminder.ts +1 -0
  50. package/src/modes/components/ttsr-notification.ts +1 -0
  51. package/src/modes/components/user-message.ts +6 -6
  52. package/src/modes/controllers/event-controller.ts +2 -7
  53. package/src/modes/controllers/selector-controller.ts +10 -3
  54. package/src/modes/interactive-mode.ts +4 -2
  55. package/src/modes/rpc/rpc-types.ts +1 -1
  56. package/src/modes/utils/context-usage.ts +28 -15
  57. package/src/prompts/tools/image-attachment-describe-system.md +8 -0
  58. package/src/prompts/tools/image-attachment-describe.md +10 -0
  59. package/src/sdk.ts +14 -18
  60. package/src/session/agent-session.ts +564 -231
  61. package/src/session/session-loader.ts +19 -32
  62. package/src/session/session-persistence.ts +27 -11
  63. package/src/ssh/connection-manager.ts +3 -2
  64. package/src/task/executor.ts +1 -1
  65. package/src/tools/image-gen.ts +67 -25
  66. package/src/tools/read.ts +28 -6
  67. package/src/tui/code-cell.ts +44 -3
  68. package/src/utils/image-vision-fallback.ts +197 -0
  69. package/src/web/search/index.ts +12 -0
  70. package/src/web/search/providers/base.ts +1 -0
  71. package/src/web/search/providers/gemini.ts +56 -18
@@ -8,6 +8,7 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
8
8
  import type { AuthStorage } from "@oh-my-pi/pi-ai";
9
9
  import { prompt } from "@oh-my-pi/pi-utils";
10
10
  import { z } from "zod/v4";
11
+ import { settings } from "../../config/settings";
11
12
  import type { CustomTool, CustomToolContext, RenderResultOptions } from "../../extensibility/custom-tools/types";
12
13
  import type { Theme } from "../../modes/theme/theme";
13
14
  import webSearchSystemPrompt from "../../prompts/system/web-search.md" with { type: "text" };
@@ -153,6 +154,16 @@ async function executeSearch(
153
154
  };
154
155
  }
155
156
 
157
+ // Invariant across providers; read once and tolerate an uninitialized
158
+ // Settings singleton (e.g. `omp q ...` CLI path, unit tests) so the
159
+ // provider-fallback loop never aborts before any provider runs.
160
+ let antigravityEndpointMode: "auto" | "production" | "sandbox" | undefined;
161
+ try {
162
+ antigravityEndpointMode = settings.get("providers.antigravityEndpoint");
163
+ } catch {
164
+ antigravityEndpointMode = undefined;
165
+ }
166
+
156
167
  const failures: Array<{ provider: SearchProvider; error: unknown }> = [];
157
168
  let lastProvider = providers[0];
158
169
  for (const provider of providers) {
@@ -169,6 +180,7 @@ async function executeSearch(
169
180
  signal,
170
181
  authStorage,
171
182
  sessionId,
183
+ antigravityEndpointMode,
172
184
  });
173
185
 
174
186
  if (!hasRenderableSearchContent(response)) {
@@ -51,6 +51,7 @@ export interface SearchParams {
51
51
  * caller's agent session when available; otherwise omit.
52
52
  */
53
53
  sessionId?: string;
54
+ antigravityEndpointMode?: "auto" | "production" | "sandbox";
54
55
  }
55
56
 
56
57
  /** Base class for web search providers. */
@@ -52,6 +52,7 @@ export interface GeminiSearchParams extends GeminiToolParams {
52
52
  authStorage: AuthStorage;
53
53
  sessionId?: string;
54
54
  fetch?: FetchImpl;
55
+ antigravityEndpointMode?: "auto" | "production" | "sandbox";
55
56
  }
56
57
 
57
58
  export function buildGeminiRequestTools(params: GeminiToolParams): Array<Record<string, Record<string, unknown>>> {
@@ -163,6 +164,7 @@ async function callGeminiSearch(
163
164
  toolParams: GeminiToolParams,
164
165
  fetchImpl: FetchImpl | undefined,
165
166
  signal: AbortSignal | undefined,
167
+ mode?: "auto" | "production" | "sandbox",
166
168
  ): Promise<{
167
169
  answer: string;
168
170
  sources: SearchSource[];
@@ -171,7 +173,19 @@ async function callGeminiSearch(
171
173
  model: string;
172
174
  usage?: { inputTokens: number; outputTokens: number; totalTokens: number };
173
175
  }> {
174
- const endpoints = auth.isAntigravity ? ANTIGRAVITY_ENDPOINT_FALLBACKS : [DEFAULT_ENDPOINT];
176
+ let endpoints: string[];
177
+ if (auth.isAntigravity) {
178
+ const m = mode ?? "auto";
179
+ if (m === "sandbox") {
180
+ endpoints = [ANTIGRAVITY_SANDBOX_ENDPOINT];
181
+ } else if (m === "production") {
182
+ endpoints = [ANTIGRAVITY_DAILY_ENDPOINT];
183
+ } else {
184
+ endpoints = [...ANTIGRAVITY_ENDPOINT_FALLBACKS];
185
+ }
186
+ } else {
187
+ endpoints = [DEFAULT_ENDPOINT];
188
+ }
175
189
  const headers = auth.isAntigravity ? { "User-Agent": getAntigravityUserAgent() } : getGeminiCliHeaders();
176
190
 
177
191
  const requestMetadata = auth.isAntigravity
@@ -187,12 +201,7 @@ async function callGeminiSearch(
187
201
 
188
202
  const normalizedSystemPrompt = systemPrompt?.toWellFormed();
189
203
  const systemInstructionParts: Array<{ text: string }> = [
190
- ...(auth.isAntigravity
191
- ? [
192
- { text: ANTIGRAVITY_SYSTEM_INSTRUCTION },
193
- { text: `Please ignore following [ignore]${ANTIGRAVITY_SYSTEM_INSTRUCTION}[/ignore]` },
194
- ]
195
- : []),
204
+ ...(auth.isAntigravity ? [{ text: ANTIGRAVITY_SYSTEM_INSTRUCTION }] : []),
196
205
  ...(normalizedSystemPrompt ? [{ text: normalizedSystemPrompt }] : []),
197
206
  ];
198
207
 
@@ -238,16 +247,45 @@ async function callGeminiSearch(
238
247
  body: JSON.stringify(requestBody),
239
248
  signal: withHardTimeout(signal),
240
249
  });
241
- const urlFor = (attempt: number) =>
242
- `${endpoints[Math.min(attempt, endpoints.length - 1)]}/v1internal:streamGenerateContent?alt=sse`;
243
-
244
- const response = await fetchWithRetry(urlFor, {
245
- ...buildInit(),
246
- fetch: fetchImpl,
247
- maxAttempts: MAX_RETRIES + 1,
248
- defaultDelayMs: attempt => BASE_DELAY_MS * 2 ** attempt,
249
- maxDelayMs: RATE_LIMIT_BUDGET_MS,
250
- });
250
+
251
+ let response: Response | undefined;
252
+
253
+ for (let i = 0; i < endpoints.length; i++) {
254
+ const endpoint = endpoints[i];
255
+ const isLastEndpoint = i === endpoints.length - 1;
256
+ try {
257
+ response = await fetchWithRetry(() => `${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
258
+ ...buildInit(),
259
+ fetch: fetchImpl,
260
+ maxAttempts: isLastEndpoint ? MAX_RETRIES + 1 : 1,
261
+ defaultDelayMs: attempt => BASE_DELAY_MS * 2 ** attempt,
262
+ maxDelayMs: RATE_LIMIT_BUDGET_MS,
263
+ });
264
+
265
+ if (response.ok) {
266
+ break;
267
+ }
268
+
269
+ if (response.status === 429 || (response.status >= 500 && response.status < 600)) {
270
+ if (!isLastEndpoint) {
271
+ continue;
272
+ }
273
+ }
274
+ break;
275
+ } catch (error) {
276
+ if (isLastEndpoint) {
277
+ throw error;
278
+ }
279
+ }
280
+ }
281
+
282
+ if (!response?.ok) {
283
+ const errorText = response ? await response.text() : "Network error";
284
+ const status = response?.status ?? 502;
285
+ const classified = classifyProviderHttpError("gemini", status, errorText);
286
+ if (classified) throw classified;
287
+ throw new SearchProviderError("gemini", `Gemini Cloud Code API error (${status}): ${errorText}`, status);
288
+ }
251
289
 
252
290
  if (!response.ok) {
253
291
  const errorText = await response.text();
@@ -410,7 +448,6 @@ export async function searchGemini(params: GeminiSearchParams): Promise<SearchRe
410
448
  // re-resolved access may omit projectId, in which case the seed's
411
449
  // project is still the right tenant for the credential. The
412
450
  // `fetchWithRetry` transport backoff stays INSIDE this attempt — auth
413
- // retry wraps transport retry.
414
451
  callGeminiSearch(
415
452
  {
416
453
  accessToken: access.accessToken,
@@ -428,6 +465,7 @@ export async function searchGemini(params: GeminiSearchParams): Promise<SearchRe
428
465
  },
429
466
  params.fetch,
430
467
  params.signal,
468
+ params.antigravityEndpointMode,
431
469
  ),
432
470
  { sessionId: params.sessionId, signal: params.signal, seed: seed.access },
433
471
  );