@oh-my-pi/pi-coding-agent 16.1.13 → 16.1.15

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 (153) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/cli.js +5615 -2833
  3. package/dist/types/advisor/runtime.d.ts +3 -0
  4. package/dist/types/config/settings-schema.d.ts +64 -14
  5. package/dist/types/eval/__tests__/julia-prelude.test.d.ts +1 -0
  6. package/dist/types/eval/backend-helpers.d.ts +23 -0
  7. package/dist/types/eval/executor-base.d.ts +118 -0
  8. package/dist/types/eval/index.d.ts +2 -0
  9. package/dist/types/eval/jl/executor.d.ts +44 -0
  10. package/dist/types/eval/jl/index.d.ts +11 -0
  11. package/dist/types/eval/jl/kernel.d.ts +28 -0
  12. package/dist/types/eval/jl/prelude.d.ts +1 -0
  13. package/dist/types/eval/jl/runtime.d.ts +22 -0
  14. package/dist/types/eval/kernel-base.d.ts +105 -0
  15. package/dist/types/eval/py/kernel.d.ts +3 -61
  16. package/dist/types/eval/rb/executor.d.ts +77 -0
  17. package/dist/types/eval/rb/index.d.ts +11 -0
  18. package/dist/types/eval/rb/kernel.d.ts +31 -0
  19. package/dist/types/eval/rb/prelude.d.ts +1 -0
  20. package/dist/types/eval/rb/runtime.d.ts +23 -0
  21. package/dist/types/eval/runtime-env.d.ts +24 -0
  22. package/dist/types/eval/types.d.ts +3 -3
  23. package/dist/types/export/share.d.ts +8 -1
  24. package/dist/types/extensibility/extensions/runner.d.ts +2 -15
  25. package/dist/types/extensibility/hooks/loader.d.ts +1 -25
  26. package/dist/types/extensibility/session-handler-types.d.ts +23 -0
  27. package/dist/types/jsonrpc/message-framing.d.ts +35 -0
  28. package/dist/types/mcp/transports/stdio.d.ts +12 -1
  29. package/dist/types/mnemopi/embed-client.d.ts +7 -24
  30. package/dist/types/modes/components/chat-transcript-builder.d.ts +1 -1
  31. package/dist/types/modes/components/custom-editor.d.ts +11 -0
  32. package/dist/types/modes/components/selector-helpers.d.ts +53 -0
  33. package/dist/types/modes/components/status-line/context-thresholds.d.ts +4 -3
  34. package/dist/types/modes/components/status-line/types.d.ts +1 -0
  35. package/dist/types/modes/interactive-mode.d.ts +0 -2
  36. package/dist/types/modes/theme/theme.d.ts +8 -1
  37. package/dist/types/modes/types.d.ts +0 -2
  38. package/dist/types/modes/utils/copy-targets.d.ts +1 -1
  39. package/dist/types/modes/utils/interactive-context-helpers.d.ts +14 -0
  40. package/dist/types/modes/utils/transcript-render-helpers.d.ts +54 -0
  41. package/dist/types/sdk.d.ts +1 -1
  42. package/dist/types/secrets/obfuscator.d.ts +3 -3
  43. package/dist/types/session/agent-session.d.ts +2 -2
  44. package/dist/types/stt/asr-client.d.ts +3 -29
  45. package/dist/types/subprocess/worker-client.d.ts +149 -0
  46. package/dist/types/subprocess/worker-runtime.d.ts +107 -0
  47. package/dist/types/tiny/title-client.d.ts +14 -34
  48. package/dist/types/tools/eval-backends.d.ts +6 -3
  49. package/dist/types/tools/eval-render.d.ts +6 -5
  50. package/dist/types/tools/eval.d.ts +13 -15
  51. package/dist/types/tools/index.d.ts +3 -3
  52. package/dist/types/tts/tts-client.d.ts +3 -28
  53. package/dist/types/tui/code-cell.d.ts +7 -0
  54. package/dist/types/utils/file-display-mode.d.ts +1 -1
  55. package/dist/types/utils/shell-snapshot.d.ts +10 -0
  56. package/dist/types/web/parallel.d.ts +6 -0
  57. package/dist/types/web/search/providers/perplexity.d.ts +17 -3
  58. package/package.json +12 -12
  59. package/src/advisor/__tests__/advisor.test.ts +114 -0
  60. package/src/advisor/runtime.ts +129 -1
  61. package/src/config/model-registry.ts +12 -4
  62. package/src/config/settings-schema.ts +74 -18
  63. package/src/config/settings.ts +5 -0
  64. package/src/dap/client.ts +13 -107
  65. package/src/eval/__tests__/julia-prelude.test.ts +77 -0
  66. package/src/eval/backend-helpers.ts +48 -0
  67. package/src/eval/executor-base.ts +425 -0
  68. package/src/eval/index.ts +2 -0
  69. package/src/eval/jl/executor.ts +540 -0
  70. package/src/eval/jl/index.ts +54 -0
  71. package/src/eval/jl/kernel.ts +235 -0
  72. package/src/eval/jl/prelude.jl +930 -0
  73. package/src/eval/jl/prelude.ts +3 -0
  74. package/src/eval/jl/runner.jl +634 -0
  75. package/src/eval/jl/runtime.ts +118 -0
  76. package/src/eval/js/index.ts +3 -14
  77. package/src/eval/kernel-base.ts +569 -0
  78. package/src/eval/py/executor.ts +43 -252
  79. package/src/eval/py/index.ts +9 -20
  80. package/src/eval/py/kernel.ts +29 -544
  81. package/src/eval/rb/executor.ts +504 -0
  82. package/src/eval/rb/index.ts +54 -0
  83. package/src/eval/rb/kernel.ts +230 -0
  84. package/src/eval/rb/prelude.rb +721 -0
  85. package/src/eval/rb/prelude.ts +3 -0
  86. package/src/eval/rb/runner.rb +474 -0
  87. package/src/eval/rb/runtime.ts +132 -0
  88. package/src/eval/runtime-env.ts +104 -0
  89. package/src/eval/types.ts +3 -3
  90. package/src/exec/bash-executor.ts +44 -0
  91. package/src/export/share.ts +51 -28
  92. package/src/extensibility/extensions/runner.ts +4 -11
  93. package/src/extensibility/hooks/loader.ts +3 -21
  94. package/src/extensibility/session-handler-types.ts +21 -0
  95. package/src/internal-urls/docs-index.generated.txt +1 -1
  96. package/src/jsonrpc/message-framing.ts +142 -0
  97. package/src/lsp/client.ts +13 -109
  98. package/src/mcp/transports/stdio.ts +20 -4
  99. package/src/mnemopi/embed-client.ts +43 -198
  100. package/src/modes/components/agent-dashboard.ts +17 -40
  101. package/src/modes/components/chat-transcript-builder.ts +18 -102
  102. package/src/modes/components/custom-editor.test.ts +22 -0
  103. package/src/modes/components/custom-editor.ts +29 -1
  104. package/src/modes/components/extensions/extension-dashboard.ts +4 -13
  105. package/src/modes/components/extensions/extension-list.ts +16 -44
  106. package/src/modes/components/footer.ts +4 -3
  107. package/src/modes/components/history-search.ts +4 -16
  108. package/src/modes/components/selector-helpers.ts +129 -0
  109. package/src/modes/components/settings-selector.ts +7 -5
  110. package/src/modes/components/status-line/component.ts +5 -1
  111. package/src/modes/components/status-line/context-thresholds.ts +11 -3
  112. package/src/modes/components/status-line/segments.ts +1 -1
  113. package/src/modes/components/status-line/types.ts +1 -0
  114. package/src/modes/components/tree-selector.ts +13 -18
  115. package/src/modes/controllers/command-controller.ts +1 -0
  116. package/src/modes/controllers/event-controller.ts +3 -9
  117. package/src/modes/controllers/input-controller.ts +32 -54
  118. package/src/modes/interactive-mode.ts +5 -7
  119. package/src/modes/theme/theme.ts +35 -0
  120. package/src/modes/types.ts +0 -2
  121. package/src/modes/utils/copy-targets.ts +3 -2
  122. package/src/modes/utils/interactive-context-helpers.ts +27 -0
  123. package/src/modes/utils/transcript-render-helpers.ts +157 -0
  124. package/src/modes/utils/ui-helpers.ts +21 -126
  125. package/src/prompts/system/system-prompt.md +5 -5
  126. package/src/prompts/tools/bash.md +2 -3
  127. package/src/prompts/tools/eval.md +6 -4
  128. package/src/prompts/tools/find.md +0 -4
  129. package/src/prompts/tools/read.md +1 -2
  130. package/src/prompts/tools/replace.md +1 -1
  131. package/src/sdk.ts +13 -7
  132. package/src/secrets/obfuscator.ts +3 -9
  133. package/src/session/agent-session.ts +42 -9
  134. package/src/slash-commands/builtin-registry.ts +2 -1
  135. package/src/stt/asr-client.ts +35 -215
  136. package/src/stt/asr-worker.ts +29 -181
  137. package/src/subprocess/worker-client.ts +297 -0
  138. package/src/subprocess/worker-runtime.ts +277 -0
  139. package/src/task/executor.ts +4 -4
  140. package/src/tiny/title-client.ts +53 -219
  141. package/src/tiny/worker.ts +29 -180
  142. package/src/tools/eval-backends.ts +10 -3
  143. package/src/tools/eval-render.ts +17 -8
  144. package/src/tools/eval.ts +187 -22
  145. package/src/tools/index.ts +51 -28
  146. package/src/tts/tts-client.ts +38 -206
  147. package/src/tts/tts-worker.ts +23 -97
  148. package/src/tui/code-cell.ts +12 -1
  149. package/src/utils/file-display-mode.ts +2 -3
  150. package/src/utils/shell-snapshot.ts +63 -1
  151. package/src/web/parallel.ts +43 -42
  152. package/src/web/search/providers/parallel.ts +10 -99
  153. package/src/web/search/providers/perplexity.ts +18 -6
@@ -3,9 +3,9 @@ import type { AgentStorage } from "../session/agent-storage";
3
3
  import { findCredential, withHardTimeout } from "./search/providers/utils";
4
4
 
5
5
  const PARALLEL_API_URL = "https://api.parallel.ai";
6
- const PARALLEL_SEARCH_URL = `${PARALLEL_API_URL}/v1beta/search`;
6
+ export const PARALLEL_SEARCH_URL = `${PARALLEL_API_URL}/v1beta/search`;
7
7
  const PARALLEL_EXTRACT_URL = `${PARALLEL_API_URL}/v1beta/extract`;
8
- const PARALLEL_BETA_HEADER = "search-extract-2025-10-10";
8
+ export const PARALLEL_BETA_HEADER = "search-extract-2025-10-10";
9
9
 
10
10
  export interface ParallelUsageItem {
11
11
  name?: string;
@@ -76,22 +76,6 @@ export class ParallelApiError extends Error {
76
76
  }
77
77
  }
78
78
 
79
- export function findParallelApiKey(storage: AgentStorage | null | undefined): string | null {
80
- return findCredential(storage, getEnvApiKey("parallel"), "parallel");
81
- }
82
-
83
- export function getParallelExtractContent(document: ParallelExtractDocument): string {
84
- const excerptContent = document.excerpts
85
- .filter(excerpt => excerpt.trim().length > 0)
86
- .join("\n\n")
87
- .trim();
88
- if (excerptContent.length > 0) {
89
- return excerptContent;
90
- }
91
-
92
- return document.fullContent?.trim() ?? "";
93
- }
94
-
95
79
  function isObject(value: unknown): value is object {
96
80
  return typeof value === "object" && value !== null;
97
81
  }
@@ -148,7 +132,7 @@ function createParallelApiError(statusCode: number, detail?: string): ParallelAp
148
132
  );
149
133
  }
150
134
 
151
- function parseParallelErrorResponse(statusCode: number, responseText: string): ParallelApiError {
135
+ export function parseParallelErrorResponse(statusCode: number, responseText: string): ParallelApiError {
152
136
  const trimmedResponseText = responseText.trim();
153
137
  if (trimmedResponseText.length === 0) {
154
138
  return createParallelApiError(statusCode);
@@ -176,24 +160,6 @@ function getAuthHeaders(apiKey: string): {
176
160
  };
177
161
  }
178
162
 
179
- function normalizeSearchMode(mode: ParallelSearchOptions["mode"]): "fast" | "one-shot" {
180
- return mode === "research" ? "one-shot" : "fast";
181
- }
182
-
183
- function parseUsageItems(payload: unknown): ParallelUsageItem[] {
184
- if (!Array.isArray(payload)) return [];
185
-
186
- const usageItems: ParallelUsageItem[] = [];
187
- for (const item of payload) {
188
- if (!isObject(item)) continue;
189
- usageItems.push({
190
- name: getString(item, "name"),
191
- count: getNumber(item, "count"),
192
- });
193
- }
194
- return usageItems;
195
- }
196
-
197
163
  function parseWarnings(payload: unknown): string[] {
198
164
  if (!Array.isArray(payload)) return [];
199
165
 
@@ -212,7 +178,24 @@ function parseWarnings(payload: unknown): string[] {
212
178
  return warnings;
213
179
  }
214
180
 
215
- function parseSearchPayload(payload: unknown): ParallelSearchResult {
181
+ function parseUsageItems(payload: unknown): ParallelUsageItem[] {
182
+ if (!Array.isArray(payload)) return [];
183
+
184
+ const usageItems: ParallelUsageItem[] = [];
185
+ for (const item of payload) {
186
+ if (!isObject(item)) continue;
187
+ usageItems.push({
188
+ name: getString(item, "name"),
189
+ count: getNumber(item, "count"),
190
+ });
191
+ }
192
+ return usageItems;
193
+ }
194
+
195
+ export function parseParallelSearchPayload(
196
+ payload: unknown,
197
+ options?: { parseMetadata?: boolean },
198
+ ): ParallelSearchResult {
216
199
  if (!isObject(payload)) {
217
200
  throw new ParallelApiError("Parallel search returned an invalid response payload.");
218
201
  }
@@ -236,14 +219,32 @@ function parseSearchPayload(payload: unknown): ParallelSearchResult {
236
219
  });
237
220
  }
238
221
 
222
+ const parseMetadata = options?.parseMetadata ?? true;
223
+
239
224
  return {
240
225
  requestId,
241
226
  sources,
242
- warnings: parseWarnings(getOwnValue(payload, "warnings")),
243
- usage: parseUsageItems(getOwnValue(payload, "usage")),
227
+ warnings: parseMetadata ? parseWarnings(getOwnValue(payload, "warnings")) : [],
228
+ usage: parseMetadata ? parseUsageItems(getOwnValue(payload, "usage")) : [],
244
229
  };
245
230
  }
246
231
 
232
+ export function findParallelApiKey(storage: AgentStorage | null | undefined): string | null {
233
+ return findCredential(storage, getEnvApiKey("parallel"), "parallel");
234
+ }
235
+
236
+ export function getParallelExtractContent(document: ParallelExtractDocument): string {
237
+ const excerptContent = document.excerpts
238
+ .filter(excerpt => excerpt.trim().length > 0)
239
+ .join("\n\n")
240
+ .trim();
241
+ if (excerptContent.length > 0) {
242
+ return excerptContent;
243
+ }
244
+
245
+ return document.fullContent?.trim() ?? "";
246
+ }
247
+
247
248
  function parseExtractPayload(payload: unknown): ParallelExtractResult {
248
249
  if (!isObject(payload)) {
249
250
  throw new ParallelApiError("Parallel extract returned an invalid response payload.");
@@ -304,7 +305,7 @@ export async function searchWithParallel(
304
305
  body: JSON.stringify({
305
306
  objective,
306
307
  search_queries: queries,
307
- mode: normalizeSearchMode(options.mode),
308
+ mode: options.mode === "research" ? "one-shot" : "fast",
308
309
  excerpts: {
309
310
  max_chars_per_result: options.maxCharsPerResult ?? 10_000,
310
311
  },
@@ -316,7 +317,7 @@ export async function searchWithParallel(
316
317
  }
317
318
 
318
319
  const payload: unknown = await response.json();
319
- return parseSearchPayload(payload);
320
+ return parseParallelSearchPayload(payload);
320
321
  }
321
322
 
322
323
  export async function extractWithParallel(
@@ -1,7 +1,14 @@
1
1
  import { type ApiKey, type AuthStorage, type FetchImpl, getEnvApiKey, withAuth } from "@oh-my-pi/pi-ai";
2
2
  import type { SearchResponse } from "../../../web/search/types";
3
3
  import { SearchProviderError } from "../../../web/search/types";
4
- import { ParallelApiError, type ParallelSearchResult, type ParallelSearchSource } from "../../parallel";
4
+ import {
5
+ PARALLEL_BETA_HEADER,
6
+ PARALLEL_SEARCH_URL,
7
+ ParallelApiError,
8
+ type ParallelSearchResult,
9
+ parseParallelErrorResponse,
10
+ parseParallelSearchPayload,
11
+ } from "../../parallel";
5
12
  import { clampNumResults } from "../utils";
6
13
  import type { SearchParams } from "./base";
7
14
  import { SearchProvider } from "./base";
@@ -9,103 +16,6 @@ import { classifyProviderHttpError, toSearchSources, withHardTimeout } from "./u
9
16
 
10
17
  const DEFAULT_NUM_RESULTS = 10;
11
18
  const MAX_NUM_RESULTS = 40;
12
- const PARALLEL_SEARCH_URL = "https://api.parallel.ai/v1beta/search";
13
- const PARALLEL_BETA_HEADER = "search-extract-2025-10-10";
14
-
15
- function isObject(value: unknown): value is object {
16
- return typeof value === "object" && value !== null;
17
- }
18
-
19
- function getOwnValue(value: object, key: string): unknown {
20
- return Object.getOwnPropertyDescriptor(value, key)?.value;
21
- }
22
-
23
- function getString(value: object, key: string): string | undefined {
24
- const field = getOwnValue(value, key);
25
- return typeof field === "string" ? field : undefined;
26
- }
27
-
28
- function getObjectArray(value: object, key: string): object[] {
29
- const field = getOwnValue(value, key);
30
- return Array.isArray(field) ? field.filter(isObject) : [];
31
- }
32
-
33
- function getStringArray(value: object, key: string): string[] {
34
- const field = getOwnValue(value, key);
35
- return Array.isArray(field) ? field.filter((item): item is string => typeof item === "string") : [];
36
- }
37
-
38
- function extractParallelErrorMessage(payload: unknown): string | null {
39
- if (!isObject(payload)) return null;
40
-
41
- const directMessage = getString(payload, "message") ?? getString(payload, "detail") ?? getString(payload, "error");
42
- if (directMessage && directMessage.trim().length > 0) {
43
- return directMessage.trim();
44
- }
45
-
46
- const errorObject = getOwnValue(payload, "error");
47
- if (isObject(errorObject)) {
48
- const nestedMessage = getString(errorObject, "message") ?? getString(errorObject, "detail");
49
- if (nestedMessage && nestedMessage.trim().length > 0) {
50
- return nestedMessage.trim();
51
- }
52
- }
53
-
54
- return null;
55
- }
56
-
57
- function createParallelApiError(statusCode: number, detail?: string): ParallelApiError {
58
- return new ParallelApiError(
59
- detail ? `Parallel API error (${statusCode}): ${detail}` : `Parallel API error (${statusCode})`,
60
- statusCode,
61
- );
62
- }
63
-
64
- function parseParallelErrorResponse(statusCode: number, responseText: string): ParallelApiError {
65
- const trimmedResponseText = responseText.trim();
66
- if (trimmedResponseText.length === 0) {
67
- return createParallelApiError(statusCode);
68
- }
69
-
70
- try {
71
- const payload: unknown = JSON.parse(trimmedResponseText);
72
- return createParallelApiError(statusCode, extractParallelErrorMessage(payload) ?? trimmedResponseText);
73
- } catch {
74
- return createParallelApiError(statusCode, trimmedResponseText);
75
- }
76
- }
77
-
78
- function parseSearchPayload(payload: unknown): ParallelSearchResult {
79
- if (!isObject(payload)) {
80
- throw new ParallelApiError("Parallel search returned an invalid response payload.");
81
- }
82
-
83
- const requestId = getString(payload, "search_id") ?? "";
84
- const rawResults = getObjectArray(payload, "results");
85
- const sources: ParallelSearchSource[] = [];
86
-
87
- for (const item of rawResults) {
88
- const url = getString(item, "url");
89
- if (!url) continue;
90
-
91
- const excerpts = getStringArray(item, "excerpts");
92
- const snippet = excerpts.length > 0 ? excerpts.join("\n\n") : undefined;
93
- sources.push({
94
- title: getString(item, "title") ?? url,
95
- url,
96
- snippet,
97
- publishedDate: getString(item, "publish_date"),
98
- excerpts,
99
- });
100
- }
101
-
102
- return {
103
- requestId,
104
- sources,
105
- warnings: [],
106
- usage: [],
107
- };
108
- }
109
19
 
110
20
  async function searchWithAuthStorage(
111
21
  objective: string,
@@ -150,12 +60,13 @@ async function searchWithAuthStorage(
150
60
  }),
151
61
  signal: withHardTimeout(params.signal),
152
62
  });
63
+
153
64
  if (!response.ok) {
154
65
  throw parseParallelErrorResponse(response.status, await response.text());
155
66
  }
156
67
 
157
68
  const payload: unknown = await response.json();
158
- return parseSearchPayload(payload);
69
+ return parseParallelSearchPayload(payload, { parseMetadata: false });
159
70
  },
160
71
  { signal: params.signal },
161
72
  );
@@ -833,16 +833,28 @@ export class PerplexityProvider extends SearchProvider {
833
833
  readonly id = "perplexity";
834
834
  readonly label = "Perplexity";
835
835
 
836
+ /**
837
+ * Auto-chain admission. Requires a direct Perplexity credential
838
+ * (`PERPLEXITY_COOKIES`, OAuth session, or `PERPLEXITY_API_KEY`).
839
+ *
840
+ * OpenRouter auth is intentionally NOT accepted here: silently using
841
+ * OpenRouter's `perplexity/sonar-pro` whenever any OpenRouter key is
842
+ * configured surprises users (and bills them) for a path they never
843
+ * asked for. The auto chain skips Perplexity in that case and falls
844
+ * through to the next configured provider. Users who DO want the
845
+ * OpenRouter-backed Perplexity path can still opt in by setting
846
+ * `webSearch: perplexity` explicitly — see {@link isExplicitlyAvailable}.
847
+ */
836
848
  isAvailable(authStorage: AuthStorage): boolean {
837
- return (
838
- !!$env.PERPLEXITY_COOKIES?.trim() || authStorage.hasAuth("perplexity") || authStorage.hasAuth("openrouter")
839
- );
849
+ return !!$env.PERPLEXITY_COOKIES?.trim() || authStorage.hasAuth("perplexity");
840
850
  }
841
851
 
842
852
  /**
843
- * Perplexity accepts anonymous browser-style ask requests, but keep auto
844
- * provider selection credential-gated so a configured provider keeps priority
845
- * over the anonymous fallback.
853
+ * Perplexity accepts anonymous browser-style ask requests, and the
854
+ * OpenRouter-backed `perplexity/sonar-pro` path is opt-in through
855
+ * explicit selection. Keep auto-chain admission credential-gated so a
856
+ * configured provider keeps priority over the anonymous/OpenRouter
857
+ * fallbacks.
846
858
  */
847
859
  isExplicitlyAvailable(_authStorage: AuthStorage): boolean {
848
860
  return true;