tide-commander 1.147.1 → 1.149.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/CHANGELOG.md +26 -0
- package/README.md +6 -3
- package/dist/assets/BossLogsModal-Cs4kWugD.js +1 -0
- package/dist/assets/BossSpawnModal-BudMgJqj.js +1 -0
- package/dist/assets/ControlsModal-Bh6_3qtH.js +1 -0
- package/dist/assets/DockerLogsModal-Nf4wQFfz.js +2 -0
- package/dist/assets/{EmbeddedEditor-DfM3SrO7.js → EmbeddedEditor-BfRXRX50.js} +1 -1
- package/dist/assets/{GmailOAuthSetup-DBWs7uzU.js → GmailOAuthSetup-CXUtjA0r.js} +1 -1
- package/dist/assets/{GoogleOAuthSetup-yQjT5QzU.js → GoogleOAuthSetup-D-_rwicD.js} +1 -1
- package/dist/assets/{IframeModal-DUTIyP5I.js → IframeModal-CdaXsQK0.js} +1 -1
- package/dist/assets/{IntegrationsPanel-DPURuiaz.js → IntegrationsPanel-ZsSVxcWr.js} +2 -2
- package/dist/assets/{LogViewerModal-CDZvTdfO.js → LogViewerModal-BAf-klB2.js} +1 -1
- package/dist/assets/{MonitoringModal-Dq2EJgbH.js → MonitoringModal-BjRbh5z4.js} +1 -1
- package/dist/assets/{PM2LogsModal-C3dlYlGv.js → PM2LogsModal-SaywDZVL.js} +2 -2
- package/dist/assets/{RestoreArchivedAreaModal-BMFk0G8D.js → RestoreArchivedAreaModal-jru2Ez9a.js} +1 -1
- package/dist/assets/Scene2DCanvas-NJHoe2Qg.js +1 -0
- package/dist/assets/SceneManager-i9wVMa_V.js +104 -0
- package/dist/assets/{SkillsPanel-D326VBDa.js → SkillsPanel-BHfKLzWe.js} +3 -3
- package/dist/assets/{SlackMultiInstanceSetup-CA4nm925.js → SlackMultiInstanceSetup-BfVevCSo.js} +1 -1
- package/dist/assets/SpawnModal-29x5z53B.js +1 -0
- package/dist/assets/{StatisticsModal-BUpvkJXA.js → StatisticsModal-MbIByjWD.js} +1 -1
- package/dist/assets/{SubordinateAssignmentModal-DtVsKDqV.js → SubordinateAssignmentModal-DF0vYaM6.js} +1 -1
- package/dist/assets/{TriggerManagerPanel-OD14xVMw.js → TriggerManagerPanel-EGcKS1Pt.js} +1 -1
- package/dist/assets/{WorkflowEditorPanel-B4UF3rcS.js → WorkflowEditorPanel-BLmejfqe.js} +1 -1
- package/dist/assets/{area-logos-Uc9SAeYg.js → area-logos-C4fgpLgO.js} +1 -1
- package/dist/assets/grok.ico +0 -0
- package/dist/assets/grok.png +0 -0
- package/dist/assets/{index-xBtKu0I8.js → index-B-2H7O_Y.js} +2 -2
- package/dist/assets/{index-CuHJm43U.js → index-B9xpLAcH.js} +1 -1
- package/dist/assets/index-BZ4wZwRu.js +19 -0
- package/dist/assets/index-BiiLWTXJ.js +1 -0
- package/dist/assets/{index-BC3Y_BAQ.js → index-C6Kf4ewu.js} +5 -5
- package/dist/assets/index-C8CGfmXP.js +1 -0
- package/dist/assets/index-DThK5_yS.js +5 -0
- package/dist/assets/index-DYgVP0G3.js +2 -0
- package/dist/assets/index-DhD3m2Qx.js +1 -0
- package/dist/assets/main-B0UlZnfk.js +260 -0
- package/dist/assets/main-DeiAIdzy.css +1 -0
- package/dist/assets/{web-DlzqHyn8.js → web-CXC8P25z.js} +1 -1
- package/dist/assets/{web-B-xc0c6e.js → web-LGEDa25c.js} +1 -1
- package/dist/assets/{web-BuDeKWBN.js → web-NM4dUqWg.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/locales/de/tools.json +3 -1
- package/dist/locales/en/tools.json +7 -3
- package/dist/locales/es/tools.json +3 -1
- package/dist/locales/fr/tools.json +4 -2
- package/dist/locales/hi/tools.json +4 -2
- package/dist/locales/it/tools.json +19 -17
- package/dist/locales/ja/tools.json +4 -2
- package/dist/locales/pt/tools.json +3 -1
- package/dist/locales/ru/tools.json +3 -1
- package/dist/locales/zh-CN/tools.json +3 -1
- package/dist/src/packages/server/claude/runner/process-lifecycle.js +53 -0
- package/dist/src/packages/server/claude/runner/stdout-pipeline.js +125 -4
- package/dist/src/packages/server/claude/runner/watchdog.js +12 -0
- package/dist/src/packages/server/claude/session-loader.js +280 -0
- package/dist/src/packages/server/data/index.js +1 -0
- package/dist/src/packages/server/grok/backend.js +231 -0
- package/dist/src/packages/server/grok/index.js +4 -0
- package/dist/src/packages/server/grok/json-event-parser.js +138 -0
- package/dist/src/packages/server/grok/session-watcher.js +460 -0
- package/dist/src/packages/server/routes/agents.js +7 -2
- package/dist/src/packages/server/runtime/grok-runtime-provider.js +11 -0
- package/dist/src/packages/server/runtime/index.js +1 -0
- package/dist/src/packages/server/services/agent-service.js +26 -5
- package/dist/src/packages/server/services/runtime-command-execution.js +4 -2
- package/dist/src/packages/server/services/runtime-events.js +46 -7
- package/dist/src/packages/server/services/runtime-service.js +19 -3
- package/dist/src/packages/server/utils/tool-formatting.js +40 -12
- package/dist/src/packages/server/websocket/handlers/agent-handler.js +70 -17
- package/dist/src/packages/server/websocket/listeners/runtime-listeners.js +63 -7
- package/dist/src/packages/shared/agent-types.js +10 -0
- package/package.json +1 -1
- package/dist/assets/BossLogsModal-Cn8IVdqn.js +0 -1
- package/dist/assets/BossSpawnModal-Don-RZyh.js +0 -1
- package/dist/assets/ControlsModal-C9--xWPi.js +0 -1
- package/dist/assets/DockerLogsModal-DSGnpfm5.js +0 -2
- package/dist/assets/Scene2DCanvas-DlumJCbl.js +0 -1
- package/dist/assets/SceneManager-UnhMFja8.js +0 -104
- package/dist/assets/SpawnModal-B1QOjZPe.js +0 -1
- package/dist/assets/index-BD6swoQU.js +0 -19
- package/dist/assets/index-C4mf6B5U.js +0 -1
- package/dist/assets/index-COHImd74.js +0 -1
- package/dist/assets/index-CScFEdm8.js +0 -1
- package/dist/assets/index-CmmpVZ8w.js +0 -2
- package/dist/assets/index-DkDzXtdj.js +0 -5
- package/dist/assets/main-Bp6V_-sL.js +0 -256
- package/dist/assets/main-ijcbyjBn.css +0 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as os from 'os';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
-
import { CLAUDE_MODELS as CLAUDE_MODEL_METADATA } from '../../shared/agent-types.js';
|
|
8
|
+
import { CLAUDE_MODELS as CLAUDE_MODEL_METADATA, GROK_MODELS, DEFAULT_GROK_MODEL } from '../../shared/agent-types.js';
|
|
9
9
|
import { loadAgents, saveAgents, saveAgentsAsync, getDataDir, loadAreas, saveAreas, loadSessionHistory, saveSessionHistory, addSessionHistoryEntry, getSessionHistoryForAgent } from '../data/index.js';
|
|
10
10
|
import { listSessions, getSessionSummary, getProjectDir, loadSession, loadToolHistory, searchSession, } from '../claude/session-loader.js';
|
|
11
11
|
import { loadSubagentHistory } from '../claude/subagent-history-loader.js';
|
|
@@ -16,11 +16,19 @@ const VALID_CLAUDE_MODELS = new Set(Object.keys(CLAUDE_MODEL_METADATA));
|
|
|
16
16
|
const DEFAULT_CLAUDE_CONTEXT_LIMIT = 200000;
|
|
17
17
|
const DEFAULT_CODEX_CONTEXT_LIMIT = 258400;
|
|
18
18
|
const DEFAULT_OPENCODE_CONTEXT_LIMIT = 200000;
|
|
19
|
-
|
|
19
|
+
/** Matches live Grok Build signals.json contextWindowTokens (catalog may list 2M). */
|
|
20
|
+
const DEFAULT_GROK_CONTEXT_LIMIT = 500000;
|
|
21
|
+
function getDefaultContextLimit(provider, model, grokModel) {
|
|
20
22
|
if (provider === 'codex')
|
|
21
23
|
return DEFAULT_CODEX_CONTEXT_LIMIT;
|
|
22
24
|
if (provider === 'opencode')
|
|
23
25
|
return DEFAULT_OPENCODE_CONTEXT_LIMIT;
|
|
26
|
+
if (provider === 'grok') {
|
|
27
|
+
if (grokModel && GROK_MODELS[grokModel]?.contextWindow) {
|
|
28
|
+
return GROK_MODELS[grokModel].contextWindow;
|
|
29
|
+
}
|
|
30
|
+
return DEFAULT_GROK_CONTEXT_LIMIT;
|
|
31
|
+
}
|
|
24
32
|
if (model && CLAUDE_MODEL_METADATA[model]) {
|
|
25
33
|
return CLAUDE_MODEL_METADATA[model].contextWindow;
|
|
26
34
|
}
|
|
@@ -61,6 +69,12 @@ export function sanitizeOpencodeModel(model) {
|
|
|
61
69
|
const trimmed = model.trim();
|
|
62
70
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
63
71
|
}
|
|
72
|
+
export function sanitizeGrokModel(model) {
|
|
73
|
+
if (typeof model !== 'string')
|
|
74
|
+
return undefined;
|
|
75
|
+
const trimmed = model.trim();
|
|
76
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
77
|
+
}
|
|
64
78
|
function findFileRecursively(rootDir, pattern) {
|
|
65
79
|
if (!fs.existsSync(rootDir))
|
|
66
80
|
return null;
|
|
@@ -215,6 +229,7 @@ export function initAgents() {
|
|
|
215
229
|
codexModel: sanitizeCodexModel(stored.codexModel),
|
|
216
230
|
codexConfig: stored.codexConfig,
|
|
217
231
|
opencodeModel: sanitizeOpencodeModel(stored.opencodeModel),
|
|
232
|
+
grokModel: sanitizeGrokModel(stored.grokModel),
|
|
218
233
|
// Boss field - fallback to checking class for backward compatibility
|
|
219
234
|
isBoss: stored.isBoss ?? stored.class === 'boss',
|
|
220
235
|
};
|
|
@@ -278,7 +293,7 @@ export function getAgent(id) {
|
|
|
278
293
|
export function getAllAgents() {
|
|
279
294
|
return Array.from(agents.values());
|
|
280
295
|
}
|
|
281
|
-
export async function createAgent(name, agentClass, cwd, position, sessionId, useChrome, permissionMode = 'bypass', initialSkillIds, isBoss, model, codexModel, customInstructions, provider = 'claude', codexConfig, effort, opencodeModel) {
|
|
296
|
+
export async function createAgent(name, agentClass, cwd, position, sessionId, useChrome, permissionMode = 'bypass', initialSkillIds, isBoss, model, codexModel, customInstructions, provider = 'claude', codexConfig, effort, opencodeModel, grokModel) {
|
|
282
297
|
log.log('🎆 [CREATE_AGENT] Starting agent creation:', {
|
|
283
298
|
name,
|
|
284
299
|
agentClass,
|
|
@@ -290,6 +305,8 @@ export async function createAgent(name, agentClass, cwd, position, sessionId, us
|
|
|
290
305
|
model,
|
|
291
306
|
codexModel,
|
|
292
307
|
codexConfig,
|
|
308
|
+
opencodeModel,
|
|
309
|
+
grokModel,
|
|
293
310
|
customInstructions: customInstructions ? `${customInstructions.length} chars` : undefined,
|
|
294
311
|
});
|
|
295
312
|
const id = generateId();
|
|
@@ -301,6 +318,9 @@ export async function createAgent(name, agentClass, cwd, position, sessionId, us
|
|
|
301
318
|
throw new Error(`Directory does not exist: ${cwd}`);
|
|
302
319
|
}
|
|
303
320
|
log.log(` ✅ Directory exists`);
|
|
321
|
+
const sanitizedGrokModel = provider === 'grok'
|
|
322
|
+
? (sanitizeGrokModel(grokModel) || DEFAULT_GROK_MODEL)
|
|
323
|
+
: undefined;
|
|
304
324
|
// Create agent object
|
|
305
325
|
// SessionId can be provided to link to an existing Claude session
|
|
306
326
|
const agent = {
|
|
@@ -318,13 +338,14 @@ export async function createAgent(name, agentClass, cwd, position, sessionId, us
|
|
|
318
338
|
useChrome,
|
|
319
339
|
permissionMode,
|
|
320
340
|
model: sanitizeModelForProvider(provider, model),
|
|
321
|
-
effort: provider === 'claude' ? effort : undefined,
|
|
341
|
+
effort: provider === 'claude' || provider === 'grok' ? effort : undefined,
|
|
322
342
|
codexModel: provider === 'codex' ? sanitizeCodexModel(codexModel) : undefined,
|
|
323
343
|
codexConfig,
|
|
324
344
|
opencodeModel: provider === 'opencode' ? sanitizeOpencodeModel(opencodeModel) : undefined,
|
|
345
|
+
grokModel: sanitizedGrokModel,
|
|
325
346
|
tokensUsed: 0,
|
|
326
347
|
contextUsed: 0,
|
|
327
|
-
contextLimit: getDefaultContextLimit(provider, sanitizeModelForProvider(provider, model)),
|
|
348
|
+
contextLimit: getDefaultContextLimit(provider, sanitizeModelForProvider(provider, model), sanitizedGrokModel),
|
|
328
349
|
taskCount: 0, // Initialize task counter
|
|
329
350
|
createdAt: Date.now(),
|
|
330
351
|
lastActivity: Date.now(),
|
|
@@ -57,8 +57,10 @@ export function createRuntimeCommandExecution(deps) {
|
|
|
57
57
|
? agentService.sanitizeModelForProvider(agent.provider, agent.model)
|
|
58
58
|
: agent.provider === 'opencode'
|
|
59
59
|
? agentService.sanitizeOpencodeModel(agent.opencodeModel)
|
|
60
|
-
:
|
|
61
|
-
|
|
60
|
+
: agent.provider === 'grok'
|
|
61
|
+
? agentService.sanitizeGrokModel(agent.grokModel)
|
|
62
|
+
: agentService.sanitizeCodexModel(agent.codexModel),
|
|
63
|
+
effort: agent.provider === 'claude' || agent.provider === 'grok' ? agent.effort : undefined,
|
|
62
64
|
useChrome: agent.useChrome,
|
|
63
65
|
permissionMode: agent.permissionMode,
|
|
64
66
|
codexConfig: agent.codexConfig,
|
|
@@ -4,6 +4,8 @@ import { clearPendingSilentContextRefresh, consumeStepCompleteReceived, markStep
|
|
|
4
4
|
import { addPendingBackgroundTask, clearPendingBackgroundTasks, getActiveSubagentByToolUseId, handleTaskToolResult, handleTaskToolStart, hasPendingBackgroundTasks, resolvePendingBackgroundTask, resolvePendingBackgroundTaskByTaskId, } from './runtime-subagents.js';
|
|
5
5
|
const DEFAULT_CLAUDE_CONTEXT_WINDOW = 200000;
|
|
6
6
|
const DEFAULT_CODEX_CONTEXT_WINDOW = 258400;
|
|
7
|
+
/** Practical Grok Build window observed in session signals.json (model catalog may list 2M). */
|
|
8
|
+
const DEFAULT_GROK_CONTEXT_WINDOW = 500000;
|
|
7
9
|
const CODEX_ROLLING_CONTEXT_TURNS = 40;
|
|
8
10
|
const CODEX_PLAUSIBLE_USAGE_MULTIPLIER = 1.2;
|
|
9
11
|
const CODEX_RECOVERABLE_RESUME_ERRORS = [
|
|
@@ -41,6 +43,8 @@ function getDefaultContextWindow(provider) {
|
|
|
41
43
|
return DEFAULT_CODEX_CONTEXT_WINDOW;
|
|
42
44
|
if (provider === 'opencode')
|
|
43
45
|
return DEFAULT_CLAUDE_CONTEXT_WINDOW;
|
|
46
|
+
if (provider === 'grok')
|
|
47
|
+
return DEFAULT_GROK_CONTEXT_WINDOW;
|
|
44
48
|
return DEFAULT_CLAUDE_CONTEXT_WINDOW;
|
|
45
49
|
}
|
|
46
50
|
function updateCodexRollingContextEstimate(agentId, turnGrowth) {
|
|
@@ -232,21 +236,28 @@ export function createRuntimeEventHandlers(deps) {
|
|
|
232
236
|
// Real-time context tracking from streaming usage data.
|
|
233
237
|
// Context window usage = input tokens only (output tokens don't count toward the limit).
|
|
234
238
|
// total_input = cache_read + cache_creation + input_tokens (the full prompt size).
|
|
239
|
+
// Grok: session-watcher maps signals.json contextTokensUsed → tokens.input.
|
|
235
240
|
if (event.tokens) {
|
|
236
241
|
const isClaudeProvider = (agent.provider ?? 'claude') === 'claude';
|
|
237
242
|
const isOpencodeProvider = (agent.provider ?? 'claude') === 'opencode';
|
|
238
|
-
|
|
243
|
+
const isGrokProvider = (agent.provider ?? 'claude') === 'grok';
|
|
244
|
+
if (isClaudeProvider || isOpencodeProvider || isGrokProvider) {
|
|
239
245
|
const cacheRead = event.tokens.cacheRead || 0;
|
|
240
246
|
const cacheCreation = event.tokens.cacheCreation || 0;
|
|
241
247
|
const inputTokens = event.tokens.input || 0;
|
|
242
248
|
// Context window = input side only (system prompt + tools + messages).
|
|
243
249
|
// Output tokens are the model's response and don't count toward the limit.
|
|
250
|
+
// For Grok, inputTokens is already the full context fill from signals.json.
|
|
244
251
|
const snapshotContextUsed = cacheRead + cacheCreation + inputTokens;
|
|
245
252
|
if (snapshotContextUsed > 0) {
|
|
246
|
-
|
|
253
|
+
// Grok signals also carry the authoritative window size.
|
|
254
|
+
const modelWindow = event.modelUsage?.contextWindow;
|
|
255
|
+
const effectiveLimit = Math.max(1, modelWindow || agent.contextLimit || getDefaultContextWindow(agent.provider));
|
|
247
256
|
// Guard against cumulative session totals: if the sum exceeds the
|
|
248
257
|
// context window, it can't represent per-request context fill.
|
|
249
|
-
|
|
258
|
+
// Grok signals can report used slightly over window during compaction —
|
|
259
|
+
// clamp instead of skip so the bar still moves.
|
|
260
|
+
if (snapshotContextUsed > effectiveLimit && !isGrokProvider) {
|
|
250
261
|
log.log(`[usage_snapshot] ${agentId}: sum ${snapshotContextUsed} exceeds limit ${effectiveLimit} (likely cumulative); skipping`);
|
|
251
262
|
// If the agent's existing contextUsed is also stale (exceeds limit),
|
|
252
263
|
// reset it to 0 so the UI doesn't keep showing an impossible value.
|
|
@@ -256,9 +267,10 @@ export function createRuntimeEventHandlers(deps) {
|
|
|
256
267
|
}
|
|
257
268
|
}
|
|
258
269
|
else {
|
|
259
|
-
const safeContextUsed = Math.max(0, snapshotContextUsed);
|
|
270
|
+
const safeContextUsed = Math.max(0, Math.min(snapshotContextUsed, effectiveLimit));
|
|
260
271
|
const updates = {
|
|
261
272
|
contextUsed: safeContextUsed,
|
|
273
|
+
contextLimit: effectiveLimit,
|
|
262
274
|
};
|
|
263
275
|
// Always keep contextStats.totalTokens in sync with contextUsed.
|
|
264
276
|
// If authoritative stats exist (from /context), merge the new total
|
|
@@ -267,10 +279,23 @@ export function createRuntimeEventHandlers(deps) {
|
|
|
267
279
|
updates.contextStats = updateContextStatsTokens(agent.contextStats, safeContextUsed, effectiveLimit);
|
|
268
280
|
}
|
|
269
281
|
else {
|
|
270
|
-
|
|
282
|
+
const modelLabel = isClaudeProvider
|
|
283
|
+
? (agent.model || 'claude')
|
|
284
|
+
: isOpencodeProvider
|
|
285
|
+
? (agent.opencodeModel || 'opencode')
|
|
286
|
+
: (agent.grokModel || 'grok');
|
|
287
|
+
updates.contextStats = buildEstimatedContextStats(safeContextUsed, effectiveLimit, modelLabel);
|
|
288
|
+
}
|
|
289
|
+
// Lifetime tokensUsed: for Grok we don't get per-turn usage, so
|
|
290
|
+
// keep the high-water mark of context fill as a lower bound on work done.
|
|
291
|
+
if (isGrokProvider) {
|
|
292
|
+
const prev = agent.tokensUsed || 0;
|
|
293
|
+
if (safeContextUsed > prev) {
|
|
294
|
+
updates.tokensUsed = safeContextUsed;
|
|
295
|
+
}
|
|
271
296
|
}
|
|
272
297
|
agentService.updateAgent(agentId, updates, false);
|
|
273
|
-
log.log(`[usage_snapshot] ${agentId}: input=${inputTokens} + cacheRead=${cacheRead} + cacheCreation=${cacheCreation} = ${snapshotContextUsed} (output=${event.tokens.output || 0}) limit=${effectiveLimit}`);
|
|
298
|
+
log.log(`[usage_snapshot] ${agentId}: input=${inputTokens} + cacheRead=${cacheRead} + cacheCreation=${cacheCreation} = ${snapshotContextUsed} (output=${event.tokens.output || 0}) limit=${effectiveLimit}${isGrokProvider ? ' [grok]' : ''}`);
|
|
274
299
|
}
|
|
275
300
|
}
|
|
276
301
|
}
|
|
@@ -295,6 +320,7 @@ export function createRuntimeEventHandlers(deps) {
|
|
|
295
320
|
const isClaudeProvider = (agent.provider ?? 'claude') === 'claude';
|
|
296
321
|
const isCodexProvider = (agent.provider ?? 'claude') === 'codex';
|
|
297
322
|
const isOpencodeProvider = (agent.provider ?? 'claude') === 'opencode';
|
|
323
|
+
const isGrokProviderStep = (agent.provider ?? 'claude') === 'grok';
|
|
298
324
|
const lastTask = agent.lastAssignedTask?.trim() || '';
|
|
299
325
|
const isContextCommand = lastTask === '/context' || lastTask === '/cost' || lastTask === '/compact';
|
|
300
326
|
let contextUsed = agent.contextUsed || 0;
|
|
@@ -326,6 +352,16 @@ export function createRuntimeEventHandlers(deps) {
|
|
|
326
352
|
contextLimit = agent.contextLimit || getDefaultContextWindow('opencode');
|
|
327
353
|
log.log(`[step_complete] OpenCode agent ${agentId}: preserving usage_snapshot contextUsed=${contextUsed}, contextLimit=${contextLimit}`);
|
|
328
354
|
}
|
|
355
|
+
else if (isGrokProviderStep) {
|
|
356
|
+
// Grok: streaming-json has no usage; session-watcher feeds usage_snapshot
|
|
357
|
+
// from signals.json. Preserve those values on step_complete.
|
|
358
|
+
contextUsed = agent.contextUsed || 0;
|
|
359
|
+
contextLimit = agent.contextLimit || getDefaultContextWindow('grok');
|
|
360
|
+
if (hasModelUsageData && event.modelUsage?.contextWindow) {
|
|
361
|
+
contextLimit = event.modelUsage.contextWindow;
|
|
362
|
+
}
|
|
363
|
+
log.log(`[step_complete] Grok agent ${agentId}: preserving signals usage_snapshot contextUsed=${contextUsed}, contextLimit=${contextLimit}`);
|
|
364
|
+
}
|
|
329
365
|
else if (hasModelUsageData && event.modelUsage) {
|
|
330
366
|
const inputTokens = event.modelUsage.inputTokens || 0;
|
|
331
367
|
const outputTokens = event.modelUsage.outputTokens || 0;
|
|
@@ -389,13 +425,16 @@ export function createRuntimeEventHandlers(deps) {
|
|
|
389
425
|
// Always keep contextStats in sync. If authoritative stats exist (from
|
|
390
426
|
// /context), merge the updated totalTokens while preserving category
|
|
391
427
|
// breakdowns. Otherwise build fresh estimated stats.
|
|
428
|
+
const isGrokProvider = (agent.provider ?? 'claude') === 'grok';
|
|
392
429
|
const modelForStats = isClaudeProvider
|
|
393
430
|
? (agent.model || 'claude')
|
|
394
431
|
: isCodexProvider
|
|
395
432
|
? (agent.codexModel || agent.model)
|
|
396
433
|
: isOpencodeProvider
|
|
397
434
|
? (agent.opencodeModel || 'opencode')
|
|
398
|
-
:
|
|
435
|
+
: isGrokProvider
|
|
436
|
+
? (agent.grokModel || 'grok')
|
|
437
|
+
: (agent.model || 'unknown');
|
|
399
438
|
if (agent.contextStats && agent.contextStats.lastUpdated) {
|
|
400
439
|
updates.contextStats = updateContextStatsTokens(agent.contextStats, Math.max(0, Math.round(contextUsed)), Math.max(1, Math.round(contextLimit)));
|
|
401
440
|
}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Runtime Service
|
|
3
3
|
* Manages Claude/Codex runtime runners and command execution
|
|
4
4
|
*/
|
|
5
|
-
import { isClaudeProcessRunningInCwd, isCodexProcessRunningInCwd, isOpencodeProcessRunningInCwd, killClaudeProcessInCwd, killCodexProcessInCwd, killOpencodeProcessInCwd, findClaudeProcessPidInCwd, findCodexProcessPidInCwd, findOpencodeProcessPidInCwd, } from '../claude/session-loader.js';
|
|
5
|
+
import { isClaudeProcessRunningInCwd, isCodexProcessRunningInCwd, isOpencodeProcessRunningInCwd, isGrokProcessRunningInCwd, killClaudeProcessInCwd, killCodexProcessInCwd, killOpencodeProcessInCwd, killGrokProcessInCwd, findClaudeProcessPidInCwd, findCodexProcessPidInCwd, findOpencodeProcessPidInCwd, findGrokProcessPidInCwd, } from '../claude/session-loader.js';
|
|
6
6
|
import * as agentService from './agent-service.js';
|
|
7
7
|
import { loadRunningProcesses, isProcessRunning } from '../data/index.js';
|
|
8
8
|
import { logger } from '../utils/logger.js';
|
|
9
|
-
import { createClaudeRuntimeProvider, createCodexRuntimeProvider, createOpencodeRuntimeProvider, } from '../runtime/index.js';
|
|
9
|
+
import { createClaudeRuntimeProvider, createCodexRuntimeProvider, createOpencodeRuntimeProvider, createGrokRuntimeProvider, } from '../runtime/index.js';
|
|
10
10
|
import { createRuntimeCommandExecution, } from './runtime-command-execution.js';
|
|
11
11
|
import { createRuntimeEventHandlers } from './runtime-events.js';
|
|
12
12
|
import { createRuntimeStatusSync } from './runtime-status-sync.js';
|
|
@@ -18,6 +18,7 @@ const runtimeProviders = {
|
|
|
18
18
|
claude: createClaudeRuntimeProvider(),
|
|
19
19
|
codex: createCodexRuntimeProvider(),
|
|
20
20
|
opencode: createOpencodeRuntimeProvider(),
|
|
21
|
+
grok: createGrokRuntimeProvider(),
|
|
21
22
|
};
|
|
22
23
|
const runners = new Map();
|
|
23
24
|
function getRunner(provider) {
|
|
@@ -55,6 +56,9 @@ async function isProviderProcessRunningInCwd(provider, cwd) {
|
|
|
55
56
|
if (provider === 'opencode') {
|
|
56
57
|
return isOpencodeProcessRunningInCwd(cwd);
|
|
57
58
|
}
|
|
59
|
+
if (provider === 'grok') {
|
|
60
|
+
return isGrokProcessRunningInCwd(cwd);
|
|
61
|
+
}
|
|
58
62
|
return isClaudeProcessRunningInCwd(cwd);
|
|
59
63
|
}
|
|
60
64
|
async function killDetachedProviderProcessInCwd(provider, cwd) {
|
|
@@ -64,6 +68,9 @@ async function killDetachedProviderProcessInCwd(provider, cwd) {
|
|
|
64
68
|
if (provider === 'opencode') {
|
|
65
69
|
return killOpencodeProcessInCwd(cwd);
|
|
66
70
|
}
|
|
71
|
+
if (provider === 'grok') {
|
|
72
|
+
return killGrokProcessInCwd(cwd);
|
|
73
|
+
}
|
|
67
74
|
return killClaudeProcessInCwd(cwd);
|
|
68
75
|
}
|
|
69
76
|
export function on(event, listener) {
|
|
@@ -147,6 +154,13 @@ export function init() {
|
|
|
147
154
|
onComplete: runtimeEvents.handleComplete,
|
|
148
155
|
onError: runtimeEvents.handleError,
|
|
149
156
|
}));
|
|
157
|
+
runners.set('grok', runtimeProviders.grok.createRunner({
|
|
158
|
+
onEvent: runtimeEvents.handleEvent,
|
|
159
|
+
onOutput: runtimeEvents.handleOutput,
|
|
160
|
+
onSessionId: runtimeEvents.handleSessionId,
|
|
161
|
+
onComplete: runtimeEvents.handleComplete,
|
|
162
|
+
onError: runtimeEvents.handleError,
|
|
163
|
+
}));
|
|
150
164
|
// Start each runner's background work (orphan recovery, persist timer,
|
|
151
165
|
// watchdog). The constructor is now side-effect-free so non-canonical
|
|
152
166
|
// contexts (tests, scripts, sidecars) that import the runner code don't
|
|
@@ -280,7 +294,9 @@ export async function getAgentRuntimeProcessInfo(agentId) {
|
|
|
280
294
|
? await findCodexProcessPidInCwd(agent.cwd)
|
|
281
295
|
: provider === 'opencode'
|
|
282
296
|
? await findOpencodeProcessPidInCwd(agent.cwd)
|
|
283
|
-
:
|
|
297
|
+
: provider === 'grok'
|
|
298
|
+
? await findGrokProcessPidInCwd(agent.cwd)
|
|
299
|
+
: await findClaudeProcessPidInCwd(agent.cwd);
|
|
284
300
|
if (discoveredPid && isProcessRunning(discoveredPid)) {
|
|
285
301
|
return {
|
|
286
302
|
pid: discoveredPid,
|
|
@@ -28,32 +28,60 @@ export function getShortPath(filePath, maxLen = 40) {
|
|
|
28
28
|
*/
|
|
29
29
|
export function getToolKeyParam(toolName, input) {
|
|
30
30
|
switch (toolName) {
|
|
31
|
-
case 'WebSearch':
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
case 'WebSearch': {
|
|
32
|
+
const query = (input.query || input.q || input.search);
|
|
33
|
+
return query ? `"${truncate(query, 40)}"` : null;
|
|
34
|
+
}
|
|
35
|
+
case 'WebFetch': {
|
|
36
|
+
const url = (input.url || input.target_url || input.targetUrl);
|
|
37
|
+
return url ? truncate(url, 60) : null;
|
|
38
|
+
}
|
|
35
39
|
case 'Read':
|
|
36
40
|
case 'Write':
|
|
37
|
-
case 'Edit':
|
|
38
|
-
|
|
41
|
+
case 'Edit': {
|
|
42
|
+
// Claude: file_path; Grok: target_file
|
|
43
|
+
const filePath = (input.file_path
|
|
44
|
+
|| input.filePath
|
|
45
|
+
|| input.target_file
|
|
46
|
+
|| input.targetFile
|
|
47
|
+
|| input.path);
|
|
39
48
|
return getShortPath(filePath);
|
|
49
|
+
}
|
|
50
|
+
case 'ListFiles':
|
|
51
|
+
case 'list_dir': {
|
|
52
|
+
const dir = (input.target_directory
|
|
53
|
+
|| input.targetDirectory
|
|
54
|
+
|| input.path
|
|
55
|
+
|| input.directory);
|
|
56
|
+
return getShortPath(dir);
|
|
57
|
+
}
|
|
40
58
|
case 'Bash':
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
case 'ExecuteCommand': {
|
|
60
|
+
const cmd = (input.command || input.cmd);
|
|
61
|
+
if (cmd)
|
|
62
|
+
return truncate(cmd, 60);
|
|
63
|
+
const desc = input.description;
|
|
64
|
+
return desc ? truncate(desc, 60) : null;
|
|
65
|
+
}
|
|
43
66
|
case 'Grep':
|
|
44
|
-
|
|
67
|
+
case 'SearchFiles': {
|
|
68
|
+
const pattern = (input.pattern || input.query);
|
|
69
|
+
return pattern ? `"${truncate(pattern, 40)}"` : null;
|
|
70
|
+
}
|
|
45
71
|
case 'Glob':
|
|
46
|
-
return truncate(input.pattern, 50);
|
|
72
|
+
return truncate((input.pattern || input.glob), 50);
|
|
47
73
|
case 'Task':
|
|
74
|
+
case 'Agent':
|
|
48
75
|
return truncate(input.description, 50);
|
|
49
|
-
case 'TodoWrite':
|
|
76
|
+
case 'TodoWrite': {
|
|
50
77
|
const todos = input.todos;
|
|
51
78
|
if (todos?.length) {
|
|
52
79
|
return `${todos.length} item${todos.length > 1 ? 's' : ''}`;
|
|
53
80
|
}
|
|
54
81
|
return null;
|
|
82
|
+
}
|
|
55
83
|
case 'NotebookEdit':
|
|
56
|
-
return getFileName(input.notebook_path);
|
|
84
|
+
return getFileName((input.notebook_path || input.notebookPath || input.target_file || input.file_path));
|
|
57
85
|
case 'AskUserQuestion':
|
|
58
86
|
return 'clarification';
|
|
59
87
|
default:
|
|
@@ -9,6 +9,7 @@ import { agentService, runtimeService, skillService, customClassService, bossSer
|
|
|
9
9
|
import { markInstructionsDirty } from '../../services/instruction-refresh.js';
|
|
10
10
|
import { createLogger } from '../../utils/index.js';
|
|
11
11
|
import { ClaudeBackend, parseContextOutput } from '../../claude/backend.js';
|
|
12
|
+
import { getGrokSessionDir, readGrokSignalsUsage } from '../../grok/session-watcher.js';
|
|
12
13
|
const log = createLogger('AgentHandler');
|
|
13
14
|
const claudeBackend = new ClaudeBackend();
|
|
14
15
|
// Test change: Server restart validation - if you see this log, the server restarted successfully
|
|
@@ -58,12 +59,14 @@ export async function handleSpawnAgent(ctx, payload) {
|
|
|
58
59
|
position: payload.position,
|
|
59
60
|
initialSkillIds: payload.initialSkillIds,
|
|
60
61
|
model: payload.model,
|
|
62
|
+
opencodeModel: payload.opencodeModel,
|
|
63
|
+
grokModel: payload.grokModel,
|
|
61
64
|
customInstructions: payload.customInstructions ? `${payload.customInstructions.length} chars` : undefined,
|
|
62
65
|
});
|
|
63
66
|
try {
|
|
64
67
|
const agent = await agentService.createAgent(payload.name, payload.class, payload.cwd, payload.position, payload.sessionId, payload.useChrome, payload.permissionMode, undefined, // initialSkillIds handled separately below
|
|
65
68
|
undefined, // isBoss
|
|
66
|
-
payload.model, payload.codexModel, payload.customInstructions, payload.provider, payload.codexConfig, payload.effort);
|
|
69
|
+
payload.model, payload.codexModel, payload.customInstructions, payload.provider, payload.codexConfig, payload.effort, payload.opencodeModel, payload.grokModel);
|
|
67
70
|
log.log('Agent created successfully:', {
|
|
68
71
|
id: agent.id,
|
|
69
72
|
name: agent.name,
|
|
@@ -119,7 +122,7 @@ async function duplicateAgentConfig(source, name, position) {
|
|
|
119
122
|
.map((skill) => skill.id);
|
|
120
123
|
const agent = await agentService.createAgent(name, source.class, source.cwd, position, undefined, // sessionId - never share the source's; clone=fresh, fork=set below
|
|
121
124
|
source.useChrome, source.permissionMode, undefined, // initialSkillIds handled separately below
|
|
122
|
-
source.isBoss, source.model, source.codexModel, source.customInstructions, source.provider, source.codexConfig, source.effort, source.opencodeModel);
|
|
125
|
+
source.isBoss, source.model, source.codexModel, source.customInstructions, source.provider, source.codexConfig, source.effort, source.opencodeModel, source.grokModel);
|
|
123
126
|
// Re-apply skills: copied direct assignments + class defaults.
|
|
124
127
|
const classDefaultSkills = customClassService.getClassDefaultSkillIds(agent.class);
|
|
125
128
|
const allSkillIds = [...new Set([...directSkillIds, ...classDefaultSkills])];
|
|
@@ -135,7 +138,7 @@ function duplicateOffset(source) {
|
|
|
135
138
|
// Providers whose conversation history can be forked (resume + native fork flag).
|
|
136
139
|
// Codex is intentionally excluded for now (no headless fork; would need rollout
|
|
137
140
|
// duplication) — forking a Codex agent gracefully degrades to a plain clone.
|
|
138
|
-
const FORKABLE_PROVIDERS = new Set(['claude', 'opencode']);
|
|
141
|
+
const FORKABLE_PROVIDERS = new Set(['claude', 'opencode', 'grok']);
|
|
139
142
|
/**
|
|
140
143
|
* Handle clone_agent message - duplicates an existing agent's configuration
|
|
141
144
|
* into a brand-new agent (fresh session, no inherited context/memory).
|
|
@@ -614,8 +617,11 @@ function buildStatsFromTrackedData(agent) {
|
|
|
614
617
|
// Do NOT prefer agent.contextStats here — those can become stale when previous
|
|
615
618
|
// fallback calls save their (potentially wrong) output back to agent.contextStats
|
|
616
619
|
// via broadcastContextStats, creating a self-reinforcing feedback loop.
|
|
617
|
-
const
|
|
618
|
-
|
|
620
|
+
const provider = agent.provider ?? 'claude';
|
|
621
|
+
const defaultContextLimit = provider === 'codex' ? 258400
|
|
622
|
+
: provider === 'opencode' ? 200000
|
|
623
|
+
: provider === 'grok' ? 500000
|
|
624
|
+
: 200000;
|
|
619
625
|
const contextLimit = Math.max(1, Math.round(agent.contextLimit || defaultContextLimit));
|
|
620
626
|
const rawContextUsed = Math.max(0, Math.round(agent.contextUsed || 0));
|
|
621
627
|
// Guard: contextUsed can never exceed contextLimit. Values above the limit are
|
|
@@ -629,7 +635,7 @@ function buildStatsFromTrackedData(agent) {
|
|
|
629
635
|
}
|
|
630
636
|
const usedPercent = Math.min(100, Math.round((contextUsed / contextLimit) * 100));
|
|
631
637
|
const freeTokens = Math.max(0, contextLimit - contextUsed);
|
|
632
|
-
const model = agent.model || agent.codexModel || agent.opencodeModel || 'unknown';
|
|
638
|
+
const model = agent.model || agent.codexModel || agent.opencodeModel || agent.grokModel || 'unknown';
|
|
633
639
|
return {
|
|
634
640
|
model,
|
|
635
641
|
contextWindow: contextLimit,
|
|
@@ -748,12 +754,47 @@ export async function handleRequestContextStats(ctx, payload) {
|
|
|
748
754
|
return;
|
|
749
755
|
}
|
|
750
756
|
}
|
|
757
|
+
// Grok: streaming-json has no usage events. Read signals.json from the session dir.
|
|
758
|
+
const isGrokProvider = (agent.provider ?? 'claude') === 'grok';
|
|
759
|
+
if (isGrokProvider && agent.sessionId && agent.cwd) {
|
|
760
|
+
try {
|
|
761
|
+
const sessionDir = getGrokSessionDir(agent.cwd, agent.sessionId);
|
|
762
|
+
const usage = readGrokSignalsUsage(sessionDir);
|
|
763
|
+
if (usage) {
|
|
764
|
+
const contextLimit = Math.max(1, usage.contextWindowTokens);
|
|
765
|
+
const contextUsed = Math.max(0, Math.min(usage.contextTokensUsed, contextLimit));
|
|
766
|
+
const usedPercent = Math.min(100, Math.round(usage.contextWindowUsage ?? (contextUsed / contextLimit) * 100));
|
|
767
|
+
const freeTokens = Math.max(0, contextLimit - contextUsed);
|
|
768
|
+
const stats = {
|
|
769
|
+
model: agent.grokModel || agent.model || 'grok',
|
|
770
|
+
contextWindow: contextLimit,
|
|
771
|
+
totalTokens: contextUsed,
|
|
772
|
+
usedPercent,
|
|
773
|
+
categories: {
|
|
774
|
+
systemPrompt: { tokens: 0, percent: 0 },
|
|
775
|
+
systemTools: { tokens: 0, percent: 0 },
|
|
776
|
+
messages: { tokens: contextUsed, percent: Number(((contextUsed / contextLimit) * 100).toFixed(1)) },
|
|
777
|
+
freeSpace: { tokens: freeTokens, percent: Number(((freeTokens / contextLimit) * 100).toFixed(1)) },
|
|
778
|
+
autocompactBuffer: { tokens: 0, percent: 0 },
|
|
779
|
+
},
|
|
780
|
+
lastUpdated: Date.now(),
|
|
781
|
+
};
|
|
782
|
+
log.log(`[contextStats] Grok signals.json for ${agent.name}: ${contextUsed}/${contextLimit}`);
|
|
783
|
+
broadcastContextStats(ctx, payload.agentId, stats, 'from Grok signals.json');
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
log.warn(`[contextStats] Grok signals.json missing/unreadable for ${agent.name} session=${agent.sessionId}`);
|
|
787
|
+
}
|
|
788
|
+
catch (err) {
|
|
789
|
+
log.error(`[contextStats] Grok signals read failed: ${err}`);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
751
792
|
// Fallback: generate from tracked data
|
|
752
793
|
const latestAgent = agentService.getAgent(payload.agentId) || agent;
|
|
753
794
|
const stats = buildStatsFromTrackedData(latestAgent);
|
|
754
|
-
const label = latestAgent.provider === 'codex'
|
|
755
|
-
|
|
756
|
-
|
|
795
|
+
const label = latestAgent.provider === 'codex' || latestAgent.provider === 'opencode' || latestAgent.provider === 'grok'
|
|
796
|
+
? 'estimated from turn usage'
|
|
797
|
+
: 'tracked from token usage';
|
|
757
798
|
broadcastContextStats(ctx, payload.agentId, stats, label);
|
|
758
799
|
}
|
|
759
800
|
/**
|
|
@@ -813,10 +854,14 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
813
854
|
const normalizedUpdatedOpencodeModel = updates.opencodeModel !== undefined
|
|
814
855
|
? agentService.sanitizeOpencodeModel(updates.opencodeModel)
|
|
815
856
|
: undefined;
|
|
857
|
+
const normalizedUpdatedGrokModel = updates.grokModel !== undefined
|
|
858
|
+
? agentService.sanitizeGrokModel(updates.grokModel)
|
|
859
|
+
: undefined;
|
|
816
860
|
// Track if model changed (requires hot restart to apply new model while preserving context)
|
|
817
861
|
const modelChanged = updates.model !== undefined && normalizedUpdatedModel !== agent.model;
|
|
818
862
|
const codexModelChanged = updates.codexModel !== undefined && normalizedUpdatedCodexModel !== agent.codexModel;
|
|
819
863
|
const opencodeModelChanged = updates.opencodeModel !== undefined && normalizedUpdatedOpencodeModel !== agent.opencodeModel;
|
|
864
|
+
const grokModelChanged = updates.grokModel !== undefined && normalizedUpdatedGrokModel !== agent.grokModel;
|
|
820
865
|
const providerChanged = updates.provider !== undefined && updates.provider !== agent.provider;
|
|
821
866
|
const classChanged = updates.class !== undefined && updates.class !== agent.class;
|
|
822
867
|
const codexConfigChanged = updates.codexConfig !== undefined
|
|
@@ -878,6 +923,9 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
878
923
|
if (updates.opencodeModel !== undefined) {
|
|
879
924
|
agentUpdates.opencodeModel = normalizedUpdatedOpencodeModel;
|
|
880
925
|
}
|
|
926
|
+
if (updates.grokModel !== undefined) {
|
|
927
|
+
agentUpdates.grokModel = normalizedUpdatedGrokModel;
|
|
928
|
+
}
|
|
881
929
|
if (updates.effort !== undefined) {
|
|
882
930
|
agentUpdates.effort = updates.effort;
|
|
883
931
|
}
|
|
@@ -920,7 +968,8 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
920
968
|
}
|
|
921
969
|
// If model changed, do a hot restart: stop process, resume with new model
|
|
922
970
|
// This preserves context by using --resume with the existing sessionId
|
|
923
|
-
|
|
971
|
+
const modelLikeChanged = modelChanged || codexModelChanged || opencodeModelChanged || grokModelChanged || providerChanged || codexConfigChanged || classChanged;
|
|
972
|
+
if (modelLikeChanged && sessionId) {
|
|
924
973
|
const reason = providerChanged
|
|
925
974
|
? `runtime changed to ${updates.provider}`
|
|
926
975
|
: classChanged
|
|
@@ -931,7 +980,9 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
931
980
|
? `Codex model changed to ${updates.codexModel}`
|
|
932
981
|
: opencodeModelChanged
|
|
933
982
|
? `OpenCode model changed to ${updates.opencodeModel}`
|
|
934
|
-
:
|
|
983
|
+
: grokModelChanged
|
|
984
|
+
? `Grok model changed to ${updates.grokModel}`
|
|
985
|
+
: `model changed to ${updates.model}`;
|
|
935
986
|
log.log(`Agent ${agent.name}: ${reason}, hot restarting with --resume to preserve context`);
|
|
936
987
|
try {
|
|
937
988
|
await runtimeService.stopAgent(agentId);
|
|
@@ -946,7 +997,7 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
946
997
|
log.error(`Failed to hot restart agent ${agent.name} after runtime config change:`, err);
|
|
947
998
|
}
|
|
948
999
|
}
|
|
949
|
-
else if (
|
|
1000
|
+
else if (modelLikeChanged && !sessionId) {
|
|
950
1001
|
const reason = providerChanged
|
|
951
1002
|
? `runtime changed to ${updates.provider}`
|
|
952
1003
|
: classChanged
|
|
@@ -957,12 +1008,14 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
957
1008
|
? `Codex model changed to ${updates.codexModel}`
|
|
958
1009
|
: opencodeModelChanged
|
|
959
1010
|
? `OpenCode model changed to ${updates.opencodeModel}`
|
|
960
|
-
:
|
|
1011
|
+
: grokModelChanged
|
|
1012
|
+
? `Grok model changed to ${updates.grokModel}`
|
|
1013
|
+
: `model changed to ${updates.model}`;
|
|
961
1014
|
log.log(`Agent ${agent.name}: ${reason}, will apply on next session start`);
|
|
962
1015
|
}
|
|
963
1016
|
// If Chrome flag changed, do a hot restart to add/remove --chrome flag
|
|
964
1017
|
// Only restart if model didn't already trigger a restart
|
|
965
|
-
if (useChromeChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !providerChanged && !codexConfigChanged && sessionId) {
|
|
1018
|
+
if (useChromeChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !providerChanged && !codexConfigChanged && sessionId) {
|
|
966
1019
|
const chromeStatus = updates.useChrome ? 'enabled' : 'disabled';
|
|
967
1020
|
log.log(`Agent ${agent.name}: Chrome ${chromeStatus}, hot restarting with --resume to apply change`);
|
|
968
1021
|
try {
|
|
@@ -982,13 +1035,13 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
982
1035
|
log.error(`Failed to hot restart agent ${agent.name} after Chrome change:`, err);
|
|
983
1036
|
}
|
|
984
1037
|
}
|
|
985
|
-
else if (useChromeChanged && !providerChanged && !codexConfigChanged && !codexModelChanged && !opencodeModelChanged && !sessionId) {
|
|
1038
|
+
else if (useChromeChanged && !providerChanged && !codexConfigChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !sessionId) {
|
|
986
1039
|
// No existing session, chrome flag will apply on next start
|
|
987
1040
|
const chromeStatus = updates.useChrome ? 'enabled' : 'disabled';
|
|
988
1041
|
log.log(`Agent ${agent.name}: Chrome ${chromeStatus}, will apply on next session start`);
|
|
989
1042
|
}
|
|
990
1043
|
// If effort changed, hot restart to apply new --effort flag
|
|
991
|
-
if (effortChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && sessionId) {
|
|
1044
|
+
if (effortChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && sessionId) {
|
|
992
1045
|
const effortLabel = updates.effort || 'default';
|
|
993
1046
|
log.log(`Agent ${agent.name}: effort changed to ${effortLabel}, hot restarting with --resume to apply change`);
|
|
994
1047
|
try {
|
|
@@ -1052,7 +1105,7 @@ export async function handleUpdateAgentProperties(ctx, payload) {
|
|
|
1052
1105
|
}
|
|
1053
1106
|
// If skills changed and we didn't already hot restart for model/chrome/cwd change, do it now
|
|
1054
1107
|
// Skills are injected into the system prompt, so we need to restart to apply them
|
|
1055
|
-
if (skillsChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && !cwdChanged && sessionId) {
|
|
1108
|
+
if (skillsChanged && !modelChanged && !codexModelChanged && !opencodeModelChanged && !grokModelChanged && !providerChanged && !codexConfigChanged && !classChanged && !useChromeChanged && !cwdChanged && sessionId) {
|
|
1056
1109
|
log.log(`Agent ${agent.name}: Skills changed, hot restarting with --resume to apply new system prompt`);
|
|
1057
1110
|
try {
|
|
1058
1111
|
// Stop the current Claude process
|