@opengeni/db 1.3.0 → 1.4.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.
Files changed (70) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/capability-reconciliation.js +2 -2
  3. package/dist/{chunk-LRSIODCQ.js → chunk-27T4AP25.js} +2 -2
  4. package/dist/{chunk-VQX54TK3.js → chunk-3WUCM7YF.js} +3 -3
  5. package/dist/{chunk-BRVBLQAL.js → chunk-AMK3FNOW.js} +4 -4
  6. package/dist/{chunk-AQMH2ZEH.js → chunk-BA52ITIY.js} +2 -2
  7. package/dist/{chunk-6S5T6FSP.js → chunk-CKDHKQS4.js} +5 -5
  8. package/dist/{chunk-HYBQABBJ.js → chunk-EFANLEWI.js} +2 -2
  9. package/dist/{chunk-PNWWNEDM.js → chunk-EMYA6XNE.js} +2 -2
  10. package/dist/{chunk-6UKNJ43T.js → chunk-GC5GUTV3.js} +2 -2
  11. package/dist/{chunk-DSNEIW5E.js → chunk-JL6TBB76.js} +2 -1
  12. package/dist/chunk-JL6TBB76.js.map +1 -0
  13. package/dist/{chunk-OEFNTGR3.js → chunk-NT7OGKYX.js} +4 -4
  14. package/dist/{chunk-BID3CNN3.js → chunk-T3CYF3DH.js} +3 -3
  15. package/dist/{chunk-3XHC5KC5.js → chunk-TRUEH4I2.js} +2 -2
  16. package/dist/{chunk-7S3O33NM.js → chunk-UQELJ6OM.js} +2 -2
  17. package/dist/{chunk-OI6YZXTU.js → chunk-VCHK4D6S.js} +2 -2
  18. package/dist/connect-attempts.js +3 -3
  19. package/dist/connection-metadata.d.ts +416 -0
  20. package/dist/editable-artifact-durable-export.js +2 -2
  21. package/dist/editable-artifacts.js +3 -3
  22. package/dist/index.d.ts +28 -7
  23. package/dist/index.js +10304 -9877
  24. package/dist/index.js.map +1 -1
  25. package/dist/legacy-tool-action-reviews.d.ts +75 -0
  26. package/dist/managed-auth-session-sets.js +3 -3
  27. package/dist/mcp-operations.js +2 -2
  28. package/dist/organization-integration-policy.js +3 -3
  29. package/dist/organization-slack-bots.d.ts +1 -1
  30. package/dist/retained-provider-commands.js +6 -6
  31. package/dist/schema.js +1 -1
  32. package/dist/session-background-commands.js +4 -4
  33. package/dist/session-command-output.js +5 -5
  34. package/dist/session-event-slices.js +3 -3
  35. package/dist/session-mcp-credential-rotation.js +5 -5
  36. package/dist/session-realtime-billing.d.ts +48 -0
  37. package/dist/session-realtime.d.ts +8 -2
  38. package/dist/session-tenancy.js +3 -3
  39. package/dist/video-generation.js +3 -3
  40. package/dist/voice-transcription-settlement.d.ts +36 -0
  41. package/dist/workspace-tool-defaults.js +4 -4
  42. package/drizzle/0623_voice_transcription_attribution.sql +128 -0
  43. package/drizzle/0624_azure_live_realtime_model.sql +30 -0
  44. package/drizzle/0625_transcription_billing_refusal_codes.sql +29 -0
  45. package/package.json +7 -7
  46. package/src/connection-metadata.ts +166 -0
  47. package/src/index.ts +98 -165
  48. package/src/insights-unified.ts +2 -1
  49. package/src/legacy-tool-action-reviews.ts +242 -0
  50. package/src/organization-slack-bots.ts +1 -1
  51. package/src/schema.ts +1 -0
  52. package/src/session-realtime-billing.ts +135 -0
  53. package/src/session-realtime-ledger.ts +9 -4
  54. package/src/session-realtime.ts +20 -2
  55. package/src/tool-action-reviews.ts +129 -18
  56. package/src/voice-transcription-settlement.ts +94 -0
  57. package/dist/chunk-DSNEIW5E.js.map +0 -1
  58. /package/dist/{chunk-LRSIODCQ.js.map → chunk-27T4AP25.js.map} +0 -0
  59. /package/dist/{chunk-VQX54TK3.js.map → chunk-3WUCM7YF.js.map} +0 -0
  60. /package/dist/{chunk-BRVBLQAL.js.map → chunk-AMK3FNOW.js.map} +0 -0
  61. /package/dist/{chunk-AQMH2ZEH.js.map → chunk-BA52ITIY.js.map} +0 -0
  62. /package/dist/{chunk-6S5T6FSP.js.map → chunk-CKDHKQS4.js.map} +0 -0
  63. /package/dist/{chunk-HYBQABBJ.js.map → chunk-EFANLEWI.js.map} +0 -0
  64. /package/dist/{chunk-PNWWNEDM.js.map → chunk-EMYA6XNE.js.map} +0 -0
  65. /package/dist/{chunk-6UKNJ43T.js.map → chunk-GC5GUTV3.js.map} +0 -0
  66. /package/dist/{chunk-OEFNTGR3.js.map → chunk-NT7OGKYX.js.map} +0 -0
  67. /package/dist/{chunk-BID3CNN3.js.map → chunk-T3CYF3DH.js.map} +0 -0
  68. /package/dist/{chunk-3XHC5KC5.js.map → chunk-TRUEH4I2.js.map} +0 -0
  69. /package/dist/{chunk-7S3O33NM.js.map → chunk-UQELJ6OM.js.map} +0 -0
  70. /package/dist/{chunk-OI6YZXTU.js.map → chunk-VCHK4D6S.js.map} +0 -0
@@ -0,0 +1,75 @@
1
+ import { type Database } from "./database.js";
2
+ /** Read-only presentation for SDK approvals created before durable connector
3
+ * reviews. Neither current catalogs nor display labels establish a provider.
4
+ * This never creates a request, changes a policy, or resumes an operation. */
5
+ export declare function legacyToolActionReview(db: Database, input: {
6
+ accountId: string;
7
+ workspaceId: string;
8
+ sessionId: string;
9
+ approvalId: string;
10
+ }): Promise<{
11
+ args: Record<string, unknown>;
12
+ context: {
13
+ kind: "generic" | "gmail";
14
+ title?: string | undefined;
15
+ accountLabel?: string | undefined;
16
+ fieldLabels?: Record<string, string> | undefined;
17
+ protectedFields?: string[] | undefined;
18
+ email?: {
19
+ from: string;
20
+ to: string;
21
+ cc: string;
22
+ bcc: string;
23
+ subject: string;
24
+ textBody: string;
25
+ htmlBody: string;
26
+ contentSha256: string;
27
+ attachments: {
28
+ name: string;
29
+ mediaType: string;
30
+ bytes: number;
31
+ }[];
32
+ } | undefined;
33
+ samples?: {
34
+ id: string;
35
+ title: string;
36
+ subtitle?: string | undefined;
37
+ provenance: "provider_metadata";
38
+ }[] | undefined;
39
+ };
40
+ proven: boolean;
41
+ review: {
42
+ version: 1;
43
+ id: string;
44
+ actionDigest: string;
45
+ revision: string;
46
+ status: "approved" | "blocked" | "cancelled" | "completed" | "executing" | "expired" | "failed" | "partial" | "pending" | "rejected" | "revoked" | "stale" | "unavailable" | "unknown";
47
+ title: string;
48
+ accountLabel?: string | undefined;
49
+ consequence?: string | undefined;
50
+ effects: string[];
51
+ selectionCount?: number | undefined;
52
+ selectionKind?: "messages" | "threads" | undefined;
53
+ samples?: {
54
+ id: string;
55
+ title: string;
56
+ subtitle?: string | undefined;
57
+ provenance: "provider_metadata";
58
+ }[] | undefined;
59
+ fields: {
60
+ path: string;
61
+ label: string;
62
+ preview: string;
63
+ count?: number | undefined;
64
+ truncated: boolean;
65
+ protected?: boolean | undefined;
66
+ }[];
67
+ moreFields: number;
68
+ reason: string;
69
+ createdAt: string;
70
+ updatedAt: string;
71
+ approveLabel: string;
72
+ availableActions: ("approve" | "reject")[];
73
+ detailsAvailable: boolean;
74
+ };
75
+ } | null>;
@@ -20,9 +20,9 @@ import {
20
20
  reapManagedAuthIsolatedSessions,
21
21
  releaseManagedAuthActorMutationLease,
22
22
  validateManagedAuthActorMutationLease
23
- } from "./chunk-7S3O33NM.js";
24
- import "./chunk-LRSIODCQ.js";
25
- import "./chunk-DSNEIW5E.js";
23
+ } from "./chunk-UQELJ6OM.js";
24
+ import "./chunk-27T4AP25.js";
25
+ import "./chunk-JL6TBB76.js";
26
26
  import "./chunk-P7YDM2RI.js";
27
27
  import "./chunk-PZ5AY32C.js";
28
28
  export {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  withRlsContext
3
- } from "./chunk-LRSIODCQ.js";
4
- import "./chunk-DSNEIW5E.js";
3
+ } from "./chunk-27T4AP25.js";
4
+ import "./chunk-JL6TBB76.js";
5
5
  import {
6
6
  LOSSLESS_CONTENT_CODEC_VERSION,
7
7
  fromPostgresLosslessJson,
@@ -3,10 +3,10 @@ import {
3
3
  updateOrganizationIntegrationPolicy,
4
4
  withOrganizationIntegrationAcquisition,
5
5
  withOrganizationIntegrationPolicyFence
6
- } from "./chunk-AQMH2ZEH.js";
6
+ } from "./chunk-BA52ITIY.js";
7
7
  import "./chunk-4UJCXBR2.js";
8
- import "./chunk-LRSIODCQ.js";
9
- import "./chunk-DSNEIW5E.js";
8
+ import "./chunk-27T4AP25.js";
9
+ import "./chunk-JL6TBB76.js";
10
10
  import "./chunk-P7YDM2RI.js";
11
11
  import "./chunk-PZ5AY32C.js";
12
12
  export {
@@ -48,7 +48,7 @@ export declare function availableSlackBotConnectionMetadata(db: Database, scope:
48
48
  metadata: {
49
49
  organizationSharingGeneration: number;
50
50
  };
51
- } | import("./index.js").ConnectionMetadataWithVerification)[]>;
51
+ } | import("./connection-metadata.js").ConnectionMetadataWithVerification)[]>;
52
52
  /** Canonical organization-administrator authentication is supplied by a trusted
53
53
  * HTTP adapter. SQL separately rechecks live authority and exact bot identity. */
54
54
  export declare function setOrganizationSlackBotAccess(db: Database, input: {
@@ -14,13 +14,13 @@ import {
14
14
  retainedProviderCommandPersistence,
15
15
  supervisedCommandProtocolReady,
16
16
  validateRouterOutputAdvance
17
- } from "./chunk-6S5T6FSP.js";
18
- import "./chunk-BRVBLQAL.js";
19
- import "./chunk-OEFNTGR3.js";
20
- import "./chunk-BID3CNN3.js";
17
+ } from "./chunk-CKDHKQS4.js";
18
+ import "./chunk-AMK3FNOW.js";
19
+ import "./chunk-NT7OGKYX.js";
20
+ import "./chunk-T3CYF3DH.js";
21
21
  import "./chunk-4UJCXBR2.js";
22
- import "./chunk-LRSIODCQ.js";
23
- import "./chunk-DSNEIW5E.js";
22
+ import "./chunk-27T4AP25.js";
23
+ import "./chunk-JL6TBB76.js";
24
24
  import "./chunk-P7YDM2RI.js";
25
25
  import "./chunk-PZ5AY32C.js";
26
26
  export {
package/dist/schema.js CHANGED
@@ -401,7 +401,7 @@ import {
401
401
  xaiRotationSettings,
402
402
  xaiSessionAccountPins,
403
403
  xaiSubscriptionCredentials
404
- } from "./chunk-DSNEIW5E.js";
404
+ } from "./chunk-JL6TBB76.js";
405
405
  import "./chunk-P7YDM2RI.js";
406
406
  import "./chunk-PZ5AY32C.js";
407
407
  export {
@@ -27,11 +27,11 @@ import {
27
27
  settleConnectedMachineSessionBackgroundCommandWithMutation,
28
28
  settleSessionBackgroundCommandForRetainedProcessInTransaction,
29
29
  unobservableRetainedProcessOutcomeSql
30
- } from "./chunk-OEFNTGR3.js";
31
- import "./chunk-BID3CNN3.js";
30
+ } from "./chunk-NT7OGKYX.js";
31
+ import "./chunk-T3CYF3DH.js";
32
32
  import "./chunk-4UJCXBR2.js";
33
- import "./chunk-LRSIODCQ.js";
34
- import "./chunk-DSNEIW5E.js";
33
+ import "./chunk-27T4AP25.js";
34
+ import "./chunk-JL6TBB76.js";
35
35
  import "./chunk-P7YDM2RI.js";
36
36
  import "./chunk-PZ5AY32C.js";
37
37
  export {
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  appendSessionCommandOutput
3
- } from "./chunk-BRVBLQAL.js";
4
- import "./chunk-OEFNTGR3.js";
5
- import "./chunk-BID3CNN3.js";
3
+ } from "./chunk-AMK3FNOW.js";
4
+ import "./chunk-NT7OGKYX.js";
5
+ import "./chunk-T3CYF3DH.js";
6
6
  import "./chunk-4UJCXBR2.js";
7
- import "./chunk-LRSIODCQ.js";
8
- import "./chunk-DSNEIW5E.js";
7
+ import "./chunk-27T4AP25.js";
8
+ import "./chunk-JL6TBB76.js";
9
9
  import "./chunk-P7YDM2RI.js";
10
10
  import "./chunk-PZ5AY32C.js";
11
11
  export {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  listSessionEventSlices,
3
3
  readSessionMessageSliceInScope
4
- } from "./chunk-VQX54TK3.js";
5
- import "./chunk-LRSIODCQ.js";
6
- import "./chunk-DSNEIW5E.js";
4
+ } from "./chunk-3WUCM7YF.js";
5
+ import "./chunk-27T4AP25.js";
6
+ import "./chunk-JL6TBB76.js";
7
7
  import "./chunk-P7YDM2RI.js";
8
8
  import "./chunk-PZ5AY32C.js";
9
9
  export {
@@ -1,23 +1,23 @@
1
1
  import {
2
2
  connectionMetadataMatchesBinding
3
- } from "./chunk-PNWWNEDM.js";
3
+ } from "./chunk-EMYA6XNE.js";
4
4
  import {
5
5
  lockSessionEventWriteRows,
6
6
  organizationApiKeyAllowsWorkspace
7
- } from "./chunk-OEFNTGR3.js";
8
- import "./chunk-BID3CNN3.js";
7
+ } from "./chunk-NT7OGKYX.js";
8
+ import "./chunk-T3CYF3DH.js";
9
9
  import "./chunk-4UJCXBR2.js";
10
10
  import {
11
11
  rawRows,
12
12
  setSubjectRlsContext,
13
13
  withRlsContext
14
- } from "./chunk-LRSIODCQ.js";
14
+ } from "./chunk-27T4AP25.js";
15
15
  import {
16
16
  apiKeys,
17
17
  sessionCommandReceipts,
18
18
  sessionMcpServers,
19
19
  sessions
20
- } from "./chunk-DSNEIW5E.js";
20
+ } from "./chunk-JL6TBB76.js";
21
21
  import "./chunk-P7YDM2RI.js";
22
22
  import "./chunk-PZ5AY32C.js";
23
23
 
@@ -0,0 +1,48 @@
1
+ import type { SessionRealtimeModel } from "@opengeni/contracts";
2
+ import { type Database } from "./database.js";
3
+ /** One provider connection of a live-voice mode, bounded by server observation. */
4
+ export type SessionRealtimeBillableConnection = {
5
+ id: string;
6
+ startedAt: Date;
7
+ observedUntil: Date;
8
+ };
9
+ export type SessionRealtimeBillingFacts = {
10
+ accountId: string;
11
+ workspaceId: string;
12
+ sessionId: string;
13
+ realtimeId: string;
14
+ model: SessionRealtimeModel;
15
+ ownerSubjectId: string;
16
+ state: "active" | "ended";
17
+ connections: SessionRealtimeBillableConnection[];
18
+ };
19
+ /**
20
+ * The last instant the server itself observed the voice owner alive. An
21
+ * explicit owner-proven end is observed at `endedAt`; an expired lease only up
22
+ * to its last heartbeat (late lazy settlement never extends the bill); an
23
+ * active mode up to `now`, bounded by its lease.
24
+ */
25
+ export declare function sessionRealtimeObservedUntil(mode: {
26
+ state: string;
27
+ endReason: string | null;
28
+ endedAt: Date | null;
29
+ lastHeartbeatAt: Date;
30
+ leaseExpiresAt: Date;
31
+ }, now: Date): Date;
32
+ /**
33
+ * Server-observed lifetime of every provider connection that was actually
34
+ * issued (an SDP answer or a minted client secret was returned). Failed or
35
+ * never-completed negotiations issued nothing billable.
36
+ */
37
+ export declare function loadSessionRealtimeBillingFacts(db: Database, input: {
38
+ workspaceId: string;
39
+ sessionId: string;
40
+ realtimeId: string;
41
+ now?: Date;
42
+ }): Promise<SessionRealtimeBillingFacts | null>;
43
+ /** Which of these usage idempotency keys are already recorded for the account. */
44
+ export declare function existingUsageEventIdempotencyKeys(db: Database, input: {
45
+ accountId: string;
46
+ workspaceId: string;
47
+ keys: readonly string[];
48
+ }): Promise<Set<string>>;
@@ -34,11 +34,17 @@ export type RenewSessionRealtimeInput = {
34
34
  expectedVersion: number;
35
35
  now?: Date;
36
36
  leaseMs?: number;
37
+ /**
38
+ * False keeps the current lease unchanged (owner still proven). Used when a
39
+ * deployment-funded call ran out of credits: the client drains and ends
40
+ * inside the remaining lease, and an ignoring client lapses on its own.
41
+ */
42
+ extendLease?: boolean;
37
43
  };
38
- export type EndSessionRealtimeInput = Omit<RenewSessionRealtimeInput, "leaseMs"> & {
44
+ export type EndSessionRealtimeInput = Omit<RenewSessionRealtimeInput, "leaseMs" | "extendLease"> & {
39
45
  reason: Extract<SessionRealtimeEndReason, "user_stop" | "browser_unload">;
40
46
  };
41
- export type AssertSessionRealtimeOwnerInput = Omit<RenewSessionRealtimeInput, "leaseMs">;
47
+ export type AssertSessionRealtimeOwnerInput = Omit<RenewSessionRealtimeInput, "leaseMs" | "extendLease">;
42
48
  export type SessionRealtimeMutationResult = {
43
49
  mode: SessionRealtimeMode;
44
50
  replay: boolean;
@@ -13,9 +13,9 @@ import {
13
13
  openPrivateSessionCreateCapability,
14
14
  replayAppliedSessionFork,
15
15
  transitionSessionVisibility
16
- } from "./chunk-OI6YZXTU.js";
17
- import "./chunk-LRSIODCQ.js";
18
- import "./chunk-DSNEIW5E.js";
16
+ } from "./chunk-VCHK4D6S.js";
17
+ import "./chunk-27T4AP25.js";
18
+ import "./chunk-JL6TBB76.js";
19
19
  import "./chunk-P7YDM2RI.js";
20
20
  import "./chunk-PZ5AY32C.js";
21
21
  export {
@@ -29,10 +29,10 @@ import {
29
29
  settleVideoGenerationFailure,
30
30
  settleVideoGenerationReady,
31
31
  updateWorkspaceVideoGenerationPolicy
32
- } from "./chunk-BID3CNN3.js";
32
+ } from "./chunk-T3CYF3DH.js";
33
33
  import "./chunk-4UJCXBR2.js";
34
- import "./chunk-LRSIODCQ.js";
35
- import "./chunk-DSNEIW5E.js";
34
+ import "./chunk-27T4AP25.js";
35
+ import "./chunk-JL6TBB76.js";
36
36
  import "./chunk-P7YDM2RI.js";
37
37
  import "./chunk-PZ5AY32C.js";
38
38
  export {
@@ -0,0 +1,36 @@
1
+ import { CreditDebitAttribution } from "./credit-debit-attribution.js";
2
+ import type { Database } from "./database.js";
3
+ /** Usage source and credit debit type of deployment-funded voice transcription. */
4
+ export declare const VOICE_TRANSCRIPTION_SOURCE_TYPE = "voice_transcription";
5
+ export declare const VOICE_TRANSCRIPTION_DEBIT_TYPE = "voice_transcription_debit";
6
+ /**
7
+ * Idempotency keys for one settled voice-transcription unit. Both derive from
8
+ * the workspace and the server-built unit id only, so an inline settlement, its
9
+ * in-process retry, and a later reconciliation converge on the same rows.
10
+ */
11
+ export declare function voiceTranscriptionSettlementKeys(input: {
12
+ workspaceId: string;
13
+ sourceId: string;
14
+ }): {
15
+ usageIdempotencyKey: string;
16
+ debitIdempotencyKey: string;
17
+ };
18
+ export type UnsettledVoiceTranscriptionCharge = {
19
+ sourceId: string;
20
+ amountMicros: number;
21
+ attribution: CreditDebitAttribution;
22
+ };
23
+ /**
24
+ * Voice usage receipts in one workspace whose credit debit never committed
25
+ * (the debit transaction failed after the receipt was durable). Bounded and
26
+ * ordered oldest first; `minAgeMilliseconds` leaves an in-flight inline
27
+ * settlement to finish with its full ledger metadata first. The scan walks the
28
+ * workspace's `model.cost` index range, so the window is short (3 days) and
29
+ * the statement is capped at 2 s; a timeout only defers reconciliation.
30
+ */
31
+ export declare function listUnsettledVoiceTranscriptionCharges(db: Database, input: {
32
+ accountId: string;
33
+ workspaceId: string;
34
+ limit?: number;
35
+ minAgeMilliseconds?: number;
36
+ }): Promise<UnsettledVoiceTranscriptionCharge[]>;
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  lockWorkspaceInferenceControl
3
- } from "./chunk-OEFNTGR3.js";
4
- import "./chunk-BID3CNN3.js";
3
+ } from "./chunk-NT7OGKYX.js";
4
+ import "./chunk-T3CYF3DH.js";
5
5
  import "./chunk-4UJCXBR2.js";
6
6
  import {
7
7
  withWorkspaceRls
8
- } from "./chunk-LRSIODCQ.js";
9
- import "./chunk-DSNEIW5E.js";
8
+ } from "./chunk-27T4AP25.js";
9
+ import "./chunk-JL6TBB76.js";
10
10
  import "./chunk-P7YDM2RI.js";
11
11
  import "./chunk-PZ5AY32C.js";
12
12
 
@@ -0,0 +1,128 @@
1
+ -- deployment-mode: rolling
2
+ -- Retain exact transcription payer receipts for member allowance attribution.
3
+ -- The API freezes the authenticated payer; ledger metadata alone is not proof.
4
+ DO $constraints$
5
+ DECLARE item record;
6
+ BEGIN
7
+ FOR item IN SELECT conname, pg_get_constraintdef(oid) AS definition FROM pg_constraint
8
+ WHERE conrelid='opengeni_private.usage_allowance_attribution_receipts'::regclass AND contype='c'
9
+ LOOP
10
+ IF (item.definition LIKE '%source_kind%' AND item.definition LIKE '%knowledge_query%') THEN
11
+ EXECUTE format('ALTER TABLE opengeni_private.usage_allowance_attribution_receipts DROP CONSTRAINT %I',item.conname);
12
+ END IF;
13
+ END LOOP;
14
+ END $constraints$;
15
+ ALTER TABLE opengeni_private.usage_allowance_attribution_receipts
16
+ ADD CONSTRAINT usage_attribution_source_kind CHECK (source_kind IN ('turn','schedule','knowledge_query','voice_transcription')),
17
+ ADD CONSTRAINT usage_attribution_source_shape CHECK (coalesce(
18
+ (source_kind='knowledge_query' AND session_id IS NULL AND quantity IS NOT NULL
19
+ AND idempotency_key='knowledge.query_cost:'||source_id)
20
+ OR (source_kind='voice_transcription' AND session_id IS NULL AND quantity IS NOT NULL
21
+ AND idempotency_key='voice.transcription_cost:'||source_id)
22
+ OR (source_kind IN ('turn','schedule') AND quantity IS NULL AND idempotency_key IS NULL),false));
23
+
24
+ CREATE OR REPLACE FUNCTION capture_usage_allowance_attribution()
25
+ RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path FROM CURRENT AS $$
26
+ DECLARE
27
+ v_source_kind text; v_source_id text; v_session_id uuid; v_attribution jsonb;
28
+ v_quantity bigint; v_idempotency_key text; opened integer;
29
+ BEGIN
30
+ IF TG_TABLE_NAME='session_turns' THEN
31
+ IF TG_OP='UPDATE' AND (NEW.id IS DISTINCT FROM OLD.id
32
+ OR NEW.account_id IS DISTINCT FROM OLD.account_id OR NEW.workspace_id IS DISTINCT FROM OLD.workspace_id
33
+ OR NEW.session_id IS DISTINCT FROM OLD.session_id
34
+ OR NEW.initiating_human_subject_id IS DISTINCT FROM OLD.initiating_human_subject_id) THEN
35
+ RAISE EXCEPTION 'Allowance turn attribution is immutable' USING ERRCODE='23514';
36
+ END IF;
37
+ v_source_kind:='turn'; v_source_id:=NEW.id::text; v_session_id:=NEW.session_id;
38
+ v_attribution:=jsonb_build_object('kind','turn','turnId',NEW.id,
39
+ 'initiatingHumanSubjectId',NEW.initiating_human_subject_id);
40
+ ELSIF TG_TABLE_NAME='scheduled_task_runs' THEN
41
+ IF TG_OP='UPDATE' AND (NEW.id IS DISTINCT FROM OLD.id
42
+ OR NEW.account_id IS DISTINCT FROM OLD.account_id OR NEW.workspace_id IS DISTINCT FROM OLD.workspace_id
43
+ OR NEW.accepted_execution_snapshot->'causalHumanSubjectId' IS DISTINCT FROM
44
+ OLD.accepted_execution_snapshot->'causalHumanSubjectId') THEN
45
+ RAISE EXCEPTION 'Allowance scheduled attribution is immutable' USING ERRCODE='23514';
46
+ END IF;
47
+ v_source_kind:='schedule'; v_source_id:=NEW.id::text;
48
+ v_attribution:=CASE WHEN NOT coalesce(NEW.accepted_execution_snapshot ? 'causalHumanSubjectId',false)
49
+ THEN '{"kind":"unknown"}'::jsonb
50
+ WHEN NEW.accepted_execution_snapshot->>'causalHumanSubjectId' IS NULL THEN '{"kind":"service"}'::jsonb
51
+ ELSE jsonb_build_object('kind','human',
52
+ 'initiatingHumanSubjectId',NEW.accepted_execution_snapshot->>'causalHumanSubjectId') END;
53
+ ELSIF TG_TABLE_NAME='usage_events' THEN
54
+ IF TG_OP='UPDATE' THEN
55
+ IF ((OLD.source_resource_type='knowledge_query' AND OLD.event_type='document.query_embedding_cost')
56
+ OR (OLD.source_resource_type='voice_transcription' AND OLD.event_type='model.cost'))
57
+ AND (NEW.account_id IS DISTINCT FROM OLD.account_id OR NEW.workspace_id IS DISTINCT FROM OLD.workspace_id
58
+ OR NEW.source_resource_type IS DISTINCT FROM OLD.source_resource_type
59
+ OR NEW.source_resource_id IS DISTINCT FROM OLD.source_resource_id
60
+ OR NEW.event_type IS DISTINCT FROM OLD.event_type OR NEW.quantity IS DISTINCT FROM OLD.quantity
61
+ OR NEW.idempotency_key IS DISTINCT FROM OLD.idempotency_key
62
+ OR NEW.initiator_context->'creditDebitAttribution' IS DISTINCT FROM
63
+ OLD.initiator_context->'creditDebitAttribution') THEN
64
+ RAISE EXCEPTION 'Allowance query attribution is immutable' USING ERRCODE='23514';
65
+ END IF;
66
+ RETURN NEW;
67
+ END IF;
68
+ IF NEW.workspace_id IS NULL OR NEW.source_resource_id IS NULL THEN RETURN NEW; END IF;
69
+ IF NEW.source_resource_type='knowledge_query' AND NEW.event_type='document.query_embedding_cost'
70
+ AND NEW.idempotency_key='knowledge.query_cost:'||NEW.source_resource_id THEN
71
+ v_source_kind:='knowledge_query';
72
+ ELSIF NEW.source_resource_type='voice_transcription' AND NEW.event_type='model.cost'
73
+ AND NEW.idempotency_key='voice.transcription_cost:'||NEW.source_resource_id THEN
74
+ v_source_kind:='voice_transcription';
75
+ ELSE RETURN NEW;
76
+ END IF;
77
+ v_source_id:=NEW.source_resource_id;
78
+ v_quantity:=NEW.quantity; v_idempotency_key:=NEW.idempotency_key;
79
+ -- Copy only attribution fields, never the initiator envelope/query/content.
80
+ v_attribution:=NEW.initiator_context->'creditDebitAttribution';
81
+ v_attribution:=CASE v_attribution->>'kind'
82
+ WHEN 'human' THEN jsonb_build_object('kind','human',
83
+ 'initiatingHumanSubjectId',v_attribution->'initiatingHumanSubjectId')
84
+ WHEN 'turn' THEN jsonb_build_object('kind','turn','turnId',v_attribution->'turnId',
85
+ 'initiatingHumanSubjectId',v_attribution->'initiatingHumanSubjectId')
86
+ WHEN 'service' THEN '{"kind":"service"}'::jsonb
87
+ ELSE '{"kind":"unknown"}'::jsonb END;
88
+ ELSE
89
+ RAISE EXCEPTION 'Unknown allowance attribution source' USING ERRCODE='55000';
90
+ END IF;
91
+ IF TG_OP='UPDATE' THEN RETURN NEW; END IF;
92
+ INSERT INTO opengeni_private.usage_allowance_capabilities VALUES
93
+ (pg_backend_pid(),pg_current_xact_id(),TG_TABLE_SCHEMA,NEW.account_id,NEW.workspace_id)
94
+ ON CONFLICT DO NOTHING;
95
+ GET DIAGNOSTICS opened=ROW_COUNT;
96
+ INSERT INTO opengeni_private.usage_allowance_attribution_receipts
97
+ (account_id,workspace_id,source_kind,source_id,session_id,attribution,quantity,idempotency_key)
98
+ VALUES(NEW.account_id,NEW.workspace_id,v_source_kind,v_source_id,v_session_id,v_attribution,v_quantity,v_idempotency_key);
99
+ IF opened=1 THEN
100
+ DELETE FROM opengeni_private.usage_allowance_capabilities
101
+ WHERE backend_pid=pg_backend_pid() AND transaction_id=pg_current_xact_id_if_assigned()
102
+ AND data_schema=TG_TABLE_SCHEMA AND account_id=NEW.account_id AND workspace_id=NEW.workspace_id;
103
+ END IF;
104
+ RETURN NEW;
105
+ END $$;
106
+
107
+ DO $debit$
108
+ DECLARE definition text:=pg_get_functiondef('count_workspace_allowance_debit()'::regprocedure);
109
+ anchor text:=$anchor$IF NEW.source_type='knowledge_query' THEN$anchor$;
110
+ replacement text:=$replacement$IF NEW.source_type='voice_transcription' THEN
111
+ SELECT receipt.attribution INTO attribution FROM opengeni_private.usage_allowance_attribution_receipts receipt
112
+ WHERE receipt.account_id=NEW.account_id AND receipt.workspace_id=NEW.workspace_id
113
+ AND receipt.source_kind='voice_transcription' AND receipt.source_id=NEW.source_id
114
+ AND receipt.idempotency_key='voice.transcription_cost:'||NEW.source_id
115
+ AND receipt.quantity=amount AND NEW.type='voice_transcription_debit';
116
+ attribution:=coalesce(attribution,'{"kind":"unknown"}'::jsonb);
117
+ ELSIF NEW.source_type='knowledge_query' THEN$replacement$;
118
+ BEGIN
119
+ IF strpos(definition,anchor)=0 OR strpos(substr(definition,strpos(definition,anchor)+length(anchor)),anchor)>0 THEN
120
+ RAISE EXCEPTION 'Unexpected allowance debit source branch' USING ERRCODE='55000';
121
+ END IF;
122
+ EXECUTE replace(definition,anchor,replacement);
123
+ END $debit$;
124
+
125
+ DO $harden$
126
+ BEGIN
127
+ EXECUTE format('ALTER FUNCTION %I.capture_usage_allowance_attribution() SET search_path=pg_catalog,%I,pg_temp', current_schema(), current_schema());
128
+ END $harden$;
@@ -0,0 +1,30 @@
1
+ -- deployment-mode: rolling
2
+ -- Admit configured Azure GPT Live WebRTC sessions.
3
+
4
+ SET lock_timeout = '5s';
5
+ SET statement_timeout = '10min';
6
+
7
+ ALTER TABLE "session_realtime_modes"
8
+ DROP CONSTRAINT "session_realtime_modes_model_check";
9
+
10
+ ALTER TABLE "session_realtime_modes"
11
+ ADD CONSTRAINT "session_realtime_modes_model_check"
12
+ CHECK (
13
+ "model" IN (
14
+ 'opengeni-azure/gpt-live-1',
15
+ 'gpt-live-1-boulder-alpha',
16
+ 'supergrok/grok-voice-think-fast-2.0',
17
+ 'opengeni-gateway/openai/gpt-realtime-2.1',
18
+ 'opengeni-gateway/openai/gpt-realtime-mini',
19
+ 'opengeni-gateway/xai/grok-voice-think-fast-2.0',
20
+ 'workspace-gateway/openai/gpt-realtime-2.1',
21
+ 'workspace-gateway/openai/gpt-realtime-mini',
22
+ 'workspace-gateway/xai/grok-voice-think-fast-2.0'
23
+ )
24
+ ) NOT VALID;
25
+
26
+ ALTER TABLE "session_realtime_modes"
27
+ VALIDATE CONSTRAINT "session_realtime_modes_model_check";
28
+
29
+ RESET statement_timeout;
30
+ RESET lock_timeout;
@@ -0,0 +1,29 @@
1
+ -- deployment-mode: rolling
2
+ -- Persist the exact credit/allowance refusal on a resumable recording and its
3
+ -- segment, so a reloaded recording still explains why it stopped. Widening an
4
+ -- allowed-value CHECK only; no row is rewritten.
5
+
6
+ SET lock_timeout = '5s';
7
+ SET statement_timeout = '10min';
8
+
9
+ ALTER TABLE "transcription_recordings"
10
+ DROP CONSTRAINT "transcription_recordings_error_code_check";
11
+
12
+ ALTER TABLE "transcription_recordings"
13
+ ADD CONSTRAINT "transcription_recordings_error_code_check"
14
+ CHECK ("error_code" IS NULL OR "error_code" IN (
15
+ 'permission_denied', 'not_supported', 'network', 'provider', 'policy_blocked',
16
+ 'timeout', 'cancelled', 'unavailable', 'too_large', 'invalid_audio', 'unknown',
17
+ 'insufficient_credits', 'allowance_exhausted', 'monthly_model_cost_limit'
18
+ ));
19
+
20
+ ALTER TABLE "transcription_recording_segments"
21
+ DROP CONSTRAINT "transcription_recording_segments_error_code_check";
22
+
23
+ ALTER TABLE "transcription_recording_segments"
24
+ ADD CONSTRAINT "transcription_recording_segments_error_code_check"
25
+ CHECK ("error_code" IS NULL OR "error_code" IN (
26
+ 'permission_denied', 'not_supported', 'network', 'provider', 'policy_blocked',
27
+ 'timeout', 'cancelled', 'unavailable', 'too_large', 'invalid_audio', 'unknown',
28
+ 'insufficient_credits', 'allowance_exhausted', 'monthly_model_cost_limit'
29
+ ));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/db",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "OpenGeni persistence: Drizzle schema, RLS-scoped query layer, the SQL migration runner, and role provisioning.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -115,12 +115,12 @@
115
115
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
116
116
  },
117
117
  "dependencies": {
118
- "@opengeni/codemode": "1.3.0",
119
- "@opengeni/codex": "1.3.0",
120
- "@opengeni/config": "1.3.0",
121
- "@opengeni/contracts": "1.3.0",
122
- "@opengeni/network": "1.3.0",
123
- "@opengeni/observability": "1.3.0",
118
+ "@opengeni/codemode": "1.4.0",
119
+ "@opengeni/codex": "1.4.0",
120
+ "@opengeni/config": "1.4.0",
121
+ "@opengeni/contracts": "1.4.0",
122
+ "@opengeni/network": "1.4.0",
123
+ "@opengeni/observability": "1.4.0",
124
124
  "drizzle-orm": "^0.45.2",
125
125
  "postgres": "^3.4.7"
126
126
  },