@opengeni/db 3.4.0-canary.2 → 3.6.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/canonical-human-identities.d.ts +20 -0
- package/dist/canonical-human-identities.js +7 -3
- package/dist/{chunk-ZWRIPCTR.js → chunk-2NT476HD.js} +2 -2
- package/dist/{chunk-PYMY3AJW.js → chunk-744DFC65.js} +202 -7
- package/dist/chunk-744DFC65.js.map +1 -0
- package/dist/{chunk-O6FTELKH.js → chunk-CDMMSUWJ.js} +3 -3
- package/dist/chunk-G3732M3T.js +299 -0
- package/dist/chunk-G3732M3T.js.map +1 -0
- package/dist/{chunk-TRBOWUG3.js → chunk-IW6O6G7R.js} +2 -2
- package/dist/{chunk-HY3F5Q4E.js → chunk-Q5YUGQVK.js} +3 -3
- package/dist/{chunk-V3TRUXFJ.js → chunk-UGDVSQ6U.js} +72 -19
- package/dist/chunk-UGDVSQ6U.js.map +1 -0
- package/dist/{chunk-C2AFP7SB.js → chunk-UJ2EW3QI.js} +6664 -6051
- package/dist/chunk-UJ2EW3QI.js.map +1 -0
- package/dist/{chunk-H7MXYG7R.js → chunk-WW7AJ5IC.js} +2 -2
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +44 -6
- package/dist/index.js +2914 -1535
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-set-schema.d.ts +1399 -0
- package/dist/managed-auth-session-sets.d.ts +145 -0
- package/dist/managed-auth-session-sets.js +50 -0
- package/dist/managed-auth-session-sets.js.map +1 -0
- package/dist/organization-recovery-schema.d.ts +2144 -0
- package/dist/organization-recovery.d.ts +186 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +7 -4
- package/dist/schema.d.ts +9 -6
- package/dist/schema.js +43 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-control.d.ts +5 -3
- package/dist/session-queue-commands.d.ts +2 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/dist/work-claims-schema.d.ts +975 -0
- package/dist/work-claims.d.ts +83 -0
- package/drizzle/0362_managed_auth_session_sets.sql +2347 -0
- package/drizzle/0363_organization_recovery_custody.sql +2418 -0
- package/drizzle/0364_workspace_learning_policy_snapshot_lock_order.sql +221 -0
- package/drizzle/0365_permission_scoped_work_claims.sql +1306 -0
- package/drizzle/0366_session_discovery_title_search_index.sql +5 -0
- package/drizzle/0367_session_discovery_goal_search_index.sql +5 -0
- package/drizzle/0368_session_discovery_claim_search_index.sql +6 -0
- package/package.json +10 -6
- package/src/canonical-human-identities.ts +105 -27
- package/src/index.ts +1471 -433
- package/src/managed-auth-session-set-schema.ts +176 -0
- package/src/managed-auth-session-sets.ts +430 -0
- package/src/organization-recovery-schema.ts +277 -0
- package/src/organization-recovery.ts +424 -0
- package/src/provision-roles.ts +67 -0
- package/src/runtime-posture.ts +144 -6
- package/src/schema.ts +3 -0
- package/src/session-control.ts +255 -16
- package/src/session-queue-commands.ts +10 -1
- package/src/session-tool-call-settlement.ts +6 -1
- package/src/work-claims-schema.ts +148 -0
- package/src/work-claims.ts +200 -0
- package/dist/chunk-C2AFP7SB.js.map +0 -1
- package/dist/chunk-PYMY3AJW.js.map +0 -1
- package/dist/chunk-V3TRUXFJ.js.map +0 -1
- /package/dist/{chunk-ZWRIPCTR.js.map → chunk-2NT476HD.js.map} +0 -0
- /package/dist/{chunk-O6FTELKH.js.map → chunk-CDMMSUWJ.js.map} +0 -0
- /package/dist/{chunk-TRBOWUG3.js.map → chunk-IW6O6G7R.js.map} +0 -0
- /package/dist/{chunk-HY3F5Q4E.js.map → chunk-Q5YUGQVK.js.map} +0 -0
- /package/dist/{chunk-H7MXYG7R.js.map → chunk-WW7AJ5IC.js.map} +0 -0
package/src/session-control.ts
CHANGED
|
@@ -2224,8 +2224,8 @@ export async function updateSessionCommandReceiptResult(
|
|
|
2224
2224
|
export type SessionControlMutationResult = {
|
|
2225
2225
|
receipt: SessionCommandReceiptRow;
|
|
2226
2226
|
control: EffectiveSessionControl;
|
|
2227
|
-
sessionControlEventId: string;
|
|
2228
|
-
workspaceControlEventId: string;
|
|
2227
|
+
sessionControlEventId: string | null;
|
|
2228
|
+
workspaceControlEventId: string | null;
|
|
2229
2229
|
interruptionCount: number;
|
|
2230
2230
|
backgroundCommandCount: number;
|
|
2231
2231
|
wakeCount: number;
|
|
@@ -2233,6 +2233,7 @@ export type SessionControlMutationResult = {
|
|
|
2233
2233
|
cancelledTurnCount: number;
|
|
2234
2234
|
affectedSessionEvents: Array<{ sessionId: string; eventIds: string[] }>;
|
|
2235
2235
|
workflowWake: SessionControlWorkflowWake | null;
|
|
2236
|
+
outcome: "changed" | "unchanged" | "replayed";
|
|
2236
2237
|
replay: boolean;
|
|
2237
2238
|
};
|
|
2238
2239
|
|
|
@@ -2278,6 +2279,115 @@ async function pendingSessionControlWorkflowWake(
|
|
|
2278
2279
|
};
|
|
2279
2280
|
}
|
|
2280
2281
|
|
|
2282
|
+
async function sessionPauseEffectsNeeded(
|
|
2283
|
+
db: Database,
|
|
2284
|
+
input: { workspaceId: string; sessionId: string; directPauseRevision: number },
|
|
2285
|
+
): Promise<boolean> {
|
|
2286
|
+
const rows = await db.execute<{ needed: boolean }>(sql`
|
|
2287
|
+
with recursive subtree(id, path, cycle) as (
|
|
2288
|
+
select session.id, array[session.id]::uuid[], false
|
|
2289
|
+
from ${schema.sessions} session
|
|
2290
|
+
where session.workspace_id = ${input.workspaceId}
|
|
2291
|
+
and session.id = ${input.sessionId}
|
|
2292
|
+
union all
|
|
2293
|
+
select child.id, parent.path || child.id, child.id = any(parent.path)
|
|
2294
|
+
from subtree parent
|
|
2295
|
+
join ${schema.sessions} child
|
|
2296
|
+
on child.workspace_id = ${input.workspaceId}
|
|
2297
|
+
and child.parent_session_id = parent.id
|
|
2298
|
+
where not parent.cycle
|
|
2299
|
+
and cardinality(parent.path) <= ${SESSION_ANCESTRY_LIMIT}
|
|
2300
|
+
), scoped_sessions as (
|
|
2301
|
+
select session.id, session.subtree_run_override_revision
|
|
2302
|
+
from subtree
|
|
2303
|
+
join ${schema.sessions} session
|
|
2304
|
+
on session.workspace_id = ${input.workspaceId}
|
|
2305
|
+
and session.id = subtree.id
|
|
2306
|
+
where not subtree.cycle
|
|
2307
|
+
)
|
|
2308
|
+
select exists (
|
|
2309
|
+
select 1
|
|
2310
|
+
from scoped_sessions session
|
|
2311
|
+
where session.subtree_run_override_revision > ${input.directPauseRevision}
|
|
2312
|
+
union all
|
|
2313
|
+
select 1
|
|
2314
|
+
from ${schema.sessionTurnAttempts} attempt
|
|
2315
|
+
join scoped_sessions session on session.id = attempt.session_id
|
|
2316
|
+
where attempt.workspace_id = ${input.workspaceId}
|
|
2317
|
+
and attempt.state in ('claimed', 'running')
|
|
2318
|
+
and not exists (
|
|
2319
|
+
select 1
|
|
2320
|
+
from ${schema.sessionAttemptInterruptions} interruption
|
|
2321
|
+
where interruption.workspace_id = attempt.workspace_id
|
|
2322
|
+
and interruption.attempt_id = attempt.id
|
|
2323
|
+
and interruption.kind in ('session_pause', 'workspace_pause')
|
|
2324
|
+
and interruption.state in ('pending', 'delivered', 'acknowledged')
|
|
2325
|
+
)
|
|
2326
|
+
union all
|
|
2327
|
+
select 1
|
|
2328
|
+
from ${schema.sessionBackgroundCommands} command
|
|
2329
|
+
join scoped_sessions session on session.id = command.session_id
|
|
2330
|
+
where command.workspace_id = ${input.workspaceId}
|
|
2331
|
+
and command.state = 'running'
|
|
2332
|
+
) as needed
|
|
2333
|
+
`);
|
|
2334
|
+
return rows[0]?.needed ?? false;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
async function workspacePauseEffectsNeeded(
|
|
2338
|
+
db: Database,
|
|
2339
|
+
input: { workspaceId: string; workspacePauseRevision: number },
|
|
2340
|
+
): Promise<boolean> {
|
|
2341
|
+
const rows = await db.execute<{ needed: boolean }>(sql`
|
|
2342
|
+
select exists (
|
|
2343
|
+
select 1
|
|
2344
|
+
from ${schema.sessions} session
|
|
2345
|
+
where session.workspace_id = ${input.workspaceId}
|
|
2346
|
+
and session.subtree_run_override_revision > ${input.workspacePauseRevision}
|
|
2347
|
+
union all
|
|
2348
|
+
select 1
|
|
2349
|
+
from ${schema.sessionTurnAttempts} attempt
|
|
2350
|
+
where attempt.workspace_id = ${input.workspaceId}
|
|
2351
|
+
and attempt.state in ('claimed', 'running')
|
|
2352
|
+
and not exists (
|
|
2353
|
+
select 1
|
|
2354
|
+
from ${schema.sessionAttemptInterruptions} interruption
|
|
2355
|
+
where interruption.workspace_id = attempt.workspace_id
|
|
2356
|
+
and interruption.attempt_id = attempt.id
|
|
2357
|
+
and interruption.kind in ('session_pause', 'workspace_pause')
|
|
2358
|
+
and interruption.state in ('pending', 'delivered', 'acknowledged')
|
|
2359
|
+
)
|
|
2360
|
+
union all
|
|
2361
|
+
select 1
|
|
2362
|
+
from ${schema.sessionBackgroundCommands} command
|
|
2363
|
+
where command.workspace_id = ${input.workspaceId}
|
|
2364
|
+
and command.state = 'running'
|
|
2365
|
+
) as needed
|
|
2366
|
+
`);
|
|
2367
|
+
return rows[0]?.needed ?? false;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
async function continuableWakeRepairNeeded(
|
|
2371
|
+
db: Database,
|
|
2372
|
+
input: { workspaceId: string; rootSessionId: string | null },
|
|
2373
|
+
): Promise<boolean> {
|
|
2374
|
+
const rows = await db.execute<{ needed: boolean }>(sql`
|
|
2375
|
+
select exists (
|
|
2376
|
+
select 1
|
|
2377
|
+
from opengeni_private.list_continuable_sessions(
|
|
2378
|
+
${input.workspaceId}::uuid,
|
|
2379
|
+
${input.rootSessionId}::uuid
|
|
2380
|
+
) eligible
|
|
2381
|
+
left join ${schema.sessionWorkflowWakeOutbox} wake
|
|
2382
|
+
on wake.workspace_id = eligible.workspace_id
|
|
2383
|
+
and wake.session_id = eligible.session_id
|
|
2384
|
+
where wake.session_id is null
|
|
2385
|
+
or wake.wake_revision <= wake.delivered_revision
|
|
2386
|
+
) as needed
|
|
2387
|
+
`);
|
|
2388
|
+
return rows[0]?.needed ?? false;
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2281
2391
|
async function loadSessionSubtreeIds(
|
|
2282
2392
|
db: Database,
|
|
2283
2393
|
workspaceId: string,
|
|
@@ -3017,13 +3127,23 @@ export async function mutateSessionControlInTransaction(
|
|
|
3017
3127
|
operationKey: input.operationKey,
|
|
3018
3128
|
canonicalRequestHash: hash,
|
|
3019
3129
|
});
|
|
3020
|
-
if (reserved.replay
|
|
3021
|
-
const
|
|
3022
|
-
|
|
3130
|
+
if (reserved.replay) {
|
|
3131
|
+
const storedOutcome = reserved.receipt.result.outcome;
|
|
3132
|
+
const unchanged =
|
|
3133
|
+
storedOutcome === "unchanged" && reserved.receipt.appliedControlRevision === null;
|
|
3134
|
+
if (!unchanged && reserved.receipt.appliedControlRevision === null) {
|
|
3135
|
+
throw new SessionControlInvariantError(
|
|
3136
|
+
"Replayed session control receipt has no applied control revision",
|
|
3137
|
+
);
|
|
3138
|
+
}
|
|
3139
|
+
const workspaceControlEventId = unchanged
|
|
3140
|
+
? null
|
|
3141
|
+
: String(reserved.receipt.result.workspaceControlEventId ?? "");
|
|
3142
|
+
if (!unchanged && !workspaceControlEventId) {
|
|
3023
3143
|
throw new SessionControlInvariantError("Replayed session control receipt has no event");
|
|
3024
3144
|
}
|
|
3025
|
-
const sessionControlEventId = String(reserved.receipt.result.eventId ?? "");
|
|
3026
|
-
if (!sessionControlEventId) {
|
|
3145
|
+
const sessionControlEventId = unchanged ? null : String(reserved.receipt.result.eventId ?? "");
|
|
3146
|
+
if (!unchanged && !sessionControlEventId) {
|
|
3027
3147
|
throw new SessionControlInvariantError(
|
|
3028
3148
|
"Replayed session control receipt has no session event",
|
|
3029
3149
|
);
|
|
@@ -3046,13 +3166,16 @@ export async function mutateSessionControlInTransaction(
|
|
|
3046
3166
|
sessionId: string;
|
|
3047
3167
|
eventIds: string[];
|
|
3048
3168
|
}>)
|
|
3049
|
-
:
|
|
3169
|
+
: sessionControlEventId
|
|
3170
|
+
? [{ sessionId: input.sessionId, eventIds: [sessionControlEventId] }]
|
|
3171
|
+
: [],
|
|
3050
3172
|
workflowWake: await pendingSessionControlWorkflowWake(
|
|
3051
3173
|
db,
|
|
3052
3174
|
input.workspaceId,
|
|
3053
3175
|
input.sessionId,
|
|
3054
3176
|
wakeCount,
|
|
3055
3177
|
),
|
|
3178
|
+
outcome: "replayed",
|
|
3056
3179
|
replay: true,
|
|
3057
3180
|
};
|
|
3058
3181
|
}
|
|
@@ -3074,6 +3197,59 @@ export async function mutateSessionControlInTransaction(
|
|
|
3074
3197
|
throw new SessionControlConflictError();
|
|
3075
3198
|
}
|
|
3076
3199
|
|
|
3200
|
+
if (input.action !== "cancel") {
|
|
3201
|
+
const targetSession = locks.sessions.find((session) => session.id === input.sessionId);
|
|
3202
|
+
if (!targetSession) {
|
|
3203
|
+
throw new SessionControlInvariantError(`Session ${input.sessionId} disappeared`);
|
|
3204
|
+
}
|
|
3205
|
+
const directPauseRevision = asSafeRevision(
|
|
3206
|
+
targetSession.directPauseRevision,
|
|
3207
|
+
"direct pause revision",
|
|
3208
|
+
);
|
|
3209
|
+
const changed =
|
|
3210
|
+
input.action === "pause"
|
|
3211
|
+
? targetSession.directControlState !== "paused" ||
|
|
3212
|
+
directPauseRevision === null ||
|
|
3213
|
+
(await sessionPauseEffectsNeeded(db, {
|
|
3214
|
+
workspaceId: input.workspaceId,
|
|
3215
|
+
sessionId: input.sessionId,
|
|
3216
|
+
directPauseRevision,
|
|
3217
|
+
}))
|
|
3218
|
+
: before.state === "paused" ||
|
|
3219
|
+
(await continuableWakeRepairNeeded(db, {
|
|
3220
|
+
workspaceId: input.workspaceId,
|
|
3221
|
+
rootSessionId: input.sessionId,
|
|
3222
|
+
}));
|
|
3223
|
+
if (!changed) {
|
|
3224
|
+
const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
|
|
3225
|
+
result: {
|
|
3226
|
+
outcome: "unchanged",
|
|
3227
|
+
interruptionCount: 0,
|
|
3228
|
+
backgroundCommandCount: 0,
|
|
3229
|
+
wakeCount: 0,
|
|
3230
|
+
cancelledSessionCount: 0,
|
|
3231
|
+
cancelledTurnCount: 0,
|
|
3232
|
+
affectedSessionEvents: [],
|
|
3233
|
+
},
|
|
3234
|
+
});
|
|
3235
|
+
return {
|
|
3236
|
+
receipt,
|
|
3237
|
+
control: before,
|
|
3238
|
+
sessionControlEventId: null,
|
|
3239
|
+
workspaceControlEventId: null,
|
|
3240
|
+
interruptionCount: 0,
|
|
3241
|
+
backgroundCommandCount: 0,
|
|
3242
|
+
wakeCount: 0,
|
|
3243
|
+
cancelledSessionCount: 0,
|
|
3244
|
+
cancelledTurnCount: 0,
|
|
3245
|
+
affectedSessionEvents: [],
|
|
3246
|
+
workflowWake: null,
|
|
3247
|
+
outcome: "unchanged",
|
|
3248
|
+
replay: false,
|
|
3249
|
+
};
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
|
|
3077
3253
|
const revision = nextRevision(workspace);
|
|
3078
3254
|
await advanceWorkspaceRevision(db, input.workspaceId, revision);
|
|
3079
3255
|
const updatedRows = await db
|
|
@@ -3281,6 +3457,7 @@ export async function mutateSessionControlInTransaction(
|
|
|
3281
3457
|
const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
|
|
3282
3458
|
controlRevision: revision,
|
|
3283
3459
|
result: {
|
|
3460
|
+
outcome: "changed",
|
|
3284
3461
|
interruptionCount,
|
|
3285
3462
|
backgroundCommandCount,
|
|
3286
3463
|
wakeCount,
|
|
@@ -3311,6 +3488,7 @@ export async function mutateSessionControlInTransaction(
|
|
|
3311
3488
|
input.sessionId,
|
|
3312
3489
|
wakeCount,
|
|
3313
3490
|
),
|
|
3491
|
+
outcome: "changed",
|
|
3314
3492
|
replay: false,
|
|
3315
3493
|
};
|
|
3316
3494
|
}
|
|
@@ -3406,11 +3584,12 @@ export async function autoResumeSessionBranchInTransaction(
|
|
|
3406
3584
|
export type WorkspaceControlMutationResult = {
|
|
3407
3585
|
receipt: SessionCommandReceiptRow;
|
|
3408
3586
|
revision: number;
|
|
3409
|
-
workspaceControlEventId: string;
|
|
3587
|
+
workspaceControlEventId: string | null;
|
|
3410
3588
|
workspaceState: EffectiveControlState;
|
|
3411
3589
|
interruptionCount: number;
|
|
3412
3590
|
backgroundCommandCount: number;
|
|
3413
3591
|
wakeCount: number;
|
|
3592
|
+
outcome: "changed" | "unchanged" | "replayed";
|
|
3414
3593
|
replay: boolean;
|
|
3415
3594
|
};
|
|
3416
3595
|
|
|
@@ -3449,19 +3628,33 @@ export async function mutateWorkspaceControlInTransaction(
|
|
|
3449
3628
|
operationKey: input.operationKey,
|
|
3450
3629
|
canonicalRequestHash: hash,
|
|
3451
3630
|
});
|
|
3452
|
-
if (reserved.replay
|
|
3453
|
-
const
|
|
3454
|
-
|
|
3631
|
+
if (reserved.replay) {
|
|
3632
|
+
const storedOutcome = reserved.receipt.result.outcome;
|
|
3633
|
+
const unchanged =
|
|
3634
|
+
storedOutcome === "unchanged" && reserved.receipt.appliedControlRevision === null;
|
|
3635
|
+
if (!unchanged && reserved.receipt.appliedControlRevision === null) {
|
|
3636
|
+
throw new SessionControlInvariantError(
|
|
3637
|
+
"Replayed workspace control receipt has no applied control revision",
|
|
3638
|
+
);
|
|
3639
|
+
}
|
|
3640
|
+
const workspaceControlEventId = unchanged
|
|
3641
|
+
? null
|
|
3642
|
+
: String(reserved.receipt.result.workspaceControlEventId ?? "");
|
|
3643
|
+
if (!unchanged && !workspaceControlEventId) {
|
|
3455
3644
|
throw new SessionControlInvariantError("Replayed workspace control receipt has no event");
|
|
3456
3645
|
}
|
|
3457
3646
|
return {
|
|
3458
3647
|
receipt: reserved.receipt,
|
|
3459
|
-
revision:
|
|
3460
|
-
|
|
3461
|
-
|
|
3648
|
+
revision:
|
|
3649
|
+
reserved.receipt.appliedControlRevision === null
|
|
3650
|
+
? currentRevision
|
|
3651
|
+
: Number(reserved.receipt.appliedControlRevision),
|
|
3652
|
+
workspaceControlEventId: workspaceControlEventId || null,
|
|
3653
|
+
workspaceState: workspace.workspaceState === "paused" ? "paused" : "active",
|
|
3462
3654
|
interruptionCount: Number(reserved.receipt.result.interruptionCount ?? 0),
|
|
3463
3655
|
backgroundCommandCount: Number(reserved.receipt.result.backgroundCommandCount ?? 0),
|
|
3464
3656
|
wakeCount: Number(reserved.receipt.result.wakeCount ?? 0),
|
|
3657
|
+
outcome: "replayed",
|
|
3465
3658
|
replay: true,
|
|
3466
3659
|
};
|
|
3467
3660
|
}
|
|
@@ -3469,6 +3662,45 @@ export async function mutateWorkspaceControlInTransaction(
|
|
|
3469
3662
|
if (input.expectedRevision !== currentRevision) throw new SessionControlConflictError();
|
|
3470
3663
|
}
|
|
3471
3664
|
|
|
3665
|
+
const workspacePauseRevision = asSafeRevision(
|
|
3666
|
+
workspace.workspacePauseRevision,
|
|
3667
|
+
"workspace pause revision",
|
|
3668
|
+
);
|
|
3669
|
+
const changed =
|
|
3670
|
+
input.action === "pause"
|
|
3671
|
+
? workspace.workspaceState !== "paused" ||
|
|
3672
|
+
workspacePauseRevision === null ||
|
|
3673
|
+
(await workspacePauseEffectsNeeded(db, {
|
|
3674
|
+
workspaceId: input.workspaceId,
|
|
3675
|
+
workspacePauseRevision,
|
|
3676
|
+
}))
|
|
3677
|
+
: workspace.workspaceState !== "active" ||
|
|
3678
|
+
(await continuableWakeRepairNeeded(db, {
|
|
3679
|
+
workspaceId: input.workspaceId,
|
|
3680
|
+
rootSessionId: null,
|
|
3681
|
+
}));
|
|
3682
|
+
if (!changed) {
|
|
3683
|
+
const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
|
|
3684
|
+
result: {
|
|
3685
|
+
outcome: "unchanged",
|
|
3686
|
+
interruptionCount: 0,
|
|
3687
|
+
backgroundCommandCount: 0,
|
|
3688
|
+
wakeCount: 0,
|
|
3689
|
+
},
|
|
3690
|
+
});
|
|
3691
|
+
return {
|
|
3692
|
+
receipt,
|
|
3693
|
+
revision: currentRevision,
|
|
3694
|
+
workspaceControlEventId: null,
|
|
3695
|
+
workspaceState: workspace.workspaceState === "paused" ? "paused" : "active",
|
|
3696
|
+
interruptionCount: 0,
|
|
3697
|
+
backgroundCommandCount: 0,
|
|
3698
|
+
wakeCount: 0,
|
|
3699
|
+
outcome: "unchanged",
|
|
3700
|
+
replay: false,
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3472
3704
|
const revision = nextRevision(workspace);
|
|
3473
3705
|
const actor =
|
|
3474
3706
|
input.actor.type === "agent_attempt"
|
|
@@ -3533,7 +3765,13 @@ export async function mutateWorkspaceControlInTransaction(
|
|
|
3533
3765
|
});
|
|
3534
3766
|
const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
|
|
3535
3767
|
controlRevision: revision,
|
|
3536
|
-
result: {
|
|
3768
|
+
result: {
|
|
3769
|
+
outcome: "changed",
|
|
3770
|
+
interruptionCount,
|
|
3771
|
+
backgroundCommandCount,
|
|
3772
|
+
wakeCount,
|
|
3773
|
+
workspaceControlEventId,
|
|
3774
|
+
},
|
|
3537
3775
|
});
|
|
3538
3776
|
return {
|
|
3539
3777
|
receipt,
|
|
@@ -3543,6 +3781,7 @@ export async function mutateWorkspaceControlInTransaction(
|
|
|
3543
3781
|
interruptionCount,
|
|
3544
3782
|
backgroundCommandCount,
|
|
3545
3783
|
wakeCount,
|
|
3784
|
+
outcome: "changed",
|
|
3546
3785
|
replay: false,
|
|
3547
3786
|
};
|
|
3548
3787
|
}
|
|
@@ -1535,6 +1535,8 @@ export async function submitHumanPromptInTransaction(
|
|
|
1535
1535
|
annotations?: TimelineAnnotation[];
|
|
1536
1536
|
modelContext?: string | null;
|
|
1537
1537
|
resources: ResourceRef[];
|
|
1538
|
+
/** Actor-owned resources used only for the exact durable-draft fence. */
|
|
1539
|
+
composerDraftResources?: ResourceRef[];
|
|
1538
1540
|
model?: string | null;
|
|
1539
1541
|
reasoningEffort?: ReasoningEffort | null;
|
|
1540
1542
|
latencyMode?: LatencyMode | null;
|
|
@@ -1601,6 +1603,11 @@ export async function submitHumanPromptInTransaction(
|
|
|
1601
1603
|
annotations,
|
|
1602
1604
|
modelContext: input.modelContext ?? null,
|
|
1603
1605
|
resources: withCanonicalResourceMountPaths(input.resources),
|
|
1606
|
+
...(input.composerDraftResources
|
|
1607
|
+
? {
|
|
1608
|
+
composerDraftResources: withCanonicalResourceMountPaths(input.composerDraftResources),
|
|
1609
|
+
}
|
|
1610
|
+
: {}),
|
|
1604
1611
|
model: input.model ?? null,
|
|
1605
1612
|
reasoningEffort: input.reasoningEffort ?? null,
|
|
1606
1613
|
latencyMode: input.latencyMode ?? null,
|
|
@@ -1777,7 +1784,9 @@ export async function submitHumanPromptInTransaction(
|
|
|
1777
1784
|
canonicalSessionCommandHash({
|
|
1778
1785
|
text: input.text,
|
|
1779
1786
|
annotations: annotations.map(({ ordinal: _ordinal, ...annotation }) => annotation),
|
|
1780
|
-
resources: withCanonicalResourceMountPaths(
|
|
1787
|
+
resources: withCanonicalResourceMountPaths(
|
|
1788
|
+
input.composerDraftResources ?? input.resources,
|
|
1789
|
+
),
|
|
1781
1790
|
model: input.model ?? session.model,
|
|
1782
1791
|
reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback,
|
|
1783
1792
|
latencyMode: input.turnExecutionPolicy?.latencyMode ?? input.latencyMode ?? "standard",
|
|
@@ -15,7 +15,12 @@ export const TOOL_RESULT_TYPE_BY_CALL_TYPE: Readonly<Record<string, string>> = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export function historyCallId(item: Record<string, unknown>): string | null {
|
|
18
|
-
const
|
|
18
|
+
const providerData =
|
|
19
|
+
item.providerData && typeof item.providerData === "object" && !Array.isArray(item.providerData)
|
|
20
|
+
? (item.providerData as Record<string, unknown>)
|
|
21
|
+
: null;
|
|
22
|
+
const value =
|
|
23
|
+
item.callId ?? item.call_id ?? providerData?.callId ?? providerData?.call_id ?? item.id;
|
|
19
24
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
20
25
|
}
|
|
21
26
|
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
customType,
|
|
4
|
+
index,
|
|
5
|
+
integer,
|
|
6
|
+
pgTable,
|
|
7
|
+
primaryKey,
|
|
8
|
+
text,
|
|
9
|
+
timestamp,
|
|
10
|
+
uniqueIndex,
|
|
11
|
+
uuid,
|
|
12
|
+
} from "drizzle-orm/pg-core";
|
|
13
|
+
|
|
14
|
+
const xid8 = customType<{ data: string; driverData: string }>({
|
|
15
|
+
dataType: () => "xid8",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Exact lifecycle-only mutation, immutable revisions, FORCE RLS, and runtime
|
|
19
|
+
// grants are owned by the work-claim migration. The application role receives
|
|
20
|
+
// SELECT on the compact head plus EXECUTE on exact-attempt mutation routines,
|
|
21
|
+
// never direct DML authority.
|
|
22
|
+
export const sessionWorkClaims = pgTable(
|
|
23
|
+
"session_work_claims",
|
|
24
|
+
{
|
|
25
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
26
|
+
accountId: uuid("account_id").notNull(),
|
|
27
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
28
|
+
sessionId: uuid("session_id").notNull(),
|
|
29
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
30
|
+
subjectNamespace: text("subject_namespace").notNull(),
|
|
31
|
+
subjectType: text("subject_type").notNull(),
|
|
32
|
+
canonicalKey: text("canonical_key").notNull(),
|
|
33
|
+
subjectDigest: text("subject_digest").notNull(),
|
|
34
|
+
displayLabel: text("display_label"),
|
|
35
|
+
role: text("role").notNull(),
|
|
36
|
+
state: text("state").notNull().default("active"),
|
|
37
|
+
revision: integer("revision").notNull().default(1),
|
|
38
|
+
provenance: text("provenance").notNull(),
|
|
39
|
+
versionKind: text("version_kind"),
|
|
40
|
+
versionValue: text("version_value"),
|
|
41
|
+
observedAt: timestamp("observed_at", { withTimezone: true }).notNull(),
|
|
42
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
43
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
44
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
45
|
+
},
|
|
46
|
+
(table) => ({
|
|
47
|
+
workspaceIdentity: uniqueIndex("session_work_claims_workspace_id_uq").on(
|
|
48
|
+
table.workspaceId,
|
|
49
|
+
table.id,
|
|
50
|
+
),
|
|
51
|
+
activeIdentity: uniqueIndex("session_work_claims_active_identity_uq")
|
|
52
|
+
.on(
|
|
53
|
+
table.workspaceId,
|
|
54
|
+
table.sessionId,
|
|
55
|
+
table.subjectNamespace,
|
|
56
|
+
table.subjectType,
|
|
57
|
+
table.subjectDigest,
|
|
58
|
+
table.role,
|
|
59
|
+
)
|
|
60
|
+
.where(sql`${table.state} = 'active'`),
|
|
61
|
+
sessionState: index("session_work_claims_session_state_idx").on(
|
|
62
|
+
table.workspaceId,
|
|
63
|
+
table.sessionId,
|
|
64
|
+
table.state,
|
|
65
|
+
table.updatedAt,
|
|
66
|
+
table.id,
|
|
67
|
+
),
|
|
68
|
+
subjectState: index("session_work_claims_subject_state_idx").on(
|
|
69
|
+
table.workspaceId,
|
|
70
|
+
table.subjectNamespace,
|
|
71
|
+
table.subjectType,
|
|
72
|
+
table.subjectDigest,
|
|
73
|
+
table.state,
|
|
74
|
+
table.updatedAt,
|
|
75
|
+
table.id,
|
|
76
|
+
),
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
export const sessionWorkClaimRevisions = pgTable(
|
|
81
|
+
"session_work_claim_revisions",
|
|
82
|
+
{
|
|
83
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
84
|
+
accountId: uuid("account_id").notNull(),
|
|
85
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
86
|
+
claimId: uuid("claim_id").notNull(),
|
|
87
|
+
sessionId: uuid("session_id").notNull(),
|
|
88
|
+
rootSessionId: uuid("root_session_id").notNull(),
|
|
89
|
+
operationId: uuid("operation_id").notNull(),
|
|
90
|
+
inputHash: text("input_hash").notNull(),
|
|
91
|
+
mutationKind: text("mutation_kind").notNull(),
|
|
92
|
+
priorRevision: integer("prior_revision"),
|
|
93
|
+
resultingRevision: integer("resulting_revision").notNull(),
|
|
94
|
+
subjectNamespace: text("subject_namespace").notNull(),
|
|
95
|
+
subjectType: text("subject_type").notNull(),
|
|
96
|
+
canonicalKey: text("canonical_key").notNull(),
|
|
97
|
+
subjectDigest: text("subject_digest").notNull(),
|
|
98
|
+
displayLabel: text("display_label"),
|
|
99
|
+
role: text("role").notNull(),
|
|
100
|
+
state: text("state").notNull(),
|
|
101
|
+
provenance: text("provenance").notNull(),
|
|
102
|
+
versionKind: text("version_kind"),
|
|
103
|
+
versionValue: text("version_value"),
|
|
104
|
+
observedAt: timestamp("observed_at", { withTimezone: true }).notNull(),
|
|
105
|
+
claimCreatedAt: timestamp("claim_created_at", { withTimezone: true }).notNull(),
|
|
106
|
+
claimUpdatedAt: timestamp("claim_updated_at", { withTimezone: true }).notNull(),
|
|
107
|
+
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
108
|
+
actorKind: text("actor_kind").notNull(),
|
|
109
|
+
actorSubjectId: text("actor_subject_id").notNull(),
|
|
110
|
+
actorSessionId: uuid("actor_session_id"),
|
|
111
|
+
actorTurnId: uuid("actor_turn_id"),
|
|
112
|
+
actorAttemptId: uuid("actor_attempt_id"),
|
|
113
|
+
actorExecutionGeneration: integer("actor_execution_generation"),
|
|
114
|
+
reason: text("reason"),
|
|
115
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
116
|
+
},
|
|
117
|
+
(table) => ({
|
|
118
|
+
operation: uniqueIndex("session_work_claim_revisions_workspace_operation_uq").on(
|
|
119
|
+
table.workspaceId,
|
|
120
|
+
table.operationId,
|
|
121
|
+
),
|
|
122
|
+
claimRevision: uniqueIndex("session_work_claim_revisions_claim_revision_uq").on(
|
|
123
|
+
table.workspaceId,
|
|
124
|
+
table.claimId,
|
|
125
|
+
table.resultingRevision,
|
|
126
|
+
),
|
|
127
|
+
sessionTimeline: index("session_work_claim_revisions_session_timeline_idx").on(
|
|
128
|
+
table.workspaceId,
|
|
129
|
+
table.sessionId,
|
|
130
|
+
table.createdAt,
|
|
131
|
+
table.id,
|
|
132
|
+
),
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
export const sessionWorkClaimWriteCapabilities = pgTable(
|
|
137
|
+
"session_work_claim_write_capabilities",
|
|
138
|
+
{
|
|
139
|
+
backendPid: integer("backend_pid").notNull(),
|
|
140
|
+
transactionId: xid8("transaction_id").notNull(),
|
|
141
|
+
capabilityId: uuid("capability_id").notNull(),
|
|
142
|
+
},
|
|
143
|
+
(table) => ({
|
|
144
|
+
identity: primaryKey({
|
|
145
|
+
columns: [table.backendPid, table.transactionId, table.capabilityId],
|
|
146
|
+
}),
|
|
147
|
+
}),
|
|
148
|
+
);
|