@oh-my-pi/pi-coding-agent 14.2.1 → 14.3.0
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 +59 -0
- package/package.json +19 -19
- package/src/cli/args.ts +10 -1
- package/src/cli/shell-cli.ts +15 -3
- package/src/config/settings-schema.ts +60 -1
- package/src/debug/system-info.ts +6 -2
- package/src/discovery/claude.ts +58 -36
- package/src/discovery/opencode.ts +20 -2
- package/src/edit/index.ts +2 -1
- package/src/edit/modes/chunk.ts +132 -56
- package/src/edit/modes/hashline.ts +36 -11
- package/src/edit/renderer.ts +98 -133
- package/src/edit/streaming.ts +351 -0
- package/src/exec/bash-executor.ts +60 -5
- package/src/internal-urls/docs-index.generated.ts +5 -5
- package/src/internal-urls/pi-protocol.ts +0 -2
- package/src/lsp/client.ts +8 -1
- package/src/lsp/defaults.json +2 -1
- package/src/modes/acp/acp-agent.ts +76 -2
- package/src/modes/components/assistant-message.ts +1 -34
- package/src/modes/components/hook-editor.ts +1 -1
- package/src/modes/components/tool-execution.ts +111 -101
- package/src/modes/controllers/input-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +0 -2
- package/src/modes/theme/mermaid-cache.ts +13 -52
- package/src/modes/theme/theme.ts +2 -2
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/chunk-edit.md +25 -22
- package/src/prompts/tools/gh-pr-push.md +2 -1
- package/src/prompts/tools/grep.md +4 -3
- package/src/prompts/tools/lsp.md +6 -0
- package/src/prompts/tools/read-chunk.md +46 -7
- package/src/prompts/tools/read.md +7 -4
- package/src/sdk.ts +8 -5
- package/src/session/agent-session.ts +36 -20
- package/src/session/session-manager.ts +228 -57
- package/src/session/streaming-output.ts +11 -0
- package/src/system-prompt.ts +7 -2
- package/src/task/executor.ts +1 -0
- package/src/tools/bash.ts +13 -0
- package/src/tools/gh.ts +6 -16
- package/src/tools/sqlite-reader.ts +116 -3
- package/src/web/search/providers/codex.ts +129 -6
|
@@ -106,6 +106,125 @@ function isImagePlaceholderAnswer(text: string): boolean {
|
|
|
106
106
|
return text.trim().toLowerCase() === "(see attached image)";
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
function addSource(sources: SearchSource[], source: SearchSource): void {
|
|
110
|
+
if (!sources.some(existing => existing.url === source.url)) {
|
|
111
|
+
sources.push(source);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function countCharacter(text: string, target: string): number {
|
|
116
|
+
let count = 0;
|
|
117
|
+
for (const char of text) {
|
|
118
|
+
if (char === target) {
|
|
119
|
+
count += 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return count;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Strips prose punctuation and unmatched closing delimiters from extracted URLs.
|
|
127
|
+
* Codex often returns links in markdown or sentence text without structured annotations.
|
|
128
|
+
*/
|
|
129
|
+
function normalizeExtractedUrl(candidate: string): string | null {
|
|
130
|
+
let url = candidate.trim();
|
|
131
|
+
|
|
132
|
+
while (url.length > 0) {
|
|
133
|
+
const lastCharacter = url.at(-1);
|
|
134
|
+
if (!lastCharacter) break;
|
|
135
|
+
if (/[.,!?;:'"]/u.test(lastCharacter)) {
|
|
136
|
+
url = url.slice(0, -1);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (lastCharacter === ")" && countCharacter(url, ")") > countCharacter(url, "(")) {
|
|
140
|
+
url = url.slice(0, -1);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (lastCharacter === "]" && countCharacter(url, "]") > countCharacter(url, "[")) {
|
|
144
|
+
url = url.slice(0, -1);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (lastCharacter === "}" && countCharacter(url, "}") > countCharacter(url, "{")) {
|
|
148
|
+
url = url.slice(0, -1);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!/^https?:\/\//.test(url)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
return new URL(url).toString();
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function findMarkdownLinkUrlEnd(text: string, openParenIndex: number): number | null {
|
|
166
|
+
let depth = 0;
|
|
167
|
+
|
|
168
|
+
for (let index = openParenIndex; index < text.length; index += 1) {
|
|
169
|
+
const character = text[index];
|
|
170
|
+
if (!character || character === "\n") {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
if (character === "(") {
|
|
174
|
+
depth += 1;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (character !== ")") {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
depth -= 1;
|
|
181
|
+
if (depth === 0) {
|
|
182
|
+
return index;
|
|
183
|
+
}
|
|
184
|
+
if (depth < 0) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Extracts citation sources from markdown links and bare URLs in the answer text.
|
|
194
|
+
* Used as a fallback when the Codex response omits `url_citation` annotations.
|
|
195
|
+
*/
|
|
196
|
+
function extractTextSources(text: string): SearchSource[] {
|
|
197
|
+
const sources: SearchSource[] = [];
|
|
198
|
+
|
|
199
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
200
|
+
if (text[index] !== "[") {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const titleEnd = text.indexOf("]", index + 1);
|
|
204
|
+
if (titleEnd === -1 || text[titleEnd + 1] !== "(") {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const urlEnd = findMarkdownLinkUrlEnd(text, titleEnd + 1);
|
|
208
|
+
if (urlEnd === null) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const title = text.slice(index + 1, titleEnd).trim();
|
|
212
|
+
const url = normalizeExtractedUrl(text.slice(titleEnd + 2, urlEnd));
|
|
213
|
+
if (url) {
|
|
214
|
+
addSource(sources, { title: title || url, url });
|
|
215
|
+
}
|
|
216
|
+
index = urlEnd;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (const match of text.matchAll(/https?:\/\/\S+/g)) {
|
|
220
|
+
const url = normalizeExtractedUrl(match[0] ?? "");
|
|
221
|
+
if (!url) continue;
|
|
222
|
+
addSource(sources, { title: url, url });
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return sources;
|
|
226
|
+
}
|
|
227
|
+
|
|
109
228
|
/**
|
|
110
229
|
* Extracts account ID from a Codex access token.
|
|
111
230
|
* @param accessToken - JWT access token
|
|
@@ -211,6 +330,7 @@ async function callCodexSearch(
|
|
|
211
330
|
search_context_size: options.searchContextSize ?? "high",
|
|
212
331
|
},
|
|
213
332
|
],
|
|
333
|
+
tool_choice: { type: "web_search" },
|
|
214
334
|
instructions: options.systemPrompt ?? DEFAULT_INSTRUCTIONS,
|
|
215
335
|
};
|
|
216
336
|
|
|
@@ -262,12 +382,7 @@ async function callCodexSearch(
|
|
|
262
382
|
for (const annotation of part.annotations) {
|
|
263
383
|
if (annotation.type === "url_citation" && annotation.url) {
|
|
264
384
|
// Deduplicate by URL
|
|
265
|
-
|
|
266
|
-
sources.push({
|
|
267
|
-
title: annotation.title ?? annotation.url,
|
|
268
|
-
url: annotation.url,
|
|
269
|
-
});
|
|
270
|
-
}
|
|
385
|
+
addSource(sources, { title: annotation.title ?? annotation.url, url: annotation.url });
|
|
271
386
|
}
|
|
272
387
|
}
|
|
273
388
|
}
|
|
@@ -317,6 +432,14 @@ async function callCodexSearch(
|
|
|
317
432
|
? streamedAnswer
|
|
318
433
|
: finalAnswer;
|
|
319
434
|
|
|
435
|
+
// Fallback: when Codex omits url_citation annotations, scrape markdown links
|
|
436
|
+
// and bare URLs from the synthesized answer so callers still receive sources.
|
|
437
|
+
if (sources.length === 0 && answer.length > 0) {
|
|
438
|
+
for (const source of extractTextSources(answer)) {
|
|
439
|
+
addSource(sources, source);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
320
443
|
return {
|
|
321
444
|
answer,
|
|
322
445
|
sources,
|