@opengeni/db 0.27.9 → 0.27.11
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-NX2JNJJP.js → chunk-JYQPJ6Y5.js} +52 -47
- package/dist/chunk-JYQPJ6Y5.js.map +1 -0
- package/dist/{chunk-2JFRTKTG.js → chunk-RPHPNVWW.js} +3 -1
- package/dist/chunk-RPHPNVWW.js.map +1 -0
- package/dist/index.d.ts +62 -30
- package/dist/index.js +303 -90
- package/dist/index.js.map +1 -1
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +2 -2
- package/dist/schema.d.ts +128 -96
- package/dist/schema.js +3 -1
- package/drizzle/0172_retire_model_visible_github_token.sql +86 -0
- package/drizzle/0173_codex_auth_boundaries.sql +107 -0
- package/drizzle/0174_session_wake_live_interruption.sql +80 -0
- package/package.json +4 -4
- package/src/index.ts +468 -166
- package/src/runtime-posture.ts +2 -0
- package/src/schema.ts +59 -47
- package/dist/chunk-2JFRTKTG.js.map +0 -1
- package/dist/chunk-NX2JNJJP.js.map +0 -1
package/src/index.ts
CHANGED
|
@@ -11473,11 +11473,10 @@ export async function upsertCodexSubscriptionCredential(
|
|
|
11473
11473
|
// it when still null) so a re-connect never clobbers a rename.
|
|
11474
11474
|
accountEmail: input.accountEmail ?? null,
|
|
11475
11475
|
label: sql`coalesce(${schema.codexSubscriptionCredentials.label}, ${input.label ?? null})`,
|
|
11476
|
-
//
|
|
11477
|
-
//
|
|
11478
|
-
//
|
|
11479
|
-
|
|
11480
|
-
connectedBySubjectId: input.connectedBySubjectId ?? null,
|
|
11476
|
+
// Reconnect refreshes credential material, never ownership. A row
|
|
11477
|
+
// without an owner may be claimed by its first direct managed human;
|
|
11478
|
+
// after that, disconnect is the explicit ownership-reset boundary.
|
|
11479
|
+
connectedBySubjectId: sql`coalesce(${schema.codexSubscriptionCredentials.connectedBySubjectId}, ${input.connectedBySubjectId ?? null})`,
|
|
11481
11480
|
status: "active",
|
|
11482
11481
|
lastError: null,
|
|
11483
11482
|
version: sql`${schema.codexSubscriptionCredentials.version} + 1`,
|
|
@@ -11503,6 +11502,333 @@ export async function upsertCodexSubscriptionCredential(
|
|
|
11503
11502
|
);
|
|
11504
11503
|
}
|
|
11505
11504
|
|
|
11505
|
+
export type CodexAppsSettings = {
|
|
11506
|
+
credentialId: string | null;
|
|
11507
|
+
version: number;
|
|
11508
|
+
designatedAt: Date | null;
|
|
11509
|
+
};
|
|
11510
|
+
|
|
11511
|
+
export async function getCodexAppsSettings(
|
|
11512
|
+
db: Database,
|
|
11513
|
+
workspaceId: string,
|
|
11514
|
+
): Promise<CodexAppsSettings> {
|
|
11515
|
+
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
11516
|
+
const [row] = await scopedDb
|
|
11517
|
+
.select({
|
|
11518
|
+
credentialId: schema.codexAppsSettings.credentialId,
|
|
11519
|
+
version: schema.codexAppsSettings.version,
|
|
11520
|
+
designatedAt: schema.codexAppsSettings.designatedAt,
|
|
11521
|
+
})
|
|
11522
|
+
.from(schema.codexAppsSettings)
|
|
11523
|
+
.where(eq(schema.codexAppsSettings.workspaceId, workspaceId))
|
|
11524
|
+
.limit(1);
|
|
11525
|
+
return row ?? { credentialId: null, version: 0, designatedAt: null };
|
|
11526
|
+
});
|
|
11527
|
+
}
|
|
11528
|
+
|
|
11529
|
+
export type CodexAppsCredentialAuthorization = {
|
|
11530
|
+
credentialId: string;
|
|
11531
|
+
ownerSubjectId: string;
|
|
11532
|
+
};
|
|
11533
|
+
|
|
11534
|
+
function canManageCodexApps(permissions: unknown): boolean {
|
|
11535
|
+
return (
|
|
11536
|
+
Array.isArray(permissions) &&
|
|
11537
|
+
(permissions.includes("connections:write") || permissions.includes("workspace:admin"))
|
|
11538
|
+
);
|
|
11539
|
+
}
|
|
11540
|
+
|
|
11541
|
+
export class CodexAppsAuthorizationRevokedError extends Error {
|
|
11542
|
+
constructor() {
|
|
11543
|
+
super("Codex Apps authorization is no longer active");
|
|
11544
|
+
this.name = "CodexAppsAuthorizationRevokedError";
|
|
11545
|
+
}
|
|
11546
|
+
}
|
|
11547
|
+
|
|
11548
|
+
/** Exact Apps credential and owner, independent of every inference-capacity field. */
|
|
11549
|
+
export async function getCodexAppsCredentialAuthorizationForRun(
|
|
11550
|
+
db: Database,
|
|
11551
|
+
workspaceId: string,
|
|
11552
|
+
): Promise<CodexAppsCredentialAuthorization | null> {
|
|
11553
|
+
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
11554
|
+
const [row] = await scopedDb
|
|
11555
|
+
.select({
|
|
11556
|
+
credentialId: schema.codexAppsSettings.credentialId,
|
|
11557
|
+
ownerSubjectId: schema.codexSubscriptionCredentials.connectedBySubjectId,
|
|
11558
|
+
})
|
|
11559
|
+
.from(schema.codexAppsSettings)
|
|
11560
|
+
.innerJoin(
|
|
11561
|
+
schema.codexSubscriptionCredentials,
|
|
11562
|
+
and(
|
|
11563
|
+
eq(schema.codexSubscriptionCredentials.id, schema.codexAppsSettings.credentialId),
|
|
11564
|
+
eq(schema.codexSubscriptionCredentials.accountId, schema.codexAppsSettings.accountId),
|
|
11565
|
+
eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),
|
|
11566
|
+
eq(schema.codexSubscriptionCredentials.status, "active"),
|
|
11567
|
+
),
|
|
11568
|
+
)
|
|
11569
|
+
.where(eq(schema.codexAppsSettings.workspaceId, workspaceId))
|
|
11570
|
+
.limit(1);
|
|
11571
|
+
return row?.credentialId && row.ownerSubjectId
|
|
11572
|
+
? { credentialId: row.credentialId, ownerSubjectId: row.ownerSubjectId }
|
|
11573
|
+
: null;
|
|
11574
|
+
});
|
|
11575
|
+
}
|
|
11576
|
+
|
|
11577
|
+
/**
|
|
11578
|
+
* Hold the exact designation, credential, and owner-membership authorization
|
|
11579
|
+
* stable through one outbound Apps request. Clear/disconnect operations share
|
|
11580
|
+
* the workspace advisory lock; credential or membership revocation must wait on
|
|
11581
|
+
* the row locks. The callback deliberately runs inside this short transaction so
|
|
11582
|
+
* no revocation can commit in the gap between a final check and network dispatch.
|
|
11583
|
+
*/
|
|
11584
|
+
export async function withCodexAppsRequestAuthorization<T>(
|
|
11585
|
+
db: Database,
|
|
11586
|
+
input: { workspaceId: string; credentialId: string },
|
|
11587
|
+
use: () => Promise<T>,
|
|
11588
|
+
): Promise<T> {
|
|
11589
|
+
return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {
|
|
11590
|
+
await scopedDb.execute(
|
|
11591
|
+
sql`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${input.workspaceId}`}, 0))`,
|
|
11592
|
+
);
|
|
11593
|
+
const [designation] = await scopedDb
|
|
11594
|
+
.select({ credentialId: schema.codexAppsSettings.credentialId })
|
|
11595
|
+
.from(schema.codexAppsSettings)
|
|
11596
|
+
.where(eq(schema.codexAppsSettings.workspaceId, input.workspaceId))
|
|
11597
|
+
.for("share")
|
|
11598
|
+
.limit(1);
|
|
11599
|
+
if (designation?.credentialId !== input.credentialId) {
|
|
11600
|
+
throw new CodexAppsAuthorizationRevokedError();
|
|
11601
|
+
}
|
|
11602
|
+
const [credential] = await scopedDb
|
|
11603
|
+
.select({
|
|
11604
|
+
ownerSubjectId: schema.codexSubscriptionCredentials.connectedBySubjectId,
|
|
11605
|
+
status: schema.codexSubscriptionCredentials.status,
|
|
11606
|
+
})
|
|
11607
|
+
.from(schema.codexSubscriptionCredentials)
|
|
11608
|
+
.where(
|
|
11609
|
+
and(
|
|
11610
|
+
eq(schema.codexSubscriptionCredentials.workspaceId, input.workspaceId),
|
|
11611
|
+
eq(schema.codexSubscriptionCredentials.id, input.credentialId),
|
|
11612
|
+
),
|
|
11613
|
+
)
|
|
11614
|
+
.for("share")
|
|
11615
|
+
.limit(1);
|
|
11616
|
+
if (!credential?.ownerSubjectId || credential.status !== "active") {
|
|
11617
|
+
throw new CodexAppsAuthorizationRevokedError();
|
|
11618
|
+
}
|
|
11619
|
+
const [membership] = await scopedDb
|
|
11620
|
+
.select({ permissions: schema.workspaceMemberships.permissions })
|
|
11621
|
+
.from(schema.workspaceMemberships)
|
|
11622
|
+
.where(
|
|
11623
|
+
and(
|
|
11624
|
+
eq(schema.workspaceMemberships.workspaceId, input.workspaceId),
|
|
11625
|
+
eq(schema.workspaceMemberships.subjectId, credential.ownerSubjectId),
|
|
11626
|
+
),
|
|
11627
|
+
)
|
|
11628
|
+
.for("share")
|
|
11629
|
+
.limit(1);
|
|
11630
|
+
if (!canManageCodexApps(membership?.permissions)) {
|
|
11631
|
+
throw new CodexAppsAuthorizationRevokedError();
|
|
11632
|
+
}
|
|
11633
|
+
return await use();
|
|
11634
|
+
});
|
|
11635
|
+
}
|
|
11636
|
+
|
|
11637
|
+
export type DesignateCodexAppsCredentialResult =
|
|
11638
|
+
| ({ kind: "updated" } & CodexAppsSettings)
|
|
11639
|
+
| ({ kind: "conflict" | "already_designated" } & CodexAppsSettings)
|
|
11640
|
+
| { kind: "not_found" }
|
|
11641
|
+
| { kind: "not_owner" }
|
|
11642
|
+
| { kind: "forbidden" }
|
|
11643
|
+
| { kind: "unavailable" };
|
|
11644
|
+
|
|
11645
|
+
export async function designateCodexAppsCredential(
|
|
11646
|
+
db: Database,
|
|
11647
|
+
input: {
|
|
11648
|
+
accountId: string;
|
|
11649
|
+
workspaceId: string;
|
|
11650
|
+
credentialId: string;
|
|
11651
|
+
subjectId: string;
|
|
11652
|
+
expectedVersion: number;
|
|
11653
|
+
},
|
|
11654
|
+
): Promise<DesignateCodexAppsCredentialResult> {
|
|
11655
|
+
return await withRlsContext(
|
|
11656
|
+
db,
|
|
11657
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
11658
|
+
async (scopedDb) => {
|
|
11659
|
+
await scopedDb.execute(
|
|
11660
|
+
sql`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${input.workspaceId}`}, 0))`,
|
|
11661
|
+
);
|
|
11662
|
+
const [currentRow] = await scopedDb
|
|
11663
|
+
.select()
|
|
11664
|
+
.from(schema.codexAppsSettings)
|
|
11665
|
+
.where(eq(schema.codexAppsSettings.workspaceId, input.workspaceId))
|
|
11666
|
+
.for("update")
|
|
11667
|
+
.limit(1);
|
|
11668
|
+
const current: CodexAppsSettings = currentRow
|
|
11669
|
+
? {
|
|
11670
|
+
credentialId: currentRow.credentialId,
|
|
11671
|
+
version: currentRow.version,
|
|
11672
|
+
designatedAt: currentRow.designatedAt,
|
|
11673
|
+
}
|
|
11674
|
+
: { credentialId: null, version: 0, designatedAt: null };
|
|
11675
|
+
if (current.version !== input.expectedVersion) return { kind: "conflict", ...current };
|
|
11676
|
+
if (current.credentialId !== null) return { kind: "already_designated", ...current };
|
|
11677
|
+
|
|
11678
|
+
const [credential] = await scopedDb
|
|
11679
|
+
.select({
|
|
11680
|
+
connectedBySubjectId: schema.codexSubscriptionCredentials.connectedBySubjectId,
|
|
11681
|
+
status: schema.codexSubscriptionCredentials.status,
|
|
11682
|
+
})
|
|
11683
|
+
.from(schema.codexSubscriptionCredentials)
|
|
11684
|
+
.where(
|
|
11685
|
+
and(
|
|
11686
|
+
eq(schema.codexSubscriptionCredentials.accountId, input.accountId),
|
|
11687
|
+
eq(schema.codexSubscriptionCredentials.workspaceId, input.workspaceId),
|
|
11688
|
+
eq(schema.codexSubscriptionCredentials.id, input.credentialId),
|
|
11689
|
+
),
|
|
11690
|
+
)
|
|
11691
|
+
.for("update")
|
|
11692
|
+
.limit(1);
|
|
11693
|
+
if (!credential) return { kind: "not_found" };
|
|
11694
|
+
if (credential.connectedBySubjectId !== input.subjectId) return { kind: "not_owner" };
|
|
11695
|
+
if (credential.status !== "active") return { kind: "unavailable" };
|
|
11696
|
+
|
|
11697
|
+
const [membership] = await scopedDb
|
|
11698
|
+
.select({ permissions: schema.workspaceMemberships.permissions })
|
|
11699
|
+
.from(schema.workspaceMemberships)
|
|
11700
|
+
.where(
|
|
11701
|
+
and(
|
|
11702
|
+
eq(schema.workspaceMemberships.accountId, input.accountId),
|
|
11703
|
+
eq(schema.workspaceMemberships.workspaceId, input.workspaceId),
|
|
11704
|
+
eq(schema.workspaceMemberships.subjectId, input.subjectId),
|
|
11705
|
+
),
|
|
11706
|
+
)
|
|
11707
|
+
.for("update")
|
|
11708
|
+
.limit(1);
|
|
11709
|
+
if (!canManageCodexApps(membership?.permissions)) return { kind: "forbidden" };
|
|
11710
|
+
|
|
11711
|
+
const now = new Date();
|
|
11712
|
+
const version = current.version + 1;
|
|
11713
|
+
const [updated] = await scopedDb
|
|
11714
|
+
.insert(schema.codexAppsSettings)
|
|
11715
|
+
.values({
|
|
11716
|
+
accountId: input.accountId,
|
|
11717
|
+
workspaceId: input.workspaceId,
|
|
11718
|
+
credentialId: input.credentialId,
|
|
11719
|
+
version,
|
|
11720
|
+
designatedAt: now,
|
|
11721
|
+
updatedAt: now,
|
|
11722
|
+
})
|
|
11723
|
+
.onConflictDoUpdate({
|
|
11724
|
+
target: schema.codexAppsSettings.workspaceId,
|
|
11725
|
+
set: {
|
|
11726
|
+
credentialId: input.credentialId,
|
|
11727
|
+
version,
|
|
11728
|
+
designatedAt: now,
|
|
11729
|
+
updatedAt: now,
|
|
11730
|
+
},
|
|
11731
|
+
})
|
|
11732
|
+
.returning({
|
|
11733
|
+
credentialId: schema.codexAppsSettings.credentialId,
|
|
11734
|
+
version: schema.codexAppsSettings.version,
|
|
11735
|
+
designatedAt: schema.codexAppsSettings.designatedAt,
|
|
11736
|
+
});
|
|
11737
|
+
if (!updated?.credentialId || !updated.designatedAt) {
|
|
11738
|
+
throw new Error("Codex Apps designation was not persisted");
|
|
11739
|
+
}
|
|
11740
|
+
await scopedDb.insert(schema.auditEvents).values({
|
|
11741
|
+
accountId: input.accountId,
|
|
11742
|
+
workspaceId: input.workspaceId,
|
|
11743
|
+
subjectId: input.subjectId,
|
|
11744
|
+
action: "codex_apps.designated",
|
|
11745
|
+
targetType: "codex_subscription_credential",
|
|
11746
|
+
targetId: input.credentialId,
|
|
11747
|
+
metadata: { version },
|
|
11748
|
+
});
|
|
11749
|
+
return { kind: "updated", ...updated };
|
|
11750
|
+
},
|
|
11751
|
+
);
|
|
11752
|
+
}
|
|
11753
|
+
|
|
11754
|
+
export type ClearCodexAppsCredentialResult = {
|
|
11755
|
+
kind: "updated" | "unchanged" | "conflict" | "forbidden";
|
|
11756
|
+
} & CodexAppsSettings;
|
|
11757
|
+
|
|
11758
|
+
export async function clearCodexAppsCredential(
|
|
11759
|
+
db: Database,
|
|
11760
|
+
input: {
|
|
11761
|
+
accountId: string;
|
|
11762
|
+
workspaceId: string;
|
|
11763
|
+
subjectId: string;
|
|
11764
|
+
expectedVersion: number;
|
|
11765
|
+
},
|
|
11766
|
+
): Promise<ClearCodexAppsCredentialResult> {
|
|
11767
|
+
return await withRlsContext(
|
|
11768
|
+
db,
|
|
11769
|
+
{ accountId: input.accountId, workspaceId: input.workspaceId },
|
|
11770
|
+
async (scopedDb) => {
|
|
11771
|
+
await scopedDb.execute(
|
|
11772
|
+
sql`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${input.workspaceId}`}, 0))`,
|
|
11773
|
+
);
|
|
11774
|
+
const [row] = await scopedDb
|
|
11775
|
+
.select()
|
|
11776
|
+
.from(schema.codexAppsSettings)
|
|
11777
|
+
.where(eq(schema.codexAppsSettings.workspaceId, input.workspaceId))
|
|
11778
|
+
.for("update")
|
|
11779
|
+
.limit(1);
|
|
11780
|
+
const current: CodexAppsSettings = row
|
|
11781
|
+
? { credentialId: row.credentialId, version: row.version, designatedAt: row.designatedAt }
|
|
11782
|
+
: { credentialId: null, version: 0, designatedAt: null };
|
|
11783
|
+
const [membership] = await scopedDb
|
|
11784
|
+
.select({ permissions: schema.workspaceMemberships.permissions })
|
|
11785
|
+
.from(schema.workspaceMemberships)
|
|
11786
|
+
.where(
|
|
11787
|
+
and(
|
|
11788
|
+
eq(schema.workspaceMemberships.accountId, input.accountId),
|
|
11789
|
+
eq(schema.workspaceMemberships.workspaceId, input.workspaceId),
|
|
11790
|
+
eq(schema.workspaceMemberships.subjectId, input.subjectId),
|
|
11791
|
+
),
|
|
11792
|
+
)
|
|
11793
|
+
.for("update")
|
|
11794
|
+
.limit(1);
|
|
11795
|
+
if (!canManageCodexApps(membership?.permissions)) {
|
|
11796
|
+
return { kind: "forbidden", ...current };
|
|
11797
|
+
}
|
|
11798
|
+
if (current.version !== input.expectedVersion) return { kind: "conflict", ...current };
|
|
11799
|
+
if (current.credentialId === null) return { kind: "unchanged", ...current };
|
|
11800
|
+
|
|
11801
|
+
const now = new Date();
|
|
11802
|
+
const version = current.version + 1;
|
|
11803
|
+
const [updated] = await scopedDb
|
|
11804
|
+
.update(schema.codexAppsSettings)
|
|
11805
|
+
.set({
|
|
11806
|
+
credentialId: null,
|
|
11807
|
+
version,
|
|
11808
|
+
designatedAt: null,
|
|
11809
|
+
updatedAt: now,
|
|
11810
|
+
})
|
|
11811
|
+
.where(eq(schema.codexAppsSettings.workspaceId, input.workspaceId))
|
|
11812
|
+
.returning({
|
|
11813
|
+
credentialId: schema.codexAppsSettings.credentialId,
|
|
11814
|
+
version: schema.codexAppsSettings.version,
|
|
11815
|
+
designatedAt: schema.codexAppsSettings.designatedAt,
|
|
11816
|
+
});
|
|
11817
|
+
if (!updated) throw new Error("Codex Apps designation clear was not persisted");
|
|
11818
|
+
await scopedDb.insert(schema.auditEvents).values({
|
|
11819
|
+
accountId: input.accountId,
|
|
11820
|
+
workspaceId: input.workspaceId,
|
|
11821
|
+
subjectId: input.subjectId,
|
|
11822
|
+
action: "codex_apps.cleared",
|
|
11823
|
+
targetType: "codex_subscription_credential",
|
|
11824
|
+
targetId: current.credentialId,
|
|
11825
|
+
metadata: { version },
|
|
11826
|
+
});
|
|
11827
|
+
return { kind: "updated", ...updated };
|
|
11828
|
+
},
|
|
11829
|
+
);
|
|
11830
|
+
}
|
|
11831
|
+
|
|
11506
11832
|
/**
|
|
11507
11833
|
* The ONLY decrypt-read accessor. Fails closed. Never call from an API route that
|
|
11508
11834
|
* returns the result.
|
|
@@ -11989,11 +12315,6 @@ export type CodexAccountStatus = {
|
|
|
11989
12315
|
// P3 rotation cooldown: when set and in the future, this account is cooling-down
|
|
11990
12316
|
// (rotated-off after a usage cap) and the engine skips it. null ⇒ not cooling.
|
|
11991
12317
|
exhaustedUntil: Date | null;
|
|
11992
|
-
// P4 connector-aware rotation: the ORIGINAL-dotted connector namespaces this
|
|
11993
|
-
// account exposes via codex_apps (github/gmail/linear/…). null ⇒ never probed
|
|
11994
|
-
// (the ranker treats it as unknown: never credited as covering, never excluded).
|
|
11995
|
-
connectorNamespaces: string[] | null;
|
|
11996
|
-
connectorsCheckedAt: Date | null;
|
|
11997
12318
|
};
|
|
11998
12319
|
|
|
11999
12320
|
/**
|
|
@@ -12112,8 +12433,6 @@ type CodexLeaseCandidateRow = {
|
|
|
12112
12433
|
secondary_reset_at: Date | string | null;
|
|
12113
12434
|
usage_checked_at: Date | string | null;
|
|
12114
12435
|
exhausted_until: Date | string | null;
|
|
12115
|
-
connector_namespaces: string[] | null;
|
|
12116
|
-
connectors_checked_at: Date | string | null;
|
|
12117
12436
|
selection_count: number;
|
|
12118
12437
|
last_selected_at: Date | string | null;
|
|
12119
12438
|
active_lease_count: number;
|
|
@@ -12146,8 +12465,6 @@ function mapCodexLeaseCandidate(
|
|
|
12146
12465
|
secondaryResetAt: codexMetadataDate(row.secondary_reset_at),
|
|
12147
12466
|
usageCheckedAt: codexMetadataDate(row.usage_checked_at),
|
|
12148
12467
|
exhaustedUntil: codexMetadataDate(row.exhausted_until),
|
|
12149
|
-
connectorNamespaces: row.connector_namespaces,
|
|
12150
|
-
connectorsCheckedAt: codexMetadataDate(row.connectors_checked_at),
|
|
12151
12468
|
selectionCount: Number(row.selection_count),
|
|
12152
12469
|
lastSelectedAt: codexMetadataDate(row.last_selected_at),
|
|
12153
12470
|
activeLeaseCount: Number(row.active_lease_count),
|
|
@@ -12207,8 +12524,6 @@ async function listCodexLeaseCandidatesInTransaction(
|
|
|
12207
12524
|
c.secondary_reset_at,
|
|
12208
12525
|
c.usage_checked_at,
|
|
12209
12526
|
c.exhausted_until,
|
|
12210
|
-
c.connector_namespaces,
|
|
12211
|
-
c.connectors_checked_at,
|
|
12212
12527
|
c.selection_count,
|
|
12213
12528
|
c.last_selected_at,
|
|
12214
12529
|
count(l.id) filter (
|
|
@@ -12255,8 +12570,6 @@ export async function acquireCodexCredentialLease<
|
|
|
12255
12570
|
holderId: string;
|
|
12256
12571
|
/** Pins must not move the workspace-global cursor. */
|
|
12257
12572
|
advanceActivePointer: boolean;
|
|
12258
|
-
/** Exact frozen credential for this same durable turn, if it is resuming. */
|
|
12259
|
-
continuationCredentialId?: string | null;
|
|
12260
12573
|
/**
|
|
12261
12574
|
* Optional downstream parser for private accepted-turn policy metadata.
|
|
12262
12575
|
* It is pure, runs under the turn/rotation transaction, and must not query
|
|
@@ -12265,8 +12578,8 @@ export async function acquireCodexCredentialLease<
|
|
|
12265
12578
|
resolvePolicyScope?: CodexCredentialLeasePolicyScopeResolver<TPolicyScope>;
|
|
12266
12579
|
/**
|
|
12267
12580
|
* Optional downstream membership policy for NEW allocations only. A live
|
|
12268
|
-
* lease
|
|
12269
|
-
*
|
|
12581
|
+
* exact-turn lease is offered to the selector against the complete workspace
|
|
12582
|
+
* rows first and can never be filtered out here.
|
|
12270
12583
|
*/
|
|
12271
12584
|
filterNewAllocationCandidates?: CodexCredentialLeaseCandidateFilter<
|
|
12272
12585
|
TPolicyScope,
|
|
@@ -12332,23 +12645,6 @@ export async function acquireCodexCredentialLease<
|
|
|
12332
12645
|
throw new Error(`Session turn not found for Codex lease: ${input.turnId}`);
|
|
12333
12646
|
}
|
|
12334
12647
|
const policyScope = input.resolvePolicyScope?.(turns[0].metadata ?? {}) ?? null;
|
|
12335
|
-
const continuationRows = input.continuationCredentialId
|
|
12336
|
-
? await tx.execute(
|
|
12337
|
-
sql<{ frozen_codex_credential_id: string | null }>`
|
|
12338
|
-
select frozen_codex_credential_id
|
|
12339
|
-
from agent_run_states
|
|
12340
|
-
where account_id = ${input.accountId}
|
|
12341
|
-
and workspace_id = ${input.workspaceId}
|
|
12342
|
-
and turn_id = ${input.turnId}
|
|
12343
|
-
order by state_version desc
|
|
12344
|
-
limit 1
|
|
12345
|
-
`,
|
|
12346
|
-
)
|
|
12347
|
-
: [];
|
|
12348
|
-
const validatedContinuationCredentialId =
|
|
12349
|
-
continuationRows[0]?.frozen_codex_credential_id === input.continuationCredentialId
|
|
12350
|
-
? input.continuationCredentialId
|
|
12351
|
-
: null;
|
|
12352
12648
|
const activeCredentialId = settingsRow.active_credential_id;
|
|
12353
12649
|
const rotationEnabled = settingsRow.rotation_enabled;
|
|
12354
12650
|
// Fail closed on a torn/manual legacy write. The user-intent bit and the
|
|
@@ -12390,7 +12686,7 @@ export async function acquireCodexCredentialLease<
|
|
|
12390
12686
|
activeCredentialId,
|
|
12391
12687
|
excludeTurnId: input.turnId,
|
|
12392
12688
|
});
|
|
12393
|
-
const sameTurnCredentialId = existingCredentialId
|
|
12689
|
+
const sameTurnCredentialId = existingCredentialId;
|
|
12394
12690
|
const selectionContext = (
|
|
12395
12691
|
accounts: CodexLeaseAccountStatus[],
|
|
12396
12692
|
unavailableDiagnostics: readonly TUnavailableDiagnostic[],
|
|
@@ -12414,10 +12710,9 @@ export async function acquireCodexCredentialLease<
|
|
|
12414
12710
|
}
|
|
12415
12711
|
}
|
|
12416
12712
|
|
|
12417
|
-
//
|
|
12713
|
+
// A live exact-turn lease is resolved before any future pool membership
|
|
12418
12714
|
// filter. The normal selector still owns health validation: a quarantined
|
|
12419
|
-
//
|
|
12420
|
-
// being reused blindly.
|
|
12715
|
+
// row falls through to scoped new acquisition rather than being reused.
|
|
12421
12716
|
if (!selected) {
|
|
12422
12717
|
const filtered = filterCodexLeaseCandidatesForPolicy(
|
|
12423
12718
|
allAccounts,
|
|
@@ -12454,11 +12749,7 @@ export async function acquireCodexCredentialLease<
|
|
|
12454
12749
|
if (!selectedAccount) {
|
|
12455
12750
|
throw new Error("Codex lease selector returned a credential outside the workspace pool");
|
|
12456
12751
|
}
|
|
12457
|
-
if (
|
|
12458
|
-
!selectedAccount.allocatorEnabled &&
|
|
12459
|
-
selectedAccount.id !== existingCredentialId &&
|
|
12460
|
-
selectedAccount.id !== validatedContinuationCredentialId
|
|
12461
|
-
) {
|
|
12752
|
+
if (!selectedAccount.allocatorEnabled && selectedAccount.id !== existingCredentialId) {
|
|
12462
12753
|
throw new Error("Codex lease selector returned a credential disabled for new allocations");
|
|
12463
12754
|
}
|
|
12464
12755
|
|
|
@@ -13873,9 +14164,6 @@ export async function listCodexAccountStatuses(
|
|
|
13873
14164
|
secondaryResetAt: schema.codexSubscriptionCredentials.secondaryResetAt,
|
|
13874
14165
|
usageCheckedAt: schema.codexSubscriptionCredentials.usageCheckedAt,
|
|
13875
14166
|
exhaustedUntil: schema.codexSubscriptionCredentials.exhaustedUntil,
|
|
13876
|
-
// P4 connector-set cache — metadata-only, rides along on this read.
|
|
13877
|
-
connectorNamespaces: schema.codexSubscriptionCredentials.connectorNamespaces,
|
|
13878
|
-
connectorsCheckedAt: schema.codexSubscriptionCredentials.connectorsCheckedAt,
|
|
13879
14167
|
})
|
|
13880
14168
|
.from(schema.codexSubscriptionCredentials)
|
|
13881
14169
|
.where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))
|
|
@@ -13893,7 +14181,6 @@ export async function listCodexAccountStatuses(
|
|
|
13893
14181
|
secondaryResetAt: codexMetadataDate(row.secondaryResetAt),
|
|
13894
14182
|
usageCheckedAt: codexMetadataDate(row.usageCheckedAt),
|
|
13895
14183
|
exhaustedUntil: codexMetadataDate(row.exhaustedUntil),
|
|
13896
|
-
connectorsCheckedAt: codexMetadataDate(row.connectorsCheckedAt),
|
|
13897
14184
|
isActive: row.id === activeId,
|
|
13898
14185
|
}));
|
|
13899
14186
|
});
|
|
@@ -15156,46 +15443,6 @@ export async function countConsecutiveReactiveRotations(
|
|
|
15156
15443
|
});
|
|
15157
15444
|
}
|
|
15158
15445
|
|
|
15159
|
-
/**
|
|
15160
|
-
* P4 connector-set cache writer: persist the set of ORIGINAL-dotted connector
|
|
15161
|
-
* namespaces a SPECIFIC credential exposes via codex_apps (+ the freshness clock).
|
|
15162
|
-
* Modeled byte-for-byte on recordCodexAccountUsage / setCodexCredentialExhausted:
|
|
15163
|
-
* RLS-scoped, guarded by (id, workspace_id), and — critically — NO `version` bump and
|
|
15164
|
-
* NO `updatedAt` touch, so it can never race the (id, version) token-refresh CAS.
|
|
15165
|
-
*
|
|
15166
|
-
* The CALLER must only invoke this with a NON-EMPTY set: codex_apps connects
|
|
15167
|
-
* best-effort (a transient failure yields an empty tools/list), and overwriting a
|
|
15168
|
-
* known non-empty set with [] would falsely "drop" coverage on a flaky turn. A
|
|
15169
|
-
* genuinely connector-less account stays null (the ranker treats null as unknown).
|
|
15170
|
-
* Returns true iff a row was updated (false ⇒ the credential was disconnected under us).
|
|
15171
|
-
*/
|
|
15172
|
-
export async function recordCodexAccountConnectors(
|
|
15173
|
-
db: Database,
|
|
15174
|
-
workspaceId: string,
|
|
15175
|
-
credentialId: string,
|
|
15176
|
-
namespaces: string[],
|
|
15177
|
-
): Promise<boolean> {
|
|
15178
|
-
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
15179
|
-
const updated = await scopedDb
|
|
15180
|
-
.update(schema.codexSubscriptionCredentials)
|
|
15181
|
-
.set({
|
|
15182
|
-
connectorNamespaces: namespaces,
|
|
15183
|
-
connectorsCheckedAt: new Date(),
|
|
15184
|
-
// NB: no `version` bump and no `updatedAt` touch — connector set is non-credential
|
|
15185
|
-
// metadata and must NOT race the (id, version) refresh CAS (same discipline as
|
|
15186
|
-
// recordCodexAccountUsage / setCodexCredentialExhausted).
|
|
15187
|
-
})
|
|
15188
|
-
.where(
|
|
15189
|
-
and(
|
|
15190
|
-
eq(schema.codexSubscriptionCredentials.id, credentialId),
|
|
15191
|
-
eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId),
|
|
15192
|
-
),
|
|
15193
|
-
)
|
|
15194
|
-
.returning({ id: schema.codexSubscriptionCredentials.id });
|
|
15195
|
-
return updated.length > 0;
|
|
15196
|
-
});
|
|
15197
|
-
}
|
|
15198
|
-
|
|
15199
15446
|
/** The supported rotation strategies (P3). */
|
|
15200
15447
|
export const CODEX_ROTATION_STRATEGIES = [
|
|
15201
15448
|
"most_remaining",
|
|
@@ -15406,6 +15653,7 @@ export async function disconnectCodexAccount(
|
|
|
15406
15653
|
db: Database,
|
|
15407
15654
|
workspaceId: string,
|
|
15408
15655
|
credentialId: string,
|
|
15656
|
+
actorSubjectId: string | null = null,
|
|
15409
15657
|
): Promise<{
|
|
15410
15658
|
removed: boolean;
|
|
15411
15659
|
newActiveCredentialId: string | null;
|
|
@@ -15417,8 +15665,20 @@ export async function disconnectCodexAccount(
|
|
|
15417
15665
|
where workspace_id = ${workspaceId}
|
|
15418
15666
|
for update
|
|
15419
15667
|
`);
|
|
15668
|
+
await scopedDb.execute(
|
|
15669
|
+
sql`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${workspaceId}`}, 0))`,
|
|
15670
|
+
);
|
|
15671
|
+
const [appsSettings] = await scopedDb
|
|
15672
|
+
.select()
|
|
15673
|
+
.from(schema.codexAppsSettings)
|
|
15674
|
+
.where(eq(schema.codexAppsSettings.workspaceId, workspaceId))
|
|
15675
|
+
.for("update")
|
|
15676
|
+
.limit(1);
|
|
15420
15677
|
const [credential] = await scopedDb
|
|
15421
|
-
.select({
|
|
15678
|
+
.select({
|
|
15679
|
+
id: schema.codexSubscriptionCredentials.id,
|
|
15680
|
+
accountId: schema.codexSubscriptionCredentials.accountId,
|
|
15681
|
+
})
|
|
15422
15682
|
.from(schema.codexSubscriptionCredentials)
|
|
15423
15683
|
.where(
|
|
15424
15684
|
and(
|
|
@@ -15460,6 +15720,27 @@ export async function disconnectCodexAccount(
|
|
|
15460
15720
|
blockedByUnresolvedRedemption: true,
|
|
15461
15721
|
};
|
|
15462
15722
|
}
|
|
15723
|
+
if (appsSettings?.credentialId === credentialId) {
|
|
15724
|
+
const version = appsSettings.version + 1;
|
|
15725
|
+
await scopedDb
|
|
15726
|
+
.update(schema.codexAppsSettings)
|
|
15727
|
+
.set({
|
|
15728
|
+
credentialId: null,
|
|
15729
|
+
version,
|
|
15730
|
+
designatedAt: null,
|
|
15731
|
+
updatedAt: new Date(),
|
|
15732
|
+
})
|
|
15733
|
+
.where(eq(schema.codexAppsSettings.id, appsSettings.id));
|
|
15734
|
+
await scopedDb.insert(schema.auditEvents).values({
|
|
15735
|
+
accountId: credential.accountId,
|
|
15736
|
+
workspaceId,
|
|
15737
|
+
subjectId: actorSubjectId,
|
|
15738
|
+
action: "codex_apps.cleared_on_disconnect",
|
|
15739
|
+
targetType: "codex_subscription_credential",
|
|
15740
|
+
targetId: credentialId,
|
|
15741
|
+
metadata: { version },
|
|
15742
|
+
});
|
|
15743
|
+
}
|
|
15463
15744
|
const removedRows = await scopedDb
|
|
15464
15745
|
.delete(schema.codexSubscriptionCredentials)
|
|
15465
15746
|
.where(
|
|
@@ -15512,10 +15793,23 @@ export async function disconnectCodexAccount(
|
|
|
15512
15793
|
export async function disconnectAllCodexAccounts(
|
|
15513
15794
|
db: Database,
|
|
15514
15795
|
workspaceId: string,
|
|
15796
|
+
actorSubjectId: string | null = null,
|
|
15515
15797
|
): Promise<{ removed: number; blockedCredentialIds: string[] }> {
|
|
15516
15798
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
15799
|
+
await scopedDb.execute(
|
|
15800
|
+
sql`select pg_advisory_xact_lock(hashtextextended(${`codex-apps-settings:${workspaceId}`}, 0))`,
|
|
15801
|
+
);
|
|
15802
|
+
const [appsSettings] = await scopedDb
|
|
15803
|
+
.select()
|
|
15804
|
+
.from(schema.codexAppsSettings)
|
|
15805
|
+
.where(eq(schema.codexAppsSettings.workspaceId, workspaceId))
|
|
15806
|
+
.for("update")
|
|
15807
|
+
.limit(1);
|
|
15517
15808
|
const credentials = await scopedDb
|
|
15518
|
-
.select({
|
|
15809
|
+
.select({
|
|
15810
|
+
id: schema.codexSubscriptionCredentials.id,
|
|
15811
|
+
accountId: schema.codexSubscriptionCredentials.accountId,
|
|
15812
|
+
})
|
|
15519
15813
|
.from(schema.codexSubscriptionCredentials)
|
|
15520
15814
|
.where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))
|
|
15521
15815
|
.orderBy(asc(schema.codexSubscriptionCredentials.id))
|
|
@@ -15538,6 +15832,27 @@ export async function disconnectAllCodexAccounts(
|
|
|
15538
15832
|
blockedCredentialIds: blocked.map((row) => row.credentialId).sort(),
|
|
15539
15833
|
};
|
|
15540
15834
|
}
|
|
15835
|
+
if (appsSettings?.credentialId) {
|
|
15836
|
+
const version = appsSettings.version + 1;
|
|
15837
|
+
await scopedDb
|
|
15838
|
+
.update(schema.codexAppsSettings)
|
|
15839
|
+
.set({
|
|
15840
|
+
credentialId: null,
|
|
15841
|
+
version,
|
|
15842
|
+
designatedAt: null,
|
|
15843
|
+
updatedAt: new Date(),
|
|
15844
|
+
})
|
|
15845
|
+
.where(eq(schema.codexAppsSettings.id, appsSettings.id));
|
|
15846
|
+
await scopedDb.insert(schema.auditEvents).values({
|
|
15847
|
+
accountId: credentials[0]!.accountId,
|
|
15848
|
+
workspaceId,
|
|
15849
|
+
subjectId: actorSubjectId,
|
|
15850
|
+
action: "codex_apps.cleared_on_disconnect",
|
|
15851
|
+
targetType: "codex_subscription_credential",
|
|
15852
|
+
targetId: appsSettings.credentialId,
|
|
15853
|
+
metadata: { version },
|
|
15854
|
+
});
|
|
15855
|
+
}
|
|
15541
15856
|
const rows = await scopedDb
|
|
15542
15857
|
.delete(schema.codexSubscriptionCredentials)
|
|
15543
15858
|
.where(eq(schema.codexSubscriptionCredentials.workspaceId, workspaceId))
|
|
@@ -17117,6 +17432,18 @@ async function lockSessionCreateIdempotencyKey(
|
|
|
17117
17432
|
);
|
|
17118
17433
|
}
|
|
17119
17434
|
|
|
17435
|
+
async function lockAgentSessionCreate(tx: Database, input: SessionCreateInput): Promise<void> {
|
|
17436
|
+
const actorSessionId = input.createdByActor?.sessionId;
|
|
17437
|
+
if (!actorSessionId) return;
|
|
17438
|
+
// Agent-originated child creation first reads the parent under FOR SHARE,
|
|
17439
|
+
// then verifies the live attempt under FOR UPDATE. Serialize creates from
|
|
17440
|
+
// the same parent session so concurrent tool calls cannot deadlock while
|
|
17441
|
+
// upgrading that row lock. Unrelated sessions retain full concurrency.
|
|
17442
|
+
await tx.execute(
|
|
17443
|
+
sql`select pg_advisory_xact_lock(hashtextextended(${`agent-session-create:${input.workspaceId}:${actorSessionId}`}, 0))`,
|
|
17444
|
+
);
|
|
17445
|
+
}
|
|
17446
|
+
|
|
17120
17447
|
async function existingSpawnDenialForKey(
|
|
17121
17448
|
tx: Database,
|
|
17122
17449
|
workspaceId: string,
|
|
@@ -17222,6 +17549,8 @@ async function createSessionInTransaction(
|
|
|
17222
17549
|
}
|
|
17223
17550
|
}
|
|
17224
17551
|
|
|
17552
|
+
await lockAgentSessionCreate(tx, input);
|
|
17553
|
+
|
|
17225
17554
|
const decision = await resolveSessionDepthDecision(tx, input, id, workspace, deploymentPolicy);
|
|
17226
17555
|
if (decision.denied) {
|
|
17227
17556
|
return {
|
|
@@ -20250,11 +20579,6 @@ export async function getLatestRunState(
|
|
|
20250
20579
|
turnId: string | null;
|
|
20251
20580
|
serializedRunState: string;
|
|
20252
20581
|
pendingApprovals: unknown[];
|
|
20253
|
-
// The codex account that froze this state (pin > workspace-active), or null
|
|
20254
|
-
// when frozen on the non-codex path / before the column existed. The replay
|
|
20255
|
-
// path compares it to the resuming turn's codex account to decide whether the
|
|
20256
|
-
// blob's account-bound reasoning must be neutralized before being replayed.
|
|
20257
|
-
frozenCodexCredentialId: string | null;
|
|
20258
20582
|
providerArtifactInvalidatedAt: Date | null;
|
|
20259
20583
|
} | null> {
|
|
20260
20584
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
@@ -20275,7 +20599,6 @@ export async function getLatestRunState(
|
|
|
20275
20599
|
turnId: row.turnId ?? null,
|
|
20276
20600
|
serializedRunState: row.serializedRunState,
|
|
20277
20601
|
pendingApprovals: row.pendingApprovals,
|
|
20278
|
-
frozenCodexCredentialId: row.frozenCodexCredentialId ?? null,
|
|
20279
20602
|
providerArtifactInvalidatedAt: row.providerArtifactInvalidatedAt ?? null,
|
|
20280
20603
|
}
|
|
20281
20604
|
: null;
|
|
@@ -21032,10 +21355,6 @@ export async function appendSessionHistoryItems(
|
|
|
21032
21355
|
turnId: string;
|
|
21033
21356
|
expectedExecutionGeneration: number;
|
|
21034
21357
|
expectedAttemptId: string;
|
|
21035
|
-
// The codex account that produced these items (the turn's resolved credential
|
|
21036
|
-
// id), or null/undefined on the non-codex path. Stored verbatim so the read
|
|
21037
|
-
// path can strip cross-account reasoning.encrypted_content blobs per turn.
|
|
21038
|
-
producerCodexCredentialId?: string | null;
|
|
21039
21358
|
modelToolOutputTruncationTokens?: number;
|
|
21040
21359
|
items: Array<{ position: number; item: Record<string, unknown> }>;
|
|
21041
21360
|
},
|
|
@@ -21064,7 +21383,6 @@ export async function appendSessionHistoryItems(
|
|
|
21064
21383
|
workspaceId: input.workspaceId,
|
|
21065
21384
|
sessionId: input.sessionId,
|
|
21066
21385
|
turnId: input.turnId,
|
|
21067
|
-
producerCodexCredentialId: input.producerCodexCredentialId ?? null,
|
|
21068
21386
|
position: entry.position,
|
|
21069
21387
|
// This is the canonical model-memory boundary. The pending-call
|
|
21070
21388
|
// ledger and audit event may retain their separate raw/preview
|
|
@@ -21443,18 +21761,18 @@ export async function getActiveSessionHistoryItems(
|
|
|
21443
21761
|
sessionId: string,
|
|
21444
21762
|
): Promise<
|
|
21445
21763
|
Array<{
|
|
21764
|
+
id: string;
|
|
21446
21765
|
position: number;
|
|
21447
21766
|
item: Record<string, unknown>;
|
|
21448
|
-
producerCodexCredentialId: string | null;
|
|
21449
21767
|
providerArtifactInvalidatedAt: Date | null;
|
|
21450
21768
|
}>
|
|
21451
21769
|
> {
|
|
21452
21770
|
return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
|
|
21453
21771
|
const rows = await scopedDb
|
|
21454
21772
|
.select({
|
|
21773
|
+
id: schema.sessionHistoryItems.id,
|
|
21455
21774
|
position: schema.sessionHistoryItems.position,
|
|
21456
21775
|
item: schema.sessionHistoryItems.item,
|
|
21457
|
-
producerCodexCredentialId: schema.sessionHistoryItems.producerCodexCredentialId,
|
|
21458
21776
|
providerArtifactInvalidatedAt: schema.sessionHistoryItems.providerArtifactInvalidatedAt,
|
|
21459
21777
|
})
|
|
21460
21778
|
.from(schema.sessionHistoryItems)
|
|
@@ -21652,8 +21970,6 @@ export async function applyContextCompaction(
|
|
|
21652
21970
|
replacementInputTokens: number;
|
|
21653
21971
|
clearRequestedCompaction?: boolean;
|
|
21654
21972
|
eventPayload?: Record<string, unknown>;
|
|
21655
|
-
/** Tag inserted history rows with the Codex credential that produced them. */
|
|
21656
|
-
producerCodexCredentialId?: string | null;
|
|
21657
21973
|
},
|
|
21658
21974
|
): Promise<ApplyContextCompactionResult> {
|
|
21659
21975
|
return await withRlsContext(
|
|
@@ -21703,9 +22019,6 @@ export async function applyContextCompaction(
|
|
|
21703
22019
|
position: supersededFrom + index,
|
|
21704
22020
|
item: sanitizeModelPayload(item),
|
|
21705
22021
|
active: true,
|
|
21706
|
-
...(input.producerCodexCredentialId
|
|
21707
|
-
? { producerCodexCredentialId: input.producerCodexCredentialId }
|
|
21708
|
-
: {}),
|
|
21709
22022
|
})),
|
|
21710
22023
|
);
|
|
21711
22024
|
}
|
|
@@ -21718,9 +22031,6 @@ export async function applyContextCompaction(
|
|
|
21718
22031
|
position: summaryPosition,
|
|
21719
22032
|
item: sanitizeModelPayload(input.summaryItem),
|
|
21720
22033
|
active: true,
|
|
21721
|
-
...(input.producerCodexCredentialId
|
|
21722
|
-
? { producerCodexCredentialId: input.producerCodexCredentialId }
|
|
21723
|
-
: {}),
|
|
21724
22034
|
});
|
|
21725
22035
|
const insertedEvents = input.eventPayload
|
|
21726
22036
|
? await tx
|
|
@@ -34416,11 +34726,6 @@ export async function saveRunState(
|
|
|
34416
34726
|
expectedAttemptId: string;
|
|
34417
34727
|
serializedRunState: string;
|
|
34418
34728
|
pendingApprovals: unknown[];
|
|
34419
|
-
// The codex account freezing this state (the turn's resolved credential id),
|
|
34420
|
-
// or null on a non-codex turn. Stamped so a resume on a DIFFERENT codex
|
|
34421
|
-
// account can strip the blob's account-bound reasoning. Defaults null so
|
|
34422
|
-
// every legacy caller (and the non-codex path) is byte-identical.
|
|
34423
|
-
frozenCodexCredentialId?: string | null;
|
|
34424
34729
|
},
|
|
34425
34730
|
): Promise<boolean> {
|
|
34426
34731
|
return await withRlsContext(
|
|
@@ -34455,7 +34760,6 @@ export async function saveRunState(
|
|
|
34455
34760
|
stateVersion: Number(maxVersion) + 1,
|
|
34456
34761
|
serializedRunState: input.serializedRunState,
|
|
34457
34762
|
pendingApprovals: input.pendingApprovals,
|
|
34458
|
-
frozenCodexCredentialId: input.frozenCodexCredentialId ?? null,
|
|
34459
34763
|
});
|
|
34460
34764
|
return true;
|
|
34461
34765
|
});
|
|
@@ -37165,7 +37469,6 @@ export async function claimSessionWorkForAttempt(
|
|
|
37165
37469
|
turnId,
|
|
37166
37470
|
position: Number(position),
|
|
37167
37471
|
item: sanitizeModelPayload(delivered.historyItem),
|
|
37168
|
-
producerCodexCredentialId: null,
|
|
37169
37472
|
});
|
|
37170
37473
|
};
|
|
37171
37474
|
|
|
@@ -38213,7 +38516,6 @@ export async function claimSessionWorkForAttempt(
|
|
|
38213
38516
|
row.prompt,
|
|
38214
38517
|
Array.isArray(row.resources) ? (row.resources as ResourceRef[]) : [],
|
|
38215
38518
|
),
|
|
38216
|
-
producerCodexCredentialId: null,
|
|
38217
38519
|
});
|
|
38218
38520
|
const providerDelegatedTurn = isSessionRealtimeDelegationTurnMetadata(row.metadata);
|
|
38219
38521
|
// Cross-session updates are already projected through
|
|
@@ -39849,7 +40151,6 @@ export type ApplySessionTurnSettlementInput = {
|
|
|
39849
40151
|
runState?: {
|
|
39850
40152
|
serializedRunState: string;
|
|
39851
40153
|
pendingApprovals: unknown[];
|
|
39852
|
-
frozenCodexCredentialId?: string | null;
|
|
39853
40154
|
humanInputRequests?: Array<{
|
|
39854
40155
|
id: string;
|
|
39855
40156
|
toolCallId: string;
|
|
@@ -40078,7 +40379,6 @@ export async function applySessionTurnSettlement(
|
|
|
40078
40379
|
stateVersion: Number(maxVersion) + 1,
|
|
40079
40380
|
serializedRunState: input.runState.serializedRunState,
|
|
40080
40381
|
pendingApprovals: input.runState.pendingApprovals,
|
|
40081
|
-
frozenCodexCredentialId: input.runState.frozenCodexCredentialId ?? null,
|
|
40082
40382
|
});
|
|
40083
40383
|
if (humanInputRequests.length > 0) {
|
|
40084
40384
|
for (const request of humanInputRequests) {
|
|
@@ -41063,7 +41363,8 @@ export type RequestSessionTurnRecoveryInput = {
|
|
|
41063
41363
|
providerRecoveryCount?: number;
|
|
41064
41364
|
fromStatuses?: SessionTurnStatus[];
|
|
41065
41365
|
providerArtifactInvalidation?: {
|
|
41066
|
-
|
|
41366
|
+
historyItemIds: string[];
|
|
41367
|
+
runStateId?: string;
|
|
41067
41368
|
reason: "encrypted_content_rejected";
|
|
41068
41369
|
};
|
|
41069
41370
|
};
|
|
@@ -41166,47 +41467,36 @@ export async function requestSessionTurnRecovery(
|
|
|
41166
41467
|
}
|
|
41167
41468
|
let providerArtifactsInvalidated = 0;
|
|
41168
41469
|
if (input.providerArtifactInvalidation) {
|
|
41169
|
-
const
|
|
41170
|
-
|
|
41171
|
-
.
|
|
41172
|
-
|
|
41173
|
-
|
|
41174
|
-
|
|
41175
|
-
|
|
41176
|
-
|
|
41177
|
-
|
|
41178
|
-
|
|
41179
|
-
|
|
41180
|
-
|
|
41181
|
-
|
|
41182
|
-
|
|
41183
|
-
|
|
41184
|
-
|
|
41185
|
-
|
|
41186
|
-
|
|
41187
|
-
|
|
41188
|
-
|
|
41189
|
-
|
|
41190
|
-
|
|
41191
|
-
|
|
41192
|
-
|
|
41193
|
-
|
|
41194
|
-
|
|
41195
|
-
|
|
41196
|
-
|
|
41197
|
-
|
|
41198
|
-
|
|
41199
|
-
eq(schema.agentRunStates.turnId, input.turnId),
|
|
41200
|
-
eq(
|
|
41201
|
-
schema.agentRunStates.frozenCodexCredentialId,
|
|
41202
|
-
input.providerArtifactInvalidation.codexCredentialId,
|
|
41203
|
-
),
|
|
41204
|
-
isNull(schema.agentRunStates.providerArtifactInvalidatedAt),
|
|
41205
|
-
),
|
|
41206
|
-
)
|
|
41207
|
-
.orderBy(desc(schema.agentRunStates.stateVersion))
|
|
41208
|
-
.limit(1);
|
|
41209
|
-
const invalidatedRunState = latestRunState
|
|
41470
|
+
const historyItemIds = [...new Set(input.providerArtifactInvalidation.historyItemIds)];
|
|
41471
|
+
const invalidatedHistory =
|
|
41472
|
+
historyItemIds.length > 0
|
|
41473
|
+
? await tx
|
|
41474
|
+
.update(schema.sessionHistoryItems)
|
|
41475
|
+
.set({
|
|
41476
|
+
providerArtifactInvalidatedAt: now,
|
|
41477
|
+
providerArtifactInvalidationReason: input.providerArtifactInvalidation.reason,
|
|
41478
|
+
providerArtifactInvalidatedByAttemptId: input.attemptId,
|
|
41479
|
+
})
|
|
41480
|
+
.where(
|
|
41481
|
+
and(
|
|
41482
|
+
eq(schema.sessionHistoryItems.accountId, session.accountId),
|
|
41483
|
+
eq(schema.sessionHistoryItems.workspaceId, workspaceId),
|
|
41484
|
+
eq(schema.sessionHistoryItems.sessionId, input.sessionId),
|
|
41485
|
+
eq(schema.sessionHistoryItems.active, true),
|
|
41486
|
+
inArray(schema.sessionHistoryItems.id, historyItemIds),
|
|
41487
|
+
isNull(schema.sessionHistoryItems.providerArtifactInvalidatedAt),
|
|
41488
|
+
sql`${schema.sessionHistoryItems.item} ->> 'type' in ('reasoning', 'compaction')`,
|
|
41489
|
+
sql`(
|
|
41490
|
+
nullif(${schema.sessionHistoryItems.item} ->> 'encrypted_content', '') is not null
|
|
41491
|
+
or nullif(${schema.sessionHistoryItems.item} ->> 'encryptedContent', '') is not null
|
|
41492
|
+
or nullif(${schema.sessionHistoryItems.item} -> 'providerData' ->> 'encrypted_content', '') is not null
|
|
41493
|
+
or nullif(${schema.sessionHistoryItems.item} -> 'providerData' ->> 'encryptedContent', '') is not null
|
|
41494
|
+
)`,
|
|
41495
|
+
),
|
|
41496
|
+
)
|
|
41497
|
+
.returning({ id: schema.sessionHistoryItems.id })
|
|
41498
|
+
: [];
|
|
41499
|
+
const invalidatedRunState = input.providerArtifactInvalidation.runStateId
|
|
41210
41500
|
? await tx
|
|
41211
41501
|
.update(schema.agentRunStates)
|
|
41212
41502
|
.set({
|
|
@@ -41216,8 +41506,20 @@ export async function requestSessionTurnRecovery(
|
|
|
41216
41506
|
})
|
|
41217
41507
|
.where(
|
|
41218
41508
|
and(
|
|
41219
|
-
eq(schema.agentRunStates.
|
|
41509
|
+
eq(schema.agentRunStates.accountId, session.accountId),
|
|
41510
|
+
eq(schema.agentRunStates.workspaceId, workspaceId),
|
|
41511
|
+
eq(schema.agentRunStates.sessionId, input.sessionId),
|
|
41512
|
+
eq(schema.agentRunStates.turnId, input.turnId),
|
|
41513
|
+
eq(schema.agentRunStates.id, input.providerArtifactInvalidation.runStateId),
|
|
41220
41514
|
isNull(schema.agentRunStates.providerArtifactInvalidatedAt),
|
|
41515
|
+
sql`${schema.agentRunStates.stateVersion} = (
|
|
41516
|
+
select max(latest.state_version)
|
|
41517
|
+
from agent_run_states latest
|
|
41518
|
+
where latest.account_id = ${session.accountId}
|
|
41519
|
+
and latest.workspace_id = ${workspaceId}
|
|
41520
|
+
and latest.session_id = ${input.sessionId}
|
|
41521
|
+
and latest.turn_id = ${input.turnId}
|
|
41522
|
+
)`,
|
|
41221
41523
|
),
|
|
41222
41524
|
)
|
|
41223
41525
|
.returning({ id: schema.agentRunStates.id })
|