@parall/claude-agent 1.31.0 → 1.32.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.
package/src/dispatch.ts CHANGED
@@ -1,11 +1,11 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { randomUUID } from "node:crypto";
4
- import { execSync, spawn } from "node:child_process";
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { execSync, spawn } from 'node:child_process';
5
5
  import {
6
6
  appendPreparedLocalAttachmentRefs,
7
7
  pinLocalAttachmentPaths,
8
- } from "@parall/agent-core/internal/attachment-input";
8
+ } from '@parall/agent-core/internal/attachment-input';
9
9
  import type {
10
10
  CleanupForkOpts,
11
11
  DispatchAdapter,
@@ -13,26 +13,23 @@ import type {
13
13
  ForkOpts,
14
14
  GatewayLogger,
15
15
  RuntimeEvent,
16
- } from "@parall/agent-core";
17
- import type { ClaudeAgentConfig } from "./config.js";
18
- import { parseClaudeStreamJson, type ClaudeParsedEvent } from "./output-parser.js";
19
- import {
20
- ClaudeSessionManager,
21
- type ClaudeProcessHandle,
22
- } from "./session-manager.js";
16
+ } from '@parall/agent-core';
17
+ import type { ClaudeAgentConfig } from './config.js';
18
+ import { parseClaudeStreamJson, type ClaudeParsedEvent } from './output-parser.js';
19
+ import { ClaudeSessionManager, type ClaudeProcessHandle } from './session-manager.js';
23
20
 
24
21
  type ClaudeCodeAdapterOptions = Pick<
25
22
  ClaudeAgentConfig,
26
- | "additionalDirs"
27
- | "allowApiKey"
28
- | "allowedTools"
29
- | "appendSystemPrompt"
30
- | "claudeBin"
31
- | "claudeHome"
32
- | "disallowedTools"
33
- | "model"
34
- | "permissionMode"
35
- | "workspaceDir"
23
+ | 'additionalDirs'
24
+ | 'allowApiKey'
25
+ | 'allowedTools'
26
+ | 'appendSystemPrompt'
27
+ | 'claudeBin'
28
+ | 'claudeHome'
29
+ | 'disallowedTools'
30
+ | 'model'
31
+ | 'permissionMode'
32
+ | 'workspaceDir'
36
33
  > & {
37
34
  sessionManager: ClaudeSessionManager;
38
35
  apiUrl: string;
@@ -43,7 +40,7 @@ type ClaudeCodeAdapterOptions = Pick<
43
40
  stepIdFilePathForSession?: (sessionKey: string) => string;
44
41
  };
45
42
 
46
- const IS_WIN32 = process.platform === "win32";
43
+ const IS_WIN32 = process.platform === 'win32';
47
44
 
48
45
  function quoteWin32Arg(arg: string): string {
49
46
  if (!/[\s"&|^<>()]/.test(arg)) return arg;
@@ -52,15 +49,17 @@ function quoteWin32Arg(arg: string): string {
52
49
 
53
50
  function killWin32Tree(pid: number): boolean {
54
51
  try {
55
- execSync(`taskkill /T /F /PID ${pid}`, { windowsHide: true, stdio: "ignore" });
52
+ execSync(`taskkill /T /F /PID ${pid}`, { windowsHide: true, stdio: 'ignore' });
56
53
  return true;
57
- } catch { return false; }
54
+ } catch {
55
+ return false;
56
+ }
58
57
  }
59
58
 
60
59
  export function buildSpawnEnv(
61
60
  parentEnv: NodeJS.ProcessEnv,
62
61
  claudeHome: string,
63
- context: DispatchOpts["context"],
62
+ context: DispatchOpts['context'],
64
63
  opts: { allowApiKey: boolean; effortLevel?: string },
65
64
  ): NodeJS.ProcessEnv {
66
65
  const env: NodeJS.ProcessEnv = { ...parentEnv };
@@ -74,12 +73,12 @@ export function buildSpawnEnv(
74
73
  PRLL_API_URL: context.apiUrl,
75
74
  PRLL_API_KEY: context.apiKey,
76
75
  PRLL_ORG_ID: context.orgId,
77
- PRLL_SESSION_ID: context.sessionId ?? "",
78
- PRLL_CHAT_ID: context.chatId ?? "",
79
- PRLL_TRIGGER_MESSAGE_ID: context.triggerMessageId ?? "",
80
- PRLL_NO_REPLY: context.noReply ? "1" : "",
81
- PRLL_CONTEXT_FILE: context.contextFilePath ?? "",
82
- PRLL_STEP_ID_FILE: context.stepIdFilePath ?? "",
76
+ PRLL_SESSION_ID: context.sessionId ?? '',
77
+ PRLL_CHAT_ID: context.chatId ?? '',
78
+ PRLL_TRIGGER_MESSAGE_ID: context.triggerMessageId ?? '',
79
+ PRLL_NO_REPLY: context.noReply ? '1' : '',
80
+ PRLL_CONTEXT_FILE: context.contextFilePath ?? '',
81
+ PRLL_STEP_ID_FILE: context.stepIdFilePath ?? '',
83
82
  };
84
83
  if (opts.effortLevel) {
85
84
  result.CLAUDE_CODE_EFFORT_LEVEL = opts.effortLevel;
@@ -113,8 +112,12 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
113
112
  this._model = opts.model;
114
113
  }
115
114
 
116
- get currentModel(): string | undefined { return this._model; }
117
- get currentEffort(): string | undefined { return this._effortLevel; }
115
+ get currentModel(): string | undefined {
116
+ return this._model;
117
+ }
118
+ get currentEffort(): string | undefined {
119
+ return this._effortLevel;
120
+ }
118
121
 
119
122
  updateConfig(config: { model?: string | null; effort?: string | null }): void {
120
123
  const modelChanged = config.model !== undefined && config.model !== this._model;
@@ -142,11 +145,28 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
142
145
  }
143
146
  }
144
147
 
148
+ abortDispatch(sessionKey: string): void {
149
+ this.pendingInjections.delete(sessionKey);
150
+ const state = this.processes.get(sessionKey);
151
+ if (!state || state.done) return;
152
+ state.done = true;
153
+ try {
154
+ state.handle.proc.stdin.end();
155
+ } catch {
156
+ /* best-effort */
157
+ }
158
+ }
159
+
145
160
  hasPendingInjections(sessionKey: string): boolean {
146
161
  return (this.pendingInjections.get(sessionKey) ?? 0) > 0;
147
162
  }
148
163
 
149
- async *dispatch({ event, bodyForAgent, sessionKey, context }: DispatchOpts): AsyncIterable<RuntimeEvent> {
164
+ async *dispatch({
165
+ event,
166
+ bodyForAgent,
167
+ sessionKey,
168
+ context,
169
+ }: DispatchOpts): AsyncIterable<RuntimeEvent> {
150
170
  const pending = this.pendingInjections.get(sessionKey) ?? 0;
151
171
  if (pending > 0) {
152
172
  this.pendingInjections.delete(sessionKey);
@@ -167,9 +187,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
167
187
  promptBody = prepared.body;
168
188
  releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
169
189
  } catch (err) {
170
- context.log?.warn?.(
171
- `failed to prepare local attachments: ${String(err)}`,
172
- );
190
+ context.log?.warn?.(`failed to prepare local attachments: ${String(err)}`);
173
191
  }
174
192
 
175
193
  try {
@@ -186,8 +204,14 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
186
204
  getSessionHistoryPath(sessionKey: string): string | undefined {
187
205
  const sessionId = this.opts.sessionManager.getSessionId(sessionKey);
188
206
  if (!sessionId) return undefined;
189
- const projectSlug = this.opts.workspaceDir.replace(/[/.]/g, "-");
190
- const filePath = path.join(this.opts.claudeHome, ".claude", "projects", projectSlug, `${sessionId}.jsonl`);
207
+ const projectSlug = this.opts.workspaceDir.replace(/[/.]/g, '-');
208
+ const filePath = path.join(
209
+ this.opts.claudeHome,
210
+ '.claude',
211
+ 'projects',
212
+ projectSlug,
213
+ `${sessionId}.jsonl`,
214
+ );
191
215
  return fs.existsSync(filePath) ? filePath : undefined;
192
216
  }
193
217
 
@@ -217,7 +241,9 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
217
241
  await this.opts.sessionManager.shutdownAll();
218
242
  }
219
243
 
220
- private static readonly STEER_TURN_TIMEOUT_MS = 10_000;
244
+ // Steer-turn read timeout. Overridable via PRLL_STEER_TURN_TIMEOUT_MS (ms),
245
+ // chiefly so tests can exercise the timeout path without a 10s wait.
246
+ private readonly steerTurnTimeoutMs = Number(process.env.PRLL_STEER_TURN_TIMEOUT_MS) || 10_000;
221
247
 
222
248
  /**
223
249
  * Consume a steer turn whose message was already written to stdin via
@@ -235,20 +261,31 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
235
261
  ): AsyncGenerator<RuntimeEvent> {
236
262
  const state = this.processes.get(sessionKey);
237
263
  if (!state || state.done) {
238
- throw new Error("process dead during steer consumption");
264
+ throw new Error('process dead during steer consumption');
239
265
  }
240
266
 
241
267
  const groupKey = randomUUID();
242
268
 
243
- const parserNext = state.parser.next();
269
+ // Reuse a pull already issued by a prior steer timeout instead of issuing a
270
+ // fresh one. A burst of N steers all takes the pending-skip path, which calls
271
+ // this method N times in a loop. Issuing a new state.parser.next() on each
272
+ // call while a previous pull is still in flight queues multiple reads on the
273
+ // same async generator, but only one can be stashed in the single-slot
274
+ // state.steerReadPending — every earlier pull is then consumed-and-dropped,
275
+ // silently losing parser events. When a dropped event is a tool_call, its
276
+ // tool_result later orphans into "call_id does not match any tool_call".
277
+ // Threading the single in-flight pull through every call keeps at most one
278
+ // outstanding read and loses nothing.
279
+ const parserNext = state.steerReadPending ?? state.parser.next();
280
+ state.steerReadPending = undefined;
244
281
  const firstRead = await Promise.race([
245
- parserNext.then((r) => ({ kind: "value" as const, result: r })),
246
- new Promise<{ kind: "timeout" }>((resolve) =>
247
- setTimeout(() => resolve({ kind: "timeout" }), ClaudeCodeAdapter.STEER_TURN_TIMEOUT_MS),
282
+ parserNext.then((r) => ({ kind: 'value' as const, result: r })),
283
+ new Promise<{ kind: 'timeout' }>((resolve) =>
284
+ setTimeout(() => resolve({ kind: 'timeout' }), this.steerTurnTimeoutMs),
248
285
  ),
249
286
  ]);
250
287
 
251
- if (firstRead.kind === "timeout") {
288
+ if (firstRead.kind === 'timeout') {
252
289
  state.steerReadPending = parserNext;
253
290
  log?.info?.(`steer turn timeout — steer was incorporated into previous turn`);
254
291
  return;
@@ -260,21 +297,25 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
260
297
  if (next.done) {
261
298
  state.done = true;
262
299
  this.processes.delete(sessionKey);
263
- throw new Error("process exited while consuming steer turn");
300
+ throw new Error('process exited while consuming steer turn');
264
301
  }
265
302
  const parsed = next.value;
266
303
 
267
- if (parsed.type === "session_id") {
304
+ if (parsed.type === 'session_id') {
268
305
  this.opts.sessionManager.recordSessionId(sessionKey, parsed.sessionId);
269
- yield { type: "runtime_session", runtimeSessionId: parsed.sessionId, runtimeLaneKey: sessionKey };
270
- } else if (parsed.type === "turn_end") {
306
+ yield {
307
+ type: 'runtime_session',
308
+ runtimeSessionId: parsed.sessionId,
309
+ runtimeLaneKey: sessionKey,
310
+ };
311
+ } else if (parsed.type === 'turn_end') {
271
312
  if (state.needsRestart) this.killProcess(sessionKey, state);
272
313
  return;
273
- } else if (parsed.type === "error") {
314
+ } else if (parsed.type === 'error') {
274
315
  yield parsed;
275
- } else if (parsed.type === "text") {
316
+ } else if (parsed.type === 'text') {
276
317
  yield { ...parsed, project: false, groupKey };
277
- } else if (parsed.type === "runtime_session") {
318
+ } else if (parsed.type === 'runtime_session') {
278
319
  yield parsed;
279
320
  } else {
280
321
  yield { ...parsed, groupKey };
@@ -292,7 +333,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
292
333
  try {
293
334
  state = this.ensureProcess(sessionKey, log);
294
335
  } catch (err) {
295
- yield { type: "error", message: `Claude spawn failed: ${String(err)}` };
336
+ yield { type: 'error', message: `Claude spawn failed: ${String(err)}` };
296
337
  return;
297
338
  }
298
339
  const groupKey = randomUUID();
@@ -301,7 +342,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
301
342
  try {
302
343
  this.writeUserMessage(state.handle, promptBody);
303
344
  } catch (err) {
304
- yield { type: "error", message: `Claude stdin write failed: ${String(err)}` };
345
+ yield { type: 'error', message: `Claude stdin write failed: ${String(err)}` };
305
346
  this.killProcess(sessionKey, state);
306
347
  return;
307
348
  }
@@ -311,18 +352,22 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
311
352
  state.steerReadPending = undefined;
312
353
  if (!orphaned.done) {
313
354
  const parsed = orphaned.value;
314
- if (parsed.type === "session_id") {
355
+ if (parsed.type === 'session_id') {
315
356
  this.opts.sessionManager.recordSessionId(sessionKey, parsed.sessionId);
316
- yield { type: "runtime_session", runtimeSessionId: parsed.sessionId, runtimeLaneKey: sessionKey };
317
- } else if (parsed.type === "turn_end") {
357
+ yield {
358
+ type: 'runtime_session',
359
+ runtimeSessionId: parsed.sessionId,
360
+ runtimeLaneKey: sessionKey,
361
+ };
362
+ } else if (parsed.type === 'turn_end') {
318
363
  if (state.needsRestart) this.killProcess(sessionKey, state);
319
364
  return;
320
- } else if (parsed.type === "error") {
365
+ } else if (parsed.type === 'error') {
321
366
  sawError = true;
322
367
  yield parsed;
323
- } else if (parsed.type === "text") {
368
+ } else if (parsed.type === 'text') {
324
369
  yield { ...parsed, project: false, groupKey };
325
- } else if (parsed.type === "runtime_session") {
370
+ } else if (parsed.type === 'runtime_session') {
326
371
  yield parsed;
327
372
  } else {
328
373
  yield { ...parsed, groupKey };
@@ -336,16 +381,19 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
336
381
  if (next.done) {
337
382
  state.done = true;
338
383
  this.processes.delete(sessionKey);
339
- const detail = state.handle.stderrChunks.join("").trim();
340
- const exit = await state.handle.exitPromise.catch(() => ({ code: null, signal: null } as const));
384
+ const detail = state.handle.stderrChunks.join('').trim();
385
+ const exit = await state.handle.exitPromise.catch(
386
+ () => ({ code: null, signal: null }) as const,
387
+ );
341
388
  if (detail) {
342
389
  log?.warn?.(`subprocess stderr: ${detail}`);
343
390
  }
344
391
  if (!sawError) {
345
392
  yield {
346
- type: "error",
347
- message: detail
348
- || `Claude exited with code ${exit.code ?? "unknown"}${exit.signal ? ` (${exit.signal})` : ""}`,
393
+ type: 'error',
394
+ message:
395
+ detail ||
396
+ `Claude exited with code ${exit.code ?? 'unknown'}${exit.signal ? ` (${exit.signal})` : ''}`,
349
397
  };
350
398
  }
351
399
  return;
@@ -353,35 +401,35 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
353
401
 
354
402
  const parsed = next.value;
355
403
 
356
- if (parsed.type === "session_id") {
404
+ if (parsed.type === 'session_id') {
357
405
  this.opts.sessionManager.recordSessionId(sessionKey, parsed.sessionId);
358
406
  yield {
359
- type: "runtime_session",
407
+ type: 'runtime_session',
360
408
  runtimeSessionId: parsed.sessionId,
361
409
  runtimeLaneKey: sessionKey,
362
410
  };
363
411
  continue;
364
412
  }
365
413
 
366
- if (parsed.type === "turn_end") {
414
+ if (parsed.type === 'turn_end') {
367
415
  if (state.needsRestart) {
368
416
  this.killProcess(sessionKey, state);
369
417
  }
370
418
  return;
371
419
  }
372
420
 
373
- if (parsed.type === "error") {
421
+ if (parsed.type === 'error') {
374
422
  sawError = true;
375
423
  yield parsed;
376
424
  continue;
377
425
  }
378
426
 
379
- if (parsed.type === "text") {
427
+ if (parsed.type === 'text') {
380
428
  yield { ...parsed, project: false, groupKey };
381
429
  continue;
382
430
  }
383
431
 
384
- if (parsed.type === "runtime_session") {
432
+ if (parsed.type === 'runtime_session') {
385
433
  yield parsed;
386
434
  continue;
387
435
  }
@@ -392,7 +440,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
392
440
 
393
441
  private ensureProcess(sessionKey: string, log: GatewayLogger | undefined): ProcessState {
394
442
  if (this.shuttingDown) {
395
- throw new Error("adapter shutting down, refusing new process");
443
+ throw new Error('adapter shutting down, refusing new process');
396
444
  }
397
445
 
398
446
  const existing = this.processes.get(sessionKey);
@@ -425,39 +473,43 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
425
473
  );
426
474
 
427
475
  log?.info(
428
- `spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`,
476
+ `spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || 'default'}, effort=${this._effortLevel || 'default'}, mode=${this.opts.permissionMode})`,
429
477
  );
430
478
 
431
479
  const proc = spawn(
432
480
  IS_WIN32 ? quoteWin32Arg(this.opts.claudeBin) : this.opts.claudeBin,
433
- IS_WIN32 ? args.map(quoteWin32Arg) : args, {
434
- cwd: this.opts.workspaceDir,
435
- env,
436
- stdio: ["pipe", "pipe", "pipe"],
437
- shell: IS_WIN32,
438
- });
481
+ IS_WIN32 ? args.map(quoteWin32Arg) : args,
482
+ {
483
+ cwd: this.opts.workspaceDir,
484
+ env,
485
+ stdio: ['pipe', 'pipe', 'pipe'],
486
+ shell: IS_WIN32,
487
+ },
488
+ );
439
489
 
440
490
  if (!proc.stdout || !proc.stderr || !proc.stdin) {
441
- throw new Error("Claude subprocess did not provide stdio pipes");
491
+ throw new Error('Claude subprocess did not provide stdio pipes');
442
492
  }
443
493
 
444
494
  const stderrChunks: string[] = [];
445
- proc.stderr.on("data", (chunk: Buffer) => {
495
+ proc.stderr.on('data', (chunk: Buffer) => {
446
496
  stderrChunks.push(chunk.toString());
447
497
  });
448
- proc.stdin.on("error", () => {
498
+ proc.stdin.on('error', () => {
449
499
  proc.stdin.destroy();
450
500
  if (proc.exitCode === null && proc.signalCode === null) {
451
501
  if (!IS_WIN32 || !proc.pid || !killWin32Tree(proc.pid)) {
452
- proc.kill("SIGTERM");
502
+ proc.kill('SIGTERM');
453
503
  }
454
504
  }
455
505
  });
456
506
 
457
- const exitPromise = new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve) => {
458
- proc.once("close", (code, signal) => resolve({ code, signal }));
459
- proc.once("error", () => resolve({ code: null, signal: null }));
460
- });
507
+ const exitPromise = new Promise<{ code: number | null; signal: NodeJS.Signals | null }>(
508
+ (resolve) => {
509
+ proc.once('close', (code, signal) => resolve({ code, signal }));
510
+ proc.once('error', () => resolve({ code: null, signal: null }));
511
+ },
512
+ );
461
513
 
462
514
  return { proc, exitPromise, stderrChunks };
463
515
  }
@@ -470,22 +522,26 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
470
522
  }
471
523
  try {
472
524
  state.handle.proc.stdin.end();
473
- } catch { /* best-effort */ }
525
+ } catch {
526
+ /* best-effort */
527
+ }
474
528
  if (state.handle.proc.exitCode === null && state.handle.proc.signalCode === null) {
475
529
  try {
476
530
  if (!IS_WIN32 || !state.handle.proc.pid || !killWin32Tree(state.handle.proc.pid)) {
477
- state.handle.proc.kill("SIGTERM");
531
+ state.handle.proc.kill('SIGTERM');
478
532
  }
479
- } catch { /* best-effort */ }
533
+ } catch {
534
+ /* best-effort */
535
+ }
480
536
  }
481
537
  }
482
538
 
483
539
  private writeUserMessage(handle: ClaudeProcessHandle, text: string) {
484
540
  const payload = JSON.stringify({
485
- type: "user",
541
+ type: 'user',
486
542
  message: {
487
- role: "user",
488
- content: [{ type: "text", text }],
543
+ role: 'user',
544
+ content: [{ type: 'text', text }],
489
545
  },
490
546
  });
491
547
  handle.proc.stdin.write(`${payload}\n`);
@@ -493,60 +549,60 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
493
549
 
494
550
  private buildArgs(sessionKey: string): string[] {
495
551
  const args = [
496
- "--verbose",
497
- "--input-format",
498
- "stream-json",
499
- "--output-format",
500
- "stream-json",
501
- "--permission-mode",
552
+ '--verbose',
553
+ '--input-format',
554
+ 'stream-json',
555
+ '--output-format',
556
+ 'stream-json',
557
+ '--permission-mode',
502
558
  this.opts.permissionMode,
503
559
  ];
504
560
 
505
561
  if (this._model) {
506
- args.push("--model", this._model);
562
+ args.push('--model', this._model);
507
563
  }
508
564
 
509
565
  if (this.opts.allowedTools.length > 0) {
510
- args.push("--allowedTools", this.opts.allowedTools.join(","));
566
+ args.push('--allowedTools', this.opts.allowedTools.join(','));
511
567
  }
512
568
 
513
569
  if (this.opts.disallowedTools.length > 0) {
514
- args.push("--disallowedTools", this.opts.disallowedTools.join(","));
570
+ args.push('--disallowedTools', this.opts.disallowedTools.join(','));
515
571
  }
516
572
 
517
573
  args.push(
518
- "--append-system-prompt-file",
519
- path.join(this.opts.workspaceDir, ".parall", "system-prompt.md"),
574
+ '--append-system-prompt-file',
575
+ path.join(this.opts.workspaceDir, '.parall', 'system-prompt.md'),
520
576
  );
521
577
 
522
578
  if (this.opts.appendSystemPrompt) {
523
- args.push("--append-system-prompt", this.opts.appendSystemPrompt);
579
+ args.push('--append-system-prompt', this.opts.appendSystemPrompt);
524
580
  }
525
581
 
526
582
  if (this.opts.additionalDirs.length > 0) {
527
- args.push("--add-dir", ...this.opts.additionalDirs);
583
+ args.push('--add-dir', ...this.opts.additionalDirs);
528
584
  }
529
585
 
530
586
  args.push(...this.opts.sessionManager.getResumeArgs(sessionKey));
531
587
  return args;
532
588
  }
533
589
 
534
- private buildPlaceholderContext(sessionKey: string): DispatchOpts["context"] {
590
+ private buildPlaceholderContext(sessionKey: string): DispatchOpts['context'] {
535
591
  return {
536
- accountId: "",
592
+ accountId: '',
537
593
  apiUrl: this.opts.apiUrl,
538
594
  apiKey: this.opts.apiKey,
539
595
  orgId: this.opts.orgId,
540
- agentUserId: "",
541
- runtimeType: "",
542
- runtimeKey: "",
543
- sessionId: "",
544
- chatId: "",
545
- triggerMessageId: "",
596
+ agentUserId: '',
597
+ runtimeType: '',
598
+ runtimeKey: '',
599
+ sessionId: '',
600
+ chatId: '',
601
+ triggerMessageId: '',
546
602
  noReply: false,
547
- contextFilePath: this.opts.contextFilePathForSession?.(sessionKey) ?? "",
548
- stepIdFilePath: this.opts.stepIdFilePathForSession?.(sessionKey) ?? "",
549
- client: undefined as unknown as DispatchOpts["context"]["client"],
603
+ contextFilePath: this.opts.contextFilePathForSession?.(sessionKey) ?? '',
604
+ stepIdFilePath: this.opts.stepIdFilePathForSession?.(sessionKey) ?? '',
605
+ client: undefined as unknown as DispatchOpts['context']['client'],
550
606
  };
551
607
  }
552
608
  }