@proposit/proposit-core 1.11.0 → 2.0.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/README.md +1 -1
- package/dist/cli/commands/expressions.d.ts +29 -0
- package/dist/cli/commands/expressions.d.ts.map +1 -1
- package/dist/cli/commands/expressions.js +118 -92
- package/dist/cli/commands/expressions.js.map +1 -1
- package/dist/extensions/argument-ingestion/shared/finalize-response-v2.d.ts.map +1 -1
- package/dist/extensions/argument-ingestion/shared/finalize-response-v2.js +18 -2
- package/dist/extensions/argument-ingestion/shared/finalize-response-v2.js.map +1 -1
- package/dist/extensions/{ieee → citations/ieee}/citation-claim.d.ts +53 -59
- package/dist/extensions/{ieee → citations/ieee}/citation-claim.d.ts.map +1 -1
- package/dist/extensions/{ieee → citations/ieee}/citation-claim.js +2 -2
- package/dist/extensions/citations/ieee/citation-claim.js.map +1 -0
- package/dist/extensions/citations/ieee/formatting.d.ts.map +1 -0
- package/dist/extensions/{ieee → citations/ieee}/formatting.js +0 -1
- package/dist/extensions/citations/ieee/formatting.js.map +1 -0
- package/dist/extensions/citations/ieee/index.d.ts.map +1 -0
- package/dist/extensions/citations/ieee/index.js.map +1 -0
- package/dist/extensions/{ieee → citations/ieee}/references.d.ts +161 -181
- package/dist/extensions/citations/ieee/references.d.ts.map +1 -0
- package/dist/extensions/{ieee → citations/ieee}/references.js +48 -22
- package/dist/extensions/citations/ieee/references.js.map +1 -0
- package/dist/extensions/{ieee → citations/ieee}/relaxed.d.ts +159 -180
- package/dist/extensions/citations/ieee/relaxed.d.ts.map +1 -0
- package/dist/extensions/{ieee → citations/ieee}/relaxed.js +1 -4
- package/dist/extensions/{ieee → citations/ieee}/relaxed.js.map +1 -1
- package/dist/extensions/citations/ieee/segment-builder.d.ts.map +1 -0
- package/dist/extensions/citations/ieee/segment-builder.js.map +1 -0
- package/dist/extensions/{ieee → citations/ieee}/segment-templates.d.ts +0 -1
- package/dist/extensions/citations/ieee/segment-templates.d.ts.map +1 -0
- package/dist/extensions/{ieee → citations/ieee}/segment-templates.js +0 -27
- package/dist/extensions/citations/ieee/segment-templates.js.map +1 -0
- package/dist/extensions/citations/unparsed/index.d.ts +2 -0
- package/dist/extensions/citations/unparsed/index.d.ts.map +1 -0
- package/dist/extensions/citations/unparsed/index.js +2 -0
- package/dist/extensions/citations/unparsed/index.js.map +1 -0
- package/dist/extensions/citations/unparsed/unparsed-citation.d.ts +11 -0
- package/dist/extensions/citations/unparsed/unparsed-citation.d.ts.map +1 -0
- package/dist/extensions/citations/unparsed/unparsed-citation.js +22 -0
- package/dist/extensions/citations/unparsed/unparsed-citation.js.map +1 -0
- package/dist/extensions/openai/errors.d.ts +8 -0
- package/dist/extensions/openai/errors.d.ts.map +1 -1
- package/dist/extensions/openai/errors.js +58 -0
- package/dist/extensions/openai/errors.js.map +1 -1
- package/dist/extensions/openai/index.d.ts +4 -2
- package/dist/extensions/openai/index.d.ts.map +1 -1
- package/dist/extensions/openai/index.js +2 -1
- package/dist/extensions/openai/index.js.map +1 -1
- package/dist/extensions/openai/openai-http.d.ts +30 -0
- package/dist/extensions/openai/openai-http.d.ts.map +1 -0
- package/dist/extensions/openai/openai-http.js +310 -0
- package/dist/extensions/openai/openai-http.js.map +1 -0
- package/dist/extensions/openai/openai-parsing.d.ts +34 -0
- package/dist/extensions/openai/openai-parsing.d.ts.map +1 -0
- package/dist/extensions/openai/openai-parsing.js +226 -0
- package/dist/extensions/openai/openai-parsing.js.map +1 -0
- package/dist/extensions/openai/openai-retrieval.d.ts +150 -0
- package/dist/extensions/openai/openai-retrieval.d.ts.map +1 -0
- package/dist/extensions/openai/openai-retrieval.js +248 -0
- package/dist/extensions/openai/openai-retrieval.js.map +1 -0
- package/dist/extensions/openai/openai-tools.d.ts +9 -0
- package/dist/extensions/openai/openai-tools.d.ts.map +1 -0
- package/dist/extensions/openai/openai-tools.js +93 -0
- package/dist/extensions/openai/openai-tools.js.map +1 -0
- package/dist/extensions/openai/provider.d.ts +2 -149
- package/dist/extensions/openai/provider.d.ts.map +1 -1
- package/dist/extensions/openai/provider.js +5 -886
- package/dist/extensions/openai/provider.js.map +1 -1
- package/dist/extensions/openai/types.d.ts +1 -0
- package/dist/extensions/openai/types.d.ts.map +1 -1
- package/dist/extensions/openai/types.js +4 -1
- package/dist/extensions/openai/types.js.map +1 -1
- package/dist/lib/core/premise-engine.d.ts +15 -0
- package/dist/lib/core/premise-engine.d.ts.map +1 -1
- package/dist/lib/core/premise-engine.js +62 -127
- package/dist/lib/core/premise-engine.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/parsing/prompt-builder.d.ts.map +1 -1
- package/dist/lib/parsing/prompt-builder.js +14 -3
- package/dist/lib/parsing/prompt-builder.js.map +1 -1
- package/dist/lib/pipelines/index.d.ts +1 -1
- package/dist/lib/pipelines/index.d.ts.map +1 -1
- package/dist/lib/pipelines/index.js +1 -1
- package/dist/lib/pipelines/index.js.map +1 -1
- package/dist/lib/pipelines/stage-helpers.d.ts +9 -0
- package/dist/lib/pipelines/stage-helpers.d.ts.map +1 -1
- package/dist/lib/pipelines/stage-helpers.js +11 -0
- package/dist/lib/pipelines/stage-helpers.js.map +1 -1
- package/package.json +10 -5
- package/dist/extensions/ieee/citation-claim.js.map +0 -1
- package/dist/extensions/ieee/formatting.d.ts.map +0 -1
- package/dist/extensions/ieee/formatting.js.map +0 -1
- package/dist/extensions/ieee/index.d.ts.map +0 -1
- package/dist/extensions/ieee/index.js.map +0 -1
- package/dist/extensions/ieee/references.d.ts.map +0 -1
- package/dist/extensions/ieee/references.js.map +0 -1
- package/dist/extensions/ieee/relaxed.d.ts.map +0 -1
- package/dist/extensions/ieee/segment-builder.d.ts.map +0 -1
- package/dist/extensions/ieee/segment-builder.js.map +0 -1
- package/dist/extensions/ieee/segment-templates.d.ts.map +0 -1
- package/dist/extensions/ieee/segment-templates.js.map +0 -1
- /package/dist/extensions/{ieee → citations/ieee}/formatting.d.ts +0 -0
- /package/dist/extensions/{ieee → citations/ieee}/index.d.ts +0 -0
- /package/dist/extensions/{ieee → citations/ieee}/index.js +0 -0
- /package/dist/extensions/{ieee → citations/ieee}/segment-builder.d.ts +0 -0
- /package/dist/extensions/{ieee → citations/ieee}/segment-builder.js +0 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
// HTTP transport for the OpenAI Responses API: the single-call POST,
|
|
2
|
+
// the foreground/background dispatch, the submit-then-poll background
|
|
3
|
+
// loop, and the background-stream create. These functions own the wire
|
|
4
|
+
// interaction (fetch, headers, abort handling, status classification);
|
|
5
|
+
// they return the parsed `TOpenAiResponsesEnvelope` and leave the
|
|
6
|
+
// retrieval-shaped projection to the layer above.
|
|
7
|
+
//
|
|
8
|
+
// Layering: this module sits above `openai-parsing.ts` (it consumes
|
|
9
|
+
// `readSseEnvelope` / `isAbortError`) and `errors.ts` (error classes +
|
|
10
|
+
// `classifyHttpError`); nothing here imports from `provider.ts` or
|
|
11
|
+
// `openai-retrieval.ts`, keeping the dependency graph acyclic.
|
|
12
|
+
import { isAbortError, readSseEnvelope } from "./openai-parsing.js";
|
|
13
|
+
import { classifyHttpError, ResponseNotFoundError, TransientLlmError, } from "./errors.js";
|
|
14
|
+
export function resolveFetch(injected, fnName) {
|
|
15
|
+
const fetchImpl = injected ?? globalThis.fetch;
|
|
16
|
+
if (!fetchImpl) {
|
|
17
|
+
throw new Error(`${fnName}: no fetch implementation available. Pass \`fetch\` explicitly or run in an environment that provides \`globalThis.fetch\` (Node ≥18, modern browsers, Expo).`);
|
|
18
|
+
}
|
|
19
|
+
return fetchImpl;
|
|
20
|
+
}
|
|
21
|
+
// -- HTTP --
|
|
22
|
+
export async function fetchResponseEnvelope(args) {
|
|
23
|
+
if (args.backgroundStream) {
|
|
24
|
+
return runBackgroundStream({
|
|
25
|
+
url: args.url,
|
|
26
|
+
apiKey: args.apiKey,
|
|
27
|
+
body: args.body,
|
|
28
|
+
fetchImpl: args.fetchImpl,
|
|
29
|
+
signal: args.signal,
|
|
30
|
+
onResponseId: args.onResponseId,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (args.background) {
|
|
34
|
+
return runBackground({
|
|
35
|
+
url: args.url,
|
|
36
|
+
apiKey: args.apiKey,
|
|
37
|
+
body: args.body,
|
|
38
|
+
fetchImpl: args.fetchImpl,
|
|
39
|
+
signal: args.signal,
|
|
40
|
+
pollIntervalMs: args.pollIntervalMs,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (args.stream) {
|
|
44
|
+
const response = await callOnce({
|
|
45
|
+
url: args.url,
|
|
46
|
+
apiKey: args.apiKey,
|
|
47
|
+
body: { ...args.body, stream: true },
|
|
48
|
+
fetchImpl: args.fetchImpl,
|
|
49
|
+
signal: args.signal,
|
|
50
|
+
});
|
|
51
|
+
return readSseEnvelope(response);
|
|
52
|
+
}
|
|
53
|
+
const response = await callOnce({
|
|
54
|
+
url: args.url,
|
|
55
|
+
apiKey: args.apiKey,
|
|
56
|
+
body: args.body,
|
|
57
|
+
fetchImpl: args.fetchImpl,
|
|
58
|
+
signal: args.signal,
|
|
59
|
+
});
|
|
60
|
+
return parseJsonOrThrowTransient(response, "OpenAI response body was not valid JSON");
|
|
61
|
+
}
|
|
62
|
+
export async function parseJsonOrThrowTransient(response, context) {
|
|
63
|
+
return response
|
|
64
|
+
.json()
|
|
65
|
+
.then((j) => j)
|
|
66
|
+
.catch((err) => {
|
|
67
|
+
throw new TransientLlmError({
|
|
68
|
+
message: `${context}: ${err instanceof Error ? err.message : String(err)}`,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function abortError() {
|
|
73
|
+
const e = new Error("The OpenAI background request was aborted.");
|
|
74
|
+
e.name = "AbortError";
|
|
75
|
+
return e;
|
|
76
|
+
}
|
|
77
|
+
// Resolves (never rejects) on abort by design: the poll loop owns the
|
|
78
|
+
// abort→cancel→throw decision at exactly two checkpoints (top-of-loop and
|
|
79
|
+
// the in-flight-GET catch), so this helper just needs to wake the loop
|
|
80
|
+
// promptly instead of waiting out the full interval. Keeping it
|
|
81
|
+
// non-throwing avoids a second, competing abort surface.
|
|
82
|
+
function abortableDelay(ms, signal) {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
if (signal?.aborted) {
|
|
85
|
+
resolve();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const onAbort = () => {
|
|
89
|
+
cleanup();
|
|
90
|
+
resolve();
|
|
91
|
+
};
|
|
92
|
+
const cleanup = () => {
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
signal?.removeEventListener("abort", onAbort);
|
|
95
|
+
};
|
|
96
|
+
const timer = setTimeout(() => {
|
|
97
|
+
cleanup();
|
|
98
|
+
resolve();
|
|
99
|
+
}, ms);
|
|
100
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export async function getResponseById(args) {
|
|
104
|
+
let response;
|
|
105
|
+
try {
|
|
106
|
+
response = await args.fetchImpl(`${args.url}/${args.id}`, {
|
|
107
|
+
method: "GET",
|
|
108
|
+
headers: { Authorization: `Bearer ${args.apiKey}` },
|
|
109
|
+
signal: args.signal,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (isAbortError(err))
|
|
114
|
+
throw err;
|
|
115
|
+
throw new TransientLlmError({
|
|
116
|
+
message: `Network error polling OpenAI background response: ${err instanceof Error ? err.message : String(err)}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (response.status === 404) {
|
|
120
|
+
// Response has aged out of the ~10-minute retention window or
|
|
121
|
+
// was never stored. Surface as a typed error so callers can
|
|
122
|
+
// clear the stored id and settle the stage as failed.
|
|
123
|
+
throw new ResponseNotFoundError({ responseId: args.id });
|
|
124
|
+
}
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
const errorBody = await response.text().catch(() => "");
|
|
127
|
+
throw classifyHttpError(response.status, `OpenAI poll ${response.status.toString()}: ${errorBody || response.statusText}`);
|
|
128
|
+
}
|
|
129
|
+
return parseJsonOrThrowTransient(response, "OpenAI poll body was not valid JSON");
|
|
130
|
+
}
|
|
131
|
+
// Intentionally takes no AbortSignal — cancel must fire even though the
|
|
132
|
+
// caller's signal has already aborted; passing the fired signal would
|
|
133
|
+
// abort the cancel itself.
|
|
134
|
+
async function cancelBackground(args) {
|
|
135
|
+
// Best-effort + idempotent — swallow errors; the abort is surfaced
|
|
136
|
+
// regardless of whether cancel succeeds.
|
|
137
|
+
try {
|
|
138
|
+
await args.fetchImpl(`${args.url}/${args.id}/cancel`, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: { Authorization: `Bearer ${args.apiKey}` },
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// ignore
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function isTerminalBackgroundStatus(status) {
|
|
148
|
+
return (status === "completed" ||
|
|
149
|
+
status === "failed" ||
|
|
150
|
+
status === "incomplete" ||
|
|
151
|
+
status === "cancelled");
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Submit a single request with `{ background: true, stream: true,
|
|
155
|
+
* store: true }` and consume the resulting SSE stream live, returning
|
|
156
|
+
* the terminal envelope.
|
|
157
|
+
*
|
|
158
|
+
* A background response can only be streamed if it was *created* with
|
|
159
|
+
* `stream: true` (a background-without-stream response is poll-only and
|
|
160
|
+
* cannot later be streamed), so this mode uses one streaming create
|
|
161
|
+
* call rather than a separate non-streaming submit POST. The response
|
|
162
|
+
* id is therefore not in a JSON POST body — it arrives in the first
|
|
163
|
+
* `response.created` SSE event. `onResponseId` fires the moment that
|
|
164
|
+
* event is parsed (before the terminal event), so the caller can
|
|
165
|
+
* persist the id while the call is still in flight.
|
|
166
|
+
*
|
|
167
|
+
* The response keeps generating server-side even if the connection
|
|
168
|
+
* drops during stream consumption, and can be recovered via
|
|
169
|
+
* `retrieveResponse` within the ~10-minute retention window. A
|
|
170
|
+
* connection drop mid-stream (no terminal event before stream end) is
|
|
171
|
+
* classified as a `TransientLlmError` so the framework's retry policy
|
|
172
|
+
* applies — but because the id was already surfaced mid-flight, a
|
|
173
|
+
* crashed in-flight call can be recovered rather than blindly re-run.
|
|
174
|
+
*/
|
|
175
|
+
async function runBackgroundStream(args) {
|
|
176
|
+
if (args.signal?.aborted)
|
|
177
|
+
throw abortError();
|
|
178
|
+
const httpResponse = await callOnce({
|
|
179
|
+
url: args.url,
|
|
180
|
+
apiKey: args.apiKey,
|
|
181
|
+
body: { ...args.body, background: true, stream: true, store: true },
|
|
182
|
+
fetchImpl: args.fetchImpl,
|
|
183
|
+
signal: args.signal,
|
|
184
|
+
});
|
|
185
|
+
return readSseEnvelope(httpResponse, args.onResponseId);
|
|
186
|
+
}
|
|
187
|
+
async function runBackground(args) {
|
|
188
|
+
if (args.signal?.aborted)
|
|
189
|
+
throw abortError();
|
|
190
|
+
const submit = await callOnce({
|
|
191
|
+
url: args.url,
|
|
192
|
+
apiKey: args.apiKey,
|
|
193
|
+
body: { ...args.body, background: true, store: true },
|
|
194
|
+
fetchImpl: args.fetchImpl,
|
|
195
|
+
signal: args.signal,
|
|
196
|
+
});
|
|
197
|
+
const submitEnvelope = await parseJsonOrThrowTransient(submit, "OpenAI background submit body was not valid JSON");
|
|
198
|
+
const id = submitEnvelope.id;
|
|
199
|
+
if (!id) {
|
|
200
|
+
throw new TransientLlmError({
|
|
201
|
+
message: "OpenAI background submit returned no response id.",
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// Fast-path: a small/cached request can come back already terminal on
|
|
205
|
+
// submit — return it directly rather than issuing a redundant poll GET
|
|
206
|
+
// (and avoid a `store`-expiry window between submit and first poll).
|
|
207
|
+
if (isTerminalBackgroundStatus(submitEnvelope.status)) {
|
|
208
|
+
if (submitEnvelope.status === "cancelled")
|
|
209
|
+
throw abortError();
|
|
210
|
+
return submitEnvelope;
|
|
211
|
+
}
|
|
212
|
+
for (;;) {
|
|
213
|
+
if (args.signal?.aborted) {
|
|
214
|
+
await cancelBackground({
|
|
215
|
+
url: args.url,
|
|
216
|
+
id,
|
|
217
|
+
apiKey: args.apiKey,
|
|
218
|
+
fetchImpl: args.fetchImpl,
|
|
219
|
+
});
|
|
220
|
+
throw abortError();
|
|
221
|
+
}
|
|
222
|
+
let env;
|
|
223
|
+
try {
|
|
224
|
+
env = await getResponseById({
|
|
225
|
+
url: args.url,
|
|
226
|
+
id,
|
|
227
|
+
apiKey: args.apiKey,
|
|
228
|
+
fetchImpl: args.fetchImpl,
|
|
229
|
+
signal: args.signal,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
// Abort landing DURING an in-flight poll GET surfaces as an
|
|
234
|
+
// AbortError from getResponseById (real fetch rejects the
|
|
235
|
+
// in-flight request). The top-of-loop check alone would miss
|
|
236
|
+
// it, so cancel here before re-throwing — this is what makes
|
|
237
|
+
// the "AbortSignal → cancel POST" guarantee hold mid-poll.
|
|
238
|
+
if (isAbortError(err)) {
|
|
239
|
+
await cancelBackground({
|
|
240
|
+
url: args.url,
|
|
241
|
+
id,
|
|
242
|
+
apiKey: args.apiKey,
|
|
243
|
+
fetchImpl: args.fetchImpl,
|
|
244
|
+
});
|
|
245
|
+
throw abortError();
|
|
246
|
+
}
|
|
247
|
+
throw err;
|
|
248
|
+
}
|
|
249
|
+
const status = env.status;
|
|
250
|
+
// Deliberately inlined rather than calling
|
|
251
|
+
// `isTerminalBackgroundStatus`: `cancelled` is terminal too but
|
|
252
|
+
// needs the opposite disposition (throw `abortError()` vs. return
|
|
253
|
+
// the envelope), so the two terminal cases are split here.
|
|
254
|
+
if (status === "completed" ||
|
|
255
|
+
status === "failed" ||
|
|
256
|
+
status === "incomplete") {
|
|
257
|
+
return env;
|
|
258
|
+
}
|
|
259
|
+
if (status === "cancelled") {
|
|
260
|
+
throw abortError();
|
|
261
|
+
}
|
|
262
|
+
await abortableDelay(args.pollIntervalMs, args.signal);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
export async function callOnce(args) {
|
|
266
|
+
let response;
|
|
267
|
+
try {
|
|
268
|
+
response = await args.fetchImpl(args.url, {
|
|
269
|
+
method: "POST",
|
|
270
|
+
headers: {
|
|
271
|
+
"Content-Type": "application/json",
|
|
272
|
+
Authorization: `Bearer ${args.apiKey}`,
|
|
273
|
+
},
|
|
274
|
+
body: JSON.stringify(args.body),
|
|
275
|
+
signal: args.signal,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
// Aborts come through as a thrown error with `name === "AbortError"`
|
|
280
|
+
// (DOM spec). Surface as-is so `llmStage`'s mid-flight-abort
|
|
281
|
+
// detector turns it into `StageAbortedError`. Other low-level
|
|
282
|
+
// fetch failures are transient.
|
|
283
|
+
if (isAbortError(err)) {
|
|
284
|
+
throw err;
|
|
285
|
+
}
|
|
286
|
+
throw new TransientLlmError({
|
|
287
|
+
message: `Network error calling OpenAI: ${err instanceof Error ? err.message : String(err)}`,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
if (response.ok) {
|
|
291
|
+
return response;
|
|
292
|
+
}
|
|
293
|
+
const errorBody = await response.text().catch(() => "");
|
|
294
|
+
const message = `OpenAI Responses API ${response.status.toString()}: ${errorBody || response.statusText}`;
|
|
295
|
+
// Best-effort structured extraction of the provider error
|
|
296
|
+
// code/type so a 429 can be split into persistent quota exhaustion
|
|
297
|
+
// vs. transient throttling. Never throws on malformed bodies — an
|
|
298
|
+
// unparseable body leaves `providerErrorCode` undefined, which
|
|
299
|
+
// `classifyHttpError` treats as the safe transient default.
|
|
300
|
+
let providerErrorCode;
|
|
301
|
+
try {
|
|
302
|
+
const parsed = JSON.parse(errorBody);
|
|
303
|
+
providerErrorCode = parsed.error?.code ?? parsed.error?.type;
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
providerErrorCode = undefined;
|
|
307
|
+
}
|
|
308
|
+
throw classifyHttpError(response.status, message, providerErrorCode);
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=openai-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-http.js","sourceRoot":"","sources":["../../../src/extensions/openai/openai-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TLlmTokenUsage } from "../../lib/llm/types.js";
|
|
2
|
+
import type { TOpenAiOutputItem, TOpenAiResponsesEnvelope } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read an SSE `text/event-stream` body and return the envelope carried
|
|
5
|
+
* by the terminal event. A stream that ends with no terminal event
|
|
6
|
+
* (connection drop) throws `TransientLlmError` so the framework retries.
|
|
7
|
+
* `AbortError` from the underlying reader propagates verbatim so
|
|
8
|
+
* `llmStage` marks the stage `skipped`.
|
|
9
|
+
*
|
|
10
|
+
* `onResponseId`, when supplied, fires the moment the `response.created`
|
|
11
|
+
* lifecycle event is parsed — i.e. while the call is still streaming,
|
|
12
|
+
* before the terminal event arrives. This is the load-bearing seam for
|
|
13
|
+
* background-stream mode: it lets a caller persist the response id
|
|
14
|
+
* mid-flight so an in-flight call interrupted before completion can be
|
|
15
|
+
* recovered from the upstream's stored copy. Invoked at most once.
|
|
16
|
+
*
|
|
17
|
+
* Note: the event-separator scan assumes LF (`\n\n`) framing, which the
|
|
18
|
+
* OpenAI Responses API emits. Reuse against a strict CRLF-only SSE
|
|
19
|
+
* server would need the separator scan adjusted to `\r\n\r\n`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readSseEnvelope(response: Response, onResponseId?: (responseId: string) => void): Promise<TOpenAiResponsesEnvelope>;
|
|
22
|
+
type TParsedFunctionCall = {
|
|
23
|
+
callId: string;
|
|
24
|
+
name: string;
|
|
25
|
+
arguments: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function pickFunctionCalls(output: TOpenAiOutputItem[] | undefined): TParsedFunctionCall[];
|
|
28
|
+
export declare function extractAssistantText(output: TOpenAiOutputItem[] | undefined): string | undefined;
|
|
29
|
+
export declare function safeParseJson(raw: string): unknown;
|
|
30
|
+
export declare function extractUsage(envelope: TOpenAiResponsesEnvelope): TLlmTokenUsage;
|
|
31
|
+
export declare function mergeUsage(accumulated: TLlmTokenUsage, next: TLlmTokenUsage): TLlmTokenUsage;
|
|
32
|
+
export declare function isAbortError(err: unknown): boolean;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=openai-parsing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-parsing.d.ts","sourceRoot":"","sources":["../../../src/extensions/openai/openai-parsing.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAoE7E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CACjC,QAAQ,EAAE,QAAQ,EAClB,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,GAC5C,OAAO,CAAC,wBAAwB,CAAC,CAkEnC;AAED,KAAK,mBAAmB,GAAG;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,iBAAiB,EAAE,GAAG,SAAS,GACxC,mBAAmB,EAAE,CAoBvB;AAED,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,iBAAiB,EAAE,GAAG,SAAS,GACxC,MAAM,GAAG,SAAS,CAiBpB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUlD;AAED,wBAAgB,YAAY,CACxB,QAAQ,EAAE,wBAAwB,GACnC,cAAc,CAYhB;AAED,wBAAgB,UAAU,CACtB,WAAW,EAAE,cAAc,EAC3B,IAAI,EAAE,cAAc,GACrB,cAAc,CAShB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAMlD"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// SSE stream reading and Responses-API envelope/output parsing for the
|
|
2
|
+
// OpenAI provider. These are pure, transport-agnostic helpers: given an
|
|
3
|
+
// HTTP `Response` (for streaming) or a parsed envelope, they extract the
|
|
4
|
+
// terminal envelope, assistant text, function calls, and token usage.
|
|
5
|
+
//
|
|
6
|
+
// `isAbortError` lives here as the lowest-level shared abort predicate —
|
|
7
|
+
// `readSseEnvelope` needs it, and the HTTP and retrieval layers (which
|
|
8
|
+
// sit above this module) import it down.
|
|
9
|
+
import { SchemaValidationLlmError, TransientLlmError } from "./errors.js";
|
|
10
|
+
const SSE_TERMINAL_EVENTS = new Set([
|
|
11
|
+
"response.completed",
|
|
12
|
+
"response.incomplete",
|
|
13
|
+
"response.failed",
|
|
14
|
+
]);
|
|
15
|
+
// The lifecycle event the Responses API emits first, before any output
|
|
16
|
+
// chunks. It carries the response object — including `.id` — so a
|
|
17
|
+
// streaming consumer learns the id while the call is still in flight.
|
|
18
|
+
const SSE_CREATED_EVENT = "response.created";
|
|
19
|
+
/**
|
|
20
|
+
* Parse one SSE event block. Returns:
|
|
21
|
+
*
|
|
22
|
+
* * `{ kind: "terminal", envelope }` for a terminal Responses-API
|
|
23
|
+
* event (`response.completed` / `.incomplete` / `.failed`),
|
|
24
|
+
* carrying the embedded full `response` envelope;
|
|
25
|
+
* * `{ kind: "created", responseId }` for the lifecycle
|
|
26
|
+
* `response.created` event, surfacing the response id the moment
|
|
27
|
+
* it is known (before any output);
|
|
28
|
+
* * `undefined` for every intermediate / unrecognized event.
|
|
29
|
+
*
|
|
30
|
+
* The events carry a `type` field inside the data JSON, so we key off
|
|
31
|
+
* that and fall back to the SSE `event:` line.
|
|
32
|
+
*/
|
|
33
|
+
function parseSseEvent(raw) {
|
|
34
|
+
let eventType;
|
|
35
|
+
const dataLines = [];
|
|
36
|
+
for (const line of raw.split("\n")) {
|
|
37
|
+
if (line.startsWith(":"))
|
|
38
|
+
continue; // SSE comment line — ignore.
|
|
39
|
+
if (line.startsWith("event:")) {
|
|
40
|
+
eventType = line.slice(6).trim();
|
|
41
|
+
}
|
|
42
|
+
else if (line.startsWith("data:")) {
|
|
43
|
+
dataLines.push(line.slice(5).replace(/^ /, ""));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (dataLines.length === 0)
|
|
47
|
+
return undefined;
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(dataLines.join("\n"));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
// Prefer the discriminator inside the data JSON (Responses-API
|
|
56
|
+
// events carry `type` there); fall back to the SSE `event:` line so
|
|
57
|
+
// the parser is robust if the API ever sends the type only there.
|
|
58
|
+
// (No `[DONE]` sentinel handling — that is a Chat-Completions frame
|
|
59
|
+
// the Responses API does not emit.)
|
|
60
|
+
const type = parsed.type ?? eventType;
|
|
61
|
+
if (type && SSE_TERMINAL_EVENTS.has(type) && parsed.response) {
|
|
62
|
+
return { kind: "terminal", envelope: parsed.response };
|
|
63
|
+
}
|
|
64
|
+
if (type === SSE_CREATED_EVENT && parsed.response?.id) {
|
|
65
|
+
return { kind: "created", responseId: parsed.response.id };
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read an SSE `text/event-stream` body and return the envelope carried
|
|
71
|
+
* by the terminal event. A stream that ends with no terminal event
|
|
72
|
+
* (connection drop) throws `TransientLlmError` so the framework retries.
|
|
73
|
+
* `AbortError` from the underlying reader propagates verbatim so
|
|
74
|
+
* `llmStage` marks the stage `skipped`.
|
|
75
|
+
*
|
|
76
|
+
* `onResponseId`, when supplied, fires the moment the `response.created`
|
|
77
|
+
* lifecycle event is parsed — i.e. while the call is still streaming,
|
|
78
|
+
* before the terminal event arrives. This is the load-bearing seam for
|
|
79
|
+
* background-stream mode: it lets a caller persist the response id
|
|
80
|
+
* mid-flight so an in-flight call interrupted before completion can be
|
|
81
|
+
* recovered from the upstream's stored copy. Invoked at most once.
|
|
82
|
+
*
|
|
83
|
+
* Note: the event-separator scan assumes LF (`\n\n`) framing, which the
|
|
84
|
+
* OpenAI Responses API emits. Reuse against a strict CRLF-only SSE
|
|
85
|
+
* server would need the separator scan adjusted to `\r\n\r\n`.
|
|
86
|
+
*/
|
|
87
|
+
export async function readSseEnvelope(response, onResponseId) {
|
|
88
|
+
const body = response.body;
|
|
89
|
+
if (!body) {
|
|
90
|
+
throw new TransientLlmError({
|
|
91
|
+
message: "OpenAI streaming response carried no body.",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const reader = body.getReader();
|
|
95
|
+
const decoder = new TextDecoder();
|
|
96
|
+
let buffer = "";
|
|
97
|
+
let terminal;
|
|
98
|
+
let idSurfaced = false;
|
|
99
|
+
const handleEvent = (rawEvent) => {
|
|
100
|
+
const parsedEvent = parseSseEvent(rawEvent);
|
|
101
|
+
if (!parsedEvent)
|
|
102
|
+
return;
|
|
103
|
+
if (parsedEvent.kind === "terminal") {
|
|
104
|
+
terminal = parsedEvent.envelope;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// kind === "created": surface the id once, the moment it's known.
|
|
108
|
+
if (!idSurfaced) {
|
|
109
|
+
idSurfaced = true;
|
|
110
|
+
onResponseId?.(parsedEvent.responseId);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
try {
|
|
114
|
+
for (;;) {
|
|
115
|
+
const chunk = await reader.read();
|
|
116
|
+
if (chunk.done)
|
|
117
|
+
break;
|
|
118
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
119
|
+
let sep = buffer.indexOf("\n\n");
|
|
120
|
+
while (sep !== -1) {
|
|
121
|
+
const rawEvent = buffer.slice(0, sep);
|
|
122
|
+
buffer = buffer.slice(sep + 2);
|
|
123
|
+
handleEvent(rawEvent);
|
|
124
|
+
sep = buffer.indexOf("\n\n");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
if (isAbortError(err)) {
|
|
130
|
+
throw err;
|
|
131
|
+
}
|
|
132
|
+
throw new TransientLlmError({
|
|
133
|
+
message: `OpenAI streaming read failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Flush any bytes the streaming decoder is still holding (an
|
|
137
|
+
// incomplete multi-byte UTF-8 sequence at the final chunk boundary),
|
|
138
|
+
// then scan for any remaining terminal frame.
|
|
139
|
+
buffer += decoder.decode();
|
|
140
|
+
let tailSep = buffer.indexOf("\n\n");
|
|
141
|
+
while (tailSep !== -1) {
|
|
142
|
+
const rawEvent = buffer.slice(0, tailSep);
|
|
143
|
+
buffer = buffer.slice(tailSep + 2);
|
|
144
|
+
handleEvent(rawEvent);
|
|
145
|
+
tailSep = buffer.indexOf("\n\n");
|
|
146
|
+
}
|
|
147
|
+
if (!terminal) {
|
|
148
|
+
throw new TransientLlmError({
|
|
149
|
+
message: "OpenAI streaming ended without a terminal response event (connection drop?).",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return terminal;
|
|
153
|
+
}
|
|
154
|
+
export function pickFunctionCalls(output) {
|
|
155
|
+
if (!output)
|
|
156
|
+
return [];
|
|
157
|
+
const calls = [];
|
|
158
|
+
for (const item of output) {
|
|
159
|
+
if (item.type === "function_call") {
|
|
160
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
161
|
+
const fc = item;
|
|
162
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
163
|
+
calls.push({
|
|
164
|
+
callId: fc.call_id,
|
|
165
|
+
name: fc.name,
|
|
166
|
+
arguments: fc.arguments,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return calls;
|
|
171
|
+
}
|
|
172
|
+
export function extractAssistantText(output) {
|
|
173
|
+
if (!output)
|
|
174
|
+
return undefined;
|
|
175
|
+
for (const item of output) {
|
|
176
|
+
if (item.type === "message") {
|
|
177
|
+
const msg = item;
|
|
178
|
+
const blocks = msg.content ?? [];
|
|
179
|
+
const textBlock = blocks.find((b) => b.type === "output_text" || b.type === "text");
|
|
180
|
+
if (textBlock?.text !== undefined) {
|
|
181
|
+
return textBlock.text;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
export function safeParseJson(raw) {
|
|
188
|
+
try {
|
|
189
|
+
return JSON.parse(raw);
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
throw new SchemaValidationLlmError({
|
|
193
|
+
message: `OpenAI returned malformed JSON in structured-output text: ${err instanceof Error ? err.message : String(err)}`,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
export function extractUsage(envelope) {
|
|
198
|
+
const usage = envelope.usage;
|
|
199
|
+
if (!usage)
|
|
200
|
+
return { input: 0, output: 0 };
|
|
201
|
+
const result = {
|
|
202
|
+
input: usage.input_tokens ?? 0,
|
|
203
|
+
output: usage.output_tokens ?? 0,
|
|
204
|
+
};
|
|
205
|
+
const reasoning = usage.output_tokens_details?.reasoning_tokens;
|
|
206
|
+
if (reasoning !== undefined) {
|
|
207
|
+
result.reasoning = reasoning;
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
export function mergeUsage(accumulated, next) {
|
|
212
|
+
const merged = {
|
|
213
|
+
input: accumulated.input + next.input,
|
|
214
|
+
output: accumulated.output + next.output,
|
|
215
|
+
};
|
|
216
|
+
if (accumulated.reasoning !== undefined || next.reasoning !== undefined) {
|
|
217
|
+
merged.reasoning = (accumulated.reasoning ?? 0) + (next.reasoning ?? 0);
|
|
218
|
+
}
|
|
219
|
+
return merged;
|
|
220
|
+
}
|
|
221
|
+
export function isAbortError(err) {
|
|
222
|
+
return (typeof err === "object" &&
|
|
223
|
+
err !== null &&
|
|
224
|
+
err.name === "AbortError");
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=openai-parsing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-parsing.js","sourceRoot":"","sources":["../../../src/extensions/openai/openai-parsing.ts"],"names":[],"mappings":"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"}
|