@plumbus/core 0.4.2 → 0.6.0
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/README.md +2 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/ai/ai/cost-tracker.d.ts +93 -0
- package/dist/ai/ai/derive-ledger-usage.d.ts +10 -0
- package/dist/ai/ai/model-pricing.d.ts +51 -0
- package/dist/ai/ai/provider.d.ts +214 -0
- package/dist/ai/ai/refusal.d.ts +27 -0
- package/dist/ai/ai/usage-client.d.ts +30 -0
- package/dist/ai/ai-service.d.ts +1 -1
- package/dist/ai/ai-service.d.ts.map +1 -1
- package/dist/ai/ai-service.js +21 -16
- package/dist/ai/ai-service.js.map +1 -1
- package/dist/ai/cost-tracker.d.ts +17 -1
- package/dist/ai/cost-tracker.d.ts.map +1 -1
- package/dist/ai/cost-tracker.js +8 -6
- package/dist/ai/cost-tracker.js.map +1 -1
- package/dist/ai/derive-ledger-usage.d.ts +11 -0
- package/dist/ai/derive-ledger-usage.d.ts.map +1 -0
- package/dist/ai/derive-ledger-usage.js +36 -0
- package/dist/ai/derive-ledger-usage.js.map +1 -0
- package/dist/ai/index.d.ts +1 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +1 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/types/config.d.ts +72 -0
- package/dist/ai/types/enums.d.ts +73 -0
- package/dist/api/route-generator.d.ts.map +1 -1
- package/dist/api/route-generator.js +27 -14
- package/dist/api/route-generator.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +3 -1
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +38 -149
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +6 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +92 -4
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/event.d.ts.map +1 -1
- package/dist/cli/commands/event.js +3 -0
- package/dist/cli/commands/event.js.map +1 -1
- package/dist/cli/commands/events-ops.d.ts +4 -0
- package/dist/cli/commands/events-ops.d.ts.map +1 -0
- package/dist/cli/commands/events-ops.js +203 -0
- package/dist/cli/commands/events-ops.js.map +1 -0
- package/dist/cli/commands/flow-schedule-list.d.ts +31 -0
- package/dist/cli/commands/flow-schedule-list.d.ts.map +1 -0
- package/dist/cli/commands/flow-schedule-list.js +93 -0
- package/dist/cli/commands/flow-schedule-list.js.map +1 -0
- package/dist/cli/commands/flow.d.ts.map +1 -1
- package/dist/cli/commands/flow.js +75 -1
- package/dist/cli/commands/flow.js.map +1 -1
- package/dist/cli/commands/generate.d.ts +4 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +94 -3
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/index.d.ts +2 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +2 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +55 -4
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +2 -0
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/start.d.ts +3 -6
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +71 -180
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/verify.d.ts +3 -1
- package/dist/cli/commands/verify.d.ts.map +1 -1
- package/dist/cli/commands/verify.js +17 -9
- package/dist/cli/commands/verify.js.map +1 -1
- package/dist/cli/commands/voice.d.ts +12 -0
- package/dist/cli/commands/voice.d.ts.map +1 -0
- package/dist/cli/commands/voice.js +109 -0
- package/dist/cli/commands/voice.js.map +1 -0
- package/dist/cli/commands/worker.d.ts +19 -0
- package/dist/cli/commands/worker.d.ts.map +1 -0
- package/dist/cli/commands/worker.js +234 -0
- package/dist/cli/commands/worker.js.map +1 -0
- package/dist/cli/mcp-serve-context.d.ts +3 -0
- package/dist/cli/mcp-serve-context.d.ts.map +1 -1
- package/dist/cli/mcp-serve-context.js +133 -111
- package/dist/cli/mcp-serve-context.js.map +1 -1
- package/dist/cli/templates/resources.d.ts.map +1 -1
- package/dist/cli/templates/resources.js +7 -2
- package/dist/cli/templates/resources.js.map +1 -1
- package/dist/cli/utils.d.ts +4 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +9 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/voice-agent-bootstrap.d.ts +22 -0
- package/dist/cli/voice-agent-bootstrap.d.ts.map +1 -0
- package/dist/cli/voice-agent-bootstrap.js +12 -0
- package/dist/cli/voice-agent-bootstrap.js.map +1 -0
- package/dist/cli/voice-serve-context.d.ts +7 -0
- package/dist/cli/voice-serve-context.d.ts.map +1 -0
- package/dist/cli/voice-serve-context.js +26 -0
- package/dist/cli/voice-serve-context.js.map +1 -0
- package/dist/data/drift-inspector.d.ts +2 -2
- package/dist/data/drift-inspector.d.ts.map +1 -1
- package/dist/data/drift-inspector.js +2 -1
- package/dist/data/drift-inspector.js.map +1 -1
- package/dist/data/migration.d.ts.map +1 -1
- package/dist/data/migration.js +2 -0
- package/dist/data/migration.js.map +1 -1
- package/dist/define/defineCapability.d.ts +5 -0
- package/dist/define/defineCapability.d.ts.map +1 -1
- package/dist/define/defineCapability.js +23 -0
- package/dist/define/defineCapability.js.map +1 -1
- package/dist/errors/http.d.ts.map +1 -1
- package/dist/errors/http.js +1 -0
- package/dist/errors/http.js.map +1 -1
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +1 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/events/dispatcher.d.ts +4 -0
- package/dist/events/dispatcher.d.ts.map +1 -1
- package/dist/events/dispatcher.js +24 -1
- package/dist/events/dispatcher.js.map +1 -1
- package/dist/events/emitter.d.ts +2 -0
- package/dist/events/emitter.d.ts.map +1 -1
- package/dist/events/emitter.js +6 -3
- package/dist/events/emitter.js.map +1 -1
- package/dist/events/queue-adapter.d.ts +7 -0
- package/dist/events/queue-adapter.d.ts.map +1 -0
- package/dist/events/queue-adapter.js +4 -0
- package/dist/events/queue-adapter.js.map +1 -0
- package/dist/events/queue.d.ts +16 -13
- package/dist/events/queue.d.ts.map +1 -1
- package/dist/events/queue.js +79 -22
- package/dist/events/queue.js.map +1 -1
- package/dist/events/worker.d.ts +4 -0
- package/dist/events/worker.d.ts.map +1 -1
- package/dist/events/worker.js +47 -1
- package/dist/events/worker.js.map +1 -1
- package/dist/execution/canonical-name.d.ts +13 -0
- package/dist/execution/canonical-name.d.ts.map +1 -0
- package/dist/execution/canonical-name.js +17 -0
- package/dist/execution/canonical-name.js.map +1 -0
- package/dist/execution/capability-executor.d.ts +1 -1
- package/dist/execution/capability-executor.d.ts.map +1 -1
- package/dist/execution/capability-executor.js +52 -24
- package/dist/execution/capability-executor.js.map +1 -1
- package/dist/execution/capability-invocation.d.ts +34 -0
- package/dist/execution/capability-invocation.d.ts.map +1 -0
- package/dist/execution/capability-invocation.js +138 -0
- package/dist/execution/capability-invocation.js.map +1 -0
- package/dist/execution/capability-registry.d.ts +6 -4
- package/dist/execution/capability-registry.d.ts.map +1 -1
- package/dist/execution/capability-registry.js +13 -7
- package/dist/execution/capability-registry.js.map +1 -1
- package/dist/execution/context-factory.d.ts.map +1 -1
- package/dist/execution/context-factory.js +18 -1
- package/dist/execution/context-factory.js.map +1 -1
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +2 -0
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/invocation-emit-scope.d.ts +11 -0
- package/dist/execution/invocation-emit-scope.d.ts.map +1 -0
- package/dist/execution/invocation-emit-scope.js +8 -0
- package/dist/execution/invocation-emit-scope.js.map +1 -0
- package/dist/flows/engine.d.ts +7 -1
- package/dist/flows/engine.d.ts.map +1 -1
- package/dist/flows/engine.js +75 -10
- package/dist/flows/engine.js.map +1 -1
- package/dist/flows/flow-delayed.d.ts +34 -0
- package/dist/flows/flow-delayed.d.ts.map +1 -0
- package/dist/flows/flow-delayed.js +60 -0
- package/dist/flows/flow-delayed.js.map +1 -0
- package/dist/flows/flow-queue.d.ts +10 -0
- package/dist/flows/flow-queue.d.ts.map +1 -0
- package/dist/flows/flow-queue.js +25 -0
- package/dist/flows/flow-queue.js.map +1 -0
- package/dist/flows/scheduler.d.ts +0 -12
- package/dist/flows/scheduler.d.ts.map +1 -1
- package/dist/flows/scheduler.js +15 -0
- package/dist/flows/scheduler.js.map +1 -1
- package/dist/flows/schema.d.ts +17 -0
- package/dist/flows/schema.d.ts.map +1 -1
- package/dist/flows/schema.js +2 -0
- package/dist/flows/schema.js.map +1 -1
- package/dist/flows/step-consumer.d.ts +24 -0
- package/dist/flows/step-consumer.d.ts.map +1 -0
- package/dist/flows/step-consumer.js +72 -0
- package/dist/flows/step-consumer.js.map +1 -0
- package/dist/flows/triggers.d.ts +1 -1
- package/dist/flows/triggers.d.ts.map +1 -1
- package/dist/flows/triggers.js +5 -7
- package/dist/flows/triggers.js.map +1 -1
- package/dist/governance/capability-source-scan.d.ts +7 -0
- package/dist/governance/capability-source-scan.d.ts.map +1 -0
- package/dist/governance/capability-source-scan.js +80 -0
- package/dist/governance/capability-source-scan.js.map +1 -0
- package/dist/governance/rules/architecture.d.ts.map +1 -1
- package/dist/governance/rules/architecture.js +2 -0
- package/dist/governance/rules/architecture.js.map +1 -1
- package/dist/governance/rules/capability-dependencies.d.ts +8 -0
- package/dist/governance/rules/capability-dependencies.d.ts.map +1 -0
- package/dist/governance/rules/capability-dependencies.js +195 -0
- package/dist/governance/rules/capability-dependencies.js.map +1 -0
- package/dist/governance/rules/index.d.ts +2 -0
- package/dist/governance/rules/index.d.ts.map +1 -1
- package/dist/governance/rules/index.js +2 -0
- package/dist/governance/rules/index.js.map +1 -1
- package/dist/governance/rules/worker.d.ts +9 -0
- package/dist/governance/rules/worker.d.ts.map +1 -0
- package/dist/governance/rules/worker.js +89 -0
- package/dist/governance/rules/worker.js.map +1 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/jobs/dispatch.d.ts +18 -0
- package/dist/jobs/dispatch.d.ts.map +1 -0
- package/dist/jobs/dispatch.js +50 -0
- package/dist/jobs/dispatch.js.map +1 -0
- package/dist/jobs/index.d.ts +9 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +8 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/routes.d.ts +10 -0
- package/dist/jobs/routes.d.ts.map +1 -0
- package/dist/jobs/routes.js +44 -0
- package/dist/jobs/routes.js.map +1 -0
- package/dist/jobs/schema.d.ts +264 -0
- package/dist/jobs/schema.d.ts.map +1 -0
- package/dist/jobs/schema.js +34 -0
- package/dist/jobs/schema.js.map +1 -0
- package/dist/jobs/service.d.ts +52 -0
- package/dist/jobs/service.d.ts.map +1 -0
- package/dist/jobs/service.js +168 -0
- package/dist/jobs/service.js.map +1 -0
- package/dist/jobs/types.d.ts +30 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +4 -0
- package/dist/jobs/types.js.map +1 -0
- package/dist/mcp/manifest-generator.d.ts.map +1 -1
- package/dist/mcp/manifest-generator.js +3 -2
- package/dist/mcp/manifest-generator.js.map +1 -1
- package/dist/observability/metrics.d.ts +9 -1
- package/dist/observability/metrics.d.ts.map +1 -1
- package/dist/observability/metrics.js +28 -1
- package/dist/observability/metrics.js.map +1 -1
- package/dist/runtime/bootstrap.d.ts +51 -0
- package/dist/runtime/bootstrap.d.ts.map +1 -0
- package/dist/runtime/bootstrap.js +140 -0
- package/dist/runtime/bootstrap.js.map +1 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +6 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/load-extensions.d.ts +4 -0
- package/dist/runtime/load-extensions.d.ts.map +1 -0
- package/dist/runtime/load-extensions.js +41 -0
- package/dist/runtime/load-extensions.js.map +1 -0
- package/dist/runtime/queue-factory.d.ts +44 -0
- package/dist/runtime/queue-factory.d.ts.map +1 -0
- package/dist/runtime/queue-factory.js +156 -0
- package/dist/runtime/queue-factory.js.map +1 -0
- package/dist/runtime/register-consumers.d.ts +29 -0
- package/dist/runtime/register-consumers.d.ts.map +1 -0
- package/dist/runtime/register-consumers.js +233 -0
- package/dist/runtime/register-consumers.js.map +1 -0
- package/dist/runtime/start-worker-pool.d.ts +32 -0
- package/dist/runtime/start-worker-pool.d.ts.map +1 -0
- package/dist/runtime/start-worker-pool.js +91 -0
- package/dist/runtime/start-worker-pool.js.map +1 -0
- package/dist/runtime/worker-health.d.ts +19 -0
- package/dist/runtime/worker-health.d.ts.map +1 -0
- package/dist/runtime/worker-health.js +41 -0
- package/dist/runtime/worker-health.js.map +1 -0
- package/dist/server/bootstrap.d.ts +6 -0
- package/dist/server/bootstrap.d.ts.map +1 -1
- package/dist/server/bootstrap.js +24 -1
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/testing/context.d.ts +3 -0
- package/dist/testing/context.d.ts.map +1 -1
- package/dist/testing/context.js +12 -0
- package/dist/testing/context.js.map +1 -1
- package/dist/testing/e2e.d.ts +6 -0
- package/dist/testing/e2e.d.ts.map +1 -1
- package/dist/testing/e2e.js +2 -0
- package/dist/testing/e2e.js.map +1 -1
- package/dist/testing/simulate-flow.d.ts.map +1 -1
- package/dist/testing/simulate-flow.js +10 -0
- package/dist/testing/simulate-flow.js.map +1 -1
- package/dist/types/capability.d.ts +8 -0
- package/dist/types/capability.d.ts.map +1 -1
- package/dist/types/capability.js.map +1 -1
- package/dist/types/config.d.ts +2 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/context.d.ts +49 -1
- package/dist/types/context.d.ts.map +1 -1
- package/dist/types/enums.d.ts +1 -0
- package/dist/types/enums.d.ts.map +1 -1
- package/dist/types/enums.js +1 -0
- package/dist/types/enums.js.map +1 -1
- package/dist/types/errors.d.ts +1 -0
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/event.d.ts +10 -0
- package/dist/types/event.d.ts.map +1 -1
- package/dist/types/event.js +5 -1
- package/dist/types/event.js.map +1 -1
- package/dist/worker/bootstrap.d.ts +32 -1
- package/dist/worker/bootstrap.d.ts.map +1 -1
- package/dist/worker/bootstrap.js +166 -2
- package/dist/worker/bootstrap.js.map +1 -1
- package/instructions/capabilities.md +36 -1
- package/instructions/deployment.md +96 -11
- package/instructions/events.md +11 -0
- package/instructions/flows.md +12 -4
- package/instructions/governance.md +6 -0
- package/instructions/mcp.md +1 -1
- package/instructions/patterns.md +1 -0
- package/instructions/security.md +9 -0
- package/instructions/testing.md +12 -1
- package/instructions/upgrading-0.5-capabilities.md +181 -0
- package/package.json +16 -4
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { TokenUsage } from './provider.js';
|
|
2
|
+
import type { UsageAPIClient } from './usage-client.js';
|
|
3
|
+
export interface AICostRecord {
|
|
4
|
+
id: string;
|
|
5
|
+
timestamp: Date;
|
|
6
|
+
model: string;
|
|
7
|
+
provider: string;
|
|
8
|
+
promptName?: string;
|
|
9
|
+
operation: 'generate' | 'extract' | 'classify' | 'embed' | 'transcribe' | 'synthesize' | 'transport';
|
|
10
|
+
/**
|
|
11
|
+
* True when the call originally streamed but fell back to a non-streaming
|
|
12
|
+
* retry after the streamed text failed JSON/schema validation. Both the
|
|
13
|
+
* original streamed attempt and the fallback attempt are billed, so this
|
|
14
|
+
* flag is the signal consumers use to detect duplicate billing for a
|
|
15
|
+
* single logical generation.
|
|
16
|
+
*/
|
|
17
|
+
fallbackUsed?: boolean;
|
|
18
|
+
usage: TokenUsage;
|
|
19
|
+
/**
|
|
20
|
+
* Optional provider-native media billing units for non-token workloads such
|
|
21
|
+
* as speech-to-text, text-to-speech, or realtime transport.
|
|
22
|
+
*/
|
|
23
|
+
mediaUsage?: {
|
|
24
|
+
audioInputSeconds?: number;
|
|
25
|
+
audioOutputSeconds?: number;
|
|
26
|
+
characters?: number;
|
|
27
|
+
connectionMinutes?: number;
|
|
28
|
+
participantMinutes?: number;
|
|
29
|
+
};
|
|
30
|
+
/** Actual cost from provider API, or null if API unavailable */
|
|
31
|
+
cost: number | null;
|
|
32
|
+
latencyMs: number;
|
|
33
|
+
tenantId?: string;
|
|
34
|
+
actor?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Whether the underlying provider call completed successfully. Failed rows
|
|
37
|
+
* still represent real provider-side spend and count toward budget caps.
|
|
38
|
+
* Defaults to 'success' inside `createCostTracker` when the caller does
|
|
39
|
+
* not set it, preserving pre-0.3.0 behavior for existing consumers.
|
|
40
|
+
*/
|
|
41
|
+
status: 'success' | 'failed' | 'refused' | 'incomplete';
|
|
42
|
+
/** Short description of the failure when `status !== 'success'`. */
|
|
43
|
+
errorMessage?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface BudgetConfig {
|
|
46
|
+
/** Max tokens per single request */
|
|
47
|
+
maxTokensPerRequest?: number;
|
|
48
|
+
/** Daily cost limit in USD */
|
|
49
|
+
dailyCostLimit?: number;
|
|
50
|
+
/** Per-tenant daily cost limit in USD */
|
|
51
|
+
perTenantDailyLimit?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Input type for {@link CostTracker.record}. `status` and `errorMessage` are
|
|
55
|
+
* optional so pre-0.3.0 call sites keep compiling; the tracker defaults
|
|
56
|
+
* `status` to `'success'` internally.
|
|
57
|
+
*/
|
|
58
|
+
export type AICostRecordInput = Omit<AICostRecord, 'id' | 'timestamp' | 'status'> & {
|
|
59
|
+
status?: AICostRecord['status'];
|
|
60
|
+
};
|
|
61
|
+
export interface CostTracker {
|
|
62
|
+
record(entry: AICostRecordInput): void;
|
|
63
|
+
checkBudget(config: {
|
|
64
|
+
tenantId?: string;
|
|
65
|
+
estimatedTokens?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Optional normalized USD estimate for non-token workloads. Voice/media
|
|
68
|
+
* layers can compute this ahead of time and pre-check shared daily caps.
|
|
69
|
+
*/
|
|
70
|
+
estimatedCostUsd?: number;
|
|
71
|
+
}): BudgetCheckResult;
|
|
72
|
+
getDailyUsage(tenantId?: string): DailyUsage;
|
|
73
|
+
getRecords(): AICostRecord[];
|
|
74
|
+
/** Fetch actual costs from provider usage APIs and update records */
|
|
75
|
+
syncCosts?(): Promise<UsageSyncResult>;
|
|
76
|
+
}
|
|
77
|
+
export interface BudgetCheckResult {
|
|
78
|
+
allowed: boolean;
|
|
79
|
+
reason?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface DailyUsage {
|
|
82
|
+
totalTokens: number;
|
|
83
|
+
totalCost: number;
|
|
84
|
+
/** Whether cost data is available from provider APIs */
|
|
85
|
+
costAvailable: boolean;
|
|
86
|
+
requestCount: number;
|
|
87
|
+
}
|
|
88
|
+
export interface UsageSyncResult {
|
|
89
|
+
synced: boolean;
|
|
90
|
+
totalCost?: number;
|
|
91
|
+
error?: string;
|
|
92
|
+
}
|
|
93
|
+
export declare function createCostTracker(budget?: BudgetConfig, usageClients?: UsageAPIClient[]): CostTracker;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AICostRecord } from './cost-tracker.js';
|
|
2
|
+
export type LedgerUsageKind = 'llm_tokens' | 'audio_seconds' | 'audio_output_seconds' | 'characters' | 'participant_minutes' | 'connection_minutes';
|
|
3
|
+
export interface DerivedLedgerUsage {
|
|
4
|
+
usageKind: LedgerUsageKind;
|
|
5
|
+
usageQuantity: number;
|
|
6
|
+
usageQuantitySecondary?: number;
|
|
7
|
+
}
|
|
8
|
+
type DeriveLedgerUsageInput = Pick<AICostRecord, 'usage' | 'mediaUsage' | 'operation'>;
|
|
9
|
+
export declare function deriveLedgerUsage(record: DeriveLedgerUsageInput): DerivedLedgerUsage;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability classification for a model. Drives the filter on
|
|
3
|
+
* `AIProviderAdapter.listModels({ kind })`.
|
|
4
|
+
*
|
|
5
|
+
* - `text`: chat / completion / reasoning (called via `complete` / `stream`)
|
|
6
|
+
* - `embedding`: text-embedding models (called via `embed`)
|
|
7
|
+
* - `moderation`: content-moderation classifiers
|
|
8
|
+
* - `image`: image generation
|
|
9
|
+
* - `audio`: speech-to-text / text-to-speech / realtime audio
|
|
10
|
+
*/
|
|
11
|
+
export type Kind = 'text' | 'embedding' | 'moderation' | 'image' | 'audio';
|
|
12
|
+
export interface ModelRate {
|
|
13
|
+
/** USD per 1M input tokens */
|
|
14
|
+
inputPerMTok: number;
|
|
15
|
+
/** USD per 1M output tokens (0 for embedding / moderation / free models) */
|
|
16
|
+
outputPerMTok: number;
|
|
17
|
+
/**
|
|
18
|
+
* Capability classification. Optional on the type for backward compat —
|
|
19
|
+
* existing consumers that destructure only the rate fields keep working —
|
|
20
|
+
* but every entry in `MODEL_PRICING` populates it.
|
|
21
|
+
*/
|
|
22
|
+
kind?: Kind;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Finds the per-token rate for a model.
|
|
26
|
+
* Tries exact match first, then strips trailing date suffixes
|
|
27
|
+
* (e.g. "claude-sonnet-4-20250514" → "claude-sonnet-4").
|
|
28
|
+
* Returns null for unknown/unsupported models (Ollama, custom).
|
|
29
|
+
*/
|
|
30
|
+
export declare function findModelRate(model: string): ModelRate | null;
|
|
31
|
+
/**
|
|
32
|
+
* Return all known model rates as an array of `[id, rate]` tuples. Used by
|
|
33
|
+
* `AIProviderAdapter.listModels()` to join live model ids against the pricing
|
|
34
|
+
* catalog. Order is not guaranteed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function allKnownModels(): ReadonlyArray<readonly [string, ModelRate]>;
|
|
37
|
+
/**
|
|
38
|
+
* Calculate the USD cost for a single AI request based on published per-token rates.
|
|
39
|
+
*
|
|
40
|
+
* Pricing adjustments applied:
|
|
41
|
+
* - **Cached input tokens**: charged at 0.1× the base input rate (both providers).
|
|
42
|
+
* - **Cache write tokens**: charged at 1.25× the base input rate (Anthropic 5-min cache).
|
|
43
|
+
* - **Long context premium**: for Claude Sonnet 4 / 4.5, when total input exceeds
|
|
44
|
+
* 200K tokens the entire request is charged at 2× input / 1.5× output.
|
|
45
|
+
*
|
|
46
|
+
* Returns 0 for unknown/unsupported models (Ollama, custom endpoints).
|
|
47
|
+
*/
|
|
48
|
+
export declare function calculateModelCost(inputTokens: number, outputTokens: number, model: string, options?: {
|
|
49
|
+
cachedInputTokens?: number;
|
|
50
|
+
cacheWriteTokens?: number;
|
|
51
|
+
}): number;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import type { AIProviderConfig } from '../types/config.js';
|
|
2
|
+
import { type Kind } from './model-pricing.js';
|
|
3
|
+
/**
|
|
4
|
+
* A single chat-history turn. Used for native multi-turn requests where the
|
|
5
|
+
* model should see real conversation flow (assistant + user alternation).
|
|
6
|
+
* Optional — when omitted, providers fall back to single-user-message mode
|
|
7
|
+
* built from `ProviderRequest.prompt`.
|
|
8
|
+
*/
|
|
9
|
+
export interface ChatMessage {
|
|
10
|
+
role: 'user' | 'assistant';
|
|
11
|
+
content: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ProviderRequest {
|
|
14
|
+
/** System prompt / instructions */
|
|
15
|
+
system?: string;
|
|
16
|
+
/**
|
|
17
|
+
* User prompt content. Used as the SOLE user message when `messages` is
|
|
18
|
+
* absent. When `messages` is provided, this field is IGNORED — the messages
|
|
19
|
+
* array is the conversation. Callers passing `messages` may still set
|
|
20
|
+
* `prompt: ''` for type-compat.
|
|
21
|
+
*/
|
|
22
|
+
prompt: string;
|
|
23
|
+
/**
|
|
24
|
+
* Optional native multi-turn conversation history. When present, providers
|
|
25
|
+
* send `[system?, ...messages]` to the API instead of `[system?, {role:'user', content: prompt}]`.
|
|
26
|
+
* The LAST entry should be a `user` message (the latest turn). Order is
|
|
27
|
+
* preserved exactly as supplied. Empty array is treated as "no messages"
|
|
28
|
+
* (falls back to single-user mode using `prompt`).
|
|
29
|
+
*/
|
|
30
|
+
messages?: ChatMessage[];
|
|
31
|
+
/** Model name override */
|
|
32
|
+
model?: string;
|
|
33
|
+
/** Temperature (0-2) */
|
|
34
|
+
temperature?: number;
|
|
35
|
+
/** Max tokens for response */
|
|
36
|
+
maxTokens?: number;
|
|
37
|
+
/** Response format hint */
|
|
38
|
+
responseFormat?: 'text' | 'json';
|
|
39
|
+
/** Provider-compatible JSON Schema for strict structured outputs. */
|
|
40
|
+
responseSchema?: Record<string, unknown>;
|
|
41
|
+
/** Transport used for provider-side structured outputs. Defaults to response_format. */
|
|
42
|
+
structuredOutputTransport?: 'response_format' | 'tool';
|
|
43
|
+
/** Request timeout in milliseconds (default: 120_000) */
|
|
44
|
+
timeout?: number;
|
|
45
|
+
/**
|
|
46
|
+
* External AbortSignal (e.g. `ctx.signal`). When fired, the in-flight
|
|
47
|
+
* fetch(es) for this request abort immediately. Combined with the internal
|
|
48
|
+
* timeout signal via `AbortSignal.any([...])`, so whichever triggers first
|
|
49
|
+
* wins.
|
|
50
|
+
*/
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
/**
|
|
53
|
+
* Deterministic sampling seed. OpenAI-compatible providers (including xAI
|
|
54
|
+
* Grok) honor this parameter: identical `{seed, temperature, model, prompt}`
|
|
55
|
+
* tuples produce the same tokens. Combined with `temperature: 0`, lets
|
|
56
|
+
* callers pin reproducible output for structural-planning prompts. Ignored
|
|
57
|
+
* by providers that do not support it.
|
|
58
|
+
*/
|
|
59
|
+
seed?: number;
|
|
60
|
+
}
|
|
61
|
+
/** Compose a request's optional user signal with a timeout, returning a single AbortSignal. */
|
|
62
|
+
export declare function combineRequestSignals(userSignal: AbortSignal | undefined, timeoutMs: number): AbortSignal;
|
|
63
|
+
export interface ProviderResponse {
|
|
64
|
+
content: string;
|
|
65
|
+
model: string;
|
|
66
|
+
usage: TokenUsage;
|
|
67
|
+
finishReason: string;
|
|
68
|
+
}
|
|
69
|
+
export interface TokenUsage {
|
|
70
|
+
inputTokens: number;
|
|
71
|
+
outputTokens: number;
|
|
72
|
+
totalTokens: number;
|
|
73
|
+
/** Tokens served from provider cache (charged at reduced rate). */
|
|
74
|
+
cachedInputTokens?: number;
|
|
75
|
+
/** Tokens written to provider cache (charged at elevated rate — Anthropic only). */
|
|
76
|
+
cacheWriteTokens?: number;
|
|
77
|
+
}
|
|
78
|
+
export interface ProviderStreamEvent {
|
|
79
|
+
type: 'content_delta' | 'usage' | 'done' | 'error';
|
|
80
|
+
/** Incremental text chunk (for content_delta) */
|
|
81
|
+
delta?: string;
|
|
82
|
+
/** Token usage (for usage / done events) */
|
|
83
|
+
usage?: TokenUsage;
|
|
84
|
+
/** Finish reason (for done events) */
|
|
85
|
+
finishReason?: string;
|
|
86
|
+
/** Error message (for error events) */
|
|
87
|
+
error?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface EmbeddingRequest {
|
|
90
|
+
texts: string[];
|
|
91
|
+
model?: string;
|
|
92
|
+
}
|
|
93
|
+
export interface EmbeddingResponse {
|
|
94
|
+
embeddings: number[][];
|
|
95
|
+
model: string;
|
|
96
|
+
usage: {
|
|
97
|
+
totalTokens: number;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* USD cost computed from the pricing catalog using `usage.totalTokens` against
|
|
101
|
+
* the model's input rate (embeddings are input-only). `0` for unknown models
|
|
102
|
+
* — same convention as completion-side cost. Optional so that external
|
|
103
|
+
* `AIProviderAdapter` implementations written before this field existed still
|
|
104
|
+
* satisfy the interface; consumers reading `cost` should treat `undefined` as
|
|
105
|
+
* "unknown" (typically by coalescing to `0`).
|
|
106
|
+
*/
|
|
107
|
+
cost?: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* A single model entry returned by `AIProviderAdapter.listModels()`.
|
|
111
|
+
* The id is whatever the provider's `/v1/models` returns; pricing and `kind`
|
|
112
|
+
* are joined from the framework's pricing catalog. Models not in the catalog
|
|
113
|
+
* surface as `kind: 'unknown'` with `null` prices.
|
|
114
|
+
*/
|
|
115
|
+
export interface ProviderModel {
|
|
116
|
+
/** API identifier (the value to pass as `model` in requests). */
|
|
117
|
+
id: string;
|
|
118
|
+
/** Adapter name (e.g. "openai", "anthropic", or a custom adapter's name). */
|
|
119
|
+
provider: string;
|
|
120
|
+
/** Capability classification, from the pricing catalog. `'unknown'` if not in the catalog. */
|
|
121
|
+
kind: Kind | 'unknown';
|
|
122
|
+
/** USD per 1M input tokens, or `null` if the model is not in the catalog. */
|
|
123
|
+
inputPerMTok: number | null;
|
|
124
|
+
/** USD per 1M output tokens, or `null` if the model is not in the catalog. */
|
|
125
|
+
outputPerMTok: number | null;
|
|
126
|
+
/** Provider-supplied human-readable label (Anthropic exposes this; OpenAI doesn't). */
|
|
127
|
+
displayName?: string;
|
|
128
|
+
/** ISO-8601 creation timestamp when the provider exposes one. */
|
|
129
|
+
createdAt?: string;
|
|
130
|
+
/** Owner/team (OpenAI exposes this; Anthropic doesn't). */
|
|
131
|
+
ownedBy?: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Optional filter passed to `AIProviderAdapter.listModels()`. `kind` accepts a
|
|
135
|
+
* single Kind or an array. When unset, all models are returned (including
|
|
136
|
+
* unknown ones). When set against an official endpoint, unknown-kind models
|
|
137
|
+
* are excluded; against a custom endpoint they are included alongside the
|
|
138
|
+
* filtered matches (see adapter docs).
|
|
139
|
+
*/
|
|
140
|
+
export interface ListModelsFilter {
|
|
141
|
+
kind?: Kind | Kind[];
|
|
142
|
+
}
|
|
143
|
+
export interface AIProviderAdapter {
|
|
144
|
+
readonly name: string;
|
|
145
|
+
/** Send a completion request */
|
|
146
|
+
complete(request: ProviderRequest): Promise<ProviderResponse>;
|
|
147
|
+
/** Stream a completion request, yielding incremental events */
|
|
148
|
+
stream(request: ProviderRequest): AsyncIterable<ProviderStreamEvent>;
|
|
149
|
+
/** Generate embeddings for texts */
|
|
150
|
+
embed(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
151
|
+
/**
|
|
152
|
+
* List models the provider exposes for this account, joined against the
|
|
153
|
+
* framework's pricing catalog. Optional — custom adapters that don't
|
|
154
|
+
* implement it still satisfy the interface.
|
|
155
|
+
*
|
|
156
|
+
* Filtering rule (see docs for full details):
|
|
157
|
+
* - No filter → all models, including unknown-kind entries.
|
|
158
|
+
* - Filter + official endpoint → only matching kinds; unknowns excluded.
|
|
159
|
+
* - Filter + custom endpoint → matching kinds **plus** all unknowns.
|
|
160
|
+
*
|
|
161
|
+
* On network error / 404 / unsupported endpoint, returns `[]` and emits
|
|
162
|
+
* one `console.warn`; does not throw.
|
|
163
|
+
*/
|
|
164
|
+
listModels?(filter?: ListModelsFilter): Promise<ProviderModel[]>;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Shared logic used by adapter `listModels` implementations: join a list of
|
|
168
|
+
* provider-supplied model entries against the pricing catalog, then apply
|
|
169
|
+
* the kind filter respecting the official-endpoint rule.
|
|
170
|
+
*/
|
|
171
|
+
export declare function joinAndFilterModels(args: {
|
|
172
|
+
provider: string;
|
|
173
|
+
entries: Array<{
|
|
174
|
+
id: string;
|
|
175
|
+
displayName?: string;
|
|
176
|
+
createdAt?: string;
|
|
177
|
+
ownedBy?: string;
|
|
178
|
+
}>;
|
|
179
|
+
filter: ListModelsFilter | undefined;
|
|
180
|
+
isOfficial: boolean;
|
|
181
|
+
}): ProviderModel[];
|
|
182
|
+
export declare class ProviderAPIError extends Error {
|
|
183
|
+
readonly providerName: string;
|
|
184
|
+
readonly statusCode?: number;
|
|
185
|
+
readonly retryable: boolean;
|
|
186
|
+
readonly attempts: number;
|
|
187
|
+
constructor(args: {
|
|
188
|
+
providerName: string;
|
|
189
|
+
message: string;
|
|
190
|
+
retryable: boolean;
|
|
191
|
+
attempts: number;
|
|
192
|
+
statusCode?: number;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
export declare function isProviderAPIError(value: unknown): value is ProviderAPIError;
|
|
196
|
+
export interface OpenAIAdapterConfig {
|
|
197
|
+
apiKey: string;
|
|
198
|
+
model?: string;
|
|
199
|
+
embeddingModel?: string;
|
|
200
|
+
baseUrl?: string;
|
|
201
|
+
/** Request timeout in milliseconds (default: 120_000) */
|
|
202
|
+
requestTimeout?: number;
|
|
203
|
+
}
|
|
204
|
+
export declare function createOpenAIAdapter(config: OpenAIAdapterConfig): AIProviderAdapter;
|
|
205
|
+
export interface AnthropicAdapterConfig {
|
|
206
|
+
apiKey: string;
|
|
207
|
+
model?: string;
|
|
208
|
+
baseUrl?: string;
|
|
209
|
+
/** Request timeout in milliseconds (default: 120_000) */
|
|
210
|
+
requestTimeout?: number;
|
|
211
|
+
}
|
|
212
|
+
export declare function createAnthropicAdapter(config: AnthropicAdapterConfig): AIProviderAdapter;
|
|
213
|
+
/** Create a provider adapter by name from a provider config entry */
|
|
214
|
+
export declare function createProviderAdapter(name: string, providerConfig: AIProviderConfig): AIProviderAdapter;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TokenUsage } from './provider.js';
|
|
2
|
+
export declare class AIRefusalError extends Error {
|
|
3
|
+
readonly provider: string;
|
|
4
|
+
readonly model: string;
|
|
5
|
+
readonly refusalText: string;
|
|
6
|
+
readonly usage: TokenUsage;
|
|
7
|
+
constructor(args: {
|
|
8
|
+
provider: string;
|
|
9
|
+
model: string;
|
|
10
|
+
refusalText: string;
|
|
11
|
+
usage?: TokenUsage;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export declare class AIIncompleteOutputError extends Error {
|
|
15
|
+
readonly provider: string;
|
|
16
|
+
readonly model: string;
|
|
17
|
+
readonly partialText: string;
|
|
18
|
+
readonly usage: TokenUsage;
|
|
19
|
+
readonly finishReason: string;
|
|
20
|
+
constructor(args: {
|
|
21
|
+
provider: string;
|
|
22
|
+
model: string;
|
|
23
|
+
partialText: string;
|
|
24
|
+
usage?: TokenUsage;
|
|
25
|
+
finishReason: string;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface UsageEntry {
|
|
2
|
+
model: string;
|
|
3
|
+
inputTokens: number;
|
|
4
|
+
outputTokens: number;
|
|
5
|
+
cost: number;
|
|
6
|
+
requestCount: number;
|
|
7
|
+
}
|
|
8
|
+
export interface UsageData {
|
|
9
|
+
totalCost: number;
|
|
10
|
+
currency: string;
|
|
11
|
+
entries: UsageEntry[];
|
|
12
|
+
}
|
|
13
|
+
export interface UsageAPIClient {
|
|
14
|
+
provider: string;
|
|
15
|
+
fetchUsage(params: {
|
|
16
|
+
startDate: Date;
|
|
17
|
+
endDate: Date;
|
|
18
|
+
}): Promise<UsageData>;
|
|
19
|
+
}
|
|
20
|
+
export interface UsageClientConfig {
|
|
21
|
+
provider: 'openai' | 'anthropic';
|
|
22
|
+
apiKey: string;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
organizationId?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function createUsageAPIClient(config: UsageClientConfig): UsageAPIClient;
|
|
27
|
+
export declare class UsageAPIError extends Error {
|
|
28
|
+
readonly provider: string;
|
|
29
|
+
constructor(provider: string, message: string);
|
|
30
|
+
}
|
package/dist/ai/ai-service.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type { AICostContext };
|
|
|
11
11
|
* Framework-level hook fired after every AI call completes (success or
|
|
12
12
|
* failure) and the in-memory cost tracker has been updated. Consumers wire
|
|
13
13
|
* this in through `ServerConfig.onAICostRecorded` to persist per-call spend
|
|
14
|
-
* to their own ledger (
|
|
14
|
+
* to their own ledger (e.g. an app-owned per-project cost ledger).
|
|
15
15
|
*/
|
|
16
16
|
export type OnAICostRecorded = (record: AICostRecord, costContext?: AICostContext) => Promise<void> | void;
|
|
17
17
|
export interface AIServiceConfig {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-service.d.ts","sourceRoot":"","sources":["../../src/ai/ai-service.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,aAAa,EAGb,SAAS,EAEV,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,YAAY,EAAqB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAA4C,MAAM,eAAe,CAAC;AACjG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAC;AAIzB,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,aAAa,KACxB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAG1B,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC7C,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,cAAc,CAAC,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC,0DAA0D,CAAC;IACjF,gFAAgF;IAChF,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CACtB,MAAM,EACN;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAChF,CAAC,kCAAkC,CAAC;IACrC,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,iBAAiB,CAAC,GAC5D,eAAe,CAMjB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"ai-service.d.ts","sourceRoot":"","sources":["../../src/ai/ai-service.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,aAAa,EAGb,SAAS,EAEV,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,YAAY,EAAqB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAA4C,MAAM,eAAe,CAAC;AACjG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAC;AAIzB,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,aAAa,KACxB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAG1B,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC7C,8DAA8D;IAC9D,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,cAAc,CAAC,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC,0DAA0D,CAAC;IACjF,gFAAgF;IAChF,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CACtB,MAAM,EACN;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAChF,CAAC,kCAAkC,CAAC;IACrC,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,iBAAiB,CAAC,GAC5D,eAAe,CAMjB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAwjClE"}
|
package/dist/ai/ai-service.js
CHANGED
|
@@ -86,7 +86,7 @@ export function createAIService(config) {
|
|
|
86
86
|
* id/timestamp generation mirror what `createCostTracker` does internally
|
|
87
87
|
* so the hook gets a fully-formed `AICostRecord`.
|
|
88
88
|
*/
|
|
89
|
-
async function
|
|
89
|
+
async function recordProviderCost(entry, costContext) {
|
|
90
90
|
if (costTracker) {
|
|
91
91
|
costTracker.record(entry);
|
|
92
92
|
}
|
|
@@ -117,12 +117,13 @@ export function createAIService(config) {
|
|
|
117
117
|
cacheWriteTokens: (left.cacheWriteTokens ?? 0) + (right.cacheWriteTokens ?? 0),
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
|
-
function checkBudget(estimatedTokens) {
|
|
120
|
+
function checkBudget(estimatedTokens, estimatedCostUsd) {
|
|
121
121
|
if (!costTracker)
|
|
122
122
|
return;
|
|
123
123
|
const result = costTracker.checkBudget({
|
|
124
124
|
tenantId: config.budget?.tenantId,
|
|
125
125
|
estimatedTokens,
|
|
126
|
+
estimatedCostUsd,
|
|
126
127
|
});
|
|
127
128
|
if (!result.allowed) {
|
|
128
129
|
throw new Error(`AI budget exceeded: ${result.reason}`);
|
|
@@ -267,7 +268,7 @@ export function createAIService(config) {
|
|
|
267
268
|
cacheWriteTokens: failureUsage.cacheWriteTokens,
|
|
268
269
|
})
|
|
269
270
|
: null;
|
|
270
|
-
await
|
|
271
|
+
await recordProviderCost({
|
|
271
272
|
model: resolvedModel,
|
|
272
273
|
provider: activeProvider.name,
|
|
273
274
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -284,7 +285,7 @@ export function createAIService(config) {
|
|
|
284
285
|
}
|
|
285
286
|
const latencyMs = performance.now() - start;
|
|
286
287
|
// Track cost (success path)
|
|
287
|
-
await
|
|
288
|
+
await recordProviderCost({
|
|
288
289
|
model: resolvedModel,
|
|
289
290
|
provider: activeProvider.name,
|
|
290
291
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -329,6 +330,10 @@ export function createAIService(config) {
|
|
|
329
330
|
};
|
|
330
331
|
}
|
|
331
332
|
return {
|
|
333
|
+
recordProviderCost,
|
|
334
|
+
checkProviderCostBudget(config = {}) {
|
|
335
|
+
checkBudget(config.estimatedTokens, config.estimatedCostUsd);
|
|
336
|
+
},
|
|
332
337
|
async generate(params) {
|
|
333
338
|
const { data } = await _generateCore(params);
|
|
334
339
|
return data;
|
|
@@ -432,7 +437,7 @@ export function createAIService(config) {
|
|
|
432
437
|
cacheWriteTokens: streamUsage.cacheWriteTokens,
|
|
433
438
|
})
|
|
434
439
|
: null;
|
|
435
|
-
await
|
|
440
|
+
await recordProviderCost({
|
|
436
441
|
model: resolvedModel,
|
|
437
442
|
provider: activeProvider.name,
|
|
438
443
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -460,7 +465,7 @@ export function createAIService(config) {
|
|
|
460
465
|
cacheWriteTokens: errUsage.cacheWriteTokens,
|
|
461
466
|
})
|
|
462
467
|
: null;
|
|
463
|
-
await
|
|
468
|
+
await recordProviderCost({
|
|
464
469
|
model: resolvedModel,
|
|
465
470
|
provider: activeProvider.name,
|
|
466
471
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -492,7 +497,7 @@ export function createAIService(config) {
|
|
|
492
497
|
if (request.responseSchema &&
|
|
493
498
|
(providerFinishReason === 'length' || providerFinishReason === 'max_tokens')) {
|
|
494
499
|
const failureUsage = streamUsage ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
495
|
-
await
|
|
500
|
+
await recordProviderCost({
|
|
496
501
|
model: resolvedModel,
|
|
497
502
|
provider: activeProvider.name,
|
|
498
503
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -516,7 +521,7 @@ export function createAIService(config) {
|
|
|
516
521
|
// Build the final validated result
|
|
517
522
|
if (singleTextField) {
|
|
518
523
|
// Plain text mode — wrap the accumulated text in the schema field
|
|
519
|
-
await
|
|
524
|
+
await recordProviderCost({
|
|
520
525
|
model: resolvedModel,
|
|
521
526
|
provider: activeProvider.name,
|
|
522
527
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -554,7 +559,7 @@ export function createAIService(config) {
|
|
|
554
559
|
cacheWriteTokens: failureUsage.cacheWriteTokens,
|
|
555
560
|
})
|
|
556
561
|
: null;
|
|
557
|
-
await
|
|
562
|
+
await recordProviderCost({
|
|
558
563
|
model: resolvedModel,
|
|
559
564
|
provider: activeProvider.name,
|
|
560
565
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -598,7 +603,7 @@ export function createAIService(config) {
|
|
|
598
603
|
cacheWriteTokens: combinedUsage.cacheWriteTokens,
|
|
599
604
|
})
|
|
600
605
|
: null;
|
|
601
|
-
await
|
|
606
|
+
await recordProviderCost({
|
|
602
607
|
model: resolvedModel,
|
|
603
608
|
provider: activeProvider.name,
|
|
604
609
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -617,7 +622,7 @@ export function createAIService(config) {
|
|
|
617
622
|
const successUsage = validationFellBackToNonStreaming
|
|
618
623
|
? sumUsage(streamUsage, fallbackUsage)
|
|
619
624
|
: (streamUsage ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 });
|
|
620
|
-
await
|
|
625
|
+
await recordProviderCost({
|
|
621
626
|
model: resolvedModel,
|
|
622
627
|
provider: activeProvider.name,
|
|
623
628
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -638,7 +643,7 @@ export function createAIService(config) {
|
|
|
638
643
|
};
|
|
639
644
|
}
|
|
640
645
|
else {
|
|
641
|
-
await
|
|
646
|
+
await recordProviderCost({
|
|
642
647
|
model: resolvedModel,
|
|
643
648
|
provider: activeProvider.name,
|
|
644
649
|
promptName: hasPromptDef ? params.prompt : undefined,
|
|
@@ -683,7 +688,7 @@ export function createAIService(config) {
|
|
|
683
688
|
const failureUsage = err instanceof AIValidationError
|
|
684
689
|
? err.usage
|
|
685
690
|
: (getTypedAIErrorUsage(err) ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 });
|
|
686
|
-
await
|
|
691
|
+
await recordProviderCost({
|
|
687
692
|
model: resolvedModel,
|
|
688
693
|
provider: activeProvider.name,
|
|
689
694
|
operation: 'extract',
|
|
@@ -698,7 +703,7 @@ export function createAIService(config) {
|
|
|
698
703
|
throw err;
|
|
699
704
|
}
|
|
700
705
|
const latencyMs = performance.now() - start;
|
|
701
|
-
await
|
|
706
|
+
await recordProviderCost({
|
|
702
707
|
model: resolvedModel,
|
|
703
708
|
provider: activeProvider.name,
|
|
704
709
|
operation: 'extract',
|
|
@@ -756,7 +761,7 @@ export function createAIService(config) {
|
|
|
756
761
|
const failureUsage = err instanceof AIValidationError
|
|
757
762
|
? err.usage
|
|
758
763
|
: (getTypedAIErrorUsage(err) ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 });
|
|
759
|
-
await
|
|
764
|
+
await recordProviderCost({
|
|
760
765
|
model: resolvedModel,
|
|
761
766
|
provider: activeProvider.name,
|
|
762
767
|
operation: 'classify',
|
|
@@ -773,7 +778,7 @@ export function createAIService(config) {
|
|
|
773
778
|
const latencyMs = performance.now() - start;
|
|
774
779
|
// Filter to only valid labels
|
|
775
780
|
const result = validated.data.filter((l) => params.labels.includes(l));
|
|
776
|
-
await
|
|
781
|
+
await recordProviderCost({
|
|
777
782
|
model: resolvedModel,
|
|
778
783
|
provider: activeProvider.name,
|
|
779
784
|
operation: 'classify',
|