@opengeni/db 0.13.1 → 0.14.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/{chunk-N4WTE6SB.js → chunk-PQKVUWQW.js} +20 -6
- package/dist/chunk-PQKVUWQW.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +817 -288
- package/dist/index.js.map +1 -1
- package/dist/provision-roles.d.ts +94 -13
- package/dist/{schema-D-hyrsFt.d.ts → schema-FoPub9yt.d.ts} +70 -15
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +1 -1
- package/drizzle/0132_connection_subject_isolation.sql +100 -0
- package/drizzle/0133_session_skills.sql +3 -0
- package/drizzle/0134_session_first_party_mcp_tools.sql +15 -0
- package/drizzle/0135_durable_machine_input_batches.sql +359 -0
- package/package.json +3 -3
- package/src/connection-token-resolver.ts +17 -7
- package/src/index.ts +1095 -344
- package/src/schema.ts +26 -6
- package/src/session-queue-commands.ts +22 -14
- package/dist/chunk-N4WTE6SB.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
workspaceVariableSetVariables,
|
|
77
77
|
workspaceVariableSets,
|
|
78
78
|
workspaces
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-PQKVUWQW.js";
|
|
80
80
|
import {
|
|
81
81
|
migrate,
|
|
82
82
|
runMigrations
|
|
@@ -119,6 +119,7 @@ import {
|
|
|
119
119
|
RigChange as RigChangeContract,
|
|
120
120
|
SessionGoal as SessionGoalContract,
|
|
121
121
|
SessionSystemUpdatePayload,
|
|
122
|
+
sessionSystemUpdateBatchHistoryItem,
|
|
122
123
|
HostEventExport as HostEventExportContract,
|
|
123
124
|
HostEventExportBatch as HostEventExportBatchContract,
|
|
124
125
|
HostExportConsumerId,
|
|
@@ -2892,14 +2893,6 @@ async function supersedeSessionCurrentDirectionInTransaction(db, input) {
|
|
|
2892
2893
|
finishedAt: now,
|
|
2893
2894
|
updatedAt: now
|
|
2894
2895
|
}).where(eq5(sessionTurns.id, current.id));
|
|
2895
|
-
await db.update(sessionSystemUpdates).set({ state: "pending", deliveredTurnId: null, deliveredAt: null }).where(
|
|
2896
|
-
and5(
|
|
2897
|
-
eq5(sessionSystemUpdates.workspaceId, input.workspaceId),
|
|
2898
|
-
eq5(sessionSystemUpdates.sessionId, input.sessionId),
|
|
2899
|
-
eq5(sessionSystemUpdates.deliveredTurnId, current.id),
|
|
2900
|
-
eq5(sessionSystemUpdates.state, "delivered")
|
|
2901
|
-
)
|
|
2902
|
-
);
|
|
2903
2896
|
if (current.status === "waiting_capacity") {
|
|
2904
2897
|
await db.update(codexCapacityWaiters).set({ status: "superseded", updatedAt: now }).where(
|
|
2905
2898
|
and5(
|
|
@@ -4186,14 +4179,14 @@ async function steerAgentSessionInTransaction(db, input) {
|
|
|
4186
4179
|
controlRevision: resumed.revision,
|
|
4187
4180
|
lastSequence: session.lastSequence
|
|
4188
4181
|
});
|
|
4189
|
-
await db.update(sessionSystemUpdates).set({ state: "superseded" }).where(
|
|
4182
|
+
const supersededUpdates = await db.update(sessionSystemUpdates).set({ state: "superseded" }).where(
|
|
4190
4183
|
and5(
|
|
4191
4184
|
eq5(sessionSystemUpdates.workspaceId, input.workspaceId),
|
|
4192
4185
|
eq5(sessionSystemUpdates.sessionId, input.targetSessionId),
|
|
4193
4186
|
eq5(sessionSystemUpdates.kind, "agent_steer_instruction"),
|
|
4194
|
-
|
|
4187
|
+
eq5(sessionSystemUpdates.state, "pending")
|
|
4195
4188
|
)
|
|
4196
|
-
);
|
|
4189
|
+
).returning({ id: sessionSystemUpdates.id });
|
|
4197
4190
|
const now = /* @__PURE__ */ new Date();
|
|
4198
4191
|
const [update] = await db.insert(sessionSystemUpdates).values({
|
|
4199
4192
|
accountId: input.accountId,
|
|
@@ -4252,6 +4245,22 @@ async function steerAgentSessionInTransaction(db, input) {
|
|
|
4252
4245
|
},
|
|
4253
4246
|
occurredAt: now
|
|
4254
4247
|
},
|
|
4248
|
+
...supersededUpdates.length > 0 ? [
|
|
4249
|
+
{
|
|
4250
|
+
accountId: input.accountId,
|
|
4251
|
+
workspaceId: input.workspaceId,
|
|
4252
|
+
sessionId: input.targetSessionId,
|
|
4253
|
+
sequence: ++sequence,
|
|
4254
|
+
type: "system.update.superseded",
|
|
4255
|
+
payload: {
|
|
4256
|
+
updateIds: supersededUpdates.map((entry) => entry.id),
|
|
4257
|
+
count: supersededUpdates.length,
|
|
4258
|
+
replacementUpdateId: update.id,
|
|
4259
|
+
reason: "newer_agent_steer"
|
|
4260
|
+
},
|
|
4261
|
+
occurredAt: now
|
|
4262
|
+
}
|
|
4263
|
+
] : [],
|
|
4255
4264
|
{
|
|
4256
4265
|
accountId: input.accountId,
|
|
4257
4266
|
workspaceId: input.workspaceId,
|
|
@@ -5194,11 +5203,15 @@ var REFRESH_WINDOW_MS = 6e4;
|
|
|
5194
5203
|
var CONNECTION_REFRESH_TIMEOUT_MS = 1e4;
|
|
5195
5204
|
function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
5196
5205
|
const load = async (input) => {
|
|
5206
|
+
const subjectOwned = input.connectionRef.subjectScope === "subject";
|
|
5207
|
+
if (subjectOwned && !input.subjectId) {
|
|
5208
|
+
return null;
|
|
5209
|
+
}
|
|
5197
5210
|
const request = {
|
|
5198
5211
|
workspaceId: input.workspaceId,
|
|
5199
5212
|
providerDomain: input.connectionRef.providerDomain,
|
|
5200
|
-
|
|
5201
|
-
|
|
5213
|
+
allowSubjectOwned: subjectOwned,
|
|
5214
|
+
...subjectOwned ? { subjectId: input.subjectId } : {}
|
|
5202
5215
|
};
|
|
5203
5216
|
if (input.connectionRef.connectionId !== void 0) {
|
|
5204
5217
|
request.connectionId = input.connectionRef.connectionId;
|
|
@@ -5206,10 +5219,12 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
|
5206
5219
|
if (input.connectionRef.kind !== void 0) {
|
|
5207
5220
|
request.kind = input.connectionRef.kind;
|
|
5208
5221
|
}
|
|
5209
|
-
|
|
5210
|
-
|
|
5222
|
+
const credential = await deps.loadCredential(db, settings, request);
|
|
5223
|
+
if (!credential) return null;
|
|
5224
|
+
if (subjectOwned) {
|
|
5225
|
+
return credential.subjectId === input.subjectId ? credential : null;
|
|
5211
5226
|
}
|
|
5212
|
-
return
|
|
5227
|
+
return credential.subjectId === null ? credential : null;
|
|
5213
5228
|
};
|
|
5214
5229
|
const snapshot = async (cred, ref, destinationUrl) => {
|
|
5215
5230
|
if (cred.status !== "active") {
|
|
@@ -5244,7 +5259,7 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
|
5244
5259
|
...ref.selectedResources ? { selectedResources: copySelectedResources(ref.selectedResources) } : {}
|
|
5245
5260
|
};
|
|
5246
5261
|
}
|
|
5247
|
-
await deps.recordUsed(db, cred.workspaceId, cred.id);
|
|
5262
|
+
await deps.recordUsed(db, cred.workspaceId, cred.id, cred.subjectId);
|
|
5248
5263
|
return {
|
|
5249
5264
|
status: "ok",
|
|
5250
5265
|
headers,
|
|
@@ -5264,7 +5279,8 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
|
5264
5279
|
workspaceId: cred.workspaceId,
|
|
5265
5280
|
credentialEncrypted: deps.encrypt(key, JSON.stringify(refreshed.credential)),
|
|
5266
5281
|
expiresAt: refreshed.expiresAt,
|
|
5267
|
-
lastRefreshAt: deps.now()
|
|
5282
|
+
lastRefreshAt: deps.now(),
|
|
5283
|
+
subjectId: cred.subjectId
|
|
5268
5284
|
};
|
|
5269
5285
|
if (refreshed.grantedScopes !== void 0) {
|
|
5270
5286
|
refreshRecord.grantedScopes = refreshed.grantedScopes;
|
|
@@ -5273,7 +5289,8 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
|
5273
5289
|
if (persisted) {
|
|
5274
5290
|
const current = await load({
|
|
5275
5291
|
workspaceId: cred.workspaceId,
|
|
5276
|
-
connectionRef: { ...ref, connectionId: cred.id }
|
|
5292
|
+
connectionRef: { ...ref, connectionId: cred.id },
|
|
5293
|
+
...cred.subjectId ? { subjectId: cred.subjectId } : {}
|
|
5277
5294
|
});
|
|
5278
5295
|
if (current) {
|
|
5279
5296
|
return current;
|
|
@@ -5281,7 +5298,8 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
|
5281
5298
|
}
|
|
5282
5299
|
const winner = await load({
|
|
5283
5300
|
workspaceId: cred.workspaceId,
|
|
5284
|
-
connectionRef: { ...ref, connectionId: cred.id }
|
|
5301
|
+
connectionRef: { ...ref, connectionId: cred.id },
|
|
5302
|
+
...cred.subjectId ? { subjectId: cred.subjectId } : {}
|
|
5285
5303
|
});
|
|
5286
5304
|
if (winner?.status === "active") {
|
|
5287
5305
|
return winner;
|
|
@@ -5289,7 +5307,7 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
|
5289
5307
|
throw new Error("connection credential changed during token refresh");
|
|
5290
5308
|
};
|
|
5291
5309
|
const refreshSingleFlight = (cred, ref) => {
|
|
5292
|
-
const key = `${cred.id}:${cred.version}`;
|
|
5310
|
+
const key = `${cred.subjectId ?? "workspace"}:${cred.id}:${cred.version}`;
|
|
5293
5311
|
const existing = inflight2.get(key);
|
|
5294
5312
|
if (existing) {
|
|
5295
5313
|
return existing;
|
|
@@ -5334,7 +5352,8 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
|
|
|
5334
5352
|
error instanceof Error ? error.message : String(error),
|
|
5335
5353
|
{
|
|
5336
5354
|
id: cred.id,
|
|
5337
|
-
version: cred.version
|
|
5355
|
+
version: cred.version,
|
|
5356
|
+
subjectId: cred.subjectId
|
|
5338
5357
|
}
|
|
5339
5358
|
).catch(() => void 0);
|
|
5340
5359
|
}
|
|
@@ -6151,6 +6170,17 @@ async function bootstrapWorkspace(db, input) {
|
|
|
6151
6170
|
updatedAt: /* @__PURE__ */ new Date()
|
|
6152
6171
|
}).where(eq7(workspaceMemberships.id, membership.id));
|
|
6153
6172
|
}
|
|
6173
|
+
await setRlsContext(tx, {
|
|
6174
|
+
accountId: workspace.accountId,
|
|
6175
|
+
workspaceId: null
|
|
6176
|
+
});
|
|
6177
|
+
const memberships = await tx.select({
|
|
6178
|
+
membership: workspaceMemberships,
|
|
6179
|
+
workspace: workspaces
|
|
6180
|
+
}).from(workspaceMemberships).innerJoin(
|
|
6181
|
+
workspaces,
|
|
6182
|
+
eq7(workspaceMemberships.workspaceId, workspaces.id)
|
|
6183
|
+
).where(eq7(workspaceMemberships.subjectId, input.subjectId)).orderBy(desc2(workspaces.createdAt));
|
|
6154
6184
|
return {
|
|
6155
6185
|
mode: input.accountExternalSource === "opengeni:local" ? "local" : "configured",
|
|
6156
6186
|
subjectId: input.subjectId,
|
|
@@ -6164,15 +6194,13 @@ async function bootstrapWorkspace(db, input) {
|
|
|
6164
6194
|
permissions: input.accountPermissions ?? allAccountPermissions
|
|
6165
6195
|
}
|
|
6166
6196
|
],
|
|
6167
|
-
workspaceGrants:
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
}
|
|
6175
|
-
],
|
|
6197
|
+
workspaceGrants: memberships.map((row) => ({
|
|
6198
|
+
workspaceId: row.workspace.id,
|
|
6199
|
+
accountId: row.workspace.accountId,
|
|
6200
|
+
subjectId: input.subjectId,
|
|
6201
|
+
...input.subjectLabel ? { subjectLabel: input.subjectLabel } : {},
|
|
6202
|
+
permissions: row.membership.permissions
|
|
6203
|
+
})),
|
|
6176
6204
|
defaultAccountId: account.id,
|
|
6177
6205
|
defaultWorkspaceId: workspace.id
|
|
6178
6206
|
};
|
|
@@ -8032,36 +8060,48 @@ var connectionMetadataColumns = {
|
|
|
8032
8060
|
function connectionSubjectVisibility(subjectId) {
|
|
8033
8061
|
return subjectId ? or(isNull2(connections.subjectId), eq7(connections.subjectId, subjectId)) : isNull2(connections.subjectId);
|
|
8034
8062
|
}
|
|
8063
|
+
function connectionExactSubject(subjectId) {
|
|
8064
|
+
return subjectId ? eq7(connections.subjectId, subjectId) : isNull2(connections.subjectId);
|
|
8065
|
+
}
|
|
8066
|
+
async function withConnectionSubjectRls(db, workspaceId, subjectId, fn) {
|
|
8067
|
+
return subjectId ? await withWorkspaceSubjectRls(db, workspaceId, subjectId, fn) : await withWorkspaceRls(db, workspaceId, fn);
|
|
8068
|
+
}
|
|
8069
|
+
async function createConnectionInScope(db, input) {
|
|
8070
|
+
const [row] = await db.insert(connections).values({
|
|
8071
|
+
accountId: input.accountId,
|
|
8072
|
+
workspaceId: input.workspaceId,
|
|
8073
|
+
subjectId: input.subjectId ?? null,
|
|
8074
|
+
providerDomain: input.providerDomain,
|
|
8075
|
+
kind: input.kind,
|
|
8076
|
+
status: input.status ?? "active",
|
|
8077
|
+
credentialEncrypted: input.credentialEncrypted,
|
|
8078
|
+
grantedScopes: input.grantedScopes ?? [],
|
|
8079
|
+
expiresAt: input.expiresAt ?? null,
|
|
8080
|
+
verifiedInstallAt: input.verifiedInstallAt ?? null,
|
|
8081
|
+
verifiedInstallVersion: input.verifiedInstallVersion ?? null,
|
|
8082
|
+
metadata: input.metadata ?? {},
|
|
8083
|
+
createdBySubjectId: input.createdBySubjectId ?? null,
|
|
8084
|
+
updatedBySubjectId: input.updatedBySubjectId ?? input.createdBySubjectId ?? null
|
|
8085
|
+
}).returning(connectionMetadataColumns);
|
|
8086
|
+
if (!row) {
|
|
8087
|
+
throw new Error("Failed to create connection");
|
|
8088
|
+
}
|
|
8089
|
+
return mapConnectionMetadata(row);
|
|
8090
|
+
}
|
|
8035
8091
|
async function createConnection(db, input) {
|
|
8036
8092
|
return await withRlsContext(
|
|
8037
8093
|
db,
|
|
8038
8094
|
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
8039
8095
|
async (scopedDb) => {
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
workspaceId: input.workspaceId,
|
|
8043
|
-
subjectId: input.subjectId ?? null,
|
|
8044
|
-
providerDomain: input.providerDomain,
|
|
8045
|
-
kind: input.kind,
|
|
8046
|
-
status: input.status ?? "active",
|
|
8047
|
-
credentialEncrypted: input.credentialEncrypted,
|
|
8048
|
-
grantedScopes: input.grantedScopes ?? [],
|
|
8049
|
-
expiresAt: input.expiresAt ?? null,
|
|
8050
|
-
verifiedInstallAt: input.verifiedInstallAt ?? null,
|
|
8051
|
-
verifiedInstallVersion: input.verifiedInstallVersion ?? null,
|
|
8052
|
-
metadata: input.metadata ?? {},
|
|
8053
|
-
createdBySubjectId: input.createdBySubjectId ?? null,
|
|
8054
|
-
updatedBySubjectId: input.updatedBySubjectId ?? input.createdBySubjectId ?? null
|
|
8055
|
-
}).returning(connectionMetadataColumns);
|
|
8056
|
-
if (!row) {
|
|
8057
|
-
throw new Error("Failed to create connection");
|
|
8096
|
+
if (input.subjectId) {
|
|
8097
|
+
await setSubjectRlsContext(scopedDb, input.subjectId);
|
|
8058
8098
|
}
|
|
8059
|
-
return
|
|
8099
|
+
return await createConnectionInScope(scopedDb, input);
|
|
8060
8100
|
}
|
|
8061
8101
|
);
|
|
8062
8102
|
}
|
|
8063
8103
|
async function listConnectionsMetadata(db, workspaceId, subjectId) {
|
|
8064
|
-
return await
|
|
8104
|
+
return await withConnectionSubjectRls(db, workspaceId, subjectId, async (scopedDb) => {
|
|
8065
8105
|
const rows = await scopedDb.select(connectionMetadataColumns).from(connections).where(
|
|
8066
8106
|
and7(
|
|
8067
8107
|
eq7(connections.workspaceId, workspaceId),
|
|
@@ -8072,7 +8112,7 @@ async function listConnectionsMetadata(db, workspaceId, subjectId) {
|
|
|
8072
8112
|
});
|
|
8073
8113
|
}
|
|
8074
8114
|
async function getConnectionMetadata(db, workspaceId, connectionId, subjectId) {
|
|
8075
|
-
return await
|
|
8115
|
+
return await withConnectionSubjectRls(db, workspaceId, subjectId, async (scopedDb) => {
|
|
8076
8116
|
const [row] = await scopedDb.select(connectionMetadataColumns).from(connections).where(
|
|
8077
8117
|
and7(
|
|
8078
8118
|
eq7(connections.workspaceId, workspaceId),
|
|
@@ -8083,66 +8123,217 @@ async function getConnectionMetadata(db, workspaceId, connectionId, subjectId) {
|
|
|
8083
8123
|
return row ? mapConnectionMetadata(row) : null;
|
|
8084
8124
|
});
|
|
8085
8125
|
}
|
|
8126
|
+
async function updateConnectionInScope(db, input) {
|
|
8127
|
+
const set = {
|
|
8128
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
8129
|
+
...input.providerDomain !== void 0 ? { providerDomain: input.providerDomain } : {},
|
|
8130
|
+
...input.subjectId !== void 0 ? { subjectId: input.subjectId } : {},
|
|
8131
|
+
...input.kind !== void 0 ? { kind: input.kind } : {},
|
|
8132
|
+
...input.status !== void 0 ? { status: input.status } : {},
|
|
8133
|
+
...input.credentialEncrypted !== void 0 ? {
|
|
8134
|
+
credentialEncrypted: input.credentialEncrypted,
|
|
8135
|
+
version: sql4`${connections.version} + 1`,
|
|
8136
|
+
lastError: null
|
|
8137
|
+
} : {},
|
|
8138
|
+
...input.grantedScopes !== void 0 ? { grantedScopes: input.grantedScopes } : {},
|
|
8139
|
+
...input.expiresAt !== void 0 ? { expiresAt: input.expiresAt } : {},
|
|
8140
|
+
...input.verifiedInstallAt !== void 0 ? { verifiedInstallAt: input.verifiedInstallAt } : {},
|
|
8141
|
+
...input.verifiedInstallVersion !== void 0 ? { verifiedInstallVersion: input.verifiedInstallVersion } : {},
|
|
8142
|
+
...input.metadata !== void 0 ? { metadata: input.metadata } : {},
|
|
8143
|
+
...input.updatedBySubjectId !== void 0 ? { updatedBySubjectId: input.updatedBySubjectId } : {}
|
|
8144
|
+
};
|
|
8145
|
+
const [row] = await db.update(connections).set(set).where(
|
|
8146
|
+
and7(
|
|
8147
|
+
eq7(connections.workspaceId, input.workspaceId),
|
|
8148
|
+
eq7(connections.id, input.connectionId),
|
|
8149
|
+
connectionSubjectVisibility(input.visibleToSubjectId),
|
|
8150
|
+
...input.expectedVersion !== void 0 ? [eq7(connections.version, input.expectedVersion)] : []
|
|
8151
|
+
)
|
|
8152
|
+
).returning(connectionMetadataColumns);
|
|
8153
|
+
return row ? mapConnectionMetadata(row) : null;
|
|
8154
|
+
}
|
|
8086
8155
|
async function updateConnection(db, input) {
|
|
8087
|
-
return await
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
)
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8156
|
+
return await withConnectionSubjectRls(
|
|
8157
|
+
db,
|
|
8158
|
+
input.workspaceId,
|
|
8159
|
+
input.visibleToSubjectId,
|
|
8160
|
+
async (scopedDb) => await updateConnectionInScope(scopedDb, input)
|
|
8161
|
+
);
|
|
8162
|
+
}
|
|
8163
|
+
async function revokeConnectionInScope(db, workspaceId, connectionId, updatedBySubjectId, expectedVersion) {
|
|
8164
|
+
const [row] = await db.update(connections).set({
|
|
8165
|
+
status: "revoked",
|
|
8166
|
+
// The version bump invalidates any in-flight refresh's (id, version) CAS,
|
|
8167
|
+
// so a racing refresh cannot commit and flip the row back to active.
|
|
8168
|
+
version: sql4`${connections.version} + 1`,
|
|
8169
|
+
// Status-only revocation does not replace the verified credential or bot
|
|
8170
|
+
// identity. Carry the marker to the same new CAS version so the dedicated
|
|
8171
|
+
// reinstall path can still recognize (but not use) the inactive row.
|
|
8172
|
+
verifiedInstallVersion: sql4`case
|
|
8173
|
+
when ${connections.verifiedInstallAt} is null then null
|
|
8174
|
+
else ${connections.version} + 1
|
|
8175
|
+
end`,
|
|
8176
|
+
updatedBySubjectId: updatedBySubjectId ?? null,
|
|
8177
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
8178
|
+
}).where(
|
|
8179
|
+
and7(
|
|
8180
|
+
eq7(connections.workspaceId, workspaceId),
|
|
8181
|
+
eq7(connections.id, connectionId),
|
|
8182
|
+
// Same visibility rule as get/update: shared rows plus the caller's own
|
|
8183
|
+
// subject rows. Cross-subject revocation (admin janitorial) arrives with
|
|
8184
|
+
// the subject-connections UX in I5, deliberately not before.
|
|
8185
|
+
connectionSubjectVisibility(updatedBySubjectId),
|
|
8186
|
+
...expectedVersion !== void 0 ? [eq7(connections.version, expectedVersion)] : []
|
|
8187
|
+
)
|
|
8188
|
+
).returning(connectionMetadataColumns);
|
|
8189
|
+
return row ? mapConnectionMetadata(row) : null;
|
|
8116
8190
|
}
|
|
8117
8191
|
async function revokeConnection(db, workspaceId, connectionId, updatedBySubjectId) {
|
|
8118
|
-
return await
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8192
|
+
return await withConnectionSubjectRls(
|
|
8193
|
+
db,
|
|
8194
|
+
workspaceId,
|
|
8195
|
+
updatedBySubjectId,
|
|
8196
|
+
async (scopedDb) => await revokeConnectionInScope(scopedDb, workspaceId, connectionId, updatedBySubjectId)
|
|
8197
|
+
);
|
|
8198
|
+
}
|
|
8199
|
+
var SlackBotLifecycleSuccessAuditError = class extends Error {
|
|
8200
|
+
constructor() {
|
|
8201
|
+
super("OpenGeni Slack bot lifecycle success audit failed");
|
|
8202
|
+
this.name = "SlackBotLifecycleSuccessAuditError";
|
|
8203
|
+
}
|
|
8204
|
+
};
|
|
8205
|
+
async function insertSlackBotLifecycleSuccessAuditInScope(db, input) {
|
|
8206
|
+
try {
|
|
8207
|
+
await db.insert(auditEvents).values({
|
|
8208
|
+
accountId: input.accountId,
|
|
8209
|
+
workspaceId: input.workspaceId,
|
|
8210
|
+
subjectId: input.subjectId,
|
|
8211
|
+
action: input.action,
|
|
8212
|
+
targetType: "connection",
|
|
8213
|
+
targetId: input.connectionId,
|
|
8214
|
+
metadata: {
|
|
8215
|
+
credentialRole: input.credentialRole,
|
|
8216
|
+
credentialLabel: input.credentialLabel,
|
|
8217
|
+
connectionId: input.connectionId,
|
|
8218
|
+
slackTeamId: input.slackTeamId,
|
|
8219
|
+
outcome: "succeeded"
|
|
8220
|
+
}
|
|
8221
|
+
});
|
|
8222
|
+
} catch {
|
|
8223
|
+
throw new SlackBotLifecycleSuccessAuditError();
|
|
8224
|
+
}
|
|
8225
|
+
}
|
|
8226
|
+
async function assertWorkspaceAccountPairInScope(db, accountId, workspaceId) {
|
|
8227
|
+
const [workspace] = await db.select({ id: workspaces.id }).from(workspaces).where(and7(eq7(workspaces.id, workspaceId), eq7(workspaces.accountId, accountId))).limit(1);
|
|
8228
|
+
if (!workspace) {
|
|
8229
|
+
throw new Error("Workspace does not belong to the expected account");
|
|
8230
|
+
}
|
|
8231
|
+
}
|
|
8232
|
+
async function withSlackBotLifecycleRls(db, input, fn) {
|
|
8233
|
+
return await withRlsContext(
|
|
8234
|
+
db,
|
|
8235
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
8236
|
+
async (scopedDb) => {
|
|
8237
|
+
await setSubjectRlsContext(scopedDb, input.subjectId);
|
|
8238
|
+
await assertWorkspaceAccountPairInScope(scopedDb, input.accountId, input.workspaceId);
|
|
8239
|
+
return await fn(scopedDb);
|
|
8240
|
+
}
|
|
8241
|
+
);
|
|
8242
|
+
}
|
|
8243
|
+
async function createConnectionWithSlackBotSuccessAudit(db, input) {
|
|
8244
|
+
if (input.connection.accountId !== input.accountId || input.connection.workspaceId !== input.workspaceId) {
|
|
8245
|
+
throw new Error("Slack bot connection and lifecycle audit tenant must match");
|
|
8246
|
+
}
|
|
8247
|
+
return await withSlackBotLifecycleRls(db, input, async (scopedDb) => {
|
|
8248
|
+
const connection = await createConnectionInScope(scopedDb, input.connection);
|
|
8249
|
+
await insertSlackBotLifecycleSuccessAuditInScope(scopedDb, {
|
|
8250
|
+
...input,
|
|
8251
|
+
action: "slack_bot.connected",
|
|
8252
|
+
connectionId: connection.id
|
|
8253
|
+
});
|
|
8254
|
+
return connection;
|
|
8144
8255
|
});
|
|
8145
8256
|
}
|
|
8257
|
+
async function updateConnectionWithSlackBotSuccessAudit(db, input) {
|
|
8258
|
+
if (input.connection.workspaceId !== input.workspaceId) {
|
|
8259
|
+
throw new Error("Slack bot connection and lifecycle audit workspace must match");
|
|
8260
|
+
}
|
|
8261
|
+
return await withSlackBotLifecycleRls(db, input, async (scopedDb) => {
|
|
8262
|
+
const connection = await updateConnectionInScope(scopedDb, input.connection);
|
|
8263
|
+
if (!connection) return null;
|
|
8264
|
+
if (connection.accountId !== input.accountId) {
|
|
8265
|
+
throw new Error("Slack bot connection and lifecycle audit account must match");
|
|
8266
|
+
}
|
|
8267
|
+
await insertSlackBotLifecycleSuccessAuditInScope(scopedDb, {
|
|
8268
|
+
...input,
|
|
8269
|
+
action: "slack_bot.reinstalled",
|
|
8270
|
+
connectionId: connection.id
|
|
8271
|
+
});
|
|
8272
|
+
return connection;
|
|
8273
|
+
});
|
|
8274
|
+
}
|
|
8275
|
+
async function revokeConnectionWithSlackBotSuccessAudit(db, input) {
|
|
8276
|
+
return await withSlackBotLifecycleRls(db, input, async (scopedDb) => {
|
|
8277
|
+
const connection = await revokeConnectionInScope(
|
|
8278
|
+
scopedDb,
|
|
8279
|
+
input.workspaceId,
|
|
8280
|
+
input.connectionId,
|
|
8281
|
+
input.subjectId,
|
|
8282
|
+
input.expectedVersion
|
|
8283
|
+
);
|
|
8284
|
+
if (!connection) return null;
|
|
8285
|
+
if (connection.accountId !== input.accountId) {
|
|
8286
|
+
throw new Error("Slack bot connection and lifecycle audit account must match");
|
|
8287
|
+
}
|
|
8288
|
+
await insertSlackBotLifecycleSuccessAuditInScope(scopedDb, {
|
|
8289
|
+
...input,
|
|
8290
|
+
action: "slack_bot.disconnected",
|
|
8291
|
+
connectionId: connection.id
|
|
8292
|
+
});
|
|
8293
|
+
return connection;
|
|
8294
|
+
});
|
|
8295
|
+
}
|
|
8296
|
+
async function recordSlackBotInstallCallbackFailure(db, input) {
|
|
8297
|
+
if (!/^[a-f0-9]{64}$/.test(input.callbackDigest)) {
|
|
8298
|
+
throw new Error("Slack callback digest must be a lowercase SHA-256 value");
|
|
8299
|
+
}
|
|
8300
|
+
return await withRlsContext(
|
|
8301
|
+
db,
|
|
8302
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
8303
|
+
async (scopedDb) => {
|
|
8304
|
+
await setSubjectRlsContext(scopedDb, input.subjectId);
|
|
8305
|
+
await assertWorkspaceAccountPairInScope(scopedDb, input.accountId, input.workspaceId);
|
|
8306
|
+
await scopedDb.execute(
|
|
8307
|
+
sql4`select pg_advisory_xact_lock(hashtextextended(${`slack-callback-failure:${input.workspaceId}:${input.callbackDigest}`}, 0))`
|
|
8308
|
+
);
|
|
8309
|
+
const [existing] = await scopedDb.select({ id: auditEvents.id }).from(auditEvents).where(
|
|
8310
|
+
and7(
|
|
8311
|
+
eq7(auditEvents.accountId, input.accountId),
|
|
8312
|
+
eq7(auditEvents.workspaceId, input.workspaceId),
|
|
8313
|
+
eq7(auditEvents.action, "slack_bot.install.callback.failed"),
|
|
8314
|
+
eq7(auditEvents.targetType, "slack_oauth_callback"),
|
|
8315
|
+
eq7(auditEvents.targetId, input.callbackDigest)
|
|
8316
|
+
)
|
|
8317
|
+
).limit(1);
|
|
8318
|
+
if (existing) return false;
|
|
8319
|
+
await scopedDb.insert(auditEvents).values({
|
|
8320
|
+
accountId: input.accountId,
|
|
8321
|
+
workspaceId: input.workspaceId,
|
|
8322
|
+
subjectId: input.subjectId,
|
|
8323
|
+
action: "slack_bot.install.callback.failed",
|
|
8324
|
+
targetType: "slack_oauth_callback",
|
|
8325
|
+
targetId: input.callbackDigest,
|
|
8326
|
+
metadata: {
|
|
8327
|
+
outcome: "failed",
|
|
8328
|
+
installMode: input.installMode,
|
|
8329
|
+
stage: input.stage,
|
|
8330
|
+
reason: input.reason
|
|
8331
|
+
}
|
|
8332
|
+
});
|
|
8333
|
+
return true;
|
|
8334
|
+
}
|
|
8335
|
+
);
|
|
8336
|
+
}
|
|
8146
8337
|
async function claimSlackBotPostOperation(db, input) {
|
|
8147
8338
|
const claimLeaseMs = Math.max(1, Math.min(Math.trunc(input.claimLeaseMs), 12e4));
|
|
8148
8339
|
return await withRlsContext(
|
|
@@ -8302,13 +8493,16 @@ async function getSlackBotPostOperation(db, workspaceId, connectionId, operation
|
|
|
8302
8493
|
});
|
|
8303
8494
|
}
|
|
8304
8495
|
async function loadConnectionCredentialForBroker(db, settings, input) {
|
|
8496
|
+
if (input.allowSubjectOwned && !input.subjectId) {
|
|
8497
|
+
return null;
|
|
8498
|
+
}
|
|
8305
8499
|
const key = environmentsEncryptionKeyBytes3(settings);
|
|
8306
8500
|
if (!key) {
|
|
8307
8501
|
throw new Error(
|
|
8308
8502
|
"connection credential present but OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured"
|
|
8309
8503
|
);
|
|
8310
8504
|
}
|
|
8311
|
-
const subjectPredicate = input.allowSubjectOwned ?
|
|
8505
|
+
const subjectPredicate = input.allowSubjectOwned ? connectionExactSubject(input.subjectId) : isNull2(connections.subjectId);
|
|
8312
8506
|
const conditions = [
|
|
8313
8507
|
eq7(connections.workspaceId, input.workspaceId),
|
|
8314
8508
|
subjectPredicate
|
|
@@ -8321,70 +8515,81 @@ async function loadConnectionCredentialForBroker(db, settings, input) {
|
|
|
8321
8515
|
conditions.push(eq7(connections.kind, input.kind));
|
|
8322
8516
|
}
|
|
8323
8517
|
}
|
|
8324
|
-
return await
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
)
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8518
|
+
return await withConnectionSubjectRls(
|
|
8519
|
+
db,
|
|
8520
|
+
input.workspaceId,
|
|
8521
|
+
input.allowSubjectOwned ? input.subjectId : null,
|
|
8522
|
+
async (scopedDb) => {
|
|
8523
|
+
const [row] = await scopedDb.select().from(connections).where(and7(...conditions)).orderBy(
|
|
8524
|
+
desc2(sql4`(${connections.status} = 'active')`),
|
|
8525
|
+
desc2(connections.updatedAt)
|
|
8526
|
+
).limit(1);
|
|
8527
|
+
if (!row) {
|
|
8528
|
+
return null;
|
|
8529
|
+
}
|
|
8530
|
+
let credential;
|
|
8531
|
+
try {
|
|
8532
|
+
credential = JSON.parse(decryptEnvironmentValue(key, row.credentialEncrypted));
|
|
8533
|
+
} catch (error) {
|
|
8534
|
+
throw new Error(
|
|
8535
|
+
`connection credential could not be decrypted for ${row.id}: ${error instanceof Error ? error.message : String(error)}`,
|
|
8536
|
+
{ cause: error }
|
|
8537
|
+
);
|
|
8538
|
+
}
|
|
8539
|
+
if (!credential || typeof credential !== "object" || Array.isArray(credential)) {
|
|
8540
|
+
throw new Error(`connection credential bundle for ${row.id} is not a JSON object`);
|
|
8541
|
+
}
|
|
8542
|
+
return {
|
|
8543
|
+
id: row.id,
|
|
8544
|
+
accountId: row.accountId,
|
|
8545
|
+
workspaceId: row.workspaceId,
|
|
8546
|
+
subjectId: row.subjectId,
|
|
8547
|
+
providerDomain: row.providerDomain,
|
|
8548
|
+
kind: row.kind,
|
|
8549
|
+
status: row.status,
|
|
8550
|
+
credential,
|
|
8551
|
+
grantedScopes: row.grantedScopes,
|
|
8552
|
+
expiresAt: row.expiresAt,
|
|
8553
|
+
lastRefreshAt: row.lastRefreshAt,
|
|
8554
|
+
version: row.version,
|
|
8555
|
+
metadata: row.metadata
|
|
8556
|
+
};
|
|
8343
8557
|
}
|
|
8344
|
-
|
|
8345
|
-
id: row.id,
|
|
8346
|
-
accountId: row.accountId,
|
|
8347
|
-
workspaceId: row.workspaceId,
|
|
8348
|
-
subjectId: row.subjectId,
|
|
8349
|
-
providerDomain: row.providerDomain,
|
|
8350
|
-
kind: row.kind,
|
|
8351
|
-
status: row.status,
|
|
8352
|
-
credential,
|
|
8353
|
-
grantedScopes: row.grantedScopes,
|
|
8354
|
-
expiresAt: row.expiresAt,
|
|
8355
|
-
lastRefreshAt: row.lastRefreshAt,
|
|
8356
|
-
version: row.version,
|
|
8357
|
-
metadata: row.metadata
|
|
8358
|
-
};
|
|
8359
|
-
});
|
|
8558
|
+
);
|
|
8360
8559
|
}
|
|
8361
8560
|
async function recordConnectionTokenRefresh(db, input) {
|
|
8362
|
-
return await
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8561
|
+
return await withConnectionSubjectRls(
|
|
8562
|
+
db,
|
|
8563
|
+
input.workspaceId,
|
|
8564
|
+
input.subjectId,
|
|
8565
|
+
async (scopedDb) => {
|
|
8566
|
+
const set = {
|
|
8567
|
+
credentialEncrypted: input.credentialEncrypted,
|
|
8568
|
+
expiresAt: input.expiresAt,
|
|
8569
|
+
lastRefreshAt: input.lastRefreshAt,
|
|
8570
|
+
status: "active",
|
|
8571
|
+
lastError: null,
|
|
8572
|
+
version: sql4`${connections.version} + 1`,
|
|
8573
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
8574
|
+
...input.grantedScopes !== void 0 ? { grantedScopes: input.grantedScopes } : {}
|
|
8575
|
+
};
|
|
8576
|
+
const updated = await scopedDb.update(connections).set(set).where(
|
|
8577
|
+
and7(
|
|
8578
|
+
eq7(connections.id, input.id),
|
|
8579
|
+
eq7(connections.workspaceId, input.workspaceId),
|
|
8580
|
+
eq7(connections.version, input.version),
|
|
8581
|
+
connectionExactSubject(input.subjectId),
|
|
8582
|
+
// A refresh may only ever renew a live credential; revoked/errored rows
|
|
8583
|
+
// stay dead even if a status change somewhere forgot to bump version.
|
|
8584
|
+
eq7(connections.status, "active")
|
|
8585
|
+
)
|
|
8586
|
+
).returning({ id: connections.id });
|
|
8587
|
+
return updated.length > 0;
|
|
8588
|
+
}
|
|
8589
|
+
);
|
|
8385
8590
|
}
|
|
8386
8591
|
async function setConnectionStatus(db, workspaceId, status, lastError, guard) {
|
|
8387
|
-
return await
|
|
8592
|
+
return await withConnectionSubjectRls(db, workspaceId, guard.subjectId, async (scopedDb) => {
|
|
8388
8593
|
const updated = await scopedDb.update(connections).set({
|
|
8389
8594
|
status,
|
|
8390
8595
|
lastError,
|
|
@@ -8398,21 +8603,23 @@ async function setConnectionStatus(db, workspaceId, status, lastError, guard) {
|
|
|
8398
8603
|
and7(
|
|
8399
8604
|
eq7(connections.workspaceId, workspaceId),
|
|
8400
8605
|
eq7(connections.id, guard.id),
|
|
8401
|
-
eq7(connections.version, guard.version)
|
|
8606
|
+
eq7(connections.version, guard.version),
|
|
8607
|
+
connectionExactSubject(guard.subjectId)
|
|
8402
8608
|
)
|
|
8403
8609
|
).returning({ id: connections.id });
|
|
8404
8610
|
return updated.length > 0;
|
|
8405
8611
|
});
|
|
8406
8612
|
}
|
|
8407
|
-
async function recordConnectionUsed(db, workspaceId, connectionId) {
|
|
8408
|
-
await
|
|
8613
|
+
async function recordConnectionUsed(db, workspaceId, connectionId, subjectId) {
|
|
8614
|
+
await withConnectionSubjectRls(db, workspaceId, subjectId, async (scopedDb) => {
|
|
8409
8615
|
await scopedDb.update(connections).set({
|
|
8410
8616
|
lastUsedAt: /* @__PURE__ */ new Date(),
|
|
8411
8617
|
updatedAt: /* @__PURE__ */ new Date()
|
|
8412
8618
|
}).where(
|
|
8413
8619
|
and7(
|
|
8414
8620
|
eq7(connections.workspaceId, workspaceId),
|
|
8415
|
-
eq7(connections.id, connectionId)
|
|
8621
|
+
eq7(connections.id, connectionId),
|
|
8622
|
+
connectionExactSubject(subjectId)
|
|
8416
8623
|
)
|
|
8417
8624
|
);
|
|
8418
8625
|
});
|
|
@@ -13536,6 +13743,7 @@ async function createSessionInTransaction(tx, input, id) {
|
|
|
13536
13743
|
initialMessage: input.initialMessage,
|
|
13537
13744
|
initialTurnInstructions: input.initialTurnInstructions ?? null,
|
|
13538
13745
|
resources: input.resources,
|
|
13746
|
+
skills: input.skills ?? [],
|
|
13539
13747
|
tools: input.tools ?? [],
|
|
13540
13748
|
toolPolicy: input.toolPolicy ?? null,
|
|
13541
13749
|
metadata: input.metadata,
|
|
@@ -13548,6 +13756,7 @@ async function createSessionInTransaction(tx, input, id) {
|
|
|
13548
13756
|
rigId: input.rigId ?? null,
|
|
13549
13757
|
rigVersionId: input.rigVersionId ?? null,
|
|
13550
13758
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
13759
|
+
firstPartyMcpTools: input.firstPartyMcpTools ?? null,
|
|
13551
13760
|
instructions: input.instructions ?? null,
|
|
13552
13761
|
parentSessionId: input.parentSessionId ?? null,
|
|
13553
13762
|
createIdempotencyKey,
|
|
@@ -14852,25 +15061,34 @@ async function getSessionLineage(db, workspaceId, sessionId) {
|
|
|
14852
15061
|
if (rootRows.length === 0) {
|
|
14853
15062
|
return null;
|
|
14854
15063
|
}
|
|
14855
|
-
const
|
|
14856
|
-
with recursive ancestors(id, parent_session_id, depth, path) as (
|
|
14857
|
-
select ${sessions.id}, ${sessions.parentSessionId}, 0, array[${sessions.id}]
|
|
15064
|
+
const ancestorLineageRows = await scopedDb.execute(sql4`
|
|
15065
|
+
with recursive ancestors(id, parent_session_id, depth, path, cycle) as (
|
|
15066
|
+
select ${sessions.id}, ${sessions.parentSessionId}, 0, array[${sessions.id}], false
|
|
14858
15067
|
from ${sessions}
|
|
14859
15068
|
where ${sessions.workspaceId} = ${workspaceId}
|
|
14860
15069
|
and ${sessions.id} = ${sessionId}
|
|
14861
15070
|
union all
|
|
14862
|
-
select
|
|
15071
|
+
select
|
|
15072
|
+
parent.id,
|
|
15073
|
+
parent.parent_session_id,
|
|
15074
|
+
ancestors.depth + 1,
|
|
15075
|
+
ancestors.path || parent.id,
|
|
15076
|
+
parent.id = any(ancestors.path)
|
|
14863
15077
|
from ${sessions} parent
|
|
14864
15078
|
join ancestors on ancestors.parent_session_id = parent.id
|
|
14865
15079
|
where parent.workspace_id = ${workspaceId}
|
|
14866
|
-
and ancestors.
|
|
14867
|
-
and
|
|
15080
|
+
and not ancestors.cycle
|
|
15081
|
+
and ancestors.depth < 64
|
|
14868
15082
|
)
|
|
14869
|
-
select id, parent_session_id as "parentSessionId", depth, path
|
|
15083
|
+
select id, parent_session_id as "parentSessionId", depth, path, cycle
|
|
14870
15084
|
from ancestors
|
|
14871
|
-
where depth > 0
|
|
14872
15085
|
order by depth desc
|
|
14873
15086
|
`);
|
|
15087
|
+
const frontier = ancestorLineageRows[0];
|
|
15088
|
+
if (!frontier || frontier.cycle || frontier.parentSessionId !== null || Number(frontier.depth) >= 64) {
|
|
15089
|
+
throw new Error(`session lineage for ${sessionId} has no valid workspace root`);
|
|
15090
|
+
}
|
|
15091
|
+
const ancestorRows = ancestorLineageRows.filter((row) => row.depth > 0);
|
|
14874
15092
|
const childRows = await scopedDb.execute(sql4`
|
|
14875
15093
|
with recursive descendants(id, parent_session_id, depth, path) as (
|
|
14876
15094
|
select child.id, child.parent_session_id, 1, array[${sessionId}, child.id]
|
|
@@ -14885,7 +15103,7 @@ async function getSessionLineage(db, workspaceId, sessionId) {
|
|
|
14885
15103
|
and descendants.depth < 5
|
|
14886
15104
|
and not child.id = any(descendants.path)
|
|
14887
15105
|
)
|
|
14888
|
-
select id, parent_session_id as "parentSessionId", depth, path
|
|
15106
|
+
select id, parent_session_id as "parentSessionId", depth, path, false as cycle
|
|
14889
15107
|
from descendants
|
|
14890
15108
|
order by path
|
|
14891
15109
|
limit ${descendantLimit + 1}
|
|
@@ -22005,7 +22223,7 @@ async function materializeGoalContinuation(db, input) {
|
|
|
22005
22223
|
eq7(sessionSystemUpdates.workspaceId, input.workspaceId),
|
|
22006
22224
|
eq7(sessionSystemUpdates.sessionId, input.sessionId),
|
|
22007
22225
|
eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
|
|
22008
|
-
|
|
22226
|
+
eq7(sessionSystemUpdates.state, "pending")
|
|
22009
22227
|
)
|
|
22010
22228
|
).limit(1);
|
|
22011
22229
|
if (pendingSteer) {
|
|
@@ -22128,6 +22346,7 @@ async function materializeGoalContinuation(db, input) {
|
|
|
22128
22346
|
idempotencyKey: `agent_run.created:goal:${input.workspaceId}:${decision.goal.id}:${goalWakeRevision}`,
|
|
22129
22347
|
occurredAt: now
|
|
22130
22348
|
}).onConflictDoNothing({ target: usageEvents.idempotencyKey });
|
|
22349
|
+
const eventPreview = internalUpdateEventMember(update);
|
|
22131
22350
|
const insertedEvents = await tx.insert(sessionEvents).values([
|
|
22132
22351
|
{
|
|
22133
22352
|
accountId: session.accountId,
|
|
@@ -22136,11 +22355,13 @@ async function materializeGoalContinuation(db, input) {
|
|
|
22136
22355
|
sequence: session.lastSequence + 1,
|
|
22137
22356
|
type: "system.update.pending",
|
|
22138
22357
|
payload: sanitizeEventPayload({
|
|
22139
|
-
updateId:
|
|
22140
|
-
kind:
|
|
22141
|
-
classification:
|
|
22142
|
-
sourceId:
|
|
22143
|
-
|
|
22358
|
+
updateId: eventPreview.id,
|
|
22359
|
+
kind: eventPreview.kind,
|
|
22360
|
+
classification: eventPreview.classification,
|
|
22361
|
+
sourceId: eventPreview.sourceId,
|
|
22362
|
+
sourceIdTruncated: eventPreview.sourceIdTruncated,
|
|
22363
|
+
summary: eventPreview.summary,
|
|
22364
|
+
summaryTruncated: eventPreview.summaryTruncated
|
|
22144
22365
|
}),
|
|
22145
22366
|
occurredAt: now
|
|
22146
22367
|
},
|
|
@@ -22521,6 +22742,62 @@ async function enqueueSessionTurn(db, input) {
|
|
|
22521
22742
|
var MAX_INTERNAL_UPDATE_BYTES = 64 * 1024;
|
|
22522
22743
|
var MAX_INTERNAL_UPDATE_BATCH_MEMBERS = 100;
|
|
22523
22744
|
var MAX_INTERNAL_UPDATE_BATCH_BYTES = 256 * 1024;
|
|
22745
|
+
var MAX_INTERNAL_UPDATE_EVENT_SUMMARY_BYTES = 512;
|
|
22746
|
+
var MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES = 256;
|
|
22747
|
+
function boundedInternalUpdateEventText(value, maxBytes) {
|
|
22748
|
+
if (Buffer.byteLength(value) <= maxBytes) return { text: value, truncated: false };
|
|
22749
|
+
const suffix = "\u2026";
|
|
22750
|
+
const bodyBudget = maxBytes - Buffer.byteLength(suffix);
|
|
22751
|
+
const bytes = Buffer.from(value);
|
|
22752
|
+
let text = bytes.subarray(0, bodyBudget).toString("utf8");
|
|
22753
|
+
if (text.endsWith("\uFFFD")) text = text.slice(0, -1);
|
|
22754
|
+
return { text: `${text}${suffix}`, truncated: true };
|
|
22755
|
+
}
|
|
22756
|
+
function internalUpdateEventMember(update) {
|
|
22757
|
+
const summary = boundedInternalUpdateEventText(
|
|
22758
|
+
update.summary,
|
|
22759
|
+
MAX_INTERNAL_UPDATE_EVENT_SUMMARY_BYTES
|
|
22760
|
+
);
|
|
22761
|
+
const source = boundedInternalUpdateEventText(
|
|
22762
|
+
update.sourceId,
|
|
22763
|
+
MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES
|
|
22764
|
+
);
|
|
22765
|
+
return {
|
|
22766
|
+
id: update.id,
|
|
22767
|
+
kind: update.kind,
|
|
22768
|
+
classification: update.classification,
|
|
22769
|
+
sourceId: source.text,
|
|
22770
|
+
sourceIdTruncated: source.truncated,
|
|
22771
|
+
summary: summary.text,
|
|
22772
|
+
summaryTruncated: summary.truncated
|
|
22773
|
+
};
|
|
22774
|
+
}
|
|
22775
|
+
function selectBoundedSystemUpdateBatch(updates) {
|
|
22776
|
+
const selected = [];
|
|
22777
|
+
let selectedBytes = 0;
|
|
22778
|
+
for (const update of updates) {
|
|
22779
|
+
const updateBytes = Buffer.byteLength(
|
|
22780
|
+
JSON.stringify({
|
|
22781
|
+
id: update.id,
|
|
22782
|
+
kind: update.kind,
|
|
22783
|
+
classification: update.classification,
|
|
22784
|
+
sourceId: update.sourceId,
|
|
22785
|
+
summary: update.summary,
|
|
22786
|
+
payload: update.payload,
|
|
22787
|
+
lineage: update.lineage
|
|
22788
|
+
})
|
|
22789
|
+
);
|
|
22790
|
+
if (selected.length >= MAX_INTERNAL_UPDATE_BATCH_MEMBERS || // One individually large canonical input must still make progress. The
|
|
22791
|
+
// model/context boundary may reject it explicitly, but the queue cannot
|
|
22792
|
+
// wedge forever merely because the coalescing target is smaller.
|
|
22793
|
+
selected.length > 0 && selectedBytes + updateBytes > MAX_INTERNAL_UPDATE_BATCH_BYTES) {
|
|
22794
|
+
break;
|
|
22795
|
+
}
|
|
22796
|
+
selected.push(update);
|
|
22797
|
+
selectedBytes += updateBytes;
|
|
22798
|
+
}
|
|
22799
|
+
return selected;
|
|
22800
|
+
}
|
|
22524
22801
|
async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
22525
22802
|
const { sessionId, workflowId } = input;
|
|
22526
22803
|
return await withWorkspaceRls(
|
|
@@ -22532,29 +22809,18 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
22532
22809
|
and7(
|
|
22533
22810
|
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
22534
22811
|
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
22535
|
-
|
|
22812
|
+
eq7(sessionSystemUpdates.state, "pending"),
|
|
22536
22813
|
eq7(sessionSystemUpdates.kind, "agent_steer_instruction")
|
|
22537
22814
|
)
|
|
22538
22815
|
).orderBy(
|
|
22539
22816
|
desc2(sessionSystemUpdates.createdAt),
|
|
22540
22817
|
desc2(sessionSystemUpdates.id)
|
|
22541
22818
|
).limit(1).for("update");
|
|
22542
|
-
if (agentSteer) {
|
|
22543
|
-
await tx.update(sessionSystemUpdates).set({ state: "superseded" }).where(
|
|
22544
|
-
and7(
|
|
22545
|
-
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
22546
|
-
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
22547
|
-
eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
|
|
22548
|
-
inArray3(sessionSystemUpdates.state, ["pending", "deferred"]),
|
|
22549
|
-
ne(sessionSystemUpdates.id, agentSteer.id)
|
|
22550
|
-
)
|
|
22551
|
-
);
|
|
22552
|
-
}
|
|
22553
22819
|
const ordinary = await tx.select().from(sessionSystemUpdates).where(
|
|
22554
22820
|
and7(
|
|
22555
22821
|
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
22556
22822
|
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
22557
|
-
|
|
22823
|
+
eq7(sessionSystemUpdates.state, "pending"),
|
|
22558
22824
|
ne(sessionSystemUpdates.kind, "agent_steer_instruction")
|
|
22559
22825
|
)
|
|
22560
22826
|
).orderBy(
|
|
@@ -22567,12 +22833,15 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
22567
22833
|
count: 0,
|
|
22568
22834
|
lastSequence: nextSequence - 1,
|
|
22569
22835
|
triggerEventId: null,
|
|
22836
|
+
historyItemId: null,
|
|
22837
|
+
historyItem: null,
|
|
22570
22838
|
updates: [],
|
|
22839
|
+
events: [],
|
|
22571
22840
|
event: null
|
|
22572
22841
|
};
|
|
22573
22842
|
}
|
|
22574
|
-
const
|
|
22575
|
-
|
|
22843
|
+
const validUpdates = [];
|
|
22844
|
+
const cancelledUpdateIds = [];
|
|
22576
22845
|
for (const update of updates) {
|
|
22577
22846
|
const payload = update.payload;
|
|
22578
22847
|
if (payload.type === "goal_continuation") {
|
|
@@ -22590,38 +22859,56 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
22590
22859
|
).for("update").limit(1) : [];
|
|
22591
22860
|
if (!goal || goal.status !== "active" || goal.version !== goalVersion) {
|
|
22592
22861
|
await tx.update(sessionSystemUpdates).set({ state: "cancelled" }).where(eq7(sessionSystemUpdates.id, update.id));
|
|
22862
|
+
cancelledUpdateIds.push(update.id);
|
|
22593
22863
|
continue;
|
|
22594
22864
|
}
|
|
22595
22865
|
}
|
|
22596
|
-
|
|
22597
|
-
JSON.stringify({
|
|
22598
|
-
id: update.id,
|
|
22599
|
-
kind: update.kind,
|
|
22600
|
-
classification: update.classification,
|
|
22601
|
-
sourceId: update.sourceId,
|
|
22602
|
-
summary: update.summary,
|
|
22603
|
-
payload: update.payload,
|
|
22604
|
-
lineage: update.lineage
|
|
22605
|
-
})
|
|
22606
|
-
);
|
|
22607
|
-
if (deliverable.length >= MAX_INTERNAL_UPDATE_BATCH_MEMBERS || deliveredBytes + updateBytes > MAX_INTERNAL_UPDATE_BATCH_BYTES) {
|
|
22608
|
-
break;
|
|
22609
|
-
}
|
|
22610
|
-
deliverable.push(update);
|
|
22611
|
-
deliveredBytes += updateBytes;
|
|
22866
|
+
validUpdates.push(update);
|
|
22612
22867
|
}
|
|
22868
|
+
const deliverable = selectBoundedSystemUpdateBatch(validUpdates);
|
|
22613
22869
|
if (deliverable.length === 0) {
|
|
22870
|
+
const cancellationEvent = cancelledUpdateIds.length > 0 ? {
|
|
22871
|
+
accountId,
|
|
22872
|
+
workspaceId,
|
|
22873
|
+
sessionId,
|
|
22874
|
+
// No receiving turn exists when every candidate was
|
|
22875
|
+
// cancelled before a model batch could be persisted.
|
|
22876
|
+
turnId: null,
|
|
22877
|
+
turnGeneration: null,
|
|
22878
|
+
turnAttemptId: null,
|
|
22879
|
+
turnAssociation: null,
|
|
22880
|
+
sequence: nextSequence,
|
|
22881
|
+
type: "system.update.cancelled",
|
|
22882
|
+
payload: sanitizeEventPayload({
|
|
22883
|
+
updateIds: cancelledUpdateIds,
|
|
22884
|
+
count: cancelledUpdateIds.length,
|
|
22885
|
+
reason: "stale_goal_continuation"
|
|
22886
|
+
}),
|
|
22887
|
+
occurredAt
|
|
22888
|
+
} : null;
|
|
22614
22889
|
return {
|
|
22615
22890
|
count: 0,
|
|
22616
|
-
lastSequence: nextSequence - 1,
|
|
22891
|
+
lastSequence: cancellationEvent ? nextSequence : nextSequence - 1,
|
|
22617
22892
|
triggerEventId: null,
|
|
22893
|
+
historyItemId: null,
|
|
22894
|
+
historyItem: null,
|
|
22618
22895
|
updates: [],
|
|
22896
|
+
events: cancellationEvent ? [cancellationEvent] : [],
|
|
22619
22897
|
event: null
|
|
22620
22898
|
};
|
|
22621
22899
|
}
|
|
22900
|
+
const modelOrdered = [
|
|
22901
|
+
...deliverable.filter((update) => update.kind !== "agent_steer_instruction"),
|
|
22902
|
+
...deliverable.filter((update) => update.kind === "agent_steer_instruction")
|
|
22903
|
+
];
|
|
22904
|
+
const historyItemId = crypto.randomUUID();
|
|
22905
|
+
const historyItem = sessionSystemUpdateBatchHistoryItem(
|
|
22906
|
+
modelOrdered.map((update) => mapSessionSystemUpdate(update))
|
|
22907
|
+
);
|
|
22622
22908
|
await tx.update(sessionSystemUpdates).set({
|
|
22623
22909
|
state: "delivered",
|
|
22624
22910
|
deliveredTurnId: turnId,
|
|
22911
|
+
deliveredHistoryItemId: historyItemId,
|
|
22625
22912
|
deliveredAt: occurredAt
|
|
22626
22913
|
}).where(
|
|
22627
22914
|
and7(
|
|
@@ -22634,6 +22921,27 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
22634
22921
|
)
|
|
22635
22922
|
);
|
|
22636
22923
|
const eventId = triggerEventId ?? crypto.randomUUID();
|
|
22924
|
+
let sequence = nextSequence - 1;
|
|
22925
|
+
const events = [];
|
|
22926
|
+
if (cancelledUpdateIds.length > 0) {
|
|
22927
|
+
events.push({
|
|
22928
|
+
accountId,
|
|
22929
|
+
workspaceId,
|
|
22930
|
+
sessionId,
|
|
22931
|
+
turnId,
|
|
22932
|
+
turnGeneration,
|
|
22933
|
+
turnAttemptId: input.attemptId,
|
|
22934
|
+
turnAssociation: "current",
|
|
22935
|
+
sequence: ++sequence,
|
|
22936
|
+
type: "system.update.cancelled",
|
|
22937
|
+
payload: sanitizeEventPayload({
|
|
22938
|
+
updateIds: cancelledUpdateIds,
|
|
22939
|
+
count: cancelledUpdateIds.length,
|
|
22940
|
+
reason: "stale_goal_continuation"
|
|
22941
|
+
}),
|
|
22942
|
+
occurredAt
|
|
22943
|
+
});
|
|
22944
|
+
}
|
|
22637
22945
|
const event = {
|
|
22638
22946
|
id: eventId,
|
|
22639
22947
|
accountId,
|
|
@@ -22643,23 +22951,55 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
22643
22951
|
turnGeneration,
|
|
22644
22952
|
turnAttemptId: input.attemptId,
|
|
22645
22953
|
turnAssociation: "current",
|
|
22646
|
-
sequence:
|
|
22954
|
+
sequence: ++sequence,
|
|
22647
22955
|
type: "system.update.delivered",
|
|
22648
22956
|
payload: sanitizeEventPayload({
|
|
22649
22957
|
updateIds: deliverable.map((update) => update.id),
|
|
22958
|
+
historyItemId,
|
|
22650
22959
|
count: deliverable.length,
|
|
22651
|
-
classifications: [...new Set(deliverable.map((update) => update.classification))]
|
|
22960
|
+
classifications: [...new Set(deliverable.map((update) => update.classification))],
|
|
22961
|
+
members: modelOrdered.map(internalUpdateEventMember)
|
|
22652
22962
|
}),
|
|
22653
22963
|
occurredAt
|
|
22654
22964
|
};
|
|
22965
|
+
events.push(event);
|
|
22655
22966
|
return {
|
|
22656
22967
|
count: deliverable.length,
|
|
22657
|
-
lastSequence:
|
|
22968
|
+
lastSequence: sequence,
|
|
22658
22969
|
triggerEventId: eventId,
|
|
22970
|
+
historyItemId,
|
|
22971
|
+
historyItem,
|
|
22659
22972
|
updates: deliverable,
|
|
22973
|
+
events,
|
|
22660
22974
|
event
|
|
22661
22975
|
};
|
|
22662
22976
|
};
|
|
22977
|
+
const persistDeliveredUpdateBatch = async (delivered2, accountId, turnId) => {
|
|
22978
|
+
if (!delivered2.historyItemId || !delivered2.historyItem) {
|
|
22979
|
+
if (delivered2.count !== 0) {
|
|
22980
|
+
throw new Error("Delivered machine-input batch has no model-memory item");
|
|
22981
|
+
}
|
|
22982
|
+
return;
|
|
22983
|
+
}
|
|
22984
|
+
const [{ position } = { position: 0 }] = await tx.select({
|
|
22985
|
+
position: sql4`coalesce(max(${sessionHistoryItems.position}), -1) + 1`
|
|
22986
|
+
}).from(sessionHistoryItems).where(
|
|
22987
|
+
and7(
|
|
22988
|
+
eq7(sessionHistoryItems.workspaceId, workspaceId),
|
|
22989
|
+
eq7(sessionHistoryItems.sessionId, sessionId)
|
|
22990
|
+
)
|
|
22991
|
+
);
|
|
22992
|
+
await tx.insert(sessionHistoryItems).values({
|
|
22993
|
+
id: delivered2.historyItemId,
|
|
22994
|
+
accountId,
|
|
22995
|
+
workspaceId,
|
|
22996
|
+
sessionId,
|
|
22997
|
+
turnId,
|
|
22998
|
+
position: Number(position),
|
|
22999
|
+
item: sanitizeModelPayload(delivered2.historyItem),
|
|
23000
|
+
producerCodexCredentialId: null
|
|
23001
|
+
});
|
|
23002
|
+
};
|
|
22663
23003
|
const workspaceControl = await lockWorkspaceInferenceControl(
|
|
22664
23004
|
tx,
|
|
22665
23005
|
workspaceId,
|
|
@@ -22694,6 +23034,12 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
22694
23034
|
and7(
|
|
22695
23035
|
eq7(sessionAttemptInterruptions.workspaceId, workspaceId),
|
|
22696
23036
|
eq7(sessionAttemptInterruptions.sessionId, sessionId),
|
|
23037
|
+
inArray3(sessionAttemptInterruptions.state, [
|
|
23038
|
+
"pending",
|
|
23039
|
+
"delivered",
|
|
23040
|
+
"acknowledged",
|
|
23041
|
+
"settled"
|
|
23042
|
+
]),
|
|
22697
23043
|
isNull2(sessionTurnAttempts.quiescedAt)
|
|
22698
23044
|
)
|
|
22699
23045
|
).orderBy(desc2(sessionAttemptInterruptions.requestedAt)).limit(1);
|
|
@@ -22899,17 +23245,21 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
22899
23245
|
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
22900
23246
|
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
22901
23247
|
eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
|
|
22902
|
-
|
|
23248
|
+
eq7(sessionSystemUpdates.state, "pending")
|
|
22903
23249
|
)
|
|
22904
23250
|
).orderBy(
|
|
22905
23251
|
desc2(sessionSystemUpdates.createdAt),
|
|
22906
23252
|
desc2(sessionSystemUpdates.id)
|
|
22907
23253
|
).limit(1).for("update");
|
|
22908
|
-
const rows =
|
|
23254
|
+
const rows = await rawRows(
|
|
22909
23255
|
tx,
|
|
22910
23256
|
sql4`select id, trigger_event_id, metadata from session_turns
|
|
22911
23257
|
where workspace_id = ${workspaceId} and session_id = ${sessionId}
|
|
22912
23258
|
and status = 'queued' and source in ('user', 'api')
|
|
23259
|
+
and (
|
|
23260
|
+
${Boolean(pendingAgentSteer)} = false
|
|
23261
|
+
or metadata->>'delivery' = 'steer'
|
|
23262
|
+
)
|
|
22913
23263
|
order by position asc, created_at asc, id asc
|
|
22914
23264
|
limit 1`
|
|
22915
23265
|
);
|
|
@@ -23073,6 +23423,19 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
23073
23423
|
triggerEventId
|
|
23074
23424
|
);
|
|
23075
23425
|
if (delivered2.count === 0) {
|
|
23426
|
+
if (delivered2.events.length > 0) {
|
|
23427
|
+
await tx.insert(sessionEvents).values(delivered2.events);
|
|
23428
|
+
await tx.update(sessions).set({
|
|
23429
|
+
status: "idle",
|
|
23430
|
+
lastSequence: delivered2.lastSequence,
|
|
23431
|
+
updatedAt: now2
|
|
23432
|
+
}).where(
|
|
23433
|
+
and7(
|
|
23434
|
+
eq7(sessions.workspaceId, workspaceId),
|
|
23435
|
+
eq7(sessions.id, sessionId)
|
|
23436
|
+
)
|
|
23437
|
+
);
|
|
23438
|
+
}
|
|
23076
23439
|
return { action: "unclaimed", reason: "no-work" };
|
|
23077
23440
|
}
|
|
23078
23441
|
const goalUpdate = delivered2.updates.find(
|
|
@@ -23211,9 +23574,10 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
23211
23574
|
startedAt: now2
|
|
23212
23575
|
}).returning();
|
|
23213
23576
|
if (!internalTurn) throw new Error("Failed to create internal update inference");
|
|
23577
|
+
await persistDeliveredUpdateBatch(delivered2, session.accountId, internalTurn.id);
|
|
23214
23578
|
await registerAttempt(internalTurn);
|
|
23215
23579
|
if (!delivered2.event) throw new Error("Delivered update batch has no durable event");
|
|
23216
|
-
await tx.insert(sessionEvents).values(delivered2.
|
|
23580
|
+
await tx.insert(sessionEvents).values(delivered2.events);
|
|
23217
23581
|
if (goalUpdate && typeof goalUpdate.payload.goalId === "string") {
|
|
23218
23582
|
await tx.update(sessionGoals).set({ lastContinuationTurnId: internalTurn.id, updatedAt: now2 }).where(
|
|
23219
23583
|
and7(
|
|
@@ -23310,8 +23674,9 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
|
|
|
23310
23674
|
session.lastSequence + 1,
|
|
23311
23675
|
now
|
|
23312
23676
|
);
|
|
23313
|
-
|
|
23314
|
-
|
|
23677
|
+
await persistDeliveredUpdateBatch(delivered, session.accountId, row.id);
|
|
23678
|
+
if (delivered.events.length > 0) {
|
|
23679
|
+
await tx.insert(sessionEvents).values(delivered.events);
|
|
23315
23680
|
}
|
|
23316
23681
|
await tx.update(sessions).set({
|
|
23317
23682
|
status: "running",
|
|
@@ -23455,6 +23820,127 @@ async function markSessionAttemptQuiesced(db, input) {
|
|
|
23455
23820
|
return [mapEvent2(event)];
|
|
23456
23821
|
});
|
|
23457
23822
|
}
|
|
23823
|
+
async function getSessionAttemptActivityRef(db, input) {
|
|
23824
|
+
return await withRlsContext(
|
|
23825
|
+
db,
|
|
23826
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
23827
|
+
async (scopedDb) => {
|
|
23828
|
+
const [attempt] = await scopedDb.select({
|
|
23829
|
+
workflowId: sessionTurnAttempts.temporalWorkflowId,
|
|
23830
|
+
workflowRunId: sessionTurnAttempts.temporalWorkflowRunId,
|
|
23831
|
+
activityId: sessionTurnAttempts.temporalActivityId,
|
|
23832
|
+
quiescedAt: sessionTurnAttempts.quiescedAt
|
|
23833
|
+
}).from(sessionTurnAttempts).where(
|
|
23834
|
+
and7(
|
|
23835
|
+
eq7(sessionTurnAttempts.accountId, input.accountId),
|
|
23836
|
+
eq7(sessionTurnAttempts.workspaceId, input.workspaceId),
|
|
23837
|
+
eq7(sessionTurnAttempts.sessionId, input.sessionId),
|
|
23838
|
+
eq7(sessionTurnAttempts.id, input.attemptId),
|
|
23839
|
+
eq7(sessionTurnAttempts.temporalWorkflowId, input.temporalWorkflowId)
|
|
23840
|
+
)
|
|
23841
|
+
).limit(1);
|
|
23842
|
+
return attempt ? {
|
|
23843
|
+
workflowId: attempt.workflowId,
|
|
23844
|
+
workflowRunId: attempt.workflowRunId,
|
|
23845
|
+
activityId: attempt.activityId,
|
|
23846
|
+
quiesced: attempt.quiescedAt !== null
|
|
23847
|
+
} : null;
|
|
23848
|
+
}
|
|
23849
|
+
);
|
|
23850
|
+
}
|
|
23851
|
+
async function reconcileSessionAttemptQuiescence(db, input) {
|
|
23852
|
+
const eligibility = await withRlsContext(
|
|
23853
|
+
db,
|
|
23854
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
23855
|
+
async (scopedDb) => {
|
|
23856
|
+
const rows = await scopedDb.execute(sql4`
|
|
23857
|
+
select
|
|
23858
|
+
attempt.account_id,
|
|
23859
|
+
attempt.state,
|
|
23860
|
+
attempt.quiesced_at,
|
|
23861
|
+
attempt.temporal_workflow_id,
|
|
23862
|
+
attempt.temporal_workflow_run_id,
|
|
23863
|
+
attempt.temporal_activity_id,
|
|
23864
|
+
exists (
|
|
23865
|
+
select 1
|
|
23866
|
+
from session_attempt_interruptions interruption
|
|
23867
|
+
where interruption.workspace_id = attempt.workspace_id
|
|
23868
|
+
and interruption.session_id = attempt.session_id
|
|
23869
|
+
and interruption.attempt_id = attempt.id
|
|
23870
|
+
and interruption.state in ('settled', 'rejected_stale')
|
|
23871
|
+
) as interruption_settled,
|
|
23872
|
+
exists (
|
|
23873
|
+
select 1
|
|
23874
|
+
from session_attempt_interruptions interruption
|
|
23875
|
+
where interruption.workspace_id = attempt.workspace_id
|
|
23876
|
+
and interruption.session_id = attempt.session_id
|
|
23877
|
+
and interruption.attempt_id = attempt.id
|
|
23878
|
+
and interruption.state in ('pending', 'delivered', 'acknowledged')
|
|
23879
|
+
) as interruption_pending,
|
|
23880
|
+
(
|
|
23881
|
+
exists (
|
|
23882
|
+
select 1
|
|
23883
|
+
from sandbox_workspace_mutation_admissions admission
|
|
23884
|
+
where admission.account_id = attempt.account_id
|
|
23885
|
+
and admission.workspace_id = attempt.workspace_id
|
|
23886
|
+
and admission.session_id = attempt.session_id
|
|
23887
|
+
and admission.settled_at is null
|
|
23888
|
+
and (
|
|
23889
|
+
admission.attempt_id = attempt.id
|
|
23890
|
+
or (
|
|
23891
|
+
admission.actor_kind = 'process'
|
|
23892
|
+
and exists (
|
|
23893
|
+
select 1
|
|
23894
|
+
from sandbox_retained_processes process
|
|
23895
|
+
where process.account_id = attempt.account_id
|
|
23896
|
+
and process.workspace_id = attempt.workspace_id
|
|
23897
|
+
and process.session_id = attempt.session_id
|
|
23898
|
+
and process.id = admission.actor_id
|
|
23899
|
+
and process.owner_attempt_id = attempt.id
|
|
23900
|
+
)
|
|
23901
|
+
)
|
|
23902
|
+
)
|
|
23903
|
+
)
|
|
23904
|
+
or exists (
|
|
23905
|
+
select 1
|
|
23906
|
+
from sandbox_retained_processes process
|
|
23907
|
+
where process.account_id = attempt.account_id
|
|
23908
|
+
and process.workspace_id = attempt.workspace_id
|
|
23909
|
+
and process.session_id = attempt.session_id
|
|
23910
|
+
and process.owner_attempt_id = attempt.id
|
|
23911
|
+
and process.state = 'active'
|
|
23912
|
+
)
|
|
23913
|
+
) as writer_pending
|
|
23914
|
+
from session_turn_attempts attempt
|
|
23915
|
+
where attempt.account_id = ${input.accountId}
|
|
23916
|
+
and attempt.workspace_id = ${input.workspaceId}
|
|
23917
|
+
and attempt.session_id = ${input.sessionId}
|
|
23918
|
+
and attempt.id = ${input.attemptId}
|
|
23919
|
+
limit 1
|
|
23920
|
+
`);
|
|
23921
|
+
return rows[0] ?? null;
|
|
23922
|
+
}
|
|
23923
|
+
);
|
|
23924
|
+
if (!eligibility || eligibility.account_id !== input.accountId || eligibility.temporal_workflow_id !== input.temporalWorkflowId || eligibility.temporal_workflow_run_id !== input.temporalWorkflowRunId || eligibility.temporal_activity_id !== input.temporalActivityId || eligibility.state !== "closed" || !eligibility.interruption_settled || eligibility.interruption_pending) {
|
|
23925
|
+
return { action: "stale", events: [] };
|
|
23926
|
+
}
|
|
23927
|
+
if (eligibility.quiesced_at) {
|
|
23928
|
+
return { action: "quiesced", events: [] };
|
|
23929
|
+
}
|
|
23930
|
+
if (!input.activitySettled || eligibility.writer_pending) {
|
|
23931
|
+
return { action: "pending", events: [] };
|
|
23932
|
+
}
|
|
23933
|
+
const events = await markSessionAttemptQuiesced(db, {
|
|
23934
|
+
accountId: input.accountId,
|
|
23935
|
+
workspaceId: input.workspaceId,
|
|
23936
|
+
sessionId: input.sessionId,
|
|
23937
|
+
attemptId: input.attemptId,
|
|
23938
|
+
temporalWorkflowId: input.temporalWorkflowId,
|
|
23939
|
+
temporalWorkflowRunId: input.temporalWorkflowRunId,
|
|
23940
|
+
temporalActivityId: input.temporalActivityId
|
|
23941
|
+
});
|
|
23942
|
+
return { action: "quiesced", events };
|
|
23943
|
+
}
|
|
23458
23944
|
async function settleSessionAttemptInterruptions(db, workspaceId, sessionId, attemptId) {
|
|
23459
23945
|
return await withWorkspaceRls(
|
|
23460
23946
|
db,
|
|
@@ -23583,12 +24069,6 @@ async function settleSessionAttemptInterruptions(db, workspaceId, sessionId, att
|
|
|
23583
24069
|
outcome,
|
|
23584
24070
|
closedAt: now
|
|
23585
24071
|
});
|
|
23586
|
-
await requeueInterruptedSessionSystemUpdatesForTurnTx(
|
|
23587
|
-
tx,
|
|
23588
|
-
workspaceId,
|
|
23589
|
-
sessionId,
|
|
23590
|
-
turn.id
|
|
23591
|
-
);
|
|
23592
24072
|
const eventValues = steer ? [
|
|
23593
24073
|
{
|
|
23594
24074
|
accountId: session.accountId,
|
|
@@ -24458,10 +24938,36 @@ async function applySessionTurnSettlement(db, workspaceId, input) {
|
|
|
24458
24938
|
}
|
|
24459
24939
|
})
|
|
24460
24940
|
);
|
|
24941
|
+
const settledMachineInputs = ["completed", "failed", "cancelled", "superseded"].includes(
|
|
24942
|
+
input.turnStatus
|
|
24943
|
+
) ? await tx.select({
|
|
24944
|
+
id: sessionSystemUpdates.id,
|
|
24945
|
+
historyItemId: sessionSystemUpdates.deliveredHistoryItemId
|
|
24946
|
+
}).from(sessionSystemUpdates).where(
|
|
24947
|
+
and7(
|
|
24948
|
+
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
24949
|
+
eq7(sessionSystemUpdates.sessionId, input.sessionId),
|
|
24950
|
+
eq7(sessionSystemUpdates.deliveredTurnId, input.turnId),
|
|
24951
|
+
eq7(sessionSystemUpdates.state, "delivered")
|
|
24952
|
+
)
|
|
24953
|
+
).orderBy(
|
|
24954
|
+
asc4(sessionSystemUpdates.createdAt),
|
|
24955
|
+
asc4(sessionSystemUpdates.id)
|
|
24956
|
+
) : [];
|
|
24957
|
+
const machineInputSettlementEvent = settledMachineInputs.length > 0 ? {
|
|
24958
|
+
type: "system.update.settled",
|
|
24959
|
+
payload: {
|
|
24960
|
+
updateIds: settledMachineInputs.map((update) => update.id),
|
|
24961
|
+
count: settledMachineInputs.length,
|
|
24962
|
+
historyItemId: settledMachineInputs[0].historyItemId,
|
|
24963
|
+
outcome: input.turnStatus
|
|
24964
|
+
}
|
|
24965
|
+
} : null;
|
|
24461
24966
|
const settlementEvents = [
|
|
24462
24967
|
...recordingEvent ? [recordingEvent] : [],
|
|
24463
24968
|
...compactionRequestEvent ? [compactionRequestEvent] : [],
|
|
24464
24969
|
...terminalHumanInputEvents,
|
|
24970
|
+
...machineInputSettlementEvent ? [machineInputSettlementEvent] : [],
|
|
24465
24971
|
...input.events
|
|
24466
24972
|
];
|
|
24467
24973
|
const values = settlementEvents.map((event) => {
|
|
@@ -24517,21 +25023,6 @@ async function applySessionTurnSettlement(db, workspaceId, input) {
|
|
|
24517
25023
|
turn
|
|
24518
25024
|
);
|
|
24519
25025
|
}
|
|
24520
|
-
if (input.turnStatus === "failed") {
|
|
24521
|
-
await deferFailedSessionSystemUpdatesForTurnTx(
|
|
24522
|
-
tx,
|
|
24523
|
-
workspaceId,
|
|
24524
|
-
input.sessionId,
|
|
24525
|
-
input.turnId
|
|
24526
|
-
);
|
|
24527
|
-
} else if (["cancelled", "superseded"].includes(input.turnStatus)) {
|
|
24528
|
-
await requeueInterruptedSessionSystemUpdatesForTurnTx(
|
|
24529
|
-
tx,
|
|
24530
|
-
workspaceId,
|
|
24531
|
-
input.sessionId,
|
|
24532
|
-
input.turnId
|
|
24533
|
-
);
|
|
24534
|
-
}
|
|
24535
25026
|
await tx.update(sessions).set({
|
|
24536
25027
|
status: effectiveSessionStatus,
|
|
24537
25028
|
activeTurnId: input.activeTurnId,
|
|
@@ -24729,14 +25220,6 @@ async function settleCodexCredentialLeaseLoss(db, input) {
|
|
|
24729
25220
|
eq7(sessions.activeTurnId, input.turnId)
|
|
24730
25221
|
)
|
|
24731
25222
|
);
|
|
24732
|
-
if (!input.checkpointDurable) {
|
|
24733
|
-
await deferFailedSessionSystemUpdatesForTurnTx(
|
|
24734
|
-
tx,
|
|
24735
|
-
input.workspaceId,
|
|
24736
|
-
input.sessionId,
|
|
24737
|
-
input.turnId
|
|
24738
|
-
);
|
|
24739
|
-
}
|
|
24740
25223
|
await tx.execute(sql4`
|
|
24741
25224
|
delete from codex_credential_leases
|
|
24742
25225
|
where account_id = ${input.accountId}
|
|
@@ -25407,16 +25890,49 @@ async function getSessionQueueSnapshot(db, workspaceId, sessionId) {
|
|
|
25407
25890
|
inArray3(sessionTurns.source, ["user", "api"])
|
|
25408
25891
|
)
|
|
25409
25892
|
).orderBy(asc4(sessionTurns.position), asc4(sessionTurns.createdAt));
|
|
25893
|
+
const pendingInputs = await scopedDb.select().from(sessionSystemUpdates).where(
|
|
25894
|
+
and7(
|
|
25895
|
+
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
25896
|
+
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
25897
|
+
eq7(sessionSystemUpdates.state, "pending")
|
|
25898
|
+
)
|
|
25899
|
+
).orderBy(
|
|
25900
|
+
sql4`case when ${sessionSystemUpdates.kind} = 'agent_steer_instruction' then 0 else 1 end`,
|
|
25901
|
+
asc4(sessionSystemUpdates.createdAt),
|
|
25902
|
+
asc4(sessionSystemUpdates.id)
|
|
25903
|
+
);
|
|
25410
25904
|
const latestInterruption = await latestSessionAttemptInterruption(
|
|
25411
25905
|
scopedDb,
|
|
25412
25906
|
workspaceId,
|
|
25413
25907
|
sessionId
|
|
25414
25908
|
);
|
|
25909
|
+
const items = rows.map(mapSessionTurn);
|
|
25910
|
+
const nextInputBatch = selectBoundedSystemUpdateBatch(pendingInputs);
|
|
25911
|
+
const hasPendingAgentSteer = pendingInputs.some(
|
|
25912
|
+
(update) => update.kind === "agent_steer_instruction"
|
|
25913
|
+
);
|
|
25914
|
+
const attachmentTurn = hasPendingAgentSteer ? items.find((turn) => turn.metadata.delivery === "steer") : items[0];
|
|
25415
25915
|
return {
|
|
25416
25916
|
version: session.queueVersion,
|
|
25417
25917
|
effectiveControl: serializeEffectiveSessionControl(effectiveControl),
|
|
25418
|
-
stoppingPreviousAttempt: latestInterruption !== null && latestInterruption.quiescedAt === null,
|
|
25419
|
-
items
|
|
25918
|
+
stoppingPreviousAttempt: latestInterruption !== null && latestInterruption.interruptionState !== "rejected_stale" && latestInterruption.quiescedAt === null,
|
|
25919
|
+
items,
|
|
25920
|
+
pendingInputs: pendingInputs.map((update) => {
|
|
25921
|
+
const canonical = mapSessionSystemUpdate(update);
|
|
25922
|
+
return {
|
|
25923
|
+
id: canonical.id,
|
|
25924
|
+
sessionId: canonical.sessionId,
|
|
25925
|
+
kind: canonical.kind,
|
|
25926
|
+
classification: canonical.classification,
|
|
25927
|
+
sourceId: boundedInternalUpdateEventText(canonical.sourceId, 256).text,
|
|
25928
|
+
summary: boundedInternalUpdateEventText(canonical.summary, 512).text,
|
|
25929
|
+
createdAt: canonical.createdAt
|
|
25930
|
+
};
|
|
25931
|
+
}),
|
|
25932
|
+
pendingInputAttachment: attachmentTurn && nextInputBatch.length > 0 ? {
|
|
25933
|
+
turnId: attachmentTurn.id,
|
|
25934
|
+
inputIds: nextInputBatch.map((update) => update.id)
|
|
25935
|
+
} : null
|
|
25420
25936
|
};
|
|
25421
25937
|
});
|
|
25422
25938
|
}
|
|
@@ -25625,6 +26141,30 @@ async function markSessionWorkflowWakeDelivered(db, input) {
|
|
|
25625
26141
|
if (pendingAgentSteer) {
|
|
25626
26142
|
return { action: "pending_admission", blocker: "pending_agent_steer" };
|
|
25627
26143
|
}
|
|
26144
|
+
const [pendingQuiescence] = await tx.select({ id: sessionTurnAttempts.id }).from(sessionTurnAttempts).innerJoin(
|
|
26145
|
+
sessionAttemptInterruptions,
|
|
26146
|
+
and7(
|
|
26147
|
+
eq7(
|
|
26148
|
+
sessionAttemptInterruptions.workspaceId,
|
|
26149
|
+
sessionTurnAttempts.workspaceId
|
|
26150
|
+
),
|
|
26151
|
+
eq7(
|
|
26152
|
+
sessionAttemptInterruptions.sessionId,
|
|
26153
|
+
sessionTurnAttempts.sessionId
|
|
26154
|
+
),
|
|
26155
|
+
eq7(sessionAttemptInterruptions.attemptId, sessionTurnAttempts.id)
|
|
26156
|
+
)
|
|
26157
|
+
).where(
|
|
26158
|
+
and7(
|
|
26159
|
+
eq7(sessionTurnAttempts.workspaceId, input.workspaceId),
|
|
26160
|
+
eq7(sessionTurnAttempts.sessionId, input.sessionId),
|
|
26161
|
+
isNull2(sessionTurnAttempts.quiescedAt),
|
|
26162
|
+
inArray3(sessionAttemptInterruptions.state, ["settled", "rejected_stale"])
|
|
26163
|
+
)
|
|
26164
|
+
).limit(1);
|
|
26165
|
+
if (pendingQuiescence) {
|
|
26166
|
+
return { action: "pending_admission", blocker: "pending_quiescence" };
|
|
26167
|
+
}
|
|
25628
26168
|
}
|
|
25629
26169
|
const [row] = await tx.update(sessionWorkflowWakeOutbox).set({
|
|
25630
26170
|
deliveredRevision: sql4`greatest(${sessionWorkflowWakeOutbox.deliveredRevision}, ${input.wakeRevision})`,
|
|
@@ -25780,30 +26320,6 @@ async function addSessionSystemUpdate(db, input) {
|
|
|
25780
26320
|
}
|
|
25781
26321
|
return await addSessionSystemUpdateWithSourceMutation(db, input, async () => void 0);
|
|
25782
26322
|
}
|
|
25783
|
-
async function requeueInterruptedSessionSystemUpdatesForTurnTx(tx, workspaceId, sessionId, turnId) {
|
|
25784
|
-
await tx.update(sessionSystemUpdates).set({ state: "pending", deliveredTurnId: null, deliveredAt: null }).where(
|
|
25785
|
-
and7(
|
|
25786
|
-
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
25787
|
-
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
25788
|
-
eq7(sessionSystemUpdates.deliveredTurnId, turnId),
|
|
25789
|
-
eq7(sessionSystemUpdates.state, "delivered")
|
|
25790
|
-
)
|
|
25791
|
-
);
|
|
25792
|
-
}
|
|
25793
|
-
async function deferFailedSessionSystemUpdatesForTurnTx(tx, workspaceId, sessionId, turnId) {
|
|
25794
|
-
await tx.update(sessionSystemUpdates).set({
|
|
25795
|
-
state: sql4`case when ${sessionSystemUpdates.payload} ->> 'type' = 'goal_continuation' then 'failed' else 'deferred' end`,
|
|
25796
|
-
deliveredTurnId: null,
|
|
25797
|
-
deliveredAt: null
|
|
25798
|
-
}).where(
|
|
25799
|
-
and7(
|
|
25800
|
-
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
25801
|
-
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
25802
|
-
eq7(sessionSystemUpdates.deliveredTurnId, turnId),
|
|
25803
|
-
eq7(sessionSystemUpdates.state, "delivered")
|
|
25804
|
-
)
|
|
25805
|
-
);
|
|
25806
|
-
}
|
|
25807
26323
|
async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource) {
|
|
25808
26324
|
if (Buffer.byteLength(JSON.stringify(input.payload)) > MAX_INTERNAL_UPDATE_BYTES) {
|
|
25809
26325
|
throw new Error(`Internal update payload exceeds ${MAX_INTERNAL_UPDATE_BYTES} bytes`);
|
|
@@ -25882,6 +26398,7 @@ async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource)
|
|
|
25882
26398
|
};
|
|
25883
26399
|
}
|
|
25884
26400
|
const now = /* @__PURE__ */ new Date();
|
|
26401
|
+
const eventPreview = internalUpdateEventMember(inserted);
|
|
25885
26402
|
const [event] = await tx.insert(sessionEvents).values({
|
|
25886
26403
|
accountId: session.accountId,
|
|
25887
26404
|
workspaceId: input.workspaceId,
|
|
@@ -25889,11 +26406,13 @@ async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource)
|
|
|
25889
26406
|
sequence: session.lastSequence + 1,
|
|
25890
26407
|
type: "system.update.pending",
|
|
25891
26408
|
payload: sanitizeEventPayload({
|
|
25892
|
-
updateId:
|
|
25893
|
-
kind:
|
|
25894
|
-
classification:
|
|
25895
|
-
sourceId:
|
|
25896
|
-
|
|
26409
|
+
updateId: eventPreview.id,
|
|
26410
|
+
kind: eventPreview.kind,
|
|
26411
|
+
classification: eventPreview.classification,
|
|
26412
|
+
sourceId: eventPreview.sourceId,
|
|
26413
|
+
sourceIdTruncated: eventPreview.sourceIdTruncated,
|
|
26414
|
+
summary: eventPreview.summary,
|
|
26415
|
+
summaryTruncated: eventPreview.summaryTruncated
|
|
25897
26416
|
}),
|
|
25898
26417
|
occurredAt: now
|
|
25899
26418
|
}).returning();
|
|
@@ -25930,7 +26449,7 @@ async function listOutstandingSessionSystemUpdates(db, workspaceId, sessionId) {
|
|
|
25930
26449
|
and7(
|
|
25931
26450
|
eq7(sessionSystemUpdates.workspaceId, workspaceId),
|
|
25932
26451
|
eq7(sessionSystemUpdates.sessionId, sessionId),
|
|
25933
|
-
|
|
26452
|
+
eq7(sessionSystemUpdates.state, "pending")
|
|
25934
26453
|
)
|
|
25935
26454
|
).orderBy(asc4(sessionSystemUpdates.createdAt), asc4(sessionSystemUpdates.id));
|
|
25936
26455
|
return rows.map(mapSessionSystemUpdate);
|
|
@@ -25971,6 +26490,7 @@ function mapSessionSystemUpdate(row) {
|
|
|
25971
26490
|
lineage: row.lineage,
|
|
25972
26491
|
state: row.state,
|
|
25973
26492
|
deliveredTurnId: row.deliveredTurnId,
|
|
26493
|
+
deliveredHistoryItemId: row.deliveredHistoryItemId,
|
|
25974
26494
|
deliveredAt: row.deliveredAt?.toISOString() ?? null,
|
|
25975
26495
|
createdAt: row.createdAt.toISOString()
|
|
25976
26496
|
};
|
|
@@ -26571,6 +27091,7 @@ function mapSession(row, effectiveControl, mcpServers = [], pin = mapSessionPin(
|
|
|
26571
27091
|
titleSource: row.titleSource ?? null,
|
|
26572
27092
|
instructions: row.instructions ?? null,
|
|
26573
27093
|
resources: row.resources,
|
|
27094
|
+
skills: row.skills ?? [],
|
|
26574
27095
|
tools: row.tools,
|
|
26575
27096
|
toolPolicy: row.toolPolicy ?? {
|
|
26576
27097
|
mode: "legacy",
|
|
@@ -26600,6 +27121,7 @@ function mapSession(row, effectiveControl, mcpServers = [], pin = mapSessionPin(
|
|
|
26600
27121
|
rigId: row.rigId ?? null,
|
|
26601
27122
|
rigVersionId: row.rigVersionId ?? null,
|
|
26602
27123
|
firstPartyMcpPermissions: row.firstPartyMcpPermissions ?? null,
|
|
27124
|
+
firstPartyMcpTools: row.firstPartyMcpTools ?? null,
|
|
26603
27125
|
mcpServers,
|
|
26604
27126
|
parentSessionId: row.parentSessionId ?? null,
|
|
26605
27127
|
rootSessionId: row.rootSessionId,
|
|
@@ -27314,6 +27836,7 @@ export {
|
|
|
27314
27836
|
SessionPinVersionConflictError,
|
|
27315
27837
|
SessionSpawnDeniedDbError,
|
|
27316
27838
|
SessionToolPolicyVersionConflictError,
|
|
27839
|
+
SlackBotLifecycleSuccessAuditError,
|
|
27317
27840
|
WORKSPACE_MEMORY_BLOCK_EMPTY,
|
|
27318
27841
|
WORKSPACE_MEMORY_BLOCK_HEADER_POPULATED,
|
|
27319
27842
|
WORKSPACE_MEMORY_BLOCK_TOKEN_BUDGET,
|
|
@@ -27417,6 +27940,7 @@ export {
|
|
|
27417
27940
|
countWorkspacesForAccount,
|
|
27418
27941
|
createApiKey,
|
|
27419
27942
|
createConnection,
|
|
27943
|
+
createConnectionWithSlackBotSuccessAudit,
|
|
27420
27944
|
createDb,
|
|
27421
27945
|
createDeviceEnrollmentRequest,
|
|
27422
27946
|
createEnrollment,
|
|
@@ -27543,6 +28067,7 @@ export {
|
|
|
27543
28067
|
getSandboxSessionEnvelope,
|
|
27544
28068
|
getScheduledTask,
|
|
27545
28069
|
getSession,
|
|
28070
|
+
getSessionAttemptActivityRef,
|
|
27546
28071
|
getSessionByCreateIdempotencyKey,
|
|
27547
28072
|
getSessionCodexState,
|
|
27548
28073
|
getSessionEvent,
|
|
@@ -27714,6 +28239,7 @@ export {
|
|
|
27714
28239
|
reapStaleLeaseHoldersGlobal,
|
|
27715
28240
|
reconcileCodexCapacityWait,
|
|
27716
28241
|
reconcileColdLostLeaseInstanceBlockers,
|
|
28242
|
+
reconcileSessionAttemptQuiescence,
|
|
27717
28243
|
recordAuditEvent,
|
|
27718
28244
|
recordCodexAccountConnectors,
|
|
27719
28245
|
recordCodexAccountUsage,
|
|
@@ -27727,6 +28253,7 @@ export {
|
|
|
27727
28253
|
recordRetainedProcessReconciliationProof,
|
|
27728
28254
|
recordSessionActiveCodexCredential,
|
|
27729
28255
|
recordSkippedContextCompaction,
|
|
28256
|
+
recordSlackBotInstallCallbackFailure,
|
|
27730
28257
|
recordStreamAcknowledgment,
|
|
27731
28258
|
recordStripeWebhookEvent,
|
|
27732
28259
|
recordUsageEvent,
|
|
@@ -27765,6 +28292,7 @@ export {
|
|
|
27765
28292
|
retireHostExportConsumer,
|
|
27766
28293
|
revokeApiKey,
|
|
27767
28294
|
revokeConnection,
|
|
28295
|
+
revokeConnectionWithSlackBotSuccessAudit,
|
|
27768
28296
|
revokeEnrollment,
|
|
27769
28297
|
revokeViewer,
|
|
27770
28298
|
rewindHostExportConsumer,
|
|
@@ -27833,6 +28361,7 @@ export {
|
|
|
27833
28361
|
updateCodexAllocatorEligibility,
|
|
27834
28362
|
updateCodexRotationSettings,
|
|
27835
28363
|
updateConnection,
|
|
28364
|
+
updateConnectionWithSlackBotSuccessAudit,
|
|
27836
28365
|
updateImportBatchCounts,
|
|
27837
28366
|
updateKnowledgeMemory,
|
|
27838
28367
|
updatePackInstallationStatus,
|