@parall/codex-agent 1.29.0 → 1.29.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.
@@ -14,6 +14,8 @@ export declare class CodexAppServerAdapter implements DispatchAdapter {
14
14
  private initialized;
15
15
  private startPromise;
16
16
  private readonly activeTurns;
17
+ private readonly activeTurnIds;
18
+ private readonly pendingInjections;
17
19
  private readonly resumedThreadIds;
18
20
  private stopping;
19
21
  /**
@@ -30,6 +32,8 @@ export declare class CodexAppServerAdapter implements DispatchAdapter {
30
32
  model?: string | null;
31
33
  reasoningEffort?: string | null;
32
34
  }): void;
35
+ enqueueDuringDispatch(sessionKey: string, body: string): Promise<boolean>;
36
+ hasPendingInjections(sessionKey: string): boolean;
33
37
  dispatch({ event, bodyForAgent, sessionKey, context }: DispatchOpts): AsyncIterable<RuntimeEvent>;
34
38
  getBranchPoint(_sessionKey: string): string | undefined;
35
39
  forkSession({ sessionKey: parentSessionKey }: ForkOpts): Promise<ForkSessionHandle | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,KAAK,4BAA4B,GAAG,IAAI,CACtC,gBAAgB,EACd,gBAAgB,GAChB,UAAU,GACV,WAAW,GACX,OAAO,GACP,iBAAiB,GACjB,SAAS,GACT,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,mBAAmB,CAAC;IACpC,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAmCF,qBAAa,qBAAsB,YAAW,eAAe;IA6B/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IA5BjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;gBAYQ,IAAI,EAAE,4BAA4B;IAE/D,YAAY,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAK/E,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IAwMxG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMjD,WAAW,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAuBhG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,cAAc;IAKhB,IAAI;YAeI,aAAa;YAyBb,OAAO;IAyErB,OAAO,CAAC,qBAAqB;YAiCf,UAAU;IA2CxB,OAAO,CAAC,iBAAiB;CA2B1B"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,KAAK,4BAA4B,GAAG,IAAI,CACtC,gBAAgB,EACd,gBAAgB,GAChB,UAAU,GACV,WAAW,GACX,OAAO,GACP,iBAAiB,GACjB,SAAS,GACT,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,mBAAmB,CAAC;IACpC,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAmCF,qBAAa,qBAAsB,YAAW,eAAe;IA+B/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IA9BjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;gBAYQ,IAAI,EAAE,4BAA4B;IAE/D,YAAY,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAKhF,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB/E,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IA6NxG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMjD,WAAW,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IA+BhG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,cAAc;IAKhB,IAAI;YAiBI,aAAa;YA2Bb,OAAO;IAyErB,OAAO,CAAC,qBAAqB;YAmCf,UAAU;IA2CxB,OAAO,CAAC,iBAAiB;CA4B1B"}
package/dist/dispatch.js CHANGED
@@ -41,6 +41,8 @@ export class CodexAppServerAdapter {
41
41
  initialized = false;
42
42
  startPromise = null;
43
43
  activeTurns = new Map();
44
+ activeTurnIds = new Map();
45
+ pendingInjections = new Map();
44
46
  resumedThreadIds = new Set();
45
47
  stopping = false;
46
48
  /**
@@ -69,7 +71,49 @@ export class CodexAppServerAdapter {
69
71
  if (config.reasoningEffort !== undefined)
70
72
  this.opts.reasoningEffort = config.reasoningEffort ?? undefined;
71
73
  }
74
+ async enqueueDuringDispatch(sessionKey, body) {
75
+ const client = this.client;
76
+ if (!client || client.isDisposed())
77
+ return false;
78
+ const threadId = this.opts.sessionManager.getThreadId(sessionKey);
79
+ if (!threadId)
80
+ return false;
81
+ const turnId = this.activeTurnIds.get(threadId);
82
+ if (!turnId)
83
+ return false;
84
+ try {
85
+ await client.sendRequest("turn/steer", {
86
+ threadId,
87
+ expectedTurnId: turnId,
88
+ input: buildTurnInput(body, []),
89
+ });
90
+ this.pendingInjections.set(sessionKey, (this.pendingInjections.get(sessionKey) ?? 0) + 1);
91
+ return true;
92
+ }
93
+ catch (err) {
94
+ this.opts.log?.warn?.(`codex-agent: turn/steer failed: ${errToString(err)}`);
95
+ return false;
96
+ }
97
+ }
98
+ hasPendingInjections(sessionKey) {
99
+ return (this.pendingInjections.get(sessionKey) ?? 0) > 0;
100
+ }
72
101
  async *dispatch({ event, bodyForAgent, sessionKey, context }) {
102
+ const pending = this.pendingInjections.get(sessionKey) ?? 0;
103
+ if (pending > 0) {
104
+ this.pendingInjections.delete(sessionKey);
105
+ const threadId = this.opts.sessionManager.getThreadId(sessionKey);
106
+ if (threadId && this.client && !this.client.isDisposed()) {
107
+ (this.opts.log ?? context.log)?.info?.(`codex-agent[${context.accountId}]: ${pending} steer injection(s) already sent; skipping turn/start`);
108
+ yield {
109
+ type: "runtime_session",
110
+ runtimeSessionId: threadId,
111
+ runtimeLaneKey: sessionKey,
112
+ };
113
+ return;
114
+ }
115
+ (this.opts.log ?? context.log)?.warn?.(`codex-agent[${context.accountId}]: pending steer invalidated (subprocess died); falling through to normal dispatch`);
116
+ }
73
117
  await this.ensureStarted(context.log);
74
118
  // After ensureStarted resolves the subprocess could still die before we
75
119
  // capture the client (handleSubprocessClose nulls this.client). Yield a
@@ -224,7 +268,9 @@ export class CodexAppServerAdapter {
224
268
  this.resumedThreadIds.add(freshThreadId);
225
269
  threadId = freshThreadId;
226
270
  }
227
- void turnStartResult; // turnId comes back here but isn't needed — we key by threadId
271
+ const turnId = extractTurnId(turnStartResult);
272
+ if (turnId)
273
+ this.activeTurnIds.set(threadId, turnId);
228
274
  yield {
229
275
  type: "runtime_session",
230
276
  runtimeSessionId: threadId,
@@ -264,8 +310,8 @@ export class CodexAppServerAdapter {
264
310
  finally {
265
311
  releasePreparedAttachments();
266
312
  this.activeTurns.delete(threadId);
313
+ this.activeTurnIds.delete(threadId);
267
314
  if (!sawTurnEnd) {
268
- // Defensive: if we bailed early, make sure we leave no dangling sink.
269
315
  sink.close();
270
316
  }
271
317
  }
@@ -284,10 +330,19 @@ export class CodexAppServerAdapter {
284
330
  return null;
285
331
  const handle = this.opts.sessionManager.createForkSessionKey();
286
332
  try {
287
- const result = await client.sendRequest("thread/fork", {
333
+ const forkParams = {
288
334
  threadId: parentThreadId,
289
335
  ephemeral: true,
290
- });
336
+ };
337
+ if (this.opts.useParallProvider) {
338
+ forkParams.modelProvider = "parall";
339
+ }
340
+ if (this.opts.model)
341
+ forkParams.model = this.opts.model;
342
+ if (this.opts.reasoningEffort) {
343
+ forkParams.config = { modelReasoningEffort: this.opts.reasoningEffort };
344
+ }
345
+ const result = await client.sendRequest("thread/fork", forkParams);
291
346
  const forkedThreadId = extractThreadId(result);
292
347
  if (!forkedThreadId) {
293
348
  this.opts.log?.warn?.("codex-agent: thread/fork returned no thread id");
@@ -314,6 +369,8 @@ export class CodexAppServerAdapter {
314
369
  this.proc = null;
315
370
  this.client = null;
316
371
  this.initialized = false;
372
+ this.activeTurnIds.clear();
373
+ this.pendingInjections.clear();
317
374
  if (client)
318
375
  client.dispose(new Error("adapter stopped"));
319
376
  if (proc && proc.exitCode === null && proc.signalCode === null) {
@@ -329,6 +386,8 @@ export class CodexAppServerAdapter {
329
386
  activeSink.close();
330
387
  }
331
388
  this.activeTurns.clear();
389
+ this.activeTurnIds.clear();
390
+ this.pendingInjections.clear();
332
391
  this.client = null;
333
392
  this.proc = null;
334
393
  this.initialized = false;
@@ -437,6 +496,8 @@ export class CodexAppServerAdapter {
437
496
  activeSink.close();
438
497
  }
439
498
  this.activeTurns.clear();
499
+ this.activeTurnIds.clear();
500
+ this.pendingInjections.clear();
440
501
  this.resumedThreadIds.clear();
441
502
  this.client = null;
442
503
  this.proc = null;
@@ -502,6 +563,7 @@ export class CodexAppServerAdapter {
502
563
  sink.push({ kind: "runtime", event });
503
564
  }
504
565
  if (method === "turn/completed") {
566
+ this.activeTurnIds.delete(threadId);
505
567
  sink.push({ kind: "turn_end", threadId });
506
568
  }
507
569
  }
@@ -592,6 +654,17 @@ function extractThreadId(result) {
592
654
  return thread.id;
593
655
  return undefined;
594
656
  }
657
+ function extractTurnId(result) {
658
+ if (!result || typeof result !== "object")
659
+ return undefined;
660
+ const r = result;
661
+ if (typeof r.turnId === "string")
662
+ return r.turnId;
663
+ const turn = r.turn;
664
+ if (turn && typeof turn.id === "string")
665
+ return turn.id;
666
+ return undefined;
667
+ }
595
668
  function extractThreadIdFromNotification(params) {
596
669
  if (!params || typeof params !== "object")
597
670
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/codex-agent",
3
- "version": "1.29.0",
3
+ "version": "1.29.1",
4
4
  "description": "Codex CLI bridge runtime for self-hosted Parall agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -26,9 +26,9 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "smol-toml": "^1.6.1",
29
- "@parall/agent-core": "1.29.0",
30
- "@parall/cli": "1.29.0",
31
- "@parall/sdk": "1.29.0"
29
+ "@parall/agent-core": "1.29.1",
30
+ "@parall/cli": "1.29.1",
31
+ "@parall/sdk": "1.29.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^22.0.0",
package/src/dispatch.ts CHANGED
@@ -77,6 +77,8 @@ export class CodexAppServerAdapter implements DispatchAdapter {
77
77
  private initialized = false;
78
78
  private startPromise: Promise<void> | null = null;
79
79
  private readonly activeTurns = new Map<string, TurnSink>();
80
+ private readonly activeTurnIds = new Map<string, string>();
81
+ private readonly pendingInjections = new Map<string, number>();
80
82
  private readonly resumedThreadIds = new Set<string>();
81
83
  private stopping = false;
82
84
 
@@ -107,7 +109,52 @@ export class CodexAppServerAdapter implements DispatchAdapter {
107
109
  if (config.reasoningEffort !== undefined) this.opts.reasoningEffort = config.reasoningEffort ?? undefined;
108
110
  }
109
111
 
112
+ async enqueueDuringDispatch(sessionKey: string, body: string): Promise<boolean> {
113
+ const client = this.client;
114
+ if (!client || client.isDisposed()) return false;
115
+ const threadId = this.opts.sessionManager.getThreadId(sessionKey);
116
+ if (!threadId) return false;
117
+ const turnId = this.activeTurnIds.get(threadId);
118
+ if (!turnId) return false;
119
+ try {
120
+ await client.sendRequest("turn/steer", {
121
+ threadId,
122
+ expectedTurnId: turnId,
123
+ input: buildTurnInput(body, []),
124
+ });
125
+ this.pendingInjections.set(sessionKey, (this.pendingInjections.get(sessionKey) ?? 0) + 1);
126
+ return true;
127
+ } catch (err) {
128
+ this.opts.log?.warn?.(`codex-agent: turn/steer failed: ${errToString(err)}`);
129
+ return false;
130
+ }
131
+ }
132
+
133
+ hasPendingInjections(sessionKey: string): boolean {
134
+ return (this.pendingInjections.get(sessionKey) ?? 0) > 0;
135
+ }
136
+
110
137
  async *dispatch({ event, bodyForAgent, sessionKey, context }: DispatchOpts): AsyncIterable<RuntimeEvent> {
138
+ const pending = this.pendingInjections.get(sessionKey) ?? 0;
139
+ if (pending > 0) {
140
+ this.pendingInjections.delete(sessionKey);
141
+ const threadId = this.opts.sessionManager.getThreadId(sessionKey);
142
+ if (threadId && this.client && !this.client.isDisposed()) {
143
+ (this.opts.log ?? context.log)?.info?.(
144
+ `codex-agent[${context.accountId}]: ${pending} steer injection(s) already sent; skipping turn/start`,
145
+ );
146
+ yield {
147
+ type: "runtime_session",
148
+ runtimeSessionId: threadId,
149
+ runtimeLaneKey: sessionKey,
150
+ };
151
+ return;
152
+ }
153
+ (this.opts.log ?? context.log)?.warn?.(
154
+ `codex-agent[${context.accountId}]: pending steer invalidated (subprocess died); falling through to normal dispatch`,
155
+ );
156
+ }
157
+
111
158
  await this.ensureStarted(context.log);
112
159
  // After ensureStarted resolves the subprocess could still die before we
113
160
  // capture the client (handleSubprocessClose nulls this.client). Yield a
@@ -260,7 +307,8 @@ export class CodexAppServerAdapter implements DispatchAdapter {
260
307
  threadId = freshThreadId;
261
308
  }
262
309
 
263
- void turnStartResult; // turnId comes back here but isn't needed — we key by threadId
310
+ const turnId = extractTurnId(turnStartResult);
311
+ if (turnId) this.activeTurnIds.set(threadId, turnId);
264
312
  yield {
265
313
  type: "runtime_session",
266
314
  runtimeSessionId: threadId,
@@ -300,8 +348,8 @@ export class CodexAppServerAdapter implements DispatchAdapter {
300
348
  } finally {
301
349
  releasePreparedAttachments();
302
350
  this.activeTurns.delete(threadId!);
351
+ this.activeTurnIds.delete(threadId!);
303
352
  if (!sawTurnEnd) {
304
- // Defensive: if we bailed early, make sure we leave no dangling sink.
305
353
  sink.close();
306
354
  }
307
355
  }
@@ -320,10 +368,18 @@ export class CodexAppServerAdapter implements DispatchAdapter {
320
368
  if (!parentThreadId) return null;
321
369
  const handle = this.opts.sessionManager.createForkSessionKey();
322
370
  try {
323
- const result = await client.sendRequest("thread/fork", {
371
+ const forkParams: Record<string, unknown> = {
324
372
  threadId: parentThreadId,
325
373
  ephemeral: true,
326
- });
374
+ };
375
+ if (this.opts.useParallProvider) {
376
+ forkParams.modelProvider = "parall";
377
+ }
378
+ if (this.opts.model) forkParams.model = this.opts.model;
379
+ if (this.opts.reasoningEffort) {
380
+ forkParams.config = { modelReasoningEffort: this.opts.reasoningEffort };
381
+ }
382
+ const result = await client.sendRequest("thread/fork", forkParams);
327
383
  const forkedThreadId = extractThreadId(result);
328
384
  if (!forkedThreadId) {
329
385
  this.opts.log?.warn?.("codex-agent: thread/fork returned no thread id");
@@ -352,6 +408,8 @@ export class CodexAppServerAdapter implements DispatchAdapter {
352
408
  this.proc = null;
353
409
  this.client = null;
354
410
  this.initialized = false;
411
+ this.activeTurnIds.clear();
412
+ this.pendingInjections.clear();
355
413
  if (client) client.dispose(new Error("adapter stopped"));
356
414
  if (proc && proc.exitCode === null && proc.signalCode === null) {
357
415
  if (!IS_WIN32 || !proc.pid || !killWin32Tree(proc.pid)) {
@@ -367,6 +425,8 @@ export class CodexAppServerAdapter implements DispatchAdapter {
367
425
  activeSink.close();
368
426
  }
369
427
  this.activeTurns.clear();
428
+ this.activeTurnIds.clear();
429
+ this.pendingInjections.clear();
370
430
  this.client = null;
371
431
  this.proc = null;
372
432
  this.initialized = false;
@@ -485,6 +545,8 @@ export class CodexAppServerAdapter implements DispatchAdapter {
485
545
  activeSink.close();
486
546
  }
487
547
  this.activeTurns.clear();
548
+ this.activeTurnIds.clear();
549
+ this.pendingInjections.clear();
488
550
  this.resumedThreadIds.clear();
489
551
  this.client = null;
490
552
  this.proc = null;
@@ -557,6 +619,7 @@ export class CodexAppServerAdapter implements DispatchAdapter {
557
619
  sink.push({ kind: "runtime", event });
558
620
  }
559
621
  if (method === "turn/completed") {
622
+ this.activeTurnIds.delete(threadId);
560
623
  sink.push({ kind: "turn_end", threadId });
561
624
  }
562
625
  }
@@ -653,6 +716,15 @@ function extractThreadId(result: unknown): string | undefined {
653
716
  return undefined;
654
717
  }
655
718
 
719
+ function extractTurnId(result: unknown): string | undefined {
720
+ if (!result || typeof result !== "object") return undefined;
721
+ const r = result as Record<string, unknown>;
722
+ if (typeof r.turnId === "string") return r.turnId;
723
+ const turn = r.turn as Record<string, unknown> | undefined;
724
+ if (turn && typeof turn.id === "string") return turn.id;
725
+ return undefined;
726
+ }
727
+
656
728
  function extractThreadIdFromNotification(params: unknown): string | undefined {
657
729
  if (!params || typeof params !== "object") return undefined;
658
730
  const p = params as Record<string, unknown>;