@sixb/pg 0.1.6 → 0.1.8
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/agents/rows.d.ts +8 -5
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/runs.d.ts +3 -2
- package/dist/agents/runs.d.ts.map +1 -1
- package/dist/agents/threads.d.ts.map +1 -1
- package/dist/ai-cost-groups.d.ts +5 -0
- package/dist/ai-cost-groups.d.ts.map +1 -0
- package/dist/auth-storage/auth-storage.d.ts +4 -1
- package/dist/auth-storage/auth-storage.d.ts.map +1 -1
- package/dist/auth-storage/device-authorizations.d.ts +29 -0
- package/dist/auth-storage/device-authorizations.d.ts.map +1 -0
- package/dist/auth-storage/rows.d.ts +19 -1
- package/dist/auth-storage/rows.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts +1 -1
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8327 -5838
- package/dist/index.js.map +28 -19
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/index.d.ts +2 -0
- package/dist/objects/index.d.ts.map +1 -0
- package/dist/{pg-object-query-compiler.d.ts → objects/query-compiler.d.ts} +25 -4
- package/dist/objects/query-compiler.d.ts.map +1 -0
- package/dist/objects/read-scope.d.ts +17 -0
- package/dist/objects/read-scope.d.ts.map +1 -0
- package/dist/objects/reader.d.ts +50 -0
- package/dist/objects/reader.d.ts.map +1 -0
- package/dist/objects/rows.d.ts +47 -0
- package/dist/objects/rows.d.ts.map +1 -0
- package/dist/objects/selected-reader.d.ts +8 -0
- package/dist/objects/selected-reader.d.ts.map +1 -0
- package/dist/{pg-object-storage.d.ts → objects/storage.d.ts} +12 -20
- package/dist/objects/storage.d.ts.map +1 -0
- package/dist/pg-ai-cost-storage.d.ts +2 -1
- package/dist/pg-ai-cost-storage.d.ts.map +1 -1
- package/dist/pg-ai-limit-storage.d.ts +34 -0
- package/dist/pg-ai-limit-storage.d.ts.map +1 -0
- package/dist/pg-ai-usage-storage.d.ts +28 -0
- package/dist/pg-ai-usage-storage.d.ts.map +1 -1
- package/dist/pg-execution-storage.d.ts +3 -2
- package/dist/pg-execution-storage.d.ts.map +1 -1
- package/dist/share-grant-storage.d.ts +11 -0
- package/dist/share-grant-storage.d.ts.map +1 -0
- package/dist/share-session-storage.d.ts +11 -0
- package/dist/share-session-storage.d.ts.map +1 -0
- package/dist/storage-errors.d.ts +2 -0
- package/dist/storage-errors.d.ts.map +1 -1
- package/dist/transactions.d.ts +9 -2
- package/dist/transactions.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/agents/rows.ts +38 -9
- package/src/agents/runs.ts +148 -11
- package/src/agents/threads.ts +1 -17
- package/src/ai-cost-groups.ts +102 -0
- package/src/auth-storage/auth-storage.ts +84 -0
- package/src/auth-storage/device-authorizations.ts +131 -0
- package/src/auth-storage/rows.ts +41 -0
- package/src/auth-storage/shared.ts +1 -0
- package/src/index.ts +24 -4
- package/src/migrations/029-model-accounting.sql +24 -0
- package/src/migrations/030-ai-usage-limits.sql +94 -0
- package/src/migrations/031-subagent-runs.sql +97 -0
- package/src/migrations/032-conversation-run-spec.sql +23 -0
- package/src/migrations/033-retire-agent-definitions.sql +28 -0
- package/src/migrations/034-device-authorizations.sql +24 -0
- package/src/migrations/035-share-grants.sql +57 -0
- package/src/migrations/036-share-sessions.sql +173 -0
- package/src/migrations.ts +22 -0
- package/src/objects/index.ts +1 -0
- package/src/{pg-object-query-compiler.ts → objects/query-compiler.ts} +185 -100
- package/src/objects/read-scope.ts +324 -0
- package/src/objects/reader.ts +604 -0
- package/src/objects/rows.ts +146 -0
- package/src/objects/selected-reader.ts +118 -0
- package/src/objects/storage.ts +305 -0
- package/src/pg-ai-cost-storage.ts +71 -24
- package/src/pg-ai-limit-storage.ts +901 -0
- package/src/pg-ai-usage-storage.ts +34 -0
- package/src/pg-execution-storage.ts +21 -2
- package/src/pg-workflow-run-storage.ts +8 -8
- package/src/share-grant-storage.ts +236 -0
- package/src/share-session-storage.ts +127 -0
- package/src/storage-errors.ts +6 -0
- package/src/transactions.ts +46 -5
- package/dist/pg-object-query-compiler.d.ts.map +0 -1
- package/dist/pg-object-storage.d.ts.map +0 -1
- package/src/pg-object-storage.ts +0 -734
package/src/auth-storage/rows.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Principal } from "@sixb/core"
|
|
2
2
|
import type {
|
|
3
3
|
AccessTokenRecord,
|
|
4
|
+
DeviceAuthorizationRecord,
|
|
4
5
|
GroupMembershipRecord,
|
|
5
6
|
GroupMembershipSource,
|
|
6
7
|
InvitationRecord,
|
|
@@ -150,6 +151,24 @@ export interface PgAuthOidcAttemptRow {
|
|
|
150
151
|
readonly consumed_at: PgDate | null
|
|
151
152
|
}
|
|
152
153
|
|
|
154
|
+
export interface PgAuthDeviceAuthorizationRow {
|
|
155
|
+
readonly project_id: string
|
|
156
|
+
readonly id: string
|
|
157
|
+
readonly device_code_hash: string
|
|
158
|
+
readonly user_code: string
|
|
159
|
+
readonly client_name: string
|
|
160
|
+
readonly token_name: string
|
|
161
|
+
readonly token_expires_at: PgDate
|
|
162
|
+
readonly status: DeviceAuthorizationRecord["status"]
|
|
163
|
+
readonly approved_user_id: string | null
|
|
164
|
+
readonly approved_session_id: string | null
|
|
165
|
+
readonly created_at: PgDate
|
|
166
|
+
readonly expires_at: PgDate
|
|
167
|
+
readonly approved_at: PgDate | null
|
|
168
|
+
readonly denied_at: PgDate | null
|
|
169
|
+
readonly consumed_at: PgDate | null
|
|
170
|
+
}
|
|
171
|
+
|
|
153
172
|
export function rowToUserRecord(row: PgAuthUserRow): UserRecord {
|
|
154
173
|
return {
|
|
155
174
|
id: row.id,
|
|
@@ -304,6 +323,28 @@ export function rowToOidcAuthorizationAttemptRecord(
|
|
|
304
323
|
}
|
|
305
324
|
}
|
|
306
325
|
|
|
326
|
+
export function rowToDeviceAuthorizationRecord(
|
|
327
|
+
row: PgAuthDeviceAuthorizationRow
|
|
328
|
+
): DeviceAuthorizationRecord {
|
|
329
|
+
return {
|
|
330
|
+
id: row.id,
|
|
331
|
+
projectId: row.project_id,
|
|
332
|
+
deviceCodeHash: row.device_code_hash,
|
|
333
|
+
userCode: row.user_code,
|
|
334
|
+
clientName: row.client_name,
|
|
335
|
+
tokenName: row.token_name,
|
|
336
|
+
tokenExpiresAt: toDate(row.token_expires_at),
|
|
337
|
+
status: row.status,
|
|
338
|
+
approvedUserId: row.approved_user_id ?? undefined,
|
|
339
|
+
approvedSessionId: row.approved_session_id ?? undefined,
|
|
340
|
+
createdAt: toDate(row.created_at),
|
|
341
|
+
expiresAt: toDate(row.expires_at),
|
|
342
|
+
approvedAt: row.approved_at ? toDate(row.approved_at) : undefined,
|
|
343
|
+
deniedAt: row.denied_at ? toDate(row.denied_at) : undefined,
|
|
344
|
+
consumedAt: row.consumed_at ? toDate(row.consumed_at) : undefined,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
307
348
|
export function serializeOptionalRecord(
|
|
308
349
|
value: Readonly<Record<string, unknown>> | undefined
|
|
309
350
|
): string | null {
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { ProviderMaterializationTransactionLifecycle } from "@sixb/core/internal
|
|
|
13
13
|
import {
|
|
14
14
|
createAgentOperationScope,
|
|
15
15
|
createAuthOperationScope,
|
|
16
|
+
createObjectOperationScope,
|
|
16
17
|
createOntologyOperationScope,
|
|
17
18
|
createOperationScopedFacade,
|
|
18
19
|
createStorageOperationScope,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
} from "@sixb/core/internal/storage-operation-scope"
|
|
21
22
|
import {
|
|
22
23
|
type AiCostStorage,
|
|
24
|
+
type AiLimitStorage,
|
|
23
25
|
type AiUsageStorage,
|
|
24
26
|
createTransactionStorageProxy,
|
|
25
27
|
type ObjectStorage,
|
|
@@ -30,13 +32,14 @@ import { PgAgentStorage } from "./agents"
|
|
|
30
32
|
import { PgAuthStorage } from "./auth-storage"
|
|
31
33
|
import { PgConnectorConnectionStorage } from "./connector-connection-storage"
|
|
32
34
|
import { createPostgresStorageMigrators, dropSchema } from "./migrations"
|
|
35
|
+
import { PgObjectStorage } from "./objects"
|
|
33
36
|
import { PgOntologyStorage, type PgOntologyTransactionContext } from "./ontology-storage"
|
|
34
37
|
import { PgActionRunStorage } from "./pg-action-run-storage"
|
|
35
38
|
import { PgAiCostStorage } from "./pg-ai-cost-storage"
|
|
39
|
+
import { PgAiLimitStorage } from "./pg-ai-limit-storage"
|
|
36
40
|
import { PgAiUsageStorage } from "./pg-ai-usage-storage"
|
|
37
41
|
import { createPgClient, type SQL, type SQLClient } from "./pg-client"
|
|
38
42
|
import { PgExecutionStorage } from "./pg-execution-storage"
|
|
39
|
-
import { PgObjectStorage } from "./pg-object-storage"
|
|
40
43
|
import { PgPipelineRunStorage } from "./pg-pipeline-run-storage"
|
|
41
44
|
import { PgProjectionRunStorage } from "./pg-projection-run-storage"
|
|
42
45
|
import { PgRulesStorage } from "./pg-rules-storage"
|
|
@@ -45,6 +48,8 @@ import { PgTimeseriesStorage } from "./pg-timeseries-storage"
|
|
|
45
48
|
import { PgWebhookRunStorage } from "./pg-webhook-run-storage"
|
|
46
49
|
import { PgWorkflowInterventionStorage } from "./pg-workflow-intervention-storage"
|
|
47
50
|
import { PgWorkflowRunStorage } from "./pg-workflow-run-storage"
|
|
51
|
+
import { PgShareGrantStorage } from "./share-grant-storage"
|
|
52
|
+
import { PgShareSessionStorage } from "./share-session-storage"
|
|
48
53
|
import { isRetryableTransactionConflict } from "./storage-errors"
|
|
49
54
|
import { registerPostgresStorageTestingAdapter } from "./testing"
|
|
50
55
|
import { type PgStoreClient, runPgTransaction } from "./transactions"
|
|
@@ -138,6 +143,7 @@ export class PostgresStorage implements MigrationCapableStorage {
|
|
|
138
143
|
readonly agents: PgAgentStorage
|
|
139
144
|
readonly aiUsage: AiUsageStorage
|
|
140
145
|
readonly aiCosts: AiCostStorage
|
|
146
|
+
readonly aiLimits: AiLimitStorage
|
|
141
147
|
readonly actionRuns: PgActionRunStorage
|
|
142
148
|
readonly pipelineRuns: PgPipelineRunStorage
|
|
143
149
|
readonly workflowRuns: PgWorkflowRunStorage
|
|
@@ -148,6 +154,8 @@ export class PostgresStorage implements MigrationCapableStorage {
|
|
|
148
154
|
readonly webhookRuns: PgWebhookRunStorage
|
|
149
155
|
readonly rules: PgRulesStorage
|
|
150
156
|
readonly connectorConnections: PgConnectorConnectionStorage
|
|
157
|
+
readonly shareGrants: PgShareGrantStorage
|
|
158
|
+
readonly shareSessions: PgShareSessionStorage
|
|
151
159
|
readonly migrators: readonly StorageMigrator[]
|
|
152
160
|
|
|
153
161
|
private readonly sql: SQL
|
|
@@ -205,13 +213,14 @@ export class PostgresStorage implements MigrationCapableStorage {
|
|
|
205
213
|
},
|
|
206
214
|
() => this.assertRootOperationAvailable()
|
|
207
215
|
)
|
|
208
|
-
this.objects =
|
|
216
|
+
this.objects = createObjectOperationScope(stores.objects, scope)
|
|
209
217
|
this.ontology = createOntologyOperationScope(stores.ontology, scope)
|
|
210
218
|
this.auth = createAuthOperationScope(stores.auth, scope)
|
|
211
219
|
this.executions = createOperationScopedFacade(stores.executions, scope)
|
|
212
220
|
this.agents = createAgentOperationScope(stores.agents, scope)
|
|
213
221
|
this.aiUsage = createOperationScopedFacade(stores.aiUsage, scope)
|
|
214
222
|
this.aiCosts = createOperationScopedFacade(stores.aiCosts, scope)
|
|
223
|
+
this.aiLimits = createOperationScopedFacade(stores.aiLimits, scope)
|
|
215
224
|
this.actionRuns = createOperationScopedFacade(stores.actionRuns, scope)
|
|
216
225
|
this.pipelineRuns = createOperationScopedFacade(stores.pipelineRuns, scope)
|
|
217
226
|
this.workflowRuns = createWorkflowRunOperationScope(stores.workflowRuns, scope)
|
|
@@ -222,6 +231,8 @@ export class PostgresStorage implements MigrationCapableStorage {
|
|
|
222
231
|
this.webhookRuns = createOperationScopedFacade(stores.webhookRuns, scope)
|
|
223
232
|
this.rules = createOperationScopedFacade(stores.rules, scope)
|
|
224
233
|
this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope)
|
|
234
|
+
this.shareGrants = createOperationScopedFacade(stores.shareGrants, scope)
|
|
235
|
+
this.shareSessions = createOperationScopedFacade(stores.shareSessions, scope)
|
|
225
236
|
registerPostgresStorageTestingAdapter(this, (durationMs) =>
|
|
226
237
|
stores.connectorConnections.advanceTimeForTesting(durationMs)
|
|
227
238
|
)
|
|
@@ -258,6 +269,7 @@ export class PostgresStorage implements MigrationCapableStorage {
|
|
|
258
269
|
transactionContext.materializations.assertCommittable()
|
|
259
270
|
return result
|
|
260
271
|
} finally {
|
|
272
|
+
await txStorage.aiLimits.settleOperations()
|
|
261
273
|
transactionContext.active = false
|
|
262
274
|
txStorage.ontology.deactivateSessions()
|
|
263
275
|
transactionContext.materializations.deactivate()
|
|
@@ -305,7 +317,7 @@ export class PostgresStorage implements MigrationCapableStorage {
|
|
|
305
317
|
private createTransactionStorage(
|
|
306
318
|
client: PgStoreClient,
|
|
307
319
|
transactionContext: PgOntologyTransactionContext
|
|
308
|
-
): Storage & { readonly ontology: PgOntologyStorage } {
|
|
320
|
+
): Storage & { readonly ontology: PgOntologyStorage; readonly aiLimits: PgAiLimitStorage } {
|
|
309
321
|
return {
|
|
310
322
|
...createPostgresStores(client, {
|
|
311
323
|
runOntologyOperation: async (run) => run(client),
|
|
@@ -329,7 +341,9 @@ function createPostgresStores(
|
|
|
329
341
|
}
|
|
330
342
|
): PostgresStoreSet {
|
|
331
343
|
const auth = new PgAuthStorage({ sql })
|
|
332
|
-
const
|
|
344
|
+
const shareGrants = new PgShareGrantStorage(sql)
|
|
345
|
+
const shareSessions = new PgShareSessionStorage(sql)
|
|
346
|
+
const executions = new PgExecutionStorage(sql, auth, shareSessions)
|
|
333
347
|
return {
|
|
334
348
|
objects: new PgObjectStorage(sql),
|
|
335
349
|
ontology: new PgOntologyStorage({
|
|
@@ -342,6 +356,7 @@ function createPostgresStores(
|
|
|
342
356
|
agents: new PgAgentStorage({ sql, executions }),
|
|
343
357
|
aiUsage: new PgAiUsageStorage(sql),
|
|
344
358
|
aiCosts: new PgAiCostStorage(sql),
|
|
359
|
+
aiLimits: new PgAiLimitStorage(sql),
|
|
345
360
|
actionRuns: new PgActionRunStorage(sql, executions),
|
|
346
361
|
pipelineRuns: new PgPipelineRunStorage(sql, executions),
|
|
347
362
|
workflowRuns: new PgWorkflowRunStorage(sql, executions),
|
|
@@ -352,6 +367,8 @@ function createPostgresStores(
|
|
|
352
367
|
webhookRuns: new PgWebhookRunStorage(sql, executions),
|
|
353
368
|
rules: new PgRulesStorage(sql),
|
|
354
369
|
connectorConnections: new PgConnectorConnectionStorage(sql),
|
|
370
|
+
shareGrants,
|
|
371
|
+
shareSessions,
|
|
355
372
|
}
|
|
356
373
|
}
|
|
357
374
|
|
|
@@ -363,6 +380,7 @@ interface PostgresStoreSet {
|
|
|
363
380
|
readonly agents: PgAgentStorage
|
|
364
381
|
readonly aiUsage: PgAiUsageStorage
|
|
365
382
|
readonly aiCosts: PgAiCostStorage
|
|
383
|
+
readonly aiLimits: PgAiLimitStorage
|
|
366
384
|
readonly actionRuns: PgActionRunStorage
|
|
367
385
|
readonly pipelineRuns: PgPipelineRunStorage
|
|
368
386
|
readonly workflowRuns: PgWorkflowRunStorage
|
|
@@ -373,6 +391,8 @@ interface PostgresStoreSet {
|
|
|
373
391
|
readonly webhookRuns: PgWebhookRunStorage
|
|
374
392
|
readonly rules: PgRulesStorage
|
|
375
393
|
readonly connectorConnections: PgConnectorConnectionStorage
|
|
394
|
+
readonly shareGrants: PgShareGrantStorage
|
|
395
|
+
readonly shareSessions: PgShareSessionStorage
|
|
376
396
|
}
|
|
377
397
|
|
|
378
398
|
function resolveTimeoutMillis(value: number | undefined, label: string): number | undefined {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- Call-time model configuration and provider identity. Historical identity remains unknown.
|
|
2
|
+
ALTER TABLE ai_model_call_usage
|
|
3
|
+
ADD COLUMN requested_reasoning JSONB
|
|
4
|
+
CHECK (
|
|
5
|
+
requested_reasoning IS NULL OR
|
|
6
|
+
jsonb_typeof(requested_reasoning) IN ('string', 'object')
|
|
7
|
+
);
|
|
8
|
+
ALTER TABLE ai_model_call_usage ADD COLUMN provider_ids JSONB;
|
|
9
|
+
|
|
10
|
+
-- Upgrade the shipped valuation reason while retaining the selected-cost projection.
|
|
11
|
+
ALTER TABLE ai_model_call_valuations
|
|
12
|
+
DROP CONSTRAINT ai_model_call_valuations_reason_check;
|
|
13
|
+
|
|
14
|
+
UPDATE ai_model_call_valuations SET reason = 'missingRateCard'
|
|
15
|
+
WHERE reason = 'missingCatalogEntry';
|
|
16
|
+
|
|
17
|
+
ALTER TABLE ai_model_call_valuations ADD CONSTRAINT ai_model_call_valuations_reason_check
|
|
18
|
+
CHECK (reason IS NULL OR reason IN (
|
|
19
|
+
'missingBillingIdentity',
|
|
20
|
+
'missingRateCard',
|
|
21
|
+
'missingUsageMeter',
|
|
22
|
+
'unsupportedPricingDimension',
|
|
23
|
+
'invalidUsageForFormula'
|
|
24
|
+
));
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
CREATE TABLE ai_usage_limits (
|
|
2
|
+
project_id TEXT NOT NULL CHECK (length(btrim(project_id)) > 0),
|
|
3
|
+
id TEXT NOT NULL CHECK (length(btrim(id)) > 0),
|
|
4
|
+
subject_type TEXT NOT NULL CHECK (
|
|
5
|
+
subject_type IN ('project', 'group', 'user', 'serviceAccount')
|
|
6
|
+
),
|
|
7
|
+
subject_id TEXT NOT NULL CHECK (
|
|
8
|
+
(subject_type = 'project' AND subject_id = '')
|
|
9
|
+
OR (subject_type <> 'project' AND length(btrim(subject_id)) > 0)
|
|
10
|
+
),
|
|
11
|
+
meter TEXT NOT NULL CHECK (meter IN ('tokens.total', 'cost.catalogEstimated')),
|
|
12
|
+
currency TEXT NOT NULL CHECK (
|
|
13
|
+
(meter = 'tokens.total' AND currency = '')
|
|
14
|
+
OR (meter = 'cost.catalogEstimated' AND currency = 'USD')
|
|
15
|
+
),
|
|
16
|
+
limit_amount NUMERIC(78, 0) NOT NULL CHECK (limit_amount >= 0),
|
|
17
|
+
period_kind TEXT NOT NULL CHECK (period_kind = 'calendarMonth'),
|
|
18
|
+
enabled BOOLEAN NOT NULL,
|
|
19
|
+
created_at TIMESTAMPTZ NOT NULL,
|
|
20
|
+
updated_at TIMESTAMPTZ NOT NULL,
|
|
21
|
+
PRIMARY KEY (project_id, id),
|
|
22
|
+
UNIQUE (project_id, subject_type, subject_id, meter, currency)
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE INDEX idx_ai_usage_limits_project_enabled
|
|
26
|
+
ON ai_usage_limits (project_id, enabled, subject_type, subject_id, meter, currency);
|
|
27
|
+
|
|
28
|
+
CREATE TABLE ai_usage_limit_periods (
|
|
29
|
+
project_id TEXT NOT NULL CHECK (length(btrim(project_id)) > 0),
|
|
30
|
+
subject_type TEXT NOT NULL CHECK (
|
|
31
|
+
subject_type IN ('project', 'group', 'user', 'serviceAccount')
|
|
32
|
+
),
|
|
33
|
+
subject_id TEXT NOT NULL CHECK (
|
|
34
|
+
(subject_type = 'project' AND subject_id = '')
|
|
35
|
+
OR (subject_type <> 'project' AND length(btrim(subject_id)) > 0)
|
|
36
|
+
),
|
|
37
|
+
meter TEXT NOT NULL CHECK (meter IN ('tokens.total', 'cost.catalogEstimated')),
|
|
38
|
+
currency TEXT NOT NULL CHECK (
|
|
39
|
+
(meter = 'tokens.total' AND currency = '')
|
|
40
|
+
OR (meter = 'cost.catalogEstimated' AND currency = 'USD')
|
|
41
|
+
),
|
|
42
|
+
period_start TIMESTAMPTZ NOT NULL,
|
|
43
|
+
period_end TIMESTAMPTZ NOT NULL,
|
|
44
|
+
actual_amount NUMERIC(78, 0) NOT NULL DEFAULT 0 CHECK (actual_amount >= 0),
|
|
45
|
+
reserved_amount NUMERIC(78, 0) NOT NULL DEFAULT 0 CHECK (reserved_amount >= 0),
|
|
46
|
+
unknown_amount NUMERIC(78, 0) NOT NULL DEFAULT 0 CHECK (unknown_amount >= 0),
|
|
47
|
+
accounting_status TEXT NOT NULL DEFAULT 'complete' CHECK (
|
|
48
|
+
accounting_status IN ('complete', 'unavailable')
|
|
49
|
+
),
|
|
50
|
+
updated_at TIMESTAMPTZ NOT NULL,
|
|
51
|
+
PRIMARY KEY (
|
|
52
|
+
project_id, subject_type, subject_id, meter, currency, period_start
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
CREATE INDEX idx_ai_usage_limit_periods_subject_period
|
|
57
|
+
ON ai_usage_limit_periods (
|
|
58
|
+
project_id, subject_type, subject_id, period_start, period_end, meter, currency
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
CREATE TABLE ai_model_call_reservations (
|
|
62
|
+
project_id TEXT NOT NULL CHECK (length(btrim(project_id)) > 0),
|
|
63
|
+
execution_id TEXT NOT NULL CHECK (length(btrim(execution_id)) > 0),
|
|
64
|
+
attempt BIGINT NOT NULL CHECK (attempt >= 1),
|
|
65
|
+
call_id TEXT NOT NULL CHECK (length(btrim(call_id)) > 0),
|
|
66
|
+
buckets JSONB NOT NULL CHECK (jsonb_typeof(buckets) = 'array'),
|
|
67
|
+
request_key TEXT NOT NULL,
|
|
68
|
+
period_start TIMESTAMPTZ NOT NULL,
|
|
69
|
+
period_end TIMESTAMPTZ NOT NULL,
|
|
70
|
+
state TEXT NOT NULL CHECK (state IN ('active', 'reconciled', 'unknown')),
|
|
71
|
+
usage_record_id TEXT,
|
|
72
|
+
reserved_at TIMESTAMPTZ NOT NULL,
|
|
73
|
+
updated_at TIMESTAMPTZ NOT NULL,
|
|
74
|
+
PRIMARY KEY (project_id, execution_id, attempt, call_id),
|
|
75
|
+
FOREIGN KEY (project_id, execution_id)
|
|
76
|
+
REFERENCES executions(project_id, id)
|
|
77
|
+
ON DELETE RESTRICT,
|
|
78
|
+
FOREIGN KEY (project_id, usage_record_id)
|
|
79
|
+
REFERENCES ai_model_call_usage(project_id, id)
|
|
80
|
+
ON DELETE RESTRICT,
|
|
81
|
+
CHECK (
|
|
82
|
+
(
|
|
83
|
+
state = 'reconciled'
|
|
84
|
+
AND usage_record_id IS NOT NULL
|
|
85
|
+
)
|
|
86
|
+
OR (
|
|
87
|
+
state <> 'reconciled'
|
|
88
|
+
AND usage_record_id IS NULL
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE INDEX idx_ai_model_call_reservations_active
|
|
94
|
+
ON ai_model_call_reservations (project_id, state, period_end, execution_id, attempt, call_id);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
-- Agent executions may either use a managed service account or inherit their parent's exact
|
|
2
|
+
-- credentialed-user / auth-disabled authority.
|
|
3
|
+
ALTER TABLE executions
|
|
4
|
+
DROP CONSTRAINT executions_check3,
|
|
5
|
+
ADD CONSTRAINT executions_agent_authority_check CHECK (
|
|
6
|
+
(
|
|
7
|
+
executor_kind = 'request'
|
|
8
|
+
AND source_kind = 'http'
|
|
9
|
+
AND executor_id = source_id
|
|
10
|
+
AND (
|
|
11
|
+
(
|
|
12
|
+
authority_kind = 'principal'
|
|
13
|
+
AND requested_by_user_id IS NOT DISTINCT FROM authority_user_id
|
|
14
|
+
AND requested_by_service_account_id IS NOT DISTINCT FROM authority_service_account_id
|
|
15
|
+
)
|
|
16
|
+
OR (
|
|
17
|
+
authority_kind = 'disabled'
|
|
18
|
+
AND requested_by_user_id IS NULL
|
|
19
|
+
AND requested_by_service_account_id IS NULL
|
|
20
|
+
)
|
|
21
|
+
)
|
|
22
|
+
)
|
|
23
|
+
OR (
|
|
24
|
+
executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
|
|
25
|
+
AND authority_kind = 'trustedPrimitive'
|
|
26
|
+
AND executor_kind = authority_primitive_kind
|
|
27
|
+
)
|
|
28
|
+
OR (
|
|
29
|
+
executor_kind = 'agent'
|
|
30
|
+
AND source_kind = 'execution'
|
|
31
|
+
AND (
|
|
32
|
+
(
|
|
33
|
+
authority_kind = 'principal'
|
|
34
|
+
AND authority_service_account_id IS NOT NULL
|
|
35
|
+
AND authority_session_id IS NULL
|
|
36
|
+
AND authority_access_token_id IS NULL
|
|
37
|
+
)
|
|
38
|
+
OR (
|
|
39
|
+
authority_kind = 'principal'
|
|
40
|
+
AND authority_user_id IS NOT NULL
|
|
41
|
+
AND num_nonnulls(authority_session_id, authority_access_token_id) = 1
|
|
42
|
+
)
|
|
43
|
+
OR authority_kind = 'disabled'
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
OR (executor_kind = 'kernel' AND authority_kind = 'kernel')
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
ALTER TABLE agent_runs
|
|
50
|
+
ADD COLUMN kind TEXT NOT NULL DEFAULT 'conversation'
|
|
51
|
+
CHECK (kind IN ('conversation', 'subagent')),
|
|
52
|
+
ADD COLUMN parent_run_id TEXT,
|
|
53
|
+
ADD COLUMN spawn_key TEXT,
|
|
54
|
+
ADD COLUMN spec JSONB,
|
|
55
|
+
ADD COLUMN result JSONB,
|
|
56
|
+
ALTER COLUMN thread_id DROP NOT NULL,
|
|
57
|
+
ALTER COLUMN agent_id DROP NOT NULL,
|
|
58
|
+
ALTER COLUMN trigger_message_id DROP NOT NULL,
|
|
59
|
+
ADD CONSTRAINT fk_agent_runs_parent
|
|
60
|
+
FOREIGN KEY (project_id, parent_run_id)
|
|
61
|
+
REFERENCES agent_runs (project_id, id)
|
|
62
|
+
ON DELETE RESTRICT,
|
|
63
|
+
ADD CONSTRAINT agent_runs_kind_fields CHECK (
|
|
64
|
+
(
|
|
65
|
+
kind = 'conversation'
|
|
66
|
+
AND thread_id IS NOT NULL
|
|
67
|
+
AND agent_id IS NOT NULL
|
|
68
|
+
AND trigger_message_id IS NOT NULL
|
|
69
|
+
AND parent_run_id IS NULL
|
|
70
|
+
AND spawn_key IS NULL
|
|
71
|
+
AND spec IS NULL
|
|
72
|
+
AND result IS NULL
|
|
73
|
+
)
|
|
74
|
+
OR
|
|
75
|
+
(
|
|
76
|
+
kind = 'subagent'
|
|
77
|
+
AND thread_id IS NULL
|
|
78
|
+
AND agent_id IS NULL
|
|
79
|
+
AND trigger_message_id IS NULL
|
|
80
|
+
AND parent_run_id IS NOT NULL
|
|
81
|
+
AND spawn_key IS NOT NULL
|
|
82
|
+
AND spec IS NOT NULL
|
|
83
|
+
)
|
|
84
|
+
),
|
|
85
|
+
ADD CONSTRAINT agent_runs_subagent_result CHECK (
|
|
86
|
+
kind <> 'subagent' OR status <> 'succeeded' OR result IS NOT NULL
|
|
87
|
+
),
|
|
88
|
+
ADD CONSTRAINT uq_agent_runs_parent_spawn_key UNIQUE (project_id, parent_run_id, spawn_key);
|
|
89
|
+
|
|
90
|
+
CREATE INDEX idx_agent_runs_project_parent_started
|
|
91
|
+
ON agent_runs (
|
|
92
|
+
project_id,
|
|
93
|
+
parent_run_id,
|
|
94
|
+
status,
|
|
95
|
+
COALESCE(started_at, created_at) DESC,
|
|
96
|
+
id DESC
|
|
97
|
+
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
ALTER TABLE agent_runs
|
|
2
|
+
DROP CONSTRAINT agent_runs_kind_fields,
|
|
3
|
+
ADD CONSTRAINT agent_runs_kind_fields CHECK (
|
|
4
|
+
(
|
|
5
|
+
kind = 'conversation'
|
|
6
|
+
AND thread_id IS NOT NULL
|
|
7
|
+
AND agent_id IS NOT NULL
|
|
8
|
+
AND trigger_message_id IS NOT NULL
|
|
9
|
+
AND parent_run_id IS NULL
|
|
10
|
+
AND spawn_key IS NULL
|
|
11
|
+
AND result IS NULL
|
|
12
|
+
)
|
|
13
|
+
OR
|
|
14
|
+
(
|
|
15
|
+
kind = 'subagent'
|
|
16
|
+
AND thread_id IS NULL
|
|
17
|
+
AND agent_id IS NULL
|
|
18
|
+
AND trigger_message_id IS NULL
|
|
19
|
+
AND parent_run_id IS NOT NULL
|
|
20
|
+
AND spawn_key IS NOT NULL
|
|
21
|
+
AND spec IS NOT NULL
|
|
22
|
+
)
|
|
23
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
DROP INDEX IF EXISTS idx_agent_threads_project_agent_activity;
|
|
2
|
+
ALTER TABLE workflow_agent_node_runs RENAME COLUMN agent_id TO actor_id;
|
|
3
|
+
DROP INDEX IF EXISTS idx_agent_runs_project_agent_started;
|
|
4
|
+
|
|
5
|
+
ALTER TABLE agent_threads DROP COLUMN agent_id;
|
|
6
|
+
|
|
7
|
+
ALTER TABLE agent_runs
|
|
8
|
+
DROP CONSTRAINT agent_runs_kind_fields,
|
|
9
|
+
DROP COLUMN agent_id,
|
|
10
|
+
ADD CONSTRAINT agent_runs_kind_fields CHECK (
|
|
11
|
+
(
|
|
12
|
+
kind = 'conversation'
|
|
13
|
+
AND thread_id IS NOT NULL
|
|
14
|
+
AND trigger_message_id IS NOT NULL
|
|
15
|
+
AND parent_run_id IS NULL
|
|
16
|
+
AND spawn_key IS NULL
|
|
17
|
+
AND result IS NULL
|
|
18
|
+
)
|
|
19
|
+
OR
|
|
20
|
+
(
|
|
21
|
+
kind = 'subagent'
|
|
22
|
+
AND thread_id IS NULL
|
|
23
|
+
AND trigger_message_id IS NULL
|
|
24
|
+
AND parent_run_id IS NOT NULL
|
|
25
|
+
AND spawn_key IS NOT NULL
|
|
26
|
+
AND spec IS NOT NULL
|
|
27
|
+
)
|
|
28
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
CREATE TABLE auth_device_authorizations (
|
|
2
|
+
project_id TEXT NOT NULL,
|
|
3
|
+
id TEXT NOT NULL,
|
|
4
|
+
device_code_hash TEXT NOT NULL,
|
|
5
|
+
user_code TEXT NOT NULL,
|
|
6
|
+
client_name TEXT NOT NULL,
|
|
7
|
+
token_name TEXT NOT NULL,
|
|
8
|
+
token_expires_at TIMESTAMPTZ NOT NULL,
|
|
9
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'approved', 'denied', 'consumed')),
|
|
10
|
+
approved_user_id TEXT,
|
|
11
|
+
approved_session_id TEXT,
|
|
12
|
+
created_at TIMESTAMPTZ NOT NULL,
|
|
13
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
14
|
+
approved_at TIMESTAMPTZ,
|
|
15
|
+
denied_at TIMESTAMPTZ,
|
|
16
|
+
consumed_at TIMESTAMPTZ,
|
|
17
|
+
PRIMARY KEY (project_id, id),
|
|
18
|
+
UNIQUE (project_id, user_code),
|
|
19
|
+
FOREIGN KEY (project_id, approved_user_id) REFERENCES auth_users (project_id, id),
|
|
20
|
+
FOREIGN KEY (project_id, approved_session_id) REFERENCES auth_sessions (project_id, id)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE INDEX idx_auth_device_authorizations_pending
|
|
24
|
+
ON auth_device_authorizations (project_id, status, expires_at DESC);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
CREATE TABLE share_grants (
|
|
2
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
3
|
+
id TEXT NOT NULL CHECK (length(trim(id)) > 0),
|
|
4
|
+
definition_id TEXT NOT NULL CHECK (length(trim(definition_id)) > 0),
|
|
5
|
+
target_object_type_id TEXT NOT NULL CHECK (length(trim(target_object_type_id)) > 0),
|
|
6
|
+
target_primary_id TEXT NOT NULL CHECK (length(trim(target_primary_id)) > 0),
|
|
7
|
+
issued_by_type TEXT NOT NULL CHECK (issued_by_type IN ('user', 'serviceAccount')),
|
|
8
|
+
issued_by_id TEXT NOT NULL CHECK (length(trim(issued_by_id)) > 0),
|
|
9
|
+
authority_version INTEGER NOT NULL CHECK (authority_version > 0),
|
|
10
|
+
authority_snapshot JSONB NOT NULL CHECK (
|
|
11
|
+
jsonb_typeof(authority_snapshot) = 'object'
|
|
12
|
+
AND jsonb_typeof(authority_snapshot -> 'version') = 'number'
|
|
13
|
+
AND (authority_snapshot ->> 'version')::integer = authority_version
|
|
14
|
+
AND jsonb_typeof(authority_snapshot -> 'access') = 'object'
|
|
15
|
+
),
|
|
16
|
+
authority_digest TEXT NOT NULL CHECK (authority_digest ~ '^[0-9a-f]{64}$'),
|
|
17
|
+
token_hash TEXT NOT NULL CHECK (token_hash ~ '^[0-9a-f]{64}$'),
|
|
18
|
+
destination_path TEXT NOT NULL CHECK (
|
|
19
|
+
left(destination_path, 1) = '/'
|
|
20
|
+
AND position('?' IN destination_path) = 0
|
|
21
|
+
AND position('#' IN destination_path) = 0
|
|
22
|
+
AND position(chr(92) IN destination_path) = 0
|
|
23
|
+
),
|
|
24
|
+
created_at TIMESTAMPTZ NOT NULL,
|
|
25
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
26
|
+
revoked_at TIMESTAMPTZ,
|
|
27
|
+
revoked_by_type TEXT CHECK (
|
|
28
|
+
revoked_by_type IS NULL OR revoked_by_type IN ('user', 'serviceAccount', 'system')
|
|
29
|
+
),
|
|
30
|
+
revoked_by_id TEXT CHECK (
|
|
31
|
+
revoked_by_id IS NULL OR length(trim(revoked_by_id)) > 0
|
|
32
|
+
),
|
|
33
|
+
PRIMARY KEY (project_id, id),
|
|
34
|
+
UNIQUE (project_id, token_hash),
|
|
35
|
+
CHECK (expires_at > created_at),
|
|
36
|
+
CHECK (revoked_at IS NULL OR revoked_at >= created_at),
|
|
37
|
+
CHECK (
|
|
38
|
+
(revoked_at IS NULL AND revoked_by_type IS NULL AND revoked_by_id IS NULL)
|
|
39
|
+
OR
|
|
40
|
+
(revoked_at IS NOT NULL AND revoked_by_type IS NOT NULL AND revoked_by_id IS NOT NULL)
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
CREATE INDEX idx_share_grants_project_created
|
|
45
|
+
ON share_grants (project_id, created_at DESC, id DESC);
|
|
46
|
+
CREATE INDEX idx_share_grants_definition_target
|
|
47
|
+
ON share_grants (
|
|
48
|
+
project_id,
|
|
49
|
+
definition_id,
|
|
50
|
+
target_object_type_id,
|
|
51
|
+
target_primary_id,
|
|
52
|
+
created_at DESC,
|
|
53
|
+
id DESC
|
|
54
|
+
);
|
|
55
|
+
CREATE INDEX idx_share_grants_expiry
|
|
56
|
+
ON share_grants (project_id, expires_at)
|
|
57
|
+
WHERE revoked_at IS NULL;
|