@opengeni/db 3.7.4 → 3.8.2-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-O56DM5GZ.js → chunk-53A2PEHT.js} +328 -31
- package/dist/chunk-53A2PEHT.js.map +1 -0
- package/dist/{chunk-SZAWDXQC.js → chunk-5S4BQAHX.js} +3 -3
- package/dist/{chunk-S3TDDCS2.js → chunk-CITYUGMW.js} +3 -3
- package/dist/{chunk-4NAR7FBA.js → chunk-F5YOZEYQ.js} +49 -1
- package/dist/chunk-F5YOZEYQ.js.map +1 -0
- package/dist/{chunk-F6PBS6WE.js → chunk-HZV7O6JR.js} +2 -2
- package/dist/{chunk-5NNCGFQY.js → chunk-RLQVPOVR.js} +2 -2
- package/dist/{chunk-DZCYW2WT.js → chunk-UKOGHUGC.js} +2 -2
- package/dist/{chunk-US4IS6IV.js → chunk-X6TO5HII.js} +2 -2
- package/dist/{chunk-U4WPPEBH.js → chunk-Y53WEFYB.js} +2 -2
- package/dist/connection-token-resolver.d.ts +4 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +164 -14
- package/dist/index.js +7327 -5442
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +9 -0
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/model-catalog.d.ts +153 -0
- package/dist/new-session-drafts.d.ts +12 -0
- package/dist/organization-membership-lifecycle.d.ts +8 -1
- package/dist/organization-model-providers.d.ts +101 -0
- package/dist/pack-components.d.ts +1 -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 +989 -2
- package/dist/schema.js +11 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-control.d.ts +35 -0
- package/dist/session-queue-commands.d.ts +17 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/dist/xai-subscription.d.ts +8 -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/drizzle/0390_organization_model_provider_connections.sql +197 -0
- package/drizzle/0391_sandbox_provider_deadline_interaction_followup.sql +295 -0
- package/drizzle/0392_context_compaction_pending_observability.sql +198 -0
- package/drizzle/0393_workspace_memory_and_learning_defaults.sql +102 -0
- package/drizzle/0394_session_selected_skill_activation.sql +20 -0
- package/drizzle/0395_scheduled_task_unclaimed_occurrence_invalidation.sql +154 -0
- package/drizzle/0396_model_call_equivalent_credit_cost.sql +28 -0
- package/drizzle/0397_sandbox_deadline_rotation_preemption.sql +113 -0
- package/drizzle/0398_organization_workspace_management_entry.sql +206 -0
- package/drizzle/0399_additional_managed_organization_creation.sql +691 -0
- package/package.json +6 -6
- package/src/automations.ts +9 -1
- package/src/connection-token-resolver.ts +12 -0
- package/src/index.ts +1551 -272
- package/src/insights-model-bundle.ts +54 -5
- package/src/insights.ts +53 -7
- package/src/model-catalog.ts +682 -0
- package/src/new-session-drafts.ts +66 -21
- package/src/organization-membership-lifecycle.ts +47 -5
- package/src/organization-model-providers.ts +614 -0
- package/src/pack-components.ts +15 -2
- package/src/pr-review.ts +19 -0
- package/src/provision-roles.ts +2 -0
- package/src/runtime-posture.ts +48 -0
- package/src/schema.ts +348 -32
- package/src/session-control.ts +170 -0
- package/src/session-queue-commands.ts +157 -82
- package/src/xai-subscription.ts +66 -14
- package/dist/chunk-4NAR7FBA.js.map +0 -1
- package/dist/chunk-O56DM5GZ.js.map +0 -1
- /package/dist/{chunk-SZAWDXQC.js.map → chunk-5S4BQAHX.js.map} +0 -0
- /package/dist/{chunk-S3TDDCS2.js.map → chunk-CITYUGMW.js.map} +0 -0
- /package/dist/{chunk-F6PBS6WE.js.map → chunk-HZV7O6JR.js.map} +0 -0
- /package/dist/{chunk-5NNCGFQY.js.map → chunk-RLQVPOVR.js.map} +0 -0
- /package/dist/{chunk-DZCYW2WT.js.map → chunk-UKOGHUGC.js.map} +0 -0
- /package/dist/{chunk-US4IS6IV.js.map → chunk-X6TO5HII.js.map} +0 -0
- /package/dist/{chunk-U4WPPEBH.js.map → chunk-Y53WEFYB.js.map} +0 -0
package/src/session-control.ts
CHANGED
|
@@ -1884,6 +1884,174 @@ async function findCommandReceipt(
|
|
|
1884
1884
|
return rows[0] ?? null;
|
|
1885
1885
|
}
|
|
1886
1886
|
|
|
1887
|
+
export type SessionPromptCommandAction = "prompt.send" | "prompt.steer";
|
|
1888
|
+
|
|
1889
|
+
async function findPromptCommandReceipts(
|
|
1890
|
+
db: Database,
|
|
1891
|
+
input: {
|
|
1892
|
+
workspaceId: string;
|
|
1893
|
+
actor: SessionCommandActor;
|
|
1894
|
+
operationKey: string;
|
|
1895
|
+
lock?: "none" | "update";
|
|
1896
|
+
},
|
|
1897
|
+
): Promise<SessionCommandReceiptRow[]> {
|
|
1898
|
+
const actorSubjectId = input.actor.type === "agent_attempt" ? null : input.actor.subjectId;
|
|
1899
|
+
const actorAttemptId = input.actor.type === "agent_attempt" ? input.actor.attemptId : null;
|
|
1900
|
+
const query = db
|
|
1901
|
+
.select()
|
|
1902
|
+
.from(schema.sessionCommandReceipts)
|
|
1903
|
+
.where(
|
|
1904
|
+
and(
|
|
1905
|
+
eq(schema.sessionCommandReceipts.workspaceId, input.workspaceId),
|
|
1906
|
+
eq(schema.sessionCommandReceipts.actorType, input.actor.type),
|
|
1907
|
+
sql`${schema.sessionCommandReceipts.actorSubjectId} is not distinct from ${actorSubjectId}`,
|
|
1908
|
+
sql`${schema.sessionCommandReceipts.actorAttemptId} is not distinct from ${actorAttemptId}::uuid`,
|
|
1909
|
+
inArray(schema.sessionCommandReceipts.action, ["prompt.send", "prompt.steer"]),
|
|
1910
|
+
eq(schema.sessionCommandReceipts.operationKey, input.operationKey),
|
|
1911
|
+
),
|
|
1912
|
+
);
|
|
1913
|
+
const rows = input.lock === "update" ? await query.for("update") : await query;
|
|
1914
|
+
return rows;
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
function fingerprintedPromptCommandReceipt(
|
|
1918
|
+
receipts: readonly SessionCommandReceiptRow[],
|
|
1919
|
+
): SessionCommandReceiptRow | null {
|
|
1920
|
+
const fingerprinted = receipts.filter(
|
|
1921
|
+
(receipt) => typeof receipt.result.boundaryRequestHash === "string",
|
|
1922
|
+
);
|
|
1923
|
+
if (fingerprinted.length > 1) {
|
|
1924
|
+
throw new SessionControlInvariantError(
|
|
1925
|
+
"Prompt operation key resolved to multiple fingerprinted receipts",
|
|
1926
|
+
);
|
|
1927
|
+
}
|
|
1928
|
+
return fingerprinted[0] ?? null;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
function assertPromptCommandReceiptIdentity(
|
|
1932
|
+
receipt: SessionCommandReceiptRow,
|
|
1933
|
+
input: {
|
|
1934
|
+
action: SessionPromptCommandAction;
|
|
1935
|
+
targetSessionId: string;
|
|
1936
|
+
boundaryRequestHash: string;
|
|
1937
|
+
},
|
|
1938
|
+
): void {
|
|
1939
|
+
if (
|
|
1940
|
+
receipt.action !== input.action ||
|
|
1941
|
+
receipt.targetSessionId !== input.targetSessionId ||
|
|
1942
|
+
receipt.targetTurnId !== null ||
|
|
1943
|
+
(typeof receipt.result.boundaryRequestHash === "string" &&
|
|
1944
|
+
receipt.result.boundaryRequestHash !== input.boundaryRequestHash)
|
|
1945
|
+
) {
|
|
1946
|
+
throw new SessionCommandIdempotencyError();
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* Prompt operation keys are actor-scoped across target sessions and across the
|
|
1952
|
+
* Send/Steer action pair. The advisory lock closes the gap left by the legacy
|
|
1953
|
+
* action/target-specific unique index without changing old receipt identities.
|
|
1954
|
+
*/
|
|
1955
|
+
export async function reserveSessionPromptCommandReceipt(
|
|
1956
|
+
db: Database,
|
|
1957
|
+
input: {
|
|
1958
|
+
accountId: string;
|
|
1959
|
+
workspaceId: string;
|
|
1960
|
+
actor: SessionCommandActor;
|
|
1961
|
+
action: SessionPromptCommandAction;
|
|
1962
|
+
targetSessionId: string;
|
|
1963
|
+
operationKey: string;
|
|
1964
|
+
canonicalRequestHash: string;
|
|
1965
|
+
boundaryRequestHash: string;
|
|
1966
|
+
},
|
|
1967
|
+
): Promise<{ receipt: SessionCommandReceiptRow; replay: boolean }> {
|
|
1968
|
+
await lockSessionPromptCommandOperation(db, input);
|
|
1969
|
+
const existingReceipts = await findPromptCommandReceipts(db, {
|
|
1970
|
+
workspaceId: input.workspaceId,
|
|
1971
|
+
actor: input.actor,
|
|
1972
|
+
operationKey: input.operationKey,
|
|
1973
|
+
lock: "update",
|
|
1974
|
+
});
|
|
1975
|
+
const fingerprinted = fingerprintedPromptCommandReceipt(existingReceipts);
|
|
1976
|
+
if (fingerprinted) {
|
|
1977
|
+
assertPromptCommandReceiptIdentity(fingerprinted, input);
|
|
1978
|
+
return { receipt: fingerprinted, replay: true };
|
|
1979
|
+
}
|
|
1980
|
+
const legacyExact = existingReceipts.find(
|
|
1981
|
+
(receipt) =>
|
|
1982
|
+
receipt.action === input.action &&
|
|
1983
|
+
receipt.targetSessionId === input.targetSessionId &&
|
|
1984
|
+
receipt.targetTurnId === null,
|
|
1985
|
+
);
|
|
1986
|
+
if (legacyExact) {
|
|
1987
|
+
if (legacyExact.canonicalRequestHash !== input.canonicalRequestHash) {
|
|
1988
|
+
throw new SessionCommandIdempotencyError();
|
|
1989
|
+
}
|
|
1990
|
+
return { receipt: legacyExact, replay: true };
|
|
1991
|
+
}
|
|
1992
|
+
return await reserveSessionCommandReceipt(db, {
|
|
1993
|
+
accountId: input.accountId,
|
|
1994
|
+
workspaceId: input.workspaceId,
|
|
1995
|
+
actor: input.actor,
|
|
1996
|
+
action: input.action,
|
|
1997
|
+
targetSessionId: input.targetSessionId,
|
|
1998
|
+
targetTurnId: null,
|
|
1999
|
+
operationKey: input.operationKey,
|
|
2000
|
+
canonicalRequestHash: input.canonicalRequestHash,
|
|
2001
|
+
...(existingReceipts.length === 0
|
|
2002
|
+
? { initialResult: { boundaryRequestHash: input.boundaryRequestHash } }
|
|
2003
|
+
: {}),
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
/** Serialize one actor-scoped prompt operation before replay or reservation. */
|
|
2008
|
+
export async function lockSessionPromptCommandOperation(
|
|
2009
|
+
db: Database,
|
|
2010
|
+
input: {
|
|
2011
|
+
workspaceId: string;
|
|
2012
|
+
actor: SessionCommandActor;
|
|
2013
|
+
operationKey: string;
|
|
2014
|
+
},
|
|
2015
|
+
): Promise<void> {
|
|
2016
|
+
const actorIdentity =
|
|
2017
|
+
input.actor.type === "agent_attempt"
|
|
2018
|
+
? `attempt:${input.actor.attemptId}`
|
|
2019
|
+
: `${input.actor.type}:${input.actor.subjectId}`;
|
|
2020
|
+
await db.execute(
|
|
2021
|
+
sql`select pg_advisory_xact_lock(hashtextextended(${`session-prompt:${input.workspaceId}:${actorIdentity}:${input.operationKey}`}, 0))`,
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
/** Return only a fully committed exact prompt receipt with the new boundary fingerprint. */
|
|
2026
|
+
export async function getCompletedSessionPromptCommandReceipt(
|
|
2027
|
+
db: Database,
|
|
2028
|
+
input: {
|
|
2029
|
+
workspaceId: string;
|
|
2030
|
+
actor: SessionCommandActor;
|
|
2031
|
+
action: SessionPromptCommandAction;
|
|
2032
|
+
targetSessionId: string;
|
|
2033
|
+
operationKey: string;
|
|
2034
|
+
boundaryRequestHash: string;
|
|
2035
|
+
},
|
|
2036
|
+
): Promise<SessionCommandReceiptRow | null> {
|
|
2037
|
+
const receipt = fingerprintedPromptCommandReceipt(
|
|
2038
|
+
await findPromptCommandReceipts(db, {
|
|
2039
|
+
workspaceId: input.workspaceId,
|
|
2040
|
+
actor: input.actor,
|
|
2041
|
+
operationKey: input.operationKey,
|
|
2042
|
+
}),
|
|
2043
|
+
);
|
|
2044
|
+
if (!receipt) return null;
|
|
2045
|
+
assertPromptCommandReceiptIdentity(receipt, input);
|
|
2046
|
+
if (
|
|
2047
|
+
typeof receipt.result.boundaryRequestHash !== "string" ||
|
|
2048
|
+
receipt.appliedQueueVersion === null
|
|
2049
|
+
) {
|
|
2050
|
+
return null;
|
|
2051
|
+
}
|
|
2052
|
+
return receipt;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
1887
2055
|
export async function reserveSessionCommandReceipt(
|
|
1888
2056
|
db: Database,
|
|
1889
2057
|
input: {
|
|
@@ -1896,6 +2064,7 @@ export async function reserveSessionCommandReceipt(
|
|
|
1896
2064
|
operationKey: string;
|
|
1897
2065
|
canonicalRequestHash: string;
|
|
1898
2066
|
identityScope?: "actor" | "goal_operation";
|
|
2067
|
+
initialResult?: Record<string, unknown>;
|
|
1899
2068
|
},
|
|
1900
2069
|
): Promise<{ receipt: SessionCommandReceiptRow; replay: boolean }> {
|
|
1901
2070
|
if (!input.operationKey.trim()) throw new Error("operationKey must not be empty");
|
|
@@ -1926,6 +2095,7 @@ export async function reserveSessionCommandReceipt(
|
|
|
1926
2095
|
targetTurnId: input.targetTurnId,
|
|
1927
2096
|
operationKey: input.operationKey,
|
|
1928
2097
|
canonicalRequestHash: input.canonicalRequestHash,
|
|
2098
|
+
result: input.initialResult ?? {},
|
|
1929
2099
|
})
|
|
1930
2100
|
.onConflictDoNothing()
|
|
1931
2101
|
.returning();
|
|
@@ -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;
|
|
@@ -1608,6 +1727,8 @@ export async function submitHumanPromptInTransaction(
|
|
|
1608
1727
|
subjectLabel?: string;
|
|
1609
1728
|
actor: SessionCommandActor;
|
|
1610
1729
|
operationKey: string;
|
|
1730
|
+
/** Stable parsed boundary-request identity used before mutable enrichment. */
|
|
1731
|
+
boundaryRequestHash?: string;
|
|
1611
1732
|
delivery: "send" | "steer";
|
|
1612
1733
|
controlEtag?: string | null;
|
|
1613
1734
|
expectedDraftRevision?: number | null;
|
|
@@ -1642,6 +1763,9 @@ export async function submitHumanPromptInTransaction(
|
|
|
1642
1763
|
id: string;
|
|
1643
1764
|
headersEncrypted: Record<string, string>;
|
|
1644
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>;
|
|
1645
1769
|
/** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
|
|
1646
1770
|
controlLockTimeoutMs?: number;
|
|
1647
1771
|
},
|
|
@@ -1708,91 +1832,41 @@ export async function submitHumanPromptInTransaction(
|
|
|
1708
1832
|
}
|
|
1709
1833
|
: {}),
|
|
1710
1834
|
});
|
|
1711
|
-
const
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
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
|
+
});
|
|
1721
1857
|
if (reserved.replay && reserved.receipt.appliedQueueVersion !== null) {
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
:
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
}
|
|
1731
|
-
const replayEvents = await db
|
|
1732
|
-
.select()
|
|
1733
|
-
.from(schema.sessionEvents)
|
|
1734
|
-
.where(
|
|
1735
|
-
and(
|
|
1736
|
-
eq(schema.sessionEvents.workspaceId, input.workspaceId),
|
|
1737
|
-
eq(schema.sessionEvents.sessionId, input.sessionId),
|
|
1738
|
-
inArray(schema.sessionEvents.id, eventIds),
|
|
1739
|
-
),
|
|
1740
|
-
)
|
|
1741
|
-
.orderBy(asc(schema.sessionEvents.sequence));
|
|
1742
|
-
const [replayTurn] = await db
|
|
1743
|
-
.select()
|
|
1744
|
-
.from(schema.sessionTurns)
|
|
1745
|
-
.where(
|
|
1746
|
-
and(
|
|
1747
|
-
eq(schema.sessionTurns.workspaceId, input.workspaceId),
|
|
1748
|
-
eq(schema.sessionTurns.sessionId, input.sessionId),
|
|
1749
|
-
eq(schema.sessionTurns.id, turnId),
|
|
1750
|
-
),
|
|
1751
|
-
)
|
|
1752
|
-
.limit(1);
|
|
1753
|
-
const events = replayEvents.map(mapSubmittedPromptEvent);
|
|
1754
|
-
const accepted = events.find((event) => event.id === acceptedEventId);
|
|
1755
|
-
if (!accepted || !replayTurn || events.length !== eventIds.length) {
|
|
1756
|
-
throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
|
|
1757
|
-
}
|
|
1758
|
-
const replayDraft =
|
|
1759
|
-
input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
|
|
1760
|
-
? null
|
|
1761
|
-
: await getComposerDraftInTransaction(db, {
|
|
1762
|
-
workspaceId: input.workspaceId,
|
|
1763
|
-
sessionId: input.sessionId,
|
|
1764
|
-
subjectId: input.subjectId,
|
|
1765
|
-
});
|
|
1766
|
-
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
|
+
: {}),
|
|
1767
1866
|
receipt: reserved.receipt,
|
|
1768
|
-
|
|
1769
|
-
reserved.receipt.result.routing === "accepted_for_execution" ||
|
|
1770
|
-
reserved.receipt.result.routing === "queued_for_execution" ||
|
|
1771
|
-
reserved.receipt.result.routing === "accepted_for_steering"
|
|
1772
|
-
? reserved.receipt.result.routing
|
|
1773
|
-
: input.delivery === "steer"
|
|
1774
|
-
? "accepted_for_steering"
|
|
1775
|
-
: // Pre-routing receipts cannot reconstruct admission-time activity
|
|
1776
|
-
// or Pause truth. Queue is the only conservative placement; a
|
|
1777
|
-
// later turn.started event moves it into chat without duplication.
|
|
1778
|
-
"queued_for_execution",
|
|
1779
|
-
queueVersion: Number(reserved.receipt.appliedQueueVersion),
|
|
1780
|
-
accepted,
|
|
1781
|
-
events,
|
|
1782
|
-
turn: mapSubmittedPromptTurn(replayTurn),
|
|
1783
|
-
draft: replayDraft,
|
|
1784
|
-
acceptedEventId,
|
|
1785
|
-
eventIds,
|
|
1786
|
-
turnId,
|
|
1787
|
-
wakeRevision,
|
|
1788
|
-
interruptionCount: Number(reserved.receipt.result.interruptionCount ?? 0),
|
|
1789
|
-
workspaceControlEventId:
|
|
1790
|
-
typeof reserved.receipt.result.workspaceControlEventId === "string"
|
|
1791
|
-
? reserved.receipt.result.workspaceControlEventId
|
|
1792
|
-
: null,
|
|
1793
|
-
replay: true,
|
|
1794
|
-
};
|
|
1867
|
+
});
|
|
1795
1868
|
}
|
|
1869
|
+
await input.beforeFreshPromptCommit?.(db);
|
|
1796
1870
|
|
|
1797
1871
|
const before = await evaluateSessionControl(db, input.workspaceId, input.sessionId, {
|
|
1798
1872
|
workspaceControl,
|
|
@@ -2434,6 +2508,7 @@ export async function submitHumanPromptInTransaction(
|
|
|
2434
2508
|
turnVersion: turn.version,
|
|
2435
2509
|
...(nextDraft ? { draftRevision: nextDraft.revision } : {}),
|
|
2436
2510
|
result: {
|
|
2511
|
+
...(input.boundaryRequestHash ? { boundaryRequestHash: input.boundaryRequestHash } : {}),
|
|
2437
2512
|
turnId,
|
|
2438
2513
|
acceptedEventId,
|
|
2439
2514
|
eventIds,
|
package/src/xai-subscription.ts
CHANGED
|
@@ -472,20 +472,72 @@ export async function workspaceXaiSubscriptionActive(
|
|
|
472
472
|
workspaceId,
|
|
473
473
|
subjectId,
|
|
474
474
|
});
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
475
|
+
return await workspaceXaiSubscriptionActiveForAuthority(db, settings, {
|
|
476
|
+
workspaceId,
|
|
477
|
+
subjectId,
|
|
478
|
+
authoritySnapshot,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** Metadata-only readiness for the exact provider-account authority frozen on a turn. */
|
|
483
|
+
export async function workspaceXaiSubscriptionActiveForAuthority(
|
|
484
|
+
db: Database,
|
|
485
|
+
settings: { readonly supergrokSubscriptionEnabled: boolean },
|
|
486
|
+
input: {
|
|
487
|
+
workspaceId: string;
|
|
488
|
+
subjectId: string;
|
|
489
|
+
authoritySnapshot: XaiAuthoritySnapshot;
|
|
490
|
+
},
|
|
491
|
+
): Promise<boolean> {
|
|
492
|
+
if (!settings.supergrokSubscriptionEnabled) return false;
|
|
493
|
+
const snapshot = XaiProviderAccountAuthoritySnapshotV1.parse(input.authoritySnapshot);
|
|
494
|
+
return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
|
|
495
|
+
const ownerMembershipId = await resolveXaiPoolOwnerMembershipId(scopedDb, {
|
|
496
|
+
workspaceId: input.workspaceId,
|
|
497
|
+
subjectId: input.subjectId,
|
|
498
|
+
authoritySnapshot: snapshot,
|
|
499
|
+
});
|
|
500
|
+
const ownerPredicate =
|
|
501
|
+
ownerMembershipId === null
|
|
502
|
+
? isNull(schema.xaiSubscriptionCredentials.ownerOrganizationMembershipId)
|
|
503
|
+
: eq(schema.xaiSubscriptionCredentials.ownerOrganizationMembershipId, ownerMembershipId);
|
|
504
|
+
const [accounts, rotation] = await Promise.all([
|
|
505
|
+
scopedDb
|
|
506
|
+
.select(xaiCredentialMetadataColumns)
|
|
507
|
+
.from(schema.xaiSubscriptionCredentials)
|
|
508
|
+
.where(
|
|
509
|
+
and(
|
|
510
|
+
eq(schema.xaiSubscriptionCredentials.workspaceId, input.workspaceId),
|
|
511
|
+
eq(schema.xaiSubscriptionCredentials.authorityScope, snapshot.scope),
|
|
512
|
+
ownerPredicate,
|
|
513
|
+
),
|
|
514
|
+
),
|
|
515
|
+
scopedDb
|
|
516
|
+
.select()
|
|
517
|
+
.from(schema.xaiRotationSettings)
|
|
518
|
+
.where(
|
|
519
|
+
and(
|
|
520
|
+
eq(schema.xaiRotationSettings.workspaceId, input.workspaceId),
|
|
521
|
+
eq(schema.xaiRotationSettings.authorityScope, snapshot.scope),
|
|
522
|
+
ownerMembershipId === null
|
|
523
|
+
? isNull(schema.xaiRotationSettings.ownerOrganizationMembershipId)
|
|
524
|
+
: eq(schema.xaiRotationSettings.ownerOrganizationMembershipId, ownerMembershipId),
|
|
525
|
+
),
|
|
526
|
+
)
|
|
527
|
+
.limit(1)
|
|
528
|
+
.then((rows) => rows[0] ?? null),
|
|
529
|
+
]);
|
|
530
|
+
const activeCredentialId = rotation?.activeCredentialId ?? null;
|
|
531
|
+
const now = new Date();
|
|
532
|
+
const eligible = (account: XaiCredentialMetadataRow) =>
|
|
533
|
+
account.status === "active" &&
|
|
534
|
+
account.allocatorEnabled &&
|
|
535
|
+
(!account.exhaustedUntil || account.exhaustedUntil <= now);
|
|
536
|
+
if (rotation?.rotationEnabled !== false) {
|
|
537
|
+
return accounts.some(eligible);
|
|
538
|
+
}
|
|
539
|
+
return accounts.some((account) => account.id === activeCredentialId && eligible(account));
|
|
540
|
+
});
|
|
489
541
|
}
|
|
490
542
|
|
|
491
543
|
export async function getXaiSubscriptionAccountMetadata(
|