@sixb/pg 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.
- 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 +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1721 -393
- package/dist/index.js.map +17 -14
- package/dist/migrations.d.ts.map +1 -1
- 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/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 +8 -1
- 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.ts +18 -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-workflow-run-storage.ts +8 -8
package/src/migrations.ts
CHANGED
|
@@ -73,6 +73,18 @@ import agentContextCheckpointsSql from "./migrations/027-agent-context-checkpoin
|
|
|
73
73
|
import objectOverrideEditTimesSql from "./migrations/028-object-override-edit-times.sql" with {
|
|
74
74
|
type: "text",
|
|
75
75
|
}
|
|
76
|
+
import modelAccountingSql from "./migrations/029-model-accounting.sql" with { type: "text" }
|
|
77
|
+
import aiUsageLimitsSql from "./migrations/030-ai-usage-limits.sql" with { type: "text" }
|
|
78
|
+
import subagentRunsSql from "./migrations/031-subagent-runs.sql" with { type: "text" }
|
|
79
|
+
import conversationRunSpecSql from "./migrations/032-conversation-run-spec.sql" with {
|
|
80
|
+
type: "text",
|
|
81
|
+
}
|
|
82
|
+
import retireAgentDefinitionsSql from "./migrations/033-retire-agent-definitions.sql" with {
|
|
83
|
+
type: "text",
|
|
84
|
+
}
|
|
85
|
+
import deviceAuthorizationsSql from "./migrations/034-device-authorizations.sql" with {
|
|
86
|
+
type: "text",
|
|
87
|
+
}
|
|
76
88
|
import type { SQL, SQLClient } from "./pg-client"
|
|
77
89
|
|
|
78
90
|
export interface PostgresMigrationContext {
|
|
@@ -354,6 +366,12 @@ export const postgresStorageMigrations = defineMigrations<PostgresMigrationConte
|
|
|
354
366
|
pgSql("026-ai-cost-accounting", aiCostAccountingSql),
|
|
355
367
|
pgSql("027-agent-context-checkpoints", agentContextCheckpointsSql),
|
|
356
368
|
pgSql("028-object-override-edit-times", objectOverrideEditTimesSql),
|
|
369
|
+
pgSql("029-model-accounting", modelAccountingSql),
|
|
370
|
+
pgSql("030-ai-usage-limits", aiUsageLimitsSql),
|
|
371
|
+
pgSql("031-subagent-runs", subagentRunsSql),
|
|
372
|
+
pgSql("032-conversation-run-spec", conversationRunSpecSql),
|
|
373
|
+
pgSql("033-retire-agent-definitions", retireAgentDefinitionsSql),
|
|
374
|
+
pgSql("034-device-authorizations", deviceAuthorizationsSql),
|
|
357
375
|
],
|
|
358
376
|
})
|
|
359
377
|
|
|
@@ -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
|
-
|
|
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',
|
|
156
|
-
FROM classified WHERE
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
? {
|
|
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
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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" }
|