mixdog 0.9.86 → 0.9.87
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/package.json +2 -2
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +125 -16
- package/src/runtime/agent/orchestrator/session/manager.mjs +3 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +9 -2
- package/src/runtime/agent/orchestrator/tools/env-scrub.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/token-manifest.json +23 -2
- package/src/runtime/memory/lib/memory-action-handlers.mjs +4 -1
- package/src/runtime/memory/tool-defs.mjs +19 -3
- package/src/session-runtime/lifecycle-api.mjs +15 -0
- package/src/session-runtime/provider-auth-api.mjs +8 -0
- package/src/session-runtime/provider-usage.mjs +30 -5
- package/src/session-runtime/runtime-core.mjs +267 -481
- package/src/session-runtime/session-lifecycle.mjs +378 -0
- package/src/standalone/agent-shard/shard-pool.mjs +6 -5
- package/src/standalone/agent-tool/job-views.mjs +329 -0
- package/src/standalone/agent-tool/spawn-flow.mjs +629 -0
- package/src/standalone/agent-tool/tag-registry.mjs +340 -0
- package/src/standalone/agent-tool.mjs +100 -1151
- package/src/standalone/usage-dashboard.mjs +23 -1
- package/src/tui/App.jsx +362 -2576
- package/src/tui/app/app-view.jsx +504 -0
- package/src/tui/app/create-app-pickers.mjs +313 -0
- package/src/tui/app/prompt-submit.mjs +501 -0
- package/src/tui/app/shell-layout.mjs +563 -0
- package/src/tui/app/usage-context-panels.mjs +288 -0
- package/src/tui/app/use-copy-selection.mjs +56 -0
- package/src/tui/app/use-global-key-input.mjs +151 -0
- package/src/tui/app/use-pasted-buffers.mjs +115 -0
- package/src/tui/app/use-prompt-draft-flow.mjs +167 -0
- package/src/tui/app/use-prompt-hint.mjs +58 -0
- package/src/tui/app/use-prompt-queue-history.mjs +100 -0
- package/src/tui/app/use-terminal-chrome.mjs +72 -0
- package/src/tui/app/use-transcript-activity.mjs +131 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +96 -0
- package/src/tui/dist/index.mjs +9802 -9024
- package/src/tui/engine/session-api-ext.mjs +23 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
// Session lifecycle, extracted from runtime-core.mjs: first-turn route
|
|
2
|
+
// resolution, route-effort refresh, and createCurrentSession (provider
|
|
3
|
+
// session construction with MCP wiring and reset handling). Shared mutable
|
|
4
|
+
// runtime state flows through the rt bag.
|
|
5
|
+
import { ensureProviderEnabled, normalizeCompactionConfig } from './config-helpers.mjs';
|
|
6
|
+
import { clean, hasOwn } from './session-text.mjs';
|
|
7
|
+
import { coerceEffortFor, deferredSurfaceModeForLead, effortItemsFor, toolSpecForMode } from './effort.mjs';
|
|
8
|
+
import { fastCapableFor } from './model-capabilities.mjs';
|
|
9
|
+
import { bootProfile } from './boot-profile.mjs';
|
|
10
|
+
import { STANDALONE_DATA_DIR } from './runtime-paths.mjs';
|
|
11
|
+
import { LEAD_DISALLOWED_TOOLS } from './tool-defs.mjs';
|
|
12
|
+
import { attachSessionHooks } from './session-hooks.mjs';
|
|
13
|
+
import { applyDeferredToolSurface } from './tool-catalog.mjs';
|
|
14
|
+
import { writeStatuslineRoute } from './statusline-route.mjs';
|
|
15
|
+
import { createWarmupSchedulers } from './warmup-schedulers.mjs';
|
|
16
|
+
import { warmCatalogsInBackground } from '../runtime/agent/orchestrator/providers/model-catalog.mjs';
|
|
17
|
+
import { envFlag } from './env.mjs';
|
|
18
|
+
import { createPrewarmSchedulers } from './prewarm.mjs';
|
|
19
|
+
import { hasActiveAutomation } from '../standalone/channel-admin.mjs';
|
|
20
|
+
import { createRemoteTranscript } from './remote-transcript.mjs';
|
|
21
|
+
export function createSessionLifecycle({
|
|
22
|
+
rt,
|
|
23
|
+
collectProviderModels,
|
|
24
|
+
ensureProvidersReady,
|
|
25
|
+
lookupModelMeta,
|
|
26
|
+
mgr,
|
|
27
|
+
loadCoreMemoryContext,
|
|
28
|
+
awaitKeychainPrewarm,
|
|
29
|
+
ensureConfigForRouteProvider,
|
|
30
|
+
reg,
|
|
31
|
+
cfgMod,
|
|
32
|
+
activeWorkflowContext,
|
|
33
|
+
memoryEnabled,
|
|
34
|
+
hooks,
|
|
35
|
+
hookCommonPayload,
|
|
36
|
+
mcpClient,
|
|
37
|
+
modelStandaloneTools,
|
|
38
|
+
applyPreSessionToolSelection,
|
|
39
|
+
statusRoutes,
|
|
40
|
+
warmupTimers,
|
|
41
|
+
providerModelCaches,
|
|
42
|
+
reloadFullConfig,
|
|
43
|
+
refreshStatuslineUsageSnapshot,
|
|
44
|
+
warmProviderModelCache,
|
|
45
|
+
cachedProviderSetup,
|
|
46
|
+
providerWarmupDelayMs,
|
|
47
|
+
providerSetupWarmupDelayMs,
|
|
48
|
+
providerModelWarmupDelayMs,
|
|
49
|
+
modelCatalogWarmupDelayMs,
|
|
50
|
+
statuslineUsageWarmupDelayMs,
|
|
51
|
+
statuslineUsageRefreshDelayMs,
|
|
52
|
+
backgroundBusyRetryMs,
|
|
53
|
+
providerWarmupEnabled,
|
|
54
|
+
modelPrefetchEnabled,
|
|
55
|
+
modelCatalogWarmupEnabled,
|
|
56
|
+
prewarmTimers,
|
|
57
|
+
channelsEnabled,
|
|
58
|
+
getCodeGraphModule,
|
|
59
|
+
channels,
|
|
60
|
+
codeGraphPrewarmDelayMs,
|
|
61
|
+
channelStartDelayMs,
|
|
62
|
+
sessionPrewarmDelayMs,
|
|
63
|
+
codeGraphPrewarmEnabled,
|
|
64
|
+
sessionPrewarmEnabled,
|
|
65
|
+
prewarmState,
|
|
66
|
+
}) {
|
|
67
|
+
async function resolveMissingRouteModelForFirstTurn() {
|
|
68
|
+
if (routeHasModel()) return rt.route;
|
|
69
|
+
const models = await collectProviderModels();
|
|
70
|
+
const picked = models[0] || null;
|
|
71
|
+
if (!picked) {
|
|
72
|
+
throw new Error('No provider models available. Open /providers to sign in, then /model to choose a model.');
|
|
73
|
+
}
|
|
74
|
+
rt.route = {
|
|
75
|
+
...rt.route,
|
|
76
|
+
provider: picked.provider,
|
|
77
|
+
model: picked.id,
|
|
78
|
+
preset: null,
|
|
79
|
+
};
|
|
80
|
+
return rt.route;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function refreshRouteEffort(modelMetaOverride = null, expectedRoute = null) {
|
|
84
|
+
const targetRoute = expectedRoute || rt.route;
|
|
85
|
+
await ensureProvidersReady(ensureProviderEnabled(rt.config, targetRoute.provider));
|
|
86
|
+
const modelMeta = modelMetaOverride || await lookupModelMeta(targetRoute.provider, targetRoute.model);
|
|
87
|
+
// A rapid second resume/model change can replace the route while provider
|
|
88
|
+
// metadata is loading. Never let the older completion overwrite it.
|
|
89
|
+
if (expectedRoute && rt.route !== expectedRoute) return null;
|
|
90
|
+
const requested = hasOwn(targetRoute, 'effort')
|
|
91
|
+
? targetRoute.effort
|
|
92
|
+
: (targetRoute.preset?.effort || null);
|
|
93
|
+
const effectiveEffort = coerceEffortFor(targetRoute.provider, modelMeta, requested);
|
|
94
|
+
const fastCapable = fastCapableFor(targetRoute.provider, modelMeta);
|
|
95
|
+
// Carry the catalog display name onto the route so the statusline shows a
|
|
96
|
+
// human label (e.g. "Claude Fable 5") for preset-less direct models instead
|
|
97
|
+
// of the raw id. `name` is only trusted when it differs from the raw model
|
|
98
|
+
// id (some providers echo the id as `name`), so it can't clobber a better
|
|
99
|
+
// already-resolved label. Falls back to existing route.modelDisplay, then unset.
|
|
100
|
+
const metaName = clean(modelMeta?.name);
|
|
101
|
+
const modelDisplay = clean(modelMeta?.display) || clean(modelMeta?.displayName)
|
|
102
|
+
|| (metaName && metaName !== clean(targetRoute.model) ? metaName : '')
|
|
103
|
+
|| clean(targetRoute.modelDisplay);
|
|
104
|
+
rt.route = {
|
|
105
|
+
...targetRoute,
|
|
106
|
+
fast: fastCapable ? targetRoute.fast === true : false,
|
|
107
|
+
fastCapable,
|
|
108
|
+
effectiveEffort,
|
|
109
|
+
effortOptions: effortItemsFor(rt.route.provider, modelMeta, effectiveEffort),
|
|
110
|
+
...(modelDisplay ? { modelDisplay } : {}),
|
|
111
|
+
};
|
|
112
|
+
return rt.route;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function routeHasModel() {
|
|
116
|
+
return !!clean(rt.route?.model);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function requireModelRoute() {
|
|
120
|
+
if (routeHasModel()) return;
|
|
121
|
+
throw new Error('No model configured. Open /providers to sign in, then /model to choose a model.');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function recreateCurrentSessionIfReady() {
|
|
125
|
+
if (!routeHasModel()) {
|
|
126
|
+
rt.session = null;
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return await createCurrentSession();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function createCurrentSession(reason = 'demand') {
|
|
133
|
+
if (rt.sessionCreatePromise) return await rt.sessionCreatePromise;
|
|
134
|
+
if (rt.session?.id && !rt.sessionNeedsCwdRefresh) {
|
|
135
|
+
const liveSession = mgr.getSession(rt.session.id);
|
|
136
|
+
if (liveSession && liveSession.closed !== true && liveSession.status !== 'closed') {
|
|
137
|
+
rt.session = liveSession;
|
|
138
|
+
return rt.session;
|
|
139
|
+
}
|
|
140
|
+
rt.session = null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const startedAt = performance.now();
|
|
144
|
+
bootProfile('session:create:start', { mode: rt.mode, reason });
|
|
145
|
+
const promise = (async () => {
|
|
146
|
+
// Demand-only: this starts only after the user submits (unless an
|
|
147
|
+
// explicitly enabled prewarm caller asks for a session). Core-memory
|
|
148
|
+
// startup does not depend on keychain/provider readiness, so overlap the
|
|
149
|
+
// two cold paths instead of paying their bounded waits serially.
|
|
150
|
+
const coreMemoryContextPromise = loadCoreMemoryContext();
|
|
151
|
+
await awaitKeychainPrewarm();
|
|
152
|
+
ensureConfigForRouteProvider();
|
|
153
|
+
await resolveMissingRouteModelForFirstTurn();
|
|
154
|
+
requireModelRoute();
|
|
155
|
+
bootProfile('session:create:route-ready', { ms: (performance.now() - startedAt).toFixed(1) });
|
|
156
|
+
// Route effort waits on provider readiness while the already-started
|
|
157
|
+
// memory load continues independently.
|
|
158
|
+
const [, coreMemoryContext] = await Promise.all([
|
|
159
|
+
refreshRouteEffort(),
|
|
160
|
+
coreMemoryContextPromise,
|
|
161
|
+
]);
|
|
162
|
+
bootProfile('session:create:effort-ready', { ms: (performance.now() - startedAt).toFixed(1) });
|
|
163
|
+
const providerImpl = reg.getProvider(rt.route.provider);
|
|
164
|
+
if (!providerImpl) {
|
|
165
|
+
throw new Error(`Provider "${rt.route.provider}" is not configured.`);
|
|
166
|
+
}
|
|
167
|
+
bootProfile('session:create:provider-ready', { ms: (performance.now() - startedAt).toFixed(1) });
|
|
168
|
+
if (rt.closeRequested) throw new Error('runtime is closing');
|
|
169
|
+
const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
|
|
170
|
+
// Load the active WORKFLOW.md pack once for both summary + context block.
|
|
171
|
+
const { summary: workflow, context: workflowContext } = activeWorkflowContext(rt.config, dataDir);
|
|
172
|
+
const sessionOpts = {
|
|
173
|
+
provider: rt.route.provider,
|
|
174
|
+
model: rt.route.model,
|
|
175
|
+
preset: rt.route.preset || undefined,
|
|
176
|
+
tools: toolSpecForMode(rt.mode),
|
|
177
|
+
owner: 'cli',
|
|
178
|
+
agent: 'lead',
|
|
179
|
+
lane: 'cli',
|
|
180
|
+
sourceType: 'lead',
|
|
181
|
+
sourceName: 'main',
|
|
182
|
+
clientHostPid: process.pid,
|
|
183
|
+
disallowedTools: LEAD_DISALLOWED_TOOLS,
|
|
184
|
+
cwd: rt.currentCwd,
|
|
185
|
+
...(rt.desktopSession && typeof rt.desktopSession === 'object' ? { desktopSession: rt.desktopSession } : {}),
|
|
186
|
+
coreMemoryContext,
|
|
187
|
+
workflow,
|
|
188
|
+
workflowContext,
|
|
189
|
+
fast: rt.route.fast === true,
|
|
190
|
+
compaction: rt.config.compaction && typeof rt.config.compaction === 'object'
|
|
191
|
+
? normalizeCompactionConfig(rt.config.compaction, { memoryEnabled: memoryEnabled() })
|
|
192
|
+
: undefined,
|
|
193
|
+
};
|
|
194
|
+
if (hasOwn(rt.route, 'effort') || rt.route.effectiveEffort) {
|
|
195
|
+
sessionOpts.effort = rt.route.effectiveEffort || null;
|
|
196
|
+
}
|
|
197
|
+
rt.session = mgr.createSession(sessionOpts);
|
|
198
|
+
rt.sessionNeedsCwdRefresh = false;
|
|
199
|
+
attachSessionHooks(rt.session, { hooks, hookCommonPayload, getCwd: () => rt.currentCwd });
|
|
200
|
+
// Every-create MCP fold (NO blocking): seed the INITIAL provider-visible
|
|
201
|
+
// surface (and native BP1 manifest) from MCP servers connected at create
|
|
202
|
+
// time. There is no await — a boot connect still mid-handshake is caught on
|
|
203
|
+
// the first user turn by refreshInitialDeferredMcpSurface (session-turn-api),
|
|
204
|
+
// which re-folds the live registry into the first-turn surface before the
|
|
205
|
+
// prompt renders. This fold keeps recreate paths (cwd change with MCP
|
|
206
|
+
// already connected) seeding their manifest instead of re-announcing late.
|
|
207
|
+
let connectedMcpTools = [];
|
|
208
|
+
try { connectedMcpTools = mcpClient.getMcpTools?.() || []; }
|
|
209
|
+
catch { connectedMcpTools = []; }
|
|
210
|
+
applyDeferredToolSurface(
|
|
211
|
+
rt.session,
|
|
212
|
+
deferredSurfaceModeForLead(rt.mode),
|
|
213
|
+
connectedMcpTools.length ? [...modelStandaloneTools(), ...connectedMcpTools] : modelStandaloneTools(),
|
|
214
|
+
{ provider: rt.route.provider },
|
|
215
|
+
);
|
|
216
|
+
// Session-local one-shot: mark this FRESH session eligible for the
|
|
217
|
+
// first-turn deferred-surface refresh (session-turn-api). A resumed
|
|
218
|
+
// session (prior transcript) is NEVER marked, so its already-baked BP1 is
|
|
219
|
+
// never rebuilt or re-announced — the gate is per-session, not the
|
|
220
|
+
// process-wide firstTurnCompleted.
|
|
221
|
+
rt.session.deferredInitialRefreshPending = !/resume/i.test(String(reason || ''));
|
|
222
|
+
applyPreSessionToolSelection();
|
|
223
|
+
writeStatuslineRoute(statusRoutes, rt.session, rt.route);
|
|
224
|
+
hooks.emit('session:create', { sessionId: rt.session.id, provider: rt.route.provider, model: rt.route.model, toolMode: rt.mode, cwd: rt.currentCwd });
|
|
225
|
+
// SessionStart: bridge to the standard project hook bus. Best-effort;
|
|
226
|
+
// a hook error must never break session creation. additionalContext is
|
|
227
|
+
// injected before the first user turn as a system-reminder context pair.
|
|
228
|
+
try {
|
|
229
|
+
const startSource = /resume/i.test(String(reason || ''))
|
|
230
|
+
? 'resume'
|
|
231
|
+
: (/clear/i.test(String(reason || '')) ? 'clear' : 'startup');
|
|
232
|
+
const startDispatch = await hooks.dispatch('SessionStart', hookCommonPayload({ session_id: rt.session.id, source: startSource, model: rt.route.model }));
|
|
233
|
+
const startContext = Array.isArray(startDispatch?.additionalContext)
|
|
234
|
+
? startDispatch.additionalContext.join('\n\n')
|
|
235
|
+
: String(startDispatch?.additionalContext || '');
|
|
236
|
+
if (startContext.trim()) {
|
|
237
|
+
rt.session.messages.push({ role: 'user', content: `<system-reminder>\n# SessionStart Hook Context\n${startContext.trim()}\n</system-reminder>` });
|
|
238
|
+
rt.session.messages.push({ role: 'assistant', content: '.' });
|
|
239
|
+
rt.session.updatedAt = Date.now();
|
|
240
|
+
}
|
|
241
|
+
} catch { /* best-effort: never break session create */ }
|
|
242
|
+
bootProfile('session:create:ready', {
|
|
243
|
+
ms: (performance.now() - startedAt).toFixed(1),
|
|
244
|
+
reason,
|
|
245
|
+
tools: Array.isArray(rt.session.tools) ? rt.session.tools.length : 0,
|
|
246
|
+
catalog: Array.isArray(rt.session.deferredToolCatalog) ? rt.session.deferredToolCatalog.length : 0,
|
|
247
|
+
});
|
|
248
|
+
// A rebind push may have been deferred (e.g. 'acquired' landed before this
|
|
249
|
+
// session existed). The writer is now bindable — flush it exactly once.
|
|
250
|
+
remoteTranscript.flushPendingTranscriptRebind();
|
|
251
|
+
return rt.session;
|
|
252
|
+
})();
|
|
253
|
+
|
|
254
|
+
rt.sessionCreatePromise = promise;
|
|
255
|
+
try {
|
|
256
|
+
return await promise;
|
|
257
|
+
} finally {
|
|
258
|
+
if (rt.sessionCreatePromise === promise) rt.sessionCreatePromise = null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const {
|
|
263
|
+
scheduleProviderWarmup,
|
|
264
|
+
scheduleProviderSetupWarmup,
|
|
265
|
+
scheduleProviderModelWarmup,
|
|
266
|
+
scheduleModelCatalogWarmup,
|
|
267
|
+
scheduleStatuslineUsageWarmup,
|
|
268
|
+
scheduleStatuslineUsageRefresh,
|
|
269
|
+
} = createWarmupSchedulers({
|
|
270
|
+
timers: warmupTimers,
|
|
271
|
+
bootProfile,
|
|
272
|
+
getRoute: () => rt.route,
|
|
273
|
+
getConfig: () => rt.config,
|
|
274
|
+
isCloseRequested: () => rt.closeRequested,
|
|
275
|
+
getActiveTurnCount: () => rt.activeTurnCount,
|
|
276
|
+
getSessionCreatePromise: () => rt.sessionCreatePromise,
|
|
277
|
+
getProviderModelsCache: () => providerModelCaches.providerModelsCache,
|
|
278
|
+
getProviderModelsPromise: () => providerModelCaches.providerModelsPromise,
|
|
279
|
+
reloadFullConfig,
|
|
280
|
+
ensureConfigForRouteProvider,
|
|
281
|
+
awaitKeychainPrewarm,
|
|
282
|
+
ensureProvidersReady,
|
|
283
|
+
ensureProviderEnabled,
|
|
284
|
+
refreshStatuslineUsageSnapshot,
|
|
285
|
+
warmProviderModelCache,
|
|
286
|
+
cachedProviderSetup,
|
|
287
|
+
warmCatalogsInBackground,
|
|
288
|
+
isFirstTurnCompleted: () => rt.firstTurnCompleted,
|
|
289
|
+
isCatalogRefreshPending: () => rt.startupProviderCatalogRefreshPending,
|
|
290
|
+
envFlag,
|
|
291
|
+
delays: {
|
|
292
|
+
providerWarmupDelayMs,
|
|
293
|
+
providerSetupWarmupDelayMs,
|
|
294
|
+
providerModelWarmupDelayMs,
|
|
295
|
+
modelCatalogWarmupDelayMs,
|
|
296
|
+
statuslineUsageWarmupDelayMs,
|
|
297
|
+
statuslineUsageRefreshDelayMs,
|
|
298
|
+
backgroundBusyRetryMs,
|
|
299
|
+
},
|
|
300
|
+
flags: {
|
|
301
|
+
providerWarmupEnabled,
|
|
302
|
+
modelPrefetchEnabled,
|
|
303
|
+
modelCatalogWarmupEnabled,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
rt.scheduleProviderModelWarmupRef = scheduleProviderModelWarmup;
|
|
307
|
+
rt.scheduleProviderSetupWarmupRef = scheduleProviderSetupWarmup;
|
|
308
|
+
|
|
309
|
+
const {
|
|
310
|
+
scheduleCodeGraphPrewarm,
|
|
311
|
+
scheduleLeadSessionPrewarm,
|
|
312
|
+
scheduleToolRuntimeWarmup,
|
|
313
|
+
invokeChannelStart,
|
|
314
|
+
scheduleChannelStart,
|
|
315
|
+
} = createPrewarmSchedulers({
|
|
316
|
+
timers: prewarmTimers,
|
|
317
|
+
bootProfile,
|
|
318
|
+
getCurrentCwd: () => rt.currentCwd,
|
|
319
|
+
isCloseRequested: () => rt.closeRequested,
|
|
320
|
+
getActiveTurnCount: () => rt.activeTurnCount,
|
|
321
|
+
getSessionCreatePromise: () => rt.sessionCreatePromise,
|
|
322
|
+
getSession: () => rt.session,
|
|
323
|
+
isRemoteEnabled: () => rt.remoteEnabled,
|
|
324
|
+
channelsEnabled,
|
|
325
|
+
hasActiveAutomation,
|
|
326
|
+
getCodeGraphModule,
|
|
327
|
+
createCurrentSession,
|
|
328
|
+
channels,
|
|
329
|
+
envFlag,
|
|
330
|
+
delays: {
|
|
331
|
+
codeGraphPrewarmDelayMs,
|
|
332
|
+
channelStartDelayMs,
|
|
333
|
+
sessionPrewarmDelayMs,
|
|
334
|
+
backgroundBusyRetryMs,
|
|
335
|
+
},
|
|
336
|
+
flags: {
|
|
337
|
+
codeGraphPrewarmEnabled,
|
|
338
|
+
sessionPrewarmEnabled,
|
|
339
|
+
},
|
|
340
|
+
state: prewarmState,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Remote transcript binding + worker rebind pushes live in
|
|
344
|
+
// remote-transcript.mjs; the facade injects the mutable session/cwd/remote
|
|
345
|
+
// state it needs.
|
|
346
|
+
const remoteTranscript = createRemoteTranscript({
|
|
347
|
+
getSession: () => rt.session,
|
|
348
|
+
getCwd: () => rt.currentCwd,
|
|
349
|
+
isRemoteEnabled: () => rt.remoteEnabled,
|
|
350
|
+
getRemoteSessionId: () => rt.remoteSessionId,
|
|
351
|
+
setRemoteSessionId: (next) => { rt.remoteSessionId = next; },
|
|
352
|
+
isCloseRequested: () => rt.closeRequested,
|
|
353
|
+
channelsEnabled,
|
|
354
|
+
channels,
|
|
355
|
+
bootProfile,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
resolveMissingRouteModelForFirstTurn,
|
|
360
|
+
scheduleProviderWarmup,
|
|
361
|
+
scheduleProviderSetupWarmup,
|
|
362
|
+
scheduleProviderModelWarmup,
|
|
363
|
+
scheduleModelCatalogWarmup,
|
|
364
|
+
scheduleStatuslineUsageWarmup,
|
|
365
|
+
scheduleStatuslineUsageRefresh,
|
|
366
|
+
scheduleCodeGraphPrewarm,
|
|
367
|
+
scheduleLeadSessionPrewarm,
|
|
368
|
+
scheduleToolRuntimeWarmup,
|
|
369
|
+
invokeChannelStart,
|
|
370
|
+
scheduleChannelStart,
|
|
371
|
+
refreshRouteEffort,
|
|
372
|
+
routeHasModel,
|
|
373
|
+
requireModelRoute,
|
|
374
|
+
recreateCurrentSessionIfReady,
|
|
375
|
+
createCurrentSession,
|
|
376
|
+
remoteTranscript,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
@@ -30,11 +30,12 @@ const IDLE_REAP_SWEEP_MS = 60_000;
|
|
|
30
30
|
export function agentShardEnabled() {
|
|
31
31
|
const value = process.env.MIXDOG_AGENT_SHARD;
|
|
32
32
|
if (value === '1') return true;
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
33
|
+
// P2 gate: sharding stays opt-in (MIXDOG_AGENT_SHARD=1). The P3
|
|
34
|
+
// default-ON flip (lead-like hosts shard unless MIXDOG_WORKER_MODE=1)
|
|
35
|
+
// is deferred until the remaining P2 items land — a default-ON pool
|
|
36
|
+
// routes every spawn through shard children, which breaks hosts that
|
|
37
|
+
// inject a custom session manager (fake/test mgr, embedded runtimes).
|
|
38
|
+
return false;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
function agentShardPoolSize() {
|