@parall/daemon 1.29.0 → 1.29.2

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.
@@ -453,6 +453,8 @@ var ENDPOINTS = {
453
453
  AUTH_CHECK_EMAIL: `${API_BASE}/auth/check-email`,
454
454
  AUTH_VERIFY_EMAIL: `${API_BASE}/auth/verify-email`,
455
455
  AUTH_RESEND_CODE: `${API_BASE}/auth/resend-code`,
456
+ AUTH_FORGOT_PASSWORD: `${API_BASE}/auth/forgot-password`,
457
+ AUTH_RESET_PASSWORD: `${API_BASE}/auth/reset-password`,
456
458
  // Users
457
459
  USERS_ME: `${API_BASE}/users/me`,
458
460
  USER_AVATAR: `${API_BASE}/users/me/avatar`,
@@ -487,6 +489,9 @@ var ENDPOINTS = {
487
489
  // Messages (global, by message ID)
488
490
  MESSAGE: (id) => `${API_BASE}/messages/${id}`,
489
491
  MESSAGE_REPLIES: (id) => `${API_BASE}/messages/${id}/replies`,
492
+ MESSAGE_WATCH: (id) => `${API_BASE}/messages/${id}/watch`,
493
+ MESSAGE_WATCHERS: (id) => `${API_BASE}/messages/${id}/watchers`,
494
+ MESSAGE_WATCHING: (id) => `${API_BASE}/messages/${id}/watching`,
490
495
  // Upload (org-scoped)
491
496
  UPLOAD_PRESIGN: (orgId) => `${API_BASE}/orgs/${orgId}/upload/presign`,
492
497
  UPLOAD_COMPLETE: (orgId) => `${API_BASE}/orgs/${orgId}/upload/complete`,
@@ -537,6 +542,9 @@ var ENDPOINTS = {
537
542
  // Attach/Detach bind an agent to/from a daemon Machine.
538
543
  MACHINE_ATTACH_AGENT: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}`,
539
544
  MACHINE_DETACH_AGENT: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}`,
545
+ MACHINE_WORKSPACE_STATES: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/workspace-states`,
546
+ MACHINE_AGENT_DAEMON_CONFIG: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/daemon-config`,
547
+ MACHINE_AGENT_WORKSPACE_SETUP: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/workspace/setup`,
540
548
  MACHINE_LLM_SOURCE: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/llm-source`,
541
549
  MACHINE_RUNTIME_AUTH: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth`,
542
550
  MACHINE_KEYS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys`,
@@ -550,6 +558,7 @@ var ENDPOINTS = {
550
558
  MACHINES_ME_AGENTS: `${API_BASE}/machines/me/agents`,
551
559
  MACHINES_ME_HEALTH: `${API_BASE}/machines/me/health`,
552
560
  MACHINES_ME_AGENT_LAUNCH_CREDENTIAL: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/launch-credential`,
561
+ MACHINES_ME_AGENT_WORKSPACE_STATE: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/workspace-state`,
553
562
  MACHINES_ME_WS_TICKET: `${API_BASE}/machines/me/ws/ticket`,
554
563
  // Tasks (org-scoped)
555
564
  TASKS: (orgId) => `${API_BASE}/orgs/${orgId}/tasks`,
@@ -729,7 +738,8 @@ var WS_EVENTS = {
729
738
  MACHINE_HELLO: "machine.hello",
730
739
  MACHINE_AGENT_ATTACHED: "machine.agent.attached",
731
740
  MACHINE_AGENT_DETACHED: "machine.agent.detached",
732
- MACHINE_STOP: "machine.stop"
741
+ MACHINE_STOP: "machine.stop",
742
+ MACHINE_WORKSPACE_SETUP_REQUESTED: "machine.workspace.setup.requested"
733
743
  };
734
744
 
735
745
  // ts/sdk/dist/client.js
@@ -749,7 +759,9 @@ var ParallClient = class _ParallClient {
749
759
  "/auth/logout",
750
760
  "/auth/verify-email",
751
761
  "/auth/resend-code",
752
- "/auth/check-email"
762
+ "/auth/check-email",
763
+ "/auth/forgot-password",
764
+ "/auth/reset-password"
753
765
  ]);
754
766
  /** Proactive refresh when token expires within this window (seconds). */
755
767
  static REFRESH_THRESHOLD_S = 5 * 60;
@@ -987,6 +999,12 @@ var ParallClient = class _ParallClient {
987
999
  async resendCode(email) {
988
1000
  return this.request("POST", ENDPOINTS.AUTH_RESEND_CODE, { email });
989
1001
  }
1002
+ async forgotPassword(email) {
1003
+ return this.request("POST", ENDPOINTS.AUTH_FORGOT_PASSWORD, { email });
1004
+ }
1005
+ async resetPassword(token, newPassword) {
1006
+ return this.request("POST", ENDPOINTS.AUTH_RESET_PASSWORD, { token, new_password: newPassword });
1007
+ }
990
1008
  // ---- WebSocket ----
991
1009
  async getWsTicket() {
992
1010
  return this.request("POST", ENDPOINTS.WS_TICKET);
@@ -1193,8 +1211,8 @@ var ParallClient = class _ParallClient {
1193
1211
  async completeUpload(orgId, attachmentId) {
1194
1212
  return this.request("POST", ENDPOINTS.UPLOAD_COMPLETE(orgId), { attachment_id: attachmentId });
1195
1213
  }
1196
- async getFileUrl(id) {
1197
- return this.request("GET", ENDPOINTS.FILE(id));
1214
+ async getFileUrl(id, opts) {
1215
+ return this.request("GET", ENDPOINTS.FILE(id), void 0, opts?.download ? { download: true } : void 0);
1198
1216
  }
1199
1217
  // ---- Approvals ----
1200
1218
  async getApproval(id) {
@@ -1391,6 +1409,16 @@ var ParallClient = class _ParallClient {
1391
1409
  async detachAgent(orgId, machineId, agentId) {
1392
1410
  return this.request("DELETE", ENDPOINTS.MACHINE_DETACH_AGENT(orgId, machineId, agentId));
1393
1411
  }
1412
+ async listAgentWorkspaceStates(orgId, machineId) {
1413
+ const res = await this.request("GET", ENDPOINTS.MACHINE_WORKSPACE_STATES(orgId, machineId));
1414
+ return res.data;
1415
+ }
1416
+ async patchAgentDaemonConfig(orgId, machineId, agentId, daemonConfig) {
1417
+ return this.request("PATCH", ENDPOINTS.MACHINE_AGENT_DAEMON_CONFIG(orgId, machineId, agentId), { daemon_config: daemonConfig });
1418
+ }
1419
+ async retryAgentWorkspaceSetup(orgId, machineId, agentId) {
1420
+ return this.request("POST", ENDPOINTS.MACHINE_AGENT_WORKSPACE_SETUP(orgId, machineId, agentId));
1421
+ }
1394
1422
  async patchMachineLLMSource(orgId, machineId, llmSource) {
1395
1423
  return this.request("PATCH", ENDPOINTS.MACHINE_LLM_SOURCE(orgId, machineId), { llm_source: llmSource });
1396
1424
  }
@@ -1436,6 +1464,12 @@ var ParallClient = class _ParallClient {
1436
1464
  async postMachineHeartbeat() {
1437
1465
  return this.request("POST", ENDPOINTS.MACHINES_ME_HEALTH);
1438
1466
  }
1467
+ async reportAgentWorkspaceState(agentId, state) {
1468
+ const res = await this.request("PUT", ENDPOINTS.MACHINES_ME_AGENT_WORKSPACE_STATE(agentId), state);
1469
+ if (res?.status === "ignored_stale") {
1470
+ throw new ApiError(409, "Workspace state report ignored as stale", "STALE_WORKSPACE_STATE");
1471
+ }
1472
+ }
1439
1473
  /**
1440
1474
  * `POST /machines/me/agents/{agentId}/launch-credential` — mint a
1441
1475
  * short-lived `agk_*` for one of this Machine's attached agents. The
@@ -1585,6 +1619,20 @@ var ParallClient = class _ParallClient {
1585
1619
  const res = await this.request("GET", ENDPOINTS.TASK_WATCHERS(orgId, taskId));
1586
1620
  return res.data;
1587
1621
  }
1622
+ async watchThread(threadRootId) {
1623
+ return this.request("POST", ENDPOINTS.MESSAGE_WATCH(threadRootId));
1624
+ }
1625
+ async unwatchThread(threadRootId) {
1626
+ return this.request("DELETE", ENDPOINTS.MESSAGE_WATCH(threadRootId));
1627
+ }
1628
+ async getThreadWatchers(threadRootId) {
1629
+ const res = await this.request("GET", ENDPOINTS.MESSAGE_WATCHERS(threadRootId));
1630
+ return res.data;
1631
+ }
1632
+ async isWatchingThread(threadRootId) {
1633
+ const res = await this.request("GET", ENDPOINTS.MESSAGE_WATCHING(threadRootId));
1634
+ return res.watching;
1635
+ }
1588
1636
  async getSubtasks(orgId, taskId) {
1589
1637
  const res = await this.request("GET", ENDPOINTS.TASK_SUBTASKS(orgId, taskId));
1590
1638
  return res.data;
@@ -1881,14 +1929,28 @@ var ParallClient = class _ParallClient {
1881
1929
  params.set("machine_id", opts.machine_id);
1882
1930
  if (opts?.unresolved_machine)
1883
1931
  params.set("unresolved_machine", "true");
1932
+ if (opts?.from)
1933
+ params.set("from", opts.from);
1934
+ if (opts?.to)
1935
+ params.set("to", opts.to);
1884
1936
  const qs = params.toString();
1885
1937
  return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}${qs ? `?${qs}` : ""}`);
1886
1938
  }
1887
- async listBillingTransactionAgentGroups(orgId) {
1888
- return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?group_by=agent`);
1889
- }
1890
- async listBillingTransactionMachineGroups(orgId) {
1891
- return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?group_by=machine`);
1939
+ async listBillingTransactionAgentGroups(orgId, opts) {
1940
+ const params = new URLSearchParams({ group_by: "agent" });
1941
+ if (opts?.from)
1942
+ params.set("from", opts.from);
1943
+ if (opts?.to)
1944
+ params.set("to", opts.to);
1945
+ return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?${params}`);
1946
+ }
1947
+ async listBillingTransactionMachineGroups(orgId, opts) {
1948
+ const params = new URLSearchParams({ group_by: "machine" });
1949
+ if (opts?.from)
1950
+ params.set("from", opts.from);
1951
+ if (opts?.to)
1952
+ params.set("to", opts.to);
1953
+ return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?${params}`);
1892
1954
  }
1893
1955
  async createCheckout(orgId, req) {
1894
1956
  return this.request("POST", ENDPOINTS.BILLING_CHECKOUT(orgId), req);
@@ -1939,6 +2001,12 @@ var ApiError = class extends Error {
1939
2001
  };
1940
2002
 
1941
2003
  // ts/sdk/dist/ws.js
2004
+ function isRetryableNetworkError(err) {
2005
+ return err instanceof Error && err.name === "ApiError" && "status" in err && err.status === 0;
2006
+ }
2007
+ function isBrowserRuntime() {
2008
+ return typeof window !== "undefined";
2009
+ }
1942
2010
  var ParallWs = class {
1943
2011
  ws = null;
1944
2012
  options;
@@ -1974,7 +2042,11 @@ var ParallWs = class {
1974
2042
  try {
1975
2043
  ticket = await this.options.getTicket();
1976
2044
  } catch (err) {
1977
- console.error("Failed to get WS ticket:", err);
2045
+ if (isBrowserRuntime() && isRetryableNetworkError(err)) {
2046
+ console.warn("Failed to get WS ticket:", err);
2047
+ } else {
2048
+ console.error("Failed to get WS ticket:", err);
2049
+ }
1978
2050
  if (this.options.reconnect) {
1979
2051
  this.scheduleReconnect();
1980
2052
  } else {
@@ -2303,6 +2375,7 @@ var ParallAgentGateway = class {
2303
2375
  opts;
2304
2376
  chatInfoMap = /* @__PURE__ */ new Map();
2305
2377
  activeDispatches = /* @__PURE__ */ new Map();
2378
+ injectedTypingCounts = /* @__PURE__ */ new Map();
2306
2379
  dispatchedTasks = /* @__PURE__ */ new Set();
2307
2380
  dispatchedMessages = /* @__PURE__ */ new Set();
2308
2381
  forkStates = /* @__PURE__ */ new Map();
@@ -2497,6 +2570,34 @@ var ParallAgentGateway = class {
2497
2570
  if (this.opts.ws.state === "connected")
2498
2571
  this.opts.ws.sendTyping(chatId, "stop");
2499
2572
  }
2573
+ shouldShowTyping(event) {
2574
+ return event.type === "message" && event.targetId.startsWith("cht_") && !event.noReply;
2575
+ }
2576
+ startInjectedTyping(event) {
2577
+ if (!this.shouldShowTyping(event))
2578
+ return;
2579
+ this.startTyping(event.targetId);
2580
+ this.injectedTypingCounts.set(event.targetId, (this.injectedTypingCounts.get(event.targetId) ?? 0) + 1);
2581
+ }
2582
+ takeInjectedTypingCount(chatId) {
2583
+ const count = this.injectedTypingCounts.get(chatId) ?? 0;
2584
+ this.injectedTypingCounts.delete(chatId);
2585
+ return count;
2586
+ }
2587
+ async runDispatchWithTyping(event, sessionKey, bodyForAgent, earlierEvents = [], captureText, opts = {}) {
2588
+ const showTyping = !opts.suppressStart && (this.shouldShowTyping(event) || earlierEvents.some((e) => this.shouldShowTyping(e)));
2589
+ if (showTyping)
2590
+ this.startTyping(event.targetId);
2591
+ try {
2592
+ return await this.runDispatch(event, sessionKey, bodyForAgent, earlierEvents, captureText);
2593
+ } finally {
2594
+ if (showTyping)
2595
+ this.stopTyping(event.targetId);
2596
+ for (let i = 0; i < (opts.injectedTypingCount ?? 0); i++) {
2597
+ this.stopTyping(event.targetId);
2598
+ }
2599
+ }
2600
+ }
2500
2601
  buildDispatchContext(event, sessionKey) {
2501
2602
  const binding = this.sessionBindings.get(sessionKey);
2502
2603
  return {
@@ -2529,7 +2630,8 @@ var ParallAgentGateway = class {
2529
2630
  trigger_ref: event.type === "task" ? { task_id: event.targetId } : event.type === "task_comment" ? { comment_id: event.messageId, task_id: event.targetId } : event.type === "schedule" ? { schedule_id: event.targetId, run_id: event.messageId } : event.type === "approval" ? { approval_id: event.messageId } : { message_id: event.messageId },
2530
2631
  sender_id: event.senderId,
2531
2632
  sender_name: event.senderName,
2532
- summary: event.body.substring(0, 200)
2633
+ summary: event.body.substring(0, 200),
2634
+ ...event.sentAt ? { sent_at: event.sentAt } : {}
2533
2635
  }
2534
2636
  });
2535
2637
  } catch (err) {
@@ -2828,7 +2930,7 @@ var ParallAgentGateway = class {
2828
2930
  const earlier = events.slice(0, -1);
2829
2931
  try {
2830
2932
  const batchText = [];
2831
- const dispatched = await this.runDispatch(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
2933
+ const dispatched = await this.runDispatchWithTyping(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
2832
2934
  if (!dispatched) {
2833
2935
  for (const item of items) {
2834
2936
  item.resolve(false);
@@ -2921,12 +3023,13 @@ var ParallAgentGateway = class {
2921
3023
  }
2922
3024
  const event = events[events.length - 1];
2923
3025
  const earlier = events.slice(0, -1);
2924
- const skipForkSplice = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
2925
- const pendingFork = skipForkSplice ? [] : this.dispatchState.pendingForkResults.splice(0);
3026
+ const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
3027
+ const injectedTypingCount = hasPendingInjections ? this.takeInjectedTypingCount(event.targetId) : 0;
3028
+ const pendingFork = hasPendingInjections ? [] : this.dispatchState.pendingForkResults.splice(0);
2926
3029
  const forkPrefix = buildForkResultPrefix(pendingFork);
2927
3030
  this.dispatchState.mainCurrentTargetId = event.targetId;
2928
3031
  this.dispatchState.mainPreDispatchBranchPoint = this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
2929
- const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
3032
+ const dispatched = await this.runDispatchWithTyping(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier, void 0, { suppressStart: injectedTypingCount > 0, injectedTypingCount });
2930
3033
  if (!dispatched) {
2931
3034
  this.dispatchState.mainBuffer.unshift(...events);
2932
3035
  this.dispatchState.pendingForkResults.unshift(...pendingFork);
@@ -2960,7 +3063,7 @@ var ParallAgentGateway = class {
2960
3063
  this.dispatchState.mainPreDispatchBranchPoint = this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
2961
3064
  let dispatched = false;
2962
3065
  try {
2963
- dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
3066
+ dispatched = await this.runDispatchWithTyping(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
2964
3067
  if (!dispatched) {
2965
3068
  this.dispatchState.pendingForkResults.unshift(...pendingFork);
2966
3069
  }
@@ -2973,10 +3076,15 @@ var ParallAgentGateway = class {
2973
3076
  if (this.shuttingDown) {
2974
3077
  return false;
2975
3078
  }
2976
- if (this.dispatchState.mainCurrentTargetId === event.targetId && this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
2977
- this.opts.log?.info(`parall[${this.opts.accountId}]: steer injected to stdin for ${event.messageId} (will drain for bookkeeping)`);
2978
- }
2979
3079
  this.dispatchState.mainBuffer.push(event);
3080
+ if (this.dispatchState.mainCurrentTargetId === event.targetId && await this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
3081
+ this.startInjectedTyping(event);
3082
+ this.opts.log?.info(`parall[${this.opts.accountId}]: steer injected for ${event.messageId} (will drain for bookkeeping)`);
3083
+ }
3084
+ if (!this.dispatchState.mainDispatching && !this.draining && this.dispatchState.mainBuffer.length > 0) {
3085
+ this.dispatchState.mainDispatching = true;
3086
+ void this.drainMainBuffer();
3087
+ }
2980
3088
  return false;
2981
3089
  }
2982
3090
  case "buffer-fork": {
@@ -3078,6 +3186,7 @@ var ParallAgentGateway = class {
3078
3186
  threadRootId: message.thread_root_id ?? void 0,
3079
3187
  noReply: message.hints?.no_reply ?? false,
3080
3188
  attachments: attachments.length > 0 ? attachments : void 0,
3189
+ sentAt: message.created_at,
3081
3190
  ackSourceType: "message",
3082
3191
  ackSourceId: message.id
3083
3192
  }
@@ -3099,9 +3208,6 @@ var ParallAgentGateway = class {
3099
3208
  return;
3100
3209
  }
3101
3210
  const event = decision.event;
3102
- const willDispatch = !this.dispatchState.mainDispatching || this.dispatchState.mainCurrentTargetId !== chatId;
3103
- if (willDispatch)
3104
- this.startTyping(chatId);
3105
3211
  try {
3106
3212
  const dispatched = await this.handleInboundEvent(event);
3107
3213
  if (dispatched) {
@@ -3113,9 +3219,6 @@ var ParallAgentGateway = class {
3113
3219
  } catch (err) {
3114
3220
  this.opts.log?.error(`parall[${this.opts.accountId}]: event dispatch failed for ${data.id}: ${String(err)}`);
3115
3221
  this.dispatchedMessages.delete(data.id);
3116
- } finally {
3117
- if (willDispatch)
3118
- this.stopTyping(chatId);
3119
3222
  }
3120
3223
  }
3121
3224
  async handleTaskAssignment(task, ackSourceId) {
@@ -3145,6 +3248,7 @@ var ParallAgentGateway = class {
3145
3248
  senderName: "system",
3146
3249
  messageId: task.id,
3147
3250
  body: parts.join("\n"),
3251
+ sentAt: task.updated_at ?? task.created_at,
3148
3252
  ackSourceType: "task_activity",
3149
3253
  ackSourceId
3150
3254
  };
@@ -5143,6 +5247,8 @@ var CodexAppServerAdapter = class {
5143
5247
  initialized = false;
5144
5248
  startPromise = null;
5145
5249
  activeTurns = /* @__PURE__ */ new Map();
5250
+ activeTurnIds = /* @__PURE__ */ new Map();
5251
+ pendingInjections = /* @__PURE__ */ new Map();
5146
5252
  resumedThreadIds = /* @__PURE__ */ new Set();
5147
5253
  stopping = false;
5148
5254
  /**
@@ -5171,7 +5277,48 @@ var CodexAppServerAdapter = class {
5171
5277
  if (config.reasoningEffort !== void 0)
5172
5278
  this.opts.reasoningEffort = config.reasoningEffort ?? void 0;
5173
5279
  }
5280
+ async enqueueDuringDispatch(sessionKey, body) {
5281
+ const client = this.client;
5282
+ if (!client || client.isDisposed())
5283
+ return false;
5284
+ const threadId = this.opts.sessionManager.getThreadId(sessionKey);
5285
+ if (!threadId)
5286
+ return false;
5287
+ const turnId = this.activeTurnIds.get(threadId);
5288
+ if (!turnId)
5289
+ return false;
5290
+ try {
5291
+ await client.sendRequest("turn/steer", {
5292
+ threadId,
5293
+ expectedTurnId: turnId,
5294
+ input: buildTurnInput(body, [])
5295
+ });
5296
+ this.pendingInjections.set(sessionKey, (this.pendingInjections.get(sessionKey) ?? 0) + 1);
5297
+ return true;
5298
+ } catch (err) {
5299
+ this.opts.log?.warn?.(`codex-agent: turn/steer failed: ${errToString(err)}`);
5300
+ return false;
5301
+ }
5302
+ }
5303
+ hasPendingInjections(sessionKey) {
5304
+ return (this.pendingInjections.get(sessionKey) ?? 0) > 0;
5305
+ }
5174
5306
  async *dispatch({ event, bodyForAgent, sessionKey, context }) {
5307
+ const pending = this.pendingInjections.get(sessionKey) ?? 0;
5308
+ if (pending > 0) {
5309
+ this.pendingInjections.delete(sessionKey);
5310
+ const threadId2 = this.opts.sessionManager.getThreadId(sessionKey);
5311
+ if (threadId2 && this.client && !this.client.isDisposed()) {
5312
+ (this.opts.log ?? context.log)?.info?.(`codex-agent[${context.accountId}]: ${pending} steer injection(s) already sent; skipping turn/start`);
5313
+ yield {
5314
+ type: "runtime_session",
5315
+ runtimeSessionId: threadId2,
5316
+ runtimeLaneKey: sessionKey
5317
+ };
5318
+ return;
5319
+ }
5320
+ (this.opts.log ?? context.log)?.warn?.(`codex-agent[${context.accountId}]: pending steer invalidated (subprocess died); falling through to normal dispatch`);
5321
+ }
5175
5322
  await this.ensureStarted(context.log);
5176
5323
  const client = this.client;
5177
5324
  if (!client) {
@@ -5284,7 +5431,9 @@ var CodexAppServerAdapter = class {
5284
5431
  this.resumedThreadIds.add(freshThreadId);
5285
5432
  threadId = freshThreadId;
5286
5433
  }
5287
- void turnStartResult;
5434
+ const turnId = extractTurnId(turnStartResult);
5435
+ if (turnId)
5436
+ this.activeTurnIds.set(threadId, turnId);
5288
5437
  yield {
5289
5438
  type: "runtime_session",
5290
5439
  runtimeSessionId: threadId,
@@ -5318,6 +5467,7 @@ var CodexAppServerAdapter = class {
5318
5467
  } finally {
5319
5468
  releasePreparedAttachments();
5320
5469
  this.activeTurns.delete(threadId);
5470
+ this.activeTurnIds.delete(threadId);
5321
5471
  if (!sawTurnEnd) {
5322
5472
  sink.close();
5323
5473
  }
@@ -5335,10 +5485,19 @@ var CodexAppServerAdapter = class {
5335
5485
  return null;
5336
5486
  const handle = this.opts.sessionManager.createForkSessionKey();
5337
5487
  try {
5338
- const result = await client.sendRequest("thread/fork", {
5488
+ const forkParams = {
5339
5489
  threadId: parentThreadId,
5340
5490
  ephemeral: true
5341
- });
5491
+ };
5492
+ if (this.opts.useParallProvider) {
5493
+ forkParams.modelProvider = "parall";
5494
+ }
5495
+ if (this.opts.model)
5496
+ forkParams.model = this.opts.model;
5497
+ if (this.opts.reasoningEffort) {
5498
+ forkParams.config = { modelReasoningEffort: this.opts.reasoningEffort };
5499
+ }
5500
+ const result = await client.sendRequest("thread/fork", forkParams);
5342
5501
  const forkedThreadId = extractThreadId(result);
5343
5502
  if (!forkedThreadId) {
5344
5503
  this.opts.log?.warn?.("codex-agent: thread/fork returned no thread id");
@@ -5364,6 +5523,8 @@ var CodexAppServerAdapter = class {
5364
5523
  this.proc = null;
5365
5524
  this.client = null;
5366
5525
  this.initialized = false;
5526
+ this.activeTurnIds.clear();
5527
+ this.pendingInjections.clear();
5367
5528
  if (client)
5368
5529
  client.dispose(new Error("adapter stopped"));
5369
5530
  if (proc && proc.exitCode === null && proc.signalCode === null) {
@@ -5379,6 +5540,8 @@ var CodexAppServerAdapter = class {
5379
5540
  activeSink.close();
5380
5541
  }
5381
5542
  this.activeTurns.clear();
5543
+ this.activeTurnIds.clear();
5544
+ this.pendingInjections.clear();
5382
5545
  this.client = null;
5383
5546
  this.proc = null;
5384
5547
  this.initialized = false;
@@ -5462,6 +5625,8 @@ var CodexAppServerAdapter = class {
5462
5625
  activeSink.close();
5463
5626
  }
5464
5627
  this.activeTurns.clear();
5628
+ this.activeTurnIds.clear();
5629
+ this.pendingInjections.clear();
5465
5630
  this.resumedThreadIds.clear();
5466
5631
  this.client = null;
5467
5632
  this.proc = null;
@@ -5507,6 +5672,7 @@ var CodexAppServerAdapter = class {
5507
5672
  sink.push({ kind: "runtime", event });
5508
5673
  }
5509
5674
  if (method === "turn/completed") {
5675
+ this.activeTurnIds.delete(threadId);
5510
5676
  sink.push({ kind: "turn_end", threadId });
5511
5677
  }
5512
5678
  }
@@ -5584,6 +5750,17 @@ function extractThreadId(result) {
5584
5750
  return thread.id;
5585
5751
  return void 0;
5586
5752
  }
5753
+ function extractTurnId(result) {
5754
+ if (!result || typeof result !== "object")
5755
+ return void 0;
5756
+ const r = result;
5757
+ if (typeof r.turnId === "string")
5758
+ return r.turnId;
5759
+ const turn = r.turn;
5760
+ if (turn && typeof turn.id === "string")
5761
+ return turn.id;
5762
+ return void 0;
5763
+ }
5587
5764
  function extractThreadIdFromNotification(params) {
5588
5765
  if (!params || typeof params !== "object")
5589
5766
  return void 0;