@sixb/sqlite 0.1.6 → 0.1.7

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 (50) 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/index.d.ts +2 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1898 -356
  27. package/dist/index.js.map +18 -15
  28. package/dist/migrations.d.ts.map +1 -1
  29. package/package.json +3 -3
  30. package/src/agents/rows.ts +36 -9
  31. package/src/agents/runs.ts +152 -13
  32. package/src/agents/threads.ts +2 -17
  33. package/src/ai-cost-groups.ts +100 -0
  34. package/src/ai-cost-storage.ts +67 -25
  35. package/src/ai-limit-storage.ts +981 -0
  36. package/src/ai-usage-storage.ts +24 -1
  37. package/src/auth-storage/access-tokens.ts +77 -68
  38. package/src/auth-storage/auth-storage.ts +80 -1
  39. package/src/auth-storage/device-authorizations.ts +153 -0
  40. package/src/auth-storage/rows.ts +41 -0
  41. package/src/auth-storage/shared.ts +1 -0
  42. package/src/index.ts +6 -0
  43. package/src/migrations/029-model-accounting.sql +79 -0
  44. package/src/migrations/030-ai-usage-limits.sql +100 -0
  45. package/src/migrations/031-subagent-runs.sql +231 -0
  46. package/src/migrations/032-conversation-run-spec.sql +78 -0
  47. package/src/migrations/033-retire-agent-definitions.sql +89 -0
  48. package/src/migrations/034-device-authorizations.sql +22 -0
  49. package/src/migrations.ts +18 -0
  50. package/src/workflow-run-storage.ts +8 -8
@@ -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
+ );
@@ -0,0 +1,89 @@
1
+ DROP INDEX idx_agent_threads_project_agent_activity;
2
+ ALTER TABLE workflow_agent_node_runs RENAME COLUMN agent_id TO actor_id;
3
+ ALTER TABLE agent_threads DROP COLUMN agent_id;
4
+
5
+ CREATE TABLE agent_runs_v5 (
6
+ project_id TEXT NOT NULL,
7
+ id TEXT NOT NULL,
8
+ execution_id TEXT NOT NULL,
9
+ kind TEXT NOT NULL DEFAULT 'conversation' CHECK (kind IN ('conversation', 'subagent')),
10
+ thread_id TEXT,
11
+ trigger_message_id TEXT,
12
+ parent_run_id TEXT,
13
+ spawn_key TEXT,
14
+ spec TEXT CHECK (spec IS NULL OR json_valid(spec)),
15
+ result TEXT CHECK (result IS NULL OR json_valid(result)),
16
+ requester_group_ids TEXT NOT NULL DEFAULT '[]'
17
+ CHECK (json_valid(requester_group_ids) AND json_type(requester_group_ids) = 'array'),
18
+ status TEXT NOT NULL CHECK (
19
+ status IN ('queued', 'running', 'succeeded', 'failed', 'cancelled')
20
+ ),
21
+ model_id TEXT,
22
+ finish_reason TEXT,
23
+ error TEXT CHECK (error IS NULL OR json_valid(error)),
24
+ diagnostics TEXT,
25
+ attempt INTEGER NOT NULL DEFAULT 0 CHECK (attempt >= 0),
26
+ execution_token TEXT,
27
+ execution_queue_lease_expires_at TEXT,
28
+ created_at TEXT NOT NULL,
29
+ started_at TEXT,
30
+ completed_at TEXT,
31
+ PRIMARY KEY (project_id, id),
32
+ UNIQUE (project_id, execution_id),
33
+ UNIQUE (project_id, parent_run_id, spawn_key),
34
+ FOREIGN KEY (project_id, execution_id)
35
+ REFERENCES executions (project_id, id)
36
+ ON DELETE RESTRICT,
37
+ FOREIGN KEY (project_id, parent_run_id)
38
+ -- Use the final name: Bun's legacy ALTER mode preserves references when foreign keys are off.
39
+ REFERENCES agent_runs (project_id, id)
40
+ ON DELETE RESTRICT,
41
+ CHECK ((execution_token IS NULL) = (execution_queue_lease_expires_at IS NULL)),
42
+ CHECK (
43
+ (
44
+ kind = 'conversation'
45
+ AND thread_id IS NOT NULL
46
+ AND trigger_message_id IS NOT NULL
47
+ AND parent_run_id IS NULL
48
+ AND spawn_key IS NULL
49
+ AND result IS NULL
50
+ )
51
+ OR
52
+ (
53
+ kind = 'subagent'
54
+ AND thread_id IS NULL
55
+ AND trigger_message_id IS NULL
56
+ AND parent_run_id IS NOT NULL
57
+ AND spawn_key IS NOT NULL
58
+ AND spec IS NOT NULL
59
+ )
60
+ ),
61
+ CHECK (kind <> 'subagent' OR status <> 'succeeded' OR result IS NOT NULL)
62
+ );
63
+
64
+ INSERT INTO agent_runs_v5 (
65
+ project_id, id, execution_id, kind, thread_id, trigger_message_id, parent_run_id, spawn_key,
66
+ spec, result, requester_group_ids, status, model_id, finish_reason, error, diagnostics, attempt,
67
+ execution_token, execution_queue_lease_expires_at, created_at, started_at, completed_at
68
+ )
69
+ SELECT
70
+ project_id, id, execution_id, kind, thread_id, trigger_message_id, parent_run_id, spawn_key,
71
+ spec, result, requester_group_ids, status, model_id, finish_reason, error, diagnostics, attempt,
72
+ execution_token, execution_queue_lease_expires_at, created_at, started_at, completed_at
73
+ FROM agent_runs;
74
+
75
+ DROP TABLE agent_runs;
76
+ ALTER TABLE agent_runs_v5 RENAME TO agent_runs;
77
+
78
+ CREATE INDEX idx_agent_runs_project_thread_started
79
+ ON agent_runs (project_id, thread_id, COALESCE(started_at, created_at) DESC, id DESC);
80
+ CREATE INDEX idx_agent_runs_project_status_created
81
+ ON agent_runs (project_id, status, created_at, id);
82
+ CREATE INDEX idx_agent_runs_project_parent_started
83
+ ON agent_runs (
84
+ project_id,
85
+ parent_run_id,
86
+ status,
87
+ COALESCE(started_at, created_at) DESC,
88
+ id DESC
89
+ );
@@ -0,0 +1,22 @@
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 TEXT 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 TEXT NOT NULL,
13
+ expires_at TEXT NOT NULL,
14
+ approved_at TEXT,
15
+ denied_at TEXT,
16
+ consumed_at TEXT,
17
+ PRIMARY KEY (project_id, id),
18
+ UNIQUE (project_id, user_code)
19
+ );
20
+
21
+ CREATE INDEX idx_auth_device_authorizations_pending
22
+ ON auth_device_authorizations(project_id, status, expires_at);
package/src/migrations.ts CHANGED
@@ -76,6 +76,18 @@ import agentContextCheckpointsSql from "./migrations/027-agent-context-checkpoin
76
76
  import objectOverrideEditTimesSql from "./migrations/028-object-override-edit-times.sql" with {
77
77
  type: "text",
78
78
  }
79
+ import modelAccountingSql from "./migrations/029-model-accounting.sql" with { type: "text" }
80
+ import aiUsageLimitsSql from "./migrations/030-ai-usage-limits.sql" with { type: "text" }
81
+ import subagentRunsSql from "./migrations/031-subagent-runs.sql" with { type: "text" }
82
+ import conversationRunSpecSql from "./migrations/032-conversation-run-spec.sql" with {
83
+ type: "text",
84
+ }
85
+ import retireAgentDefinitionsSql from "./migrations/033-retire-agent-definitions.sql" with {
86
+ type: "text",
87
+ }
88
+ import deviceAuthorizationsSql from "./migrations/034-device-authorizations.sql" with {
89
+ type: "text",
90
+ }
79
91
 
80
92
  const MIGRATIONS_TABLE_SQL = `
81
93
  CREATE TABLE IF NOT EXISTS sixb_migrations (
@@ -159,6 +171,12 @@ export const sqliteStorageMigrations = defineMigrations({
159
171
  sqliteSql("026-ai-cost-accounting", aiCostAccountingSql),
160
172
  sqliteSql("027-agent-context-checkpoints", agentContextCheckpointsSql),
161
173
  sqliteSql("028-object-override-edit-times", objectOverrideEditTimesSql),
174
+ sqliteSql("029-model-accounting", modelAccountingSql),
175
+ sqliteSql("030-ai-usage-limits", aiUsageLimitsSql),
176
+ sqliteSql("031-subagent-runs", subagentRunsSql),
177
+ sqliteSql("032-conversation-run-spec", conversationRunSpecSql),
178
+ sqliteSql("033-retire-agent-definitions", retireAgentDefinitionsSql),
179
+ sqliteSql("034-device-authorizations", deviceAuthorizationsSql),
162
180
  ],
163
181
  })
164
182
 
@@ -491,7 +491,7 @@ export class SqliteWorkflowAgentNodeRunStorage implements WorkflowAgentNodeRunSt
491
491
  projectId: input.projectId,
492
492
  executionId: input.executionId,
493
493
  nodeRunId: input.nodeRunId,
494
- agentId: input.agentId,
494
+ actorId: input.actorId,
495
495
  workflowExecutionId: parent.execution_id,
496
496
  })
497
497
 
@@ -499,14 +499,14 @@ export class SqliteWorkflowAgentNodeRunStorage implements WorkflowAgentNodeRunSt
499
499
  this.db
500
500
  .query(`
501
501
  INSERT INTO workflow_agent_node_runs (
502
- project_id, node_run_id, execution_id, agent_id, status, prompt, attempt, created_at
502
+ project_id, node_run_id, execution_id, actor_id, status, prompt, attempt, created_at
503
503
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
504
504
  `)
505
505
  .run(
506
506
  input.projectId,
507
507
  input.nodeRunId,
508
508
  input.executionId,
509
- input.agentId,
509
+ input.actorId,
510
510
  "queued",
511
511
  input.prompt,
512
512
  0,
@@ -659,9 +659,9 @@ export class SqliteWorkflowAgentNodeRunStorage implements WorkflowAgentNodeRunSt
659
659
  if (hasEmptyStatuses(input)) return { runs: [], total: 0, hasMore: false }
660
660
  const whereClauses = ["project_id = ?"]
661
661
  const args: SqliteValue[] = [input.projectId]
662
- if (input.agentId) {
663
- whereClauses.push("agent_id = ?")
664
- args.push(input.agentId)
662
+ if (input.actorId) {
663
+ whereClauses.push("actor_id = ?")
664
+ args.push(input.actorId)
665
665
  }
666
666
  appendRunListFilters(whereClauses, args, input)
667
667
  const result = queryRunList<WorkflowAgentNodeRunDatabaseRow>({
@@ -1073,7 +1073,7 @@ interface WorkflowAgentNodeRunDatabaseRow {
1073
1073
  project_id: string
1074
1074
  node_run_id: string
1075
1075
  execution_id: string
1076
- agent_id: string
1076
+ actor_id: string
1077
1077
  status: WorkflowAgentNodeRunRecord["status"]
1078
1078
  prompt: string
1079
1079
  model_id: string | null
@@ -1107,7 +1107,7 @@ function rowToWorkflowAgentNodeRunRecord(
1107
1107
  projectId: row.project_id,
1108
1108
  nodeRunId: row.node_run_id,
1109
1109
  executionId: row.execution_id,
1110
- agentId: row.agent_id,
1110
+ actorId: row.actor_id,
1111
1111
  status: row.status,
1112
1112
  prompt: row.prompt,
1113
1113
  ...(row.model_id ? { modelId: row.model_id } : {}),