@sixb/sqlite 0.1.5 → 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 (55) 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 +1937 -387
  27. package/dist/index.js.map +20 -17
  28. package/dist/migrations.d.ts.map +1 -1
  29. package/dist/ontology-storage/materialization-state.d.ts +7 -3
  30. package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
  31. package/dist/ontology-storage/materializations.d.ts.map +1 -1
  32. package/package.json +3 -3
  33. package/src/agents/rows.ts +36 -9
  34. package/src/agents/runs.ts +152 -13
  35. package/src/agents/threads.ts +2 -17
  36. package/src/ai-cost-groups.ts +100 -0
  37. package/src/ai-cost-storage.ts +67 -25
  38. package/src/ai-limit-storage.ts +981 -0
  39. package/src/ai-usage-storage.ts +24 -1
  40. package/src/auth-storage/access-tokens.ts +77 -68
  41. package/src/auth-storage/auth-storage.ts +80 -1
  42. package/src/auth-storage/device-authorizations.ts +153 -0
  43. package/src/auth-storage/rows.ts +41 -0
  44. package/src/auth-storage/shared.ts +1 -0
  45. package/src/index.ts +6 -0
  46. package/src/migrations/029-model-accounting.sql +79 -0
  47. package/src/migrations/030-ai-usage-limits.sql +100 -0
  48. package/src/migrations/031-subagent-runs.sql +231 -0
  49. package/src/migrations/032-conversation-run-spec.sql +78 -0
  50. package/src/migrations/033-retire-agent-definitions.sql +89 -0
  51. package/src/migrations/034-device-authorizations.sql +22 -0
  52. package/src/migrations.ts +18 -0
  53. package/src/ontology-storage/materialization-state.ts +53 -33
  54. package/src/ontology-storage/materializations.ts +4 -5
  55. package/src/workflow-run-storage.ts +8 -8
@@ -10,6 +10,7 @@ import {
10
10
  parseAiModelCallCostDetails,
11
11
  toAccountingItem,
12
12
  } from "@sixb/core/internal/ai-cost-storage-provider"
13
+ import { normalizeModelProviderIds } from "@sixb/core/models"
13
14
  import type { ReadonlyJsonObject } from "@sixb/core/storage"
14
15
  import {
15
16
  type AiAccountingOverview,
@@ -20,9 +21,13 @@ import {
20
21
  type AiModelCallUsageRecord,
21
22
  type ListAiModelCallAccountingInput,
22
23
  type ListAiModelCallAccountingResult,
24
+ type ListAiModelCallGroupsInput,
25
+ type ListAiModelCallGroupsResult,
23
26
  type QueryAiAccountingOverviewInput,
24
27
  type SummarizeAiCostExecutionsInput,
25
28
  } from "@sixb/core/storage"
29
+ import { listAiModelCallGroups } from "./ai-cost-groups"
30
+ import { requestedReasoningFromRow } from "./ai-usage-storage"
26
31
  import { isUniqueConstraintError } from "./storage-errors"
27
32
  import { runImmediateTransaction, type SqliteStoreConnection } from "./transactions"
28
33
 
@@ -30,6 +35,12 @@ import { runImmediateTransaction, type SqliteStoreConnection } from "./transacti
30
35
  export class SqliteAiCostStorage implements AiCostStorage {
31
36
  constructor(private readonly connection: SqliteStoreConnection) {}
32
37
 
38
+ async listModelCallGroups(
39
+ input: ListAiModelCallGroupsInput
40
+ ): Promise<ListAiModelCallGroupsResult> {
41
+ return listAiModelCallGroups(this.connection, input)
42
+ }
43
+
33
44
  async recordModelCallCost(input: AiModelCallCostRecord): Promise<void> {
34
45
  const record = normalizeAiModelCallCostRecord(input)
35
46
  runImmediateTransaction(this.connection.db, () => {
@@ -176,13 +187,15 @@ const SQLITE_ACCOUNTING_LIST_COUNT_SQL = `
176
187
  const SQLITE_ACCOUNTING_LIST_PAGE_SQL = `
177
188
  SELECT usage.*,
178
189
  CASE
179
- WHEN direct_agent.id IS NOT NULL THEN 'agent'
190
+ WHEN direct_agent.kind = 'conversation' THEN 'agent'
191
+ WHEN direct_agent.kind = 'subagent' THEN 'subagent'
180
192
  WHEN workflow_agent.node_run_id IS NOT NULL THEN 'workflowAgent'
181
193
  ELSE NULL
182
194
  END AS attribution_kind,
183
- COALESCE(direct_agent.agent_id, workflow_agent.agent_id) AS attribution_agent_id,
195
+ workflow_node.node_id AS attribution_agent_step_id,
184
196
  direct_agent.id AS attribution_agent_run_id,
185
197
  direct_agent.thread_id AS attribution_thread_id,
198
+ direct_agent.parent_run_id AS attribution_parent_run_id,
186
199
  workflow_agent.node_run_id AS attribution_node_run_id,
187
200
  workflow_node.workflow_id AS attribution_workflow_id,
188
201
  workflow_node.workflow_run_id AS attribution_workflow_run_id,
@@ -231,7 +244,12 @@ const SQLITE_ACCOUNTING_OVERVIEW_SQL = `
231
244
  usage.text_output_tokens,
232
245
  usage.reasoning_output_tokens,
233
246
  usage.reporting_status,
234
- COALESCE(direct_agent.agent_id, workflow_agent.agent_id) AS attribution_agent_id,
247
+ CASE
248
+ WHEN direct_agent.kind = 'conversation' THEN 'agent'
249
+ WHEN workflow_agent.node_run_id IS NOT NULL THEN 'workflowAgent'
250
+ ELSE NULL
251
+ END AS attribution_agent_kind,
252
+ workflow_node.node_id AS attribution_agent_step_id,
235
253
  workflow_node.workflow_id AS attribution_workflow_id,
236
254
  CASE
237
255
  WHEN cost.status = 'rated' THEN 'rated'
@@ -256,11 +274,11 @@ const SQLITE_ACCOUNTING_OVERVIEW_SQL = `
256
274
  AND (? IS NULL OR usage.provider_id = ?)
257
275
  AND (? IS NULL OR usage.requested_model_id = ?)
258
276
  ), expanded AS (
259
- SELECT 'totals' AS dimension, NULL AS key_1, NULL AS key_2, NULL AS bucket_start,
277
+ SELECT 'totals' AS dimension, NULL AS key_1, NULL AS key_2, NULL AS key_3, NULL AS bucket_start,
260
278
  classified.*
261
279
  FROM classified
262
280
  UNION ALL
263
- SELECT 'series', NULL, NULL,
281
+ SELECT 'series', NULL, NULL, NULL,
264
282
  CASE ?
265
283
  WHEN 'hour' THEN strftime('%Y-%m-%dT%H:00:00.000Z', occurred_at)
266
284
  WHEN 'day' THEN strftime('%Y-%m-%dT00:00:00.000Z', occurred_at)
@@ -273,17 +291,18 @@ const SQLITE_ACCOUNTING_OVERVIEW_SQL = `
273
291
  classified.*
274
292
  FROM classified
275
293
  UNION ALL
276
- SELECT 'model', provider_id, requested_model_id, NULL, classified.* FROM classified
294
+ SELECT 'model', provider_id, requested_model_id, NULL, NULL, classified.* FROM classified
277
295
  UNION ALL
278
- SELECT 'agent', attribution_agent_id, NULL, NULL, classified.*
279
- FROM classified WHERE attribution_agent_id IS NOT NULL
296
+ SELECT 'agent', attribution_agent_kind, attribution_workflow_id, attribution_agent_step_id, NULL, classified.*
297
+ FROM classified WHERE attribution_agent_kind IS NOT NULL
280
298
  UNION ALL
281
- SELECT 'workflow', attribution_workflow_id, NULL, NULL, classified.*
299
+ SELECT 'workflow', attribution_workflow_id, NULL, NULL, NULL, classified.*
282
300
  FROM classified WHERE attribution_workflow_id IS NOT NULL
283
301
  )
284
302
  SELECT dimension,
285
303
  key_1,
286
304
  key_2,
305
+ key_3,
287
306
  bucket_start,
288
307
  amount_currency,
289
308
  CAST(COUNT(*) AS TEXT) AS model_call_count,
@@ -313,7 +332,7 @@ const SQLITE_ACCOUNTING_OVERVIEW_SQL = `
313
332
  CAST(SUM((amount_nanos / 1000000) % 1000000) AS TEXT) AS amount_middle,
314
333
  CAST(SUM(amount_nanos % 1000000) AS TEXT) AS amount_low
315
334
  FROM expanded
316
- GROUP BY dimension, key_1, key_2, bucket_start, amount_currency
335
+ GROUP BY dimension, key_1, key_2, key_3, bucket_start, amount_currency
317
336
  `
318
337
 
319
338
  function accountingListFilterParameters(
@@ -355,6 +374,7 @@ interface UsageRow {
355
374
  readonly call_id: string
356
375
  readonly provider_id: string
357
376
  readonly requested_model_id: string
377
+ readonly requested_reasoning: string | null
358
378
  readonly response_model_id: string | null
359
379
  readonly response_id: string
360
380
  readonly input_tokens: number | null
@@ -367,15 +387,17 @@ interface UsageRow {
367
387
  readonly reasoning_output_tokens: number | null
368
388
  readonly reporting_status: AiModelCallUsageRecord["usage"]["reportingStatus"]
369
389
  readonly raw_usage: string | null
390
+ readonly provider_ids: string | null
370
391
  readonly occurred_at: string
371
392
  readonly recorded_at: string
372
393
  }
373
394
 
374
395
  interface JoinedRow extends UsageRow {
375
- readonly attribution_kind: "agent" | "workflowAgent" | null
376
- readonly attribution_agent_id: string | null
396
+ readonly attribution_kind: "agent" | "subagent" | "workflowAgent" | null
397
+ readonly attribution_agent_step_id: string | null
377
398
  readonly attribution_agent_run_id: string | null
378
399
  readonly attribution_thread_id: string | null
400
+ readonly attribution_parent_run_id: string | null
379
401
  readonly attribution_node_run_id: string | null
380
402
  readonly attribution_workflow_id: string | null
381
403
  readonly attribution_workflow_run_id: string | null
@@ -394,6 +416,7 @@ interface AggregateRow {
394
416
  readonly dimension: AiAccountingAggregateFragment["dimension"]
395
417
  readonly key_1: string | null
396
418
  readonly key_2: string | null
419
+ readonly key_3: string | null
397
420
  readonly bucket_start: string | null
398
421
  readonly amount_currency: string | null
399
422
  readonly model_call_count: string
@@ -436,7 +459,12 @@ function aggregateFragmentFromRow(row: AggregateRow): AiAccountingAggregateFragm
436
459
  row.dimension === "model"
437
460
  ? { providerId: required(row.key_1), modelId: required(row.key_2) }
438
461
  : row.dimension === "agent"
439
- ? { agentId: required(row.key_1) }
462
+ ? {
463
+ agentKind: required(row.key_1) as "agent" | "workflowAgent",
464
+ ...(row.key_1 === "workflowAgent"
465
+ ? { workflowId: required(row.key_2), agentStepId: required(row.key_3) }
466
+ : {}),
467
+ }
440
468
  : row.dimension === "workflow"
441
469
  ? { workflowId: required(row.key_1) }
442
470
  : row.dimension === "series"
@@ -510,17 +538,22 @@ function accountingItemFromRow(row: JoinedRow): AiAccountingRecordSetItem {
510
538
  : row.attribution_kind === "agent"
511
539
  ? {
512
540
  kind: "agent" as const,
513
- agentId: required(row.attribution_agent_id),
514
541
  agentRunId: required(row.attribution_agent_run_id),
515
542
  threadId: required(row.attribution_thread_id),
516
543
  }
517
- : {
518
- kind: "workflowAgent" as const,
519
- agentId: required(row.attribution_agent_id),
520
- nodeRunId: required(row.attribution_node_run_id),
521
- workflowId: required(row.attribution_workflow_id),
522
- workflowRunId: required(row.attribution_workflow_run_id),
523
- }
544
+ : row.attribution_kind === "subagent"
545
+ ? {
546
+ kind: "subagent" as const,
547
+ subagentRunId: required(row.attribution_agent_run_id),
548
+ parentRunId: required(row.attribution_parent_run_id),
549
+ }
550
+ : {
551
+ kind: "workflowAgent" as const,
552
+ agentStepId: required(row.attribution_agent_step_id),
553
+ nodeRunId: required(row.attribution_node_run_id),
554
+ workflowId: required(row.attribution_workflow_id),
555
+ workflowRunId: required(row.attribution_workflow_run_id),
556
+ }
524
557
  return {
525
558
  usage,
526
559
  ...(attribution ? { attribution } : {}),
@@ -537,7 +570,13 @@ function usageFromRow(row: UsageRow, requesterGroupIds: readonly string[]): AiMo
537
570
  callId: row.call_id,
538
571
  requesterGroupIds,
539
572
  providerId: row.provider_id,
573
+ ...(row.provider_ids === null
574
+ ? {}
575
+ : { providerIds: normalizeModelProviderIds(JSON.parse(row.provider_ids)) }),
540
576
  requestedModelId: row.requested_model_id,
577
+ ...(row.requested_reasoning === null
578
+ ? {}
579
+ : { requestedReasoning: requestedReasoningFromRow(row.requested_reasoning) }),
541
580
  ...(row.response_model_id === null ? {} : { responseModelId: row.response_model_id }),
542
581
  responseId: row.response_id,
543
582
  usage: {
@@ -610,14 +649,15 @@ function costRecord(input: {
610
649
  ratedAt: string
611
650
  }): AiModelCallCostRecord {
612
651
  const details = parseAiModelCallCostDetails(input.details)
652
+ const priceSource =
653
+ details.priceSource === undefined
654
+ ? undefined
655
+ : { ...details.priceSource, observedAt: new Date(details.priceSource.observedAt) }
613
656
  const base = {
657
+ ...(details.estimate === undefined ? {} : { estimate: details.estimate }),
614
658
  projectId: input.projectId,
615
659
  usageRecordId: input.usageId,
616
660
  pricingContext: details.pricingContext,
617
- priceSource: {
618
- ...details.priceSource,
619
- observedAt: new Date(details.priceSource.observedAt),
620
- },
621
661
  ratedAt: new Date(input.ratedAt),
622
662
  }
623
663
  if (input.status === "rated") {
@@ -625,6 +665,7 @@ function costRecord(input: {
625
665
  ...base,
626
666
  status: "rated",
627
667
  billingIdentity: { providerId: required(input.providerId), modelId: required(input.modelId) },
668
+ priceSource: required(priceSource),
628
669
  money: { currency: required(input.currency), amountNanos: required(input.amountNanos) },
629
670
  components: required(details.components),
630
671
  })
@@ -635,6 +676,7 @@ function costRecord(input: {
635
676
  ...(input.providerId && input.modelId
636
677
  ? { billingIdentity: { providerId: input.providerId, modelId: input.modelId } }
637
678
  : {}),
679
+ ...(priceSource === undefined ? {} : { priceSource }),
638
680
  reason: required(input.reason) as Extract<
639
681
  AiModelCallCostRecord,
640
682
  { status: "unpriceable" }