@oh-my-pi/pi-coding-agent 14.0.3 → 14.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.
- package/CHANGELOG.md +63 -1
- package/package.json +11 -8
- package/src/config/model-registry.ts +3 -2
- package/src/config/model-resolver.ts +33 -25
- package/src/config/settings.ts +9 -2
- package/src/dap/session.ts +31 -39
- package/src/debug/log-formatting.ts +2 -2
- package/src/edit/index.ts +2 -0
- package/src/edit/modes/chunk.ts +45 -16
- package/src/edit/modes/hashline.ts +2 -2
- package/src/ipy/executor.ts +3 -7
- package/src/ipy/kernel.ts +3 -3
- package/src/lsp/client.ts +4 -2
- package/src/lsp/index.ts +4 -9
- package/src/lsp/lspmux.ts +2 -2
- package/src/lsp/utils.ts +27 -143
- package/src/modes/components/diff.ts +1 -1
- package/src/modes/controllers/event-controller.ts +438 -426
- package/src/modes/theme/mermaid-cache.ts +5 -7
- package/src/modes/theme/theme.ts +2 -161
- package/src/priority.json +8 -0
- package/src/prompts/agents/designer.md +1 -2
- package/src/prompts/system/system-prompt.md +40 -2
- package/src/prompts/tools/chunk-edit.md +66 -38
- package/src/prompts/tools/read-chunk.md +10 -1
- package/src/sdk.ts +2 -1
- package/src/session/agent-session.ts +10 -0
- package/src/session/compaction/compaction.ts +1 -1
- package/src/tools/ast-edit.ts +2 -2
- package/src/tools/browser.ts +84 -21
- package/src/tools/fetch.ts +1 -1
- package/src/tools/find.ts +40 -94
- package/src/tools/gemini-image.ts +1 -0
- package/src/tools/index.ts +2 -3
- package/src/tools/read.ts +2 -0
- package/src/tools/render-utils.ts +1 -1
- package/src/tools/report-tool-issue.ts +2 -2
- package/src/utils/edit-mode.ts +2 -2
- package/src/utils/image-resize.ts +73 -37
- package/src/utils/lang-from-path.ts +239 -0
- package/src/utils/sixel.ts +2 -2
- package/src/web/scrapers/types.ts +50 -32
- package/src/web/search/providers/codex.ts +21 -2
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extension segment → [highlight language id, LSP language id].
|
|
5
|
+
* Highlight ids match tree-sitter / native highlighter; LSP ids match Language Server Protocol.
|
|
6
|
+
*/
|
|
7
|
+
const EXTENSION_LANG: Record<string, readonly [string, string]> = {
|
|
8
|
+
// TypeScript / JavaScript
|
|
9
|
+
ts: ["typescript", "typescript"],
|
|
10
|
+
cts: ["typescript", "typescript"],
|
|
11
|
+
mts: ["typescript", "typescript"],
|
|
12
|
+
tsx: ["tsx", "typescriptreact"],
|
|
13
|
+
js: ["javascript", "javascript"],
|
|
14
|
+
jsx: ["javascript", "javascriptreact"],
|
|
15
|
+
mjs: ["javascript", "javascript"],
|
|
16
|
+
cjs: ["javascript", "javascript"],
|
|
17
|
+
|
|
18
|
+
// Systems
|
|
19
|
+
rs: ["rust", "rust"],
|
|
20
|
+
go: ["go", "go"],
|
|
21
|
+
c: ["c", "c"],
|
|
22
|
+
h: ["c", "c"],
|
|
23
|
+
cpp: ["cpp", "cpp"],
|
|
24
|
+
cc: ["cpp", "cpp"],
|
|
25
|
+
cxx: ["cpp", "cpp"],
|
|
26
|
+
hh: ["cpp", "cpp"],
|
|
27
|
+
hpp: ["cpp", "cpp"],
|
|
28
|
+
hxx: ["cpp", "cpp"],
|
|
29
|
+
cu: ["cpp", "cpp"],
|
|
30
|
+
ino: ["cpp", "cpp"],
|
|
31
|
+
zig: ["zig", "zig"],
|
|
32
|
+
|
|
33
|
+
// Scripting
|
|
34
|
+
py: ["python", "python"],
|
|
35
|
+
pyi: ["python", "python"],
|
|
36
|
+
rb: ["ruby", "ruby"],
|
|
37
|
+
rbw: ["ruby", "ruby"],
|
|
38
|
+
gemspec: ["ruby", "ruby"],
|
|
39
|
+
lua: ["lua", "lua"],
|
|
40
|
+
sh: ["bash", "shellscript"],
|
|
41
|
+
bash: ["bash", "shellscript"],
|
|
42
|
+
zsh: ["bash", "shellscript"],
|
|
43
|
+
ksh: ["bash", "shellscript"],
|
|
44
|
+
bats: ["bash", "shellscript"],
|
|
45
|
+
tmux: ["bash", "shellscript"],
|
|
46
|
+
cgi: ["bash", "shellscript"],
|
|
47
|
+
fcgi: ["bash", "shellscript"],
|
|
48
|
+
command: ["bash", "shellscript"],
|
|
49
|
+
tool: ["bash", "shellscript"],
|
|
50
|
+
fish: ["fish", "fish"],
|
|
51
|
+
pl: ["perl", "perl"],
|
|
52
|
+
pm: ["perl", "perl"],
|
|
53
|
+
perl: ["perl", "perl"],
|
|
54
|
+
php: ["php", "php"],
|
|
55
|
+
|
|
56
|
+
// JVM
|
|
57
|
+
java: ["java", "java"],
|
|
58
|
+
kt: ["kotlin", "kotlin"],
|
|
59
|
+
ktm: ["kotlin", "kotlin"],
|
|
60
|
+
kts: ["kotlin", "kotlin"],
|
|
61
|
+
scala: ["scala", "scala"],
|
|
62
|
+
sc: ["scala", "scala"],
|
|
63
|
+
sbt: ["scala", "scala"],
|
|
64
|
+
groovy: ["groovy", "groovy"],
|
|
65
|
+
clj: ["clojure", "clojure"],
|
|
66
|
+
cljc: ["clojure", "clojure"],
|
|
67
|
+
cljs: ["clojure", "clojure"],
|
|
68
|
+
edn: ["clojure", "clojure"],
|
|
69
|
+
|
|
70
|
+
// .NET
|
|
71
|
+
cs: ["csharp", "csharp"],
|
|
72
|
+
fs: ["fsharp", "fsharp"],
|
|
73
|
+
vb: ["vb", "vb"],
|
|
74
|
+
|
|
75
|
+
// Web
|
|
76
|
+
html: ["html", "html"],
|
|
77
|
+
htm: ["html", "html"],
|
|
78
|
+
xhtml: ["html", "html"],
|
|
79
|
+
css: ["css", "css"],
|
|
80
|
+
scss: ["scss", "scss"],
|
|
81
|
+
sass: ["sass", "sass"],
|
|
82
|
+
less: ["less", "less"],
|
|
83
|
+
vue: ["vue", "vue"],
|
|
84
|
+
svelte: ["svelte", "svelte"],
|
|
85
|
+
astro: ["astro", "astro"],
|
|
86
|
+
|
|
87
|
+
// Data
|
|
88
|
+
json: ["json", "json"],
|
|
89
|
+
jsonc: ["jsonc", "jsonc"],
|
|
90
|
+
yaml: ["yaml", "yaml"],
|
|
91
|
+
yml: ["yaml", "yaml"],
|
|
92
|
+
toml: ["toml", "toml"],
|
|
93
|
+
xml: ["xml", "xml"],
|
|
94
|
+
xsl: ["xml", "xml"],
|
|
95
|
+
xslt: ["xml", "xml"],
|
|
96
|
+
svg: ["xml", "xml"],
|
|
97
|
+
plist: ["xml", "xml"],
|
|
98
|
+
ini: ["ini", "ini"],
|
|
99
|
+
|
|
100
|
+
// Docs
|
|
101
|
+
md: ["markdown", "markdown"],
|
|
102
|
+
markdown: ["markdown", "markdown"],
|
|
103
|
+
mdx: ["markdown", "markdown"],
|
|
104
|
+
rst: ["restructuredtext", "restructuredtext"],
|
|
105
|
+
adoc: ["asciidoc", "asciidoc"],
|
|
106
|
+
tex: ["latex", "latex"],
|
|
107
|
+
|
|
108
|
+
// Other languages
|
|
109
|
+
sql: ["sql", "sql"],
|
|
110
|
+
graphql: ["graphql", "graphql"],
|
|
111
|
+
gql: ["graphql", "graphql"],
|
|
112
|
+
proto: ["protobuf", "protobuf"],
|
|
113
|
+
dockerfile: ["dockerfile", "dockerfile"],
|
|
114
|
+
containerfile: ["dockerfile", "dockerfile"],
|
|
115
|
+
tf: ["hcl", "terraform"],
|
|
116
|
+
hcl: ["hcl", "hcl"],
|
|
117
|
+
tfvars: ["hcl", "hcl"],
|
|
118
|
+
nix: ["nix", "nix"],
|
|
119
|
+
ex: ["elixir", "elixir"],
|
|
120
|
+
exs: ["elixir", "elixir"],
|
|
121
|
+
erl: ["erlang", "erlang"],
|
|
122
|
+
hrl: ["erlang", "erlang"],
|
|
123
|
+
hs: ["haskell", "haskell"],
|
|
124
|
+
ml: ["ocaml", "ocaml"],
|
|
125
|
+
mli: ["ocaml", "ocaml"],
|
|
126
|
+
swift: ["swift", "swift"],
|
|
127
|
+
r: ["r", "r"],
|
|
128
|
+
jl: ["julia", "julia"],
|
|
129
|
+
dart: ["dart", "dart"],
|
|
130
|
+
elm: ["elm", "elm"],
|
|
131
|
+
v: ["verilog", "v"],
|
|
132
|
+
nim: ["nim", "nim"],
|
|
133
|
+
cr: ["crystal", "crystal"],
|
|
134
|
+
d: ["d", "d"],
|
|
135
|
+
pas: ["pascal", "pascal"],
|
|
136
|
+
pp: ["pascal", "pascal"],
|
|
137
|
+
lisp: ["lisp", "lisp"],
|
|
138
|
+
lsp: ["lisp", "lisp"],
|
|
139
|
+
rkt: ["racket", "racket"],
|
|
140
|
+
scm: ["scheme", "scheme"],
|
|
141
|
+
ps1: ["powershell", "powershell"],
|
|
142
|
+
psm1: ["powershell", "powershell"],
|
|
143
|
+
bat: ["bat", "bat"],
|
|
144
|
+
cmd: ["bat", "bat"],
|
|
145
|
+
tla: ["tlaplus", "tlaplus"],
|
|
146
|
+
tlaplus: ["tlaplus", "tlaplus"],
|
|
147
|
+
m: ["objc", "plaintext"],
|
|
148
|
+
mm: ["objc", "plaintext"],
|
|
149
|
+
sol: ["solidity", "plaintext"],
|
|
150
|
+
odin: ["odin", "plaintext"],
|
|
151
|
+
star: ["starlark", "plaintext"],
|
|
152
|
+
bzl: ["starlark", "plaintext"],
|
|
153
|
+
sv: ["verilog", "plaintext"],
|
|
154
|
+
svh: ["verilog", "plaintext"],
|
|
155
|
+
vh: ["verilog", "plaintext"],
|
|
156
|
+
vim: ["vim", "plaintext"],
|
|
157
|
+
ipynb: ["ipynb", "plaintext"],
|
|
158
|
+
hbs: ["handlebars", "plaintext"],
|
|
159
|
+
hsb: ["handlebars", "plaintext"],
|
|
160
|
+
handlebars: ["handlebars", "plaintext"],
|
|
161
|
+
diff: ["diff", "plaintext"],
|
|
162
|
+
patch: ["diff", "plaintext"],
|
|
163
|
+
makefile: ["make", "plaintext"],
|
|
164
|
+
mk: ["make", "plaintext"],
|
|
165
|
+
mak: ["make", "plaintext"],
|
|
166
|
+
cmake: ["cmake", "cmake"],
|
|
167
|
+
justfile: ["just", "plaintext"],
|
|
168
|
+
txt: ["text", "plaintext"],
|
|
169
|
+
text: ["text", "plaintext"],
|
|
170
|
+
log: ["log", "plaintext"],
|
|
171
|
+
csv: ["csv", "plaintext"],
|
|
172
|
+
tsv: ["tsv", "plaintext"],
|
|
173
|
+
cfg: ["conf", "plaintext"],
|
|
174
|
+
conf: ["conf", "plaintext"],
|
|
175
|
+
config: ["conf", "plaintext"],
|
|
176
|
+
properties: ["conf", "plaintext"],
|
|
177
|
+
env: ["env", "plaintext"],
|
|
178
|
+
gitignore: ["conf", "plaintext"],
|
|
179
|
+
gitattributes: ["conf", "plaintext"],
|
|
180
|
+
gitmodules: ["conf", "plaintext"],
|
|
181
|
+
editorconfig: ["conf", "plaintext"],
|
|
182
|
+
npmrc: ["conf", "plaintext"],
|
|
183
|
+
prettierrc: ["conf", "plaintext"],
|
|
184
|
+
eslintrc: ["conf", "plaintext"],
|
|
185
|
+
prettierignore: ["conf", "plaintext"],
|
|
186
|
+
eslintignore: ["conf", "plaintext"],
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/** Final segment after the last `.` in the full path (prior theme behavior). */
|
|
190
|
+
function themeExtensionKey(filePath: string): string {
|
|
191
|
+
const extBeg = filePath.lastIndexOf(".");
|
|
192
|
+
return extBeg !== -1 ? filePath.slice(extBeg + 1).toLowerCase() : filePath.toLowerCase();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function lspExtensionKey(filePath: string): string {
|
|
196
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
197
|
+
return ext.startsWith(".") ? ext.slice(1) : "";
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Language id for syntax highlighting and UI (icons, read tool), or undefined if unknown.
|
|
202
|
+
*/
|
|
203
|
+
export function getLanguageFromPath(filePath: string): string | undefined {
|
|
204
|
+
const pair = EXTENSION_LANG[themeExtensionKey(filePath)];
|
|
205
|
+
if (pair) return pair[0];
|
|
206
|
+
|
|
207
|
+
const baseName = path.basename(filePath).toLowerCase();
|
|
208
|
+
if (baseName.startsWith(".env.")) return "env";
|
|
209
|
+
if (baseName === "dockerfile" || baseName.startsWith("dockerfile.") || baseName === "containerfile") {
|
|
210
|
+
return "dockerfile";
|
|
211
|
+
}
|
|
212
|
+
if (baseName === "justfile") return "just";
|
|
213
|
+
if (baseName === "cmakelists.txt") return "cmake";
|
|
214
|
+
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* LSP language identifier; falls back to `plaintext`.
|
|
220
|
+
*/
|
|
221
|
+
export function detectLanguageId(filePath: string): string {
|
|
222
|
+
const baseName = path.basename(filePath).toLowerCase();
|
|
223
|
+
if (baseName === "dockerfile" || baseName.startsWith("dockerfile.") || baseName === "containerfile") {
|
|
224
|
+
return "dockerfile";
|
|
225
|
+
}
|
|
226
|
+
if (baseName === "makefile" || baseName === "gnumakefile") {
|
|
227
|
+
return "makefile";
|
|
228
|
+
}
|
|
229
|
+
if (baseName === "justfile") {
|
|
230
|
+
return "just";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const lspExt = lspExtensionKey(filePath);
|
|
234
|
+
if (baseName === "cmakelists.txt" || lspExt === "cmake") {
|
|
235
|
+
return "cmake";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return EXTENSION_LANG[lspExt]?.[1] ?? "plaintext";
|
|
239
|
+
}
|
package/src/utils/sixel.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $env } from "@oh-my-pi/pi-utils";
|
|
1
|
+
import { $env, $flag } from "@oh-my-pi/pi-utils";
|
|
2
2
|
|
|
3
3
|
const SIXEL_START_REGEX = /\x1bP(?:[0-9;]*)q/u;
|
|
4
4
|
const SIXEL_END_SEQUENCE = "\x1b\\";
|
|
@@ -15,7 +15,7 @@ const SIXEL_PLACEHOLDER_PREFIX = "__OMP_SIXEL_SEQUENCE_";
|
|
|
15
15
|
*/
|
|
16
16
|
export function isSixelPassthroughEnabled(): boolean {
|
|
17
17
|
const forcedProtocol = $env.PI_FORCE_IMAGE_PROTOCOL?.trim().toLowerCase();
|
|
18
|
-
return forcedProtocol === "sixel" && $
|
|
18
|
+
return forcedProtocol === "sixel" && $flag("PI_ALLOW_SIXEL_PASSTHROUGH");
|
|
19
19
|
}
|
|
20
20
|
/** Returns true when the text contains a SIXEL start sequence. */
|
|
21
21
|
export function containsSixelSequence(text: string): boolean {
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Shared types and utilities for web-fetch handlers
|
|
3
3
|
*/
|
|
4
4
|
import { ptree } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import TurndownService from "turndown";
|
|
6
|
+
import { gfm } from "turndown-plugin-gfm";
|
|
5
7
|
import { ToolAbortError } from "../../tools/tool-errors";
|
|
6
8
|
|
|
7
9
|
export { formatNumber } from "@oh-my-pi/pi-utils";
|
|
@@ -153,41 +155,57 @@ export async function loadPage(url: string, options: LoadPageOptions = {}): Prom
|
|
|
153
155
|
return { content: "", contentType: "", finalUrl: url, ok: false };
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
/** Module-level Turndown instance — matches markit-ai's configuration. */
|
|
159
|
+
const turndown = new TurndownService({
|
|
160
|
+
headingStyle: "atx",
|
|
161
|
+
codeBlockStyle: "fenced",
|
|
162
|
+
bulletListMarker: "-",
|
|
163
|
+
});
|
|
164
|
+
turndown.use(gfm);
|
|
165
|
+
turndown.addRule("strikethrough", {
|
|
166
|
+
filter: ["del", "s", "strike"],
|
|
167
|
+
replacement(content) {
|
|
168
|
+
return `~~${content}~~`;
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
turndown.addRule("heading", {
|
|
172
|
+
filter: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
|
173
|
+
replacement(content, node) {
|
|
174
|
+
const level = Number(node.nodeName.charAt(1));
|
|
175
|
+
const prefix = "#".repeat(level);
|
|
176
|
+
const cleaned = content.replace(/\\([.])/g, "$1").trim();
|
|
177
|
+
return `\n\n${prefix} ${cleaned}\n\n`;
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
type TurndownListParent = {
|
|
182
|
+
nodeName: string;
|
|
183
|
+
getAttribute(name: string): string | null;
|
|
184
|
+
children: ArrayLike<unknown>;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
turndown.addRule("listItem", {
|
|
188
|
+
filter: "li",
|
|
189
|
+
replacement(content, node, options) {
|
|
190
|
+
content = content.replace(/^\n+/, "").replace(/\n+$/, "\n").replace(/\n/gm, "\n ");
|
|
191
|
+
const parent = node.parentNode as unknown as TurndownListParent | null;
|
|
192
|
+
let prefix = `${options.bulletListMarker} `;
|
|
193
|
+
if (parent?.nodeName === "OL") {
|
|
194
|
+
const start = parent.getAttribute("start");
|
|
195
|
+
const index = Array.prototype.indexOf.call(parent.children, node);
|
|
196
|
+
prefix = `${(start ? Number(start) : 1) + index}. `;
|
|
197
|
+
}
|
|
198
|
+
return prefix + content + (node.nextSibling ? "\n" : "");
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
|
|
156
202
|
/**
|
|
157
|
-
* Convert
|
|
203
|
+
* Convert HTML to markdown using Turndown with GFM support.
|
|
204
|
+
* Strips script/style tags before conversion.
|
|
158
205
|
*/
|
|
159
206
|
export function htmlToBasicMarkdown(html: string): string {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
.replace(/<\/code><\/pre>/g, "\n```\n")
|
|
163
|
-
.replace(/<code[^>]*>/g, "`")
|
|
164
|
-
.replace(/<\/code>/g, "`")
|
|
165
|
-
.replace(/<strong[^>]*>/g, "**")
|
|
166
|
-
.replace(/<\/strong>/g, "**")
|
|
167
|
-
.replace(/<b[^>]*>/g, "**")
|
|
168
|
-
.replace(/<\/b>/g, "**")
|
|
169
|
-
.replace(/<em[^>]*>/g, "*")
|
|
170
|
-
.replace(/<\/em>/g, "*")
|
|
171
|
-
.replace(/<i[^>]*>/g, "*")
|
|
172
|
-
.replace(/<\/i>/g, "*")
|
|
173
|
-
.replace(
|
|
174
|
-
/<a[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/g,
|
|
175
|
-
(_, href, text) => `[${text.replace(/<[^>]+>/g, "").trim()}](${href})`,
|
|
176
|
-
)
|
|
177
|
-
.replace(/<p[^>]*>/g, "\n\n")
|
|
178
|
-
.replace(/<\/p>/g, "")
|
|
179
|
-
.replace(/<br\s*\/?>/g, "\n")
|
|
180
|
-
.replace(/<li[^>]*>/g, "- ")
|
|
181
|
-
.replace(/<\/li>/g, "\n")
|
|
182
|
-
.replace(/<\/?[uo]l[^>]*>/g, "\n")
|
|
183
|
-
.replace(/<h(\d)[^>]*>/g, (_, n) => `\n${"#".repeat(parseInt(n, 10))} `)
|
|
184
|
-
.replace(/<\/h\d>/g, "\n")
|
|
185
|
-
.replace(/<blockquote[^>]*>/g, "\n> ")
|
|
186
|
-
.replace(/<\/blockquote>/g, "\n")
|
|
187
|
-
.replace(/<[^>]+>/g, "")
|
|
188
|
-
.replace(/\n{3,}/g, "\n\n")
|
|
189
|
-
.trim();
|
|
190
|
-
return decodeHtmlEntities(stripped);
|
|
207
|
+
const cleaned = html.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
208
|
+
return turndown.turndown(cleaned).trim();
|
|
191
209
|
}
|
|
192
210
|
|
|
193
211
|
/**
|
|
@@ -90,6 +90,10 @@ interface CodexResponse {
|
|
|
90
90
|
usage?: CodexUsage;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
function isImagePlaceholderAnswer(text: string): boolean {
|
|
94
|
+
return text.trim().toLowerCase() === "(see attached image)";
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
/**
|
|
94
98
|
* Decodes a JWT token and extracts the payload.
|
|
95
99
|
* @param token - JWT token string
|
|
@@ -232,6 +236,7 @@ async function callCodexSearch(
|
|
|
232
236
|
|
|
233
237
|
// Parse SSE stream
|
|
234
238
|
const answerParts: string[] = [];
|
|
239
|
+
const streamedAnswerParts: string[] = [];
|
|
235
240
|
const sources: SearchSource[] = [];
|
|
236
241
|
let model = requestedModel;
|
|
237
242
|
let requestId = "";
|
|
@@ -241,7 +246,12 @@ async function callCodexSearch(
|
|
|
241
246
|
const eventType = typeof rawEvent.type === "string" ? rawEvent.type : "";
|
|
242
247
|
if (!eventType) continue;
|
|
243
248
|
|
|
244
|
-
if (eventType === "response.
|
|
249
|
+
if (eventType === "response.output_text.delta") {
|
|
250
|
+
const delta = typeof rawEvent.delta === "string" ? rawEvent.delta : "";
|
|
251
|
+
if (delta) {
|
|
252
|
+
streamedAnswerParts.push(delta);
|
|
253
|
+
}
|
|
254
|
+
} else if (eventType === "response.output_item.done") {
|
|
245
255
|
const item = rawEvent.item as CodexResponseItem | undefined;
|
|
246
256
|
if (!item) continue;
|
|
247
257
|
|
|
@@ -302,8 +312,17 @@ async function callCodexSearch(
|
|
|
302
312
|
}
|
|
303
313
|
}
|
|
304
314
|
|
|
315
|
+
const finalAnswer = answerParts.join("\n\n").trim();
|
|
316
|
+
const streamedAnswer = streamedAnswerParts.join("").trim();
|
|
317
|
+
const answer =
|
|
318
|
+
finalAnswer.length > 0 && !isImagePlaceholderAnswer(finalAnswer)
|
|
319
|
+
? finalAnswer
|
|
320
|
+
: streamedAnswer.length > 0
|
|
321
|
+
? streamedAnswer
|
|
322
|
+
: finalAnswer;
|
|
323
|
+
|
|
305
324
|
return {
|
|
306
|
-
answer
|
|
325
|
+
answer,
|
|
307
326
|
sources,
|
|
308
327
|
model,
|
|
309
328
|
requestId,
|