@slock-ai/daemon 0.57.0-play.20260606141931 → 0.57.1
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/dist/{chunk-Q55N6BNS.js → chunk-6RZCYFJP.js} +923 -448
- package/dist/core.js +1 -5
- package/dist/index.js +3 -5
- package/package.json +1 -1
- package/dist/drivers/piSdkRunner.js +0 -96
|
@@ -1980,19 +1980,6 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
1980
1980
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
1981
1981
|
}
|
|
1982
1982
|
|
|
1983
|
-
// src/authEnv.ts
|
|
1984
|
-
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
1985
|
-
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
1986
|
-
function scrubDaemonAuthEnv(env) {
|
|
1987
|
-
delete env[DAEMON_API_KEY_ENV];
|
|
1988
|
-
return env;
|
|
1989
|
-
}
|
|
1990
|
-
function scrubDaemonChildEnv(env) {
|
|
1991
|
-
delete env[DAEMON_API_KEY_ENV];
|
|
1992
|
-
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
1993
|
-
return env;
|
|
1994
|
-
}
|
|
1995
|
-
|
|
1996
1983
|
// src/agentCredentialProxy.ts
|
|
1997
1984
|
import { randomBytes } from "crypto";
|
|
1998
1985
|
import http from "http";
|
|
@@ -2248,6 +2235,412 @@ function reduceApmGatedFlushReadiness(state, input) {
|
|
|
2248
2235
|
};
|
|
2249
2236
|
}
|
|
2250
2237
|
|
|
2238
|
+
// src/agentInboxStateMachine.ts
|
|
2239
|
+
var DEFAULT_HELD_CONTEXT_LIMIT = 3;
|
|
2240
|
+
function planAgentInboxSideEffect(input) {
|
|
2241
|
+
const heldContextLimit = input.heldContextLimit ?? DEFAULT_HELD_CONTEXT_LIMIT;
|
|
2242
|
+
const trace = [
|
|
2243
|
+
{
|
|
2244
|
+
step: "input",
|
|
2245
|
+
data: compactTraceData({
|
|
2246
|
+
action: input.action,
|
|
2247
|
+
target: input.target,
|
|
2248
|
+
continueAnyway: input.continueAnyway,
|
|
2249
|
+
pendingCount: input.pendingMessages.length,
|
|
2250
|
+
recentCount: input.recentMessages.length,
|
|
2251
|
+
existingSeenUpToSeq: input.existingSeenUpToSeq,
|
|
2252
|
+
modelSeenSeq: input.modelSeenSeq
|
|
2253
|
+
})
|
|
2254
|
+
}
|
|
2255
|
+
];
|
|
2256
|
+
if (input.continueAnyway) {
|
|
2257
|
+
appendTrace(trace, "continue_anyway_bypass");
|
|
2258
|
+
return forwardPlan(input, {
|
|
2259
|
+
action: input.action,
|
|
2260
|
+
decision: "bypass",
|
|
2261
|
+
target: input.target,
|
|
2262
|
+
inboxTrustState: "trusted",
|
|
2263
|
+
reason: "continue_anyway"
|
|
2264
|
+
}, trace);
|
|
2265
|
+
}
|
|
2266
|
+
if (input.pendingMessages.length > 0) {
|
|
2267
|
+
appendTrace(trace, "pending_messages_found", { pendingCount: input.pendingMessages.length });
|
|
2268
|
+
const pending = sortInboxMessagesBySeq(normalizeInboxVisibleMessages(input.pendingMessages, input.target));
|
|
2269
|
+
const boundary2 = resolveFreshnessBoundary(pending);
|
|
2270
|
+
if (!boundary2.ok) {
|
|
2271
|
+
appendTrace(trace, "pending_context_missing_boundary");
|
|
2272
|
+
return forwardWithoutDecision(input, trace);
|
|
2273
|
+
}
|
|
2274
|
+
const alreadySeenPending = [];
|
|
2275
|
+
const unconsumedMessages = [];
|
|
2276
|
+
for (const message of pending) {
|
|
2277
|
+
if (isMessageModelSeen(input, message)) {
|
|
2278
|
+
alreadySeenPending.push(message);
|
|
2279
|
+
} else {
|
|
2280
|
+
unconsumedMessages.push(message);
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
appendTrace(trace, "pending_context_classified", {
|
|
2284
|
+
pendingCount: pending.length,
|
|
2285
|
+
unseenCount: unconsumedMessages.length
|
|
2286
|
+
});
|
|
2287
|
+
if (unconsumedMessages.length === 0) {
|
|
2288
|
+
const contiguousBoundary = maxKnownContiguousBoundary(input);
|
|
2289
|
+
const canAdvanceBoundary = typeof contiguousBoundary === "number" && contiguousBoundary >= boundary2.seenUpToSeq;
|
|
2290
|
+
appendTrace(trace, "pending_context_already_seen", { boundarySeq: boundary2.seenUpToSeq });
|
|
2291
|
+
return forwardPlan(input, {
|
|
2292
|
+
action: input.action,
|
|
2293
|
+
decision: "forward",
|
|
2294
|
+
target: input.target,
|
|
2295
|
+
inboxTrustState: "trusted",
|
|
2296
|
+
reason: "exact_target_pending_already_seen",
|
|
2297
|
+
pendingCount: pending.length,
|
|
2298
|
+
pendingMaxSeq: boundary2.seenUpToSeq,
|
|
2299
|
+
modelSeenSeq: contiguousBoundary,
|
|
2300
|
+
heldMessageCount: 0,
|
|
2301
|
+
omittedMessageCount: 0
|
|
2302
|
+
}, trace, {
|
|
2303
|
+
forwardSeenUpToSeq: input.action === "send" && canAdvanceBoundary ? boundary2.seenUpToSeq : void 0,
|
|
2304
|
+
consumeEffect: {
|
|
2305
|
+
type: "consume_visible_messages",
|
|
2306
|
+
target: input.target,
|
|
2307
|
+
messages: exactSeenConsumeMessages(input, pending),
|
|
2308
|
+
boundarySeq: canAdvanceBoundary ? boundary2.seenUpToSeq : void 0,
|
|
2309
|
+
source: "side_effect_preflight_context"
|
|
2310
|
+
}
|
|
2311
|
+
});
|
|
2312
|
+
}
|
|
2313
|
+
const heldBoundary = resolveFreshnessBoundary(unconsumedMessages);
|
|
2314
|
+
if (heldBoundary.ok) {
|
|
2315
|
+
const heldMessages = latestVisibleMessages(unconsumedMessages, heldContextLimit);
|
|
2316
|
+
const omittedMessageCount = Math.max(0, unconsumedMessages.length - heldMessages.length);
|
|
2317
|
+
const context = {
|
|
2318
|
+
heldMessages,
|
|
2319
|
+
newMessageCount: unconsumedMessages.length,
|
|
2320
|
+
shownMessageCount: heldMessages.length,
|
|
2321
|
+
omittedMessageCount,
|
|
2322
|
+
seenUpToSeq: heldBoundary.seenUpToSeq
|
|
2323
|
+
};
|
|
2324
|
+
appendTrace(trace, "held_context_built", {
|
|
2325
|
+
boundarySeq: boundary2.seenUpToSeq,
|
|
2326
|
+
heldBoundarySeq: heldBoundary.seenUpToSeq,
|
|
2327
|
+
heldCount: context.shownMessageCount,
|
|
2328
|
+
omittedCount: context.omittedMessageCount
|
|
2329
|
+
});
|
|
2330
|
+
return heldPlan(input, {
|
|
2331
|
+
decision: {
|
|
2332
|
+
action: input.action,
|
|
2333
|
+
decision: "local_hold",
|
|
2334
|
+
target: input.target,
|
|
2335
|
+
inboxTrustState: "trusted",
|
|
2336
|
+
reason: "exact_target_pending",
|
|
2337
|
+
pendingCount: input.pendingMessages.length,
|
|
2338
|
+
pendingMaxSeq: heldBoundary.seenUpToSeq,
|
|
2339
|
+
modelSeenSeq: input.modelSeenSeq,
|
|
2340
|
+
heldMessageCount: context.shownMessageCount,
|
|
2341
|
+
omittedMessageCount: context.omittedMessageCount
|
|
2342
|
+
},
|
|
2343
|
+
context,
|
|
2344
|
+
consumeMessages: sortInboxMessagesBySeq([
|
|
2345
|
+
...exactSeenConsumeMessages(input, alreadySeenPending),
|
|
2346
|
+
...context.heldMessages
|
|
2347
|
+
]),
|
|
2348
|
+
consumeBoundarySeq: heldBoundary.seenUpToSeq
|
|
2349
|
+
}, trace);
|
|
2350
|
+
}
|
|
2351
|
+
appendTrace(trace, "pending_unseen_context_missing_boundary");
|
|
2352
|
+
return forwardWithoutDecision(input, trace);
|
|
2353
|
+
}
|
|
2354
|
+
const boundary = Math.max(input.existingSeenUpToSeq ?? 0, input.modelSeenSeq ?? 0);
|
|
2355
|
+
appendTrace(trace, "model_boundary_checked", { boundary });
|
|
2356
|
+
if (boundary > 0) {
|
|
2357
|
+
appendTrace(trace, "model_boundary_selected", { boundary });
|
|
2358
|
+
return forwardPlan(input, {
|
|
2359
|
+
action: input.action,
|
|
2360
|
+
decision: "forward",
|
|
2361
|
+
target: input.target,
|
|
2362
|
+
inboxTrustState: "trusted",
|
|
2363
|
+
reason: "model_seen_boundary",
|
|
2364
|
+
pendingCount: 0,
|
|
2365
|
+
modelSeenSeq: boundary
|
|
2366
|
+
}, trace, { forwardSeenUpToSeq: input.action === "send" ? boundary : void 0 });
|
|
2367
|
+
}
|
|
2368
|
+
if (input.recentMessages.length > 0) {
|
|
2369
|
+
return planFirstTouchRecentContext(input, heldContextLimit, trace);
|
|
2370
|
+
}
|
|
2371
|
+
appendTrace(trace, "no_context_available");
|
|
2372
|
+
return forwardPlan(input, {
|
|
2373
|
+
action: input.action,
|
|
2374
|
+
decision: "forward",
|
|
2375
|
+
target: input.target,
|
|
2376
|
+
inboxTrustState: "trusted",
|
|
2377
|
+
reason: "no_exact_target_pending_or_recent_context",
|
|
2378
|
+
pendingCount: 0,
|
|
2379
|
+
modelSeenSeq: 0
|
|
2380
|
+
}, trace);
|
|
2381
|
+
}
|
|
2382
|
+
function normalizeInboxVisibleMessage(message, target) {
|
|
2383
|
+
const targetFields = target ? parseTargetFields(target) : {};
|
|
2384
|
+
const normalized = {
|
|
2385
|
+
...targetFields,
|
|
2386
|
+
...message,
|
|
2387
|
+
message_id: message.message_id ?? message.id,
|
|
2388
|
+
timestamp: message.timestamp ?? message.createdAt,
|
|
2389
|
+
sender_type: message.sender_type ?? message.senderType,
|
|
2390
|
+
sender_name: message.sender_name ?? message.senderName,
|
|
2391
|
+
sender_description: message.sender_description ?? message.senderDescription ?? null
|
|
2392
|
+
};
|
|
2393
|
+
const senderId = messageSenderId(message);
|
|
2394
|
+
if (senderId) normalized.sender_id = senderId;
|
|
2395
|
+
return normalized;
|
|
2396
|
+
}
|
|
2397
|
+
function normalizeInboxVisibleMessages(messages, target) {
|
|
2398
|
+
return messages.map((message) => normalizeInboxVisibleMessage(message, target));
|
|
2399
|
+
}
|
|
2400
|
+
function maxInboxMessageSeq(messages) {
|
|
2401
|
+
let maxSeq = 0;
|
|
2402
|
+
for (const message of messages) {
|
|
2403
|
+
const seq = Math.floor(messageSeq(message));
|
|
2404
|
+
if (Number.isFinite(seq) && seq > 0) maxSeq = Math.max(maxSeq, seq);
|
|
2405
|
+
}
|
|
2406
|
+
return maxSeq > 0 ? maxSeq : void 0;
|
|
2407
|
+
}
|
|
2408
|
+
function maxKnownContiguousBoundary(input) {
|
|
2409
|
+
const boundary = Math.max(input.existingSeenUpToSeq ?? 0, input.modelSeenSeq ?? 0);
|
|
2410
|
+
return boundary > 0 ? boundary : void 0;
|
|
2411
|
+
}
|
|
2412
|
+
function exactSeenConsumeMessages(input, messages) {
|
|
2413
|
+
const boundary = maxKnownContiguousBoundary(input);
|
|
2414
|
+
return messages.map((message) => {
|
|
2415
|
+
const seq = Math.floor(messageSeq(message));
|
|
2416
|
+
if (Number.isFinite(seq) && seq > 0 && typeof boundary === "number" && boundary >= seq) {
|
|
2417
|
+
return message;
|
|
2418
|
+
}
|
|
2419
|
+
const id = typeof message.message_id === "string" && message.message_id.length > 0 ? message.message_id : typeof message.id === "string" && message.id.length > 0 ? message.id : void 0;
|
|
2420
|
+
return id ? { ...message, seq: void 0 } : message;
|
|
2421
|
+
});
|
|
2422
|
+
}
|
|
2423
|
+
function sortInboxMessagesBySeq(messages) {
|
|
2424
|
+
return [...messages].sort((a, b) => messageSeq(a) - messageSeq(b));
|
|
2425
|
+
}
|
|
2426
|
+
function planFirstTouchRecentContext(input, heldContextLimit, trace) {
|
|
2427
|
+
const recent = sortInboxMessagesBySeq(normalizeInboxVisibleMessages(input.recentMessages, input.target));
|
|
2428
|
+
const unconsumedMessages = recent.filter((message) => !isMessageModelSeen(input, message));
|
|
2429
|
+
appendTrace(trace, "recent_context_loaded", {
|
|
2430
|
+
recentCount: recent.length,
|
|
2431
|
+
unseenCount: unconsumedMessages.length
|
|
2432
|
+
});
|
|
2433
|
+
const boundary = resolveFreshnessBoundary(recent);
|
|
2434
|
+
if (!boundary.ok) {
|
|
2435
|
+
appendTrace(trace, "recent_context_missing_boundary");
|
|
2436
|
+
return forwardPlan(input, {
|
|
2437
|
+
action: input.action,
|
|
2438
|
+
decision: "forward",
|
|
2439
|
+
target: input.target,
|
|
2440
|
+
inboxTrustState: "untrusted",
|
|
2441
|
+
reason: "target_first_touch_recent_context_without_seq_boundary",
|
|
2442
|
+
pendingCount: 0,
|
|
2443
|
+
modelSeenSeq: 0
|
|
2444
|
+
}, trace);
|
|
2445
|
+
}
|
|
2446
|
+
appendTrace(trace, "recent_boundary_resolved", { boundarySeq: boundary.seenUpToSeq });
|
|
2447
|
+
if (unconsumedMessages.length === 0) {
|
|
2448
|
+
appendTrace(trace, "recent_context_already_seen");
|
|
2449
|
+
return forwardPlan(input, {
|
|
2450
|
+
action: input.action,
|
|
2451
|
+
decision: "forward",
|
|
2452
|
+
target: input.target,
|
|
2453
|
+
inboxTrustState: "untrusted",
|
|
2454
|
+
reason: "target_first_touch_recent_context_already_seen",
|
|
2455
|
+
pendingCount: 0,
|
|
2456
|
+
pendingMaxSeq: boundary.seenUpToSeq,
|
|
2457
|
+
modelSeenSeq: boundary.seenUpToSeq,
|
|
2458
|
+
heldMessageCount: 0,
|
|
2459
|
+
omittedMessageCount: 0
|
|
2460
|
+
}, trace, {
|
|
2461
|
+
forwardSeenUpToSeq: input.action === "send" ? boundary.seenUpToSeq : void 0,
|
|
2462
|
+
consumeEffect: {
|
|
2463
|
+
type: "consume_visible_messages",
|
|
2464
|
+
target: input.target,
|
|
2465
|
+
messages: recent,
|
|
2466
|
+
boundarySeq: boundary.seenUpToSeq,
|
|
2467
|
+
source: "side_effect_preflight_context"
|
|
2468
|
+
}
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
const heldBoundary = resolveFreshnessBoundary(unconsumedMessages);
|
|
2472
|
+
if (!heldBoundary.ok) {
|
|
2473
|
+
appendTrace(trace, "unseen_context_missing_boundary");
|
|
2474
|
+
return forwardPlan(input, {
|
|
2475
|
+
action: input.action,
|
|
2476
|
+
decision: "forward",
|
|
2477
|
+
target: input.target,
|
|
2478
|
+
inboxTrustState: "untrusted",
|
|
2479
|
+
reason: "target_first_touch_unseen_context_without_seq_boundary",
|
|
2480
|
+
pendingCount: 0,
|
|
2481
|
+
modelSeenSeq: 0
|
|
2482
|
+
}, trace);
|
|
2483
|
+
}
|
|
2484
|
+
appendTrace(trace, "unseen_boundary_resolved", { boundarySeq: heldBoundary.seenUpToSeq });
|
|
2485
|
+
const heldMessages = latestVisibleMessages(unconsumedMessages, heldContextLimit);
|
|
2486
|
+
const omittedMessageCount = Math.max(0, unconsumedMessages.length - heldMessages.length);
|
|
2487
|
+
appendTrace(trace, "unseen_hold_selected", {
|
|
2488
|
+
heldCount: heldMessages.length,
|
|
2489
|
+
omittedCount: omittedMessageCount,
|
|
2490
|
+
consumeBoundarySeq: boundary.seenUpToSeq
|
|
2491
|
+
});
|
|
2492
|
+
return heldPlan(input, {
|
|
2493
|
+
decision: {
|
|
2494
|
+
action: input.action,
|
|
2495
|
+
decision: "syncing_hold",
|
|
2496
|
+
target: input.target,
|
|
2497
|
+
inboxTrustState: "untrusted",
|
|
2498
|
+
reason: "target_first_touch_recent_context",
|
|
2499
|
+
pendingCount: 0,
|
|
2500
|
+
pendingMaxSeq: heldBoundary.seenUpToSeq,
|
|
2501
|
+
modelSeenSeq: 0,
|
|
2502
|
+
heldMessageCount: heldMessages.length,
|
|
2503
|
+
omittedMessageCount
|
|
2504
|
+
},
|
|
2505
|
+
context: {
|
|
2506
|
+
heldMessages,
|
|
2507
|
+
newMessageCount: unconsumedMessages.length,
|
|
2508
|
+
shownMessageCount: heldMessages.length,
|
|
2509
|
+
omittedMessageCount,
|
|
2510
|
+
seenUpToSeq: boundary.seenUpToSeq
|
|
2511
|
+
},
|
|
2512
|
+
consumeMessages: recent,
|
|
2513
|
+
consumeBoundarySeq: boundary.seenUpToSeq
|
|
2514
|
+
}, trace);
|
|
2515
|
+
}
|
|
2516
|
+
function heldPlan(input, held, trace) {
|
|
2517
|
+
const producerFactId = buildApmFreshnessDecisionProducerFactId(input.agentId, held.decision);
|
|
2518
|
+
const decision = { ...held.decision, producerFactId };
|
|
2519
|
+
appendTrace(trace, "plan_built", {
|
|
2520
|
+
outcome: "held",
|
|
2521
|
+
decision: decision.decision,
|
|
2522
|
+
effectCount: 2,
|
|
2523
|
+
localResponseState: "held",
|
|
2524
|
+
seenUpToSeq: held.context.seenUpToSeq
|
|
2525
|
+
});
|
|
2526
|
+
return {
|
|
2527
|
+
outcome: "held",
|
|
2528
|
+
target: input.target,
|
|
2529
|
+
effects: [
|
|
2530
|
+
{
|
|
2531
|
+
type: "consume_visible_messages",
|
|
2532
|
+
target: input.target,
|
|
2533
|
+
messages: held.consumeMessages,
|
|
2534
|
+
boundarySeq: held.consumeBoundarySeq,
|
|
2535
|
+
source: "side_effect_preflight_context"
|
|
2536
|
+
},
|
|
2537
|
+
{ type: "record_freshness_decision", decision }
|
|
2538
|
+
],
|
|
2539
|
+
trace,
|
|
2540
|
+
localResponse: projectApmHeldFreshnessEnvelope({
|
|
2541
|
+
producerFactId,
|
|
2542
|
+
action: input.action,
|
|
2543
|
+
heldMessages: held.context.heldMessages,
|
|
2544
|
+
newMessageCount: held.context.newMessageCount,
|
|
2545
|
+
omittedMessageCount: held.context.omittedMessageCount,
|
|
2546
|
+
seenUpToSeq: held.context.seenUpToSeq
|
|
2547
|
+
}).body
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
function forwardPlan(input, decision, trace, options = {}) {
|
|
2551
|
+
appendTrace(trace, "plan_built", {
|
|
2552
|
+
outcome: "forward",
|
|
2553
|
+
decision: decision.decision,
|
|
2554
|
+
effectCount: options.consumeEffect ? 2 : 1,
|
|
2555
|
+
forwardSeenUpToSeq: options.forwardSeenUpToSeq
|
|
2556
|
+
});
|
|
2557
|
+
return {
|
|
2558
|
+
outcome: "forward",
|
|
2559
|
+
target: input.target,
|
|
2560
|
+
forwardSeenUpToSeq: options.forwardSeenUpToSeq,
|
|
2561
|
+
effects: [
|
|
2562
|
+
...options.consumeEffect ? [options.consumeEffect] : [],
|
|
2563
|
+
{ type: "record_freshness_decision", decision }
|
|
2564
|
+
],
|
|
2565
|
+
trace
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2568
|
+
function forwardWithoutDecision(input, trace) {
|
|
2569
|
+
appendTrace(trace, "plan_built", {
|
|
2570
|
+
outcome: "forward",
|
|
2571
|
+
decision: "none",
|
|
2572
|
+
effectCount: 0
|
|
2573
|
+
});
|
|
2574
|
+
return {
|
|
2575
|
+
outcome: "forward",
|
|
2576
|
+
target: input.target,
|
|
2577
|
+
effects: [],
|
|
2578
|
+
trace
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
function resolveFreshnessBoundary(messages) {
|
|
2582
|
+
const seenUpToSeq = maxInboxMessageSeq(messages);
|
|
2583
|
+
return typeof seenUpToSeq === "number" ? { ok: true, seenUpToSeq } : { ok: false, reason: "missing_seq_boundary" };
|
|
2584
|
+
}
|
|
2585
|
+
function latestVisibleMessages(messages, limit) {
|
|
2586
|
+
const sorted = sortInboxMessagesBySeq(messages);
|
|
2587
|
+
return sorted.slice(Math.max(0, sorted.length - limit));
|
|
2588
|
+
}
|
|
2589
|
+
function isMessageModelSeen(input, message) {
|
|
2590
|
+
const seq = Math.floor(messageSeq(message));
|
|
2591
|
+
if (Number.isFinite(seq) && seq > 0 && typeof input.modelSeenSeq === "number" && input.modelSeenSeq >= seq) return true;
|
|
2592
|
+
return input.isMessageModelSeen?.({ target: input.target, message }) === true;
|
|
2593
|
+
}
|
|
2594
|
+
function messageSeq(message) {
|
|
2595
|
+
return Number(message.seq ?? 0);
|
|
2596
|
+
}
|
|
2597
|
+
function messageSenderId(message) {
|
|
2598
|
+
if (typeof message.sender_id === "string" && message.sender_id.length > 0) return message.sender_id;
|
|
2599
|
+
if (typeof message.senderId === "string" && message.senderId.length > 0) return message.senderId;
|
|
2600
|
+
return void 0;
|
|
2601
|
+
}
|
|
2602
|
+
function appendTrace(trace, step, data) {
|
|
2603
|
+
const compacted = compactTraceData(data);
|
|
2604
|
+
trace.push(Object.keys(compacted).length > 0 ? { step, data: compacted } : { step });
|
|
2605
|
+
}
|
|
2606
|
+
function compactTraceData(data) {
|
|
2607
|
+
const compacted = {};
|
|
2608
|
+
if (!data) return compacted;
|
|
2609
|
+
for (const [key, value] of Object.entries(data)) {
|
|
2610
|
+
if (value !== void 0) compacted[key] = value;
|
|
2611
|
+
}
|
|
2612
|
+
return compacted;
|
|
2613
|
+
}
|
|
2614
|
+
function parseTargetFields(target) {
|
|
2615
|
+
if (target.startsWith("dm:@")) {
|
|
2616
|
+
const rest = target.slice("dm:@".length);
|
|
2617
|
+
const [peer, threadId] = rest.split(":", 2);
|
|
2618
|
+
if (threadId) {
|
|
2619
|
+
return {
|
|
2620
|
+
channel_type: "thread",
|
|
2621
|
+
channel_name: threadId,
|
|
2622
|
+
parent_channel_type: "dm",
|
|
2623
|
+
parent_channel_name: peer
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
return { channel_type: "dm", channel_name: peer };
|
|
2627
|
+
}
|
|
2628
|
+
if (target.startsWith("#")) {
|
|
2629
|
+
const rest = target.slice(1);
|
|
2630
|
+
const [channel, threadId] = rest.split(":", 2);
|
|
2631
|
+
if (threadId) {
|
|
2632
|
+
return {
|
|
2633
|
+
channel_type: "thread",
|
|
2634
|
+
channel_name: threadId,
|
|
2635
|
+
parent_channel_type: "channel",
|
|
2636
|
+
parent_channel_name: channel
|
|
2637
|
+
};
|
|
2638
|
+
}
|
|
2639
|
+
return { channel_type: "channel", channel_name: channel };
|
|
2640
|
+
}
|
|
2641
|
+
return {};
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2251
2644
|
// src/agentInboxProjection.ts
|
|
2252
2645
|
function projectAgentInboxSnapshot(messages) {
|
|
2253
2646
|
const buckets = /* @__PURE__ */ new Map();
|
|
@@ -2277,16 +2670,16 @@ function projectBucket(target, messages) {
|
|
|
2277
2670
|
channelType: latest.channel_type,
|
|
2278
2671
|
pendingCount: messages.length,
|
|
2279
2672
|
firstPendingMsgId: messageId(first),
|
|
2280
|
-
firstPendingSeq:
|
|
2673
|
+
firstPendingSeq: messageSeq2(first),
|
|
2281
2674
|
latestMsgId: messageId(latest),
|
|
2282
|
-
latestSeq:
|
|
2675
|
+
latestSeq: messageSeq2(latest),
|
|
2283
2676
|
latestSenderName: latest.sender_name ?? latest.senderName,
|
|
2284
2677
|
latestSenderType: normalizeSenderType(latest.sender_type ?? latest.senderType),
|
|
2285
2678
|
flags: [...flags].sort()
|
|
2286
2679
|
});
|
|
2287
2680
|
}
|
|
2288
2681
|
function compareInboxMessages(a, b) {
|
|
2289
|
-
return (
|
|
2682
|
+
return (messageSeq2(a) ?? 0) - (messageSeq2(b) ?? 0) || (messageId(a) ?? "").localeCompare(messageId(b) ?? "");
|
|
2290
2683
|
}
|
|
2291
2684
|
function formatInboxMessageTarget(message) {
|
|
2292
2685
|
if (message.channel_type === "thread" && message.parent_channel_name && message.channel_name) {
|
|
@@ -2302,7 +2695,7 @@ function messageId(message) {
|
|
|
2302
2695
|
if (!message) return void 0;
|
|
2303
2696
|
return nonEmptyString(message.message_id) ?? nonEmptyString(message.id);
|
|
2304
2697
|
}
|
|
2305
|
-
function
|
|
2698
|
+
function messageSeq2(message) {
|
|
2306
2699
|
if (!message || typeof message.seq !== "number" || !Number.isFinite(message.seq) || message.seq <= 0) return void 0;
|
|
2307
2700
|
return Math.floor(message.seq);
|
|
2308
2701
|
}
|
|
@@ -2827,42 +3220,9 @@ async function readRequestBody(req) {
|
|
|
2827
3220
|
}
|
|
2828
3221
|
return Buffer.concat(chunks);
|
|
2829
3222
|
}
|
|
2830
|
-
function
|
|
3223
|
+
function messageSeq3(message) {
|
|
2831
3224
|
return Number(message.seq ?? 0);
|
|
2832
3225
|
}
|
|
2833
|
-
function maxMessageSeq(messages) {
|
|
2834
|
-
let maxSeq = 0;
|
|
2835
|
-
for (const message of messages) {
|
|
2836
|
-
const seq = Math.floor(messageSeq2(message));
|
|
2837
|
-
if (Number.isFinite(seq) && seq > 0) maxSeq = Math.max(maxSeq, seq);
|
|
2838
|
-
}
|
|
2839
|
-
return maxSeq > 0 ? maxSeq : void 0;
|
|
2840
|
-
}
|
|
2841
|
-
function messageSenderId(message) {
|
|
2842
|
-
if (typeof message.sender_id === "string" && message.sender_id.length > 0) return message.sender_id;
|
|
2843
|
-
if (typeof message.senderId === "string" && message.senderId.length > 0) return message.senderId;
|
|
2844
|
-
return void 0;
|
|
2845
|
-
}
|
|
2846
|
-
function isSelfAuthoredMessage(registration, message) {
|
|
2847
|
-
return messageSenderId(message) === registration.agentId;
|
|
2848
|
-
}
|
|
2849
|
-
function isMessageModelSeen(coordinator, target, message) {
|
|
2850
|
-
const seq = Math.floor(messageSeq2(message));
|
|
2851
|
-
const boundary = coordinator.getBoundary(target);
|
|
2852
|
-
if (Number.isFinite(seq) && seq > 0 && typeof boundary === "number" && boundary >= seq) return true;
|
|
2853
|
-
return coordinator.isMessageModelSeen?.({ target, message }) === true;
|
|
2854
|
-
}
|
|
2855
|
-
function resolveFreshnessBoundary(messages) {
|
|
2856
|
-
const seenUpToSeq = maxMessageSeq(messages);
|
|
2857
|
-
return typeof seenUpToSeq === "number" ? { ok: true, seenUpToSeq } : { ok: false, reason: "missing_seq_boundary" };
|
|
2858
|
-
}
|
|
2859
|
-
function sortBySeq(messages) {
|
|
2860
|
-
return [...messages].sort((a, b) => messageSeq2(a) - messageSeq2(b));
|
|
2861
|
-
}
|
|
2862
|
-
function latestVisibleMessages(messages, limit) {
|
|
2863
|
-
const sorted = sortBySeq(messages);
|
|
2864
|
-
return sorted.slice(Math.max(0, sorted.length - limit));
|
|
2865
|
-
}
|
|
2866
3226
|
function localAgentApiInboxResponse(registration) {
|
|
2867
3227
|
const coordinator = registration.inboxCoordinator;
|
|
2868
3228
|
if (!coordinator) return void 0;
|
|
@@ -2910,9 +3270,9 @@ function localAgentApiEventsResponse(registration, target) {
|
|
|
2910
3270
|
return { status: 400, body: parsedQuery.error };
|
|
2911
3271
|
}
|
|
2912
3272
|
if (pending.length === 0) return void 0;
|
|
2913
|
-
const normalized =
|
|
3273
|
+
const normalized = sortInboxMessagesBySeq(normalizeInboxVisibleMessages(pending));
|
|
2914
3274
|
const filtered = parsedQuery.sinceSeq !== null ? normalized.filter((message) => {
|
|
2915
|
-
const seq =
|
|
3275
|
+
const seq = messageSeq3(message);
|
|
2916
3276
|
return Number.isFinite(seq) && seq > parsedQuery.sinceSeq;
|
|
2917
3277
|
}) : normalized;
|
|
2918
3278
|
const events = filtered.slice(0, parsedQuery.limit);
|
|
@@ -2921,7 +3281,7 @@ function localAgentApiEventsResponse(registration, target) {
|
|
|
2921
3281
|
const lastSeenMsgId = newestEvent?.message_id ?? newestEvent?.id ?? null;
|
|
2922
3282
|
const lastSeenSeq = newestEvent?.seq ?? parsedQuery.sinceSeq;
|
|
2923
3283
|
if (events.length > 0) {
|
|
2924
|
-
coordinator.consumeVisibleMessages({ messages: events, source: "
|
|
3284
|
+
coordinator.consumeVisibleMessages({ messages: events, source: "agent_api_events_local" });
|
|
2925
3285
|
}
|
|
2926
3286
|
coordinator.recordDrainOutcome?.({
|
|
2927
3287
|
source: "daemon_pending",
|
|
@@ -2943,30 +3303,6 @@ function localAgentApiEventsResponse(registration, target) {
|
|
|
2943
3303
|
}
|
|
2944
3304
|
};
|
|
2945
3305
|
}
|
|
2946
|
-
function localHeldContext(input) {
|
|
2947
|
-
if (input.messages.length === 0) return { ok: false, reason: "empty_context" };
|
|
2948
|
-
const normalized = sortBySeq(normalizeVisibleMessages(input.messages, input.target));
|
|
2949
|
-
const heldMessages = latestVisibleMessages(normalized, LOCAL_HELD_CONTEXT_LIMIT);
|
|
2950
|
-
const omittedMessageCount = Math.max(0, normalized.length - heldMessages.length);
|
|
2951
|
-
const boundary = resolveFreshnessBoundary(normalized);
|
|
2952
|
-
if (!boundary.ok) return boundary;
|
|
2953
|
-
input.coordinator.consumeVisibleMessages({
|
|
2954
|
-
target: input.target,
|
|
2955
|
-
messages: heldMessages,
|
|
2956
|
-
boundarySeq: boundary.seenUpToSeq,
|
|
2957
|
-
source: input.source
|
|
2958
|
-
});
|
|
2959
|
-
return {
|
|
2960
|
-
ok: true,
|
|
2961
|
-
context: {
|
|
2962
|
-
heldMessages,
|
|
2963
|
-
newMessageCount: normalized.length,
|
|
2964
|
-
shownMessageCount: heldMessages.length,
|
|
2965
|
-
omittedMessageCount,
|
|
2966
|
-
seenUpToSeq: boundary.seenUpToSeq
|
|
2967
|
-
}
|
|
2968
|
-
};
|
|
2969
|
-
}
|
|
2970
3306
|
function recordFreshnessDecision(coordinator, decision) {
|
|
2971
3307
|
coordinator?.recordFreshnessDecision?.(decision);
|
|
2972
3308
|
}
|
|
@@ -2980,53 +3316,6 @@ function sideEffectTarget(action, body) {
|
|
|
2980
3316
|
const field = action === "send" ? body.target : body.channel;
|
|
2981
3317
|
return typeof field === "string" && field.length > 0 ? field : void 0;
|
|
2982
3318
|
}
|
|
2983
|
-
function parseTargetFields(target) {
|
|
2984
|
-
if (target.startsWith("dm:@")) {
|
|
2985
|
-
const rest = target.slice("dm:@".length);
|
|
2986
|
-
const [peer, threadId] = rest.split(":", 2);
|
|
2987
|
-
if (threadId) {
|
|
2988
|
-
return {
|
|
2989
|
-
channel_type: "thread",
|
|
2990
|
-
channel_name: threadId,
|
|
2991
|
-
parent_channel_type: "dm",
|
|
2992
|
-
parent_channel_name: peer
|
|
2993
|
-
};
|
|
2994
|
-
}
|
|
2995
|
-
return { channel_type: "dm", channel_name: peer };
|
|
2996
|
-
}
|
|
2997
|
-
if (target.startsWith("#")) {
|
|
2998
|
-
const rest = target.slice(1);
|
|
2999
|
-
const [channel, threadId] = rest.split(":", 2);
|
|
3000
|
-
if (threadId) {
|
|
3001
|
-
return {
|
|
3002
|
-
channel_type: "thread",
|
|
3003
|
-
channel_name: threadId,
|
|
3004
|
-
parent_channel_type: "channel",
|
|
3005
|
-
parent_channel_name: channel
|
|
3006
|
-
};
|
|
3007
|
-
}
|
|
3008
|
-
return { channel_type: "channel", channel_name: channel };
|
|
3009
|
-
}
|
|
3010
|
-
return {};
|
|
3011
|
-
}
|
|
3012
|
-
function normalizeVisibleMessage(message, target) {
|
|
3013
|
-
const targetFields = target ? parseTargetFields(target) : {};
|
|
3014
|
-
const normalized = {
|
|
3015
|
-
...targetFields,
|
|
3016
|
-
...message,
|
|
3017
|
-
message_id: message.message_id ?? message.id,
|
|
3018
|
-
timestamp: message.timestamp ?? message.createdAt,
|
|
3019
|
-
sender_type: message.sender_type ?? message.senderType,
|
|
3020
|
-
sender_name: message.sender_name ?? message.senderName,
|
|
3021
|
-
sender_description: message.sender_description ?? message.senderDescription ?? null
|
|
3022
|
-
};
|
|
3023
|
-
const senderId = messageSenderId(message);
|
|
3024
|
-
if (senderId) normalized.sender_id = senderId;
|
|
3025
|
-
return normalized;
|
|
3026
|
-
}
|
|
3027
|
-
function normalizeVisibleMessages(messages, target) {
|
|
3028
|
-
return messages.map((message) => normalizeVisibleMessage(message, target));
|
|
3029
|
-
}
|
|
3030
3319
|
async function loadRecentTargetMessages(registration, headers, target) {
|
|
3031
3320
|
const historyUrl = new URL2("/internal/agent-api/history", registration.serverUrl);
|
|
3032
3321
|
historyUrl.searchParams.set("channel", target);
|
|
@@ -3036,181 +3325,57 @@ async function loadRecentTargetMessages(registration, headers, target) {
|
|
|
3036
3325
|
historyHeaders.delete("content-type");
|
|
3037
3326
|
const res = await fetch(historyUrl, { method: "GET", headers: historyHeaders });
|
|
3038
3327
|
if (!res.ok) return [];
|
|
3039
|
-
const parsed = await res.json().catch(() => null);
|
|
3040
|
-
return Array.isArray(parsed?.messages) ?
|
|
3041
|
-
}
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
return { bodyText: rawBody };
|
|
3048
|
-
}
|
|
3049
|
-
const target = sideEffectTarget(action, body);
|
|
3050
|
-
const coordinator = registration.inboxCoordinator;
|
|
3051
|
-
if (!target || !coordinator) {
|
|
3052
|
-
return { bodyText: JSON.stringify(body), target };
|
|
3053
|
-
}
|
|
3054
|
-
if (action === "send" && body.continueAnyway === true) {
|
|
3055
|
-
recordFreshnessDecision(coordinator, {
|
|
3056
|
-
action,
|
|
3057
|
-
decision: "bypass",
|
|
3058
|
-
target,
|
|
3059
|
-
inboxTrustState: "trusted",
|
|
3060
|
-
reason: "continue_anyway"
|
|
3061
|
-
});
|
|
3062
|
-
return { bodyText: JSON.stringify(body), target };
|
|
3063
|
-
}
|
|
3064
|
-
const pending = coordinator.getPendingMessages(target);
|
|
3065
|
-
if (pending.length > 0) {
|
|
3066
|
-
const modelSeenSeq = coordinator.getBoundary(target);
|
|
3067
|
-
const contextResult = localHeldContext({
|
|
3068
|
-
target,
|
|
3069
|
-
messages: pending,
|
|
3070
|
-
coordinator,
|
|
3071
|
-
source: "side_effect_preflight_context"
|
|
3072
|
-
});
|
|
3073
|
-
if (contextResult.ok) {
|
|
3074
|
-
const { context } = contextResult;
|
|
3075
|
-
const decision = {
|
|
3076
|
-
action,
|
|
3077
|
-
decision: "local_hold",
|
|
3078
|
-
target,
|
|
3079
|
-
inboxTrustState: "trusted",
|
|
3080
|
-
reason: "exact_target_pending",
|
|
3081
|
-
pendingCount: pending.length,
|
|
3082
|
-
pendingMaxSeq: context.seenUpToSeq,
|
|
3083
|
-
modelSeenSeq,
|
|
3084
|
-
heldMessageCount: context.shownMessageCount,
|
|
3085
|
-
omittedMessageCount: context.omittedMessageCount
|
|
3086
|
-
};
|
|
3087
|
-
const producerFactId = buildApmFreshnessDecisionProducerFactId(registration.agentId, decision);
|
|
3088
|
-
const localResponse = projectApmHeldFreshnessEnvelope({
|
|
3089
|
-
producerFactId,
|
|
3090
|
-
action,
|
|
3091
|
-
heldMessages: context.heldMessages,
|
|
3092
|
-
newMessageCount: context.newMessageCount,
|
|
3093
|
-
omittedMessageCount: context.omittedMessageCount,
|
|
3094
|
-
seenUpToSeq: context.seenUpToSeq
|
|
3095
|
-
}).body;
|
|
3096
|
-
recordFreshnessDecision(coordinator, { ...decision, producerFactId });
|
|
3097
|
-
return {
|
|
3098
|
-
bodyText: JSON.stringify(body),
|
|
3099
|
-
target,
|
|
3100
|
-
localResponse
|
|
3101
|
-
};
|
|
3102
|
-
}
|
|
3103
|
-
return {
|
|
3104
|
-
bodyText: JSON.stringify(body),
|
|
3105
|
-
target
|
|
3106
|
-
};
|
|
3107
|
-
}
|
|
3108
|
-
const existingBoundary = typeof body.seenUpToSeq === "number" && Number.isFinite(body.seenUpToSeq) ? Math.max(0, Math.floor(body.seenUpToSeq)) : void 0;
|
|
3109
|
-
const loadedBoundary = coordinator.getBoundary(target);
|
|
3110
|
-
const boundary = Math.max(existingBoundary ?? 0, loadedBoundary ?? 0);
|
|
3111
|
-
if (boundary > 0) {
|
|
3112
|
-
if (action === "send") body.seenUpToSeq = boundary;
|
|
3113
|
-
recordFreshnessDecision(coordinator, {
|
|
3114
|
-
action,
|
|
3115
|
-
decision: "forward",
|
|
3116
|
-
target,
|
|
3117
|
-
inboxTrustState: "trusted",
|
|
3118
|
-
reason: "model_seen_boundary",
|
|
3119
|
-
pendingCount: 0,
|
|
3120
|
-
modelSeenSeq: boundary
|
|
3121
|
-
});
|
|
3122
|
-
return { bodyText: JSON.stringify(body), target };
|
|
3123
|
-
}
|
|
3124
|
-
const recent = await loadRecentTargetMessages(registration, headers, target);
|
|
3125
|
-
if (recent.length > 0) {
|
|
3126
|
-
const unconsumedCounterparty = recent.filter(
|
|
3127
|
-
(message) => !isSelfAuthoredMessage(registration, message) && !isMessageModelSeen(coordinator, target, message)
|
|
3128
|
-
);
|
|
3129
|
-
const boundary2 = resolveFreshnessBoundary(recent);
|
|
3130
|
-
if (!boundary2.ok) {
|
|
3131
|
-
recordFreshnessDecision(coordinator, {
|
|
3132
|
-
action,
|
|
3133
|
-
decision: "forward",
|
|
3134
|
-
target,
|
|
3135
|
-
inboxTrustState: "untrusted",
|
|
3136
|
-
reason: "target_first_touch_recent_context_without_seq_boundary",
|
|
3137
|
-
pendingCount: 0,
|
|
3138
|
-
modelSeenSeq: 0
|
|
3139
|
-
});
|
|
3140
|
-
return { bodyText: JSON.stringify(body), target };
|
|
3141
|
-
}
|
|
3142
|
-
if (unconsumedCounterparty.length === 0) {
|
|
3143
|
-
const { seenUpToSeq: seenUpToSeq2 } = boundary2;
|
|
3144
|
-
if (action === "send") body.seenUpToSeq = seenUpToSeq2;
|
|
3145
|
-
coordinator.consumeVisibleMessages({ target, messages: recent, boundarySeq: seenUpToSeq2, source: "side_effect_preflight_context" });
|
|
3146
|
-
recordFreshnessDecision(coordinator, {
|
|
3147
|
-
action,
|
|
3148
|
-
decision: "forward",
|
|
3149
|
-
target,
|
|
3150
|
-
inboxTrustState: "untrusted",
|
|
3151
|
-
reason: "target_first_touch_recent_context_already_seen",
|
|
3152
|
-
pendingCount: 0,
|
|
3153
|
-
pendingMaxSeq: seenUpToSeq2,
|
|
3154
|
-
modelSeenSeq: seenUpToSeq2,
|
|
3155
|
-
heldMessageCount: 0,
|
|
3156
|
-
omittedMessageCount: 0
|
|
3157
|
-
});
|
|
3158
|
-
return { bodyText: JSON.stringify(body), target };
|
|
3328
|
+
const parsed = await res.json().catch(() => null);
|
|
3329
|
+
return Array.isArray(parsed?.messages) ? normalizeInboxVisibleMessages(parsed.messages, target) : [];
|
|
3330
|
+
}
|
|
3331
|
+
function applyAgentInboxStateMachineEffects(coordinator, effects) {
|
|
3332
|
+
for (const effect of effects) {
|
|
3333
|
+
if (effect.type === "record_freshness_decision") {
|
|
3334
|
+
recordFreshnessDecision(coordinator, effect.decision);
|
|
3335
|
+
continue;
|
|
3159
3336
|
}
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
decision: "syncing_hold",
|
|
3180
|
-
target,
|
|
3181
|
-
inboxTrustState: "untrusted",
|
|
3182
|
-
reason: "target_first_touch_recent_context",
|
|
3183
|
-
pendingCount: 0,
|
|
3184
|
-
pendingMaxSeq: heldBoundary.seenUpToSeq,
|
|
3185
|
-
modelSeenSeq: 0,
|
|
3186
|
-
heldMessageCount: heldMessages.length,
|
|
3187
|
-
omittedMessageCount
|
|
3188
|
-
};
|
|
3189
|
-
const producerFactId = buildApmFreshnessDecisionProducerFactId(registration.agentId, decision);
|
|
3190
|
-
recordFreshnessDecision(coordinator, { ...decision, producerFactId });
|
|
3191
|
-
return {
|
|
3192
|
-
bodyText: JSON.stringify(body),
|
|
3193
|
-
target,
|
|
3194
|
-
localResponse: projectApmHeldFreshnessEnvelope({
|
|
3195
|
-
producerFactId,
|
|
3196
|
-
action,
|
|
3197
|
-
heldMessages,
|
|
3198
|
-
newMessageCount: unconsumedCounterparty.length,
|
|
3199
|
-
omittedMessageCount,
|
|
3200
|
-
seenUpToSeq
|
|
3201
|
-
}).body
|
|
3202
|
-
};
|
|
3337
|
+
coordinator.consumeVisibleMessages({
|
|
3338
|
+
target: effect.target,
|
|
3339
|
+
messages: effect.messages,
|
|
3340
|
+
boundarySeq: effect.boundarySeq,
|
|
3341
|
+
source: effect.source
|
|
3342
|
+
});
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
async function prepareAgentApiSideEffectForward(registration, headers, rawBody, action) {
|
|
3346
|
+
let body;
|
|
3347
|
+
try {
|
|
3348
|
+
body = rawBody ? JSON.parse(rawBody) : {};
|
|
3349
|
+
} catch {
|
|
3350
|
+
return { bodyText: rawBody };
|
|
3351
|
+
}
|
|
3352
|
+
const target = sideEffectTarget(action, body);
|
|
3353
|
+
const coordinator = registration.inboxCoordinator;
|
|
3354
|
+
if (!target || !coordinator) {
|
|
3355
|
+
return { bodyText: JSON.stringify(body), target };
|
|
3203
3356
|
}
|
|
3204
|
-
|
|
3357
|
+
const pending = coordinator.getPendingMessages(target);
|
|
3358
|
+
const existingBoundary = typeof body.seenUpToSeq === "number" && Number.isFinite(body.seenUpToSeq) ? Math.max(0, Math.floor(body.seenUpToSeq)) : void 0;
|
|
3359
|
+
const continueAnyway = action === "send" && body.continueAnyway === true;
|
|
3360
|
+
const shouldLoadRecent = pending.length === 0 && !continueAnyway && Math.max(existingBoundary ?? 0, coordinator.getBoundary(target) ?? 0) <= 0;
|
|
3361
|
+
const recent = shouldLoadRecent ? await loadRecentTargetMessages(registration, headers, target) : [];
|
|
3362
|
+
const plan = planAgentInboxSideEffect({
|
|
3363
|
+
agentId: registration.agentId,
|
|
3205
3364
|
action,
|
|
3206
|
-
decision: "forward",
|
|
3207
3365
|
target,
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3366
|
+
continueAnyway,
|
|
3367
|
+
existingSeenUpToSeq: existingBoundary,
|
|
3368
|
+
modelSeenSeq: coordinator.getBoundary(target),
|
|
3369
|
+
pendingMessages: pending,
|
|
3370
|
+
recentMessages: recent,
|
|
3371
|
+
isMessageModelSeen: (messageInput) => coordinator.isMessageModelSeen?.(messageInput) === true,
|
|
3372
|
+
heldContextLimit: LOCAL_HELD_CONTEXT_LIMIT
|
|
3212
3373
|
});
|
|
3213
|
-
|
|
3374
|
+
applyAgentInboxStateMachineEffects(coordinator, plan.effects);
|
|
3375
|
+
if (typeof plan.forwardSeenUpToSeq === "number") {
|
|
3376
|
+
if (action === "send") body.seenUpToSeq = plan.forwardSeenUpToSeq;
|
|
3377
|
+
}
|
|
3378
|
+
return { bodyText: JSON.stringify(body), target, localResponse: plan.localResponse };
|
|
3214
3379
|
}
|
|
3215
3380
|
function shouldBufferJsonResponse(upstream, pathname, registration) {
|
|
3216
3381
|
if (!registration.inboxCoordinator) return false;
|
|
@@ -3230,27 +3395,26 @@ function consumeVisibleResponse(registration, targetUrl, sendTarget, responseTex
|
|
|
3230
3395
|
if (targetUrl.pathname === "/internal/agent-api/send" && parsed.state === "held" && Array.isArray(parsed.heldMessages)) {
|
|
3231
3396
|
coordinator.consumeVisibleMessages({
|
|
3232
3397
|
target: sendTarget,
|
|
3233
|
-
messages:
|
|
3398
|
+
messages: normalizeInboxVisibleMessages(parsed.heldMessages, sendTarget),
|
|
3234
3399
|
boundarySeq: typeof parsed.seenUpToSeq === "number" ? parsed.seenUpToSeq : void 0,
|
|
3235
3400
|
source: "server_held_context"
|
|
3236
3401
|
});
|
|
3237
3402
|
return;
|
|
3238
3403
|
}
|
|
3239
3404
|
if (targetUrl.pathname === "/internal/agent-api/send" && parsed.state === "sent") {
|
|
3240
|
-
const
|
|
3241
|
-
if (sendTarget &&
|
|
3405
|
+
const messageSeq4 = typeof parsed.messageSeq === "number" && Number.isFinite(parsed.messageSeq) ? Math.floor(parsed.messageSeq) : void 0;
|
|
3406
|
+
if (sendTarget && messageSeq4 && messageSeq4 > 0) {
|
|
3242
3407
|
coordinator.consumeVisibleMessages({
|
|
3243
3408
|
target: sendTarget,
|
|
3244
|
-
messages:
|
|
3245
|
-
boundarySeq: messageSeq3,
|
|
3409
|
+
messages: normalizeInboxVisibleMessages([{ id: parsed.messageId }], sendTarget),
|
|
3246
3410
|
source: "agent_api_send_commit"
|
|
3247
3411
|
});
|
|
3248
3412
|
}
|
|
3249
3413
|
return;
|
|
3250
3414
|
}
|
|
3251
3415
|
if (targetUrl.pathname === "/internal/agent-api/events" && Array.isArray(parsed.events)) {
|
|
3252
|
-
const messages =
|
|
3253
|
-
coordinator.consumeVisibleMessages({ messages, source: "
|
|
3416
|
+
const messages = normalizeInboxVisibleMessages(parsed.events);
|
|
3417
|
+
coordinator.consumeVisibleMessages({ messages, source: "agent_api_events_server" });
|
|
3254
3418
|
coordinator.recordDrainOutcome?.({
|
|
3255
3419
|
source: "server_events",
|
|
3256
3420
|
sinceCursorKind: parseAgentApiEventsQuery(targetUrl).sinceCursorKind,
|
|
@@ -3262,8 +3426,8 @@ function consumeVisibleResponse(registration, targetUrl, sendTarget, responseTex
|
|
|
3262
3426
|
}
|
|
3263
3427
|
if (targetUrl.pathname === "/internal/agent-api/history" && Array.isArray(parsed.messages)) {
|
|
3264
3428
|
const target = targetUrl.searchParams.get("channel") ?? void 0;
|
|
3265
|
-
const messages =
|
|
3266
|
-
coordinator.consumeVisibleMessages({ target, messages, boundarySeq:
|
|
3429
|
+
const messages = normalizeInboxVisibleMessages(parsed.messages, target);
|
|
3430
|
+
coordinator.consumeVisibleMessages({ target, messages, boundarySeq: maxInboxMessageSeq(messages), source: "agent_api_history" });
|
|
3267
3431
|
}
|
|
3268
3432
|
}
|
|
3269
3433
|
async function registerAgentCredentialProxy(input) {
|
|
@@ -3302,9 +3466,7 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
|
|
|
3302
3466
|
var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
|
|
3303
3467
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
3304
3468
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
3305
|
-
"
|
|
3306
|
-
"SLOCK_AGENT_CREDENTIAL_KEY",
|
|
3307
|
-
"SLOCK_AGENT_CREDENTIAL_KEY_FILE"
|
|
3469
|
+
"SLOCK_AGENT_CREDENTIAL_KEY"
|
|
3308
3470
|
];
|
|
3309
3471
|
var cachedOpencliBinPath;
|
|
3310
3472
|
function resolveOpencliBinPath() {
|
|
@@ -3519,7 +3681,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
|
|
|
3519
3681
|
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
3520
3682
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
3521
3683
|
};
|
|
3522
|
-
|
|
3684
|
+
delete spawnEnv.SLOCK_AGENT_TOKEN;
|
|
3523
3685
|
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
3524
3686
|
delete spawnEnv[key];
|
|
3525
3687
|
}
|
|
@@ -3948,7 +4110,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
|
|
|
3948
4110
|
}
|
|
3949
4111
|
function resolveCommandOnPath(command, deps = {}) {
|
|
3950
4112
|
const platform = deps.platform ?? process.platform;
|
|
3951
|
-
const env =
|
|
4113
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
3952
4114
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
3953
4115
|
const existsSyncFn = deps.existsSyncFn ?? existsSync2;
|
|
3954
4116
|
if (platform === "win32") {
|
|
@@ -3974,7 +4136,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
3974
4136
|
return null;
|
|
3975
4137
|
}
|
|
3976
4138
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
3977
|
-
const env =
|
|
4139
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
3978
4140
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
3979
4141
|
try {
|
|
3980
4142
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -5328,11 +5490,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
5328
5490
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
5329
5491
|
}
|
|
5330
5492
|
function buildCursorModelProbeEnv(deps = {}) {
|
|
5331
|
-
return
|
|
5493
|
+
return withWindowsUserEnvironment({
|
|
5332
5494
|
...deps.env ?? process.env,
|
|
5333
5495
|
FORCE_COLOR: "0",
|
|
5334
5496
|
NO_COLOR: "1"
|
|
5335
|
-
}, deps)
|
|
5497
|
+
}, deps);
|
|
5336
5498
|
}
|
|
5337
5499
|
function runCursorModelsCommand() {
|
|
5338
5500
|
return spawnSync("cursor-agent", ["models"], {
|
|
@@ -5388,7 +5550,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
5388
5550
|
}
|
|
5389
5551
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
5390
5552
|
const existsSyncFn = deps.existsSyncFn ?? existsSync4;
|
|
5391
|
-
const env =
|
|
5553
|
+
const env = deps.env ?? process.env;
|
|
5392
5554
|
const winPath = path6.win32;
|
|
5393
5555
|
let geminiEntry = null;
|
|
5394
5556
|
try {
|
|
@@ -5528,15 +5690,12 @@ var GeminiDriver = class {
|
|
|
5528
5690
|
// src/drivers/kimi.ts
|
|
5529
5691
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5530
5692
|
import { spawn as spawn7 } from "child_process";
|
|
5531
|
-
import {
|
|
5693
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5532
5694
|
import os3 from "os";
|
|
5533
5695
|
import path7 from "path";
|
|
5534
5696
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
5535
5697
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
5536
5698
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
5537
|
-
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
5538
|
-
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
5539
|
-
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
5540
5699
|
function parseToolArguments(raw) {
|
|
5541
5700
|
if (typeof raw !== "string") return raw;
|
|
5542
5701
|
try {
|
|
@@ -5545,73 +5704,6 @@ function parseToolArguments(raw) {
|
|
|
5545
5704
|
return raw;
|
|
5546
5705
|
}
|
|
5547
5706
|
}
|
|
5548
|
-
function readKimiConfigSource(home = os3.homedir(), env = process.env) {
|
|
5549
|
-
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5550
|
-
if (inlineConfig && inlineConfig.trim()) {
|
|
5551
|
-
return {
|
|
5552
|
-
raw: inlineConfig,
|
|
5553
|
-
explicitPath: null,
|
|
5554
|
-
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
5555
|
-
};
|
|
5556
|
-
}
|
|
5557
|
-
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5558
|
-
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path7.join(home, ".kimi", "config.toml");
|
|
5559
|
-
try {
|
|
5560
|
-
return {
|
|
5561
|
-
raw: readFileSync3(configPath, "utf8"),
|
|
5562
|
-
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5563
|
-
sourcePath: configPath
|
|
5564
|
-
};
|
|
5565
|
-
} catch {
|
|
5566
|
-
return {
|
|
5567
|
-
raw: null,
|
|
5568
|
-
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
5569
|
-
sourcePath: configPath
|
|
5570
|
-
};
|
|
5571
|
-
}
|
|
5572
|
-
}
|
|
5573
|
-
function buildKimiSpawnEnv(env = process.env) {
|
|
5574
|
-
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
5575
|
-
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
5576
|
-
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
5577
|
-
return scrubDaemonChildEnv(spawnEnv);
|
|
5578
|
-
}
|
|
5579
|
-
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
5580
|
-
return {
|
|
5581
|
-
...process.env,
|
|
5582
|
-
...ctx.config.envVars || {},
|
|
5583
|
-
...overrideEnv || {}
|
|
5584
|
-
};
|
|
5585
|
-
}
|
|
5586
|
-
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
5587
|
-
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
5588
|
-
const source = readKimiConfigSource(opts.home ?? os3.homedir(), env);
|
|
5589
|
-
const args = [];
|
|
5590
|
-
let configFilePath = null;
|
|
5591
|
-
let configContent = null;
|
|
5592
|
-
if (source.explicitPath) {
|
|
5593
|
-
configFilePath = source.explicitPath;
|
|
5594
|
-
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
5595
|
-
configFilePath = path7.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
5596
|
-
configContent = source.raw;
|
|
5597
|
-
if (opts.writeGeneratedConfig !== false) {
|
|
5598
|
-
writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
5599
|
-
chmodSync(configFilePath, 384);
|
|
5600
|
-
}
|
|
5601
|
-
}
|
|
5602
|
-
if (configFilePath) {
|
|
5603
|
-
args.push("--config-file", configFilePath);
|
|
5604
|
-
}
|
|
5605
|
-
if (ctx.config.model && ctx.config.model !== "default") {
|
|
5606
|
-
args.push("--model", ctx.config.model);
|
|
5607
|
-
}
|
|
5608
|
-
return {
|
|
5609
|
-
args,
|
|
5610
|
-
env: buildKimiSpawnEnv(env),
|
|
5611
|
-
configFilePath,
|
|
5612
|
-
configContent
|
|
5613
|
-
};
|
|
5614
|
-
}
|
|
5615
5707
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
5616
5708
|
return {
|
|
5617
5709
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -5635,25 +5727,7 @@ var KimiDriver = class {
|
|
|
5635
5727
|
};
|
|
5636
5728
|
model = {
|
|
5637
5729
|
detectedModelsVerifiedAs: "launchable",
|
|
5638
|
-
toLaunchSpec: (modelId
|
|
5639
|
-
if (!ctx) return { args: ["--model", modelId] };
|
|
5640
|
-
const launchCtx = {
|
|
5641
|
-
...ctx,
|
|
5642
|
-
config: {
|
|
5643
|
-
...ctx.config,
|
|
5644
|
-
model: modelId
|
|
5645
|
-
}
|
|
5646
|
-
};
|
|
5647
|
-
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
5648
|
-
home: opts?.home,
|
|
5649
|
-
writeGeneratedConfig: false
|
|
5650
|
-
});
|
|
5651
|
-
return {
|
|
5652
|
-
args: launch.args,
|
|
5653
|
-
env: launch.env,
|
|
5654
|
-
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
5655
|
-
};
|
|
5656
|
-
}
|
|
5730
|
+
toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
|
|
5657
5731
|
};
|
|
5658
5732
|
supportsStdinNotification = true;
|
|
5659
5733
|
mcpToolPrefix = "";
|
|
@@ -5679,23 +5753,21 @@ var KimiDriver = class {
|
|
|
5679
5753
|
` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
|
|
5680
5754
|
""
|
|
5681
5755
|
].join("\n"), "utf8");
|
|
5682
|
-
const launch = buildKimiLaunchOptions(ctx);
|
|
5683
5756
|
const args = [
|
|
5684
5757
|
"--wire",
|
|
5685
5758
|
"--yolo",
|
|
5686
5759
|
"--agent-file",
|
|
5687
5760
|
agentFilePath,
|
|
5688
5761
|
"--session",
|
|
5689
|
-
this.sessionId
|
|
5690
|
-
...launch.args
|
|
5762
|
+
this.sessionId
|
|
5691
5763
|
];
|
|
5692
5764
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
5693
5765
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
|
|
5694
5766
|
args.push("--model", launchRuntimeFields.model);
|
|
5695
5767
|
}
|
|
5696
5768
|
const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
5697
|
-
const
|
|
5698
|
-
const proc = spawn7(
|
|
5769
|
+
const launch = resolveKimiSpawn(args);
|
|
5770
|
+
const proc = spawn7(launch.command, launch.args, {
|
|
5699
5771
|
cwd: ctx.workingDirectory,
|
|
5700
5772
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5701
5773
|
env: spawnEnv,
|
|
@@ -5703,7 +5775,7 @@ var KimiDriver = class {
|
|
|
5703
5775
|
// and has an 8191-character command-line limit. Kimi's official
|
|
5704
5776
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
5705
5777
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
5706
|
-
shell:
|
|
5778
|
+
shell: launch.shell
|
|
5707
5779
|
});
|
|
5708
5780
|
proc.stdin?.write(JSON.stringify({
|
|
5709
5781
|
jsonrpc: "2.0",
|
|
@@ -5817,9 +5889,14 @@ var KimiDriver = class {
|
|
|
5817
5889
|
return detectKimiModels();
|
|
5818
5890
|
}
|
|
5819
5891
|
};
|
|
5820
|
-
function detectKimiModels(home = os3.homedir()
|
|
5821
|
-
const
|
|
5822
|
-
|
|
5892
|
+
function detectKimiModels(home = os3.homedir()) {
|
|
5893
|
+
const configPath = path7.join(home, ".kimi", "config.toml");
|
|
5894
|
+
let raw;
|
|
5895
|
+
try {
|
|
5896
|
+
raw = readFileSync3(configPath, "utf8");
|
|
5897
|
+
} catch {
|
|
5898
|
+
return null;
|
|
5899
|
+
}
|
|
5823
5900
|
const models = [];
|
|
5824
5901
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
5825
5902
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -6059,7 +6136,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
6059
6136
|
const platform = deps.platform ?? process.platform;
|
|
6060
6137
|
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
6061
6138
|
const result = spawnSyncFn("opencode", ["models"], {
|
|
6062
|
-
env:
|
|
6139
|
+
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
6063
6140
|
encoding: "utf8",
|
|
6064
6141
|
timeout: 5e3,
|
|
6065
6142
|
shell: platform === "win32"
|
|
@@ -7304,9 +7381,26 @@ var RuntimeProgressState = class {
|
|
|
7304
7381
|
};
|
|
7305
7382
|
|
|
7306
7383
|
// src/runtimeNotificationState.ts
|
|
7384
|
+
function computeInboxNoticeFingerprint(messages) {
|
|
7385
|
+
const keys = [];
|
|
7386
|
+
for (const m of messages) {
|
|
7387
|
+
const seq = typeof m.seq === "number" && Number.isFinite(m.seq) && m.seq > 0 ? Math.floor(m.seq) : null;
|
|
7388
|
+
if (seq !== null) {
|
|
7389
|
+
keys.push(`s:${seq}`);
|
|
7390
|
+
continue;
|
|
7391
|
+
}
|
|
7392
|
+
const id = typeof m.message_id === "string" && m.message_id.length > 0 ? m.message_id : typeof m.id === "string" && m.id.length > 0 ? m.id : "";
|
|
7393
|
+
if (id.length > 0) keys.push(`m:${id}`);
|
|
7394
|
+
}
|
|
7395
|
+
if (keys.length === 0) return "";
|
|
7396
|
+
keys.sort();
|
|
7397
|
+
return keys.join(",");
|
|
7398
|
+
}
|
|
7307
7399
|
var RuntimeNotificationState = class {
|
|
7308
7400
|
timerValue = null;
|
|
7309
7401
|
pendingCountValue = 0;
|
|
7402
|
+
lastNoticeFingerprint = null;
|
|
7403
|
+
lastNoticeSessionId = null;
|
|
7310
7404
|
get pendingCount() {
|
|
7311
7405
|
return this.pendingCountValue;
|
|
7312
7406
|
}
|
|
@@ -7337,6 +7431,25 @@ var RuntimeNotificationState = class {
|
|
|
7337
7431
|
clear() {
|
|
7338
7432
|
this.clearPending();
|
|
7339
7433
|
this.clearTimer();
|
|
7434
|
+
this.clearNoticeFingerprint();
|
|
7435
|
+
}
|
|
7436
|
+
/**
|
|
7437
|
+
* True iff this exact unread-set was already successfully written in THIS
|
|
7438
|
+
* session (per-(agent,session) scope — never suppress across a session
|
|
7439
|
+
* change). Empty fingerprint always returns false (fail toward sending).
|
|
7440
|
+
*/
|
|
7441
|
+
isDuplicateNotice(fingerprint, sessionId) {
|
|
7442
|
+
if (fingerprint.length === 0) return false;
|
|
7443
|
+
return this.lastNoticeFingerprint === fingerprint && this.lastNoticeSessionId === sessionId;
|
|
7444
|
+
}
|
|
7445
|
+
/** Register a fingerprint as written — call ONLY after a successful stdin write. */
|
|
7446
|
+
recordNoticeWritten(fingerprint, sessionId) {
|
|
7447
|
+
this.lastNoticeFingerprint = fingerprint;
|
|
7448
|
+
this.lastNoticeSessionId = sessionId;
|
|
7449
|
+
}
|
|
7450
|
+
clearNoticeFingerprint() {
|
|
7451
|
+
this.lastNoticeFingerprint = null;
|
|
7452
|
+
this.lastNoticeSessionId = null;
|
|
7340
7453
|
}
|
|
7341
7454
|
schedule(callback, delayMs) {
|
|
7342
7455
|
if (this.timerValue) return false;
|
|
@@ -7468,34 +7581,24 @@ function toLocalTime(iso) {
|
|
|
7468
7581
|
function formatChannelLabel(message) {
|
|
7469
7582
|
return message.channel_type === "dm" ? `DM:@${message.channel_name}` : `#${message.channel_name}`;
|
|
7470
7583
|
}
|
|
7471
|
-
function
|
|
7472
|
-
if (
|
|
7473
|
-
const shortId = getMessageShortId(
|
|
7474
|
-
if (
|
|
7475
|
-
return `dm:@${
|
|
7584
|
+
function computeTarget(channelType, channelName, parentChannelName, parentChannelType) {
|
|
7585
|
+
if (channelType === "thread" && parentChannelName) {
|
|
7586
|
+
const shortId = getMessageShortId(String(channelName ?? ""));
|
|
7587
|
+
if (parentChannelType === "dm") {
|
|
7588
|
+
return `dm:@${parentChannelName}:${shortId}`;
|
|
7476
7589
|
}
|
|
7477
|
-
return `#${
|
|
7590
|
+
return `#${parentChannelName}:${shortId}`;
|
|
7478
7591
|
}
|
|
7479
|
-
if (
|
|
7480
|
-
return `dm:@${
|
|
7592
|
+
if (channelType === "dm") {
|
|
7593
|
+
return `dm:@${channelName}`;
|
|
7481
7594
|
}
|
|
7482
|
-
return `#${
|
|
7595
|
+
return `#${channelName}`;
|
|
7596
|
+
}
|
|
7597
|
+
function formatMessageTarget(message) {
|
|
7598
|
+
return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
|
|
7483
7599
|
}
|
|
7484
7600
|
function formatVisibleMessageTarget(message) {
|
|
7485
|
-
|
|
7486
|
-
const shortId = getMessageShortId(String(message.channel_name));
|
|
7487
|
-
if (message.parent_channel_type === "dm") {
|
|
7488
|
-
return `dm:@${message.parent_channel_name}:${shortId}`;
|
|
7489
|
-
}
|
|
7490
|
-
return `#${message.parent_channel_name}:${shortId}`;
|
|
7491
|
-
}
|
|
7492
|
-
if (message.channel_type === "dm" && message.channel_name) {
|
|
7493
|
-
return `dm:@${message.channel_name}`;
|
|
7494
|
-
}
|
|
7495
|
-
if (message.channel_name) {
|
|
7496
|
-
return `#${message.channel_name}`;
|
|
7497
|
-
}
|
|
7498
|
-
return null;
|
|
7601
|
+
return computeTarget(message.channel_type, message.channel_name, message.parent_channel_name, message.parent_channel_type);
|
|
7499
7602
|
}
|
|
7500
7603
|
function getMessageShortId(messageId2) {
|
|
7501
7604
|
return messageId2.startsWith("thread-") ? messageId2.slice(7) : messageId2.slice(0, 8);
|
|
@@ -7717,6 +7820,8 @@ var TRAJECTORY_COALESCE_MS = 350;
|
|
|
7717
7820
|
var ACTIVITY_HEARTBEAT_MS = 6e4;
|
|
7718
7821
|
var STDIN_NOTIFICATION_INITIAL_DELAY_MS = 3e3;
|
|
7719
7822
|
var STDIN_NOTIFICATION_RETRY_DELAY_MS = 15e3;
|
|
7823
|
+
var RUNTIME_ERROR_DELIVERY_BACKOFF_BASE_MS = 1e4;
|
|
7824
|
+
var RUNTIME_ERROR_DELIVERY_BACKOFF_MAX_MS = 5 * 6e4;
|
|
7720
7825
|
var COMPACTION_STALE_MS = 5 * 6e4;
|
|
7721
7826
|
var RUNTIME_PROGRESS_STALE_MS = 15 * 6e4;
|
|
7722
7827
|
var DEFAULT_RUNTIME_START_TIMEOUT_MS = 2 * 6e4;
|
|
@@ -8130,6 +8235,14 @@ function createRuntimeTraceCounters() {
|
|
|
8130
8235
|
thinkingEvents: 0
|
|
8131
8236
|
};
|
|
8132
8237
|
}
|
|
8238
|
+
function createRuntimeErrorDeliveryBackoffState() {
|
|
8239
|
+
return {
|
|
8240
|
+
attempts: 0,
|
|
8241
|
+
untilMs: 0,
|
|
8242
|
+
timer: null,
|
|
8243
|
+
reason: null
|
|
8244
|
+
};
|
|
8245
|
+
}
|
|
8133
8246
|
function cleanupAgentCredentialProxy(agentId, launchId) {
|
|
8134
8247
|
unregisterAgentCredentialProxyForLaunch({ agentId, launchId });
|
|
8135
8248
|
}
|
|
@@ -8574,6 +8687,10 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8574
8687
|
defaultAgentEnvVarsProvider;
|
|
8575
8688
|
tracer;
|
|
8576
8689
|
stdinNotificationRetryMs;
|
|
8690
|
+
runtimeErrorDeliveryBackoffBaseMs;
|
|
8691
|
+
runtimeErrorDeliveryBackoffMaxMs;
|
|
8692
|
+
runtimeErrorDeliveryBackoffJitterRatio;
|
|
8693
|
+
runtimeErrorDeliveryBackoffFailPointForTesting;
|
|
8577
8694
|
cliTransportTraceDir = null;
|
|
8578
8695
|
deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
|
|
8579
8696
|
runtimeExitTraceAttrs = /* @__PURE__ */ new WeakMap();
|
|
@@ -8597,6 +8714,19 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8597
8714
|
0,
|
|
8598
8715
|
Math.floor(opts.stdinNotificationRetryMs ?? STDIN_NOTIFICATION_RETRY_DELAY_MS)
|
|
8599
8716
|
);
|
|
8717
|
+
this.runtimeErrorDeliveryBackoffBaseMs = Math.max(
|
|
8718
|
+
0,
|
|
8719
|
+
Math.floor(opts.runtimeErrorDeliveryBackoff?.baseMs ?? RUNTIME_ERROR_DELIVERY_BACKOFF_BASE_MS)
|
|
8720
|
+
);
|
|
8721
|
+
this.runtimeErrorDeliveryBackoffMaxMs = Math.max(
|
|
8722
|
+
this.runtimeErrorDeliveryBackoffBaseMs,
|
|
8723
|
+
Math.floor(opts.runtimeErrorDeliveryBackoff?.maxMs ?? RUNTIME_ERROR_DELIVERY_BACKOFF_MAX_MS)
|
|
8724
|
+
);
|
|
8725
|
+
this.runtimeErrorDeliveryBackoffJitterRatio = Math.max(
|
|
8726
|
+
0,
|
|
8727
|
+
Math.min(1, opts.runtimeErrorDeliveryBackoff?.jitterRatio ?? 0.1)
|
|
8728
|
+
);
|
|
8729
|
+
this.runtimeErrorDeliveryBackoffFailPointForTesting = opts.runtimeErrorDeliveryBackoff?.failPointForTesting ?? null;
|
|
8600
8730
|
this.maxConcurrentAgentStarts = Math.max(
|
|
8601
8731
|
1,
|
|
8602
8732
|
Math.floor(
|
|
@@ -8650,6 +8780,183 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8650
8780
|
this.sendStdinNotification(agentId);
|
|
8651
8781
|
}, delayMs);
|
|
8652
8782
|
}
|
|
8783
|
+
clearRuntimeErrorDeliveryBackoff(ap) {
|
|
8784
|
+
if (ap.runtimeErrorDeliveryBackoff.timer) {
|
|
8785
|
+
clearTimeout(ap.runtimeErrorDeliveryBackoff.timer);
|
|
8786
|
+
}
|
|
8787
|
+
ap.runtimeErrorDeliveryBackoff = createRuntimeErrorDeliveryBackoffState();
|
|
8788
|
+
}
|
|
8789
|
+
clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, eventKind) {
|
|
8790
|
+
if (ap.runtimeErrorDeliveryBackoff.attempts === 0 && ap.runtimeErrorDeliveryBackoff.untilMs === 0) return;
|
|
8791
|
+
const attempts = ap.runtimeErrorDeliveryBackoff.attempts;
|
|
8792
|
+
const reason = ap.runtimeErrorDeliveryBackoff.reason;
|
|
8793
|
+
this.clearRuntimeErrorDeliveryBackoff(ap);
|
|
8794
|
+
this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.reset", {
|
|
8795
|
+
agentId,
|
|
8796
|
+
runtime: ap.config.runtime,
|
|
8797
|
+
model: ap.config.model,
|
|
8798
|
+
launchId: ap.launchId || void 0,
|
|
8799
|
+
reason: reason || void 0,
|
|
8800
|
+
attempts,
|
|
8801
|
+
reset_source: eventKind
|
|
8802
|
+
});
|
|
8803
|
+
}
|
|
8804
|
+
runtimeErrorDeliveryBackoffRemainingMs(ap) {
|
|
8805
|
+
return Math.max(0, ap.runtimeErrorDeliveryBackoff.untilMs - Date.now());
|
|
8806
|
+
}
|
|
8807
|
+
scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap) {
|
|
8808
|
+
const delayMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
|
|
8809
|
+
if (delayMs <= 0 || ap.runtimeErrorDeliveryBackoff.timer) return false;
|
|
8810
|
+
ap.runtimeErrorDeliveryBackoff.timer = setTimeout(() => {
|
|
8811
|
+
ap.runtimeErrorDeliveryBackoff.timer = null;
|
|
8812
|
+
this.flushRuntimeErrorDeliveryBackoff(agentId);
|
|
8813
|
+
}, delayMs);
|
|
8814
|
+
ap.runtimeErrorDeliveryBackoff.timer.unref?.();
|
|
8815
|
+
return true;
|
|
8816
|
+
}
|
|
8817
|
+
recoverableRuntimeDeliveryBackoffReason(message, terminalFailure, stickyTerminalFailure, reasonOverride) {
|
|
8818
|
+
if (stickyTerminalFailure || terminalFailure?.actionRequired) return null;
|
|
8819
|
+
if (reasonOverride !== void 0) return reasonOverride;
|
|
8820
|
+
if (terminalFailure) return "recoverable_terminal_runtime_error";
|
|
8821
|
+
const runtimeErrorClass = buildRuntimeErrorDiagnosticEnvelope(message).spanAttrs.runtime_error_class;
|
|
8822
|
+
switch (runtimeErrorClass) {
|
|
8823
|
+
case "RateLimitError":
|
|
8824
|
+
return "rate_limited";
|
|
8825
|
+
case "ProviderServerError":
|
|
8826
|
+
return "provider_server_error";
|
|
8827
|
+
case "ProviderConnectionError":
|
|
8828
|
+
return "provider_connection_error";
|
|
8829
|
+
case "ProviderStreamError":
|
|
8830
|
+
return "provider_stream_error";
|
|
8831
|
+
default:
|
|
8832
|
+
return null;
|
|
8833
|
+
}
|
|
8834
|
+
}
|
|
8835
|
+
noteRuntimeErrorDeliveryBackoff(agentId, ap, message, terminalFailure, stickyTerminalFailure, reasonOverride) {
|
|
8836
|
+
const reason = this.recoverableRuntimeDeliveryBackoffReason(message, terminalFailure, stickyTerminalFailure, reasonOverride);
|
|
8837
|
+
if (!reason) return false;
|
|
8838
|
+
const attempts = ap.runtimeErrorDeliveryBackoff.attempts + 1;
|
|
8839
|
+
const exponentialDelayMs = this.runtimeErrorDeliveryBackoffBaseMs * 2 ** Math.max(0, attempts - 1);
|
|
8840
|
+
const cappedDelayMs = Math.min(this.runtimeErrorDeliveryBackoffMaxMs, exponentialDelayMs);
|
|
8841
|
+
const jitterMs = Math.floor(cappedDelayMs * this.runtimeErrorDeliveryBackoffJitterRatio * Math.random());
|
|
8842
|
+
const delayMs = Math.min(this.runtimeErrorDeliveryBackoffMaxMs, cappedDelayMs + jitterMs);
|
|
8843
|
+
if (ap.runtimeErrorDeliveryBackoff.timer) {
|
|
8844
|
+
clearTimeout(ap.runtimeErrorDeliveryBackoff.timer);
|
|
8845
|
+
ap.runtimeErrorDeliveryBackoff.timer = null;
|
|
8846
|
+
}
|
|
8847
|
+
ap.runtimeErrorDeliveryBackoff.attempts = attempts;
|
|
8848
|
+
ap.runtimeErrorDeliveryBackoff.reason = reason;
|
|
8849
|
+
ap.runtimeErrorDeliveryBackoff.untilMs = Date.now() + delayMs;
|
|
8850
|
+
if (ap.inbox.length > 0) {
|
|
8851
|
+
this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
|
|
8852
|
+
}
|
|
8853
|
+
this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff", {
|
|
8854
|
+
agentId,
|
|
8855
|
+
runtime: ap.config.runtime,
|
|
8856
|
+
model: ap.config.model,
|
|
8857
|
+
launchId: ap.launchId || void 0,
|
|
8858
|
+
reason,
|
|
8859
|
+
attempts,
|
|
8860
|
+
delay_ms: delayMs,
|
|
8861
|
+
until_ms: ap.runtimeErrorDeliveryBackoff.untilMs,
|
|
8862
|
+
inbox_count: ap.inbox.length,
|
|
8863
|
+
pending_notification_count: ap.notifications.pendingCount
|
|
8864
|
+
});
|
|
8865
|
+
return true;
|
|
8866
|
+
}
|
|
8867
|
+
queueDeliveryForRuntimeErrorBackoff(agentId, ap, message) {
|
|
8868
|
+
const remainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
|
|
8869
|
+
if (remainingMs <= 0) return false;
|
|
8870
|
+
ap.inbox.push(message);
|
|
8871
|
+
if (!ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
|
|
8872
|
+
ap.notifications.add();
|
|
8873
|
+
}
|
|
8874
|
+
const scheduled = this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
|
|
8875
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
8876
|
+
outcome: "queued_runtime_error_backoff",
|
|
8877
|
+
accepted: true,
|
|
8878
|
+
process_present: true,
|
|
8879
|
+
runtime: ap.config.runtime,
|
|
8880
|
+
session_id_present: Boolean(ap.sessionId),
|
|
8881
|
+
launchId: ap.launchId || void 0,
|
|
8882
|
+
is_idle: ap.isIdle,
|
|
8883
|
+
inbox_count: ap.inbox.length,
|
|
8884
|
+
pending_notification_count: ap.notifications.pendingCount,
|
|
8885
|
+
runtime_error_backoff_remaining_ms: remainingMs,
|
|
8886
|
+
runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
|
|
8887
|
+
runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
|
|
8888
|
+
runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null
|
|
8889
|
+
}));
|
|
8890
|
+
return true;
|
|
8891
|
+
}
|
|
8892
|
+
flushRuntimeErrorDeliveryBackoff(agentId) {
|
|
8893
|
+
const ap = this.agents.get(agentId);
|
|
8894
|
+
if (!ap) return false;
|
|
8895
|
+
const remainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
|
|
8896
|
+
if (remainingMs > 0) {
|
|
8897
|
+
this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
|
|
8898
|
+
return false;
|
|
8899
|
+
}
|
|
8900
|
+
if (ap.inbox.length === 0) return false;
|
|
8901
|
+
const reason = ap.runtimeErrorDeliveryBackoff.reason || "runtime_error_backoff";
|
|
8902
|
+
if (ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
|
|
8903
|
+
const messages = [...ap.inbox];
|
|
8904
|
+
ap.notifications.clearPending();
|
|
8905
|
+
ap.notifications.clearTimer();
|
|
8906
|
+
this.commitApmIdleState(agentId, ap, false);
|
|
8907
|
+
this.startRuntimeTrace(agentId, ap, "runtime-error-backoff-idle-delivery", messages);
|
|
8908
|
+
this.broadcastActivity(agentId, "working", "Message received");
|
|
8909
|
+
const accepted2 = this.deliverInboxUpdateViaStdin(
|
|
8910
|
+
agentId,
|
|
8911
|
+
ap,
|
|
8912
|
+
messages,
|
|
8913
|
+
"idle",
|
|
8914
|
+
"runtime_error_backoff_idle_delivery"
|
|
8915
|
+
);
|
|
8916
|
+
this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.flush", {
|
|
8917
|
+
agentId,
|
|
8918
|
+
runtime: ap.config.runtime,
|
|
8919
|
+
model: ap.config.model,
|
|
8920
|
+
launchId: ap.launchId || void 0,
|
|
8921
|
+
reason,
|
|
8922
|
+
mode: "idle",
|
|
8923
|
+
outcome: accepted2 ? "written" : "not_written",
|
|
8924
|
+
inbox_count: ap.inbox.length,
|
|
8925
|
+
messages_count: messages.length
|
|
8926
|
+
});
|
|
8927
|
+
return accepted2;
|
|
8928
|
+
}
|
|
8929
|
+
if (!ap.driver.supportsStdinNotification || !ap.sessionId) {
|
|
8930
|
+
this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.flush", {
|
|
8931
|
+
agentId,
|
|
8932
|
+
runtime: ap.config.runtime,
|
|
8933
|
+
model: ap.config.model,
|
|
8934
|
+
launchId: ap.launchId || void 0,
|
|
8935
|
+
reason,
|
|
8936
|
+
outcome: "queued_without_stdin",
|
|
8937
|
+
inbox_count: ap.inbox.length,
|
|
8938
|
+
session_id_present: Boolean(ap.sessionId),
|
|
8939
|
+
supports_stdin_notification: ap.driver.supportsStdinNotification
|
|
8940
|
+
});
|
|
8941
|
+
return false;
|
|
8942
|
+
}
|
|
8943
|
+
if (ap.notifications.pendingCount === 0) {
|
|
8944
|
+
ap.notifications.add(ap.inbox.length);
|
|
8945
|
+
}
|
|
8946
|
+
const accepted = this.sendStdinNotification(agentId);
|
|
8947
|
+
this.recordDaemonTrace("daemon.agent.runtime_error_delivery_backoff.flush", {
|
|
8948
|
+
agentId,
|
|
8949
|
+
runtime: ap.config.runtime,
|
|
8950
|
+
model: ap.config.model,
|
|
8951
|
+
launchId: ap.launchId || void 0,
|
|
8952
|
+
reason,
|
|
8953
|
+
mode: "busy",
|
|
8954
|
+
outcome: accepted ? "written" : "not_written",
|
|
8955
|
+
inbox_count: ap.inbox.length,
|
|
8956
|
+
pending_notification_count: ap.notifications.pendingCount
|
|
8957
|
+
});
|
|
8958
|
+
return accepted;
|
|
8959
|
+
}
|
|
8653
8960
|
allPendingVisibleMessages(agentId) {
|
|
8654
8961
|
const collect = (messages) => (messages ?? []).filter((message) => typeof message.seq === "number" && message.seq > 0);
|
|
8655
8962
|
return [
|
|
@@ -8696,10 +9003,13 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8696
9003
|
if (byTarget.size === 0) return;
|
|
8697
9004
|
const boundaryMap = this.visibleBoundaryMap(agentId);
|
|
8698
9005
|
const visibleIds = this.visibleMessageIdMap(agentId);
|
|
9006
|
+
const advancesBoundary = input.source === "spawn_wake_message" || input.source === "agent_api_events_local" || input.source.startsWith("stdin_");
|
|
8699
9007
|
for (const [target, bucket] of byTarget) {
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
9008
|
+
if (advancesBoundary) {
|
|
9009
|
+
const highWaterSeq = Math.max(bucket.maxSeq, bucket.boundarySeq);
|
|
9010
|
+
const previous = boundaryMap.get(target) ?? 0;
|
|
9011
|
+
boundaryMap.set(target, Math.max(previous, highWaterSeq));
|
|
9012
|
+
}
|
|
8703
9013
|
if (bucket.ids.size > 0) {
|
|
8704
9014
|
let targetIds = visibleIds.get(target);
|
|
8705
9015
|
if (!targetIds) {
|
|
@@ -8763,6 +9073,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8763
9073
|
active.notifications.remove(removedActive);
|
|
8764
9074
|
if (active.inbox.length === 0) {
|
|
8765
9075
|
active.notifications.clear();
|
|
9076
|
+
this.clearRuntimeErrorDeliveryBackoff(active);
|
|
8766
9077
|
}
|
|
8767
9078
|
}
|
|
8768
9079
|
const removedCount = removedActive + removedStarting;
|
|
@@ -9277,6 +9588,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9277
9588
|
recentStdout: [],
|
|
9278
9589
|
recentStderr: [],
|
|
9279
9590
|
lastRuntimeError: null,
|
|
9591
|
+
runtimeErrorDeliveryBackoff: createRuntimeErrorDeliveryBackoffState(),
|
|
9280
9592
|
spawnError: null,
|
|
9281
9593
|
exitCode: null,
|
|
9282
9594
|
exitSignal: null,
|
|
@@ -9379,6 +9691,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9379
9691
|
const ap = this.agents.get(agentId);
|
|
9380
9692
|
if (ap.runtime !== runtime) return;
|
|
9381
9693
|
ap.notifications.clearTimer();
|
|
9694
|
+
this.clearRuntimeErrorDeliveryBackoff(ap);
|
|
9382
9695
|
if (ap.pendingTrajectory?.timer) {
|
|
9383
9696
|
clearTimeout(ap.pendingTrajectory.timer);
|
|
9384
9697
|
}
|
|
@@ -9496,6 +9809,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9496
9809
|
logger.warn(`[Agent ${agentId}] Recoverable provider stream failure (${reason}) \u2014 keeping agent wakeable`);
|
|
9497
9810
|
this.sendAgentStatus(agentId, "active", ap.launchId);
|
|
9498
9811
|
} else if (startupTimeoutTermination) {
|
|
9812
|
+
this.cacheStartupTimeoutRetryConfig(agentId, ap);
|
|
9499
9813
|
logger.warn(`[Agent ${agentId}] Startup timeout cleanup completed (${reason})`);
|
|
9500
9814
|
} else {
|
|
9501
9815
|
this.idleAgentConfigs.delete(agentId);
|
|
@@ -9566,6 +9880,23 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9566
9880
|
this.agents.delete(agentId);
|
|
9567
9881
|
this.idleAgentConfigs.delete(agentId);
|
|
9568
9882
|
}
|
|
9883
|
+
cacheStartupTimeoutRetryConfig(agentId, ap) {
|
|
9884
|
+
const retryConfig = {
|
|
9885
|
+
...stripManagedRunnerCredential(ap.config),
|
|
9886
|
+
sessionId: ap.sessionId
|
|
9887
|
+
};
|
|
9888
|
+
this.idleAgentConfigs.set(agentId, {
|
|
9889
|
+
config: retryConfig,
|
|
9890
|
+
sessionId: ap.sessionId,
|
|
9891
|
+
launchId: ap.launchId
|
|
9892
|
+
});
|
|
9893
|
+
this.recordDaemonTrace("daemon.agent.startup_timeout.retry_config_cached", {
|
|
9894
|
+
agentId,
|
|
9895
|
+
launchId: ap.launchId || void 0,
|
|
9896
|
+
runtime: ap.config.runtime,
|
|
9897
|
+
session_id_present: Boolean(ap.sessionId)
|
|
9898
|
+
});
|
|
9899
|
+
}
|
|
9569
9900
|
async buildSpawnConfig(agentId, config) {
|
|
9570
9901
|
const baseConfig = config.serverUrl === this.serverUrl ? config : { ...config, serverUrl: this.serverUrl };
|
|
9571
9902
|
const runnerConfig = await this.ensureManagedRunnerCredential(agentId, baseConfig);
|
|
@@ -9793,6 +10124,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9793
10124
|
return;
|
|
9794
10125
|
}
|
|
9795
10126
|
ap.notifications.clearTimer();
|
|
10127
|
+
this.clearRuntimeErrorDeliveryBackoff(ap);
|
|
9796
10128
|
if (ap.activityHeartbeat) {
|
|
9797
10129
|
clearInterval(ap.activityHeartbeat);
|
|
9798
10130
|
}
|
|
@@ -9847,6 +10179,14 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9847
10179
|
this.deliveryTraceContexts.set(message, traceContext);
|
|
9848
10180
|
}
|
|
9849
10181
|
const transientDelivery = this.isTransientDelivery(message);
|
|
10182
|
+
if (!transientDelivery && this.isVisibleMessageModelSeen(agentId, formatMessageTarget(message), message)) {
|
|
10183
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
10184
|
+
outcome: "dropped_already_consumed",
|
|
10185
|
+
accepted: true,
|
|
10186
|
+
process_present: Boolean(this.agents.get(agentId))
|
|
10187
|
+
}));
|
|
10188
|
+
return true;
|
|
10189
|
+
}
|
|
9850
10190
|
const ap = this.agents.get(agentId);
|
|
9851
10191
|
if (!ap) {
|
|
9852
10192
|
if (this.agentsStarting.has(agentId) || this.queuedAgentStarts.has(agentId)) {
|
|
@@ -9990,6 +10330,9 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9990
10330
|
return true;
|
|
9991
10331
|
}
|
|
9992
10332
|
}
|
|
10333
|
+
if (!transientDelivery && this.queueDeliveryForRuntimeErrorBackoff(agentId, ap, message)) {
|
|
10334
|
+
return true;
|
|
10335
|
+
}
|
|
9993
10336
|
if (ap.isIdle && ap.driver.supportsStdinNotification && ap.sessionId) {
|
|
9994
10337
|
if (transientDelivery) {
|
|
9995
10338
|
this.commitApmIdleState(agentId, ap, false);
|
|
@@ -11042,6 +11385,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11042
11385
|
return written;
|
|
11043
11386
|
}
|
|
11044
11387
|
case "deliver_stdin": {
|
|
11388
|
+
const runtimeErrorBackoffRemainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
|
|
11389
|
+
if (runtimeErrorBackoffRemainingMs > 0) {
|
|
11390
|
+
const scheduled = this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
|
|
11391
|
+
this.recordApmGatedSteeringEffectTrace(agentId, ap, effect, {
|
|
11392
|
+
outcome: "suppressed_runtime_error_backoff",
|
|
11393
|
+
runtime_error_backoff_remaining_ms: runtimeErrorBackoffRemainingMs,
|
|
11394
|
+
runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
|
|
11395
|
+
runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
|
|
11396
|
+
runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null,
|
|
11397
|
+
delivered_messages_count: 0
|
|
11398
|
+
});
|
|
11399
|
+
return false;
|
|
11400
|
+
}
|
|
11045
11401
|
const messages = [...ap.inbox];
|
|
11046
11402
|
ap.notifications.clear();
|
|
11047
11403
|
if (messages.length === 0) {
|
|
@@ -11151,7 +11507,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11151
11507
|
logger.warn(`[Agent ${agentId}] ${ap.driver.id} did not emit a startup runtime event within ${timeoutMs}ms; terminating process`);
|
|
11152
11508
|
this.broadcastActivity(agentId, "error", detail, [{ kind: "text", text: `Error: ${detail}` }], ap.launchId);
|
|
11153
11509
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
11154
|
-
this.
|
|
11510
|
+
this.cacheStartupTimeoutRetryConfig(agentId, ap);
|
|
11155
11511
|
try {
|
|
11156
11512
|
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
11157
11513
|
stop_source: "startup_timeout",
|
|
@@ -11282,6 +11638,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11282
11638
|
}
|
|
11283
11639
|
if (event.kind === "internal_progress") {
|
|
11284
11640
|
ap.runtimeProgress.noteInternalProgress();
|
|
11641
|
+
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
11285
11642
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.internal_observed", {
|
|
11286
11643
|
turn_outcome: "held",
|
|
11287
11644
|
turn_subtype: "runtime_progress",
|
|
@@ -11306,6 +11663,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11306
11663
|
this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
|
|
11307
11664
|
this.queueTrajectoryText(agentId, "thinking", event.text);
|
|
11308
11665
|
if (ap) {
|
|
11666
|
+
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
11309
11667
|
const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
|
|
11310
11668
|
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "thinking" });
|
|
11311
11669
|
}
|
|
@@ -11315,6 +11673,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11315
11673
|
this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
|
|
11316
11674
|
this.queueTrajectoryText(agentId, "text", event.text);
|
|
11317
11675
|
if (ap) {
|
|
11676
|
+
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
11318
11677
|
const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
|
|
11319
11678
|
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "text" });
|
|
11320
11679
|
}
|
|
@@ -11325,6 +11684,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11325
11684
|
this.flushPendingTrajectory(agentId);
|
|
11326
11685
|
const invocation = normalizeToolDisplayInvocation(event.name, event.input);
|
|
11327
11686
|
if (ap) {
|
|
11687
|
+
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
11328
11688
|
const reduction = reduceApmGatedToolUse(ap.gatedSteering, { kind: "tool_call" });
|
|
11329
11689
|
this.recordRuntimeTraceEvent(agentId, ap, "tool.call.started", { tool: invocation.toolName });
|
|
11330
11690
|
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, {
|
|
@@ -11344,6 +11704,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11344
11704
|
case "tool_output": {
|
|
11345
11705
|
const invocation = normalizeToolDisplayInvocation(event.name, {});
|
|
11346
11706
|
if (ap) {
|
|
11707
|
+
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
11347
11708
|
const reduction = reduceApmGatedToolUse(ap.gatedSteering, { kind: "tool_output" });
|
|
11348
11709
|
this.recordRuntimeTraceEvent(agentId, ap, "tool.output.observed", { tool: invocation.toolName });
|
|
11349
11710
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.continuation.expected");
|
|
@@ -11403,6 +11764,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11403
11764
|
this.commitApmIdleState(agentId, ap, true);
|
|
11404
11765
|
if (stickyTerminalFailure) {
|
|
11405
11766
|
this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
|
|
11767
|
+
} else if (ap.lastRuntimeError && ap.runtimeErrorDeliveryBackoff.attempts > 0) {
|
|
11768
|
+
this.broadcastActivity(agentId, "error", ap.lastRuntimeError);
|
|
11406
11769
|
} else {
|
|
11407
11770
|
this.broadcastActivity(agentId, "online", "Idle");
|
|
11408
11771
|
}
|
|
@@ -11452,12 +11815,19 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11452
11815
|
visibleErrorMessage = formatRuntimeLoginRequiredMessage(ap.driver.id);
|
|
11453
11816
|
}
|
|
11454
11817
|
const shouldDisableToolBoundaryFlush = ap.runtime.descriptor.busyDelivery === "gated" && this.isThinkingBlockMutationError(event.message);
|
|
11455
|
-
const
|
|
11818
|
+
const backoffFailPoint = this.runtimeErrorDeliveryBackoffFailPointForTesting?.({
|
|
11819
|
+
agentId,
|
|
11820
|
+
message: event.message
|
|
11821
|
+
}) ?? null;
|
|
11822
|
+
const terminalFailure = backoffFailPoint && Object.prototype.hasOwnProperty.call(backoffFailPoint, "terminalFailure") ? backoffFailPoint.terminalFailure ?? null : classifyTerminalFailure(ap);
|
|
11823
|
+
const stickyTerminalFailure = backoffFailPoint && Object.prototype.hasOwnProperty.call(backoffFailPoint, "stickyTerminalFailure") ? backoffFailPoint.stickyTerminalFailure ?? null : classifyStickyTerminalFailure(ap);
|
|
11824
|
+
const backoffReasonOverride = backoffFailPoint && Object.prototype.hasOwnProperty.call(backoffFailPoint, "reason") ? backoffFailPoint.reason ?? null : void 0;
|
|
11456
11825
|
const reduction = reduceApmGatedError(ap.gatedSteering, {
|
|
11457
11826
|
disableToolBoundaryFlush: shouldDisableToolBoundaryFlush,
|
|
11458
11827
|
terminalWakeable: Boolean(ap.driver.supportsStdinNotification && terminalFailure && !terminalFailure.actionRequired)
|
|
11459
11828
|
});
|
|
11460
11829
|
this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "error" });
|
|
11830
|
+
this.noteRuntimeErrorDeliveryBackoff(agentId, ap, event.message, terminalFailure, stickyTerminalFailure, backoffReasonOverride);
|
|
11461
11831
|
if (reduction.shouldDisableToolBoundaryFlush) {
|
|
11462
11832
|
this.recordGatedSteeringEvent(agentId, ap, "disabled", {
|
|
11463
11833
|
reason: "thinking_block_mutation_error",
|
|
@@ -11478,7 +11848,6 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11478
11848
|
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
|
|
11479
11849
|
});
|
|
11480
11850
|
if (ap.driver.supportsStdinNotification && terminalFailure) {
|
|
11481
|
-
const stickyTerminalFailure = classifyStickyTerminalFailure(ap);
|
|
11482
11851
|
if (terminalFailure.actionRequired) {
|
|
11483
11852
|
logger.warn(`[Agent ${agentId}] ${ap.driver.id} auth requires user action; terminating runtime process`);
|
|
11484
11853
|
try {
|
|
@@ -11496,7 +11865,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11496
11865
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
11497
11866
|
logger.warn(`[Agent ${agentId}] ${ap.driver.id} terminal runtime error requires explicit recovery`);
|
|
11498
11867
|
} else {
|
|
11499
|
-
ap.notifications.
|
|
11868
|
+
ap.notifications.clearPending();
|
|
11869
|
+
ap.notifications.clearTimer();
|
|
11500
11870
|
logger.info(`[Agent ${agentId}] Marked ${ap.driver.id} wakeable after terminal runtime error`);
|
|
11501
11871
|
}
|
|
11502
11872
|
}
|
|
@@ -11607,6 +11977,27 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11607
11977
|
if (count === 0) return false;
|
|
11608
11978
|
if (ap.isIdle) return false;
|
|
11609
11979
|
if (!ap.sessionId) return false;
|
|
11980
|
+
const runtimeErrorBackoffRemainingMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
|
|
11981
|
+
if (runtimeErrorBackoffRemainingMs > 0) {
|
|
11982
|
+
ap.notifications.add(count);
|
|
11983
|
+
const scheduled = this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
|
|
11984
|
+
this.recordDaemonTrace("daemon.agent.stdin_notification", {
|
|
11985
|
+
agentId,
|
|
11986
|
+
runtime: ap.config.runtime,
|
|
11987
|
+
model: ap.config.model,
|
|
11988
|
+
launchId: ap.launchId || void 0,
|
|
11989
|
+
outcome: "suppressed_runtime_error_backoff",
|
|
11990
|
+
mode: "busy",
|
|
11991
|
+
pending_notification_count: count,
|
|
11992
|
+
inbox_count: ap.inbox.length,
|
|
11993
|
+
session_id_present: true,
|
|
11994
|
+
runtime_error_backoff_remaining_ms: runtimeErrorBackoffRemainingMs,
|
|
11995
|
+
runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
|
|
11996
|
+
runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
|
|
11997
|
+
runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null
|
|
11998
|
+
});
|
|
11999
|
+
return false;
|
|
12000
|
+
}
|
|
11610
12001
|
if (ap.gatedSteering.compacting) {
|
|
11611
12002
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.compaction_boundary.delivery_suppressed", {
|
|
11612
12003
|
pendingNotificationCount: count,
|
|
@@ -11622,6 +12013,22 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11622
12013
|
const inboxCount = ap.inbox.length;
|
|
11623
12014
|
if (inboxCount === 0) return false;
|
|
11624
12015
|
const changedMessages = ap.inbox.slice(Math.max(0, ap.inbox.length - count));
|
|
12016
|
+
const noticeFingerprint = computeInboxNoticeFingerprint(changedMessages);
|
|
12017
|
+
if (ap.notifications.isDuplicateNotice(noticeFingerprint, ap.sessionId)) {
|
|
12018
|
+
this.recordDaemonTrace("daemon.agent.stdin_notification", {
|
|
12019
|
+
agentId,
|
|
12020
|
+
runtime: ap.config.runtime,
|
|
12021
|
+
model: ap.config.model,
|
|
12022
|
+
launchId: ap.launchId || void 0,
|
|
12023
|
+
outcome: "suppressed_duplicate",
|
|
12024
|
+
mode: "busy",
|
|
12025
|
+
pending_notification_count: count,
|
|
12026
|
+
inbox_count: ap.inbox.length,
|
|
12027
|
+
session_id_present: true
|
|
12028
|
+
});
|
|
12029
|
+
logger.info(`[Agent ${agentId}] Suppressing duplicate stdin inbox notice (unread-set unchanged since last write); pending=${ap.inbox.length}`);
|
|
12030
|
+
return false;
|
|
12031
|
+
}
|
|
11625
12032
|
const inboxRows = projectAgentInboxSnapshot(changedMessages);
|
|
11626
12033
|
const notification = `[Slock inbox notice:
|
|
11627
12034
|
${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
@@ -11659,6 +12066,7 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
|
|
|
11659
12066
|
inbox_target_count: inboxRows.length,
|
|
11660
12067
|
session_id_present: true
|
|
11661
12068
|
});
|
|
12069
|
+
ap.notifications.recordNoticeWritten(noticeFingerprint, ap.sessionId);
|
|
11662
12070
|
return true;
|
|
11663
12071
|
} else {
|
|
11664
12072
|
ap.notifications.add(count);
|
|
@@ -11955,6 +12363,8 @@ var DaemonConnection = class {
|
|
|
11955
12363
|
lastDroppedSendLogAt = 0;
|
|
11956
12364
|
lastInboundAt = null;
|
|
11957
12365
|
lastInboundMessageKind = null;
|
|
12366
|
+
pendingActivityByAgent = /* @__PURE__ */ new Map();
|
|
12367
|
+
latestObservedLaunchIdByAgent = /* @__PURE__ */ new Map();
|
|
11958
12368
|
constructor(options) {
|
|
11959
12369
|
this.options = options;
|
|
11960
12370
|
this.clock = options.clock ?? systemClock;
|
|
@@ -11968,6 +12378,7 @@ var DaemonConnection = class {
|
|
|
11968
12378
|
}
|
|
11969
12379
|
disconnect() {
|
|
11970
12380
|
this.shouldConnect = false;
|
|
12381
|
+
this.pendingActivityByAgent.clear();
|
|
11971
12382
|
this.clearWatchdog();
|
|
11972
12383
|
if (this.reconnectTimer) {
|
|
11973
12384
|
this.clock.clearTimeout(this.reconnectTimer);
|
|
@@ -11981,9 +12392,15 @@ var DaemonConnection = class {
|
|
|
11981
12392
|
}
|
|
11982
12393
|
send(msg) {
|
|
11983
12394
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
12395
|
+
this.observeLaunchIdentity(msg);
|
|
12396
|
+
if (msg.type === "agent:activity") {
|
|
12397
|
+
this.pendingActivityByAgent.delete(msg.agentId);
|
|
12398
|
+
}
|
|
11984
12399
|
this.ws.send(JSON.stringify(msg));
|
|
11985
12400
|
return;
|
|
11986
12401
|
}
|
|
12402
|
+
this.observeLaunchIdentity(msg);
|
|
12403
|
+
this.queueReplayableMessage(msg);
|
|
11987
12404
|
const now = this.clock.now();
|
|
11988
12405
|
if (now - this.lastDroppedSendLogAt > 5e3) {
|
|
11989
12406
|
this.lastDroppedSendLogAt = now;
|
|
@@ -12026,6 +12443,7 @@ var DaemonConnection = class {
|
|
|
12026
12443
|
reconnect_attempt: priorReconnectAttempt,
|
|
12027
12444
|
inbound_watchdog_ms: this.options.inboundWatchdogMs ?? INBOUND_WATCHDOG_MS
|
|
12028
12445
|
});
|
|
12446
|
+
this.flushPendingActivity(ws);
|
|
12029
12447
|
this.options.onConnect();
|
|
12030
12448
|
});
|
|
12031
12449
|
ws.on("message", (data) => {
|
|
@@ -12123,6 +12541,65 @@ var DaemonConnection = class {
|
|
|
12123
12541
|
this.lastInboundAt = this.clock.now();
|
|
12124
12542
|
this.lastInboundMessageKind = messageKind;
|
|
12125
12543
|
}
|
|
12544
|
+
queueReplayableMessage(msg) {
|
|
12545
|
+
if (msg.type !== "agent:activity") return;
|
|
12546
|
+
const latestLaunchId = this.latestObservedLaunchIdByAgent.get(msg.agentId);
|
|
12547
|
+
if (msg.launchId && latestLaunchId && msg.launchId !== latestLaunchId) {
|
|
12548
|
+
this.trace("daemon.connection.pending_activity_invalidated", {
|
|
12549
|
+
reason: "launch_changed",
|
|
12550
|
+
message_type: msg.type,
|
|
12551
|
+
agentId: msg.agentId,
|
|
12552
|
+
stale_launch_id_present: true,
|
|
12553
|
+
next_launch_id_present: true
|
|
12554
|
+
});
|
|
12555
|
+
return;
|
|
12556
|
+
}
|
|
12557
|
+
this.pendingActivityByAgent.set(msg.agentId, msg);
|
|
12558
|
+
}
|
|
12559
|
+
observeLaunchIdentity(msg) {
|
|
12560
|
+
const identity = this.agentLaunchIdentity(msg);
|
|
12561
|
+
if (!identity?.launchId) return;
|
|
12562
|
+
if (msg.type !== "agent:activity") {
|
|
12563
|
+
this.latestObservedLaunchIdByAgent.set(identity.agentId, identity.launchId);
|
|
12564
|
+
}
|
|
12565
|
+
const pending = this.pendingActivityByAgent.get(identity.agentId);
|
|
12566
|
+
if (!pending || pending.launchId === identity.launchId) return;
|
|
12567
|
+
this.pendingActivityByAgent.delete(identity.agentId);
|
|
12568
|
+
this.trace("daemon.connection.pending_activity_invalidated", {
|
|
12569
|
+
reason: "launch_changed",
|
|
12570
|
+
message_type: msg.type,
|
|
12571
|
+
agentId: identity.agentId,
|
|
12572
|
+
stale_launch_id_present: Boolean(pending.launchId),
|
|
12573
|
+
next_launch_id_present: true
|
|
12574
|
+
});
|
|
12575
|
+
}
|
|
12576
|
+
agentLaunchIdentity(msg) {
|
|
12577
|
+
switch (msg.type) {
|
|
12578
|
+
case "agent:activity":
|
|
12579
|
+
case "agent:status":
|
|
12580
|
+
case "agent:session":
|
|
12581
|
+
case "agent:runtime_profile":
|
|
12582
|
+
case "agent:runtime_profile:migration:ack":
|
|
12583
|
+
case "agent:runtime_profile:migration_done":
|
|
12584
|
+
case "agent:runtime_profile:daemon_release_notice:ack":
|
|
12585
|
+
return { agentId: msg.agentId, launchId: msg.launchId };
|
|
12586
|
+
default:
|
|
12587
|
+
return null;
|
|
12588
|
+
}
|
|
12589
|
+
}
|
|
12590
|
+
flushPendingActivity(ws) {
|
|
12591
|
+
if (this.pendingActivityByAgent.size === 0) return;
|
|
12592
|
+
if (this.ws !== ws || ws.readyState !== WebSocket.OPEN) return;
|
|
12593
|
+
const pending = [...this.pendingActivityByAgent.values()];
|
|
12594
|
+
this.pendingActivityByAgent.clear();
|
|
12595
|
+
for (const msg of pending) {
|
|
12596
|
+
ws.send(JSON.stringify(msg));
|
|
12597
|
+
}
|
|
12598
|
+
this.trace("daemon.connection.outbound_replayed", {
|
|
12599
|
+
message_type: "agent:activity",
|
|
12600
|
+
message_count: pending.length
|
|
12601
|
+
});
|
|
12602
|
+
}
|
|
12126
12603
|
lastInboundAgeBucket() {
|
|
12127
12604
|
return durationMsBucket(this.lastInboundAt == null ? null : this.clock.now() - this.lastInboundAt);
|
|
12128
12605
|
}
|
|
@@ -12945,7 +13422,7 @@ var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
|
|
|
12945
13422
|
var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
|
|
12946
13423
|
var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS2 = 3;
|
|
12947
13424
|
var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2 = 250;
|
|
12948
|
-
var DAEMON_CLI_USAGE =
|
|
13425
|
+
var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
|
|
12949
13426
|
var RunnerCredentialMintError2 = class extends Error {
|
|
12950
13427
|
code;
|
|
12951
13428
|
retryable;
|
|
@@ -12981,9 +13458,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
12981
13458
|
async function waitForRunnerCredentialRetry2() {
|
|
12982
13459
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
12983
13460
|
}
|
|
12984
|
-
function parseDaemonCliArgs(args
|
|
13461
|
+
function parseDaemonCliArgs(args) {
|
|
12985
13462
|
let serverUrl = "";
|
|
12986
|
-
let apiKey =
|
|
13463
|
+
let apiKey = "";
|
|
12987
13464
|
for (let i = 0; i < args.length; i++) {
|
|
12988
13465
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
12989
13466
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -13752,8 +14229,6 @@ var DaemonCore = class {
|
|
|
13752
14229
|
};
|
|
13753
14230
|
|
|
13754
14231
|
export {
|
|
13755
|
-
DAEMON_API_KEY_ENV,
|
|
13756
|
-
scrubDaemonAuthEnv,
|
|
13757
14232
|
subscribeDaemonLogs,
|
|
13758
14233
|
resolveWorkspaceDirectoryPath,
|
|
13759
14234
|
scanWorkspaceDirectories,
|