@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
@@ -3,7 +3,12 @@
3
3
  */
4
4
 
5
5
  import { IRunnerApp } from "../types/runner-interface";
6
- import { RunnerMessage, MethodHandler, ConversationContext } from "../types";
6
+ import {
7
+ RunnerMessage,
8
+ MethodHandler,
9
+ ConversationContext,
10
+ ConversationConfig,
11
+ } from "../types";
7
12
  import { SSEClient, SSEEvent } from "../services/SSEClient";
8
13
  import { RunnerAPIClient } from "../services/RunnerAPIClient";
9
14
  import { statusLineManager } from "../utils/status-line";
@@ -499,8 +504,11 @@ export class MessageHandler {
499
504
  }
500
505
  );
501
506
 
507
+ const provider = this.resolveAgentProvider(conversationData, config);
508
+ const manager = this.getManagerForProvider(provider);
509
+
502
510
  // Start the conversation with the provided/loaded conversation details
503
- await this.runner.claudeManager_.startConversation(
511
+ await manager.startConversation(
504
512
  finalObjectType,
505
513
  finalObjectId,
506
514
  config,
@@ -551,7 +559,8 @@ export class MessageHandler {
551
559
 
552
560
  if (context && targetConversationId) {
553
561
  context.status = "stopping";
554
- await this.runner.claudeManager_.stopConversation(
562
+ const manager = this.getManagerForConversationContext(context);
563
+ await manager.stopConversation(
555
564
  context.agentSessionId,
556
565
  context,
557
566
  false, // Not a runner shutdown
@@ -611,7 +620,9 @@ export class MessageHandler {
611
620
  throw new Error("Cannot resume conversation without agentSessionId");
612
621
  }
613
622
 
614
- await this.runner.claudeManager_.resumeConversation(
623
+ const provider = this.resolveAgentProvider(conversationData, config);
624
+ const manager = this.getManagerForProvider(provider);
625
+ await manager.resumeConversation(
615
626
  conversationData.objectType,
616
627
  conversationData.objectId,
617
628
  agentSessionId,
@@ -666,7 +677,9 @@ export class MessageHandler {
666
677
  );
667
678
 
668
679
  // Stop the current conversation
669
- await this.runner.claudeManager_.stopConversation(
680
+ const manager = this.getManagerForConversationContext(context);
681
+
682
+ await manager.stopConversation(
670
683
  context.agentSessionId,
671
684
  context,
672
685
  false // Not a runner shutdown, just updating config
@@ -680,7 +693,7 @@ export class MessageHandler {
680
693
  );
681
694
 
682
695
  // Resume with new config
683
- await this.runner.claudeManager_.resumeConversation(
696
+ await manager.resumeConversation(
684
697
  context.conversationObjectType,
685
698
  context.conversationObjectId,
686
699
  context.agentSessionId,
@@ -717,6 +730,7 @@ export class MessageHandler {
717
730
  conversationObjectType = message.conversationObjectType || "Task",
718
731
  conversationObjectId = message.conversationObjectId,
719
732
  conversation,
733
+ agentSessionId,
720
734
  } = params;
721
735
 
722
736
  // Validate required parameters
@@ -728,13 +742,21 @@ export class MessageHandler {
728
742
  throw new Error("Missing required parameter: content");
729
743
  }
730
744
 
731
- await this.runner.claudeManager_.sendUserMessage(
745
+ const existingContext = this.runner.getConversationContext(conversationId);
746
+ const manager = existingContext
747
+ ? this.getManagerForConversationContext(existingContext)
748
+ : this.getManagerForProvider(
749
+ this.resolveAgentProvider(conversation, config)
750
+ );
751
+
752
+ await manager.sendUserMessage(
732
753
  conversationId,
733
754
  content,
734
755
  config,
735
756
  conversationObjectType,
736
757
  conversationObjectId,
737
- conversation
758
+ conversation,
759
+ agentSessionId
738
760
  );
739
761
  }
740
762
 
@@ -1022,4 +1044,53 @@ export class MessageHandler {
1022
1044
  timestamp: new Date(),
1023
1045
  });
1024
1046
  }
1047
+
1048
+ private resolveAgentProvider(
1049
+ conversation?: {
1050
+ providerType?: string;
1051
+ agentProviderType?: string;
1052
+ model?: string;
1053
+ },
1054
+ config?: ConversationConfig
1055
+ ): "openai" | "claude" {
1056
+ const explicitProvider =
1057
+ conversation?.providerType ||
1058
+ conversation?.agentProviderType ||
1059
+ (config as any)?.providerType ||
1060
+ (config as any)?.agentProviderType;
1061
+
1062
+ if (typeof explicitProvider === "string") {
1063
+ const normalized = explicitProvider.toLowerCase();
1064
+ if (normalized === "openai") return "openai";
1065
+ if (normalized === "claude") return "claude";
1066
+ }
1067
+
1068
+ const model =
1069
+ conversation?.model ||
1070
+ (config as any)?.model ||
1071
+ (config as any)?.defaultModel ||
1072
+ "";
1073
+ const normalizedModel = model.toLowerCase();
1074
+
1075
+ const looksLikeCodex =
1076
+ normalizedModel.includes("gpt") ||
1077
+ /^o\d/.test(normalizedModel) ||
1078
+ normalizedModel.includes("openai") ||
1079
+ normalizedModel.includes("codex");
1080
+
1081
+ return looksLikeCodex ? "openai" : "claude";
1082
+ }
1083
+
1084
+ private getManagerForProvider(provider?: string) {
1085
+ if (provider?.toLowerCase() === "openai") {
1086
+ return this.runner.codexManager_;
1087
+ }
1088
+ return this.runner.claudeManager_;
1089
+ }
1090
+
1091
+ private getManagerForConversationContext(context: ConversationContext) {
1092
+ return context.provider === "openai"
1093
+ ? this.runner.codexManager_
1094
+ : this.runner.claudeManager_;
1095
+ }
1025
1096
  }
package/src/runner-sse.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  import { IRunnerApp } from "./types/runner-interface";
14
14
  import { MessageHandler } from "./components/message-handler-sse";
15
15
  import { ClaudeManager } from "./components/claude-sdk-manager";
16
+ import { CodexManager } from "./components/codex-sdk-manager";
16
17
  import { EnhancedRepositoryManager } from "./components/enhanced-repository-manager";
17
18
  import { StateManager } from "./utils/StateManager";
18
19
  import { createLogger } from "./utils/logger";
@@ -23,9 +24,137 @@ import computerName from "computer-name";
23
24
 
24
25
  const logger = createLogger("RunnerApp");
25
26
 
27
+ const TOOL_RESPONSE_BYTE_LIMIT = 500 * 1024; // 500 KiB per tool response field
28
+ const TOOL_RESPONSE_SUFFIX = "... [truncated]";
29
+
30
+ function sanitizeToolResponsePayload(
31
+ method: string | undefined,
32
+ params: any
33
+ ): any {
34
+ if (method !== "message.agent" || !params) {
35
+ return params;
36
+ }
37
+
38
+ if (!isToolResultPayload(params)) {
39
+ return params;
40
+ }
41
+
42
+ const [sanitized, changed] = truncateStringsRecursively(params);
43
+ if (!changed) {
44
+ return params;
45
+ }
46
+
47
+ const toolUseId = extractToolUseId(params);
48
+ const message = `Tool response exceeded ${TOOL_RESPONSE_BYTE_LIMIT} bytes and was truncated`;
49
+ if (toolUseId) {
50
+ logger.warn(message, { toolUseId });
51
+ } else {
52
+ logger.warn(message);
53
+ }
54
+ return sanitized;
55
+ }
56
+
57
+ function isToolResultPayload(payload: any): boolean {
58
+ if (!payload) {
59
+ return false;
60
+ }
61
+ if (payload.type === "tool_result" || payload.subtype === "tool_result") {
62
+ return true;
63
+ }
64
+ if (Array.isArray(payload.content)) {
65
+ return payload.content.some((entry: any) => isToolResultBlock(entry));
66
+ }
67
+ return isToolResultBlock(payload.content);
68
+ }
69
+
70
+ function isToolResultBlock(block: any): boolean {
71
+ if (!block) {
72
+ return false;
73
+ }
74
+ return (
75
+ block.type === "tool_result" ||
76
+ block.subtype === "tool_result" ||
77
+ typeof block.tool_use_id === "string"
78
+ );
79
+ }
80
+
81
+ function extractToolUseId(payload: any): string | undefined {
82
+ if (!payload) {
83
+ return undefined;
84
+ }
85
+ if (typeof payload.tool_use_id === "string") {
86
+ return payload.tool_use_id;
87
+ }
88
+ if (Array.isArray(payload.content)) {
89
+ const match = payload.content.find(
90
+ (entry: any) => entry && typeof entry.tool_use_id === "string"
91
+ );
92
+ if (match) {
93
+ return match.tool_use_id;
94
+ }
95
+ }
96
+ if (payload.content && typeof payload.content === "object") {
97
+ return extractToolUseId(payload.content);
98
+ }
99
+ return undefined;
100
+ }
101
+
102
+ function truncateStringsRecursively(value: any): [any, boolean] {
103
+ if (typeof value === "string") {
104
+ return truncateStringValue(value);
105
+ }
106
+
107
+ if (Array.isArray(value)) {
108
+ let mutated = false;
109
+ let result: any[] = value;
110
+ for (let i = 0; i < value.length; i++) {
111
+ const [newItem, changed] = truncateStringsRecursively(value[i]);
112
+ if (changed) {
113
+ if (!mutated) {
114
+ result = value.slice();
115
+ mutated = true;
116
+ }
117
+ result[i] = newItem;
118
+ }
119
+ }
120
+ return [result, mutated];
121
+ }
122
+
123
+ if (value && typeof value === "object") {
124
+ let mutated = false;
125
+ let result: any = value;
126
+ for (const key of Object.keys(value)) {
127
+ const [newVal, changed] = truncateStringsRecursively(value[key]);
128
+ if (changed) {
129
+ if (!mutated) {
130
+ result = { ...value };
131
+ mutated = true;
132
+ }
133
+ result[key] = newVal;
134
+ }
135
+ }
136
+ return [result, mutated];
137
+ }
138
+
139
+ return [value, false];
140
+ }
141
+
142
+ function truncateStringValue(value: string): [string, boolean] {
143
+ const byteLength = Buffer.byteLength(value, "utf8");
144
+ if (byteLength <= TOOL_RESPONSE_BYTE_LIMIT) {
145
+ return [value, false];
146
+ }
147
+
148
+ const suffixBytes = Buffer.byteLength(TOOL_RESPONSE_SUFFIX, "utf8");
149
+ const maxBytes = Math.max(0, TOOL_RESPONSE_BYTE_LIMIT - suffixBytes);
150
+ const truncatedBuffer = Buffer.from(value, "utf8").subarray(0, maxBytes);
151
+ return [truncatedBuffer.toString("utf8") + TOOL_RESPONSE_SUFFIX, true];
152
+ }
153
+
26
154
  export class RunnerApp implements IRunnerApp {
27
155
  private messageHandler!: MessageHandler;
28
156
  private claudeManager!: ClaudeManager;
157
+ private codexManager!: CodexManager;
29
158
  private repositoryManager!: EnhancedRepositoryManager;
30
159
  private stateManager!: StateManager;
31
160
  private agentConversations: Map<string, ConversationContext>; // Keyed by conversation.id
@@ -91,6 +220,9 @@ export class RunnerApp implements IRunnerApp {
91
220
  // Initialize Claude manager with repository manager (using SDK-native manager)
92
221
  this.claudeManager = new ClaudeManager(this, this.repositoryManager);
93
222
 
223
+ // Initialize Codex manager for OpenAI-based conversations
224
+ this.codexManager = new CodexManager(this, this.repositoryManager);
225
+
94
226
  // Initialize message handler with SSE support
95
227
  this.messageHandler = new MessageHandler(this);
96
228
  }
@@ -193,17 +325,18 @@ export class RunnerApp implements IRunnerApp {
193
325
 
194
326
  async notify(method: string, params: any): Promise<void> {
195
327
  try {
328
+ const safeParams = sanitizeToolResponsePayload(method, params);
196
329
  // Log RPC notification in debug mode
197
330
  logger.debug(`[RPC] Sending notification: ${method}`, {
198
331
  method,
199
- params: JSON.stringify(params, null, 2),
332
+ params: JSON.stringify(safeParams, null, 2),
200
333
  });
201
334
 
202
335
  // Send notification with retry logic
203
336
  await this.sendToOrchestratorWithRetry({
204
337
  jsonrpc: "2.0",
205
338
  method,
206
- params,
339
+ params: safeParams,
207
340
  });
208
341
  } catch (error) {
209
342
  // Special handling for heartbeat errors - just log a simple line
@@ -224,13 +357,25 @@ export class RunnerApp implements IRunnerApp {
224
357
  }
225
358
 
226
359
  async sendToOrchestrator(message: JsonRpcMessage): Promise<any> {
360
+ const sanitizedParams = sanitizeToolResponsePayload(
361
+ message.method,
362
+ message.params
363
+ );
364
+ const messageToSend =
365
+ sanitizedParams === message.params
366
+ ? message
367
+ : {
368
+ ...message,
369
+ params: sanitizedParams,
370
+ };
371
+
227
372
  try {
228
373
  // Log RPC request in debug mode
229
374
  logger.debug(`[RPC] Sending request:`, {
230
- method: message.method,
231
- id: message.id,
232
- params: message.params
233
- ? JSON.stringify(message.params, null, 2)
375
+ method: messageToSend.method,
376
+ id: messageToSend.id,
377
+ params: messageToSend.params
378
+ ? JSON.stringify(messageToSend.params, null, 2)
234
379
  : undefined,
235
380
  });
236
381
 
@@ -250,7 +395,7 @@ export class RunnerApp implements IRunnerApp {
250
395
  {
251
396
  method: "POST",
252
397
  headers,
253
- body: JSON.stringify(message),
398
+ body: JSON.stringify(messageToSend),
254
399
  signal: AbortSignal.timeout(30000), // 30 second timeout
255
400
  }
256
401
  );
@@ -264,8 +409,8 @@ export class RunnerApp implements IRunnerApp {
264
409
 
265
410
  // Log RPC response in debug mode
266
411
  logger.debug(`[RPC] Received response:`, {
267
- method: message.method,
268
- id: message.id,
412
+ method: messageToSend.method,
413
+ id: messageToSend.id,
269
414
  result: result?.result
270
415
  ? JSON.stringify(result.result, null, 2)
271
416
  : undefined,
@@ -288,8 +433,8 @@ export class RunnerApp implements IRunnerApp {
288
433
  } else {
289
434
  // For other RPC messages, log the attempted message and error
290
435
  logger.error(`RPC failed:`, {
291
- method: message.method,
292
- params: message.params,
436
+ method: messageToSend.method,
437
+ params: messageToSend.params,
293
438
  error: errorMessage,
294
439
  });
295
440
  }
@@ -302,7 +447,7 @@ export class RunnerApp implements IRunnerApp {
302
447
  ): ConversationContext | undefined {
303
448
  // Using conversation.id as primary key for conversation tracking
304
449
  const context = this.agentConversations.get(conversationId);
305
- console.log(`[Runner] getConversationContext lookup:`, {
450
+ logger.debug(`[Runner] getConversationContext lookup:`, {
306
451
  conversationId,
307
452
  found: !!context,
308
453
  totalConversations: this.agentConversations.size,
@@ -327,12 +472,12 @@ export class RunnerApp implements IRunnerApp {
327
472
  `RunnerRepo validated: ${repo.name} at ${resolvedPath}`
328
473
  );
329
474
  } else {
330
- logger.error(
475
+ logger.warn(
331
476
  `RunnerRepo path is not a directory: ${repo.name} at ${resolvedPath}`
332
477
  );
333
478
  }
334
479
  } catch (error) {
335
- logger.error(
480
+ logger.warn(
336
481
  `RunnerRepo path does not exist: ${repo.name} at ${repo.path}`
337
482
  );
338
483
  }
@@ -760,8 +905,9 @@ export class RunnerApp implements IRunnerApp {
760
905
 
761
906
  for (const [conversationId, context] of this.agentConversations) {
762
907
  if (context.status === "active" || context.status === "starting") {
908
+ const manager = this.getManagerForContext(context);
763
909
  stopPromises.push(
764
- this.claudeManager
910
+ manager
765
911
  .stopConversation(context.agentSessionId, context, isRunnerShutdown)
766
912
  .catch((error) => {
767
913
  logger.error(
@@ -797,6 +943,9 @@ export class RunnerApp implements IRunnerApp {
797
943
  get claudeManager_(): ClaudeManager {
798
944
  return this.claudeManager;
799
945
  }
946
+ get codexManager_(): CodexManager {
947
+ return this.codexManager;
948
+ }
800
949
  get repositoryManager_(): EnhancedRepositoryManager {
801
950
  return this.repositoryManager;
802
951
  }
@@ -859,4 +1008,14 @@ export class RunnerApp implements IRunnerApp {
859
1008
  setDelayFunction(fn: (ms: number) => Promise<void>): void {
860
1009
  this.delayFn = fn;
861
1010
  }
1011
+
1012
+ private getManagerForContext(
1013
+ context?: ConversationContext | null
1014
+ ): ClaudeManager | CodexManager {
1015
+ const provider = context?.provider?.toLowerCase();
1016
+ if (provider === "openai") {
1017
+ return this.codexManager;
1018
+ }
1019
+ return this.claudeManager;
1020
+ }
862
1021
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { Conversation } from "@botanicastudios/claude-code-sdk-ts";
6
+ import type { Thread } from "@northflare/codex-sdk";
6
7
 
7
8
  // Repository information passed in conversation config
8
9
  export interface RepositoryInfo {
@@ -25,6 +26,7 @@ export interface ConversationConfig {
25
26
  repository?: RepositoryInfo; // Repository details from orchestrator
26
27
  sessionId?: string; // For resume operations
27
28
  runnerRepoPath?: string; // Path to local runner repo for local workspaces
29
+ codexAuth?: CodexAuthConfig;
28
30
  }
29
31
 
30
32
  // Internal conversation tracking
@@ -39,7 +41,9 @@ export interface ConversationContext {
39
41
  config: ConversationConfig;
40
42
  startedAt: Date;
41
43
  lastActivityAt: Date;
42
- conversation?: Conversation; // Claude SDK conversation instance (stateful)
44
+ conversation?: Conversation | Thread; // Conversation or Codex thread instance
45
+ provider?: "claude" | "openai" | string;
46
+ metadata?: Record<string, any>;
43
47
 
44
48
  // Additional conversation details from database
45
49
  model: string;
@@ -48,6 +52,13 @@ export interface ConversationContext {
48
52
  permissionsMode: string;
49
53
  }
50
54
 
55
+ export interface CodexAuthConfig {
56
+ accessToken: string;
57
+ idToken: string;
58
+ accountId: string;
59
+ lastRefresh?: string | null;
60
+ }
61
+
51
62
  // Message type for initial messages
52
63
  export interface Message {
53
64
  content: string;
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { RunnerConfig, ConversationContext, JsonRpcMessage } from './index';
6
6
  import { ClaudeManager } from '../components/claude-sdk-manager';
7
+ import { CodexManager } from '../components/codex-sdk-manager';
7
8
  import { EnhancedRepositoryManager } from '../components/enhanced-repository-manager';
8
9
 
9
10
  export interface IRunnerApp {
@@ -18,6 +19,7 @@ export interface IRunnerApp {
18
19
  get config_(): RunnerConfig;
19
20
  get activeConversations_(): Map<string, ConversationContext>;
20
21
  get claudeManager_(): ClaudeManager;
22
+ get codexManager_(): CodexManager;
21
23
  get repositoryManager_(): EnhancedRepositoryManager;
22
24
 
23
25
  // Runner state
@@ -31,4 +33,4 @@ export interface IRunnerApp {
31
33
 
32
34
  // Optional methods for SSE implementation
33
35
  updateLastProcessedAt?(timestamp: Date | null): Promise<void>;
34
- }
36
+ }
@@ -0,0 +1,29 @@
1
+ export type ModelReasoningEffort = "low" | "medium" | "high";
2
+
3
+ const REASONING_VALUES: readonly ModelReasoningEffort[] = [
4
+ "low",
5
+ "medium",
6
+ "high",
7
+ ];
8
+
9
+ export function parseModelValue(value?: string | null): {
10
+ baseModel?: string;
11
+ reasoningEffort?: ModelReasoningEffort;
12
+ } {
13
+ if (!value) {
14
+ return {};
15
+ }
16
+
17
+ const [model, possibleEffort] = value.split(":");
18
+ if (
19
+ possibleEffort &&
20
+ REASONING_VALUES.includes(possibleEffort as ModelReasoningEffort)
21
+ ) {
22
+ return {
23
+ baseModel: model,
24
+ reasoningEffort: possibleEffort as ModelReasoningEffort,
25
+ };
26
+ }
27
+
28
+ return { baseModel: value };
29
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * StatusLineManager - Manages persistent status line output for active Claude Code processes
2
+ * StatusLineManager - Manages persistent status line output for active agent processes
3
3
  *
4
4
  * This component maintains a single-line status output that updates every minute to show
5
- * the count of active Claude Code processes. It prevents the machine from entering idle
5
+ * the count of active agent processes. It prevents the machine from entering idle
6
6
  * state while processes are running and provides clear visual feedback without cluttering
7
7
  * the terminal with multiple log lines.
8
8
  */
@@ -84,11 +84,11 @@ export class StatusLineManager {
84
84
 
85
85
  let newLine: string;
86
86
  if (this.activeCount === 0) {
87
- newLine = "No active Claude Code processes";
87
+ newLine = "No active agent processes";
88
88
  } else if (this.activeCount === 1) {
89
- newLine = `${timeStr} 1 active Claude Code process`;
89
+ newLine = `${timeStr} 1 active agent process`;
90
90
  } else {
91
- newLine = `${timeStr} ${this.activeCount} active Claude Code processes`;
91
+ newLine = `${timeStr} ${this.activeCount} active agent processes`;
92
92
  }
93
93
 
94
94
  // If this is the first status line, position it
@@ -118,4 +118,4 @@ export class StatusLineManager {
118
118
  }
119
119
 
120
120
  // Singleton instance
121
- export const statusLineManager = new StatusLineManager();
121
+ export const statusLineManager = new StatusLineManager();