bopodev-db 0.1.13 → 0.1.14

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.
@@ -1,5 +1,5 @@
1
1
 
2
2
  
3
- > bopodev-db@0.1.13 build /Users/danielkrusenstrahle/Documents/Projects/Monorepo/bopohq/packages/db
3
+ > bopodev-db@0.1.14 build /Users/danielkrusenstrahle/Documents/Projects/Monorepo/bopohq/packages/db
4
4
  > tsc -p tsconfig.json --emitDeclarationOnly
5
5
 
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 BopoDev contributors
3
+ Copyright (c) 2026 Bopo
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -319,7 +319,7 @@ export declare function createAgent(db: BopoDb, input: {
319
319
  managerAgentId?: string | null;
320
320
  role: string;
321
321
  name: string;
322
- providerType: "claude_code" | "codex" | "cursor" | "opencode" | "openai_api" | "anthropic_api" | "http" | "shell";
322
+ providerType: "claude_code" | "codex" | "cursor" | "opencode" | "gemini_cli" | "openai_api" | "anthropic_api" | "http" | "shell";
323
323
  heartbeatCron: string;
324
324
  monthlyBudgetUsd: string;
325
325
  canHireAgents?: boolean;
@@ -341,7 +341,7 @@ export declare function createAgent(db: BopoDb, input: {
341
341
  managerAgentId?: string | null;
342
342
  role: string;
343
343
  name: string;
344
- providerType: "claude_code" | "codex" | "cursor" | "opencode" | "openai_api" | "anthropic_api" | "http" | "shell";
344
+ providerType: "claude_code" | "codex" | "cursor" | "opencode" | "gemini_cli" | "openai_api" | "anthropic_api" | "http" | "shell";
345
345
  heartbeatCron: string;
346
346
  monthlyBudgetUsd: string;
347
347
  canHireAgents?: boolean;
@@ -392,7 +392,7 @@ export declare function updateAgent(db: BopoDb, input: {
392
392
  managerAgentId?: string | null;
393
393
  role?: string;
394
394
  name?: string;
395
- providerType?: "claude_code" | "codex" | "cursor" | "opencode" | "openai_api" | "anthropic_api" | "http" | "shell";
395
+ providerType?: "claude_code" | "codex" | "cursor" | "opencode" | "gemini_cli" | "openai_api" | "anthropic_api" | "http" | "shell";
396
396
  status?: string;
397
397
  heartbeatCron?: string;
398
398
  monthlyBudgetUsd?: string;
@@ -514,6 +514,10 @@ export declare function clearApprovalInboxDismissed(db: BopoDb, input: {
514
514
  export declare function appendCost(db: BopoDb, input: {
515
515
  companyId: string;
516
516
  providerType: string;
517
+ runtimeModelId?: string | null;
518
+ pricingProviderType?: string | null;
519
+ pricingModelId?: string | null;
520
+ pricingSource?: "exact" | "missing" | null;
517
521
  tokenInput: number;
518
522
  tokenOutput: number;
519
523
  usdCost: string;
@@ -528,6 +532,10 @@ export declare function listCostEntries(db: BopoDb, companyId: string, limit?: n
528
532
  issueId: string | null;
529
533
  agentId: string | null;
530
534
  providerType: string;
535
+ runtimeModelId: string | null;
536
+ pricingProviderType: string | null;
537
+ pricingModelId: string | null;
538
+ pricingSource: string | null;
531
539
  tokenInput: number;
532
540
  tokenOutput: number;
533
541
  usdCost: string;
@@ -685,3 +693,39 @@ export declare function listPluginRuns(db: BopoDb, input: {
685
693
  diagnosticsJson: string;
686
694
  createdAt: Date;
687
695
  }[]>;
696
+ export declare function listModelPricing(db: BopoDb, companyId: string): Promise<{
697
+ companyId: string;
698
+ providerType: string;
699
+ modelId: string;
700
+ displayName: string | null;
701
+ inputUsdPer1M: string;
702
+ outputUsdPer1M: string;
703
+ currency: string;
704
+ updatedAt: Date;
705
+ updatedBy: string | null;
706
+ }[]>;
707
+ export declare function getModelPricing(db: BopoDb, input: {
708
+ companyId: string;
709
+ providerType: string;
710
+ modelId: string;
711
+ }): Promise<{
712
+ companyId: string;
713
+ providerType: string;
714
+ modelId: string;
715
+ displayName: string | null;
716
+ inputUsdPer1M: string;
717
+ outputUsdPer1M: string;
718
+ currency: string;
719
+ updatedAt: Date;
720
+ updatedBy: string | null;
721
+ } | null>;
722
+ export declare function upsertModelPricing(db: BopoDb, input: {
723
+ companyId: string;
724
+ providerType: string;
725
+ modelId: string;
726
+ displayName?: string | null;
727
+ inputUsdPer1M?: string | null;
728
+ outputUsdPer1M?: string | null;
729
+ currency?: string | null;
730
+ updatedBy?: string | null;
731
+ }): Promise<void>;
package/dist/schema.d.ts CHANGED
@@ -2296,6 +2296,74 @@ export declare const costLedger: import("drizzle-orm/pg-core").PgTableWithColumn
2296
2296
  identity: undefined;
2297
2297
  generated: undefined;
2298
2298
  }, {}, {}>;
2299
+ runtimeModelId: import("drizzle-orm/pg-core").PgColumn<{
2300
+ name: "runtime_model_id";
2301
+ tableName: "cost_ledger";
2302
+ dataType: "string";
2303
+ columnType: "PgText";
2304
+ data: string;
2305
+ driverParam: string;
2306
+ notNull: false;
2307
+ hasDefault: false;
2308
+ isPrimaryKey: false;
2309
+ isAutoincrement: false;
2310
+ hasRuntimeDefault: false;
2311
+ enumValues: [string, ...string[]];
2312
+ baseColumn: never;
2313
+ identity: undefined;
2314
+ generated: undefined;
2315
+ }, {}, {}>;
2316
+ pricingProviderType: import("drizzle-orm/pg-core").PgColumn<{
2317
+ name: "pricing_provider_type";
2318
+ tableName: "cost_ledger";
2319
+ dataType: "string";
2320
+ columnType: "PgText";
2321
+ data: string;
2322
+ driverParam: string;
2323
+ notNull: false;
2324
+ hasDefault: false;
2325
+ isPrimaryKey: false;
2326
+ isAutoincrement: false;
2327
+ hasRuntimeDefault: false;
2328
+ enumValues: [string, ...string[]];
2329
+ baseColumn: never;
2330
+ identity: undefined;
2331
+ generated: undefined;
2332
+ }, {}, {}>;
2333
+ pricingModelId: import("drizzle-orm/pg-core").PgColumn<{
2334
+ name: "pricing_model_id";
2335
+ tableName: "cost_ledger";
2336
+ dataType: "string";
2337
+ columnType: "PgText";
2338
+ data: string;
2339
+ driverParam: string;
2340
+ notNull: false;
2341
+ hasDefault: false;
2342
+ isPrimaryKey: false;
2343
+ isAutoincrement: false;
2344
+ hasRuntimeDefault: false;
2345
+ enumValues: [string, ...string[]];
2346
+ baseColumn: never;
2347
+ identity: undefined;
2348
+ generated: undefined;
2349
+ }, {}, {}>;
2350
+ pricingSource: import("drizzle-orm/pg-core").PgColumn<{
2351
+ name: "pricing_source";
2352
+ tableName: "cost_ledger";
2353
+ dataType: "string";
2354
+ columnType: "PgText";
2355
+ data: string;
2356
+ driverParam: string;
2357
+ notNull: false;
2358
+ hasDefault: false;
2359
+ isPrimaryKey: false;
2360
+ isAutoincrement: false;
2361
+ hasRuntimeDefault: false;
2362
+ enumValues: [string, ...string[]];
2363
+ baseColumn: never;
2364
+ identity: undefined;
2365
+ generated: undefined;
2366
+ }, {}, {}>;
2299
2367
  tokenInput: import("drizzle-orm/pg-core").PgColumn<{
2300
2368
  name: "token_input";
2301
2369
  tableName: "cost_ledger";
@@ -2738,6 +2806,166 @@ export declare const plugins: import("drizzle-orm/pg-core").PgTableWithColumns<{
2738
2806
  };
2739
2807
  dialect: "pg";
2740
2808
  }>;
2809
+ export declare const modelPricing: import("drizzle-orm/pg-core").PgTableWithColumns<{
2810
+ name: "model_pricing";
2811
+ schema: undefined;
2812
+ columns: {
2813
+ companyId: import("drizzle-orm/pg-core").PgColumn<{
2814
+ name: "company_id";
2815
+ tableName: "model_pricing";
2816
+ dataType: "string";
2817
+ columnType: "PgText";
2818
+ data: string;
2819
+ driverParam: string;
2820
+ notNull: true;
2821
+ hasDefault: false;
2822
+ isPrimaryKey: false;
2823
+ isAutoincrement: false;
2824
+ hasRuntimeDefault: false;
2825
+ enumValues: [string, ...string[]];
2826
+ baseColumn: never;
2827
+ identity: undefined;
2828
+ generated: undefined;
2829
+ }, {}, {}>;
2830
+ providerType: import("drizzle-orm/pg-core").PgColumn<{
2831
+ name: "provider_type";
2832
+ tableName: "model_pricing";
2833
+ dataType: "string";
2834
+ columnType: "PgText";
2835
+ data: string;
2836
+ driverParam: string;
2837
+ notNull: true;
2838
+ hasDefault: false;
2839
+ isPrimaryKey: false;
2840
+ isAutoincrement: false;
2841
+ hasRuntimeDefault: false;
2842
+ enumValues: [string, ...string[]];
2843
+ baseColumn: never;
2844
+ identity: undefined;
2845
+ generated: undefined;
2846
+ }, {}, {}>;
2847
+ modelId: import("drizzle-orm/pg-core").PgColumn<{
2848
+ name: "model_id";
2849
+ tableName: "model_pricing";
2850
+ dataType: "string";
2851
+ columnType: "PgText";
2852
+ data: string;
2853
+ driverParam: string;
2854
+ notNull: true;
2855
+ hasDefault: false;
2856
+ isPrimaryKey: false;
2857
+ isAutoincrement: false;
2858
+ hasRuntimeDefault: false;
2859
+ enumValues: [string, ...string[]];
2860
+ baseColumn: never;
2861
+ identity: undefined;
2862
+ generated: undefined;
2863
+ }, {}, {}>;
2864
+ displayName: import("drizzle-orm/pg-core").PgColumn<{
2865
+ name: "display_name";
2866
+ tableName: "model_pricing";
2867
+ dataType: "string";
2868
+ columnType: "PgText";
2869
+ data: string;
2870
+ driverParam: string;
2871
+ notNull: false;
2872
+ hasDefault: false;
2873
+ isPrimaryKey: false;
2874
+ isAutoincrement: false;
2875
+ hasRuntimeDefault: false;
2876
+ enumValues: [string, ...string[]];
2877
+ baseColumn: never;
2878
+ identity: undefined;
2879
+ generated: undefined;
2880
+ }, {}, {}>;
2881
+ inputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
2882
+ name: "input_usd_per_1m";
2883
+ tableName: "model_pricing";
2884
+ dataType: "string";
2885
+ columnType: "PgNumeric";
2886
+ data: string;
2887
+ driverParam: string;
2888
+ notNull: true;
2889
+ hasDefault: true;
2890
+ isPrimaryKey: false;
2891
+ isAutoincrement: false;
2892
+ hasRuntimeDefault: false;
2893
+ enumValues: undefined;
2894
+ baseColumn: never;
2895
+ identity: undefined;
2896
+ generated: undefined;
2897
+ }, {}, {}>;
2898
+ outputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
2899
+ name: "output_usd_per_1m";
2900
+ tableName: "model_pricing";
2901
+ dataType: "string";
2902
+ columnType: "PgNumeric";
2903
+ data: string;
2904
+ driverParam: string;
2905
+ notNull: true;
2906
+ hasDefault: true;
2907
+ isPrimaryKey: false;
2908
+ isAutoincrement: false;
2909
+ hasRuntimeDefault: false;
2910
+ enumValues: undefined;
2911
+ baseColumn: never;
2912
+ identity: undefined;
2913
+ generated: undefined;
2914
+ }, {}, {}>;
2915
+ currency: import("drizzle-orm/pg-core").PgColumn<{
2916
+ name: "currency";
2917
+ tableName: "model_pricing";
2918
+ dataType: "string";
2919
+ columnType: "PgText";
2920
+ data: string;
2921
+ driverParam: string;
2922
+ notNull: true;
2923
+ hasDefault: true;
2924
+ isPrimaryKey: false;
2925
+ isAutoincrement: false;
2926
+ hasRuntimeDefault: false;
2927
+ enumValues: [string, ...string[]];
2928
+ baseColumn: never;
2929
+ identity: undefined;
2930
+ generated: undefined;
2931
+ }, {}, {}>;
2932
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
2933
+ name: "updated_at";
2934
+ tableName: "model_pricing";
2935
+ dataType: "date";
2936
+ columnType: "PgTimestamp";
2937
+ data: Date;
2938
+ driverParam: string;
2939
+ notNull: true;
2940
+ hasDefault: true;
2941
+ isPrimaryKey: false;
2942
+ isAutoincrement: false;
2943
+ hasRuntimeDefault: false;
2944
+ enumValues: undefined;
2945
+ baseColumn: never;
2946
+ identity: undefined;
2947
+ generated: undefined;
2948
+ }, {}, {}>;
2949
+ updatedBy: import("drizzle-orm/pg-core").PgColumn<{
2950
+ name: "updated_by";
2951
+ tableName: "model_pricing";
2952
+ dataType: "string";
2953
+ columnType: "PgText";
2954
+ data: string;
2955
+ driverParam: string;
2956
+ notNull: false;
2957
+ hasDefault: false;
2958
+ isPrimaryKey: false;
2959
+ isAutoincrement: false;
2960
+ hasRuntimeDefault: false;
2961
+ enumValues: [string, ...string[]];
2962
+ baseColumn: never;
2963
+ identity: undefined;
2964
+ generated: undefined;
2965
+ }, {}, {}>;
2966
+ };
2967
+ dialect: "pg";
2968
+ }>;
2741
2969
  export declare const pluginConfigs: import("drizzle-orm/pg-core").PgTableWithColumns<{
2742
2970
  name: "plugin_configs";
2743
2971
  schema: undefined;
@@ -5415,6 +5643,74 @@ export declare const schema: {
5415
5643
  identity: undefined;
5416
5644
  generated: undefined;
5417
5645
  }, {}, {}>;
5646
+ runtimeModelId: import("drizzle-orm/pg-core").PgColumn<{
5647
+ name: "runtime_model_id";
5648
+ tableName: "cost_ledger";
5649
+ dataType: "string";
5650
+ columnType: "PgText";
5651
+ data: string;
5652
+ driverParam: string;
5653
+ notNull: false;
5654
+ hasDefault: false;
5655
+ isPrimaryKey: false;
5656
+ isAutoincrement: false;
5657
+ hasRuntimeDefault: false;
5658
+ enumValues: [string, ...string[]];
5659
+ baseColumn: never;
5660
+ identity: undefined;
5661
+ generated: undefined;
5662
+ }, {}, {}>;
5663
+ pricingProviderType: import("drizzle-orm/pg-core").PgColumn<{
5664
+ name: "pricing_provider_type";
5665
+ tableName: "cost_ledger";
5666
+ dataType: "string";
5667
+ columnType: "PgText";
5668
+ data: string;
5669
+ driverParam: string;
5670
+ notNull: false;
5671
+ hasDefault: false;
5672
+ isPrimaryKey: false;
5673
+ isAutoincrement: false;
5674
+ hasRuntimeDefault: false;
5675
+ enumValues: [string, ...string[]];
5676
+ baseColumn: never;
5677
+ identity: undefined;
5678
+ generated: undefined;
5679
+ }, {}, {}>;
5680
+ pricingModelId: import("drizzle-orm/pg-core").PgColumn<{
5681
+ name: "pricing_model_id";
5682
+ tableName: "cost_ledger";
5683
+ dataType: "string";
5684
+ columnType: "PgText";
5685
+ data: string;
5686
+ driverParam: string;
5687
+ notNull: false;
5688
+ hasDefault: false;
5689
+ isPrimaryKey: false;
5690
+ isAutoincrement: false;
5691
+ hasRuntimeDefault: false;
5692
+ enumValues: [string, ...string[]];
5693
+ baseColumn: never;
5694
+ identity: undefined;
5695
+ generated: undefined;
5696
+ }, {}, {}>;
5697
+ pricingSource: import("drizzle-orm/pg-core").PgColumn<{
5698
+ name: "pricing_source";
5699
+ tableName: "cost_ledger";
5700
+ dataType: "string";
5701
+ columnType: "PgText";
5702
+ data: string;
5703
+ driverParam: string;
5704
+ notNull: false;
5705
+ hasDefault: false;
5706
+ isPrimaryKey: false;
5707
+ isAutoincrement: false;
5708
+ hasRuntimeDefault: false;
5709
+ enumValues: [string, ...string[]];
5710
+ baseColumn: never;
5711
+ identity: undefined;
5712
+ generated: undefined;
5713
+ }, {}, {}>;
5418
5714
  tokenInput: import("drizzle-orm/pg-core").PgColumn<{
5419
5715
  name: "token_input";
5420
5716
  tableName: "cost_ledger";
@@ -6177,6 +6473,166 @@ export declare const schema: {
6177
6473
  };
6178
6474
  dialect: "pg";
6179
6475
  }>;
6476
+ modelPricing: import("drizzle-orm/pg-core").PgTableWithColumns<{
6477
+ name: "model_pricing";
6478
+ schema: undefined;
6479
+ columns: {
6480
+ companyId: import("drizzle-orm/pg-core").PgColumn<{
6481
+ name: "company_id";
6482
+ tableName: "model_pricing";
6483
+ dataType: "string";
6484
+ columnType: "PgText";
6485
+ data: string;
6486
+ driverParam: string;
6487
+ notNull: true;
6488
+ hasDefault: false;
6489
+ isPrimaryKey: false;
6490
+ isAutoincrement: false;
6491
+ hasRuntimeDefault: false;
6492
+ enumValues: [string, ...string[]];
6493
+ baseColumn: never;
6494
+ identity: undefined;
6495
+ generated: undefined;
6496
+ }, {}, {}>;
6497
+ providerType: import("drizzle-orm/pg-core").PgColumn<{
6498
+ name: "provider_type";
6499
+ tableName: "model_pricing";
6500
+ dataType: "string";
6501
+ columnType: "PgText";
6502
+ data: string;
6503
+ driverParam: string;
6504
+ notNull: true;
6505
+ hasDefault: false;
6506
+ isPrimaryKey: false;
6507
+ isAutoincrement: false;
6508
+ hasRuntimeDefault: false;
6509
+ enumValues: [string, ...string[]];
6510
+ baseColumn: never;
6511
+ identity: undefined;
6512
+ generated: undefined;
6513
+ }, {}, {}>;
6514
+ modelId: import("drizzle-orm/pg-core").PgColumn<{
6515
+ name: "model_id";
6516
+ tableName: "model_pricing";
6517
+ dataType: "string";
6518
+ columnType: "PgText";
6519
+ data: string;
6520
+ driverParam: string;
6521
+ notNull: true;
6522
+ hasDefault: false;
6523
+ isPrimaryKey: false;
6524
+ isAutoincrement: false;
6525
+ hasRuntimeDefault: false;
6526
+ enumValues: [string, ...string[]];
6527
+ baseColumn: never;
6528
+ identity: undefined;
6529
+ generated: undefined;
6530
+ }, {}, {}>;
6531
+ displayName: import("drizzle-orm/pg-core").PgColumn<{
6532
+ name: "display_name";
6533
+ tableName: "model_pricing";
6534
+ dataType: "string";
6535
+ columnType: "PgText";
6536
+ data: string;
6537
+ driverParam: string;
6538
+ notNull: false;
6539
+ hasDefault: false;
6540
+ isPrimaryKey: false;
6541
+ isAutoincrement: false;
6542
+ hasRuntimeDefault: false;
6543
+ enumValues: [string, ...string[]];
6544
+ baseColumn: never;
6545
+ identity: undefined;
6546
+ generated: undefined;
6547
+ }, {}, {}>;
6548
+ inputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
6549
+ name: "input_usd_per_1m";
6550
+ tableName: "model_pricing";
6551
+ dataType: "string";
6552
+ columnType: "PgNumeric";
6553
+ data: string;
6554
+ driverParam: string;
6555
+ notNull: true;
6556
+ hasDefault: true;
6557
+ isPrimaryKey: false;
6558
+ isAutoincrement: false;
6559
+ hasRuntimeDefault: false;
6560
+ enumValues: undefined;
6561
+ baseColumn: never;
6562
+ identity: undefined;
6563
+ generated: undefined;
6564
+ }, {}, {}>;
6565
+ outputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
6566
+ name: "output_usd_per_1m";
6567
+ tableName: "model_pricing";
6568
+ dataType: "string";
6569
+ columnType: "PgNumeric";
6570
+ data: string;
6571
+ driverParam: string;
6572
+ notNull: true;
6573
+ hasDefault: true;
6574
+ isPrimaryKey: false;
6575
+ isAutoincrement: false;
6576
+ hasRuntimeDefault: false;
6577
+ enumValues: undefined;
6578
+ baseColumn: never;
6579
+ identity: undefined;
6580
+ generated: undefined;
6581
+ }, {}, {}>;
6582
+ currency: import("drizzle-orm/pg-core").PgColumn<{
6583
+ name: "currency";
6584
+ tableName: "model_pricing";
6585
+ dataType: "string";
6586
+ columnType: "PgText";
6587
+ data: string;
6588
+ driverParam: string;
6589
+ notNull: true;
6590
+ hasDefault: true;
6591
+ isPrimaryKey: false;
6592
+ isAutoincrement: false;
6593
+ hasRuntimeDefault: false;
6594
+ enumValues: [string, ...string[]];
6595
+ baseColumn: never;
6596
+ identity: undefined;
6597
+ generated: undefined;
6598
+ }, {}, {}>;
6599
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
6600
+ name: "updated_at";
6601
+ tableName: "model_pricing";
6602
+ dataType: "date";
6603
+ columnType: "PgTimestamp";
6604
+ data: Date;
6605
+ driverParam: string;
6606
+ notNull: true;
6607
+ hasDefault: true;
6608
+ isPrimaryKey: false;
6609
+ isAutoincrement: false;
6610
+ hasRuntimeDefault: false;
6611
+ enumValues: undefined;
6612
+ baseColumn: never;
6613
+ identity: undefined;
6614
+ generated: undefined;
6615
+ }, {}, {}>;
6616
+ updatedBy: import("drizzle-orm/pg-core").PgColumn<{
6617
+ name: "updated_by";
6618
+ tableName: "model_pricing";
6619
+ dataType: "string";
6620
+ columnType: "PgText";
6621
+ data: string;
6622
+ driverParam: string;
6623
+ notNull: false;
6624
+ hasDefault: false;
6625
+ isPrimaryKey: false;
6626
+ isAutoincrement: false;
6627
+ hasRuntimeDefault: false;
6628
+ enumValues: [string, ...string[]];
6629
+ baseColumn: never;
6630
+ identity: undefined;
6631
+ generated: undefined;
6632
+ }, {}, {}>;
6633
+ };
6634
+ dialect: "pg";
6635
+ }>;
6180
6636
  agentIssueLabels: import("drizzle-orm/pg-core").PgTableWithColumns<{
6181
6637
  name: "agent_issue_labels";
6182
6638
  schema: undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bopodev-db",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/bootstrap.ts CHANGED
@@ -279,12 +279,46 @@ export async function bootstrapDatabase(dbPath?: string) {
279
279
  issue_id TEXT REFERENCES issues(id) ON DELETE SET NULL,
280
280
  agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
281
281
  provider_type TEXT NOT NULL,
282
+ runtime_model_id TEXT,
283
+ pricing_provider_type TEXT,
284
+ pricing_model_id TEXT,
285
+ pricing_source TEXT,
282
286
  token_input INTEGER NOT NULL DEFAULT 0,
283
287
  token_output INTEGER NOT NULL DEFAULT 0,
284
288
  usd_cost NUMERIC(12, 6) NOT NULL DEFAULT 0,
285
289
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
286
290
  );
287
291
  `);
292
+ await db.execute(sql`
293
+ ALTER TABLE cost_ledger
294
+ ADD COLUMN IF NOT EXISTS runtime_model_id TEXT;
295
+ `);
296
+ await db.execute(sql`
297
+ ALTER TABLE cost_ledger
298
+ ADD COLUMN IF NOT EXISTS pricing_provider_type TEXT;
299
+ `);
300
+ await db.execute(sql`
301
+ ALTER TABLE cost_ledger
302
+ ADD COLUMN IF NOT EXISTS pricing_model_id TEXT;
303
+ `);
304
+ await db.execute(sql`
305
+ ALTER TABLE cost_ledger
306
+ ADD COLUMN IF NOT EXISTS pricing_source TEXT;
307
+ `);
308
+ await db.execute(sql`
309
+ CREATE TABLE IF NOT EXISTS model_pricing (
310
+ company_id TEXT NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
311
+ provider_type TEXT NOT NULL,
312
+ model_id TEXT NOT NULL,
313
+ display_name TEXT,
314
+ input_usd_per_1m NUMERIC(12, 6) NOT NULL DEFAULT 0,
315
+ output_usd_per_1m NUMERIC(12, 6) NOT NULL DEFAULT 0,
316
+ currency TEXT NOT NULL DEFAULT 'USD',
317
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
318
+ updated_by TEXT,
319
+ PRIMARY KEY (company_id, provider_type, model_id)
320
+ );
321
+ `);
288
322
  await db.execute(sql`
289
323
  CREATE TABLE IF NOT EXISTS audit_events (
290
324
  id TEXT PRIMARY KEY,
@@ -15,6 +15,7 @@ import {
15
15
  issueAttachments,
16
16
  issueComments,
17
17
  issues,
18
+ modelPricing,
18
19
  pluginConfigs,
19
20
  pluginRuns,
20
21
  plugins,
@@ -542,6 +543,7 @@ export async function createAgent(
542
543
  | "codex"
543
544
  | "cursor"
544
545
  | "opencode"
546
+ | "gemini_cli"
545
547
  | "openai_api"
546
548
  | "anthropic_api"
547
549
  | "http"
@@ -612,6 +614,7 @@ export async function updateAgent(
612
614
  | "codex"
613
615
  | "cursor"
614
616
  | "opencode"
617
+ | "gemini_cli"
615
618
  | "openai_api"
616
619
  | "anthropic_api"
617
620
  | "http"
@@ -843,6 +846,10 @@ export async function appendCost(
843
846
  input: {
844
847
  companyId: string;
845
848
  providerType: string;
849
+ runtimeModelId?: string | null;
850
+ pricingProviderType?: string | null;
851
+ pricingModelId?: string | null;
852
+ pricingSource?: "exact" | "missing" | null;
846
853
  tokenInput: number;
847
854
  tokenOutput: number;
848
855
  usdCost: string;
@@ -856,6 +863,10 @@ export async function appendCost(
856
863
  id,
857
864
  companyId: input.companyId,
858
865
  providerType: input.providerType,
866
+ runtimeModelId: input.runtimeModelId ?? null,
867
+ pricingProviderType: input.pricingProviderType ?? null,
868
+ pricingModelId: input.pricingModelId ?? null,
869
+ pricingSource: input.pricingSource ?? null,
859
870
  tokenInput: input.tokenInput,
860
871
  tokenOutput: input.tokenOutput,
861
872
  usdCost: input.usdCost,
@@ -1247,6 +1258,70 @@ export async function listPluginRuns(
1247
1258
  .limit(limit);
1248
1259
  }
1249
1260
 
1261
+ export async function listModelPricing(db: BopoDb, companyId: string) {
1262
+ return db
1263
+ .select()
1264
+ .from(modelPricing)
1265
+ .where(eq(modelPricing.companyId, companyId))
1266
+ .orderBy(asc(modelPricing.providerType), asc(modelPricing.modelId));
1267
+ }
1268
+
1269
+ export async function getModelPricing(
1270
+ db: BopoDb,
1271
+ input: { companyId: string; providerType: string; modelId: string }
1272
+ ) {
1273
+ const rows = await db
1274
+ .select()
1275
+ .from(modelPricing)
1276
+ .where(
1277
+ and(
1278
+ eq(modelPricing.companyId, input.companyId),
1279
+ eq(modelPricing.providerType, input.providerType),
1280
+ eq(modelPricing.modelId, input.modelId)
1281
+ )
1282
+ )
1283
+ .limit(1);
1284
+ return rows[0] ?? null;
1285
+ }
1286
+
1287
+ export async function upsertModelPricing(
1288
+ db: BopoDb,
1289
+ input: {
1290
+ companyId: string;
1291
+ providerType: string;
1292
+ modelId: string;
1293
+ displayName?: string | null;
1294
+ inputUsdPer1M?: string | null;
1295
+ outputUsdPer1M?: string | null;
1296
+ currency?: string | null;
1297
+ updatedBy?: string | null;
1298
+ }
1299
+ ) {
1300
+ await db
1301
+ .insert(modelPricing)
1302
+ .values({
1303
+ companyId: input.companyId,
1304
+ providerType: input.providerType,
1305
+ modelId: input.modelId,
1306
+ displayName: input.displayName ?? null,
1307
+ inputUsdPer1M: input.inputUsdPer1M ?? "0.000000",
1308
+ outputUsdPer1M: input.outputUsdPer1M ?? "0.000000",
1309
+ currency: input.currency ?? "USD",
1310
+ updatedBy: input.updatedBy ?? null
1311
+ })
1312
+ .onConflictDoUpdate({
1313
+ target: [modelPricing.companyId, modelPricing.providerType, modelPricing.modelId],
1314
+ set: compactUpdate({
1315
+ displayName: input.displayName ?? null,
1316
+ inputUsdPer1M: input.inputUsdPer1M ?? "0.000000",
1317
+ outputUsdPer1M: input.outputUsdPer1M ?? "0.000000",
1318
+ currency: input.currency ?? "USD",
1319
+ updatedBy: input.updatedBy ?? null,
1320
+ updatedAt: touchUpdatedAtSql
1321
+ })
1322
+ });
1323
+ }
1324
+
1250
1325
  function compactUpdate<T extends Record<string, unknown>>(input: T) {
1251
1326
  return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
1252
1327
  }
package/src/schema.ts CHANGED
@@ -1,13 +1,5 @@
1
1
  import { sql } from "drizzle-orm";
2
- import {
3
- boolean,
4
- integer,
5
- numeric,
6
- pgTable,
7
- primaryKey,
8
- text,
9
- timestamp
10
- } from "drizzle-orm/pg-core";
2
+ import { boolean, integer, numeric, pgTable, primaryKey, text, timestamp } from "drizzle-orm/pg-core";
11
3
 
12
4
  export const companies = pgTable("companies", {
13
5
  id: text("id").primaryKey(),
@@ -222,6 +214,10 @@ export const costLedger = pgTable("cost_ledger", {
222
214
  issueId: text("issue_id").references(() => issues.id, { onDelete: "set null" }),
223
215
  agentId: text("agent_id").references(() => agents.id, { onDelete: "set null" }),
224
216
  providerType: text("provider_type").notNull(),
217
+ runtimeModelId: text("runtime_model_id"),
218
+ pricingProviderType: text("pricing_provider_type"),
219
+ pricingModelId: text("pricing_model_id"),
220
+ pricingSource: text("pricing_source"),
225
221
  tokenInput: integer("token_input").notNull().default(0),
226
222
  tokenOutput: integer("token_output").notNull().default(0),
227
223
  usdCost: numeric("usd_cost", { precision: 12, scale: 6 }).notNull().default("0"),
@@ -257,6 +253,24 @@ export const plugins = pgTable("plugins", {
257
253
  updatedAt: timestamp("updated_at", { mode: "date" }).defaultNow().notNull()
258
254
  });
259
255
 
256
+ export const modelPricing = pgTable(
257
+ "model_pricing",
258
+ {
259
+ companyId: text("company_id")
260
+ .notNull()
261
+ .references(() => companies.id, { onDelete: "cascade" }),
262
+ providerType: text("provider_type").notNull(),
263
+ modelId: text("model_id").notNull(),
264
+ displayName: text("display_name"),
265
+ inputUsdPer1M: numeric("input_usd_per_1m", { precision: 12, scale: 6 }).notNull().default("0"),
266
+ outputUsdPer1M: numeric("output_usd_per_1m", { precision: 12, scale: 6 }).notNull().default("0"),
267
+ currency: text("currency").notNull().default("USD"),
268
+ updatedAt: timestamp("updated_at", { mode: "date" }).defaultNow().notNull(),
269
+ updatedBy: text("updated_by")
270
+ },
271
+ (table) => [primaryKey({ columns: [table.companyId, table.providerType, table.modelId] })]
272
+ );
273
+
260
274
  export const pluginConfigs = pgTable(
261
275
  "plugin_configs",
262
276
  {
@@ -325,6 +339,7 @@ export const schema = {
325
339
  plugins,
326
340
  pluginConfigs,
327
341
  pluginRuns,
342
+ modelPricing,
328
343
  agentIssueLabels
329
344
  };
330
345