@northflare/runner 0.0.7 → 0.0.9

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 (68) hide show
  1. package/dist/components/claude-sdk-manager.d.ts +1 -1
  2. package/dist/components/claude-sdk-manager.d.ts.map +1 -1
  3. package/dist/components/claude-sdk-manager.js +25 -12
  4. package/dist/components/claude-sdk-manager.js.map +1 -1
  5. package/dist/components/codex-sdk-manager.d.ts +58 -0
  6. package/dist/components/codex-sdk-manager.d.ts.map +1 -0
  7. package/dist/components/codex-sdk-manager.js +907 -0
  8. package/dist/components/codex-sdk-manager.js.map +1 -0
  9. package/dist/components/message-handler-sse.d.ts +3 -0
  10. package/dist/components/message-handler-sse.d.ts.map +1 -1
  11. package/dist/components/message-handler-sse.js +51 -7
  12. package/dist/components/message-handler-sse.js.map +1 -1
  13. package/dist/runner-sse.d.ts +4 -0
  14. package/dist/runner-sse.d.ts.map +1 -1
  15. package/dist/runner-sse.js +145 -15
  16. package/dist/runner-sse.js.map +1 -1
  17. package/dist/types/claude.d.ts +11 -1
  18. package/dist/types/claude.d.ts.map +1 -1
  19. package/dist/types/runner-interface.d.ts +2 -0
  20. package/dist/types/runner-interface.d.ts.map +1 -1
  21. package/dist/utils/model.d.ts +6 -0
  22. package/dist/utils/model.d.ts.map +1 -0
  23. package/dist/utils/model.js +23 -0
  24. package/dist/utils/model.js.map +1 -0
  25. package/dist/utils/status-line.d.ts +2 -2
  26. package/dist/utils/status-line.js +5 -5
  27. package/dist/utils/status-line.js.map +1 -1
  28. package/lib/codex-sdk/.prettierignore +3 -0
  29. package/lib/codex-sdk/.prettierrc +5 -0
  30. package/lib/codex-sdk/README.md +133 -0
  31. package/lib/codex-sdk/dist/index.d.ts +260 -0
  32. package/lib/codex-sdk/dist/index.js +426 -0
  33. package/lib/codex-sdk/eslint.config.js +21 -0
  34. package/lib/codex-sdk/jest.config.cjs +31 -0
  35. package/lib/codex-sdk/package.json +65 -0
  36. package/lib/codex-sdk/samples/basic_streaming.ts +90 -0
  37. package/lib/codex-sdk/samples/helpers.ts +8 -0
  38. package/lib/codex-sdk/samples/structured_output.ts +22 -0
  39. package/lib/codex-sdk/samples/structured_output_zod.ts +19 -0
  40. package/lib/codex-sdk/src/codex.ts +38 -0
  41. package/lib/codex-sdk/src/codexOptions.ts +10 -0
  42. package/lib/codex-sdk/src/events.ts +80 -0
  43. package/lib/codex-sdk/src/exec.ts +336 -0
  44. package/lib/codex-sdk/src/index.ts +39 -0
  45. package/lib/codex-sdk/src/items.ts +127 -0
  46. package/lib/codex-sdk/src/outputSchemaFile.ts +40 -0
  47. package/lib/codex-sdk/src/thread.ts +155 -0
  48. package/lib/codex-sdk/src/threadOptions.ts +18 -0
  49. package/lib/codex-sdk/src/turnOptions.ts +6 -0
  50. package/lib/codex-sdk/tests/abort.test.ts +165 -0
  51. package/lib/codex-sdk/tests/codexExecSpy.ts +37 -0
  52. package/lib/codex-sdk/tests/responsesProxy.ts +225 -0
  53. package/lib/codex-sdk/tests/run.test.ts +687 -0
  54. package/lib/codex-sdk/tests/runStreamed.test.ts +211 -0
  55. package/lib/codex-sdk/tsconfig.json +24 -0
  56. package/lib/codex-sdk/tsup.config.ts +12 -0
  57. package/package.json +3 -1
  58. package/rejections.log +2 -0
  59. package/src/components/claude-sdk-manager.ts +33 -13
  60. package/src/components/codex-sdk-manager.ts +1248 -0
  61. package/src/components/message-handler-sse.ts +79 -8
  62. package/src/runner-sse.ts +174 -15
  63. package/src/types/claude.ts +12 -1
  64. package/src/types/runner-interface.ts +3 -1
  65. package/src/utils/model.ts +29 -0
  66. package/src/utils/status-line.ts +6 -6
  67. package/src/utils/codex-sdk.js +0 -448
  68. package/src/utils/sdk-demo.js +0 -34
@@ -0,0 +1,211 @@
1
+ import path from "node:path";
2
+
3
+ import { describe, expect, it } from "@jest/globals";
4
+
5
+ import { Codex } from "../src/codex";
6
+ import { ThreadEvent } from "../src/index";
7
+
8
+ import {
9
+ assistantMessage,
10
+ responseCompleted,
11
+ responseStarted,
12
+ sse,
13
+ startResponsesTestProxy,
14
+ } from "./responsesProxy";
15
+
16
+ const codexExecPath = path.join(process.cwd(), "..", "..", "codex-rs", "target", "debug", "codex");
17
+
18
+ describe("Codex", () => {
19
+ it("returns thread events", async () => {
20
+ const { url, close } = await startResponsesTestProxy({
21
+ statusCode: 200,
22
+ responseBodies: [sse(responseStarted(), assistantMessage("Hi!"), responseCompleted())],
23
+ });
24
+
25
+ try {
26
+ const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
27
+
28
+ const thread = client.startThread();
29
+ const result = await thread.runStreamed("Hello, world!");
30
+
31
+ const events: ThreadEvent[] = [];
32
+ for await (const event of result.events) {
33
+ events.push(event);
34
+ }
35
+
36
+ expect(events).toEqual([
37
+ {
38
+ type: "thread.started",
39
+ thread_id: expect.any(String),
40
+ },
41
+ {
42
+ type: "turn.started",
43
+ },
44
+ {
45
+ type: "item.completed",
46
+ item: {
47
+ id: "item_0",
48
+ type: "agent_message",
49
+ text: "Hi!",
50
+ },
51
+ },
52
+ {
53
+ type: "turn.completed",
54
+ usage: {
55
+ cached_input_tokens: 12,
56
+ input_tokens: 42,
57
+ output_tokens: 5,
58
+ },
59
+ },
60
+ ]);
61
+ expect(thread.id).toEqual(expect.any(String));
62
+ } finally {
63
+ await close();
64
+ }
65
+ });
66
+
67
+ it("sends previous items when runStreamed is called twice", async () => {
68
+ const { url, close, requests } = await startResponsesTestProxy({
69
+ statusCode: 200,
70
+ responseBodies: [
71
+ sse(
72
+ responseStarted("response_1"),
73
+ assistantMessage("First response", "item_1"),
74
+ responseCompleted("response_1"),
75
+ ),
76
+ sse(
77
+ responseStarted("response_2"),
78
+ assistantMessage("Second response", "item_2"),
79
+ responseCompleted("response_2"),
80
+ ),
81
+ ],
82
+ });
83
+
84
+ try {
85
+ const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
86
+
87
+ const thread = client.startThread();
88
+ const first = await thread.runStreamed("first input");
89
+ await drainEvents(first.events);
90
+
91
+ const second = await thread.runStreamed("second input");
92
+ await drainEvents(second.events);
93
+
94
+ // Check second request continues the same thread
95
+ expect(requests.length).toBeGreaterThanOrEqual(2);
96
+ const secondRequest = requests[1];
97
+ expect(secondRequest).toBeDefined();
98
+ const payload = secondRequest!.json;
99
+
100
+ const assistantEntry = payload.input.find(
101
+ (entry: { role: string }) => entry.role === "assistant",
102
+ );
103
+ expect(assistantEntry).toBeDefined();
104
+ const assistantText = assistantEntry?.content?.find(
105
+ (item: { type: string; text: string }) => item.type === "output_text",
106
+ )?.text;
107
+ expect(assistantText).toBe("First response");
108
+ } finally {
109
+ await close();
110
+ }
111
+ });
112
+
113
+ it("resumes thread by id when streaming", async () => {
114
+ const { url, close, requests } = await startResponsesTestProxy({
115
+ statusCode: 200,
116
+ responseBodies: [
117
+ sse(
118
+ responseStarted("response_1"),
119
+ assistantMessage("First response", "item_1"),
120
+ responseCompleted("response_1"),
121
+ ),
122
+ sse(
123
+ responseStarted("response_2"),
124
+ assistantMessage("Second response", "item_2"),
125
+ responseCompleted("response_2"),
126
+ ),
127
+ ],
128
+ });
129
+
130
+ try {
131
+ const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
132
+
133
+ const originalThread = client.startThread();
134
+ const first = await originalThread.runStreamed("first input");
135
+ await drainEvents(first.events);
136
+
137
+ const resumedThread = client.resumeThread(originalThread.id!);
138
+ const second = await resumedThread.runStreamed("second input");
139
+ await drainEvents(second.events);
140
+
141
+ expect(resumedThread.id).toBe(originalThread.id);
142
+
143
+ expect(requests.length).toBeGreaterThanOrEqual(2);
144
+ const secondRequest = requests[1];
145
+ expect(secondRequest).toBeDefined();
146
+ const payload = secondRequest!.json;
147
+
148
+ const assistantEntry = payload.input.find(
149
+ (entry: { role: string }) => entry.role === "assistant",
150
+ );
151
+ expect(assistantEntry).toBeDefined();
152
+ const assistantText = assistantEntry?.content?.find(
153
+ (item: { type: string; text: string }) => item.type === "output_text",
154
+ )?.text;
155
+ expect(assistantText).toBe("First response");
156
+ } finally {
157
+ await close();
158
+ }
159
+ });
160
+
161
+ it("applies output schema turn options when streaming", async () => {
162
+ const { url, close, requests } = await startResponsesTestProxy({
163
+ statusCode: 200,
164
+ responseBodies: [
165
+ sse(
166
+ responseStarted("response_1"),
167
+ assistantMessage("Structured response", "item_1"),
168
+ responseCompleted("response_1"),
169
+ ),
170
+ ],
171
+ });
172
+
173
+ const schema = {
174
+ type: "object",
175
+ properties: {
176
+ answer: { type: "string" },
177
+ },
178
+ required: ["answer"],
179
+ additionalProperties: false,
180
+ } as const;
181
+
182
+ try {
183
+ const client = new Codex({ codexPathOverride: codexExecPath, baseUrl: url, apiKey: "test" });
184
+
185
+ const thread = client.startThread();
186
+ const streamed = await thread.runStreamed("structured", { outputSchema: schema });
187
+ await drainEvents(streamed.events);
188
+
189
+ expect(requests.length).toBeGreaterThanOrEqual(1);
190
+ const payload = requests[0];
191
+ expect(payload).toBeDefined();
192
+ const text = payload!.json.text;
193
+ expect(text).toBeDefined();
194
+ expect(text?.format).toEqual({
195
+ name: "codex_output_schema",
196
+ type: "json_schema",
197
+ strict: true,
198
+ schema,
199
+ });
200
+ } finally {
201
+ await close();
202
+ }
203
+ });
204
+ });
205
+
206
+ async function drainEvents(events: AsyncGenerator<ThreadEvent>): Promise<void> {
207
+ let done = false;
208
+ do {
209
+ done = (await events.next()).done ?? false;
210
+ } while (!done);
211
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "allowSyntheticDefaultImports": true,
7
+ "esModuleInterop": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "skipLibCheck": true,
10
+ "strict": true,
11
+ "noUncheckedIndexedAccess": true,
12
+ "resolveJsonModule": true,
13
+ "lib": ["ES2022"],
14
+ "types": ["node", "jest"],
15
+ "sourceMap": true,
16
+ "declaration": true,
17
+ "declarationMap": true,
18
+ "noImplicitAny": true,
19
+ "outDir": "dist",
20
+ "stripInternal": true
21
+ },
22
+ "include": ["src", "tests", "tsup.config.ts", "samples"],
23
+ "exclude": ["dist", "node_modules"]
24
+ }
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ format: ["esm"],
6
+ dts: true,
7
+ sourcemap: true,
8
+ clean: true,
9
+ minify: false,
10
+ target: "node18",
11
+ shims: false,
12
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@northflare/runner",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Distributed conversation runner for Northflare",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -24,6 +24,8 @@
24
24
  "@anthropic-ai/claude-agent-sdk": "0.1.37",
25
25
  "@botanicastudios/claude-code-sdk-ts": "0.2.22-fork",
26
26
  "@botanicastudios/mcp-host-rpc": "^0.4.0",
27
+ "@northflare/codex-sdk": "file:lib/codex-sdk",
28
+ "@openai/codex-sdk": "^0.58.0",
27
29
  "@tanstack/react-query": "^5.x.x",
28
30
  "@types/jsonwebtoken": "^9.0.10",
29
31
  "ajv": "^8.x.x",
package/rejections.log CHANGED
@@ -61,3 +61,5 @@
61
61
  {"date":"Mon Sep 08 2025 22:57:44 GMT+0200 (Central European Summer Time)","error":{},"level":"error","message":"unhandledRejection: HTTP 502: \nError: HTTP 502: \n at RunnerApp.sendToOrchestrator (/Users/toby/Code/claudette/runner/dist/runner-sse.js:202:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async RunnerApp.sendToOrchestratorWithRetry (/Users/toby/Code/claudette/runner/dist/runner-sse.js:447:24)\n at async RunnerApp.notify (/Users/toby/Code/claudette/runner/dist/runner-sse.js:157:13)\n at async /Users/toby/Code/claudette/runner/dist/components/claude-manager.js:253:13","os":{"loadavg":[3.6865234375,4.97021484375,5.3193359375],"uptime":194745},"process":{"argv":["/Users/toby/.nvm/versions/node/v22.15.0/bin/node","/Users/toby/Code/claudette/runner/bin/claudette-runner"],"cwd":"/Users/toby/Code/claudette/runner","execPath":"/Users/toby/.nvm/versions/node/v22.15.0/bin/node","gid":20,"memoryUsage":{"arrayBuffers":791696,"external":4349826,"heapTotal":23592960,"heapUsed":17737264,"rss":77004800},"pid":70062,"uid":501,"version":"v22.15.0"},"rejection":true,"stack":"Error: HTTP 502: \n at RunnerApp.sendToOrchestrator (/Users/toby/Code/claudette/runner/dist/runner-sse.js:202:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async RunnerApp.sendToOrchestratorWithRetry (/Users/toby/Code/claudette/runner/dist/runner-sse.js:447:24)\n at async RunnerApp.notify (/Users/toby/Code/claudette/runner/dist/runner-sse.js:157:13)\n at async /Users/toby/Code/claudette/runner/dist/components/claude-manager.js:253:13","trace":[{"column":23,"file":"/Users/toby/Code/claudette/runner/dist/runner-sse.js","function":"RunnerApp.sendToOrchestrator","line":202,"method":"sendToOrchestrator","native":false},{"column":5,"file":"node:internal/process/task_queues","function":"process.processTicksAndRejections","line":105,"method":"processTicksAndRejections","native":false},{"column":24,"file":"/Users/toby/Code/claudette/runner/dist/runner-sse.js","function":"async RunnerApp.sendToOrchestratorWithRetry","line":447,"method":"sendToOrchestratorWithRetry","native":false},{"column":13,"file":"/Users/toby/Code/claudette/runner/dist/runner-sse.js","function":"async RunnerApp.notify","line":157,"method":"notify","native":false},{"column":13,"file":"async /Users/toby/Code/claudette/runner/dist/components/claude-manager.js","function":null,"line":253,"method":null,"native":false}]}
62
62
  {"date":"Tue Sep 09 2025 10:29:32 GMT+0200 (Central European Summer Time)","error":{},"level":"error","message":"unhandledRejection: HTTP 502: \nError: HTTP 502: \n at RunnerApp.sendToOrchestrator (/Users/toby/Code/claudette/runner/dist/runner-sse.js:202:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async RunnerApp.sendToOrchestratorWithRetry (/Users/toby/Code/claudette/runner/dist/runner-sse.js:447:24)\n at async RunnerApp.notify (/Users/toby/Code/claudette/runner/dist/runner-sse.js:157:13)\n at async /Users/toby/Code/claudette/runner/dist/components/claude-manager.js:253:13","os":{"loadavg":[3.1787109375,4.40380859375,4.64892578125],"uptime":236253},"process":{"argv":["/Users/toby/.nvm/versions/node/v22.15.0/bin/node","/Users/toby/Code/claudette/runner/bin/claudette-runner"],"cwd":"/Users/toby/Code/claudette/runner","execPath":"/Users/toby/.nvm/versions/node/v22.15.0/bin/node","gid":20,"memoryUsage":{"arrayBuffers":167387,"external":3725517,"heapTotal":25362432,"heapUsed":16211304,"rss":59359232},"pid":7619,"uid":501,"version":"v22.15.0"},"rejection":true,"stack":"Error: HTTP 502: \n at RunnerApp.sendToOrchestrator (/Users/toby/Code/claudette/runner/dist/runner-sse.js:202:23)\n at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n at async RunnerApp.sendToOrchestratorWithRetry (/Users/toby/Code/claudette/runner/dist/runner-sse.js:447:24)\n at async RunnerApp.notify (/Users/toby/Code/claudette/runner/dist/runner-sse.js:157:13)\n at async /Users/toby/Code/claudette/runner/dist/components/claude-manager.js:253:13","trace":[{"column":23,"file":"/Users/toby/Code/claudette/runner/dist/runner-sse.js","function":"RunnerApp.sendToOrchestrator","line":202,"method":"sendToOrchestrator","native":false},{"column":5,"file":"node:internal/process/task_queues","function":"process.processTicksAndRejections","line":105,"method":"processTicksAndRejections","native":false},{"column":24,"file":"/Users/toby/Code/claudette/runner/dist/runner-sse.js","function":"async RunnerApp.sendToOrchestratorWithRetry","line":447,"method":"sendToOrchestratorWithRetry","native":false},{"column":13,"file":"/Users/toby/Code/claudette/runner/dist/runner-sse.js","function":"async RunnerApp.notify","line":157,"method":"notify","native":false},{"column":13,"file":"async /Users/toby/Code/claudette/runner/dist/components/claude-manager.js","function":null,"line":253,"method":null,"native":false}]}
63
63
  {"date":"Fri Oct 31 2025 15:15:47 GMT+0100 (Central European Standard Time)","error":{"code":"MODULE_NOT_FOUND","path":"/Users/toby/Code/claudette/runner/node_modules/@anthropic-ai/claude-code/package.json","requestPath":"@anthropic-ai/claude-code"},"level":"error","message":"unhandledRejection: Cannot find module '/Users/toby/Code/claudette/runner/node_modules/@anthropic-ai/claude-code/sdk.mjs'. Please verify that the package.json has a valid \"main\" entry\nError: Cannot find module '/Users/toby/Code/claudette/runner/node_modules/@anthropic-ai/claude-code/sdk.mjs'. Please verify that the package.json has a valid \"main\" entry\n at tryPackage (node:internal/modules/cjs/loader:511:19)\n at Function._findPath (node:internal/modules/cjs/loader:796:18)\n at Function._resolveFilename (node:internal/modules/cjs/loader:1387:27)\n at defaultResolveImpl (node:internal/modules/cjs/loader:1057:19)\n at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1062:22)\n at Function._load (node:internal/modules/cjs/loader:1211:37)\n at TracingChannel.traceSync (node:diagnostics_channel:322:14)\n at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)\n at Module.require (node:internal/modules/cjs/loader:1487:12)\n at require (node:internal/modules/helpers:135:16)","os":{"loadavg":[10.09228515625,5.86376953125,4.3662109375],"uptime":187703},"process":{"argv":["/Users/toby/.nvm/versions/node/v22.15.0/bin/node","/Users/toby/Code/claudette/runner/bin/claudette-runner"],"cwd":"/Users/toby/Code/claudette/runner","execPath":"/Users/toby/.nvm/versions/node/v22.15.0/bin/node","gid":20,"memoryUsage":{"arrayBuffers":12531,"external":1652665,"heapTotal":10829824,"heapUsed":7045984,"rss":56049664},"pid":4552,"uid":501,"version":"v22.15.0"},"rejection":true,"stack":"Error: Cannot find module '/Users/toby/Code/claudette/runner/node_modules/@anthropic-ai/claude-code/sdk.mjs'. Please verify that the package.json has a valid \"main\" entry\n at tryPackage (node:internal/modules/cjs/loader:511:19)\n at Function._findPath (node:internal/modules/cjs/loader:796:18)\n at Function._resolveFilename (node:internal/modules/cjs/loader:1387:27)\n at defaultResolveImpl (node:internal/modules/cjs/loader:1057:19)\n at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1062:22)\n at Function._load (node:internal/modules/cjs/loader:1211:37)\n at TracingChannel.traceSync (node:diagnostics_channel:322:14)\n at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)\n at Module.require (node:internal/modules/cjs/loader:1487:12)\n at require (node:internal/modules/helpers:135:16)","trace":[{"column":19,"file":"node:internal/modules/cjs/loader","function":"tryPackage","line":511,"method":null,"native":false},{"column":18,"file":"node:internal/modules/cjs/loader","function":"Function._findPath","line":796,"method":"_findPath","native":false},{"column":27,"file":"node:internal/modules/cjs/loader","function":"Function._resolveFilename","line":1387,"method":"_resolveFilename","native":false},{"column":19,"file":"node:internal/modules/cjs/loader","function":"defaultResolveImpl","line":1057,"method":null,"native":false},{"column":22,"file":"node:internal/modules/cjs/loader","function":"resolveForCJSWithHooks","line":1062,"method":null,"native":false},{"column":37,"file":"node:internal/modules/cjs/loader","function":"Function._load","line":1211,"method":"_load","native":false},{"column":14,"file":"node:diagnostics_channel","function":"TracingChannel.traceSync","line":322,"method":"traceSync","native":false},{"column":24,"file":"node:internal/modules/cjs/loader","function":"wrapModuleLoad","line":235,"method":null,"native":false},{"column":12,"file":"node:internal/modules/cjs/loader","function":"Module.require","line":1487,"method":"require","native":false},{"column":16,"file":"node:internal/modules/helpers","function":"require","line":135,"method":null,"native":false}]}
64
+ {"date":"Tue Nov 18 2025 11:23:35 GMT+0100 (Central European Standard Time)","error":{"code":"ERR_PACKAGE_PATH_NOT_EXPORTED"},"level":"error","message":"unhandledRejection: No \"exports\" main defined in /Users/toby/Code/claudette/runner/node_modules/@northflare/codex-sdk/package.json\nError [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \"exports\" main defined in /Users/toby/Code/claudette/runner/node_modules/@northflare/codex-sdk/package.json\n at exportsNotFound (node:internal/modules/esm/resolve:314:10)\n at packageExportsResolve (node:internal/modules/esm/resolve:604:13)\n at resolveExports (node:internal/modules/cjs/loader:657:36)\n at Function._findPath (node:internal/modules/cjs/loader:749:31)\n at Function._resolveFilename (node:internal/modules/cjs/loader:1387:27)\n at defaultResolveImpl (node:internal/modules/cjs/loader:1057:19)\n at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1062:22)\n at Function._load (node:internal/modules/cjs/loader:1211:37)\n at TracingChannel.traceSync (node:diagnostics_channel:322:14)\n at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)","os":{"loadavg":[4.82373046875,4.37255859375,4.115234375],"uptime":97198},"process":{"argv":["/Users/toby/.nvm/versions/node/v22.15.0/bin/node","/Users/toby/Code/claudette/runner/bin/northflare-runner"],"cwd":"/Users/toby/Code/claudette/runner","execPath":"/Users/toby/.nvm/versions/node/v22.15.0/bin/node","gid":20,"memoryUsage":{"arrayBuffers":18675,"external":2091282,"heapTotal":18972672,"heapUsed":12330016,"rss":65404928},"pid":95991,"uid":501,"version":"v22.15.0"},"rejection":true,"stack":"Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \"exports\" main defined in /Users/toby/Code/claudette/runner/node_modules/@northflare/codex-sdk/package.json\n at exportsNotFound (node:internal/modules/esm/resolve:314:10)\n at packageExportsResolve (node:internal/modules/esm/resolve:604:13)\n at resolveExports (node:internal/modules/cjs/loader:657:36)\n at Function._findPath (node:internal/modules/cjs/loader:749:31)\n at Function._resolveFilename (node:internal/modules/cjs/loader:1387:27)\n at defaultResolveImpl (node:internal/modules/cjs/loader:1057:19)\n at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1062:22)\n at Function._load (node:internal/modules/cjs/loader:1211:37)\n at TracingChannel.traceSync (node:diagnostics_channel:322:14)\n at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)","trace":[{"column":10,"file":"node:internal/modules/esm/resolve","function":"exportsNotFound","line":314,"method":null,"native":false},{"column":13,"file":"node:internal/modules/esm/resolve","function":"packageExportsResolve","line":604,"method":null,"native":false},{"column":36,"file":"node:internal/modules/cjs/loader","function":"resolveExports","line":657,"method":null,"native":false},{"column":31,"file":"node:internal/modules/cjs/loader","function":"Function._findPath","line":749,"method":"_findPath","native":false},{"column":27,"file":"node:internal/modules/cjs/loader","function":"Function._resolveFilename","line":1387,"method":"_resolveFilename","native":false},{"column":19,"file":"node:internal/modules/cjs/loader","function":"defaultResolveImpl","line":1057,"method":null,"native":false},{"column":22,"file":"node:internal/modules/cjs/loader","function":"resolveForCJSWithHooks","line":1062,"method":null,"native":false},{"column":37,"file":"node:internal/modules/cjs/loader","function":"Function._load","line":1211,"method":"_load","native":false},{"column":14,"file":"node:diagnostics_channel","function":"TracingChannel.traceSync","line":322,"method":"traceSync","native":false},{"column":24,"file":"node:internal/modules/cjs/loader","function":"wrapModuleLoad","line":235,"method":null,"native":false}]}
65
+ {"date":"Tue Nov 18 2025 11:24:17 GMT+0100 (Central European Standard Time)","error":{"code":"ERR_PACKAGE_PATH_NOT_EXPORTED"},"level":"error","message":"unhandledRejection: No \"exports\" main defined in /Users/toby/Code/claudette/runner/node_modules/@northflare/codex-sdk/package.json\nError [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \"exports\" main defined in /Users/toby/Code/claudette/runner/node_modules/@northflare/codex-sdk/package.json\n at exportsNotFound (node:internal/modules/esm/resolve:314:10)\n at packageExportsResolve (node:internal/modules/esm/resolve:604:13)\n at resolveExports (node:internal/modules/cjs/loader:657:36)\n at Function._findPath (node:internal/modules/cjs/loader:749:31)\n at Function._resolveFilename (node:internal/modules/cjs/loader:1387:27)\n at defaultResolveImpl (node:internal/modules/cjs/loader:1057:19)\n at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1062:22)\n at Function._load (node:internal/modules/cjs/loader:1211:37)\n at TracingChannel.traceSync (node:diagnostics_channel:322:14)\n at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)","os":{"loadavg":[7.13623046875,4.9140625,4.31787109375],"uptime":97240},"process":{"argv":["/Users/toby/.nvm/versions/node/v22.15.0/bin/node","/Users/toby/Code/claudette/runner/bin/northflare-runner"],"cwd":"/Users/toby/Code/claudette/runner","execPath":"/Users/toby/.nvm/versions/node/v22.15.0/bin/node","gid":20,"memoryUsage":{"arrayBuffers":18675,"external":2091282,"heapTotal":18710528,"heapUsed":12265536,"rss":65486848},"pid":99528,"uid":501,"version":"v22.15.0"},"rejection":true,"stack":"Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \"exports\" main defined in /Users/toby/Code/claudette/runner/node_modules/@northflare/codex-sdk/package.json\n at exportsNotFound (node:internal/modules/esm/resolve:314:10)\n at packageExportsResolve (node:internal/modules/esm/resolve:604:13)\n at resolveExports (node:internal/modules/cjs/loader:657:36)\n at Function._findPath (node:internal/modules/cjs/loader:749:31)\n at Function._resolveFilename (node:internal/modules/cjs/loader:1387:27)\n at defaultResolveImpl (node:internal/modules/cjs/loader:1057:19)\n at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1062:22)\n at Function._load (node:internal/modules/cjs/loader:1211:37)\n at TracingChannel.traceSync (node:diagnostics_channel:322:14)\n at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)","trace":[{"column":10,"file":"node:internal/modules/esm/resolve","function":"exportsNotFound","line":314,"method":null,"native":false},{"column":13,"file":"node:internal/modules/esm/resolve","function":"packageExportsResolve","line":604,"method":null,"native":false},{"column":36,"file":"node:internal/modules/cjs/loader","function":"resolveExports","line":657,"method":null,"native":false},{"column":31,"file":"node:internal/modules/cjs/loader","function":"Function._findPath","line":749,"method":"_findPath","native":false},{"column":27,"file":"node:internal/modules/cjs/loader","function":"Function._resolveFilename","line":1387,"method":"_resolveFilename","native":false},{"column":19,"file":"node:internal/modules/cjs/loader","function":"defaultResolveImpl","line":1057,"method":null,"native":false},{"column":22,"file":"node:internal/modules/cjs/loader","function":"resolveForCJSWithHooks","line":1062,"method":null,"native":false},{"column":37,"file":"node:internal/modules/cjs/loader","function":"Function._load","line":1211,"method":"_load","native":false},{"column":14,"file":"node:diagnostics_channel","function":"TracingChannel.traceSync","line":322,"method":"traceSync","native":false},{"column":24,"file":"node:internal/modules/cjs/loader","function":"wrapModuleLoad","line":235,"method":null,"native":false}]}
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
  import { query as sdkQuery } from "@anthropic-ai/claude-agent-sdk";
18
+ import type { Conversation as ClaudeConversation } from "@botanicastudios/claude-code-sdk-ts";
18
19
  // Keep SDKMessage loosely typed to avoid tight coupling to SDK typings
19
20
  type SDKMessage = any;
20
21
  import { IRunnerApp } from "../types/runner-interface";
@@ -301,11 +302,11 @@ export class ClaudeManager {
301
302
  // Simplified MCP server configuration
302
303
  let mcpServers: Record<string, any> | undefined;
303
304
  if (config.mcpServers) {
305
+ mcpServers = expandEnv(config.mcpServers, { TOOL_TOKEN: toolToken });
304
306
  console.log(
305
307
  "[ClaudeManager] MCP servers configuration:",
306
- JSON.stringify(config.mcpServers, null, 2)
308
+ JSON.stringify(mcpServers, null, 2)
307
309
  );
308
- mcpServers = expandEnv(config.mcpServers, { TOOL_TOKEN: toolToken });
309
310
  }
310
311
 
311
312
  // Create input stream for user messages (simplified message queueing)
@@ -473,7 +474,9 @@ export class ClaudeManager {
473
474
  context.status = "stopped";
474
475
 
475
476
  // Properly end the conversation using the SDK
476
- await context.conversation.end();
477
+ if (isClaudeConversation(context.conversation)) {
478
+ await context.conversation.end();
479
+ }
477
480
  } catch (error) {
478
481
  console.error(`Error ending conversation ${agentSessionId}:`, error);
479
482
  }
@@ -508,7 +511,7 @@ export class ClaudeManager {
508
511
 
509
512
  // After starting the conversation with the sessionId, we need to send a message
510
513
  // to actually trigger the Claude process to continue
511
- if (context.conversation) {
514
+ if (context.conversation && isClaudeConversation(context.conversation)) {
512
515
  try {
513
516
  // Use the provided resume message or default to system instruction
514
517
  const messageToSend =
@@ -524,6 +527,10 @@ export class ClaudeManager {
524
527
  } catch (error) {
525
528
  console.error(`[ClaudeManager] Error sending resume message:`, error);
526
529
  }
530
+ } else {
531
+ console.warn(
532
+ "[ClaudeManager] Resume requested but conversation instance missing or incompatible"
533
+ );
527
534
  }
528
535
 
529
536
  return context.agentSessionId;
@@ -573,7 +580,8 @@ export class ClaudeManager {
573
580
  config?: ConversationConfig,
574
581
  conversationObjectType?: "Task" | "TaskPlan",
575
582
  conversationObjectId?: string,
576
- conversation?: any
583
+ conversation?: any,
584
+ _agentSessionIdOverride?: string
577
585
  ): Promise<void> {
578
586
  console.log(`[ClaudeManager] sendUserMessage called with:`, {
579
587
  conversationId,
@@ -644,7 +652,7 @@ export class ClaudeManager {
644
652
 
645
653
  try {
646
654
  // Send immediately when a conversation instance exists; no need to wait for "active"
647
- if (!context.conversation) {
655
+ if (!context.conversation || !isClaudeConversation(context.conversation)) {
648
656
  throw new Error(
649
657
  `No conversation instance found for conversation ${context.conversationId}`
650
658
  );
@@ -980,14 +988,17 @@ export class ClaudeManager {
980
988
  }
981
989
 
982
990
  case "thinking" as any: {
983
- // Map thinking to assistant with subtype
984
- messageType = "assistant";
985
- subtype = "thinking";
991
+ messageType = "thinking";
992
+ subtype = undefined;
986
993
  const thinkingMsg = message as any;
987
- structuredContent = {
988
- text: thinkingMsg.content || "",
989
- timestamp: new Date().toISOString(),
990
- };
994
+ structuredContent = [
995
+ {
996
+ type: "thinking",
997
+ thinking: thinkingMsg.content || "",
998
+ text: thinkingMsg.content || "",
999
+ timestamp: new Date().toISOString(),
1000
+ },
1001
+ ];
991
1002
  break;
992
1003
  }
993
1004
 
@@ -1402,3 +1413,12 @@ function createConversationWrapper(
1402
1413
  },
1403
1414
  };
1404
1415
  }
1416
+ function isClaudeConversation(
1417
+ conversation: ConversationContext["conversation"]
1418
+ ): conversation is ClaudeConversation {
1419
+ return (
1420
+ !!conversation &&
1421
+ typeof (conversation as ClaudeConversation).send === "function" &&
1422
+ typeof (conversation as ClaudeConversation).end === "function"
1423
+ );
1424
+ }