@sixb/sqlite 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.
Files changed (91) hide show
  1. package/dist/agents/rows.d.ts +7 -4
  2. package/dist/agents/rows.d.ts.map +1 -1
  3. package/dist/agents/runs.d.ts +3 -2
  4. package/dist/agents/runs.d.ts.map +1 -1
  5. package/dist/agents/threads.d.ts.map +1 -1
  6. package/dist/ai-cost-groups.d.ts +5 -0
  7. package/dist/ai-cost-groups.d.ts.map +1 -0
  8. package/dist/ai-cost-storage.d.ts +2 -1
  9. package/dist/ai-cost-storage.d.ts.map +1 -1
  10. package/dist/ai-limit-storage.d.ts +35 -0
  11. package/dist/ai-limit-storage.d.ts.map +1 -0
  12. package/dist/ai-usage-storage.d.ts +1 -0
  13. package/dist/ai-usage-storage.d.ts.map +1 -1
  14. package/dist/auth-storage/access-tokens.d.ts +1 -1
  15. package/dist/auth-storage/access-tokens.d.ts.map +1 -1
  16. package/dist/auth-storage/auth-storage.d.ts +4 -1
  17. package/dist/auth-storage/auth-storage.d.ts.map +1 -1
  18. package/dist/auth-storage/device-authorizations.d.ts +29 -0
  19. package/dist/auth-storage/device-authorizations.d.ts.map +1 -0
  20. package/dist/auth-storage/rows.d.ts +19 -1
  21. package/dist/auth-storage/rows.d.ts.map +1 -1
  22. package/dist/auth-storage/shared.d.ts +1 -1
  23. package/dist/auth-storage/shared.d.ts.map +1 -1
  24. package/dist/execution-storage.d.ts +3 -2
  25. package/dist/execution-storage.d.ts.map +1 -1
  26. package/dist/index.d.ts +4 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +3443 -789
  29. package/dist/index.js.map +29 -20
  30. package/dist/migrations.d.ts.map +1 -1
  31. package/dist/objects/index.d.ts +3 -0
  32. package/dist/objects/index.d.ts.map +1 -0
  33. package/dist/{object-query-compiler.d.ts → objects/query-compiler.d.ts} +16 -1
  34. package/dist/objects/query-compiler.d.ts.map +1 -0
  35. package/dist/objects/read-scope.d.ts +17 -0
  36. package/dist/objects/read-scope.d.ts.map +1 -0
  37. package/dist/objects/reader.d.ts +51 -0
  38. package/dist/objects/reader.d.ts.map +1 -0
  39. package/dist/objects/rows.d.ts +33 -0
  40. package/dist/objects/rows.d.ts.map +1 -0
  41. package/dist/objects/selected-reader.d.ts +9 -0
  42. package/dist/objects/selected-reader.d.ts.map +1 -0
  43. package/dist/{object-storage.d.ts → objects/storage.d.ts} +12 -9
  44. package/dist/objects/storage.d.ts.map +1 -0
  45. package/dist/share-grant-storage.d.ts +20 -0
  46. package/dist/share-grant-storage.d.ts.map +1 -0
  47. package/dist/share-session-storage.d.ts +19 -0
  48. package/dist/share-session-storage.d.ts.map +1 -0
  49. package/dist/storage-errors.d.ts +1 -0
  50. package/dist/storage-errors.d.ts.map +1 -1
  51. package/dist/transactions.d.ts +8 -0
  52. package/dist/transactions.d.ts.map +1 -1
  53. package/package.json +3 -3
  54. package/src/agents/rows.ts +36 -9
  55. package/src/agents/runs.ts +152 -13
  56. package/src/agents/threads.ts +2 -17
  57. package/src/ai-cost-groups.ts +100 -0
  58. package/src/ai-cost-storage.ts +67 -25
  59. package/src/ai-limit-storage.ts +981 -0
  60. package/src/ai-usage-storage.ts +24 -1
  61. package/src/auth-storage/access-tokens.ts +77 -68
  62. package/src/auth-storage/auth-storage.ts +80 -1
  63. package/src/auth-storage/device-authorizations.ts +153 -0
  64. package/src/auth-storage/rows.ts +41 -0
  65. package/src/auth-storage/shared.ts +1 -0
  66. package/src/execution-storage.ts +22 -3
  67. package/src/index.ts +24 -3
  68. package/src/migrations/029-model-accounting.sql +79 -0
  69. package/src/migrations/030-ai-usage-limits.sql +100 -0
  70. package/src/migrations/031-subagent-runs.sql +231 -0
  71. package/src/migrations/032-conversation-run-spec.sql +78 -0
  72. package/src/migrations/033-retire-agent-definitions.sql +89 -0
  73. package/src/migrations/034-device-authorizations.sql +22 -0
  74. package/src/migrations/035-share-grants.sql +66 -0
  75. package/src/migrations/036-share-sessions.sql +226 -0
  76. package/src/migrations.ts +22 -0
  77. package/src/objects/index.ts +2 -0
  78. package/src/{object-query-compiler.ts → objects/query-compiler.ts} +104 -54
  79. package/src/objects/read-scope.ts +316 -0
  80. package/src/objects/reader.ts +526 -0
  81. package/src/objects/rows.ts +123 -0
  82. package/src/objects/selected-reader.ts +119 -0
  83. package/src/objects/storage.ts +296 -0
  84. package/src/share-grant-storage.ts +252 -0
  85. package/src/share-session-storage.ts +189 -0
  86. package/src/storage-errors.ts +4 -0
  87. package/src/transactions.ts +32 -0
  88. package/src/workflow-run-storage.ts +8 -8
  89. package/dist/object-query-compiler.d.ts.map +0 -1
  90. package/dist/object-storage.d.ts.map +0 -1
  91. package/src/object-storage.ts +0 -709
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,14 +21,18 @@ 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,
27
+ type ShareGrantStorage,
28
+ type ShareSessionStorage,
25
29
  StorageTransactionError,
26
30
  throwNestedStorageTransaction,
27
31
  } from "@sixb/core/storage"
28
32
  import { SqliteActionRunStorage } from "./action-run-storage"
29
33
  import { SqliteAgentStorage } from "./agents"
30
34
  import { SqliteAiCostStorage } from "./ai-cost-storage"
35
+ import { SqliteAiLimitStorage } from "./ai-limit-storage"
31
36
  import { SqliteAiUsageStorage } from "./ai-usage-storage"
32
37
  import { SqliteAuthStorage } from "./auth-storage"
33
38
  import { SqliteConnectorConnectionStorage } from "./connector-connection-storage"
@@ -37,11 +42,13 @@ import {
37
42
  installFreshSqliteSchema,
38
43
  sqliteStoragePath,
39
44
  } from "./migrations"
40
- import { SqliteObjectStorage } from "./object-storage"
45
+ import { SqliteObjectStorage } from "./objects"
41
46
  import { SqliteOntologyStorage, type SqliteOntologyTransactionContext } from "./ontology-storage"
42
47
  import { SqlitePipelineRunStorage } from "./pipeline-run-storage"
43
48
  import { SqliteProjectionRunStorage } from "./projection-run-storage"
44
49
  import { SqliteRulesStorage } from "./rules-storage"
50
+ import { SqliteShareGrantStorage } from "./share-grant-storage"
51
+ import { SqliteShareSessionStorage } from "./share-session-storage"
45
52
  import { SqliteSyncRunStorage } from "./sync-run-storage"
46
53
  import { registerSqliteStorageTestingAdapter } from "./testing"
47
54
  import { SqliteTimeseriesStorage } from "./timeseries-storage"
@@ -84,6 +91,7 @@ export class SqliteStorage implements MigrationCapableStorage {
84
91
  readonly agents: SqliteAgentStorage
85
92
  readonly aiUsage: AiUsageStorage
86
93
  readonly aiCosts: AiCostStorage
94
+ readonly aiLimits: AiLimitStorage
87
95
  readonly actionRuns: SqliteActionRunStorage
88
96
  readonly pipelineRuns: SqlitePipelineRunStorage
89
97
  readonly syncRuns: SqliteSyncRunStorage
@@ -93,6 +101,8 @@ export class SqliteStorage implements MigrationCapableStorage {
93
101
  readonly timeseries: Storage["timeseries"]
94
102
  readonly webhookRuns: SqliteWebhookRunStorage
95
103
  readonly rules: SqliteRulesStorage
104
+ readonly shareGrants: ShareGrantStorage
105
+ readonly shareSessions: ShareSessionStorage
96
106
  readonly connectorConnections: SqliteConnectorConnectionStorage
97
107
  readonly migrators: readonly StorageMigrator[]
98
108
 
@@ -140,13 +150,14 @@ export class SqliteStorage implements MigrationCapableStorage {
140
150
  const readTimeseries = path
141
151
  ? new SqliteTimeseriesStorage({ connection: this.readConnection })
142
152
  : stores.timeseries
143
- this.objects = createOperationScopedFacade(readObjects, readScope)
153
+ this.objects = createObjectOperationScope(readObjects, readScope)
144
154
  this.ontology = createOntologyOperationScope(stores.ontology, ontologyScope)
145
155
  this.auth = createAuthOperationScope(stores.auth, scope)
146
156
  this.executions = createOperationScopedFacade(stores.executions, scope)
147
157
  this.agents = createAgentOperationScope(stores.agents, scope)
148
158
  this.aiUsage = createOperationScopedFacade(stores.aiUsage, scope)
149
159
  this.aiCosts = createOperationScopedFacade(stores.aiCosts, scope)
160
+ this.aiLimits = createOperationScopedFacade(stores.aiLimits, scope)
150
161
  this.actionRuns = createOperationScopedFacade(stores.actionRuns, scope)
151
162
  this.pipelineRuns = createOperationScopedFacade(stores.pipelineRuns, scope)
152
163
  this.timeseries = createOperationScopedFacade(readTimeseries, readScope)
@@ -156,6 +167,8 @@ export class SqliteStorage implements MigrationCapableStorage {
156
167
  this.workflowInterventions = createOperationScopedFacade(stores.workflowInterventions, scope)
157
168
  this.webhookRuns = createOperationScopedFacade(stores.webhookRuns, scope)
158
169
  this.rules = createOperationScopedFacade(stores.rules, scope)
170
+ this.shareGrants = createOperationScopedFacade(stores.shareGrants, scope)
171
+ this.shareSessions = createOperationScopedFacade(stores.shareSessions, scope)
159
172
  this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope)
160
173
  this.migrators = options.path ? createSqliteStorageMigrators(options.path) : []
161
174
  registerSqliteStorageTestingAdapter(this, (durationMs) =>
@@ -290,7 +303,9 @@ function createSqliteStores(
290
303
  }
291
304
  ): SqliteStoreSet {
292
305
  const auth = new SqliteAuthStorage({ connection })
293
- const executions = new SqliteExecutionStorage(connection.db, auth)
306
+ const shareGrants = new SqliteShareGrantStorage({ connection })
307
+ const shareSessions = new SqliteShareSessionStorage({ connection })
308
+ const executions = new SqliteExecutionStorage(connection.db, auth, shareSessions)
294
309
  return {
295
310
  objects: new SqliteObjectStorage({ connection }),
296
311
  ontology: new SqliteOntologyStorage({
@@ -303,6 +318,7 @@ function createSqliteStores(
303
318
  agents: new SqliteAgentStorage({ connection, executions }),
304
319
  aiUsage: new SqliteAiUsageStorage({ connection }),
305
320
  aiCosts: new SqliteAiCostStorage(connection),
321
+ aiLimits: new SqliteAiLimitStorage({ connection }),
306
322
  actionRuns: new SqliteActionRunStorage({ connection, executions }),
307
323
  pipelineRuns: new SqlitePipelineRunStorage({ connection, executions }),
308
324
  timeseries: new SqliteTimeseriesStorage({ connection }),
@@ -312,6 +328,8 @@ function createSqliteStores(
312
328
  workflowInterventions: new SqliteWorkflowInterventionStorage({ connection }),
313
329
  webhookRuns: new SqliteWebhookRunStorage({ connection, executions }),
314
330
  rules: new SqliteRulesStorage({ connection }),
331
+ shareGrants,
332
+ shareSessions,
315
333
  connectorConnections: new SqliteConnectorConnectionStorage(connection),
316
334
  }
317
335
  }
@@ -324,6 +342,7 @@ interface SqliteStoreSet {
324
342
  readonly agents: SqliteAgentStorage
325
343
  readonly aiUsage: SqliteAiUsageStorage
326
344
  readonly aiCosts: SqliteAiCostStorage
345
+ readonly aiLimits: SqliteAiLimitStorage
327
346
  readonly actionRuns: SqliteActionRunStorage
328
347
  readonly pipelineRuns: SqlitePipelineRunStorage
329
348
  readonly syncRuns: SqliteSyncRunStorage
@@ -333,6 +352,8 @@ interface SqliteStoreSet {
333
352
  readonly timeseries: SqliteTimeseriesStorage
334
353
  readonly webhookRuns: SqliteWebhookRunStorage
335
354
  readonly rules: SqliteRulesStorage
355
+ readonly shareGrants: SqliteShareGrantStorage
356
+ readonly shareSessions: SqliteShareSessionStorage
336
357
  readonly connectorConnections: SqliteConnectorConnectionStorage
337
358
  }
338
359
 
@@ -0,0 +1,79 @@
1
+ -- Call-time model configuration and provider identity. Historical identity remains unknown.
2
+ ALTER TABLE ai_model_call_usage
3
+ ADD COLUMN requested_reasoning TEXT
4
+ CHECK (
5
+ requested_reasoning IS NULL OR (
6
+ json_valid(requested_reasoning) AND
7
+ json_type(requested_reasoning) IN ('text', 'object')
8
+ )
9
+ );
10
+ ALTER TABLE ai_model_call_usage ADD COLUMN provider_ids TEXT
11
+ CHECK (provider_ids IS NULL OR json_valid(provider_ids));
12
+
13
+ -- Upgrade the shipped valuation reason while retaining the selected-cost projection.
14
+ CREATE TABLE ai_model_call_valuations_next (
15
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
16
+ usage_record_id TEXT NOT NULL CHECK (length(trim(usage_record_id)) > 0),
17
+ status TEXT NOT NULL CHECK (status IN ('rated', 'unpriceable')),
18
+ provider_id TEXT CHECK (provider_id IS NULL OR length(trim(provider_id)) > 0),
19
+ model_id TEXT CHECK (model_id IS NULL OR length(trim(model_id)) > 0),
20
+ currency TEXT CHECK (
21
+ currency IS NULL OR (length(currency) = 3 AND currency GLOB '[A-Z][A-Z][A-Z]')
22
+ ),
23
+ amount_nanos INTEGER CHECK (
24
+ amount_nanos IS NULL OR (typeof(amount_nanos) = 'integer' AND amount_nanos >= 0)
25
+ ),
26
+ reason TEXT CHECK (
27
+ reason IS NULL OR reason IN (
28
+ 'missingBillingIdentity',
29
+ 'missingRateCard',
30
+ 'missingUsageMeter',
31
+ 'unsupportedPricingDimension',
32
+ 'invalidUsageForFormula'
33
+ )
34
+ ),
35
+ details TEXT NOT NULL CHECK (json_valid(details) AND json_type(details) = 'object'),
36
+ rated_at TEXT NOT NULL CHECK (length(trim(rated_at)) > 0),
37
+ PRIMARY KEY (project_id, usage_record_id),
38
+ FOREIGN KEY (project_id, usage_record_id)
39
+ REFERENCES ai_model_call_usage(project_id, id)
40
+ ON DELETE RESTRICT,
41
+ CHECK (
42
+ (
43
+ status = 'rated'
44
+ AND provider_id IS NOT NULL
45
+ AND model_id IS NOT NULL
46
+ AND currency IS NOT NULL
47
+ AND amount_nanos IS NOT NULL
48
+ AND reason IS NULL
49
+ )
50
+ OR
51
+ (
52
+ status = 'unpriceable'
53
+ AND currency IS NULL
54
+ AND amount_nanos IS NULL
55
+ AND reason IS NOT NULL
56
+ AND (
57
+ (reason = 'missingBillingIdentity' AND provider_id IS NULL AND model_id IS NULL)
58
+ OR
59
+ (reason <> 'missingBillingIdentity' AND provider_id IS NOT NULL AND model_id IS NOT NULL)
60
+ )
61
+ )
62
+ )
63
+ );
64
+
65
+ INSERT INTO ai_model_call_valuations_next (
66
+ project_id, usage_record_id, status, provider_id, model_id,
67
+ currency, amount_nanos, reason, details, rated_at
68
+ )
69
+ SELECT project_id, usage_record_id, status, provider_id, model_id,
70
+ currency, amount_nanos,
71
+ CASE WHEN reason = 'missingCatalogEntry' THEN 'missingRateCard' ELSE reason END,
72
+ details, rated_at
73
+ FROM ai_model_call_valuations;
74
+
75
+ DROP TABLE ai_model_call_valuations;
76
+ ALTER TABLE ai_model_call_valuations_next RENAME TO ai_model_call_valuations;
77
+
78
+ CREATE INDEX idx_ai_model_call_valuations_summary
79
+ ON ai_model_call_valuations (project_id, status, currency, usage_record_id);
@@ -0,0 +1,100 @@
1
+ CREATE TABLE ai_usage_limits (
2
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
3
+ id TEXT NOT NULL CHECK (length(trim(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(trim(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 TEXT NOT NULL CHECK (
17
+ limit_amount = '0'
18
+ OR (
19
+ limit_amount NOT GLOB '*[^0-9]*'
20
+ AND substr(limit_amount, 1, 1) BETWEEN '1' AND '9'
21
+ )
22
+ ),
23
+ period_kind TEXT NOT NULL CHECK (period_kind = 'calendarMonth'),
24
+ enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),
25
+ created_at TEXT NOT NULL,
26
+ updated_at TEXT NOT NULL,
27
+ PRIMARY KEY (project_id, id),
28
+ UNIQUE (project_id, subject_type, subject_id, meter, currency)
29
+ );
30
+
31
+ CREATE INDEX idx_ai_usage_limits_project_enabled
32
+ ON ai_usage_limits (project_id, enabled, subject_type, subject_id, meter, currency);
33
+
34
+ CREATE TABLE ai_usage_limit_periods (
35
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
36
+ subject_type TEXT NOT NULL CHECK (
37
+ subject_type IN ('project', 'group', 'user', 'serviceAccount')
38
+ ),
39
+ subject_id TEXT NOT NULL CHECK (
40
+ (subject_type = 'project' AND subject_id = '')
41
+ OR (subject_type <> 'project' AND length(trim(subject_id)) > 0)
42
+ ),
43
+ meter TEXT NOT NULL CHECK (meter IN ('tokens.total', 'cost.catalogEstimated')),
44
+ currency TEXT NOT NULL CHECK (
45
+ (meter = 'tokens.total' AND currency = '')
46
+ OR (meter = 'cost.catalogEstimated' AND currency = 'USD')
47
+ ),
48
+ period_start TEXT NOT NULL,
49
+ period_end TEXT NOT NULL,
50
+ actual_amount TEXT NOT NULL DEFAULT '0',
51
+ reserved_amount TEXT NOT NULL DEFAULT '0',
52
+ unknown_amount TEXT NOT NULL DEFAULT '0',
53
+ accounting_status TEXT NOT NULL DEFAULT 'complete' CHECK (
54
+ accounting_status IN ('complete', 'unavailable')
55
+ ),
56
+ updated_at TEXT NOT NULL,
57
+ PRIMARY KEY (
58
+ project_id, subject_type, subject_id, meter, currency, period_start
59
+ )
60
+ );
61
+
62
+ CREATE INDEX idx_ai_usage_limit_periods_subject_period
63
+ ON ai_usage_limit_periods (
64
+ project_id, subject_type, subject_id, period_start, period_end, meter, currency
65
+ );
66
+
67
+ CREATE TABLE ai_model_call_reservations (
68
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
69
+ execution_id TEXT NOT NULL CHECK (length(trim(execution_id)) > 0),
70
+ attempt INTEGER NOT NULL CHECK (attempt >= 1),
71
+ call_id TEXT NOT NULL CHECK (length(trim(call_id)) > 0),
72
+ buckets TEXT NOT NULL CHECK (json_valid(buckets) AND json_type(buckets) = 'array'),
73
+ request_key TEXT NOT NULL,
74
+ period_start TEXT NOT NULL,
75
+ period_end TEXT NOT NULL,
76
+ state TEXT NOT NULL CHECK (state IN ('active', 'reconciled', 'unknown')),
77
+ usage_record_id TEXT,
78
+ reserved_at TEXT NOT NULL,
79
+ updated_at TEXT NOT NULL,
80
+ PRIMARY KEY (project_id, execution_id, attempt, call_id),
81
+ FOREIGN KEY (project_id, execution_id)
82
+ REFERENCES executions(project_id, id)
83
+ ON DELETE RESTRICT,
84
+ FOREIGN KEY (project_id, usage_record_id)
85
+ REFERENCES ai_model_call_usage(project_id, id)
86
+ ON DELETE RESTRICT,
87
+ CHECK (
88
+ (
89
+ state = 'reconciled'
90
+ AND usage_record_id IS NOT NULL
91
+ )
92
+ OR (
93
+ state <> 'reconciled'
94
+ AND usage_record_id IS NULL
95
+ )
96
+ )
97
+ );
98
+
99
+ CREATE INDEX idx_ai_model_call_reservations_active
100
+ ON ai_model_call_reservations (project_id, state, period_end, execution_id, attempt, call_id);
@@ -0,0 +1,231 @@
1
+ -- SQLite cannot alter a CHECK constraint in place. Rebuild the execution table to align SQL with
2
+ -- the durable Agent authority model: managed service account or exact inherited user/disabled.
3
+ CREATE TABLE executions_v3 (
4
+ project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
5
+ id TEXT NOT NULL CHECK (length(trim(id)) > 0),
6
+ executor_kind TEXT NOT NULL CHECK (
7
+ executor_kind IN (
8
+ 'request', 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow',
9
+ 'agent', 'kernel'
10
+ )
11
+ ),
12
+ executor_id TEXT NOT NULL CHECK (length(trim(executor_id)) > 0),
13
+ source_kind TEXT NOT NULL CHECK (
14
+ source_kind IN ('http', 'webhook', 'schedule', 'event', 'datasetVersion', 'execution')
15
+ ),
16
+ source_id TEXT NOT NULL CHECK (length(trim(source_id)) > 0),
17
+ requested_by_user_id TEXT,
18
+ requested_by_service_account_id TEXT,
19
+ correlation_id TEXT NOT NULL CHECK (length(trim(correlation_id)) > 0),
20
+ parent_execution_id TEXT,
21
+ authority_kind TEXT NOT NULL CHECK (
22
+ authority_kind IN ('principal', 'trustedPrimitive', 'kernel', 'disabled')
23
+ ),
24
+ authority_user_id TEXT,
25
+ authority_service_account_id TEXT,
26
+ authority_session_id TEXT,
27
+ authority_access_token_id TEXT,
28
+ authority_primitive_kind TEXT CHECK (
29
+ authority_primitive_kind IS NULL
30
+ OR authority_primitive_kind IN (
31
+ 'action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow'
32
+ )
33
+ ),
34
+ authority_primitive_id TEXT,
35
+ authority_kernel_operation TEXT CHECK (
36
+ authority_kernel_operation IS NULL OR authority_kernel_operation = 'ontology.recover'
37
+ ),
38
+ created_at TEXT NOT NULL,
39
+ PRIMARY KEY (project_id, id),
40
+ FOREIGN KEY (project_id, parent_execution_id) REFERENCES executions (project_id, id),
41
+ FOREIGN KEY (project_id, requested_by_user_id) REFERENCES auth_users (project_id, id),
42
+ FOREIGN KEY (project_id, requested_by_service_account_id)
43
+ REFERENCES auth_service_accounts (project_id, id),
44
+ FOREIGN KEY (project_id, authority_user_id) REFERENCES auth_users (project_id, id),
45
+ FOREIGN KEY (project_id, authority_service_account_id)
46
+ REFERENCES auth_service_accounts (project_id, id),
47
+ FOREIGN KEY (project_id, authority_session_id) REFERENCES auth_sessions (project_id, id),
48
+ FOREIGN KEY (project_id, authority_access_token_id)
49
+ REFERENCES auth_access_tokens (project_id, id),
50
+ CHECK ((requested_by_user_id IS NOT NULL) + (requested_by_service_account_id IS NOT NULL) <= 1),
51
+ CHECK (
52
+ (source_kind = 'execution' AND parent_execution_id = source_id)
53
+ OR (source_kind <> 'execution' AND parent_execution_id IS NULL)
54
+ ),
55
+ CHECK (
56
+ (
57
+ authority_kind = 'principal'
58
+ AND (authority_user_id IS NOT NULL) + (authority_service_account_id IS NOT NULL) = 1
59
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) <= 1
60
+ AND (authority_session_id IS NULL OR authority_user_id IS NOT NULL)
61
+ AND authority_primitive_kind IS NULL
62
+ AND authority_primitive_id IS NULL
63
+ AND authority_kernel_operation IS NULL
64
+ )
65
+ OR (
66
+ authority_kind = 'trustedPrimitive'
67
+ AND authority_user_id IS NULL
68
+ AND authority_service_account_id IS NULL
69
+ AND authority_session_id IS NULL
70
+ AND authority_access_token_id IS NULL
71
+ AND authority_primitive_kind IS NOT NULL
72
+ AND authority_primitive_id IS NOT NULL
73
+ AND length(trim(authority_primitive_id)) > 0
74
+ AND authority_kernel_operation IS NULL
75
+ )
76
+ OR (
77
+ authority_kind = 'kernel'
78
+ AND authority_user_id IS NULL
79
+ AND authority_service_account_id IS NULL
80
+ AND authority_session_id IS NULL
81
+ AND authority_access_token_id IS NULL
82
+ AND authority_primitive_kind IS NULL
83
+ AND authority_primitive_id IS NULL
84
+ AND authority_kernel_operation IS NOT NULL
85
+ )
86
+ OR (
87
+ authority_kind = 'disabled'
88
+ AND authority_user_id IS NULL
89
+ AND authority_service_account_id IS NULL
90
+ AND authority_session_id IS NULL
91
+ AND authority_access_token_id IS NULL
92
+ AND authority_primitive_kind IS NULL
93
+ AND authority_primitive_id IS NULL
94
+ AND authority_kernel_operation IS NULL
95
+ )
96
+ ),
97
+ CHECK (
98
+ (
99
+ executor_kind = 'request'
100
+ AND source_kind = 'http'
101
+ AND executor_id = source_id
102
+ AND (
103
+ (
104
+ authority_kind = 'principal'
105
+ AND requested_by_user_id IS authority_user_id
106
+ AND requested_by_service_account_id IS authority_service_account_id
107
+ )
108
+ OR (
109
+ authority_kind = 'disabled'
110
+ AND requested_by_user_id IS NULL
111
+ AND requested_by_service_account_id IS NULL
112
+ )
113
+ )
114
+ )
115
+ OR (
116
+ executor_kind IN ('action', 'pipeline', 'projection', 'rule', 'sync', 'webhook', 'workflow')
117
+ AND authority_kind = 'trustedPrimitive'
118
+ AND executor_kind = authority_primitive_kind
119
+ )
120
+ OR (
121
+ executor_kind = 'agent'
122
+ AND source_kind = 'execution'
123
+ AND (
124
+ (
125
+ authority_kind = 'principal'
126
+ AND authority_service_account_id IS NOT NULL
127
+ AND authority_session_id IS NULL
128
+ AND authority_access_token_id IS NULL
129
+ )
130
+ OR (
131
+ authority_kind = 'principal'
132
+ AND authority_user_id IS NOT NULL
133
+ AND (authority_session_id IS NOT NULL) + (authority_access_token_id IS NOT NULL) = 1
134
+ )
135
+ OR authority_kind = 'disabled'
136
+ )
137
+ )
138
+ OR (executor_kind = 'kernel' AND authority_kind = 'kernel')
139
+ )
140
+ );
141
+
142
+ INSERT INTO executions_v3 SELECT * FROM executions;
143
+ DROP TABLE executions;
144
+ ALTER TABLE executions_v3 RENAME TO executions;
145
+
146
+ CREATE TABLE agent_runs_v3 (
147
+ project_id TEXT NOT NULL,
148
+ id TEXT NOT NULL,
149
+ execution_id TEXT NOT NULL,
150
+ kind TEXT NOT NULL DEFAULT 'conversation' CHECK (kind IN ('conversation', 'subagent')),
151
+ thread_id TEXT,
152
+ agent_id TEXT,
153
+ trigger_message_id TEXT,
154
+ parent_run_id TEXT,
155
+ spawn_key TEXT,
156
+ spec TEXT CHECK (spec IS NULL OR json_valid(spec)),
157
+ result TEXT CHECK (result IS NULL OR json_valid(result)),
158
+ requester_group_ids TEXT NOT NULL DEFAULT '[]'
159
+ CHECK (json_valid(requester_group_ids) AND json_type(requester_group_ids) = 'array'),
160
+ status TEXT NOT NULL CHECK (
161
+ status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')
162
+ ),
163
+ model_id TEXT,
164
+ finish_reason TEXT,
165
+ error TEXT CHECK (error IS NULL OR json_valid(error)),
166
+ diagnostics TEXT,
167
+ attempt INTEGER NOT NULL DEFAULT 0 CHECK (attempt >= 0),
168
+ execution_token TEXT,
169
+ execution_queue_lease_expires_at TEXT,
170
+ created_at TEXT NOT NULL,
171
+ started_at TEXT,
172
+ completed_at TEXT,
173
+ PRIMARY KEY (project_id, id),
174
+ UNIQUE (project_id, execution_id),
175
+ UNIQUE (project_id, parent_run_id, spawn_key),
176
+ FOREIGN KEY (project_id, execution_id)
177
+ REFERENCES executions (project_id, id)
178
+ ON DELETE RESTRICT,
179
+ FOREIGN KEY (project_id, parent_run_id)
180
+ REFERENCES agent_runs_v3 (project_id, id)
181
+ ON DELETE RESTRICT,
182
+ CHECK ((execution_token IS NULL) = (execution_queue_lease_expires_at IS NULL)),
183
+ CHECK (
184
+ (
185
+ kind = 'conversation'
186
+ AND thread_id IS NOT NULL
187
+ AND agent_id IS NOT NULL
188
+ AND trigger_message_id IS NOT NULL
189
+ AND parent_run_id IS NULL
190
+ AND spawn_key IS NULL
191
+ AND spec IS NULL
192
+ AND result IS NULL
193
+ )
194
+ OR
195
+ (
196
+ kind = 'subagent'
197
+ AND thread_id IS NULL
198
+ AND agent_id IS NULL
199
+ AND trigger_message_id IS NULL
200
+ AND parent_run_id IS NOT NULL
201
+ AND spawn_key IS NOT NULL
202
+ AND spec IS NOT NULL
203
+ )
204
+ ),
205
+ CHECK (kind <> 'subagent' OR status <> 'succeeded' OR result IS NOT NULL)
206
+ );
207
+
208
+ INSERT INTO agent_runs_v3 (
209
+ project_id, id, execution_id, kind, thread_id, agent_id, trigger_message_id,
210
+ requester_group_ids, status, model_id, finish_reason, error, diagnostics, attempt,
211
+ execution_token, execution_queue_lease_expires_at, created_at, started_at, completed_at
212
+ )
213
+ SELECT
214
+ project_id, id, execution_id, 'conversation', thread_id, agent_id, trigger_message_id,
215
+ requester_group_ids, status, model_id, finish_reason, error, diagnostics, attempt,
216
+ execution_token, execution_queue_lease_expires_at, created_at, started_at, completed_at
217
+ FROM agent_runs;
218
+
219
+ DROP TABLE agent_runs;
220
+ ALTER TABLE agent_runs_v3 RENAME TO agent_runs;
221
+
222
+ CREATE INDEX idx_agent_runs_project_started
223
+ ON agent_runs(project_id, COALESCE(started_at, created_at) DESC);
224
+ CREATE INDEX idx_agent_runs_project_thread_started
225
+ ON agent_runs(project_id, thread_id, COALESCE(started_at, created_at) DESC);
226
+ CREATE INDEX idx_agent_runs_project_agent_started
227
+ ON agent_runs(project_id, agent_id, COALESCE(started_at, created_at) DESC);
228
+ CREATE INDEX idx_agent_runs_project_status_started
229
+ ON agent_runs(project_id, status, COALESCE(started_at, created_at) DESC);
230
+ CREATE INDEX idx_agent_runs_project_parent_started
231
+ ON agent_runs(project_id, parent_run_id, status, COALESCE(started_at, created_at) DESC);
@@ -0,0 +1,78 @@
1
+ CREATE TABLE agent_runs_v4 (
2
+ project_id TEXT NOT NULL,
3
+ id TEXT NOT NULL,
4
+ execution_id TEXT NOT NULL,
5
+ kind TEXT NOT NULL DEFAULT 'conversation' CHECK (kind IN ('conversation', 'subagent')),
6
+ thread_id TEXT,
7
+ agent_id TEXT,
8
+ trigger_message_id TEXT,
9
+ parent_run_id TEXT,
10
+ spawn_key TEXT,
11
+ spec TEXT CHECK (spec IS NULL OR json_valid(spec)),
12
+ result TEXT CHECK (result IS NULL OR json_valid(result)),
13
+ requester_group_ids TEXT NOT NULL DEFAULT '[]'
14
+ CHECK (json_valid(requester_group_ids) AND json_type(requester_group_ids) = 'array'),
15
+ status TEXT NOT NULL CHECK (
16
+ status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')
17
+ ),
18
+ model_id TEXT,
19
+ finish_reason TEXT,
20
+ error TEXT CHECK (error IS NULL OR json_valid(error)),
21
+ diagnostics TEXT,
22
+ attempt INTEGER NOT NULL DEFAULT 0 CHECK (attempt >= 0),
23
+ execution_token TEXT,
24
+ execution_queue_lease_expires_at TEXT,
25
+ created_at TEXT NOT NULL,
26
+ started_at TEXT,
27
+ completed_at TEXT,
28
+ PRIMARY KEY (project_id, id),
29
+ UNIQUE (project_id, execution_id),
30
+ UNIQUE (project_id, parent_run_id, spawn_key),
31
+ FOREIGN KEY (project_id, execution_id)
32
+ REFERENCES executions (project_id, id)
33
+ ON DELETE RESTRICT,
34
+ FOREIGN KEY (project_id, parent_run_id)
35
+ -- Use the final name: Bun's legacy ALTER mode preserves references when foreign keys are off.
36
+ REFERENCES agent_runs (project_id, id)
37
+ ON DELETE RESTRICT,
38
+ CHECK ((execution_token IS NULL) = (execution_queue_lease_expires_at IS NULL)),
39
+ CHECK (
40
+ (
41
+ kind = 'conversation'
42
+ AND thread_id IS NOT NULL
43
+ AND agent_id IS NOT NULL
44
+ AND trigger_message_id IS NOT NULL
45
+ AND parent_run_id IS NULL
46
+ AND spawn_key IS NULL
47
+ AND result IS NULL
48
+ )
49
+ OR
50
+ (
51
+ kind = 'subagent'
52
+ AND thread_id IS NULL
53
+ AND agent_id IS NULL
54
+ AND trigger_message_id IS NULL
55
+ AND parent_run_id IS NOT NULL
56
+ AND spawn_key IS NOT NULL
57
+ AND spec IS NOT NULL
58
+ )
59
+ ),
60
+ CHECK (kind <> 'subagent' OR status <> 'succeeded' OR result IS NOT NULL)
61
+ );
62
+
63
+ INSERT INTO agent_runs_v4 SELECT * FROM agent_runs;
64
+ DROP TABLE agent_runs;
65
+ ALTER TABLE agent_runs_v4 RENAME TO agent_runs;
66
+
67
+ CREATE INDEX idx_agent_runs_project_thread_started
68
+ ON agent_runs (project_id, thread_id, COALESCE(started_at, created_at) DESC, id DESC);
69
+ CREATE INDEX idx_agent_runs_project_status_created
70
+ ON agent_runs (project_id, status, created_at, id);
71
+ CREATE INDEX idx_agent_runs_project_parent_started
72
+ ON agent_runs (
73
+ project_id,
74
+ parent_run_id,
75
+ status,
76
+ COALESCE(started_at, created_at) DESC,
77
+ id DESC
78
+ );