@ai0x0/codex-ts 0.1.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.
Files changed (130) hide show
  1. package/LICENSE +201 -0
  2. package/dist/core/src/codex_thread.d.ts +80 -0
  3. package/dist/core/src/codex_thread.d.ts.map +1 -0
  4. package/dist/core/src/codex_thread.js +167 -0
  5. package/dist/core/src/codex_thread.js.map +1 -0
  6. package/dist/core/src/index.d.ts +5 -0
  7. package/dist/core/src/index.d.ts.map +1 -0
  8. package/dist/core/src/index.js +4 -0
  9. package/dist/core/src/index.js.map +1 -0
  10. package/dist/core/src/session/turn.d.ts +34 -0
  11. package/dist/core/src/session/turn.d.ts.map +1 -0
  12. package/dist/core/src/session/turn.js +178 -0
  13. package/dist/core/src/session/turn.js.map +1 -0
  14. package/dist/core/src/tools/handlers/plan_spec.d.ts +14 -0
  15. package/dist/core/src/tools/handlers/plan_spec.d.ts.map +1 -0
  16. package/dist/core/src/tools/handlers/plan_spec.js +50 -0
  17. package/dist/core/src/tools/handlers/plan_spec.js.map +1 -0
  18. package/dist/core/src/tools/handlers/request_user_input.d.ts +17 -0
  19. package/dist/core/src/tools/handlers/request_user_input.d.ts.map +1 -0
  20. package/dist/core/src/tools/handlers/request_user_input.js +17 -0
  21. package/dist/core/src/tools/handlers/request_user_input.js.map +1 -0
  22. package/dist/core/src/tools/handlers/request_user_input_spec.d.ts +25 -0
  23. package/dist/core/src/tools/handlers/request_user_input_spec.d.ts.map +1 -0
  24. package/dist/core/src/tools/handlers/request_user_input_spec.js +51 -0
  25. package/dist/core/src/tools/handlers/request_user_input_spec.js.map +1 -0
  26. package/dist/core/src/tools/router.d.ts +30 -0
  27. package/dist/core/src/tools/router.d.ts.map +1 -0
  28. package/dist/core/src/tools/router.js +82 -0
  29. package/dist/core/src/tools/router.js.map +1 -0
  30. package/dist/core/tests/common/lib.d.ts +26 -0
  31. package/dist/core/tests/common/lib.d.ts.map +1 -0
  32. package/dist/core/tests/common/lib.js +97 -0
  33. package/dist/core/tests/common/lib.js.map +1 -0
  34. package/dist/core/tests/suite/goal.test.d.ts +6 -0
  35. package/dist/core/tests/suite/goal.test.d.ts.map +1 -0
  36. package/dist/core/tests/suite/goal.test.js +87 -0
  37. package/dist/core/tests/suite/goal.test.js.map +1 -0
  38. package/dist/core/tests/suite/plan.test.d.ts +5 -0
  39. package/dist/core/tests/suite/plan.test.d.ts.map +1 -0
  40. package/dist/core/tests/suite/plan.test.js +89 -0
  41. package/dist/core/tests/suite/plan.test.js.map +1 -0
  42. package/dist/core/tests/suite/request_user_input.test.d.ts +5 -0
  43. package/dist/core/tests/suite/request_user_input.test.d.ts.map +1 -0
  44. package/dist/core/tests/suite/request_user_input.test.js +151 -0
  45. package/dist/core/tests/suite/request_user_input.test.js.map +1 -0
  46. package/dist/core/tests/suite/resume.test.d.ts +8 -0
  47. package/dist/core/tests/suite/resume.test.d.ts.map +1 -0
  48. package/dist/core/tests/suite/resume.test.js +70 -0
  49. package/dist/core/tests/suite/resume.test.js.map +1 -0
  50. package/dist/ext/goal/src/index.d.ts +3 -0
  51. package/dist/ext/goal/src/index.d.ts.map +1 -0
  52. package/dist/ext/goal/src/index.js +3 -0
  53. package/dist/ext/goal/src/index.js.map +1 -0
  54. package/dist/ext/goal/src/spec.d.ts +13 -0
  55. package/dist/ext/goal/src/spec.d.ts.map +1 -0
  56. package/dist/ext/goal/src/spec.js +61 -0
  57. package/dist/ext/goal/src/spec.js.map +1 -0
  58. package/dist/ext/goal/src/tool.d.ts +34 -0
  59. package/dist/ext/goal/src/tool.d.ts.map +1 -0
  60. package/dist/ext/goal/src/tool.js +104 -0
  61. package/dist/ext/goal/src/tool.js.map +1 -0
  62. package/dist/protocol/src/index.d.ts +5 -0
  63. package/dist/protocol/src/index.d.ts.map +1 -0
  64. package/dist/protocol/src/index.js +2 -0
  65. package/dist/protocol/src/index.js.map +1 -0
  66. package/dist/protocol/src/plan_tool.d.ts +16 -0
  67. package/dist/protocol/src/plan_tool.d.ts.map +1 -0
  68. package/dist/protocol/src/plan_tool.js +5 -0
  69. package/dist/protocol/src/plan_tool.js.map +1 -0
  70. package/dist/protocol/src/protocol.d.ts +87 -0
  71. package/dist/protocol/src/protocol.d.ts.map +1 -0
  72. package/dist/protocol/src/protocol.js +8 -0
  73. package/dist/protocol/src/protocol.js.map +1 -0
  74. package/dist/protocol/src/request_user_input.d.ts +31 -0
  75. package/dist/protocol/src/request_user_input.d.ts.map +1 -0
  76. package/dist/protocol/src/request_user_input.js +3 -0
  77. package/dist/protocol/src/request_user_input.js.map +1 -0
  78. package/dist/protocol/src/user_input.d.ts +9 -0
  79. package/dist/protocol/src/user_input.d.ts.map +1 -0
  80. package/dist/protocol/src/user_input.js +3 -0
  81. package/dist/protocol/src/user_input.js.map +1 -0
  82. package/dist/state/src/index.d.ts +3 -0
  83. package/dist/state/src/index.d.ts.map +1 -0
  84. package/dist/state/src/index.js +2 -0
  85. package/dist/state/src/index.js.map +1 -0
  86. package/dist/state/src/runtime/goals.d.ts +48 -0
  87. package/dist/state/src/runtime/goals.d.ts.map +1 -0
  88. package/dist/state/src/runtime/goals.js +93 -0
  89. package/dist/state/src/runtime/goals.js.map +1 -0
  90. package/dist/thread-store/src/in_memory.d.ts +20 -0
  91. package/dist/thread-store/src/in_memory.d.ts.map +1 -0
  92. package/dist/thread-store/src/in_memory.js +70 -0
  93. package/dist/thread-store/src/in_memory.js.map +1 -0
  94. package/dist/thread-store/src/index.d.ts +8 -0
  95. package/dist/thread-store/src/index.d.ts.map +1 -0
  96. package/dist/thread-store/src/index.js +5 -0
  97. package/dist/thread-store/src/index.js.map +1 -0
  98. package/dist/thread-store/src/io_backend.d.ts +30 -0
  99. package/dist/thread-store/src/io_backend.d.ts.map +1 -0
  100. package/dist/thread-store/src/io_backend.js +31 -0
  101. package/dist/thread-store/src/io_backend.js.map +1 -0
  102. package/dist/thread-store/src/live_thread.d.ts +21 -0
  103. package/dist/thread-store/src/live_thread.d.ts.map +1 -0
  104. package/dist/thread-store/src/live_thread.js +42 -0
  105. package/dist/thread-store/src/live_thread.js.map +1 -0
  106. package/dist/thread-store/src/local_thread_store.d.ts +25 -0
  107. package/dist/thread-store/src/local_thread_store.d.ts.map +1 -0
  108. package/dist/thread-store/src/local_thread_store.js +96 -0
  109. package/dist/thread-store/src/local_thread_store.js.map +1 -0
  110. package/dist/thread-store/src/store.d.ts +22 -0
  111. package/dist/thread-store/src/store.d.ts.map +1 -0
  112. package/dist/thread-store/src/store.js +8 -0
  113. package/dist/thread-store/src/store.js.map +1 -0
  114. package/dist/thread-store/src/types.d.ts +72 -0
  115. package/dist/thread-store/src/types.d.ts.map +1 -0
  116. package/dist/thread-store/src/types.js +6 -0
  117. package/dist/thread-store/src/types.js.map +1 -0
  118. package/dist/tools/src/index.d.ts +5 -0
  119. package/dist/tools/src/index.d.ts.map +1 -0
  120. package/dist/tools/src/index.js +3 -0
  121. package/dist/tools/src/index.js.map +1 -0
  122. package/dist/tools/src/json_schema.d.ts +16 -0
  123. package/dist/tools/src/json_schema.d.ts.map +1 -0
  124. package/dist/tools/src/json_schema.js +26 -0
  125. package/dist/tools/src/json_schema.js.map +1 -0
  126. package/dist/tools/src/tool_spec.d.ts +21 -0
  127. package/dist/tools/src/tool_spec.d.ts.map +1 -0
  128. package/dist/tools/src/tool_spec.js +17 -0
  129. package/dist/tools/src/tool_spec.js.map +1 -0
  130. package/package.json +48 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/common/lib.rs
3
+ *
4
+ * Shared test helpers: waitForEvent, mock SSE server helpers.
5
+ */
6
+ // ─── waitForEvent ─────────────────────────────────────────────────────────────
7
+ /**
8
+ * Mirrors wait_for_event() in core_test_support.
9
+ * Polls nextEvent() until predicate returns true, then returns that EventMsg.
10
+ */
11
+ export async function waitForEvent(codex, predicate, timeoutMs = 2000) {
12
+ const deadline = Date.now() + timeoutMs;
13
+ for (;;) {
14
+ if (Date.now() > deadline) {
15
+ throw new Error(`waitForEvent timed out after ${timeoutMs}ms`);
16
+ }
17
+ const event = await Promise.race([
18
+ codex.nextEvent(),
19
+ new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs)),
20
+ ]);
21
+ if (predicate(event.msg))
22
+ return event.msg;
23
+ }
24
+ }
25
+ /**
26
+ * Mirrors wait_for_event_match() — extracts a typed value from the matching event.
27
+ */
28
+ export async function waitForEventMatch(codex, matcher, timeoutMs = 2000) {
29
+ const msg = await waitForEvent(codex, (m) => matcher(m) !== null, timeoutMs);
30
+ return matcher(msg);
31
+ }
32
+ // ─── SSE mock helpers (mirrors core_test_support/responses.rs) ────────────────
33
+ /** Build a raw SSE data payload string from an array of event objects */
34
+ export function sse(events) {
35
+ return events.map((e) => `data: ${JSON.stringify(e)}\n\n`).join("");
36
+ }
37
+ export function evResponseCreated(id) {
38
+ return { type: "response.created", response: { id, status: "in_progress" } };
39
+ }
40
+ export function evFunctionCall(callId, name, args) {
41
+ const argsStr = JSON.stringify(args);
42
+ return [
43
+ {
44
+ type: "response.output_item.added",
45
+ item: { type: "function_call", call_id: callId, name },
46
+ },
47
+ {
48
+ type: "response.function_call_arguments.delta",
49
+ call_id: callId,
50
+ delta: argsStr,
51
+ },
52
+ {
53
+ type: "response.output_item.done",
54
+ item: { type: "function_call", call_id: callId, name, arguments: argsStr },
55
+ },
56
+ ];
57
+ }
58
+ export function evAssistantMessage(text) {
59
+ return [
60
+ {
61
+ type: "response.output_item.added",
62
+ item: { id: "msg-1", type: "message", status: "in_progress", content: [] },
63
+ },
64
+ { type: "response.output_text.delta", delta: text },
65
+ { type: "response.output_text.done", text },
66
+ {
67
+ type: "response.output_item.done",
68
+ item: {
69
+ id: "msg-1",
70
+ type: "message",
71
+ content: [{ type: "output_text", text }],
72
+ },
73
+ },
74
+ ];
75
+ }
76
+ export function evCompleted(id) {
77
+ return { type: "response.done", response: { id, status: "completed" } };
78
+ }
79
+ /** Flatten nested arrays of SSE events into a single SSE string */
80
+ export function sseFlat(events) {
81
+ return sse(events.flat());
82
+ }
83
+ // ─── Mock fetch ───────────────────────────────────────────────────────────────
84
+ export function makeSseResponse(sseText) {
85
+ return {
86
+ ok: true,
87
+ status: 200,
88
+ body: new ReadableStream({
89
+ start(controller) {
90
+ controller.enqueue(new TextEncoder().encode(sseText));
91
+ controller.close();
92
+ },
93
+ }),
94
+ text: async () => sseText,
95
+ };
96
+ }
97
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../../../../core/tests/common/lib.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/tool_harness.rs (goal-related tests)
3
+ * and ext/goal/src/ unit tests.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=goal.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal.test.d.ts","sourceRoot":"","sources":["../../../../core/tests/suite/goal.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/tool_harness.rs (goal-related tests)
3
+ * and ext/goal/src/ unit tests.
4
+ */
5
+ import { describe, it, expect, vi, beforeEach } from "vitest";
6
+ import { CodexThread } from "../../src/codex_thread.js";
7
+ import { GoalToolExecutor } from "../../../ext/goal/src/tool.js";
8
+ import { waitForEvent, waitForEventMatch, sseFlat, evFunctionCall, evAssistantMessage, evCompleted, evResponseCreated, makeSseResponse, } from "../common/lib.js";
9
+ // ─── GoalToolExecutor unit tests ──────────────────────────────────────────────
10
+ describe("GoalToolExecutor", () => {
11
+ let ex;
12
+ beforeEach(() => { ex = new GoalToolExecutor("thread-1"); });
13
+ it("get returns null goal when none exists", async () => {
14
+ const r = JSON.parse((await ex.get()).output);
15
+ expect(r.goal).toBeNull();
16
+ });
17
+ it("create sets goal to Active", async () => {
18
+ const r = JSON.parse((await ex.create("build it")).output);
19
+ expect(r.goal.status).toBe("Active");
20
+ expect(r.goal.objective).toBe("build it");
21
+ });
22
+ it("create rejects second goal", async () => {
23
+ await ex.create("first");
24
+ const r = JSON.parse((await ex.create("second")).output);
25
+ expect(r.error).toMatch(/already exists/);
26
+ });
27
+ it("create stores token_budget", async () => {
28
+ const r = JSON.parse((await ex.create("work", 500)).output);
29
+ expect(r.remaining_tokens).toBe(500);
30
+ });
31
+ it("update marks goal Complete", async () => {
32
+ await ex.create("finish");
33
+ const r = JSON.parse((await ex.update("complete")).output);
34
+ expect(r.goal.status).toBe("Complete");
35
+ });
36
+ it("update marks goal Blocked", async () => {
37
+ await ex.create("finish");
38
+ const r = JSON.parse((await ex.update("blocked")).output);
39
+ expect(r.goal.status).toBe("Blocked");
40
+ });
41
+ it("update fails with no goal", async () => {
42
+ const r = JSON.parse((await ex.update("complete")).output);
43
+ expect(r.error).toMatch(/No active goal/);
44
+ });
45
+ it("recordTokens reduces remaining budget", async () => {
46
+ await ex.create("work", 1000);
47
+ await ex.recordTokens(300);
48
+ await ex.recordTokens(200);
49
+ const r = JSON.parse((await ex.get()).output);
50
+ expect(r.goal.tokens_used).toBe(500);
51
+ expect(r.remaining_tokens).toBe(500);
52
+ });
53
+ it("create emits a ThreadGoalUpdatedEvent", async () => {
54
+ const { event } = await ex.create("do something");
55
+ expect(event).not.toBeNull();
56
+ expect(event?.goal.status).toBe("Active");
57
+ });
58
+ });
59
+ // ─── Integration: create_goal tool call through CodexThread ───────────────────
60
+ describe("create_goal tool call", () => {
61
+ beforeEach(() => { vi.unstubAllGlobals(); });
62
+ it("emits ThreadGoalUpdated event and TurnComplete", async () => {
63
+ const fetchMock = vi.fn();
64
+ // Turn 1: model calls create_goal
65
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
66
+ evResponseCreated("resp-1"),
67
+ evFunctionCall("call-1", "create_goal", { objective: "test goal" }),
68
+ evCompleted("resp-1"),
69
+ ])));
70
+ // Turn 2: model replies after receiving tool output
71
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
72
+ evResponseCreated("resp-2"),
73
+ evAssistantMessage("Goal created."),
74
+ evCompleted("resp-2"),
75
+ ])));
76
+ vi.stubGlobal("fetch", fetchMock);
77
+ const codex = new CodexThread({ apiKey: "test", model: "gpt-4o" });
78
+ await codex.submit({ type: "UserInput", items: [{ type: "text", text: "create a goal" }] });
79
+ const goalUpdated = await waitForEventMatch(codex, (msg) => msg.type === "ThreadGoalUpdated" ? msg.event : null);
80
+ expect(goalUpdated.goal.objective).toBe("test goal");
81
+ expect(goalUpdated.goal.status).toBe("Active");
82
+ const done = await waitForEvent(codex, (msg) => msg.type === "TurnComplete");
83
+ expect(done.type).toBe("TurnComplete");
84
+ expect(fetchMock).toHaveBeenCalledTimes(2);
85
+ });
86
+ });
87
+ //# sourceMappingURL=goal.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal.test.js","sourceRoot":"","sources":["../../../../core/tests/suite/goal.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/tool_harness.rs (plan-related tests)
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=plan.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.test.d.ts","sourceRoot":"","sources":["../../../../core/tests/suite/plan.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/tool_harness.rs (plan-related tests)
3
+ */
4
+ import { describe, it, expect, vi, beforeEach } from "vitest";
5
+ import { CodexThread } from "../../src/codex_thread.js";
6
+ import { waitForEvent, waitForEventMatch, sseFlat, evFunctionCall, evAssistantMessage, evCompleted, evResponseCreated, makeSseResponse, } from "../common/lib.js";
7
+ beforeEach(() => { vi.unstubAllGlobals(); });
8
+ describe("update_plan_tool_emits_plan_update_event", () => {
9
+ it("emits PlanUpdate with correct steps and TurnComplete", async () => {
10
+ const callId = "plan-tool-call";
11
+ const planArgs = {
12
+ explanation: "Tool harness check",
13
+ plan: [
14
+ { step: "Inspect workspace", status: "in_progress" },
15
+ { step: "Report results", status: "pending" },
16
+ ],
17
+ };
18
+ const fetchMock = vi.fn();
19
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
20
+ evResponseCreated("resp-1"),
21
+ evFunctionCall(callId, "update_plan", planArgs),
22
+ evCompleted("resp-1"),
23
+ ])));
24
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
25
+ evResponseCreated("resp-2"),
26
+ evAssistantMessage("plan acknowledged"),
27
+ evCompleted("resp-2"),
28
+ ])));
29
+ vi.stubGlobal("fetch", fetchMock);
30
+ const codex = new CodexThread({ apiKey: "test", model: "gpt-4o" });
31
+ await codex.submit({
32
+ type: "UserInput",
33
+ items: [{ type: "text", text: "please update the plan" }],
34
+ });
35
+ const update = await waitForEventMatch(codex, (msg) => msg.type === "PlanUpdate" ? msg.event : null);
36
+ expect(update.explanation).toBe("Tool harness check");
37
+ expect(update.plan).toHaveLength(2);
38
+ expect(update.plan[0]?.step).toBe("Inspect workspace");
39
+ expect(update.plan[0]?.status).toBe("in_progress");
40
+ expect(update.plan[1]?.step).toBe("Report results");
41
+ expect(update.plan[1]?.status).toBe("pending");
42
+ await waitForEvent(codex, (msg) => msg.type === "TurnComplete");
43
+ // The tool output sent to the model should be "Plan updated"
44
+ const secondBody = JSON.parse(fetchMock.mock.calls[1][1].body);
45
+ const toolOutput = secondBody.input.find((i) => i.type === "function_call_output" && i.call_id === callId);
46
+ expect(toolOutput?.output).toBe("Plan updated");
47
+ });
48
+ });
49
+ describe("update_plan_tool_rejects_malformed_payload", () => {
50
+ it("returns error output and does not emit PlanUpdate for missing plan", async () => {
51
+ const callId = "plan-tool-invalid";
52
+ const capturedBodies = [];
53
+ const fetchMock = vi.fn().mockImplementation(async (_url, init) => {
54
+ capturedBodies.push(JSON.parse(init.body));
55
+ const idx = capturedBodies.length;
56
+ if (idx === 1) {
57
+ return makeSseResponse(sseFlat([
58
+ evResponseCreated("resp-1"),
59
+ evFunctionCall(callId, "update_plan", { explanation: "Missing plan data" }),
60
+ evCompleted("resp-1"),
61
+ ]));
62
+ }
63
+ return makeSseResponse(sseFlat([
64
+ evResponseCreated("resp-2"),
65
+ evAssistantMessage("malformed plan payload"),
66
+ evCompleted("resp-2"),
67
+ ]));
68
+ });
69
+ vi.stubGlobal("fetch", fetchMock);
70
+ const codex = new CodexThread({ apiKey: "test", model: "gpt-4o" });
71
+ await codex.submit({
72
+ type: "UserInput",
73
+ items: [{ type: "text", text: "please update the plan" }],
74
+ });
75
+ let sawPlanUpdate = false;
76
+ await waitForEvent(codex, (msg) => {
77
+ if (msg.type === "PlanUpdate")
78
+ sawPlanUpdate = true;
79
+ return msg.type === "TurnComplete";
80
+ });
81
+ expect(sawPlanUpdate).toBe(false);
82
+ const secondBody = capturedBodies[1];
83
+ const toolOutput = secondBody.input.find((i) => i.type === "function_call_output" && i.call_id === callId);
84
+ expect(toolOutput).toBeDefined();
85
+ const parsed = JSON.parse(toolOutput.output ?? "{}");
86
+ expect(parsed.error).toMatch(/failed to parse function arguments/);
87
+ });
88
+ });
89
+ //# sourceMappingURL=plan.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.test.js","sourceRoot":"","sources":["../../../../core/tests/suite/plan.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/request_user_input.rs
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=request_user_input.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request_user_input.test.d.ts","sourceRoot":"","sources":["../../../../core/tests/suite/request_user_input.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/request_user_input.rs
3
+ */
4
+ import { describe, it, expect, vi, beforeEach } from "vitest";
5
+ import { CodexThread } from "../../src/codex_thread.js";
6
+ import { waitForEvent, waitForEventMatch, sseFlat, evFunctionCall, evAssistantMessage, evCompleted, evResponseCreated, makeSseResponse, } from "../common/lib.js";
7
+ beforeEach(() => { vi.unstubAllGlobals(); });
8
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
9
+ function makeRequestUserInputArgs(callId) {
10
+ return sseFlat([
11
+ evResponseCreated("resp-1"),
12
+ evFunctionCall(callId, "request_user_input", {
13
+ questions: [
14
+ {
15
+ id: "confirm_path",
16
+ header: "Confirm",
17
+ question: "Proceed with deployment?",
18
+ options: [
19
+ { label: "Yes (Recommended)", description: "Continue." },
20
+ { label: "No", description: "Abort." },
21
+ ],
22
+ },
23
+ ],
24
+ }),
25
+ evCompleted("resp-1"),
26
+ ]);
27
+ }
28
+ // ─── Tests ────────────────────────────────────────────────────────────────────
29
+ describe("request_user_input_round_trip_resolves_pending", () => {
30
+ it("emits RequestUserInput then completes after UserInputAnswer", async () => {
31
+ const callId = "call-rui-1";
32
+ const fetchMock = vi.fn();
33
+ fetchMock.mockResolvedValueOnce(makeSseResponse(makeRequestUserInputArgs(callId)));
34
+ fetchMock.mockResolvedValueOnce(makeSseResponse(sseFlat([
35
+ evResponseCreated("resp-2"),
36
+ evAssistantMessage("thanks"),
37
+ evCompleted("resp-2"),
38
+ ])));
39
+ vi.stubGlobal("fetch", fetchMock);
40
+ const codex = new CodexThread({ apiKey: "test", model: "gpt-4o" });
41
+ await codex.submit({
42
+ type: "UserInput",
43
+ items: [{ type: "text", text: "please confirm" }],
44
+ });
45
+ // Wait for the agent to request user input
46
+ const request = await waitForEventMatch(codex, (msg) => msg.type === "RequestUserInput" ? msg.event : null);
47
+ expect(request.call_id).toBe(callId);
48
+ expect(request.questions).toHaveLength(1);
49
+ expect(request.questions[0]?.id).toBe("confirm_path");
50
+ // normalizeRequestUserInputArgs sets isOther = true
51
+ expect(request.questions[0]?.isOther).toBe(true);
52
+ // Submit the answer — keyed by turn_id (mirrors Op::UserInputAnswer { id: request.turn_id })
53
+ await codex.submit({
54
+ type: "UserInputAnswer",
55
+ id: request.turn_id,
56
+ response: {
57
+ answers: {
58
+ confirm_path: { answers: ["yes"] },
59
+ },
60
+ },
61
+ });
62
+ // After answering the turn should complete
63
+ const done = await waitForEvent(codex, (msg) => msg.type === "TurnComplete");
64
+ expect(done.type).toBe("TurnComplete");
65
+ expect(fetchMock).toHaveBeenCalledTimes(2);
66
+ });
67
+ });
68
+ describe("request_user_input output sent to model", () => {
69
+ it("includes the user answers in the next Responses API request", async () => {
70
+ const callId = "call-rui-2";
71
+ const fetchMock = vi.fn();
72
+ const capturedBodies = [];
73
+ fetchMock.mockImplementation(async (_url, init) => {
74
+ capturedBodies.push(JSON.parse(init.body));
75
+ const idx = capturedBodies.length;
76
+ if (idx === 1) {
77
+ return makeSseResponse(makeRequestUserInputArgs(callId));
78
+ }
79
+ return makeSseResponse(sseFlat([
80
+ evResponseCreated("resp-2"),
81
+ evAssistantMessage("done"),
82
+ evCompleted("resp-2"),
83
+ ]));
84
+ });
85
+ vi.stubGlobal("fetch", fetchMock);
86
+ const codex = new CodexThread({ apiKey: "test", model: "gpt-4o" });
87
+ await codex.submit({
88
+ type: "UserInput",
89
+ items: [{ type: "text", text: "ask me something" }],
90
+ });
91
+ const request = await waitForEventMatch(codex, (msg) => (msg.type === "RequestUserInput" ? msg.event : null));
92
+ await codex.submit({
93
+ type: "UserInputAnswer",
94
+ id: request.turn_id,
95
+ response: { answers: { confirm_path: { answers: ["yes"] } } },
96
+ });
97
+ await waitForEvent(codex, (msg) => msg.type === "TurnComplete");
98
+ // The second request to the model should contain the function_call_output
99
+ const secondBody = capturedBodies[1];
100
+ const toolOutput = secondBody.input.find((i) => i.type === "function_call_output" && i.call_id === callId);
101
+ expect(toolOutput).toBeDefined();
102
+ const parsed = JSON.parse(toolOutput.output ?? "{}");
103
+ expect(parsed.answers["confirm_path"]?.answers).toEqual(["yes"]);
104
+ });
105
+ });
106
+ describe("request_user_input missing options rejects", () => {
107
+ it("returns error output when options are empty", async () => {
108
+ const callId = "call-rui-bad";
109
+ const fetchMock = vi.fn();
110
+ const capturedBodies = [];
111
+ fetchMock.mockImplementation(async (_url, init) => {
112
+ capturedBodies.push(JSON.parse(init.body));
113
+ const idx = capturedBodies.length;
114
+ if (idx === 1) {
115
+ return makeSseResponse(sseFlat([
116
+ evResponseCreated("resp-1"),
117
+ evFunctionCall(callId, "request_user_input", {
118
+ questions: [
119
+ {
120
+ id: "q1",
121
+ header: "Q",
122
+ question: "Choose?",
123
+ options: [], // invalid — empty options
124
+ },
125
+ ],
126
+ }),
127
+ evCompleted("resp-1"),
128
+ ]));
129
+ }
130
+ return makeSseResponse(sseFlat([
131
+ evResponseCreated("resp-2"),
132
+ evAssistantMessage("acknowledged"),
133
+ evCompleted("resp-2"),
134
+ ]));
135
+ });
136
+ vi.stubGlobal("fetch", fetchMock);
137
+ const codex = new CodexThread({ apiKey: "test", model: "gpt-4o" });
138
+ await codex.submit({
139
+ type: "UserInput",
140
+ items: [{ type: "text", text: "question" }],
141
+ });
142
+ await waitForEvent(codex, (msg) => msg.type === "TurnComplete");
143
+ // Tool output for the bad call should contain an error, not suspend
144
+ const secondBody = capturedBodies[1];
145
+ const toolOutput = secondBody.input.find((i) => i.type === "function_call_output" && i.call_id === callId);
146
+ expect(toolOutput).toBeDefined();
147
+ const parsed = JSON.parse(toolOutput.output ?? "{}");
148
+ expect(parsed.error).toMatch(/non-empty options/);
149
+ });
150
+ });
151
+ //# sourceMappingURL=request_user_input.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request_user_input.test.js","sourceRoot":"","sources":["../../../../core/tests/suite/request_user_input.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/resume.rs
3
+ *
4
+ * Verifies that CodexThread.create() reloads persisted conversation history
5
+ * so a resumed thread sends prior turns to the model.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=resume.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.test.d.ts","sourceRoot":"","sources":["../../../../core/tests/suite/resume.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * mirrors codex-rs/core/tests/suite/resume.rs
3
+ *
4
+ * Verifies that CodexThread.create() reloads persisted conversation history
5
+ * so a resumed thread sends prior turns to the model.
6
+ */
7
+ import { describe, it, expect, vi, beforeEach } from "vitest";
8
+ import { CodexThread } from "../../src/codex_thread.js";
9
+ import { InMemoryIoBackend } from "../../../thread-store/src/io_backend.js";
10
+ import { waitForEvent, sseFlat, evAssistantMessage, evCompleted, evResponseCreated, makeSseResponse, } from "../common/lib.js";
11
+ beforeEach(() => { vi.unstubAllGlobals(); });
12
+ describe("CodexThread.create — resume", () => {
13
+ it("loads persisted history so the model receives prior turns on resume", async () => {
14
+ const ioBackend = new InMemoryIoBackend();
15
+ const capturedBodies = [];
16
+ const fetchMock = vi.fn().mockImplementation(async (_url, init) => {
17
+ capturedBodies.push(JSON.parse(init.body));
18
+ return makeSseResponse(sseFlat([
19
+ evResponseCreated("resp-1"),
20
+ evAssistantMessage("all good"),
21
+ evCompleted("resp-1"),
22
+ ]));
23
+ });
24
+ vi.stubGlobal("fetch", fetchMock);
25
+ // ── First session: run one turn ───────────────────────────────────────────
26
+ const first = new CodexThread({ apiKey: "test", model: "gpt-4o", ioBackend });
27
+ const threadId = first.id;
28
+ await first.submit({ type: "UserInput", items: [{ type: "text", text: "hello" }] });
29
+ await waitForEvent(first, (msg) => msg.type === "TurnComplete");
30
+ // ── Second session: resume with same threadId + ioBackend ─────────────────
31
+ const resumed = await CodexThread.create({
32
+ apiKey: "test",
33
+ model: "gpt-4o",
34
+ threadId,
35
+ ioBackend,
36
+ });
37
+ await resumed.submit({ type: "UserInput", items: [{ type: "text", text: "follow-up" }] });
38
+ await waitForEvent(resumed, (msg) => msg.type === "TurnComplete");
39
+ // The second request should contain the full history:
40
+ // user "hello" → assistant "all good" → user "follow-up"
41
+ const secondBody = capturedBodies[1];
42
+ const inputItems = secondBody.input;
43
+ const userMessages = inputItems.filter((i) => i.role === "user");
44
+ const assistantMessages = inputItems.filter((i) => i.role === "assistant");
45
+ expect(userMessages).toHaveLength(2);
46
+ expect(assistantMessages).toHaveLength(1);
47
+ // First user message contains "hello"
48
+ const firstUser = userMessages[0];
49
+ const firstContent = firstUser.content;
50
+ expect(firstContent.some((c) => c.text === "hello")).toBe(true);
51
+ // Assistant message is the persisted reply
52
+ expect(assistantMessages[0].content).toBe("all good");
53
+ });
54
+ it("new CodexThread() without threadId starts fresh even with ioBackend", async () => {
55
+ const ioBackend = new InMemoryIoBackend();
56
+ const capturedBodies = [];
57
+ vi.stubGlobal("fetch", vi.fn().mockImplementation(async (_url, init) => {
58
+ capturedBodies.push(JSON.parse(init.body));
59
+ return makeSseResponse(sseFlat([evResponseCreated("r"), evAssistantMessage("hi"), evCompleted("r")]));
60
+ }));
61
+ const thread = new CodexThread({ apiKey: "test", model: "gpt-4o", ioBackend });
62
+ await thread.submit({ type: "UserInput", items: [{ type: "text", text: "start" }] });
63
+ await waitForEvent(thread, (msg) => msg.type === "TurnComplete");
64
+ // Only one user message — no prior history loaded
65
+ const body = capturedBodies[0];
66
+ const userItems = body.input.filter((i) => i.role === "user");
67
+ expect(userItems).toHaveLength(1);
68
+ });
69
+ });
70
+ //# sourceMappingURL=resume.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.test.js","sourceRoot":"","sources":["../../../../core/tests/suite/resume.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { GoalToolExecutor } from "./tool.js";
2
+ export { GET_GOAL_TOOL_NAME, CREATE_GOAL_TOOL_NAME, UPDATE_GOAL_TOOL_NAME, createGetGoalTool, createCreateGoalTool, createUpdateGoalTool, } from "./spec.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../ext/goal/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { GoalToolExecutor } from "./tool.js";
2
+ export { GET_GOAL_TOOL_NAME, CREATE_GOAL_TOOL_NAME, UPDATE_GOAL_TOOL_NAME, createGetGoalTool, createCreateGoalTool, createUpdateGoalTool, } from "./spec.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../ext/goal/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * mirrors codex-rs/ext/goal/src/spec.rs
3
+ *
4
+ * Tool schemas for create_goal, get_goal, update_goal.
5
+ */
6
+ import type { ToolSpec } from "../../../tools/src/tool_spec.js";
7
+ export declare const GET_GOAL_TOOL_NAME = "get_goal";
8
+ export declare const CREATE_GOAL_TOOL_NAME = "create_goal";
9
+ export declare const UPDATE_GOAL_TOOL_NAME = "update_goal";
10
+ export declare function createGetGoalTool(): ToolSpec;
11
+ export declare function createCreateGoalTool(): ToolSpec;
12
+ export declare function createUpdateGoalTool(): ToolSpec;
13
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../../ext/goal/src/spec.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAGhE,eAAO,MAAM,kBAAkB,aAAa,CAAC;AAC7C,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD,wBAAgB,iBAAiB,IAAI,QAAQ,CAW5C;AAED,wBAAgB,oBAAoB,IAAI,QAAQ,CA0B/C;AAED,wBAAgB,oBAAoB,IAAI,QAAQ,CA2B/C"}