@oh-my-pi/pi-coding-agent 14.5.12 → 14.5.14

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 (112) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/package.json +18 -10
  3. package/src/cli/jupyter-cli.ts +1 -1
  4. package/src/commit/pipeline.ts +4 -3
  5. package/src/config/model-equivalence.ts +49 -16
  6. package/src/config/model-registry.ts +100 -25
  7. package/src/config/model-resolver.ts +29 -15
  8. package/src/config/settings-schema.ts +20 -6
  9. package/src/config/settings.ts +9 -8
  10. package/src/config.ts +18 -6
  11. package/src/eval/backend.ts +43 -0
  12. package/src/eval/eval.lark +43 -0
  13. package/src/eval/index.ts +5 -0
  14. package/src/eval/js/context-manager.ts +717 -0
  15. package/src/eval/js/executor.ts +131 -0
  16. package/src/eval/js/index.ts +46 -0
  17. package/src/eval/js/prelude.ts +2 -0
  18. package/src/eval/js/prelude.txt +84 -0
  19. package/src/eval/js/tool-bridge.ts +124 -0
  20. package/src/eval/parse.ts +337 -0
  21. package/src/{ipy → eval/py}/executor.ts +2 -180
  22. package/src/{ipy → eval/py}/gateway-coordinator.ts +2 -2
  23. package/src/eval/py/index.ts +58 -0
  24. package/src/{ipy → eval/py}/kernel.ts +9 -45
  25. package/src/{ipy → eval/py}/prelude.py +39 -227
  26. package/src/eval/types.ts +48 -0
  27. package/src/export/html/template.generated.ts +1 -1
  28. package/src/export/html/template.js +8 -10
  29. package/src/extensibility/extensions/types.ts +2 -3
  30. package/src/internal-urls/docs-index.generated.ts +5 -5
  31. package/src/lsp/client.ts +9 -0
  32. package/src/lsp/index.ts +395 -0
  33. package/src/lsp/types.ts +15 -4
  34. package/src/main.ts +35 -14
  35. package/src/mcp/manager.ts +22 -0
  36. package/src/mcp/oauth-flow.ts +1 -1
  37. package/src/memories/index.ts +1 -1
  38. package/src/modes/acp/acp-event-mapper.ts +1 -1
  39. package/src/modes/components/{python-execution.ts → eval-execution.ts} +11 -4
  40. package/src/modes/components/login-dialog.ts +1 -1
  41. package/src/modes/components/oauth-selector.ts +2 -1
  42. package/src/modes/components/tool-execution.ts +3 -4
  43. package/src/modes/controllers/command-controller.ts +28 -8
  44. package/src/modes/controllers/input-controller.ts +4 -4
  45. package/src/modes/controllers/selector-controller.ts +2 -1
  46. package/src/modes/interactive-mode.ts +4 -5
  47. package/src/modes/rpc/rpc-client.ts +9 -0
  48. package/src/modes/rpc/rpc-mode.ts +6 -0
  49. package/src/modes/rpc/rpc-types.ts +9 -0
  50. package/src/modes/types.ts +3 -3
  51. package/src/modes/utils/ui-helpers.ts +2 -2
  52. package/src/prompts/system/system-prompt.md +3 -3
  53. package/src/prompts/tools/eval.md +92 -0
  54. package/src/prompts/tools/lsp.md +7 -3
  55. package/src/sdk.ts +64 -35
  56. package/src/session/agent-session.ts +152 -46
  57. package/src/session/messages.ts +1 -1
  58. package/src/slash-commands/builtin-registry.ts +1 -1
  59. package/src/system-prompt.ts +34 -66
  60. package/src/task/agents.ts +4 -5
  61. package/src/task/executor.ts +5 -9
  62. package/src/tools/archive-reader.ts +9 -3
  63. package/src/tools/browser/launch.ts +22 -0
  64. package/src/tools/browser/readable.ts +11 -6
  65. package/src/tools/browser/registry.ts +25 -244
  66. package/src/tools/browser/render.ts +1 -1
  67. package/src/tools/browser/tab-protocol.ts +101 -0
  68. package/src/tools/browser/tab-supervisor.ts +429 -0
  69. package/src/tools/browser/tab-worker-entry.ts +21 -0
  70. package/src/tools/browser/tab-worker.ts +1006 -0
  71. package/src/tools/browser.ts +17 -32
  72. package/src/tools/checkpoint.ts +2 -2
  73. package/src/tools/{python.ts → eval.ts} +324 -315
  74. package/src/tools/exit-plan-mode.ts +1 -1
  75. package/src/tools/image-gen.ts +2 -2
  76. package/src/tools/index.ts +62 -100
  77. package/src/tools/read.ts +0 -6
  78. package/src/tools/recipe/runners/pkg.ts +34 -32
  79. package/src/tools/renderers.ts +2 -2
  80. package/src/tools/resolve.ts +7 -2
  81. package/src/tools/todo-write.ts +0 -1
  82. package/src/tools/tool-timeouts.ts +2 -2
  83. package/src/tools/write.ts +8 -1
  84. package/src/utils/markit.ts +15 -7
  85. package/src/utils/tools-manager.ts +5 -5
  86. package/src/web/scrapers/crossref.ts +3 -3
  87. package/src/web/scrapers/devto.ts +1 -1
  88. package/src/web/scrapers/discourse.ts +5 -5
  89. package/src/web/scrapers/firefox-addons.ts +1 -1
  90. package/src/web/scrapers/flathub.ts +2 -2
  91. package/src/web/scrapers/gitlab.ts +1 -1
  92. package/src/web/scrapers/go-pkg.ts +2 -2
  93. package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
  94. package/src/web/scrapers/mastodon.ts +9 -9
  95. package/src/web/scrapers/mdn.ts +11 -7
  96. package/src/web/scrapers/pub-dev.ts +1 -1
  97. package/src/web/scrapers/rawg.ts +3 -3
  98. package/src/web/scrapers/readthedocs.ts +1 -1
  99. package/src/web/scrapers/spdx.ts +1 -1
  100. package/src/web/scrapers/stackoverflow.ts +2 -2
  101. package/src/web/scrapers/types.ts +53 -39
  102. package/src/web/scrapers/w3c.ts +1 -1
  103. package/src/web/search/index.ts +5 -5
  104. package/src/web/search/provider.ts +121 -39
  105. package/src/web/search/providers/gemini.ts +4 -4
  106. package/src/web/search/render.ts +2 -2
  107. package/src/ipy/modules.ts +0 -144
  108. package/src/prompts/tools/python.md +0 -57
  109. package/src/tools/browser/vm.ts +0 -792
  110. /package/src/{ipy → eval/py}/cancellation.ts +0 -0
  111. /package/src/{ipy → eval/py}/prelude.ts +0 -0
  112. /package/src/{ipy → eval/py}/runtime.ts +0 -0
@@ -8,11 +8,11 @@
8
8
  import {
9
9
  ANTIGRAVITY_SYSTEM_INSTRUCTION,
10
10
  extractRetryDelay,
11
- getAntigravityHeaders,
11
+ getAntigravityUserAgent,
12
12
  getGeminiCliHeaders,
13
- refreshAntigravityToken,
14
- refreshGoogleCloudToken,
15
13
  } from "@oh-my-pi/pi-ai";
14
+ import { refreshAntigravityToken } from "@oh-my-pi/pi-ai/utils/oauth/google-antigravity";
15
+ import { refreshGoogleCloudToken } from "@oh-my-pi/pi-ai/utils/oauth/google-gemini-cli";
16
16
  import { getAgentDbPath } from "@oh-my-pi/pi-utils";
17
17
  import { AgentStorage } from "../../../session/agent-storage";
18
18
  import type { SearchCitation, SearchResponse, SearchSource } from "../../../web/search/types";
@@ -248,7 +248,7 @@ async function callGeminiSearch(
248
248
  usage?: { inputTokens: number; outputTokens: number; totalTokens: number };
249
249
  }> {
250
250
  const endpoints = auth.isAntigravity ? ANTIGRAVITY_ENDPOINT_FALLBACKS : [DEFAULT_ENDPOINT];
251
- const headers = auth.isAntigravity ? getAntigravityHeaders() : getGeminiCliHeaders();
251
+ const headers = auth.isAntigravity ? { "User-Agent": getAntigravityUserAgent() } : getGeminiCliHeaders();
252
252
 
253
253
  const requestMetadata = auth.isAntigravity
254
254
  ? {
@@ -22,7 +22,7 @@ import {
22
22
  } from "../../tools/render-utils";
23
23
  import { renderStatusLine, renderTreeList } from "../../tui";
24
24
  import { CachedOutputBlock } from "../../tui/output-block";
25
- import { getSearchProvider } from "./provider";
25
+ import { getSearchProviderLabel } from "./provider";
26
26
  import type { SearchResponse } from "./types";
27
27
 
28
28
  const MAX_COLLAPSED_ANSWER_LINES = PREVIEW_LIMITS.COLLAPSED_LINES;
@@ -112,7 +112,7 @@ export function renderSearchResult(
112
112
  : [];
113
113
  const totalAnswerLines = answerLines.length;
114
114
 
115
- const providerLabel = provider !== "none" ? getSearchProvider(provider).label : "None";
115
+ const providerLabel = provider !== "none" ? getSearchProviderLabel(provider) : "None";
116
116
  const queryPreview = args?.query
117
117
  ? truncateToWidth(args.query, 80)
118
118
  : searchQueries[0]
@@ -1,144 +0,0 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
3
- import { getAgentModulesDir, getProjectDir, getProjectModulesDir } from "@oh-my-pi/pi-utils";
4
- import { getExecutionCancellationError } from "./cancellation";
5
-
6
- export type PythonModuleSource = "user" | "project";
7
-
8
- export interface PythonModuleEntry {
9
- path: string;
10
- content: string;
11
- source: PythonModuleSource;
12
- }
13
-
14
- export interface PythonModuleExecuteResult {
15
- status: "ok" | "error";
16
- cancelled: boolean;
17
- timedOut?: boolean;
18
- error?: { name: string; value: string; traceback: string[] };
19
- }
20
-
21
- export interface PythonModuleExecutor {
22
- execute: (
23
- code: string,
24
- options?: { signal?: AbortSignal; timeoutMs?: number; silent?: boolean; storeHistory?: boolean },
25
- ) => Promise<PythonModuleExecuteResult>;
26
- }
27
-
28
- export interface DiscoverPythonModulesOptions {
29
- /** Working directory for project-level modules. Default: getProjectDir() */
30
- cwd?: string;
31
- /** Agent directory for user-level modules. Default: from getAgentDir() */
32
- agentDir?: string;
33
- }
34
-
35
- export interface LoadPythonModulesOptions extends DiscoverPythonModulesOptions {
36
- signal?: AbortSignal;
37
- timeoutMs?: number;
38
- deadlineMs?: number;
39
- }
40
-
41
- interface ModuleCandidate {
42
- name: string;
43
- path: string;
44
- source: PythonModuleSource;
45
- }
46
-
47
- async function listModuleCandidates(dir: string, source: PythonModuleSource): Promise<ModuleCandidate[]> {
48
- try {
49
- const entries = await fs.readdir(dir, { withFileTypes: true });
50
- return entries
51
- .filter(entry => entry.isFile() && entry.name.endsWith(".py"))
52
- .map(entry => ({
53
- name: entry.name,
54
- path: path.resolve(dir, entry.name),
55
- source,
56
- }));
57
- } catch {
58
- return [];
59
- }
60
- }
61
-
62
- async function readModuleContent(candidate: ModuleCandidate): Promise<PythonModuleEntry> {
63
- try {
64
- const content = await Bun.file(candidate.path).text();
65
- return { path: candidate.path, content, source: candidate.source };
66
- } catch (err) {
67
- const message = err instanceof Error ? err.message : String(err);
68
- throw new Error(`Failed to read Python module ${candidate.path}: ${message}`);
69
- }
70
- }
71
-
72
- function createTimeoutError(message: string): Error {
73
- const error = new Error(message);
74
- error.name = "TimeoutError";
75
- return error;
76
- }
77
-
78
- function requireModuleExecutionTimeoutMs(options: LoadPythonModulesOptions): number | undefined {
79
- if (options.deadlineMs === undefined) {
80
- return options.timeoutMs;
81
- }
82
-
83
- const remainingMs = options.deadlineMs - Date.now();
84
- if (remainingMs <= 0) {
85
- throw createTimeoutError("Python module loading timed out");
86
- }
87
-
88
- return remainingMs;
89
- }
90
-
91
- /**
92
- * Discover Python prelude extension modules from user and project directories.
93
- */
94
- export async function discoverPythonModules(options: DiscoverPythonModulesOptions = {}): Promise<PythonModuleEntry[]> {
95
- const cwd = options.cwd ?? getProjectDir();
96
-
97
- const userDir = getAgentModulesDir(options.agentDir);
98
- const projectDir = getProjectModulesDir(cwd);
99
-
100
- const userCandidates = await listModuleCandidates(userDir, "user");
101
- const projectCandidates = await listModuleCandidates(projectDir, "project");
102
-
103
- const byName = new Map<string, ModuleCandidate>();
104
- for (const candidate of userCandidates) {
105
- if (!byName.has(candidate.name)) {
106
- byName.set(candidate.name, candidate);
107
- }
108
- }
109
- for (const candidate of projectCandidates) {
110
- const existing = byName.get(candidate.name);
111
- if (!existing || existing.source === "user") {
112
- byName.set(candidate.name, candidate);
113
- }
114
- }
115
-
116
- const sorted = Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name));
117
- return Promise.all(sorted.map(candidate => readModuleContent(candidate)));
118
- }
119
-
120
- /**
121
- * Load Python prelude extension modules into an active kernel.
122
- */
123
- export async function loadPythonModules(
124
- executor: PythonModuleExecutor,
125
- options: LoadPythonModulesOptions = {},
126
- ): Promise<PythonModuleEntry[]> {
127
- const modules = await discoverPythonModules(options);
128
- for (const module of modules) {
129
- const result = await executor.execute(module.content, {
130
- signal: options.signal,
131
- timeoutMs: requireModuleExecutionTimeoutMs(options),
132
- silent: true,
133
- storeHistory: false,
134
- });
135
- if (result.cancelled) {
136
- throw getExecutionCancellationError(result, options.signal, `Failed to load Python module ${module.path}`);
137
- }
138
- if (result.status === "error") {
139
- const details = result.error ? `${result.error.name}: ${result.error.value}` : "unknown error";
140
- throw new Error(`Failed to load Python module ${module.path}: ${details}`);
141
- }
142
- }
143
- return modules;
144
- }
@@ -1,57 +0,0 @@
1
- Runs Python cells sequentially in persistent IPython kernel.
2
-
3
- <instruction>
4
- Kernel persists across calls and cells; **imports, variables, and functions survive — use this.**
5
-
6
- **Work incrementally:** one logical step per cell (imports, define, test, use). Pass multiple small cells in one call. Define small reusable functions you can debug individually. You **MUST** put workflow explanations in the assistant message or cell title — never inside cell code.
7
-
8
- **On failure:** errors identify the failing cell (e.g., "Cell 3 failed"). Resubmit only the fixed cell (or fixed cell + remaining cells).
9
- </instruction>
10
-
11
- {{#if categories.length}}
12
- <prelude>
13
- All helpers auto-print results and return values for chaining.
14
-
15
- {{#each categories}}
16
- ### {{name}}
17
-
18
- ```
19
- {{#each functions}}
20
- {{name}}{{signature}}
21
- {{docstring}}
22
- {{/each}}
23
- ```
24
- {{/each}}
25
- </prelude>
26
- {{/if}}
27
-
28
- <output>
29
- User sees output like Jupyter notebook; rich displays render fully:
30
- - `display(JSON(data))` → interactive JSON tree
31
- - `display(HTML(…))` → rendered HTML
32
- - `display(Markdown(…))` → formatted markdown
33
- - `plt.show()` → inline figures
34
-
35
- **You will see object repr** (e.g., `<IPython.core.display.JSON object>`). Trust `display()`; you **MUST NOT** assume the user sees only the repr.
36
- </output>
37
-
38
- <caution>
39
- - Per-call mode uses a fresh kernel each call
40
- - You **MUST** use `reset: true` to clear state when session mode is active
41
- </caution>
42
-
43
- <critical>
44
- - You **MUST** use `run()` for shell commands; you **MUST NOT** use raw `subprocess`
45
- </critical>
46
-
47
- <examples>
48
- # Multiple small cells
49
- ```python
50
- cells: [
51
- {"title": "imports", "code": "import json\nfrom pathlib import Path"},
52
- {"title": "parse helper", "code": "def parse_config(path):\n return json.loads(Path(path).read_text())"},
53
- {"title": "test helper", "code": "parse_config('config.json')"},
54
- {"title": "use helper", "code": "configs = [parse_config(p) for p in Path('.').glob('*.json')]"}
55
- ]
56
- ```
57
- </examples>