@polka-codes/core 0.9.100 → 0.9.102
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/_tsup-dts-rollup.d.ts +55 -2
- package/dist/index.d.ts +4 -1
- package/dist/index.js +238 -33
- package/package.json +1 -1
|
@@ -330,6 +330,7 @@ declare const configSchema: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
|
330
330
|
}>>>;
|
|
331
331
|
path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
332
332
|
}, z.core.$strict>>;
|
|
333
|
+
loadRules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
333
334
|
}, z.core.$strict>>>;
|
|
334
335
|
export { configSchema }
|
|
335
336
|
export { configSchema as configSchema_alias_1 }
|
|
@@ -363,6 +364,12 @@ export { convertJsonSchemaToZod }
|
|
|
363
364
|
export { convertJsonSchemaToZod as convertJsonSchemaToZod_alias_1 }
|
|
364
365
|
export { convertJsonSchemaToZod as convertJsonSchemaToZod_alias_2 }
|
|
365
366
|
|
|
367
|
+
/**
|
|
368
|
+
* Convert Portkey pricing (cents per token) to ModelInfo (USD per 1M tokens)
|
|
369
|
+
* Formula: cents_per_token * 10 = usd_per_1M_tokens
|
|
370
|
+
*/
|
|
371
|
+
export declare function convertPortkeyToModelInfo(portkey: PortkeyPricingResponse): ModelInfo;
|
|
372
|
+
|
|
366
373
|
declare function createContext<TTools extends ToolRegistry>(tools: WorkflowTools<TTools>, stepFn?: StepFn, logger?: Logger): WorkflowContext<TTools>;
|
|
367
374
|
export { createContext }
|
|
368
375
|
export { createContext as createContext_alias_1 }
|
|
@@ -889,6 +896,8 @@ export { ExitReason }
|
|
|
889
896
|
export { ExitReason as ExitReason_alias_1 }
|
|
890
897
|
export { ExitReason as ExitReason_alias_2 }
|
|
891
898
|
|
|
899
|
+
export declare function fetchPricing(provider: string, model: string): Promise<PortkeyPricingResponse | null>;
|
|
900
|
+
|
|
892
901
|
/**
|
|
893
902
|
* File statistics
|
|
894
903
|
*/
|
|
@@ -1654,6 +1663,8 @@ declare type ModelInfo = {
|
|
|
1654
1663
|
};
|
|
1655
1664
|
export { ModelInfo }
|
|
1656
1665
|
export { ModelInfo as ModelInfo_alias_1 }
|
|
1666
|
+
export { ModelInfo as ModelInfo_alias_2 }
|
|
1667
|
+
export { ModelInfo as ModelInfo_alias_3 }
|
|
1657
1668
|
|
|
1658
1669
|
/**
|
|
1659
1670
|
* Node.js file system provider implementation
|
|
@@ -1695,12 +1706,51 @@ export { ParseOutputResult }
|
|
|
1695
1706
|
export { ParseOutputResult as ParseOutputResult_alias_1 }
|
|
1696
1707
|
export { ParseOutputResult as ParseOutputResult_alias_2 }
|
|
1697
1708
|
|
|
1709
|
+
declare interface PortkeyPricingConfig {
|
|
1710
|
+
provider: string;
|
|
1711
|
+
model: string;
|
|
1712
|
+
pricing: PortkeyPricingResponse;
|
|
1713
|
+
}
|
|
1714
|
+
export { PortkeyPricingConfig }
|
|
1715
|
+
export { PortkeyPricingConfig as PortkeyPricingConfig_alias_1 }
|
|
1716
|
+
export { PortkeyPricingConfig as PortkeyPricingConfig_alias_2 }
|
|
1717
|
+
|
|
1718
|
+
declare interface PortkeyPricingResponse {
|
|
1719
|
+
request_token?: {
|
|
1720
|
+
price: number;
|
|
1721
|
+
};
|
|
1722
|
+
response_token?: {
|
|
1723
|
+
price: number;
|
|
1724
|
+
};
|
|
1725
|
+
cache_write_input_token?: {
|
|
1726
|
+
price: number;
|
|
1727
|
+
};
|
|
1728
|
+
cache_read_input_token?: {
|
|
1729
|
+
price: number;
|
|
1730
|
+
};
|
|
1731
|
+
additional_units?: Record<string, {
|
|
1732
|
+
price: number;
|
|
1733
|
+
}>;
|
|
1734
|
+
}
|
|
1735
|
+
export { PortkeyPricingResponse }
|
|
1736
|
+
export { PortkeyPricingResponse as PortkeyPricingResponse_alias_1 }
|
|
1737
|
+
export { PortkeyPricingResponse as PortkeyPricingResponse_alias_2 }
|
|
1738
|
+
|
|
1698
1739
|
/**
|
|
1699
1740
|
* Simplify boolean string preprocessing
|
|
1700
1741
|
* Converts 'true'/'false' strings to actual booleans
|
|
1701
1742
|
*/
|
|
1702
1743
|
export declare function preprocessBoolean(val: unknown): unknown;
|
|
1703
1744
|
|
|
1745
|
+
declare class PricingService {
|
|
1746
|
+
#private;
|
|
1747
|
+
constructor(fallbackPrices?: Record<string, Record<string, Partial<ModelInfo>>>);
|
|
1748
|
+
getPricing(provider: string, model: string): Promise<ModelInfo>;
|
|
1749
|
+
}
|
|
1750
|
+
export { PricingService }
|
|
1751
|
+
export { PricingService as PricingService_alias_1 }
|
|
1752
|
+
export { PricingService as PricingService_alias_2 }
|
|
1753
|
+
|
|
1704
1754
|
declare type ProviderConfig = z.infer<typeof providerConfigSchema>;
|
|
1705
1755
|
export { ProviderConfig }
|
|
1706
1756
|
export { ProviderConfig as ProviderConfig_alias_1 }
|
|
@@ -2637,6 +2687,7 @@ declare class UsageMeter {
|
|
|
2637
2687
|
constructor(modelInfos?: Record<string, Record<string, Partial<ModelInfo>>>, opts?: {
|
|
2638
2688
|
maxMessages?: number;
|
|
2639
2689
|
maxCost?: number;
|
|
2690
|
+
pricingService?: PricingService;
|
|
2640
2691
|
});
|
|
2641
2692
|
addUsage(llm: LanguageModelV2, resp: {
|
|
2642
2693
|
usage: LanguageModelV2Usage;
|
|
@@ -2646,7 +2697,7 @@ declare class UsageMeter {
|
|
|
2646
2697
|
providerMetadata?: any;
|
|
2647
2698
|
}, options?: {
|
|
2648
2699
|
modelInfo?: ModelInfo;
|
|
2649
|
-
}): void
|
|
2700
|
+
}): Promise<void>;
|
|
2650
2701
|
/** Override the running totals (e.g., restore from saved state). */
|
|
2651
2702
|
setUsage(newUsage: Partial<Totals>, options?: {
|
|
2652
2703
|
clearMetadata?: boolean;
|
|
@@ -2687,11 +2738,13 @@ declare class UsageMeter {
|
|
|
2687
2738
|
clearProviderMetadata(): void;
|
|
2688
2739
|
/** Merge another UsageMeter's totals into this one. */
|
|
2689
2740
|
merge(other: UsageMeter): void;
|
|
2741
|
+
/** Wait for all pending usage updates to complete. */
|
|
2742
|
+
waitForPending(): Promise<void>;
|
|
2690
2743
|
getUsageText(): string;
|
|
2691
2744
|
onFinishHandler(llm: LanguageModelV2): (evt: {
|
|
2692
2745
|
totalUsage: LanguageModelV2Usage;
|
|
2693
2746
|
providerMetadata: any;
|
|
2694
|
-
}) => void
|
|
2747
|
+
}) => Promise<void>;
|
|
2695
2748
|
}
|
|
2696
2749
|
export { UsageMeter }
|
|
2697
2750
|
export { UsageMeter as UsageMeter_alias_1 }
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,10 @@ export { MemoryOperation } from './_tsup-dts-rollup.js';
|
|
|
40
40
|
export { DatabaseStats } from './_tsup-dts-rollup.js';
|
|
41
41
|
export { IMemoryStore } from './_tsup-dts-rollup.js';
|
|
42
42
|
export { MemoryStoreConfig } from './_tsup-dts-rollup.js';
|
|
43
|
+
export { PricingService } from './_tsup-dts-rollup.js';
|
|
44
|
+
export { ModelInfo_alias_1 as ModelInfo } from './_tsup-dts-rollup.js';
|
|
45
|
+
export { PortkeyPricingConfig } from './_tsup-dts-rollup.js';
|
|
46
|
+
export { PortkeyPricingResponse } from './_tsup-dts-rollup.js';
|
|
43
47
|
export { SKILL_LIMITS } from './_tsup-dts-rollup.js';
|
|
44
48
|
export { IGNORED_DIRECTORIES } from './_tsup-dts-rollup.js';
|
|
45
49
|
export { SUSPICIOUS_PATTERNS } from './_tsup-dts-rollup.js';
|
|
@@ -117,7 +121,6 @@ export { UpdateTodoItemInputSchema } from './_tsup-dts-rollup.js';
|
|
|
117
121
|
export { UpdateTodoItemInput } from './_tsup-dts-rollup.js';
|
|
118
122
|
export { UpdateTodoItemOutputSchema } from './_tsup-dts-rollup.js';
|
|
119
123
|
export { UpdateTodoItemOutput } from './_tsup-dts-rollup.js';
|
|
120
|
-
export { ModelInfo_alias_1 as ModelInfo } from './_tsup-dts-rollup.js';
|
|
121
124
|
export { UsageMeter_alias_1 as UsageMeter } from './_tsup-dts-rollup.js';
|
|
122
125
|
export { deepMerge } from './_tsup-dts-rollup.js';
|
|
123
126
|
export { AgentWorkflowInput } from './_tsup-dts-rollup.js';
|
package/dist/index.js
CHANGED
|
@@ -329,7 +329,8 @@ var configSchema = z3.object({
|
|
|
329
329
|
rules: z3.array(ruleSchema).optional().or(z3.string()).optional(),
|
|
330
330
|
excludeFiles: z3.array(z3.string()).optional(),
|
|
331
331
|
agent: agentSchema,
|
|
332
|
-
memory: memoryConfigSchema
|
|
332
|
+
memory: memoryConfigSchema,
|
|
333
|
+
loadRules: z3.record(z3.string(), z3.boolean()).optional()
|
|
333
334
|
}).strict().nullish();
|
|
334
335
|
|
|
335
336
|
// src/errors/base.ts
|
|
@@ -402,6 +403,179 @@ var NodeFileSystemProvider = class {
|
|
|
402
403
|
}
|
|
403
404
|
};
|
|
404
405
|
|
|
406
|
+
// src/pricing/pricing-service.ts
|
|
407
|
+
import { randomUUID } from "crypto";
|
|
408
|
+
import { mkdir, readFile as readFile2, rename, writeFile } from "fs/promises";
|
|
409
|
+
import { homedir } from "os";
|
|
410
|
+
import { dirname, join as join2 } from "path";
|
|
411
|
+
|
|
412
|
+
// src/pricing/converter.ts
|
|
413
|
+
function convertPortkeyToModelInfo(portkey) {
|
|
414
|
+
return {
|
|
415
|
+
inputPrice: (portkey.request_token?.price ?? 0) * 10,
|
|
416
|
+
outputPrice: (portkey.response_token?.price ?? 0) * 10,
|
|
417
|
+
cacheWritesPrice: (portkey.cache_write_input_token?.price ?? 0) * 10,
|
|
418
|
+
cacheReadsPrice: (portkey.cache_read_input_token?.price ?? 0) * 10
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/pricing/portkey-client.ts
|
|
423
|
+
var PORTKEY_BASE_URL = "https://api.portkey.ai/model-configs/pricing";
|
|
424
|
+
var TIMEOUT_MS = 5e3;
|
|
425
|
+
var MAX_RETRIES = 2;
|
|
426
|
+
async function fetchWithTimeout(url, timeoutMs) {
|
|
427
|
+
const controller = new AbortController();
|
|
428
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
429
|
+
try {
|
|
430
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
431
|
+
return response;
|
|
432
|
+
} finally {
|
|
433
|
+
clearTimeout(timeout);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
async function sleep(ms) {
|
|
437
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
438
|
+
}
|
|
439
|
+
function shouldRetry(response, error) {
|
|
440
|
+
if (error) return true;
|
|
441
|
+
if (response.status >= 500) return true;
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
async function fetchPricing(provider, model) {
|
|
445
|
+
const url = `${PORTKEY_BASE_URL}/${provider}/${model}`;
|
|
446
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
447
|
+
try {
|
|
448
|
+
const response = await fetchWithTimeout(url, TIMEOUT_MS);
|
|
449
|
+
if (!response.ok) {
|
|
450
|
+
if (!shouldRetry(response, null)) {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
if (attempt < MAX_RETRIES) {
|
|
454
|
+
await sleep(2 ** attempt * 1e3);
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
const data = await response.json();
|
|
460
|
+
return data;
|
|
461
|
+
} catch (error) {
|
|
462
|
+
if (attempt < MAX_RETRIES && shouldRetry(new Response(null, { status: 500 }), error)) {
|
|
463
|
+
await sleep(2 ** attempt * 1e3);
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// src/pricing/pricing-service.ts
|
|
473
|
+
var CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
474
|
+
var PricingService = class {
|
|
475
|
+
#fallbackPrices;
|
|
476
|
+
#cacheFile;
|
|
477
|
+
#cache = null;
|
|
478
|
+
#loadPromise = null;
|
|
479
|
+
constructor(fallbackPrices = {}) {
|
|
480
|
+
const normalized = {};
|
|
481
|
+
for (const [provider, providerInfo] of Object.entries(fallbackPrices)) {
|
|
482
|
+
const normalizedProvider = provider.split("-")[0];
|
|
483
|
+
normalized[normalizedProvider] = {};
|
|
484
|
+
for (const [model, modelInfo] of Object.entries(providerInfo)) {
|
|
485
|
+
const normalizedModel = model.replace(/[.-]/g, "");
|
|
486
|
+
normalized[normalizedProvider][normalizedModel] = {
|
|
487
|
+
inputPrice: modelInfo.inputPrice ?? 0,
|
|
488
|
+
outputPrice: modelInfo.outputPrice ?? 0,
|
|
489
|
+
cacheWritesPrice: modelInfo.cacheWritesPrice ?? 0,
|
|
490
|
+
cacheReadsPrice: modelInfo.cacheReadsPrice ?? 0
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
this.#fallbackPrices = normalized;
|
|
495
|
+
this.#cacheFile = join2(homedir(), ".config", "polkacodes", "pricing-cache.json");
|
|
496
|
+
}
|
|
497
|
+
async #load() {
|
|
498
|
+
if (this.#loadPromise) {
|
|
499
|
+
return this.#loadPromise;
|
|
500
|
+
}
|
|
501
|
+
this.#loadPromise = (async () => {
|
|
502
|
+
this.#cache = /* @__PURE__ */ new Map();
|
|
503
|
+
try {
|
|
504
|
+
const content = await readFile2(this.#cacheFile, "utf-8");
|
|
505
|
+
const data = JSON.parse(content);
|
|
506
|
+
for (const [key, value] of Object.entries(data)) {
|
|
507
|
+
this.#cache.set(key, value);
|
|
508
|
+
}
|
|
509
|
+
} catch {
|
|
510
|
+
}
|
|
511
|
+
})();
|
|
512
|
+
return this.#loadPromise;
|
|
513
|
+
}
|
|
514
|
+
async #get(provider, model) {
|
|
515
|
+
await this.#load();
|
|
516
|
+
const key = `${provider}:${model}`;
|
|
517
|
+
const entry = this.#cache?.get(key);
|
|
518
|
+
if (!entry) {
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
if (Date.now() - entry.timestamp > CACHE_TTL_MS) {
|
|
522
|
+
this.#cache?.delete(key);
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
return entry.pricing;
|
|
526
|
+
}
|
|
527
|
+
async #set(provider, model, pricing) {
|
|
528
|
+
await this.#load();
|
|
529
|
+
const key = `${provider}:${model}`;
|
|
530
|
+
this.#cache?.set(key, {
|
|
531
|
+
pricing,
|
|
532
|
+
timestamp: Date.now()
|
|
533
|
+
});
|
|
534
|
+
await this.#save();
|
|
535
|
+
}
|
|
536
|
+
async #save() {
|
|
537
|
+
if (!this.#cache) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
const dir = dirname(this.#cacheFile);
|
|
542
|
+
await mkdir(dir, { recursive: true });
|
|
543
|
+
const data = {};
|
|
544
|
+
for (const [key, value] of this.#cache.entries()) {
|
|
545
|
+
data[key] = value;
|
|
546
|
+
}
|
|
547
|
+
const tempFile = `${this.#cacheFile}.${randomUUID()}.tmp`;
|
|
548
|
+
await writeFile(tempFile, JSON.stringify(data, null, 2), "utf-8");
|
|
549
|
+
await rename(tempFile, this.#cacheFile);
|
|
550
|
+
} catch {
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
async getPricing(provider, model) {
|
|
554
|
+
const normalizedProvider = provider.split("-")[0];
|
|
555
|
+
const normalizedModel = model.replace(/[.-]/g, "");
|
|
556
|
+
const cached = await this.#get(normalizedProvider, normalizedModel);
|
|
557
|
+
if (cached) {
|
|
558
|
+
return cached;
|
|
559
|
+
}
|
|
560
|
+
const fallbackPrice = this.#fallbackPrices[normalizedProvider]?.[normalizedModel];
|
|
561
|
+
if (fallbackPrice) {
|
|
562
|
+
return fallbackPrice;
|
|
563
|
+
}
|
|
564
|
+
const portkeyPricing = await fetchPricing(normalizedProvider, model);
|
|
565
|
+
if (portkeyPricing) {
|
|
566
|
+
const modelInfo = convertPortkeyToModelInfo(portkeyPricing);
|
|
567
|
+
await this.#set(normalizedProvider, normalizedModel, modelInfo);
|
|
568
|
+
return modelInfo;
|
|
569
|
+
}
|
|
570
|
+
return {
|
|
571
|
+
inputPrice: 0,
|
|
572
|
+
outputPrice: 0,
|
|
573
|
+
cacheWritesPrice: 0,
|
|
574
|
+
cacheReadsPrice: 0
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
|
|
405
579
|
// src/skills/constants.ts
|
|
406
580
|
var SKILL_LIMITS = {
|
|
407
581
|
MAX_FILE_SIZE: 1024 * 1024,
|
|
@@ -455,7 +629,7 @@ var SOURCE_ICONS = {
|
|
|
455
629
|
};
|
|
456
630
|
|
|
457
631
|
// src/skills/discovery.ts
|
|
458
|
-
import { homedir } from "os";
|
|
632
|
+
import { homedir as homedir2 } from "os";
|
|
459
633
|
import { parse } from "yaml";
|
|
460
634
|
import { ZodError } from "zod";
|
|
461
635
|
|
|
@@ -545,7 +719,7 @@ var SkillDiscoveryService = class {
|
|
|
545
719
|
pluginSkillsDirs;
|
|
546
720
|
constructor(options) {
|
|
547
721
|
this.fs = options.fs ?? new NodeFileSystemProvider();
|
|
548
|
-
this.personalSkillsDir = options.personalSkillsDir ?? this.fs.join(
|
|
722
|
+
this.personalSkillsDir = options.personalSkillsDir ?? this.fs.join(homedir2(), ".claude", "skills");
|
|
549
723
|
this.projectSkillsDir = this.fs.join(options.cwd, ".claude", "skills");
|
|
550
724
|
this.pluginSkillsDirs = options.pluginSkillsDirs ?? [];
|
|
551
725
|
}
|
|
@@ -787,19 +961,19 @@ var SkillDiscoveryService = class {
|
|
|
787
961
|
};
|
|
788
962
|
|
|
789
963
|
// src/skills/validation.ts
|
|
790
|
-
import { join as
|
|
964
|
+
import { join as join3, normalize as normalize2 } from "path";
|
|
791
965
|
function validateSkillSecurity(skill) {
|
|
792
966
|
const { MAX_FILE_SIZE, MAX_SKILL_SIZE } = SKILL_LIMITS;
|
|
793
967
|
let totalSize = 0;
|
|
794
968
|
const contentSize = Buffer.byteLength(skill.content, "utf8");
|
|
795
969
|
if (contentSize > MAX_FILE_SIZE) {
|
|
796
|
-
throw new SkillValidationError(`SKILL.md content exceeds size limit (${contentSize} > ${MAX_FILE_SIZE})`,
|
|
970
|
+
throw new SkillValidationError(`SKILL.md content exceeds size limit (${contentSize} > ${MAX_FILE_SIZE})`, join3(skill.path, "SKILL.md"));
|
|
797
971
|
}
|
|
798
972
|
totalSize += contentSize;
|
|
799
973
|
for (const [filename, content] of skill.files) {
|
|
800
974
|
const fileSize = Buffer.byteLength(content, "utf8");
|
|
801
975
|
if (fileSize > MAX_FILE_SIZE) {
|
|
802
|
-
throw new SkillValidationError(`File ${filename} exceeds size limit (${fileSize} > ${MAX_FILE_SIZE})`,
|
|
976
|
+
throw new SkillValidationError(`File ${filename} exceeds size limit (${fileSize} > ${MAX_FILE_SIZE})`, join3(skill.path, filename));
|
|
803
977
|
}
|
|
804
978
|
totalSize += fileSize;
|
|
805
979
|
}
|
|
@@ -808,7 +982,7 @@ function validateSkillSecurity(skill) {
|
|
|
808
982
|
}
|
|
809
983
|
validateContentSecurity(skill.content, skill.path);
|
|
810
984
|
for (const [filename, content] of skill.files) {
|
|
811
|
-
validateContentSecurity(content,
|
|
985
|
+
validateContentSecurity(content, join3(skill.path, filename));
|
|
812
986
|
}
|
|
813
987
|
}
|
|
814
988
|
function validateContentSecurity(content, path) {
|
|
@@ -2270,9 +2444,11 @@ var writeToFile_default = {
|
|
|
2270
2444
|
var UsageMeter = class {
|
|
2271
2445
|
#totals = { input: 0, output: 0, cachedRead: 0, cost: 0, messageCount: 0 };
|
|
2272
2446
|
#providerMetadataEntries = [];
|
|
2447
|
+
#pendingUpdates = /* @__PURE__ */ new Set();
|
|
2273
2448
|
#modelInfos;
|
|
2274
2449
|
#maxMessages;
|
|
2275
2450
|
#maxCost;
|
|
2451
|
+
#pricingService;
|
|
2276
2452
|
constructor(modelInfos = {}, opts = {}) {
|
|
2277
2453
|
const infos = {};
|
|
2278
2454
|
for (const [provider, providerInfo] of Object.entries(modelInfos)) {
|
|
@@ -2288,6 +2464,7 @@ var UsageMeter = class {
|
|
|
2288
2464
|
this.#modelInfos = infos;
|
|
2289
2465
|
this.#maxMessages = opts.maxMessages ?? 1e3;
|
|
2290
2466
|
this.#maxCost = opts.maxCost ?? 100;
|
|
2467
|
+
this.#pricingService = opts.pricingService;
|
|
2291
2468
|
}
|
|
2292
2469
|
#calculateUsage(usage, providerMetadata, modelInfo) {
|
|
2293
2470
|
const providerMetadataKey = Object.keys(providerMetadata ?? {})[0];
|
|
@@ -2338,30 +2515,52 @@ var UsageMeter = class {
|
|
|
2338
2515
|
}
|
|
2339
2516
|
}
|
|
2340
2517
|
addUsage(llm, resp, options = {}) {
|
|
2341
|
-
const
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2518
|
+
const provider = llm.provider.split(".")[0];
|
|
2519
|
+
const normalizedModel = llm.modelId.replace(/[.-]/g, "");
|
|
2520
|
+
const key = `${provider}:${normalizedModel}`;
|
|
2521
|
+
let modelInfo = options.modelInfo ?? this.#modelInfos[key];
|
|
2522
|
+
const updatePromise = (async () => {
|
|
2523
|
+
try {
|
|
2524
|
+
if (!modelInfo && this.#pricingService) {
|
|
2525
|
+
modelInfo = await this.#pricingService.getPricing(provider, llm.modelId);
|
|
2526
|
+
this.#modelInfos[key] = modelInfo;
|
|
2527
|
+
}
|
|
2528
|
+
} catch {
|
|
2529
|
+
modelInfo = {
|
|
2530
|
+
inputPrice: 0,
|
|
2531
|
+
outputPrice: 0,
|
|
2532
|
+
cacheWritesPrice: 0,
|
|
2533
|
+
cacheReadsPrice: 0
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
modelInfo = modelInfo ?? {
|
|
2537
|
+
inputPrice: 0,
|
|
2538
|
+
outputPrice: 0,
|
|
2539
|
+
cacheWritesPrice: 0,
|
|
2540
|
+
cacheReadsPrice: 0
|
|
2541
|
+
};
|
|
2542
|
+
const usage = "totalUsage" in resp ? resp.totalUsage : resp.usage;
|
|
2543
|
+
const result = this.#calculateUsage(usage, resp.providerMetadata, modelInfo);
|
|
2544
|
+
this.#totals.input += result.input || 0;
|
|
2545
|
+
this.#totals.output += result.output || 0;
|
|
2546
|
+
this.#totals.cachedRead += result.cachedRead || 0;
|
|
2547
|
+
this.#totals.cost += result.cost || 0;
|
|
2548
|
+
this.#totals.messageCount += 1;
|
|
2549
|
+
if (resp.providerMetadata && Object.keys(resp.providerMetadata).length > 0) {
|
|
2550
|
+
const providerKey = Object.keys(resp.providerMetadata)[0];
|
|
2551
|
+
this.#providerMetadataEntries.push({
|
|
2552
|
+
provider: providerKey || llm.provider,
|
|
2553
|
+
model: llm.modelId,
|
|
2554
|
+
metadata: resp.providerMetadata[providerKey] || resp.providerMetadata,
|
|
2555
|
+
timestamp: Date.now()
|
|
2556
|
+
});
|
|
2557
|
+
}
|
|
2558
|
+
})();
|
|
2559
|
+
this.#pendingUpdates.add(updatePromise);
|
|
2560
|
+
updatePromise.finally(() => {
|
|
2561
|
+
this.#pendingUpdates.delete(updatePromise);
|
|
2562
|
+
});
|
|
2563
|
+
return updatePromise;
|
|
2365
2564
|
}
|
|
2366
2565
|
/** Override the running totals (e.g., restore from saved state). */
|
|
2367
2566
|
setUsage(newUsage, options = {}) {
|
|
@@ -2452,13 +2651,18 @@ var UsageMeter = class {
|
|
|
2452
2651
|
this.#totals.messageCount += otherUsage.messageCount;
|
|
2453
2652
|
this.#providerMetadataEntries.push(...other.providerMetadata);
|
|
2454
2653
|
}
|
|
2654
|
+
/** Wait for all pending usage updates to complete. */
|
|
2655
|
+
async waitForPending() {
|
|
2656
|
+
const pending = Array.from(this.#pendingUpdates);
|
|
2657
|
+
await Promise.allSettled(pending);
|
|
2658
|
+
}
|
|
2455
2659
|
getUsageText() {
|
|
2456
2660
|
const u = this.usage;
|
|
2457
2661
|
return `Usage - messages: ${u.messageCount}, input: ${u.input}, cached: ${u.cachedRead}, output: ${u.output}, cost: $${u.cost.toFixed(4)}`;
|
|
2458
2662
|
}
|
|
2459
2663
|
onFinishHandler(llm) {
|
|
2460
|
-
return (evt) => {
|
|
2461
|
-
this.addUsage(llm, evt);
|
|
2664
|
+
return async (evt) => {
|
|
2665
|
+
await this.addUsage(llm, evt);
|
|
2462
2666
|
};
|
|
2463
2667
|
}
|
|
2464
2668
|
};
|
|
@@ -3775,6 +3979,7 @@ export {
|
|
|
3775
3979
|
LoadSkillOutputSchema,
|
|
3776
3980
|
MockProvider,
|
|
3777
3981
|
NodeFileSystemProvider,
|
|
3982
|
+
PricingService,
|
|
3778
3983
|
ReadSkillFileInputSchema,
|
|
3779
3984
|
ReadSkillFileOutputSchema,
|
|
3780
3985
|
SKILL_ERROR_MESSAGES,
|