@opengeni/db 3.6.0 → 3.7.4-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automations.d.ts +4 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/{chunk-UGDVSQ6U.js → chunk-3ZMN4EXC.js} +2 -2
- package/dist/{chunk-744DFC65.js → chunk-6FIVOJ3V.js} +96 -6
- package/dist/chunk-6FIVOJ3V.js.map +1 -0
- package/dist/{chunk-UJ2EW3QI.js → chunk-DXJ2WY6W.js} +427 -85
- package/dist/chunk-DXJ2WY6W.js.map +1 -0
- package/dist/{chunk-CDMMSUWJ.js → chunk-JP6IYGYI.js} +3 -3
- package/dist/{chunk-Q5YUGQVK.js → chunk-JS3AWDKZ.js} +3 -3
- package/dist/{chunk-G3732M3T.js → chunk-LHKB62GC.js} +2 -2
- package/dist/{chunk-2NT476HD.js → chunk-QL4AHBYD.js} +2 -2
- package/dist/{chunk-IW6O6G7R.js → chunk-VDXHLVDE.js} +2 -2
- package/dist/{chunk-WW7AJ5IC.js → chunk-ZTSJPFDH.js} +5 -7
- package/dist/chunk-ZTSJPFDH.js.map +1 -0
- package/dist/codex-token-resolver.d.ts +12 -1
- package/dist/company-profile-agent-admin.d.ts +4 -2
- package/dist/company-profile-agent-policy.d.ts +20 -0
- package/dist/company-profile-schema.d.ts +573 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +487 -20
- package/dist/index.js +9489 -6041
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/managed-human-provisioning.d.ts +3 -3
- package/dist/memory-domain.d.ts +5 -3
- package/dist/model-catalog.d.ts +153 -0
- package/dist/pr-review.d.ts +9 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +7 -7
- package/dist/schema.d.ts +1069 -6
- package/dist/schema.js +17 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-control.d.ts +75 -5
- package/dist/session-queue-commands.d.ts +19 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/user-resource-authority.d.ts +8 -0
- package/dist/video-generation.js +3 -3
- package/dist/xai-subscription.d.ts +8 -0
- package/drizzle/0369_local_human_personal_authority.sql +350 -0
- package/drizzle/0370_workspace_member_management_scope.sql +98 -0
- package/drizzle/0371_workspace_member_candidate_inventory.sql +128 -0
- package/drizzle/0372_ordered_variable_set_runtime_authority.sql +287 -0
- package/drizzle/0373_sandbox_shared_preparation.sql +59 -0
- package/drizzle/0374_session_event_cursors.sql +315 -0
- package/drizzle/0375_session_recovery_observability.sql +73 -0
- package/drizzle/0376_organization_workspace_inventory.sql +88 -0
- package/drizzle/0377_scoped_rig_health_projection.sql +80 -0
- package/drizzle/0378_scoped_rig_health_audit_timestamp.sql +77 -0
- package/drizzle/0379_session_event_raw_lane_activation.sql +518 -0
- package/drizzle/0380_autonomous_company_profile_agent_policy.sql +829 -0
- package/drizzle/0381_organization_codex_subscription_inheritance.sql +720 -0
- package/drizzle/0382_organization_api_key_provenance.sql +91 -0
- package/drizzle/0383_codex_cooldown_reconciliation.sql +51 -0
- package/drizzle/0384_codex_cooldown_revision_guard_privileges.sql +6 -0
- package/drizzle/0385_connected_machine_legacy_tilde_workdirs.sql +25 -0
- package/drizzle/0386_local_organization_administration.sql +157 -0
- package/drizzle/0387_bound_host_export_session_payloads.sql +165 -0
- package/drizzle/0388_sandbox_provider_deadline_interactions.sql +491 -0
- package/drizzle/0389_model_catalog_and_gateway_custom_models.sql +241 -0
- package/package.json +6 -6
- package/src/automations.ts +9 -1
- package/src/codex-token-resolver.ts +26 -1
- package/src/company-brain-governed-writes.ts +30 -1
- package/src/company-profile-agent-admin.ts +68 -1
- package/src/company-profile-agent-policy.ts +126 -0
- package/src/company-profile-schema.ts +115 -1
- package/src/database.ts +3 -5
- package/src/index.ts +4473 -570
- package/src/insights.ts +21 -7
- package/src/managed-human-provisioning.ts +3 -3
- package/src/memory-domain.ts +9 -4
- package/src/model-catalog.ts +682 -0
- package/src/organization-membership-lifecycle.ts +0 -1
- package/src/pr-review.ts +19 -0
- package/src/provision-roles.ts +83 -4
- package/src/runtime-posture.ts +26 -0
- package/src/schema.ts +259 -10
- package/src/session-control.ts +347 -59
- package/src/session-queue-commands.ts +303 -122
- package/src/session-tool-call-settlement.ts +34 -7
- package/src/user-resource-authority.ts +56 -0
- package/src/xai-subscription.ts +66 -14
- package/dist/chunk-744DFC65.js.map +0 -1
- package/dist/chunk-UJ2EW3QI.js.map +0 -1
- package/dist/chunk-WW7AJ5IC.js.map +0 -1
- /package/dist/{chunk-UGDVSQ6U.js.map → chunk-3ZMN4EXC.js.map} +0 -0
- /package/dist/{chunk-CDMMSUWJ.js.map → chunk-JP6IYGYI.js.map} +0 -0
- /package/dist/{chunk-Q5YUGQVK.js.map → chunk-JS3AWDKZ.js.map} +0 -0
- /package/dist/{chunk-G3732M3T.js.map → chunk-LHKB62GC.js.map} +0 -0
- /package/dist/{chunk-2NT476HD.js.map → chunk-QL4AHBYD.js.map} +0 -0
- /package/dist/{chunk-IW6O6G7R.js.map → chunk-VDXHLVDE.js.map} +0 -0
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
type TimelineAnnotation,
|
|
30
30
|
type PersonalResourceAttachmentIntent,
|
|
31
31
|
} from "@opengeni/contracts";
|
|
32
|
-
import { and, asc, eq, inArray, sql } from "drizzle-orm";
|
|
32
|
+
import { and, asc, desc, eq, inArray, sql } from "drizzle-orm";
|
|
33
33
|
import { setSubjectRlsContext, type Database, type SessionActivityDatabase } from "./database";
|
|
34
34
|
import {
|
|
35
35
|
fromPostgresLosslessJson,
|
|
@@ -44,10 +44,13 @@ import {
|
|
|
44
44
|
canonicalSessionCommandHash,
|
|
45
45
|
evaluateSessionControl,
|
|
46
46
|
lockSessionEventWriteRows,
|
|
47
|
+
lockSessionPromptCommandOperation,
|
|
47
48
|
lockWorkspaceInferenceControl,
|
|
48
49
|
lockWorkspaceInferenceControlForAdmission,
|
|
50
|
+
getCompletedSessionPromptCommandReceipt,
|
|
49
51
|
registerInternalUpdateWakeInTransaction,
|
|
50
52
|
reserveSessionCommandReceipt,
|
|
53
|
+
reserveSessionPromptCommandReceipt,
|
|
51
54
|
registerSessionWorkflowWakeInTransaction,
|
|
52
55
|
type SessionCommandActor,
|
|
53
56
|
type SessionCommandReceiptRow,
|
|
@@ -210,6 +213,122 @@ function mapSubmittedPromptTurn(row: typeof schema.sessionTurns.$inferSelect): S
|
|
|
210
213
|
};
|
|
211
214
|
}
|
|
212
215
|
|
|
216
|
+
async function loadSubmittedHumanPromptReplay(
|
|
217
|
+
db: Database,
|
|
218
|
+
input: {
|
|
219
|
+
workspaceId: string;
|
|
220
|
+
sessionId: string;
|
|
221
|
+
subjectId: string;
|
|
222
|
+
delivery: "send" | "steer";
|
|
223
|
+
expectedDraftRevision?: number | null;
|
|
224
|
+
receipt: SessionCommandReceiptRow;
|
|
225
|
+
},
|
|
226
|
+
): Promise<SubmitHumanPromptResult> {
|
|
227
|
+
const turnId = String(input.receipt.result.turnId ?? "");
|
|
228
|
+
const acceptedEventId = String(input.receipt.result.acceptedEventId ?? "");
|
|
229
|
+
const eventIds = Array.isArray(input.receipt.result.eventIds)
|
|
230
|
+
? input.receipt.result.eventIds.filter((id): id is string => typeof id === "string")
|
|
231
|
+
: [];
|
|
232
|
+
const wakeRevision = Number(input.receipt.result.wakeRevision ?? 0);
|
|
233
|
+
if (!turnId || !acceptedEventId || wakeRevision < 1) {
|
|
234
|
+
throw new SessionControlInvariantError("Replayed prompt receipt is incomplete");
|
|
235
|
+
}
|
|
236
|
+
const replayEvents = await db
|
|
237
|
+
.select()
|
|
238
|
+
.from(schema.sessionEvents)
|
|
239
|
+
.where(
|
|
240
|
+
and(
|
|
241
|
+
eq(schema.sessionEvents.workspaceId, input.workspaceId),
|
|
242
|
+
eq(schema.sessionEvents.sessionId, input.sessionId),
|
|
243
|
+
inArray(schema.sessionEvents.id, eventIds),
|
|
244
|
+
),
|
|
245
|
+
)
|
|
246
|
+
.orderBy(asc(schema.sessionEvents.sequence));
|
|
247
|
+
const [replayTurn] = await db
|
|
248
|
+
.select()
|
|
249
|
+
.from(schema.sessionTurns)
|
|
250
|
+
.where(
|
|
251
|
+
and(
|
|
252
|
+
eq(schema.sessionTurns.workspaceId, input.workspaceId),
|
|
253
|
+
eq(schema.sessionTurns.sessionId, input.sessionId),
|
|
254
|
+
eq(schema.sessionTurns.id, turnId),
|
|
255
|
+
),
|
|
256
|
+
)
|
|
257
|
+
.limit(1);
|
|
258
|
+
const events = replayEvents.map(mapSubmittedPromptEvent);
|
|
259
|
+
const accepted = events.find((event) => event.id === acceptedEventId);
|
|
260
|
+
if (!accepted || !replayTurn || events.length !== eventIds.length) {
|
|
261
|
+
throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
|
|
262
|
+
}
|
|
263
|
+
const replayDraft =
|
|
264
|
+
input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
|
|
265
|
+
? null
|
|
266
|
+
: await getComposerDraftInTransaction(db, {
|
|
267
|
+
workspaceId: input.workspaceId,
|
|
268
|
+
sessionId: input.sessionId,
|
|
269
|
+
subjectId: input.subjectId,
|
|
270
|
+
});
|
|
271
|
+
return {
|
|
272
|
+
receipt: input.receipt,
|
|
273
|
+
routing:
|
|
274
|
+
input.receipt.result.routing === "accepted_for_execution" ||
|
|
275
|
+
input.receipt.result.routing === "queued_for_execution" ||
|
|
276
|
+
input.receipt.result.routing === "accepted_for_steering"
|
|
277
|
+
? input.receipt.result.routing
|
|
278
|
+
: input.delivery === "steer"
|
|
279
|
+
? "accepted_for_steering"
|
|
280
|
+
: // Pre-routing receipts cannot reconstruct admission-time activity
|
|
281
|
+
// or Pause truth. Queue is the only conservative placement; a
|
|
282
|
+
// later turn.started event moves it into chat without duplication.
|
|
283
|
+
"queued_for_execution",
|
|
284
|
+
queueVersion: Number(input.receipt.appliedQueueVersion),
|
|
285
|
+
accepted,
|
|
286
|
+
events,
|
|
287
|
+
turn: mapSubmittedPromptTurn(replayTurn),
|
|
288
|
+
draft: replayDraft,
|
|
289
|
+
acceptedEventId,
|
|
290
|
+
eventIds,
|
|
291
|
+
turnId,
|
|
292
|
+
wakeRevision,
|
|
293
|
+
interruptionCount: Number(input.receipt.result.interruptionCount ?? 0),
|
|
294
|
+
workspaceControlEventId:
|
|
295
|
+
typeof input.receipt.result.workspaceControlEventId === "string"
|
|
296
|
+
? input.receipt.result.workspaceControlEventId
|
|
297
|
+
: null,
|
|
298
|
+
replay: true,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export async function replaySubmittedHumanPromptFromBoundaryReceipt(
|
|
303
|
+
db: Database,
|
|
304
|
+
input: {
|
|
305
|
+
workspaceId: string;
|
|
306
|
+
sessionId: string;
|
|
307
|
+
subjectId: string;
|
|
308
|
+
actor: SessionCommandActor;
|
|
309
|
+
operationKey: string;
|
|
310
|
+
delivery: "send" | "steer";
|
|
311
|
+
boundaryRequestHash: string;
|
|
312
|
+
expectedDraftRevision?: number | null;
|
|
313
|
+
/** Wait for an overlapping same-key transaction before checking committed replay truth. */
|
|
314
|
+
serializeOperation?: boolean;
|
|
315
|
+
},
|
|
316
|
+
): Promise<SubmitHumanPromptResult | null> {
|
|
317
|
+
if (input.serializeOperation) {
|
|
318
|
+
await lockSessionPromptCommandOperation(db, input);
|
|
319
|
+
}
|
|
320
|
+
const receipt = await getCompletedSessionPromptCommandReceipt(db, {
|
|
321
|
+
workspaceId: input.workspaceId,
|
|
322
|
+
actor: input.actor,
|
|
323
|
+
action: input.delivery === "steer" ? "prompt.steer" : "prompt.send",
|
|
324
|
+
targetSessionId: input.sessionId,
|
|
325
|
+
operationKey: input.operationKey,
|
|
326
|
+
boundaryRequestHash: input.boundaryRequestHash,
|
|
327
|
+
});
|
|
328
|
+
if (!receipt) return null;
|
|
329
|
+
return await loadSubmittedHumanPromptReplay(db, { ...input, receipt });
|
|
330
|
+
}
|
|
331
|
+
|
|
213
332
|
export type AgentInternalUpdateCommandResult = {
|
|
214
333
|
receipt: SessionCommandReceiptRow;
|
|
215
334
|
updateId: string;
|
|
@@ -345,11 +464,55 @@ async function lockSession(
|
|
|
345
464
|
|
|
346
465
|
type SteerSupersessionResult = {
|
|
347
466
|
interruptionCount: number;
|
|
467
|
+
steerTargetTurn: typeof schema.sessionTurns.$inferSelect | null;
|
|
348
468
|
replacedTurn: typeof schema.sessionTurns.$inferSelect | null;
|
|
349
469
|
liveCurrentTurnId: string | null;
|
|
470
|
+
deferredUntilCompaction: boolean;
|
|
350
471
|
lastSequence: number;
|
|
351
472
|
};
|
|
352
473
|
|
|
474
|
+
async function turnAttemptIsCompacting(
|
|
475
|
+
db: Database,
|
|
476
|
+
input: {
|
|
477
|
+
workspaceId: string;
|
|
478
|
+
sessionId: string;
|
|
479
|
+
turn: typeof schema.sessionTurns.$inferSelect;
|
|
480
|
+
},
|
|
481
|
+
): Promise<boolean> {
|
|
482
|
+
// A standalone operator compaction is maintenance rather than replaceable
|
|
483
|
+
// direction. Once claimed, let it finish even before its provider-visible
|
|
484
|
+
// started landmark is appended.
|
|
485
|
+
if (input.turn.source === "compaction") return true;
|
|
486
|
+
if (!input.turn.activeAttemptId) return false;
|
|
487
|
+
|
|
488
|
+
// Automatic/proactive/overflow compaction happens inside an ordinary turn.
|
|
489
|
+
// The latest exact-attempt landmark is durable state: `started` means the
|
|
490
|
+
// checkpoint provider call is still in flight, while compacted/skipped opens
|
|
491
|
+
// ordinary Steer interruption again. Multiple compactions in one attempt are
|
|
492
|
+
// therefore handled by the newest lifecycle event rather than a historical
|
|
493
|
+
// existence test.
|
|
494
|
+
const [latest] = await db
|
|
495
|
+
.select({ type: schema.sessionEvents.type })
|
|
496
|
+
.from(schema.sessionEvents)
|
|
497
|
+
.where(
|
|
498
|
+
and(
|
|
499
|
+
eq(schema.sessionEvents.workspaceId, input.workspaceId),
|
|
500
|
+
eq(schema.sessionEvents.sessionId, input.sessionId),
|
|
501
|
+
eq(schema.sessionEvents.turnId, input.turn.id),
|
|
502
|
+
eq(schema.sessionEvents.turnGeneration, input.turn.executionGeneration),
|
|
503
|
+
eq(schema.sessionEvents.turnAttemptId, input.turn.activeAttemptId),
|
|
504
|
+
inArray(schema.sessionEvents.type, [
|
|
505
|
+
"session.context.compaction.started",
|
|
506
|
+
"session.context.compacted",
|
|
507
|
+
"session.context.compaction.skipped",
|
|
508
|
+
]),
|
|
509
|
+
),
|
|
510
|
+
)
|
|
511
|
+
.orderBy(desc(schema.sessionEvents.sequence), desc(schema.sessionEvents.id))
|
|
512
|
+
.limit(1);
|
|
513
|
+
return latest?.type === "session.context.compaction.started";
|
|
514
|
+
}
|
|
515
|
+
|
|
353
516
|
/**
|
|
354
517
|
* One canonical replacement transition shared by human row/new-prompt Steer
|
|
355
518
|
* and Agent Steer. A live owner is interrupted and remains current until exact
|
|
@@ -371,8 +534,10 @@ export async function supersedeSessionCurrentDirectionInTransaction(
|
|
|
371
534
|
if (!input.activeTurnId) {
|
|
372
535
|
return {
|
|
373
536
|
interruptionCount: 0,
|
|
537
|
+
steerTargetTurn: null,
|
|
374
538
|
replacedTurn: null,
|
|
375
539
|
liveCurrentTurnId: null,
|
|
540
|
+
deferredUntilCompaction: false,
|
|
376
541
|
lastSequence: input.lastSequence,
|
|
377
542
|
};
|
|
378
543
|
}
|
|
@@ -391,6 +556,7 @@ export async function supersedeSessionCurrentDirectionInTransaction(
|
|
|
391
556
|
workspaceId: input.workspaceId,
|
|
392
557
|
controlLock: "already_locked",
|
|
393
558
|
workspaceLock: "already_locked",
|
|
559
|
+
sessionIds: [input.sessionId],
|
|
394
560
|
turnIds: [input.activeTurnId],
|
|
395
561
|
attemptIds: preview?.activeAttemptId ? [preview.activeAttemptId] : [],
|
|
396
562
|
});
|
|
@@ -410,6 +576,26 @@ export async function supersedeSessionCurrentDirectionInTransaction(
|
|
|
410
576
|
`Running turn ${current.id} has no first-class attempt owner`,
|
|
411
577
|
);
|
|
412
578
|
}
|
|
579
|
+
if (
|
|
580
|
+
current.activeAttemptId &&
|
|
581
|
+
(await turnAttemptIsCompacting(db, {
|
|
582
|
+
workspaceId: input.workspaceId,
|
|
583
|
+
sessionId: input.sessionId,
|
|
584
|
+
turn: current,
|
|
585
|
+
}))
|
|
586
|
+
) {
|
|
587
|
+
return {
|
|
588
|
+
interruptionCount: 0,
|
|
589
|
+
steerTargetTurn: current,
|
|
590
|
+
// An ordinary turn is superseded cooperatively as soon as its checkpoint
|
|
591
|
+
// settles. Standalone maintenance completes normally, then the Steer is
|
|
592
|
+
// already first in line.
|
|
593
|
+
replacedTurn: current.source === "compaction" ? null : current,
|
|
594
|
+
liveCurrentTurnId: current.id,
|
|
595
|
+
deferredUntilCompaction: true,
|
|
596
|
+
lastSequence: input.lastSequence,
|
|
597
|
+
};
|
|
598
|
+
}
|
|
413
599
|
if (current.activeAttemptId) {
|
|
414
600
|
if (current.status !== "running") {
|
|
415
601
|
throw new SessionControlInvariantError(
|
|
@@ -431,8 +617,10 @@ export async function supersedeSessionCurrentDirectionInTransaction(
|
|
|
431
617
|
.returning({ id: schema.sessionAttemptInterruptions.id });
|
|
432
618
|
return {
|
|
433
619
|
interruptionCount: interruption ? 1 : 0,
|
|
620
|
+
steerTargetTurn: current,
|
|
434
621
|
replacedTurn: current,
|
|
435
622
|
liveCurrentTurnId: current.id,
|
|
623
|
+
deferredUntilCompaction: false,
|
|
436
624
|
lastSequence: input.lastSequence,
|
|
437
625
|
};
|
|
438
626
|
}
|
|
@@ -571,8 +759,10 @@ export async function supersedeSessionCurrentDirectionInTransaction(
|
|
|
571
759
|
}
|
|
572
760
|
return {
|
|
573
761
|
interruptionCount: 0,
|
|
762
|
+
steerTargetTurn: current,
|
|
574
763
|
replacedTurn: current,
|
|
575
764
|
liveCurrentTurnId: null,
|
|
765
|
+
deferredUntilCompaction: false,
|
|
576
766
|
lastSequence,
|
|
577
767
|
};
|
|
578
768
|
}
|
|
@@ -1388,9 +1578,11 @@ export async function steerQueuedTurnInTransaction(
|
|
|
1388
1578
|
lastSequence: session.lastSequence,
|
|
1389
1579
|
});
|
|
1390
1580
|
const interruptionCount = supersession.interruptionCount;
|
|
1581
|
+
const steerTargetTurn = supersession.steerTargetTurn;
|
|
1391
1582
|
const supersededTurnId = supersession.replacedTurn?.id ?? null;
|
|
1392
1583
|
const supersededAttemptId = supersession.replacedTurn?.activeAttemptId ?? null;
|
|
1393
1584
|
const liveCurrentTurnId = supersession.liveCurrentTurnId;
|
|
1585
|
+
const deferredUntilCompaction = supersession.deferredUntilCompaction;
|
|
1394
1586
|
|
|
1395
1587
|
const withoutTarget = rows.filter((row) => row.id !== target.id);
|
|
1396
1588
|
const ordered = [target, ...withoutTarget];
|
|
@@ -1412,6 +1604,7 @@ export async function steerQueuedTurnInTransaction(
|
|
|
1412
1604
|
replacedTurnId: supersededTurnId,
|
|
1413
1605
|
replacedAttemptId: supersededAttemptId,
|
|
1414
1606
|
interruptionCount,
|
|
1607
|
+
...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
|
|
1415
1608
|
},
|
|
1416
1609
|
updatedAt: now,
|
|
1417
1610
|
})
|
|
@@ -1440,12 +1633,16 @@ export async function steerQueuedTurnInTransaction(
|
|
|
1440
1633
|
sessionId: input.sessionId,
|
|
1441
1634
|
sequence: ++sequence,
|
|
1442
1635
|
type: "session.control.steer_requested",
|
|
1443
|
-
turnId:
|
|
1636
|
+
turnId: steerTargetTurn?.id ?? target.id,
|
|
1637
|
+
turnGeneration: steerTargetTurn?.executionGeneration ?? null,
|
|
1638
|
+
turnAttemptId: steerTargetTurn?.activeAttemptId ?? null,
|
|
1639
|
+
turnAssociation: steerTargetTurn ? "current" : null,
|
|
1444
1640
|
payload: {
|
|
1445
1641
|
operationId: reserved.receipt.id,
|
|
1446
1642
|
targetTurnId: target.id,
|
|
1447
1643
|
replacedTurnId: supersededTurnId,
|
|
1448
|
-
stopping: liveCurrentTurnId !== null,
|
|
1644
|
+
stopping: liveCurrentTurnId !== null && !deferredUntilCompaction,
|
|
1645
|
+
...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
|
|
1449
1646
|
},
|
|
1450
1647
|
occurredAt: now,
|
|
1451
1648
|
});
|
|
@@ -1480,6 +1677,7 @@ export async function steerQueuedTurnInTransaction(
|
|
|
1480
1677
|
operationId: reserved.receipt.id,
|
|
1481
1678
|
replacedTurnId: supersededTurnId,
|
|
1482
1679
|
interruptionCount,
|
|
1680
|
+
deferredUntilCompaction,
|
|
1483
1681
|
},
|
|
1484
1682
|
},
|
|
1485
1683
|
"metadata",
|
|
@@ -1501,6 +1699,7 @@ export async function steerQueuedTurnInTransaction(
|
|
|
1501
1699
|
result: {
|
|
1502
1700
|
interruptionCount,
|
|
1503
1701
|
supersededTurnId,
|
|
1702
|
+
deferredUntilCompaction,
|
|
1504
1703
|
wakeRevision,
|
|
1505
1704
|
workspaceControlEventId: resumed.workspaceControlEventId,
|
|
1506
1705
|
},
|
|
@@ -1528,6 +1727,8 @@ export async function submitHumanPromptInTransaction(
|
|
|
1528
1727
|
subjectLabel?: string;
|
|
1529
1728
|
actor: SessionCommandActor;
|
|
1530
1729
|
operationKey: string;
|
|
1730
|
+
/** Stable parsed boundary-request identity used before mutable enrichment. */
|
|
1731
|
+
boundaryRequestHash?: string;
|
|
1531
1732
|
delivery: "send" | "steer";
|
|
1532
1733
|
controlEtag?: string | null;
|
|
1533
1734
|
expectedDraftRevision?: number | null;
|
|
@@ -1562,6 +1763,9 @@ export async function submitHumanPromptInTransaction(
|
|
|
1562
1763
|
id: string;
|
|
1563
1764
|
headersEncrypted: Record<string, string>;
|
|
1564
1765
|
}>;
|
|
1766
|
+
/** Trusted database-only admission seam. It runs only after a completed
|
|
1767
|
+
* operation replay has been ruled out; throwing rolls the prompt back. */
|
|
1768
|
+
beforeFreshPromptCommit?: (tx: Database) => Promise<void>;
|
|
1565
1769
|
/** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
|
|
1566
1770
|
controlLockTimeoutMs?: number;
|
|
1567
1771
|
},
|
|
@@ -1628,91 +1832,41 @@ export async function submitHumanPromptInTransaction(
|
|
|
1628
1832
|
}
|
|
1629
1833
|
: {}),
|
|
1630
1834
|
});
|
|
1631
|
-
const
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1835
|
+
const action = input.delivery === "steer" ? "prompt.steer" : "prompt.send";
|
|
1836
|
+
const reserved = input.boundaryRequestHash
|
|
1837
|
+
? await reserveSessionPromptCommandReceipt(db, {
|
|
1838
|
+
accountId: input.accountId,
|
|
1839
|
+
workspaceId: input.workspaceId,
|
|
1840
|
+
actor: input.actor,
|
|
1841
|
+
action,
|
|
1842
|
+
targetSessionId: input.sessionId,
|
|
1843
|
+
operationKey: input.operationKey,
|
|
1844
|
+
canonicalRequestHash: requestHash,
|
|
1845
|
+
boundaryRequestHash: input.boundaryRequestHash,
|
|
1846
|
+
})
|
|
1847
|
+
: await reserveSessionCommandReceipt(db, {
|
|
1848
|
+
accountId: input.accountId,
|
|
1849
|
+
workspaceId: input.workspaceId,
|
|
1850
|
+
actor: input.actor,
|
|
1851
|
+
action,
|
|
1852
|
+
targetSessionId: input.sessionId,
|
|
1853
|
+
targetTurnId: null,
|
|
1854
|
+
operationKey: input.operationKey,
|
|
1855
|
+
canonicalRequestHash: requestHash,
|
|
1856
|
+
});
|
|
1641
1857
|
if (reserved.replay && reserved.receipt.appliedQueueVersion !== null) {
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
:
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
}
|
|
1651
|
-
const replayEvents = await db
|
|
1652
|
-
.select()
|
|
1653
|
-
.from(schema.sessionEvents)
|
|
1654
|
-
.where(
|
|
1655
|
-
and(
|
|
1656
|
-
eq(schema.sessionEvents.workspaceId, input.workspaceId),
|
|
1657
|
-
eq(schema.sessionEvents.sessionId, input.sessionId),
|
|
1658
|
-
inArray(schema.sessionEvents.id, eventIds),
|
|
1659
|
-
),
|
|
1660
|
-
)
|
|
1661
|
-
.orderBy(asc(schema.sessionEvents.sequence));
|
|
1662
|
-
const [replayTurn] = await db
|
|
1663
|
-
.select()
|
|
1664
|
-
.from(schema.sessionTurns)
|
|
1665
|
-
.where(
|
|
1666
|
-
and(
|
|
1667
|
-
eq(schema.sessionTurns.workspaceId, input.workspaceId),
|
|
1668
|
-
eq(schema.sessionTurns.sessionId, input.sessionId),
|
|
1669
|
-
eq(schema.sessionTurns.id, turnId),
|
|
1670
|
-
),
|
|
1671
|
-
)
|
|
1672
|
-
.limit(1);
|
|
1673
|
-
const events = replayEvents.map(mapSubmittedPromptEvent);
|
|
1674
|
-
const accepted = events.find((event) => event.id === acceptedEventId);
|
|
1675
|
-
if (!accepted || !replayTurn || events.length !== eventIds.length) {
|
|
1676
|
-
throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
|
|
1677
|
-
}
|
|
1678
|
-
const replayDraft =
|
|
1679
|
-
input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
|
|
1680
|
-
? null
|
|
1681
|
-
: await getComposerDraftInTransaction(db, {
|
|
1682
|
-
workspaceId: input.workspaceId,
|
|
1683
|
-
sessionId: input.sessionId,
|
|
1684
|
-
subjectId: input.subjectId,
|
|
1685
|
-
});
|
|
1686
|
-
return {
|
|
1858
|
+
return await loadSubmittedHumanPromptReplay(db, {
|
|
1859
|
+
workspaceId: input.workspaceId,
|
|
1860
|
+
sessionId: input.sessionId,
|
|
1861
|
+
subjectId: input.subjectId,
|
|
1862
|
+
delivery: input.delivery,
|
|
1863
|
+
...(input.expectedDraftRevision !== undefined
|
|
1864
|
+
? { expectedDraftRevision: input.expectedDraftRevision }
|
|
1865
|
+
: {}),
|
|
1687
1866
|
receipt: reserved.receipt,
|
|
1688
|
-
|
|
1689
|
-
reserved.receipt.result.routing === "accepted_for_execution" ||
|
|
1690
|
-
reserved.receipt.result.routing === "queued_for_execution" ||
|
|
1691
|
-
reserved.receipt.result.routing === "accepted_for_steering"
|
|
1692
|
-
? reserved.receipt.result.routing
|
|
1693
|
-
: input.delivery === "steer"
|
|
1694
|
-
? "accepted_for_steering"
|
|
1695
|
-
: // Pre-routing receipts cannot reconstruct admission-time activity
|
|
1696
|
-
// or Pause truth. Queue is the only conservative placement; a
|
|
1697
|
-
// later turn.started event moves it into chat without duplication.
|
|
1698
|
-
"queued_for_execution",
|
|
1699
|
-
queueVersion: Number(reserved.receipt.appliedQueueVersion),
|
|
1700
|
-
accepted,
|
|
1701
|
-
events,
|
|
1702
|
-
turn: mapSubmittedPromptTurn(replayTurn),
|
|
1703
|
-
draft: replayDraft,
|
|
1704
|
-
acceptedEventId,
|
|
1705
|
-
eventIds,
|
|
1706
|
-
turnId,
|
|
1707
|
-
wakeRevision,
|
|
1708
|
-
interruptionCount: Number(reserved.receipt.result.interruptionCount ?? 0),
|
|
1709
|
-
workspaceControlEventId:
|
|
1710
|
-
typeof reserved.receipt.result.workspaceControlEventId === "string"
|
|
1711
|
-
? reserved.receipt.result.workspaceControlEventId
|
|
1712
|
-
: null,
|
|
1713
|
-
replay: true,
|
|
1714
|
-
};
|
|
1867
|
+
});
|
|
1715
1868
|
}
|
|
1869
|
+
await input.beforeFreshPromptCommit?.(db);
|
|
1716
1870
|
|
|
1717
1871
|
const before = await evaluateSessionControl(db, input.workspaceId, input.sessionId, {
|
|
1718
1872
|
workspaceControl,
|
|
@@ -1730,12 +1884,37 @@ export async function submitHumanPromptInTransaction(
|
|
|
1730
1884
|
);
|
|
1731
1885
|
}
|
|
1732
1886
|
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1887
|
+
const draft =
|
|
1888
|
+
input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
|
|
1889
|
+
? null
|
|
1890
|
+
: await getComposerDraftInTransaction(db, {
|
|
1891
|
+
workspaceId: input.workspaceId,
|
|
1892
|
+
sessionId: input.sessionId,
|
|
1893
|
+
subjectId: input.subjectId,
|
|
1894
|
+
lock: true,
|
|
1895
|
+
});
|
|
1896
|
+
const isQueueEditSubmission = draft?.sourceTurnId !== null && draft?.sourceTurnId !== undefined;
|
|
1897
|
+
|
|
1898
|
+
// A normal Send received while the active branch is waiting in
|
|
1899
|
+
// `requires_action` is the human choosing to continue conversationally
|
|
1900
|
+
// instead of through the pending decision surface. Promote only that active
|
|
1901
|
+
// wait to Steer semantics so the frozen wait is cancelled and the new prompt
|
|
1902
|
+
// runs next. A queue-edit submission preserves the identity and placement of
|
|
1903
|
+
// already accepted queued work, so it must never cancel an unrelated active
|
|
1904
|
+
// wait. An explicitly paused branch remains inert until Resume or an explicit
|
|
1905
|
+
// Steer; running, recovering, and capacity-waiting work also retain ordinary
|
|
1906
|
+
// queue semantics.
|
|
1907
|
+
const effectiveDelivery =
|
|
1908
|
+
input.delivery === "send" &&
|
|
1909
|
+
(input.actor.type === "human" || input.actor.type === "operator") &&
|
|
1910
|
+
!isQueueEditSubmission &&
|
|
1911
|
+
before.state === "active" &&
|
|
1912
|
+
session.status === "requires_action" &&
|
|
1913
|
+
session.activeTurnId !== null
|
|
1914
|
+
? "steer"
|
|
1915
|
+
: input.delivery;
|
|
1737
1916
|
const resumed =
|
|
1738
|
-
|
|
1917
|
+
effectiveDelivery === "send"
|
|
1739
1918
|
? {
|
|
1740
1919
|
revision: before.controlVersion,
|
|
1741
1920
|
control: before,
|
|
@@ -1753,16 +1932,6 @@ export async function submitHumanPromptInTransaction(
|
|
|
1753
1932
|
observedControlEtag: input.controlEtag ?? null,
|
|
1754
1933
|
admission,
|
|
1755
1934
|
});
|
|
1756
|
-
|
|
1757
|
-
const draft =
|
|
1758
|
-
input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
|
|
1759
|
-
? null
|
|
1760
|
-
: await getComposerDraftInTransaction(db, {
|
|
1761
|
-
workspaceId: input.workspaceId,
|
|
1762
|
-
sessionId: input.sessionId,
|
|
1763
|
-
subjectId: input.subjectId,
|
|
1764
|
-
lock: true,
|
|
1765
|
-
});
|
|
1766
1935
|
if (input.expectedDraftRevision !== null && input.expectedDraftRevision !== undefined) {
|
|
1767
1936
|
const actualRevision = draft?.revision ?? 0;
|
|
1768
1937
|
if (actualRevision !== input.expectedDraftRevision) {
|
|
@@ -1928,7 +2097,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
1928
2097
|
: (input.modelContext ?? null);
|
|
1929
2098
|
const existingQueued = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
|
|
1930
2099
|
const routing: SessionPromptRouting =
|
|
1931
|
-
|
|
2100
|
+
effectiveDelivery === "steer"
|
|
1932
2101
|
? "accepted_for_steering"
|
|
1933
2102
|
: before.state === "paused" || session.activeTurnId || existingQueued.length > 0
|
|
1934
2103
|
? "queued_for_execution"
|
|
@@ -1959,7 +2128,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
1959
2128
|
...(input.model ? { model: input.model } : {}),
|
|
1960
2129
|
...(input.reasoningEffort ? { reasoningEffort: input.reasoningEffort } : {}),
|
|
1961
2130
|
...(input.latencyMode ? { latencyMode: input.latencyMode } : {}),
|
|
1962
|
-
delivery:
|
|
2131
|
+
delivery: effectiveDelivery,
|
|
1963
2132
|
routing,
|
|
1964
2133
|
initiator: frozenInitiator.initiator,
|
|
1965
2134
|
},
|
|
@@ -1980,7 +2149,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
1980
2149
|
status: "queued",
|
|
1981
2150
|
source: input.source,
|
|
1982
2151
|
promptRouting: routing,
|
|
1983
|
-
position:
|
|
2152
|
+
position: effectiveDelivery === "steer" ? 0 : existingQueued.length + 1,
|
|
1984
2153
|
prompt: input.text,
|
|
1985
2154
|
annotations,
|
|
1986
2155
|
modelContext: effectiveModelContext,
|
|
@@ -2072,7 +2241,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2072
2241
|
});
|
|
2073
2242
|
|
|
2074
2243
|
const supersession =
|
|
2075
|
-
|
|
2244
|
+
effectiveDelivery === "steer"
|
|
2076
2245
|
? await supersedeSessionCurrentDirectionInTransaction(db, {
|
|
2077
2246
|
accountId: input.accountId,
|
|
2078
2247
|
workspaceId: input.workspaceId,
|
|
@@ -2085,8 +2254,10 @@ export async function submitHumanPromptInTransaction(
|
|
|
2085
2254
|
})
|
|
2086
2255
|
: {
|
|
2087
2256
|
interruptionCount: 0,
|
|
2257
|
+
steerTargetTurn: null,
|
|
2088
2258
|
replacedTurn: null,
|
|
2089
2259
|
liveCurrentTurnId: null,
|
|
2260
|
+
deferredUntilCompaction: false,
|
|
2090
2261
|
lastSequence: session.lastSequence,
|
|
2091
2262
|
};
|
|
2092
2263
|
// Ownerless Steer settlement may have appended interrupted tool results.
|
|
@@ -2094,9 +2265,11 @@ export async function submitHumanPromptInTransaction(
|
|
|
2094
2265
|
sequence = supersession.lastSequence;
|
|
2095
2266
|
for (const event of eventValues) event.sequence = ++sequence;
|
|
2096
2267
|
const interruptionCount = supersession.interruptionCount;
|
|
2268
|
+
const steerTargetTurn = supersession.steerTargetTurn;
|
|
2097
2269
|
const replacedTurnId = supersession.replacedTurn?.id ?? null;
|
|
2098
2270
|
const replacedAttemptId = supersession.replacedTurn?.activeAttemptId ?? null;
|
|
2099
2271
|
const liveCurrentTurnId = supersession.liveCurrentTurnId;
|
|
2272
|
+
const deferredUntilCompaction = supersession.deferredUntilCompaction;
|
|
2100
2273
|
// Durable provenance for the queue projection. Until the superseded attempt
|
|
2101
2274
|
// loses inference, user-visible output, and workspace-persistence authority,
|
|
2102
2275
|
// its exact first-class attempt has no quiescence receipt. Pairing that
|
|
@@ -2104,7 +2277,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2104
2277
|
// attempt…" truthfully across refresh/reconnect, even though logical
|
|
2105
2278
|
// settlement has already cleared sessions.active_turn_id. Do not infer this
|
|
2106
2279
|
// state from a local request spinner or queue position.
|
|
2107
|
-
if (
|
|
2280
|
+
if (effectiveDelivery === "steer") {
|
|
2108
2281
|
const [updatedTurn] = await db
|
|
2109
2282
|
.update(schema.sessionTurns)
|
|
2110
2283
|
.set({
|
|
@@ -2114,6 +2287,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2114
2287
|
replacedTurnId,
|
|
2115
2288
|
replacedAttemptId,
|
|
2116
2289
|
interruptionCount,
|
|
2290
|
+
...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
|
|
2117
2291
|
},
|
|
2118
2292
|
updatedAt: now,
|
|
2119
2293
|
})
|
|
@@ -2130,8 +2304,8 @@ export async function submitHumanPromptInTransaction(
|
|
|
2130
2304
|
}
|
|
2131
2305
|
committedTurn = updatedTurn;
|
|
2132
2306
|
}
|
|
2133
|
-
if (
|
|
2134
|
-
const current =
|
|
2307
|
+
if (steerTargetTurn) {
|
|
2308
|
+
const current = steerTargetTurn;
|
|
2135
2309
|
if (!liveCurrentTurnId) {
|
|
2136
2310
|
eventValues.push({
|
|
2137
2311
|
accountId: input.accountId,
|
|
@@ -2157,8 +2331,9 @@ export async function submitHumanPromptInTransaction(
|
|
|
2157
2331
|
payload: {
|
|
2158
2332
|
operationId: reserved.receipt.id,
|
|
2159
2333
|
targetTurnId: turnId,
|
|
2160
|
-
replacedTurnId
|
|
2161
|
-
stopping: liveCurrentTurnId !== null,
|
|
2334
|
+
replacedTurnId,
|
|
2335
|
+
stopping: liveCurrentTurnId !== null && !deferredUntilCompaction,
|
|
2336
|
+
...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
|
|
2162
2337
|
},
|
|
2163
2338
|
occurredAt: now,
|
|
2164
2339
|
});
|
|
@@ -2188,7 +2363,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2188
2363
|
}
|
|
2189
2364
|
|
|
2190
2365
|
const ordered =
|
|
2191
|
-
|
|
2366
|
+
effectiveDelivery === "steer" ? [turn, ...existingQueued] : [...existingQueued, turn];
|
|
2192
2367
|
await normalizeQueuePositions(
|
|
2193
2368
|
db,
|
|
2194
2369
|
input.workspaceId,
|
|
@@ -2196,7 +2371,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2196
2371
|
ordered.map((row) => row.id),
|
|
2197
2372
|
);
|
|
2198
2373
|
const noCurrentAfter =
|
|
2199
|
-
|
|
2374
|
+
effectiveDelivery === "steer" ? liveCurrentTurnId === null : !session.activeTurnId;
|
|
2200
2375
|
const nextStatus = noCurrentAfter ? "queued" : session.status;
|
|
2201
2376
|
if (nextStatus !== session.status) {
|
|
2202
2377
|
eventValues.push({
|
|
@@ -2223,12 +2398,12 @@ export async function submitHumanPromptInTransaction(
|
|
|
2223
2398
|
turnId,
|
|
2224
2399
|
channel: null,
|
|
2225
2400
|
text: renderRealtimeHumanInputContext({
|
|
2226
|
-
delivery:
|
|
2401
|
+
delivery: effectiveDelivery,
|
|
2227
2402
|
routing,
|
|
2228
2403
|
text: renderTimelineAnnotationsForModel(input.text, annotations),
|
|
2229
2404
|
}),
|
|
2230
2405
|
payload: {
|
|
2231
|
-
delivery:
|
|
2406
|
+
delivery: effectiveDelivery,
|
|
2232
2407
|
routing,
|
|
2233
2408
|
acceptedEventId,
|
|
2234
2409
|
instruction: "OpenGeni accepted and routed this user input; do not delegate it again.",
|
|
@@ -2242,7 +2417,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2242
2417
|
.set({
|
|
2243
2418
|
resources: mergeResourceRefs(session.resources as ResourceRef[], input.resources),
|
|
2244
2419
|
tools: session.tools,
|
|
2245
|
-
activeTurnId:
|
|
2420
|
+
activeTurnId: effectiveDelivery === "steer" ? liveCurrentTurnId : session.activeTurnId,
|
|
2246
2421
|
status: nextStatus,
|
|
2247
2422
|
queueVersion,
|
|
2248
2423
|
queueHeadPosition: 0,
|
|
@@ -2276,8 +2451,8 @@ export async function submitHumanPromptInTransaction(
|
|
|
2276
2451
|
workspaceId: input.workspaceId,
|
|
2277
2452
|
sessionId: input.sessionId,
|
|
2278
2453
|
temporalWorkflowId: workflowId,
|
|
2279
|
-
reason:
|
|
2280
|
-
controlRequested:
|
|
2454
|
+
reason: effectiveDelivery === "steer" ? "prompt_steer" : "prompt_send",
|
|
2455
|
+
controlRequested: effectiveDelivery === "steer",
|
|
2281
2456
|
});
|
|
2282
2457
|
await db.insert(schema.auditEvents).values(
|
|
2283
2458
|
withLosslessContentWriteVersion(
|
|
@@ -2288,13 +2463,14 @@ export async function submitHumanPromptInTransaction(
|
|
|
2288
2463
|
input.actor.type === "agent_attempt"
|
|
2289
2464
|
? `attempt:${input.actor.attemptId}`
|
|
2290
2465
|
: input.actor.subjectId,
|
|
2291
|
-
action:
|
|
2466
|
+
action: effectiveDelivery === "steer" ? "session.prompt.steer" : "session.prompt.send",
|
|
2292
2467
|
targetType: "session_turn",
|
|
2293
2468
|
targetId: turnId,
|
|
2294
2469
|
metadata: {
|
|
2295
2470
|
operationId: reserved.receipt.id,
|
|
2296
2471
|
replacedTurnId,
|
|
2297
2472
|
interruptionCount,
|
|
2473
|
+
deferredUntilCompaction,
|
|
2298
2474
|
...(input.turnExecutionPolicy
|
|
2299
2475
|
? turnExecutionPolicyAuditMetadata(input.turnExecutionPolicy, turnId)
|
|
2300
2476
|
: {}),
|
|
@@ -2332,12 +2508,14 @@ export async function submitHumanPromptInTransaction(
|
|
|
2332
2508
|
turnVersion: turn.version,
|
|
2333
2509
|
...(nextDraft ? { draftRevision: nextDraft.revision } : {}),
|
|
2334
2510
|
result: {
|
|
2511
|
+
...(input.boundaryRequestHash ? { boundaryRequestHash: input.boundaryRequestHash } : {}),
|
|
2335
2512
|
turnId,
|
|
2336
2513
|
acceptedEventId,
|
|
2337
2514
|
eventIds,
|
|
2338
2515
|
wakeRevision,
|
|
2339
2516
|
interruptionCount,
|
|
2340
2517
|
replacedTurnId,
|
|
2518
|
+
deferredUntilCompaction,
|
|
2341
2519
|
workspaceControlEventId: resumed.workspaceControlEventId,
|
|
2342
2520
|
routing,
|
|
2343
2521
|
...(input.turnExecutionPolicy
|
|
@@ -2815,16 +2993,17 @@ export async function steerAgentSessionInTransaction(
|
|
|
2815
2993
|
sessionId: input.targetSessionId,
|
|
2816
2994
|
sequence: ++sequence,
|
|
2817
2995
|
type: "session.control.steer_requested",
|
|
2818
|
-
turnId: supersession.
|
|
2819
|
-
turnGeneration: supersession.
|
|
2820
|
-
turnAttemptId: supersession.
|
|
2821
|
-
turnAssociation: supersession.
|
|
2996
|
+
turnId: supersession.steerTargetTurn?.id ?? null,
|
|
2997
|
+
turnGeneration: supersession.steerTargetTurn?.executionGeneration ?? null,
|
|
2998
|
+
turnAttemptId: supersession.steerTargetTurn?.activeAttemptId ?? null,
|
|
2999
|
+
turnAssociation: supersession.steerTargetTurn ? "current" : null,
|
|
2822
3000
|
payload: {
|
|
2823
3001
|
operationId: reserved.receipt.id,
|
|
2824
3002
|
targetUpdateId: update.id,
|
|
2825
3003
|
replacedTurnId: supersession.replacedTurn?.id ?? null,
|
|
2826
3004
|
actorSessionId: input.actor.sessionId,
|
|
2827
|
-
stopping: supersession.liveCurrentTurnId !== null,
|
|
3005
|
+
stopping: supersession.liveCurrentTurnId !== null && !supersession.deferredUntilCompaction,
|
|
3006
|
+
...(supersession.deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
|
|
2828
3007
|
},
|
|
2829
3008
|
occurredAt: now,
|
|
2830
3009
|
},
|
|
@@ -2912,6 +3091,7 @@ export async function steerAgentSessionInTransaction(
|
|
|
2912
3091
|
callerExecutionGeneration: input.actor.executionGeneration,
|
|
2913
3092
|
controlRevision: resumed.revision,
|
|
2914
3093
|
interruptionCount: supersession.interruptionCount,
|
|
3094
|
+
deferredUntilCompaction: supersession.deferredUntilCompaction,
|
|
2915
3095
|
workspaceControlEventId: resumed.workspaceControlEventId,
|
|
2916
3096
|
},
|
|
2917
3097
|
},
|
|
@@ -2928,6 +3108,7 @@ export async function steerAgentSessionInTransaction(
|
|
|
2928
3108
|
wakeRevision,
|
|
2929
3109
|
workflowId,
|
|
2930
3110
|
interruptionCount: supersession.interruptionCount,
|
|
3111
|
+
deferredUntilCompaction: supersession.deferredUntilCompaction,
|
|
2931
3112
|
},
|
|
2932
3113
|
});
|
|
2933
3114
|
return {
|