@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.
Files changed (88) hide show
  1. package/dist/agents/rows.d.ts +8 -5
  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/auth-storage/auth-storage.d.ts +4 -1
  9. package/dist/auth-storage/auth-storage.d.ts.map +1 -1
  10. package/dist/auth-storage/device-authorizations.d.ts +29 -0
  11. package/dist/auth-storage/device-authorizations.d.ts.map +1 -0
  12. package/dist/auth-storage/rows.d.ts +19 -1
  13. package/dist/auth-storage/rows.d.ts.map +1 -1
  14. package/dist/auth-storage/shared.d.ts +1 -1
  15. package/dist/auth-storage/shared.d.ts.map +1 -1
  16. package/dist/index.d.ts +6 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +8327 -5838
  19. package/dist/index.js.map +28 -19
  20. package/dist/migrations.d.ts.map +1 -1
  21. package/dist/objects/index.d.ts +2 -0
  22. package/dist/objects/index.d.ts.map +1 -0
  23. package/dist/{pg-object-query-compiler.d.ts → objects/query-compiler.d.ts} +25 -4
  24. package/dist/objects/query-compiler.d.ts.map +1 -0
  25. package/dist/objects/read-scope.d.ts +17 -0
  26. package/dist/objects/read-scope.d.ts.map +1 -0
  27. package/dist/objects/reader.d.ts +50 -0
  28. package/dist/objects/reader.d.ts.map +1 -0
  29. package/dist/objects/rows.d.ts +47 -0
  30. package/dist/objects/rows.d.ts.map +1 -0
  31. package/dist/objects/selected-reader.d.ts +8 -0
  32. package/dist/objects/selected-reader.d.ts.map +1 -0
  33. package/dist/{pg-object-storage.d.ts → objects/storage.d.ts} +12 -20
  34. package/dist/objects/storage.d.ts.map +1 -0
  35. package/dist/pg-ai-cost-storage.d.ts +2 -1
  36. package/dist/pg-ai-cost-storage.d.ts.map +1 -1
  37. package/dist/pg-ai-limit-storage.d.ts +34 -0
  38. package/dist/pg-ai-limit-storage.d.ts.map +1 -0
  39. package/dist/pg-ai-usage-storage.d.ts +28 -0
  40. package/dist/pg-ai-usage-storage.d.ts.map +1 -1
  41. package/dist/pg-execution-storage.d.ts +3 -2
  42. package/dist/pg-execution-storage.d.ts.map +1 -1
  43. package/dist/share-grant-storage.d.ts +11 -0
  44. package/dist/share-grant-storage.d.ts.map +1 -0
  45. package/dist/share-session-storage.d.ts +11 -0
  46. package/dist/share-session-storage.d.ts.map +1 -0
  47. package/dist/storage-errors.d.ts +2 -0
  48. package/dist/storage-errors.d.ts.map +1 -1
  49. package/dist/transactions.d.ts +9 -2
  50. package/dist/transactions.d.ts.map +1 -1
  51. package/package.json +4 -4
  52. package/src/agents/rows.ts +38 -9
  53. package/src/agents/runs.ts +148 -11
  54. package/src/agents/threads.ts +1 -17
  55. package/src/ai-cost-groups.ts +102 -0
  56. package/src/auth-storage/auth-storage.ts +84 -0
  57. package/src/auth-storage/device-authorizations.ts +131 -0
  58. package/src/auth-storage/rows.ts +41 -0
  59. package/src/auth-storage/shared.ts +1 -0
  60. package/src/index.ts +24 -4
  61. package/src/migrations/029-model-accounting.sql +24 -0
  62. package/src/migrations/030-ai-usage-limits.sql +94 -0
  63. package/src/migrations/031-subagent-runs.sql +97 -0
  64. package/src/migrations/032-conversation-run-spec.sql +23 -0
  65. package/src/migrations/033-retire-agent-definitions.sql +28 -0
  66. package/src/migrations/034-device-authorizations.sql +24 -0
  67. package/src/migrations/035-share-grants.sql +57 -0
  68. package/src/migrations/036-share-sessions.sql +173 -0
  69. package/src/migrations.ts +22 -0
  70. package/src/objects/index.ts +1 -0
  71. package/src/{pg-object-query-compiler.ts → objects/query-compiler.ts} +185 -100
  72. package/src/objects/read-scope.ts +324 -0
  73. package/src/objects/reader.ts +604 -0
  74. package/src/objects/rows.ts +146 -0
  75. package/src/objects/selected-reader.ts +118 -0
  76. package/src/objects/storage.ts +305 -0
  77. package/src/pg-ai-cost-storage.ts +71 -24
  78. package/src/pg-ai-limit-storage.ts +901 -0
  79. package/src/pg-ai-usage-storage.ts +34 -0
  80. package/src/pg-execution-storage.ts +21 -2
  81. package/src/pg-workflow-run-storage.ts +8 -8
  82. package/src/share-grant-storage.ts +236 -0
  83. package/src/share-session-storage.ts +127 -0
  84. package/src/storage-errors.ts +6 -0
  85. package/src/transactions.ts +46 -5
  86. package/dist/pg-object-query-compiler.d.ts.map +0 -1
  87. package/dist/pg-object-storage.d.ts.map +0 -1
  88. package/src/pg-object-storage.ts +0 -734
@@ -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 "./pg-ai-usage-storage"
26
31
  import type { PgStoreClient } from "./transactions"
27
32
  import { runPgTransaction } from "./transactions"
28
33
 
@@ -30,6 +35,12 @@ import { runPgTransaction } from "./transactions"
30
35
  export class PgAiCostStorage implements AiCostStorage {
31
36
  constructor(private readonly sql: PgStoreClient) {}
32
37
 
38
+ async listModelCallGroups(
39
+ input: ListAiModelCallGroupsInput
40
+ ): Promise<ListAiModelCallGroupsResult> {
41
+ return listAiModelCallGroups(this.sql, input)
42
+ }
43
+
33
44
  async recordModelCallCost(input: AiModelCallCostRecord): Promise<void> {
34
45
  const record = normalizeAiModelCallCostRecord(input)
35
46
  await runPgTransaction(this.sql, async (tx) => {
@@ -100,7 +111,12 @@ export class PgAiCostStorage implements AiCostStorage {
100
111
  usage.text_output_tokens,
101
112
  usage.reasoning_output_tokens,
102
113
  usage.reporting_status,
103
- COALESCE(direct_agent.agent_id, workflow_agent.agent_id) AS attribution_agent_id,
114
+ CASE
115
+ WHEN direct_agent.kind = 'conversation' THEN 'agent'
116
+ WHEN workflow_agent.node_run_id IS NOT NULL THEN 'workflowAgent'
117
+ ELSE NULL
118
+ END AS attribution_agent_kind,
119
+ workflow_node.node_id AS attribution_agent_step_id,
104
120
  workflow_node.workflow_id AS attribution_workflow_id,
105
121
  cost.status AS cost_status,
106
122
  cost.currency AS cost_currency,
@@ -135,11 +151,12 @@ export class PgAiCostStorage implements AiCostStorage {
135
151
  SELECT 'totals'::text AS dimension,
136
152
  NULL::text AS key_1,
137
153
  NULL::text AS key_2,
154
+ NULL::text AS key_3,
138
155
  NULL::timestamptz AS bucket_start,
139
156
  classified.*
140
157
  FROM classified
141
158
  UNION ALL
142
- SELECT 'series', NULL, NULL,
159
+ SELECT 'series', NULL, NULL, NULL,
143
160
  CASE ${input.bucket}::text
144
161
  WHEN 'hour' THEN
145
162
  date_trunc('hour', occurred_at AT TIME ZONE 'UTC') AT TIME ZONE 'UTC'
@@ -150,17 +167,18 @@ export class PgAiCostStorage implements AiCostStorage {
150
167
  classified.*
151
168
  FROM classified
152
169
  UNION ALL
153
- SELECT 'model', provider_id, requested_model_id, NULL, classified.* FROM classified
170
+ SELECT 'model', provider_id, requested_model_id, NULL, NULL, classified.* FROM classified
154
171
  UNION ALL
155
- SELECT 'agent', attribution_agent_id, NULL, NULL, classified.*
156
- FROM classified WHERE attribution_agent_id IS NOT NULL
172
+ SELECT 'agent', attribution_agent_kind, attribution_workflow_id, attribution_agent_step_id, NULL, classified.*
173
+ FROM classified WHERE attribution_agent_kind IS NOT NULL
157
174
  UNION ALL
158
- SELECT 'workflow', attribution_workflow_id, NULL, NULL, classified.*
175
+ SELECT 'workflow', attribution_workflow_id, NULL, NULL, NULL, classified.*
159
176
  FROM classified WHERE attribution_workflow_id IS NOT NULL
160
177
  )
161
178
  SELECT dimension,
162
179
  key_1,
163
180
  key_2,
181
+ key_3,
164
182
  bucket_start,
165
183
  amount_currency,
166
184
  COUNT(*)::text AS model_call_count,
@@ -187,7 +205,7 @@ export class PgAiCostStorage implements AiCostStorage {
187
205
  AS unvalued_call_count,
188
206
  SUM(amount_nanos)::text AS amount_nanos
189
207
  FROM expanded
190
- GROUP BY dimension, key_1, key_2, bucket_start, amount_currency
208
+ GROUP BY dimension, key_1, key_2, key_3, bucket_start, amount_currency
191
209
  `
192
210
  return buildAiAccountingOverviewFromFragments(input, rows.map(aggregateFragmentFromRow))
193
211
  }
@@ -221,13 +239,15 @@ export class PgAiCostStorage implements AiCostStorage {
221
239
  const rows = await this.sql<JoinedRow[]>`
222
240
  SELECT usage.*,
223
241
  CASE
224
- WHEN direct_agent.id IS NOT NULL THEN 'agent'
242
+ WHEN direct_agent.kind = 'conversation' THEN 'agent'
243
+ WHEN direct_agent.kind = 'subagent' THEN 'subagent'
225
244
  WHEN workflow_agent.node_run_id IS NOT NULL THEN 'workflowAgent'
226
245
  ELSE NULL
227
246
  END AS attribution_kind,
228
- COALESCE(direct_agent.agent_id, workflow_agent.agent_id) AS attribution_agent_id,
247
+ workflow_node.node_id AS attribution_agent_step_id,
229
248
  direct_agent.id AS attribution_agent_run_id,
230
249
  direct_agent.thread_id AS attribution_thread_id,
250
+ direct_agent.parent_run_id AS attribution_parent_run_id,
231
251
  workflow_agent.node_run_id AS attribution_node_run_id,
232
252
  workflow_node.workflow_id AS attribution_workflow_id,
233
253
  workflow_node.workflow_run_id AS attribution_workflow_run_id,
@@ -303,6 +323,7 @@ interface UsageRow {
303
323
  readonly call_id: string
304
324
  readonly provider_id: string
305
325
  readonly requested_model_id: string
326
+ readonly requested_reasoning: string | Record<string, unknown> | null
306
327
  readonly response_model_id: string | null
307
328
  readonly response_id: string
308
329
  readonly input_tokens: number | string | null
@@ -315,15 +336,17 @@ interface UsageRow {
315
336
  readonly reasoning_output_tokens: number | string | null
316
337
  readonly reporting_status: AiModelCallUsageRecord["usage"]["reportingStatus"]
317
338
  readonly raw_usage: ReadonlyJsonObject | string | null
339
+ readonly provider_ids: Record<string, unknown> | string | null
318
340
  readonly occurred_at: Date | string
319
341
  readonly recorded_at: Date | string
320
342
  }
321
343
 
322
344
  interface JoinedRow extends UsageRow {
323
- readonly attribution_kind: "agent" | "workflowAgent" | null
324
- readonly attribution_agent_id: string | null
345
+ readonly attribution_kind: "agent" | "subagent" | "workflowAgent" | null
346
+ readonly attribution_agent_step_id: string | null
325
347
  readonly attribution_agent_run_id: string | null
326
348
  readonly attribution_thread_id: string | null
349
+ readonly attribution_parent_run_id: string | null
327
350
  readonly attribution_node_run_id: string | null
328
351
  readonly attribution_workflow_id: string | null
329
352
  readonly attribution_workflow_run_id: string | null
@@ -342,6 +365,7 @@ interface AggregateRow {
342
365
  readonly dimension: AiAccountingAggregateFragment["dimension"]
343
366
  readonly key_1: string | null
344
367
  readonly key_2: string | null
368
+ readonly key_3: string | null
345
369
  readonly bucket_start: Date | string | null
346
370
  readonly amount_currency: string | null
347
371
  readonly model_call_count: string
@@ -405,7 +429,12 @@ function aggregateFragmentFromRow(row: AggregateRow): AiAccountingAggregateFragm
405
429
  row.dimension === "model"
406
430
  ? { providerId: required(row.key_1), modelId: required(row.key_2) }
407
431
  : row.dimension === "agent"
408
- ? { agentId: required(row.key_1) }
432
+ ? {
433
+ agentKind: required(row.key_1) as "agent" | "workflowAgent",
434
+ ...(row.key_1 === "workflowAgent"
435
+ ? { workflowId: required(row.key_2), agentStepId: required(row.key_3) }
436
+ : {}),
437
+ }
409
438
  : row.dimension === "workflow"
410
439
  ? { workflowId: required(row.key_1) }
411
440
  : row.dimension === "series"
@@ -466,17 +495,22 @@ function accountingItemFromRow(row: JoinedRow): AiAccountingRecordSetItem {
466
495
  : row.attribution_kind === "agent"
467
496
  ? {
468
497
  kind: "agent" as const,
469
- agentId: required(row.attribution_agent_id),
470
498
  agentRunId: required(row.attribution_agent_run_id),
471
499
  threadId: required(row.attribution_thread_id),
472
500
  }
473
- : {
474
- kind: "workflowAgent" as const,
475
- agentId: required(row.attribution_agent_id),
476
- nodeRunId: required(row.attribution_node_run_id),
477
- workflowId: required(row.attribution_workflow_id),
478
- workflowRunId: required(row.attribution_workflow_run_id),
479
- }
501
+ : row.attribution_kind === "subagent"
502
+ ? {
503
+ kind: "subagent" as const,
504
+ subagentRunId: required(row.attribution_agent_run_id),
505
+ parentRunId: required(row.attribution_parent_run_id),
506
+ }
507
+ : {
508
+ kind: "workflowAgent" as const,
509
+ agentStepId: required(row.attribution_agent_step_id),
510
+ nodeRunId: required(row.attribution_node_run_id),
511
+ workflowId: required(row.attribution_workflow_id),
512
+ workflowRunId: required(row.attribution_workflow_run_id),
513
+ }
480
514
  return {
481
515
  usage,
482
516
  ...(attribution ? { attribution } : {}),
@@ -494,7 +528,17 @@ function usageFromRow(row: UsageRow, requesterGroupIds: readonly string[]): AiMo
494
528
  callId: row.call_id,
495
529
  requesterGroupIds,
496
530
  providerId: row.provider_id,
531
+ ...(row.provider_ids === null
532
+ ? {}
533
+ : {
534
+ providerIds: normalizeModelProviderIds(
535
+ typeof row.provider_ids === "string" ? JSON.parse(row.provider_ids) : row.provider_ids
536
+ ),
537
+ }),
497
538
  requestedModelId: row.requested_model_id,
539
+ ...(row.requested_reasoning === null
540
+ ? {}
541
+ : { requestedReasoning: requestedReasoningFromRow(row.requested_reasoning) }),
498
542
  ...(row.response_model_id === null ? {} : { responseModelId: row.response_model_id }),
499
543
  responseId: row.response_id,
500
544
  usage: {
@@ -569,14 +613,15 @@ function costRecord(input: {
569
613
  ratedAt: Date | string
570
614
  }): AiModelCallCostRecord {
571
615
  const details = parseAiModelCallCostDetails(input.details)
616
+ const priceSource =
617
+ details.priceSource === undefined
618
+ ? undefined
619
+ : { ...details.priceSource, observedAt: new Date(details.priceSource.observedAt) }
572
620
  const base = {
621
+ ...(details.estimate === undefined ? {} : { estimate: details.estimate }),
573
622
  projectId: input.projectId,
574
623
  usageRecordId: input.usageId,
575
624
  pricingContext: details.pricingContext,
576
- priceSource: {
577
- ...details.priceSource,
578
- observedAt: new Date(details.priceSource.observedAt),
579
- },
580
625
  ratedAt: new Date(input.ratedAt),
581
626
  }
582
627
  if (input.status === "rated") {
@@ -584,6 +629,7 @@ function costRecord(input: {
584
629
  ...base,
585
630
  status: "rated",
586
631
  billingIdentity: { providerId: required(input.providerId), modelId: required(input.modelId) },
632
+ priceSource: required(priceSource),
587
633
  money: { currency: required(input.currency), amountNanos: required(input.amountNanos) },
588
634
  components: required(details.components),
589
635
  })
@@ -594,6 +640,7 @@ function costRecord(input: {
594
640
  ...(input.providerId && input.modelId
595
641
  ? { billingIdentity: { providerId: input.providerId, modelId: input.modelId } }
596
642
  : {}),
643
+ ...(priceSource === undefined ? {} : { priceSource }),
597
644
  reason: required(input.reason) as Extract<
598
645
  AiModelCallCostRecord,
599
646
  { status: "unpriceable" }