@ai0x0/codex-ts 0.9.0 → 0.9.1

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.
@@ -1,6 +1,26 @@
1
1
  /**
2
2
  * SSE stream parser for the OpenAI Responses API.
3
3
  * Extracted from turn.ts so compact.ts can share it.
4
+ *
5
+ * mirrors codex-rs: codex-api/src/sse/responses.rs reads the body through the
6
+ * `eventsource-stream` crate (`stream.eventsource()`), which follows the SSE spec
7
+ * (https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation).
8
+ * This port used to match only `data: ` (with the space) and to reset its data
9
+ * buffer on every network read, so it silently dropped:
10
+ * · every event of an upstream that writes `data:{…}` — legal SSE; a DeepSeek
11
+ * gateway behind Aihubmix switched to it on 2026-10-03 and whole turns came
12
+ * back empty: no text, no tool calls, no error;
13
+ * · any event whose `data:` line and closing blank line arrived in two reads.
14
+ *
15
+ * The spec rules kept here:
16
+ * · a line ends in CRLF, LF or CR;
17
+ * · a blank line dispatches the event; a line starting with ":" is a comment;
18
+ * · `field:value` drops one leading space of the value; the `data` lines of one
19
+ * event are joined with "\n". The other fields (event / id / retry) are not
20
+ * needed: callers dispatch on the JSON payload's `type`.
21
+ * One deliberate leniency: data still pending when the body ends is dispatched
22
+ * (the spec discards it), so an upstream that leaves out the final blank line
23
+ * does not lose its last event — usually response.completed.
4
24
  */
5
25
  export type RawSseEvent = Record<string, unknown>;
6
26
  export declare function parseSseStream(body: ReadableStream<Uint8Array>): AsyncGenerator<RawSseEvent>;
@@ -1 +1 @@
1
- {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../../core/src/session/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,wBAAuB,cAAc,CACnC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAC/B,cAAc,CAAC,WAAW,CAAC,CA8B7B"}
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../../core/src/session/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAsClD,wBAAuB,cAAc,CACnC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAC/B,cAAc,CAAC,WAAW,CAAC,CAyC7B"}
@@ -1,35 +1,96 @@
1
1
  /**
2
2
  * SSE stream parser for the OpenAI Responses API.
3
3
  * Extracted from turn.ts so compact.ts can share it.
4
+ *
5
+ * mirrors codex-rs: codex-api/src/sse/responses.rs reads the body through the
6
+ * `eventsource-stream` crate (`stream.eventsource()`), which follows the SSE spec
7
+ * (https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation).
8
+ * This port used to match only `data: ` (with the space) and to reset its data
9
+ * buffer on every network read, so it silently dropped:
10
+ * · every event of an upstream that writes `data:{…}` — legal SSE; a DeepSeek
11
+ * gateway behind Aihubmix switched to it on 2026-10-03 and whole turns came
12
+ * back empty: no text, no tool calls, no error;
13
+ * · any event whose `data:` line and closing blank line arrived in two reads.
14
+ *
15
+ * The spec rules kept here:
16
+ * · a line ends in CRLF, LF or CR;
17
+ * · a blank line dispatches the event; a line starting with ":" is a comment;
18
+ * · `field:value` drops one leading space of the value; the `data` lines of one
19
+ * event are joined with "\n". The other fields (event / id / retry) are not
20
+ * needed: callers dispatch on the JSON payload's `type`.
21
+ * One deliberate leniency: data still pending when the body ends is dispatched
22
+ * (the spec discards it), so an upstream that leaves out the final blank line
23
+ * does not lose its last event — usually response.completed.
4
24
  */
25
+ function isRecord(value) {
26
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27
+ }
28
+ /** The event the pending `data` lines make up (the lines are cleared either way). */
29
+ function dispatch(state) {
30
+ if (state.data.length === 0)
31
+ return undefined;
32
+ const data = state.data.join("\n");
33
+ state.data = [];
34
+ if (data === "[DONE]")
35
+ return undefined;
36
+ try {
37
+ const parsed = JSON.parse(data);
38
+ return isRecord(parsed) ? parsed : undefined;
39
+ }
40
+ catch {
41
+ /* malformed JSON — skip */
42
+ return undefined;
43
+ }
44
+ }
45
+ /** One line (without its line ending); returns the event a blank line dispatches. */
46
+ function takeLine(state, line) {
47
+ if (line === "")
48
+ return dispatch(state);
49
+ if (line.startsWith(":"))
50
+ return undefined;
51
+ const colon = line.indexOf(":");
52
+ const field = colon < 0 ? line : line.slice(0, colon);
53
+ if (field !== "data")
54
+ return undefined;
55
+ const value = colon < 0 ? "" : line.slice(colon + 1);
56
+ state.data.push(value.startsWith(" ") ? value.slice(1) : value);
57
+ return undefined;
58
+ }
5
59
  export async function* parseSseStream(body) {
6
60
  const reader = body.getReader();
7
61
  const decoder = new TextDecoder();
62
+ // Local, not module-level: two streams parsed at once must not share lastIndex.
63
+ const lineEnd = /\r\n|\n|\r/gu;
64
+ const state = { data: [] };
8
65
  let buffer = "";
9
66
  try {
10
67
  for (;;) {
11
68
  const { done, value } = await reader.read();
12
- if (done)
13
- break;
14
- buffer += decoder.decode(value, { stream: true });
15
- const lines = buffer.split("\n");
16
- buffer = lines.pop() ?? "";
17
- let dataLine = "";
18
- for (const line of lines) {
19
- if (line.startsWith("data: ")) {
20
- dataLine = line.slice(6).trim();
21
- }
22
- else if (line === "" && dataLine) {
23
- if (dataLine !== "[DONE]") {
24
- try {
25
- yield JSON.parse(dataLine);
26
- }
27
- catch {
28
- /* malformed JSON — skip */
29
- }
30
- }
31
- dataLine = "";
69
+ buffer += done
70
+ ? decoder.decode()
71
+ : decoder.decode(value, { stream: true });
72
+ let start = 0;
73
+ lineEnd.lastIndex = 0;
74
+ for (let match = lineEnd.exec(buffer); match; match = lineEnd.exec(buffer)) {
75
+ // A "\r" at the very end may be the first half of "\r\n": wait for the next read.
76
+ if (!done && match[0] === "\r" && match.index === buffer.length - 1) {
77
+ break;
32
78
  }
79
+ const event = takeLine(state, buffer.slice(start, match.index));
80
+ start = match.index + match[0].length;
81
+ if (event)
82
+ yield event;
83
+ }
84
+ buffer = buffer.slice(start);
85
+ if (done) {
86
+ // The lenient end (see the header): the last line and its event still count.
87
+ const last = buffer ? takeLine(state, buffer) : undefined;
88
+ if (last)
89
+ yield last;
90
+ const pending = dispatch(state);
91
+ if (pending)
92
+ yield pending;
93
+ break;
33
94
  }
34
95
  }
35
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../../core/src/session/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,cAAc,CACnC,IAAgC;IAEhC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YAC3B,IAAI,QAAQ,GAAG,EAAE,CAAC;YAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC9B,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClC,CAAC;qBAAM,IAAI,IAAI,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;oBACnC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;wBAC1B,IAAI,CAAC;4BACH,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAgB,CAAC;wBAC5C,CAAC;wBAAC,MAAM,CAAC;4BACP,2BAA2B;wBAC7B,CAAC;oBACH,CAAC;oBACD,QAAQ,GAAG,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../../core/src/session/sse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * mirror codex-rs: the Responses stream is parsed per the SSE spec, as the
3
+ * `eventsource-stream` crate does for codex-api/src/sse/responses.rs.
4
+ *
5
+ * Before this fix parseSseStream matched only `data: ` (with the space) and reset
6
+ * its data buffer on every network read. On 2026-10-03 a DeepSeek gateway behind
7
+ * Aihubmix started writing `id:1` / `event:…` / `:HTTP_STATUS/200` / `data:{…}` —
8
+ * legal SSE, but this port saw no events at all: the model's tool calls were never
9
+ * run, and the turn ended empty without an error.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=sse_parse.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse_parse.test.d.ts","sourceRoot":"","sources":["../../../../core/tests/suite/sse_parse.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * mirror codex-rs: the Responses stream is parsed per the SSE spec, as the
3
+ * `eventsource-stream` crate does for codex-api/src/sse/responses.rs.
4
+ *
5
+ * Before this fix parseSseStream matched only `data: ` (with the space) and reset
6
+ * its data buffer on every network read. On 2026-10-03 a DeepSeek gateway behind
7
+ * Aihubmix started writing `id:1` / `event:…` / `:HTTP_STATUS/200` / `data:{…}` —
8
+ * legal SSE, but this port saw no events at all: the model's tool calls were never
9
+ * run, and the turn ended empty without an error.
10
+ */
11
+ import { beforeEach, describe, expect, it, vi } from "vitest";
12
+ import { CodexThread } from "../../src/codex_thread.js";
13
+ import { parseSseStream } from "../../src/session/sse.js";
14
+ import { evAssistantMessage, evCompleted, evResponseCreated, makeSseResponse, sseFlat, waitForEvent, } from "../common/lib.js";
15
+ /** The stream cut into reads at these byte offsets (a cut may fall inside a line). */
16
+ function chunked(text, cuts = []) {
17
+ const bytes = new TextEncoder().encode(text);
18
+ const edges = [0, ...cuts, bytes.length];
19
+ return new ReadableStream({
20
+ start(controller) {
21
+ for (let index = 1; index < edges.length; index += 1) {
22
+ controller.enqueue(bytes.slice(edges[index - 1], edges[index]));
23
+ }
24
+ controller.close();
25
+ },
26
+ });
27
+ }
28
+ async function eventsOf(body) {
29
+ const events = [];
30
+ for await (const event of parseSseStream(body))
31
+ events.push(event);
32
+ return events;
33
+ }
34
+ /** The 2026-10-03 gateway's framing: no space after the colons, plus id / event / a comment. */
35
+ function bare(events) {
36
+ return events
37
+ .map((event, index) => `id:${index + 1}\nevent:${event.type}\n:HTTP_STATUS/200\ndata:${JSON.stringify(event)}\n\n`)
38
+ .join("");
39
+ }
40
+ const CREATED = { type: "response.created", response: { id: "r1" } };
41
+ const DELTA = { type: "response.output_text.delta", delta: "好" };
42
+ const DONE = { type: "response.completed", response: { id: "r1" } };
43
+ describe("parseSseStream", () => {
44
+ it("reads `data:` without the space, skipping id / event / comment lines", async () => {
45
+ expect(await eventsOf(chunked(bare([CREATED, DELTA, DONE])))).toEqual([
46
+ CREATED,
47
+ DELTA,
48
+ DONE,
49
+ ]);
50
+ });
51
+ it("still reads `data: ` with the space", async () => {
52
+ const text = [CREATED, DONE]
53
+ .map((event) => `data: ${JSON.stringify(event)}\n\n`)
54
+ .join("");
55
+ expect(await eventsOf(chunked(text))).toEqual([CREATED, DONE]);
56
+ });
57
+ it("keeps an event whose data line and blank line arrive in two reads", async () => {
58
+ const text = `data: ${JSON.stringify(CREATED)}\n\ndata: ${JSON.stringify(DONE)}\n\n`;
59
+ const firstEnd = text.indexOf("\n\n") + 1;
60
+ expect(await eventsOf(chunked(text, [firstEnd]))).toEqual([CREATED, DONE]);
61
+ });
62
+ it("does not lose events at any read boundary, multi-byte text included", async () => {
63
+ const text = bare([CREATED, DELTA, DONE]);
64
+ const length = new TextEncoder().encode(text).length;
65
+ for (let cut = 1; cut < length; cut += 1) {
66
+ expect(await eventsOf(chunked(text, [cut]))).toEqual([
67
+ CREATED,
68
+ DELTA,
69
+ DONE,
70
+ ]);
71
+ }
72
+ });
73
+ it("takes CRLF and CR line endings, a CRLF split across two reads included", async () => {
74
+ const crlf = bare([CREATED, DONE]).replace(/\n/g, "\r\n");
75
+ const middle = crlf.indexOf("\r\n\r\n") + 1;
76
+ expect(await eventsOf(chunked(crlf, [middle]))).toEqual([CREATED, DONE]);
77
+ const cr = bare([CREATED, DONE]).replace(/\n/g, "\r");
78
+ expect(await eventsOf(chunked(cr))).toEqual([CREATED, DONE]);
79
+ });
80
+ it("joins multi-line data with a newline", async () => {
81
+ const text = 'data: {"type":"x",\ndata: "n":1}\n\n';
82
+ expect(await eventsOf(chunked(text))).toEqual([{ type: "x", n: 1 }]);
83
+ });
84
+ it("skips [DONE] and malformed JSON", async () => {
85
+ const text = `data: {oops\n\ndata: ${JSON.stringify(DONE)}\n\ndata: [DONE]\n\n`;
86
+ expect(await eventsOf(chunked(text))).toEqual([DONE]);
87
+ });
88
+ it("keeps the last event when the body ends without the closing blank line", async () => {
89
+ const text = `data: ${JSON.stringify(CREATED)}\n\ndata:${JSON.stringify(DONE)}`;
90
+ expect(await eventsOf(chunked(text))).toEqual([CREATED, DONE]);
91
+ });
92
+ });
93
+ describe("a turn on a stream without the space after `data:`", () => {
94
+ beforeEach(() => {
95
+ vi.unstubAllGlobals();
96
+ });
97
+ it("runs the model's tool call and finishes the turn", async () => {
98
+ const commands = [];
99
+ const tool = {
100
+ name: "dotv",
101
+ spec: () => ({
102
+ type: "function",
103
+ tool: {
104
+ name: "dotv",
105
+ description: "Run a command.",
106
+ parameters: {
107
+ type: "object",
108
+ properties: { command: { type: "string" } },
109
+ required: ["command"],
110
+ additionalProperties: false,
111
+ },
112
+ strict: false,
113
+ },
114
+ }),
115
+ execute: async (args) => {
116
+ commands.push(String(args.command));
117
+ return "listed";
118
+ },
119
+ };
120
+ let rounds = 0;
121
+ const fetchMock = vi.fn().mockImplementation(async () => {
122
+ rounds += 1;
123
+ if (rounds === 1) {
124
+ return makeSseResponse(bare([
125
+ evResponseCreated("r1"),
126
+ {
127
+ type: "response.output_item.done",
128
+ item: {
129
+ type: "function_call",
130
+ id: "msg_1",
131
+ call_id: "call_1",
132
+ name: "dotv",
133
+ arguments: '{"command": "dotv canvas-node outline"}',
134
+ },
135
+ },
136
+ evCompleted("r1"),
137
+ ]));
138
+ }
139
+ return makeSseResponse(sseFlat([
140
+ evResponseCreated("r2"),
141
+ evAssistantMessage("done"),
142
+ evCompleted("r2"),
143
+ ]));
144
+ });
145
+ vi.stubGlobal("fetch", fetchMock);
146
+ const codex = new CodexThread({
147
+ apiKey: "test",
148
+ model: "deepseek-flash",
149
+ customTools: [tool],
150
+ });
151
+ await codex.submit({
152
+ type: "UserInput",
153
+ items: [{ type: "text", text: "outline the canvas" }],
154
+ });
155
+ await waitForEvent(codex, (m) => m.type === "TurnComplete");
156
+ expect(commands).toEqual(["dotv canvas-node outline"]);
157
+ expect(rounds).toBe(2);
158
+ });
159
+ });
160
+ //# sourceMappingURL=sse_parse.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse_parse.test.js","sourceRoot":"","sources":["../../../../core/tests/suite/sse_parse.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai0x0/codex-ts",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {