@tokenbuddy/tokenbuddy 1.0.36 → 1.0.37

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 (143) hide show
  1. package/dist/src/buyer-store.d.ts +6 -1
  2. package/dist/src/buyer-store.js +43 -4
  3. package/dist/src/cli.js +2 -2
  4. package/dist/src/daemon.d.ts +12 -0
  5. package/dist/src/daemon.js +791 -61
  6. package/dist/src/doctor-diagnostics.js +1 -6
  7. package/dist/src/provider-install.d.ts +2 -2
  8. package/dist/src/provider-install.js +248 -2
  9. package/dist/src/seller-catalog.d.ts +21 -0
  10. package/dist/src/seller-catalog.js +17 -0
  11. package/dist/src/seller-route-planner.d.ts +4 -1
  12. package/dist/src/seller-route-planner.js +3 -0
  13. package/dist/src/seller-routing-strategy.d.ts +3 -0
  14. package/dist/src/terminal-detect.d.ts +1 -1
  15. package/dist/src/terminal-detect.js +3 -2
  16. package/package.json +15 -2
  17. package/static/ui/assets/index-Djfl9tw5.js +271 -0
  18. package/static/ui/assets/index-DkfztCkn.css +1 -0
  19. package/static/ui/index.html +2 -2
  20. package/dist/src/buyer-store.d.ts.map +0 -1
  21. package/dist/src/buyer-store.js.map +0 -1
  22. package/dist/src/clawtip-bootstrap.d.ts.map +0 -1
  23. package/dist/src/clawtip-bootstrap.js.map +0 -1
  24. package/dist/src/cli.d.ts.map +0 -1
  25. package/dist/src/cli.js.map +0 -1
  26. package/dist/src/credit-tracker.d.ts.map +0 -1
  27. package/dist/src/credit-tracker.js.map +0 -1
  28. package/dist/src/daemon.d.ts.map +0 -1
  29. package/dist/src/daemon.js.map +0 -1
  30. package/dist/src/doctor-clawtip-wallet.d.ts.map +0 -1
  31. package/dist/src/doctor-clawtip-wallet.js.map +0 -1
  32. package/dist/src/doctor-diagnostics.d.ts.map +0 -1
  33. package/dist/src/doctor-diagnostics.js.map +0 -1
  34. package/dist/src/index.d.ts.map +0 -1
  35. package/dist/src/index.js.map +0 -1
  36. package/dist/src/init-clawtip-activation.d.ts.map +0 -1
  37. package/dist/src/init-clawtip-activation.js.map +0 -1
  38. package/dist/src/init-payment-options.d.ts.map +0 -1
  39. package/dist/src/init-payment-options.js.map +0 -1
  40. package/dist/src/init-setup.d.ts.map +0 -1
  41. package/dist/src/init-setup.js.map +0 -1
  42. package/dist/src/model-index.d.ts.map +0 -1
  43. package/dist/src/model-index.js.map +0 -1
  44. package/dist/src/package-update.d.ts.map +0 -1
  45. package/dist/src/package-update.js.map +0 -1
  46. package/dist/src/prewarm-cache.d.ts.map +0 -1
  47. package/dist/src/prewarm-cache.js.map +0 -1
  48. package/dist/src/prewarm-scheduler.d.ts.map +0 -1
  49. package/dist/src/prewarm-scheduler.js.map +0 -1
  50. package/dist/src/provider-install.d.ts.map +0 -1
  51. package/dist/src/provider-install.js.map +0 -1
  52. package/dist/src/provider-routing-config.d.ts.map +0 -1
  53. package/dist/src/provider-routing-config.js.map +0 -1
  54. package/dist/src/registry-trust.d.ts.map +0 -1
  55. package/dist/src/registry-trust.js.map +0 -1
  56. package/dist/src/route-failover.d.ts.map +0 -1
  57. package/dist/src/route-failover.js.map +0 -1
  58. package/dist/src/seller-catalog.d.ts.map +0 -1
  59. package/dist/src/seller-catalog.js.map +0 -1
  60. package/dist/src/seller-concurrency-limiter.d.ts.map +0 -1
  61. package/dist/src/seller-concurrency-limiter.js.map +0 -1
  62. package/dist/src/seller-metadata-cache.d.ts.map +0 -1
  63. package/dist/src/seller-metadata-cache.js.map +0 -1
  64. package/dist/src/seller-pool.d.ts.map +0 -1
  65. package/dist/src/seller-pool.js.map +0 -1
  66. package/dist/src/seller-route-planner.d.ts.map +0 -1
  67. package/dist/src/seller-route-planner.js.map +0 -1
  68. package/dist/src/seller-routing-config.d.ts.map +0 -1
  69. package/dist/src/seller-routing-config.js.map +0 -1
  70. package/dist/src/seller-routing-strategy.d.ts.map +0 -1
  71. package/dist/src/seller-routing-strategy.js.map +0 -1
  72. package/dist/src/stream-failover.d.ts.map +0 -1
  73. package/dist/src/stream-failover.js.map +0 -1
  74. package/dist/src/tb-clawtip-proof.d.ts.map +0 -1
  75. package/dist/src/tb-clawtip-proof.js.map +0 -1
  76. package/dist/src/tb-proxyd.d.ts.map +0 -1
  77. package/dist/src/tb-proxyd.js.map +0 -1
  78. package/dist/src/terminal-detect.d.ts.map +0 -1
  79. package/dist/src/terminal-detect.js.map +0 -1
  80. package/dist/src/terminal-image.d.ts.map +0 -1
  81. package/dist/src/terminal-image.js.map +0 -1
  82. package/src/buyer-store.ts +0 -1090
  83. package/src/clawtip-bootstrap.ts +0 -65
  84. package/src/cli.ts +0 -2243
  85. package/src/credit-tracker.ts +0 -295
  86. package/src/daemon.ts +0 -5475
  87. package/src/doctor-clawtip-wallet.ts +0 -95
  88. package/src/doctor-diagnostics.ts +0 -1026
  89. package/src/index.ts +0 -16
  90. package/src/init-clawtip-activation.ts +0 -695
  91. package/src/init-payment-options.ts +0 -373
  92. package/src/init-setup.ts +0 -165
  93. package/src/model-index.ts +0 -278
  94. package/src/package-update.ts +0 -311
  95. package/src/prewarm-cache.ts +0 -485
  96. package/src/prewarm-scheduler.ts +0 -675
  97. package/src/provider-install.ts +0 -1006
  98. package/src/provider-routing-config.ts +0 -410
  99. package/src/registry-trust.ts +0 -51
  100. package/src/route-failover.ts +0 -304
  101. package/src/seller-catalog.ts +0 -505
  102. package/src/seller-concurrency-limiter.ts +0 -161
  103. package/src/seller-metadata-cache.ts +0 -91
  104. package/src/seller-pool.ts +0 -557
  105. package/src/seller-route-planner.ts +0 -513
  106. package/src/seller-routing-config.ts +0 -211
  107. package/src/seller-routing-strategy.ts +0 -362
  108. package/src/stream-failover.ts +0 -152
  109. package/src/tb-clawtip-proof.ts +0 -28
  110. package/src/tb-proxyd.ts +0 -101
  111. package/src/terminal-detect.ts +0 -333
  112. package/src/terminal-image.ts +0 -228
  113. package/static/ui/assets/index-0MVXD7bH.css +0 -1
  114. package/static/ui/assets/index-BVbeDEwq.js +0 -271
  115. package/static/ui/assets/index-BVbeDEwq.js.map +0 -1
  116. package/tests/cli-routing.test.ts +0 -363
  117. package/tests/control-plane-ui-endpoints.test.ts +0 -1630
  118. package/tests/credit-tracker.test.ts +0 -165
  119. package/tests/daemon-413-fallback.test.ts +0 -92
  120. package/tests/daemon-classify.test.ts +0 -452
  121. package/tests/daemon-roles.test.ts +0 -92
  122. package/tests/daemon-trusted-registry-cache.test.ts +0 -132
  123. package/tests/e2e.test.ts +0 -366
  124. package/tests/image-generation-e2e.test.ts +0 -230
  125. package/tests/model-index.test.ts +0 -198
  126. package/tests/package-update.test.ts +0 -147
  127. package/tests/prewarm-cache.test.ts +0 -296
  128. package/tests/prewarm-scheduler.test.ts +0 -367
  129. package/tests/provider-routing-config.test.ts +0 -150
  130. package/tests/registry-trust.test.ts +0 -28
  131. package/tests/route-failover.test.ts +0 -222
  132. package/tests/seller-catalog-413.test.ts +0 -120
  133. package/tests/seller-catalog-utilities.test.ts +0 -124
  134. package/tests/seller-concurrency-limiter.test.ts +0 -83
  135. package/tests/seller-metadata-cache.test.ts +0 -89
  136. package/tests/seller-pool.test.ts +0 -365
  137. package/tests/seller-route-planner.test.ts +0 -312
  138. package/tests/seller-routing-config.test.ts +0 -124
  139. package/tests/seller-routing-strategy.test.ts +0 -167
  140. package/tests/stream-failover.test.ts +0 -52
  141. package/tests/thousand-seller.test.ts +0 -151
  142. package/tests/tokenbuddy.test.ts +0 -4043
  143. package/tsconfig.json +0 -8
@@ -80,13 +80,14 @@ export interface SafePurchaseLedgerEntry {
80
80
  * buyer 端单次推理请求的账本输入。
81
81
  * `prompt` / `response` 在落库前会 hash,原始内容永不落盘。
82
82
  *
83
- * v1.2 tb-ui v1 (Iter 4):补 7 字段 — 排查 / 性能 / 路由决策溯源必备。
83
+ * v1.2 tb-ui v1 (Iter 4):补充排查 / 性能 / 路由决策溯源必备字段。
84
84
  * - `ttftMs`:首字延迟(从请求发起到首 byte),`forwardProxyRequest` 计算
85
85
  * - `fallbackCount`:本请求实际走过的 seller 数(> 1 即发生 failover)
86
86
  * - `routeReason`:`planSellerRouteSet().reason`(如 `fullAuto:balanced:routes_3`)
87
87
  * - `falloverChain`:failover 路径上 seller id 数组(空 = 主路径成功)
88
88
  * - `upstreamStatus`:seller 透传的上游健康状态(`healthy|degraded|unhealthy|unknown`)
89
89
  * - `durationMs`:总耗时(req start → response end 或失败)
90
+ * - `avgOutputTokensPerSecond`:请求级输出速度,按输出窗口统计,不由 UI 现场推导
90
91
  * - `paymentMethod`:本请求使用的支付方式(`mock|clawtip`)
91
92
  */
92
93
  export interface InferenceLedgerInput {
@@ -130,6 +131,7 @@ export interface InferenceLedgerInput {
130
131
  falloverChain?: string[];
131
132
  upstreamStatus?: string;
132
133
  durationMs?: number;
134
+ avgOutputTokensPerSecond?: number;
133
135
  paymentMethod?: string;
134
136
  }
135
137
  /**
@@ -178,6 +180,7 @@ export interface SafeInferenceLedgerEntry {
178
180
  falloverChain?: string[];
179
181
  upstreamStatus?: string;
180
182
  durationMs?: number;
183
+ avgOutputTokensPerSecond?: number;
181
184
  paymentMethod?: string;
182
185
  }
183
186
  /**
@@ -292,6 +295,8 @@ export declare class BuyerStore {
292
295
  listInferenceLedger(): SafeInferenceLedgerEntry[];
293
296
  close(): void;
294
297
  private initSchema;
298
+ private backfillPurchasePaymentAmountsFromPending;
299
+ private pendingPurchasePaymentSummary;
295
300
  private ensureColumn;
296
301
  private countRows;
297
302
  /**
@@ -251,11 +251,12 @@ export class BuyerStore {
251
251
  }
252
252
  recordPurchaseLedger(input) {
253
253
  const createdAt = nowIso();
254
+ const pendingPayment = this.pendingPurchasePaymentSummary(input.purchaseId);
254
255
  this.db.prepare(`INSERT INTO purchase_ledger (
255
256
  purchase_id, seller_key, model_id, payment_method, status, credit_micros,
256
257
  currency, payment_amount, payment_amount_minor, payment_currency,
257
258
  payment_reference_hash, created_at, completed_at
258
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(input.purchaseId, input.sellerKey, input.modelId, input.paymentMethod, input.status, input.creditMicros, input.currency, input.paymentAmount ?? null, input.paymentAmountMinor ?? null, input.paymentCurrency ?? null, safeHash(input.paymentReference) || null, createdAt, input.completedAt || null);
259
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(input.purchaseId, input.sellerKey, input.modelId, input.paymentMethod, input.status, input.creditMicros, input.currency, input.paymentAmount ?? pendingPayment?.paymentAmount ?? null, input.paymentAmountMinor ?? pendingPayment?.paymentAmountMinor ?? null, input.paymentCurrency ?? pendingPayment?.paymentCurrency ?? null, safeHash(input.paymentReference) || null, createdAt, input.completedAt || null);
259
260
  }
260
261
  listPurchaseLedger() {
261
262
  const rows = this.db.prepare(`SELECT purchase_id, seller_key, model_id, payment_method, status, credit_micros,
@@ -292,8 +293,8 @@ export class BuyerStore {
292
293
  balance_snapshot_micros, balance_source,
293
294
  prompt_hash, response_hash, created_at,
294
295
  ttft_ms, fallback_count, route_reason, fallover_chain_json, upstream_status,
295
- duration_ms, payment_method
296
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(input.requestId, input.sellerKey, input.modelId, input.endpoint, input.status, input.promptTokens, input.completionTokens, input.cacheReadTokens ?? 0, input.billedMicros, input.estimatedMicros ?? input.billedMicros, input.settledMicros ?? null, input.settledUsdMicros ?? null, input.priceVersion || null, input.inputPriceMicrosPer1m ?? null, input.outputPriceMicrosPer1m ?? null, input.cacheReadPriceMicrosPer1m ?? null, input.inputCostMicros ?? null, input.outputCostMicros ?? null, input.cacheReadCostMicros ?? null, input.originalUsdMicros ?? null, input.billingMultiplier ?? null, input.serviceTier ?? null, input.billingUnit ?? (input.endpoint === "/v1/images/generations" ? "images" : "tokens"), input.imageCount ?? null, input.imageSize ?? null, input.imageQuality ?? null, input.imageOutputFormat ?? null, input.imageOutputTokens ?? null, input.imageOutputCostMicros ?? null, input.imageCostMicrosPerImage ?? null, input.balanceSnapshotMicros ?? null, input.balanceSource || "unknown", safeHash(input.prompt) || null, safeHash(input.response) || null, nowIso(), input.ttftMs ?? null, input.fallbackCount ?? null, input.routeReason ?? null, input.falloverChain ? JSON.stringify(input.falloverChain) : null, input.upstreamStatus ?? null, input.durationMs ?? null, input.paymentMethod ?? null);
296
+ duration_ms, avg_output_tokens_per_second, payment_method
297
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(input.requestId, input.sellerKey, input.modelId, input.endpoint, input.status, input.promptTokens, input.completionTokens, input.cacheReadTokens ?? 0, input.billedMicros, input.estimatedMicros ?? input.billedMicros, input.settledMicros ?? null, input.settledUsdMicros ?? null, input.priceVersion || null, input.inputPriceMicrosPer1m ?? null, input.outputPriceMicrosPer1m ?? null, input.cacheReadPriceMicrosPer1m ?? null, input.inputCostMicros ?? null, input.outputCostMicros ?? null, input.cacheReadCostMicros ?? null, input.originalUsdMicros ?? null, input.billingMultiplier ?? null, input.serviceTier ?? null, input.billingUnit ?? (input.endpoint === "/v1/images/generations" ? "images" : "tokens"), input.imageCount ?? null, input.imageSize ?? null, input.imageQuality ?? null, input.imageOutputFormat ?? null, input.imageOutputTokens ?? null, input.imageOutputCostMicros ?? null, input.imageCostMicrosPerImage ?? null, input.balanceSnapshotMicros ?? null, input.balanceSource || "unknown", safeHash(input.prompt) || null, safeHash(input.response) || null, nowIso(), input.ttftMs ?? null, input.fallbackCount ?? null, input.routeReason ?? null, input.falloverChain ? JSON.stringify(input.falloverChain) : null, input.upstreamStatus ?? null, input.durationMs ?? null, input.avgOutputTokensPerSecond ?? null, input.paymentMethod ?? null);
297
298
  }
298
299
  listInferenceLedger() {
299
300
  const rows = this.db.prepare(`SELECT request_id, seller_key, model_id, endpoint, status, prompt_tokens,
@@ -307,7 +308,7 @@ export class BuyerStore {
307
308
  balance_snapshot_micros, balance_source,
308
309
  prompt_hash, response_hash, created_at,
309
310
  ttft_ms, fallback_count, route_reason, fallover_chain_json, upstream_status,
310
- duration_ms, payment_method
311
+ duration_ms, avg_output_tokens_per_second, payment_method
311
312
  FROM inference_ledger
312
313
  ORDER BY id ASC`).all();
313
314
  return rows.map(row => ({
@@ -352,6 +353,7 @@ export class BuyerStore {
352
353
  falloverChain: row.fallover_chain_json ? JSON.parse(row.fallover_chain_json) : undefined,
353
354
  upstreamStatus: row.upstream_status ?? undefined,
354
355
  durationMs: row.duration_ms ?? undefined,
356
+ avgOutputTokensPerSecond: row.avg_output_tokens_per_second ?? undefined,
355
357
  paymentMethod: row.payment_method ?? undefined
356
358
  }));
357
359
  }
@@ -454,6 +456,7 @@ export class BuyerStore {
454
456
  fallover_chain_json TEXT,
455
457
  upstream_status TEXT,
456
458
  duration_ms INTEGER,
459
+ avg_output_tokens_per_second REAL,
457
460
  payment_method TEXT
458
461
  );
459
462
 
@@ -523,10 +526,46 @@ export class BuyerStore {
523
526
  ["fallover_chain_json", "TEXT"],
524
527
  ["upstream_status", "TEXT"],
525
528
  ["duration_ms", "INTEGER"],
529
+ ["avg_output_tokens_per_second", "REAL"],
526
530
  ["payment_method", "TEXT"]
527
531
  ]) {
528
532
  this.ensureColumn("inference_ledger", column, definition);
529
533
  }
534
+ this.backfillPurchasePaymentAmountsFromPending();
535
+ }
536
+ backfillPurchasePaymentAmountsFromPending() {
537
+ this.db.prepare(`UPDATE purchase_ledger
538
+ SET payment_amount = (
539
+ SELECT printf('%.4f', pending_purchases.amount_usd_micros / 1000000.0)
540
+ FROM pending_purchases
541
+ WHERE pending_purchases.purchase_id = purchase_ledger.purchase_id
542
+ ),
543
+ payment_amount_minor = (
544
+ SELECT CAST(ROUND(pending_purchases.amount_usd_micros / 10000.0) AS INTEGER)
545
+ FROM pending_purchases
546
+ WHERE pending_purchases.purchase_id = purchase_ledger.purchase_id
547
+ ),
548
+ payment_currency = 'USD'
549
+ WHERE (payment_amount IS NULL OR payment_amount = '' OR payment_amount_minor IS NULL OR payment_currency IS NULL OR payment_currency = '')
550
+ AND EXISTS (
551
+ SELECT 1
552
+ FROM pending_purchases
553
+ WHERE pending_purchases.purchase_id = purchase_ledger.purchase_id
554
+ AND pending_purchases.amount_usd_micros >= 0
555
+ )`).run();
556
+ }
557
+ pendingPurchasePaymentSummary(purchaseId) {
558
+ const row = this.db.prepare(`SELECT amount_usd_micros
559
+ FROM pending_purchases
560
+ WHERE purchase_id = ?`).get(purchaseId);
561
+ if (!row || !Number.isFinite(row.amount_usd_micros) || row.amount_usd_micros < 0) {
562
+ return undefined;
563
+ }
564
+ return {
565
+ paymentAmount: (row.amount_usd_micros / 1_000_000).toFixed(4),
566
+ paymentAmountMinor: Math.round(row.amount_usd_micros / 10_000),
567
+ paymentCurrency: "USD"
568
+ };
530
569
  }
531
570
  ensureColumn(table, column, definition) {
532
571
  const rows = this.db.prepare(`PRAGMA table_info(${table})`).all();
package/dist/src/cli.js CHANGED
@@ -6,7 +6,7 @@ import * as os from "os";
6
6
  import { execFileSync, spawn } from "child_process";
7
7
  import Table from "cli-table3";
8
8
  import { BuyerStore } from "./buyer-store.js";
9
- import { applyProviderInstall, detectProviders, getProviderModelSelectionKind, getProviderProtocolPreference, } from "./provider-install.js";
9
+ import { applyProviderInstall, detectProviders, getProviderModelSelectionKind, getProviderProtocolPreference, PROXY_ACCESS_TOKEN_PLACEHOLDER, } from "./provider-install.js";
10
10
  import { createModuleLogger } from "@tokenbuddy/logging";
11
11
  import * as crypto from "crypto";
12
12
  import { fileURLToPath } from "url";
@@ -1511,7 +1511,7 @@ export function buildCli() {
1511
1511
  "✅ OpenAI-compatible Proxy",
1512
1512
  " URL: http://127.0.0.1:17821/v1",
1513
1513
  " Probe: http://127.0.0.1:17821/v1/models",
1514
- " Token: TOKENBUDDY_PROXY",
1514
+ ` Token: ${PROXY_ACCESS_TOKEN_PLACEHOLDER}`,
1515
1515
  "",
1516
1516
  "✅ Anthropic-compatible Proxy",
1517
1517
  " URL: http://127.0.0.1:17821"
@@ -142,6 +142,7 @@ export declare class TokenbuddyDaemon {
142
142
  private resolveClaudeRoleModel;
143
143
  private resolveRouteModelId;
144
144
  private applyResolvedModelToBody;
145
+ private withOpenAiStreamUsage;
145
146
  private defaultPaymentMethod;
146
147
  private selectManualProviderRoutes;
147
148
  private selectSellerRoutes;
@@ -173,7 +174,11 @@ export declare class TokenbuddyDaemon {
173
174
  private sellerCatalogWithRuntimeMetrics;
174
175
  private refreshSellerRouteMetadata;
175
176
  private routeMetricFromPoolEntry;
177
+ private routeStateFromPoolEntry;
178
+ private routeStateFromCatalogStatus;
176
179
  private readUsage;
180
+ private usageSummaryFromData;
181
+ private readUsageFromSse;
177
182
  private parseSellerSettlementSummary;
178
183
  private recordReconciledInference;
179
184
  private refreshSellerBalance;
@@ -190,6 +195,7 @@ export declare class TokenbuddyDaemon {
190
195
  * `TB_PROXYD_REQUEST_DEADLINE_MS` (default 180s).
191
196
  */
192
197
  private requestDeadlineMs;
198
+ private userInferenceTestTimeoutMs;
193
199
  /**
194
200
  * Safety margin subtracted from the cached token's `expiresAt` before
195
201
  * deciding to reuse it. Buying a new token 60s before expiry gives the
@@ -206,6 +212,12 @@ export declare class TokenbuddyDaemon {
206
212
  private manualProviderEndpointUrl;
207
213
  private manualProviderEndpointUrlFromBase;
208
214
  private probeManualProviderModels;
215
+ private probeManualProviderProtocols;
216
+ private probeManualProviderProtocol;
217
+ private probeManualProviderProtocolModel;
218
+ private testManualProviderInference;
219
+ private testSellerInference;
220
+ private recordManualProviderProbeResult;
209
221
  private manualProviderErrorClass;
210
222
  private shouldFailoverManualProvider;
211
223
  private fetchManualProviderRoute;