@venturekit-pro/ai 0.0.47 → 0.0.50

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 (147) hide show
  1. package/README.md +192 -0
  2. package/dist/agent-loop/index.d.ts +9 -0
  3. package/dist/agent-loop/index.d.ts.map +1 -0
  4. package/dist/agent-loop/index.js +7 -0
  5. package/dist/agent-loop/index.js.map +1 -0
  6. package/dist/agent-loop/registry.d.ts +85 -0
  7. package/dist/agent-loop/registry.d.ts.map +1 -0
  8. package/dist/agent-loop/registry.js +100 -0
  9. package/dist/agent-loop/registry.js.map +1 -0
  10. package/dist/agent-loop/run-agent.d.ts +37 -0
  11. package/dist/agent-loop/run-agent.d.ts.map +1 -0
  12. package/dist/agent-loop/run-agent.js +405 -0
  13. package/dist/agent-loop/run-agent.js.map +1 -0
  14. package/dist/agent-loop/tools.d.ts +10 -0
  15. package/dist/agent-loop/tools.d.ts.map +1 -0
  16. package/dist/agent-loop/tools.js +28 -0
  17. package/dist/agent-loop/tools.js.map +1 -0
  18. package/dist/agent-loop/types.d.ts +175 -0
  19. package/dist/agent-loop/types.d.ts.map +1 -0
  20. package/dist/agent-loop/types.js +8 -0
  21. package/dist/agent-loop/types.js.map +1 -0
  22. package/dist/chat/types.d.ts +4 -2
  23. package/dist/chat/types.d.ts.map +1 -1
  24. package/dist/cost/types.d.ts +15 -0
  25. package/dist/cost/types.d.ts.map +1 -1
  26. package/dist/cost-ledger/migrations/vk_ai_cost_0004_llm_gateway.sql +69 -0
  27. package/dist/cost-ledger/migrations/vk_ai_cost_0005_harness.sql +99 -0
  28. package/dist/cost-ledger/migrations/vk_ai_cost_0006_cache_write_prices.sql +17 -0
  29. package/dist/cost-ledger/migrations/vk_ai_cost_0007_harness_fan_out.sql +47 -0
  30. package/dist/gateway/errors.d.ts +24 -0
  31. package/dist/gateway/errors.d.ts.map +1 -0
  32. package/dist/gateway/errors.js +29 -0
  33. package/dist/gateway/errors.js.map +1 -0
  34. package/dist/gateway/gateway.d.ts +27 -0
  35. package/dist/gateway/gateway.d.ts.map +1 -0
  36. package/dist/gateway/gateway.js +503 -0
  37. package/dist/gateway/gateway.js.map +1 -0
  38. package/dist/gateway/index.d.ts +13 -0
  39. package/dist/gateway/index.d.ts.map +1 -0
  40. package/dist/gateway/index.js +10 -0
  41. package/dist/gateway/index.js.map +1 -0
  42. package/dist/gateway/policies.d.ts +32 -0
  43. package/dist/gateway/policies.d.ts.map +1 -0
  44. package/dist/gateway/policies.js +45 -0
  45. package/dist/gateway/policies.js.map +1 -0
  46. package/dist/gateway/postgres.d.ts +55 -0
  47. package/dist/gateway/postgres.d.ts.map +1 -0
  48. package/dist/gateway/postgres.js +127 -0
  49. package/dist/gateway/postgres.js.map +1 -0
  50. package/dist/gateway/pricing.d.ts +11 -0
  51. package/dist/gateway/pricing.d.ts.map +1 -0
  52. package/dist/gateway/pricing.js +47 -0
  53. package/dist/gateway/pricing.js.map +1 -0
  54. package/dist/gateway/routing.d.ts +25 -0
  55. package/dist/gateway/routing.d.ts.map +1 -0
  56. package/dist/gateway/routing.js +23 -0
  57. package/dist/gateway/routing.js.map +1 -0
  58. package/dist/gateway/types.d.ts +225 -0
  59. package/dist/gateway/types.d.ts.map +1 -0
  60. package/dist/gateway/types.js +7 -0
  61. package/dist/gateway/types.js.map +1 -0
  62. package/dist/generate/anthropic.d.ts +38 -0
  63. package/dist/generate/anthropic.d.ts.map +1 -0
  64. package/dist/generate/anthropic.js +446 -0
  65. package/dist/generate/anthropic.js.map +1 -0
  66. package/dist/generate/client.d.ts +9 -0
  67. package/dist/generate/client.d.ts.map +1 -0
  68. package/dist/generate/client.js +44 -0
  69. package/dist/generate/client.js.map +1 -0
  70. package/dist/generate/google.d.ts +39 -0
  71. package/dist/generate/google.d.ts.map +1 -0
  72. package/dist/generate/google.js +372 -0
  73. package/dist/generate/google.js.map +1 -0
  74. package/dist/generate/http.d.ts +48 -0
  75. package/dist/generate/http.d.ts.map +1 -0
  76. package/dist/generate/http.js +180 -0
  77. package/dist/generate/http.js.map +1 -0
  78. package/dist/generate/index.d.ts +13 -0
  79. package/dist/generate/index.d.ts.map +1 -0
  80. package/dist/generate/index.js +12 -0
  81. package/dist/generate/index.js.map +1 -0
  82. package/dist/generate/openai.d.ts +29 -0
  83. package/dist/generate/openai.d.ts.map +1 -0
  84. package/dist/generate/openai.js +314 -0
  85. package/dist/generate/openai.js.map +1 -0
  86. package/dist/generate/perplexity.d.ts +27 -0
  87. package/dist/generate/perplexity.d.ts.map +1 -0
  88. package/dist/generate/perplexity.js +208 -0
  89. package/dist/generate/perplexity.js.map +1 -0
  90. package/dist/generate/types.d.ts +253 -0
  91. package/dist/generate/types.d.ts.map +1 -0
  92. package/dist/generate/types.js +19 -0
  93. package/dist/generate/types.js.map +1 -0
  94. package/dist/harness/define.d.ts +15 -0
  95. package/dist/harness/define.d.ts.map +1 -0
  96. package/dist/harness/define.js +38 -0
  97. package/dist/harness/define.js.map +1 -0
  98. package/dist/harness/harness.d.ts +29 -0
  99. package/dist/harness/harness.d.ts.map +1 -0
  100. package/dist/harness/harness.js +1287 -0
  101. package/dist/harness/harness.js.map +1 -0
  102. package/dist/harness/index.d.ts +14 -0
  103. package/dist/harness/index.d.ts.map +1 -0
  104. package/dist/harness/index.js +10 -0
  105. package/dist/harness/index.js.map +1 -0
  106. package/dist/harness/memory-store.d.ts +8 -0
  107. package/dist/harness/memory-store.d.ts.map +1 -0
  108. package/dist/harness/memory-store.js +270 -0
  109. package/dist/harness/memory-store.js.map +1 -0
  110. package/dist/harness/postgres-store.d.ts +12 -0
  111. package/dist/harness/postgres-store.d.ts.map +1 -0
  112. package/dist/harness/postgres-store.js +368 -0
  113. package/dist/harness/postgres-store.js.map +1 -0
  114. package/dist/harness/scheduler.d.ts +12 -0
  115. package/dist/harness/scheduler.d.ts.map +1 -0
  116. package/dist/harness/scheduler.js +23 -0
  117. package/dist/harness/scheduler.js.map +1 -0
  118. package/dist/harness/store.d.ts +172 -0
  119. package/dist/harness/store.d.ts.map +1 -0
  120. package/dist/harness/store.js +21 -0
  121. package/dist/harness/store.js.map +1 -0
  122. package/dist/harness/types.d.ts +312 -0
  123. package/dist/harness/types.d.ts.map +1 -0
  124. package/dist/harness/types.js +11 -0
  125. package/dist/harness/types.js.map +1 -0
  126. package/dist/index.d.ts +12 -0
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +11 -0
  129. package/dist/index.js.map +1 -1
  130. package/dist/model-catalog/crud.d.ts.map +1 -1
  131. package/dist/model-catalog/crud.js +33 -2
  132. package/dist/model-catalog/crud.js.map +1 -1
  133. package/dist/model-catalog/types.d.ts +20 -0
  134. package/dist/model-catalog/types.d.ts.map +1 -1
  135. package/dist/tracing/index.d.ts +68 -0
  136. package/dist/tracing/index.d.ts.map +1 -0
  137. package/dist/tracing/index.js +72 -0
  138. package/dist/tracing/index.js.map +1 -0
  139. package/dist/tracing/recording.d.ts +23 -0
  140. package/dist/tracing/recording.d.ts.map +1 -0
  141. package/dist/tracing/recording.js +49 -0
  142. package/dist/tracing/recording.js.map +1 -0
  143. package/package.json +7 -4
  144. package/src/cost-ledger/migrations/vk_ai_cost_0004_llm_gateway.sql +69 -0
  145. package/src/cost-ledger/migrations/vk_ai_cost_0005_harness.sql +99 -0
  146. package/src/cost-ledger/migrations/vk_ai_cost_0006_cache_write_prices.sql +17 -0
  147. package/src/cost-ledger/migrations/vk_ai_cost_0007_harness_fan_out.sql +47 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Postgres sinks for the LLM gateway (migration `vk_ai_cost_0004_llm_gateway.sql`):
3
+ *
4
+ * - `recordCost` → one `vk_llm_cost_events` row per billed call,
5
+ * idempotent on `llm-call:<callId>` (every vendor call is counted
6
+ * once; a re-run is a new call, so a new row).
7
+ * - `recordCall` → one `vk_llm_calls` row per call with attempts,
8
+ * policy decisions, usage, cost and the full request / response
9
+ * content, kept until `expires_at` (`purgeExpiredLlmCalls`).
10
+ */
11
+ import type { Querier } from '../model-catalog/types.js';
12
+ import type { LlmCallRecord, GatewaySinks } from './types.js';
13
+ export interface PostgresGatewaySinksOptions {
14
+ /** Days a `vk_llm_calls` row is kept (full content). Default 90; may depend on the call. */
15
+ retentionDays?: number | ((record: LlmCallRecord) => number);
16
+ }
17
+ export declare function createPostgresGatewaySinks(querier: Querier, options?: PostgresGatewaySinksOptions): GatewaySinks;
18
+ /** Delete up to `limit` audit rows past their `expires_at`. Returns how many went. */
19
+ export declare function purgeExpiredLlmCalls(querier: Querier, options?: {
20
+ limit?: number;
21
+ }): Promise<number>;
22
+ export interface LlmCallRow {
23
+ id: string;
24
+ tenantId: string | null;
25
+ feature: string;
26
+ correlationId: string | null;
27
+ targetType: string | null;
28
+ targetId: string | null;
29
+ status: string;
30
+ modelKey: string | null;
31
+ provider: string | null;
32
+ model: string | null;
33
+ credentialSource: string | null;
34
+ fellBack: boolean;
35
+ attempts: unknown;
36
+ policyDecisions: unknown;
37
+ usage: unknown;
38
+ costUsd: string | null;
39
+ costMicroUsd: string | null;
40
+ latencyMs: number | null;
41
+ labels: Record<string, unknown>;
42
+ request: unknown;
43
+ response: unknown;
44
+ error: unknown;
45
+ startedAt: Date;
46
+ finishedAt: Date;
47
+ expiresAt: Date;
48
+ }
49
+ /** The audit trail of an operation (a run) or a workspace, newest first. */
50
+ export declare function listLlmCalls(querier: Querier, filter: {
51
+ correlationId?: string;
52
+ tenantId?: string;
53
+ limit?: number;
54
+ }): Promise<LlmCallRow[]>;
55
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/gateway/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,2BAA2B;IAC1C,4FAA4F;IAC5F,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,CAAC,CAAC;CAC9D;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,2BAAgC,GACxC,YAAY,CAuFd;AAED,sFAAsF;AACtF,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,4EAA4E;AAC5E,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE,OAAO,CAAC,UAAU,EAAE,CAAC,CAwBvB"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Postgres sinks for the LLM gateway (migration `vk_ai_cost_0004_llm_gateway.sql`):
3
+ *
4
+ * - `recordCost` → one `vk_llm_cost_events` row per billed call,
5
+ * idempotent on `llm-call:<callId>` (every vendor call is counted
6
+ * once; a re-run is a new call, so a new row).
7
+ * - `recordCall` → one `vk_llm_calls` row per call with attempts,
8
+ * policy decisions, usage, cost and the full request / response
9
+ * content, kept until `expires_at` (`purgeExpiredLlmCalls`).
10
+ */
11
+ import { recordLlmCost } from '../cost-ledger/record.js';
12
+ export function createPostgresGatewaySinks(querier, options = {}) {
13
+ const retention = (record) => {
14
+ const days = typeof options.retentionDays === 'function'
15
+ ? options.retentionDays(record)
16
+ : (options.retentionDays ?? 90);
17
+ return Math.max(1, Math.round(days));
18
+ };
19
+ return {
20
+ async recordCost(record) {
21
+ if (!record.usage || !record.provider || !record.model)
22
+ return;
23
+ await recordLlmCost(querier, {
24
+ tenantId: record.context.tenantId,
25
+ source: record.context.feature,
26
+ ...(record.context.target ? { target: record.context.target } : {}),
27
+ provider: record.provider,
28
+ model: record.model,
29
+ tokensIn: record.usage.tokensIn,
30
+ tokensOut: record.usage.tokensOut,
31
+ costUsd: record.cost?.costUsd ?? null,
32
+ costMicroUsd: record.cost?.costMicroUsd ?? null,
33
+ latencyMs: record.latencyMs,
34
+ ...(record.context.correlationId ? { correlationId: record.context.correlationId } : {}),
35
+ idempotencyKey: `llm-call:${record.id}`,
36
+ payload: {
37
+ callId: record.id,
38
+ modelKey: record.modelKey,
39
+ cachedTokensIn: record.usage.cachedTokensIn,
40
+ ...(record.usage.cacheWriteTokensIn
41
+ ? { cacheWriteTokensIn: record.usage.cacheWriteTokensIn }
42
+ : {}),
43
+ ...(record.usage.cacheWrite1hTokensIn
44
+ ? { cacheWrite1hTokensIn: record.usage.cacheWrite1hTokensIn }
45
+ : {}),
46
+ webSearches: record.usage.webSearches,
47
+ credentialSource: record.credentialSource,
48
+ fellBack: record.fellBack,
49
+ labels: record.context.labels ?? {},
50
+ },
51
+ });
52
+ },
53
+ async recordCall(record) {
54
+ await querier(`INSERT INTO vk_llm_calls (
55
+ id, tenant_id, feature, actor_type, actor_id, target_type, target_id, correlation_id,
56
+ status, model_key, provider, model, credential_source, fell_back,
57
+ attempts, policy_decisions, usage, cost_usd, cost_micro_usd, latency_ms,
58
+ labels, request, response, error, started_at, finished_at, expires_at
59
+ ) VALUES (
60
+ $1, $2, $3, $4, $5, $6, $7, $8,
61
+ $9, $10, $11, $12, $13, $14,
62
+ $15::jsonb, $16::jsonb, $17::jsonb, $18, $19, $20,
63
+ $21::jsonb, $22::jsonb, $23::jsonb, $24::jsonb, $25, $26, now() + make_interval(days => $27)
64
+ )
65
+ ON CONFLICT (id) DO NOTHING`, [
66
+ record.id,
67
+ record.context.tenantId,
68
+ record.context.feature,
69
+ record.context.actor?.type ?? null,
70
+ record.context.actor?.id ?? null,
71
+ record.context.target?.type ?? null,
72
+ record.context.target?.id ?? null,
73
+ record.context.correlationId ?? null,
74
+ record.status,
75
+ record.modelKey,
76
+ record.provider,
77
+ record.model,
78
+ record.credentialSource,
79
+ record.fellBack,
80
+ JSON.stringify(record.attempts),
81
+ JSON.stringify(record.policyDecisions),
82
+ record.usage ? JSON.stringify(record.usage) : null,
83
+ record.cost?.costUsd ?? null,
84
+ record.cost?.costMicroUsd ?? null,
85
+ record.latencyMs,
86
+ JSON.stringify(record.context.labels ?? {}),
87
+ JSON.stringify(record.request),
88
+ record.response ? JSON.stringify(record.response) : null,
89
+ record.error ? JSON.stringify(record.error) : null,
90
+ record.startedAt,
91
+ record.finishedAt,
92
+ retention(record),
93
+ ]);
94
+ },
95
+ };
96
+ }
97
+ /** Delete up to `limit` audit rows past their `expires_at`. Returns how many went. */
98
+ export async function purgeExpiredLlmCalls(querier, options = {}) {
99
+ const rows = await querier(`DELETE FROM vk_llm_calls
100
+ WHERE id IN (SELECT id FROM vk_llm_calls WHERE expires_at < now() ORDER BY expires_at LIMIT $1)
101
+ RETURNING id`, [options.limit ?? 5000]);
102
+ return rows.length;
103
+ }
104
+ /** The audit trail of an operation (a run) or a workspace, newest first. */
105
+ export async function listLlmCalls(querier, filter) {
106
+ const where = [];
107
+ const params = [];
108
+ if (filter.correlationId) {
109
+ params.push(filter.correlationId);
110
+ where.push(`correlation_id = $${params.length}`);
111
+ }
112
+ if (filter.tenantId) {
113
+ params.push(filter.tenantId);
114
+ where.push(`tenant_id = $${params.length}`);
115
+ }
116
+ params.push(Math.min(Math.max(filter.limit ?? 100, 1), 1000));
117
+ return querier(`SELECT id, tenant_id AS "tenantId", feature, correlation_id AS "correlationId", target_type AS "targetType",
118
+ target_id AS "targetId", status, model_key AS "modelKey", provider, model, credential_source AS "credentialSource",
119
+ fell_back AS "fellBack", attempts, policy_decisions AS "policyDecisions", usage, cost_usd AS "costUsd",
120
+ cost_micro_usd AS "costMicroUsd", latency_ms AS "latencyMs", labels, request, response, error,
121
+ started_at AS "startedAt", finished_at AS "finishedAt", expires_at AS "expiresAt"
122
+ FROM vk_llm_calls
123
+ ${where.length ? `WHERE ${where.join(' AND ')}` : ''}
124
+ ORDER BY started_at DESC
125
+ LIMIT $${params.length}`, params);
126
+ }
127
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/gateway/postgres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Price one served call from the catalog: uncached input + cached input
3
+ * (input rate when the model has no cached rate) + cache writes (input
4
+ * rate when the model has no write rate; 1-hour writes at their own rate)
5
+ * + output + web searches.
6
+ */
7
+ import type { ModelDescriptor } from '../cost/types.js';
8
+ import type { GenerateUsage } from '../generate/types.js';
9
+ import type { GatewayCost } from './types.js';
10
+ export declare function priceCall(usage: GenerateUsage, model: ModelDescriptor): GatewayCost | null;
11
+ //# sourceMappingURL=pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/gateway/pricing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,GAAG,WAAW,GAAG,IAAI,CAsC1F"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Price one served call from the catalog: uncached input + cached input
3
+ * (input rate when the model has no cached rate) + cache writes (input
4
+ * rate when the model has no write rate; 1-hour writes at their own rate)
5
+ * + output + web searches.
6
+ */
7
+ import { round8 } from '../chat/cost-util.js';
8
+ export function priceCall(usage, model) {
9
+ if (model.costPer1kInputUsd === undefined || model.costPer1kOutputUsd === undefined)
10
+ return null;
11
+ if (usage.tokensIn === null && usage.tokensOut === null && usage.webSearches === 0)
12
+ return null;
13
+ const tokensIn = usage.tokensIn ?? 0;
14
+ const cached = Math.min(usage.cachedTokensIn ?? 0, tokensIn);
15
+ const written = Math.min(usage.cacheWriteTokensIn ?? 0, tokensIn - cached);
16
+ const written1h = Math.min(usage.cacheWrite1hTokensIn ?? 0, written);
17
+ const cachedRate = model.costPer1kCachedInputUsd ?? model.costPer1kInputUsd;
18
+ const writeRate = model.costPer1kCacheWriteUsd ?? model.costPer1kInputUsd;
19
+ const write1hRate = model.costPer1kCacheWrite1hUsd ?? writeRate;
20
+ const costUsd = round8(((tokensIn - cached - written) / 1000) * model.costPer1kInputUsd +
21
+ (cached / 1000) * cachedRate +
22
+ ((written - written1h) / 1000) * writeRate +
23
+ (written1h / 1000) * write1hRate +
24
+ ((usage.tokensOut ?? 0) / 1000) * model.costPer1kOutputUsd +
25
+ (usage.webSearches / 1000) * (model.webSearchPer1kUsd ?? 0));
26
+ return {
27
+ costUsd,
28
+ costMicroUsd: Math.round(costUsd * 1_000_000),
29
+ pricing: {
30
+ costPer1kInputUsd: model.costPer1kInputUsd,
31
+ costPer1kOutputUsd: model.costPer1kOutputUsd,
32
+ ...(model.costPer1kCachedInputUsd !== undefined
33
+ ? { costPer1kCachedInputUsd: model.costPer1kCachedInputUsd }
34
+ : {}),
35
+ ...(model.costPer1kCacheWriteUsd !== undefined
36
+ ? { costPer1kCacheWriteUsd: model.costPer1kCacheWriteUsd }
37
+ : {}),
38
+ ...(model.costPer1kCacheWrite1hUsd !== undefined
39
+ ? { costPer1kCacheWrite1hUsd: model.costPer1kCacheWrite1hUsd }
40
+ : {}),
41
+ ...(model.webSearchPer1kUsd !== undefined
42
+ ? { webSearchPer1kUsd: model.webSearchPer1kUsd }
43
+ : {}),
44
+ },
45
+ };
46
+ }
47
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/gateway/pricing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAK9C,MAAM,UAAU,SAAS,CAAC,KAAoB,EAAE,KAAsB;IACpE,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,IAAI,KAAK,CAAC,kBAAkB,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACjG,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,WAAW,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChG,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,CAAC;IAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,KAAK,CAAC,uBAAuB,IAAI,KAAK,CAAC,iBAAiB,CAAC;IAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,sBAAsB,IAAI,KAAK,CAAC,iBAAiB,CAAC;IAC1E,MAAM,WAAW,GAAG,KAAK,CAAC,wBAAwB,IAAI,SAAS,CAAC;IAChE,MAAM,OAAO,GAAG,MAAM,CACpB,CAAC,CAAC,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,iBAAiB;QAC9D,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,UAAU;QAC5B,CAAC,CAAC,OAAO,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,SAAS;QAC1C,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,WAAW;QAChC,CAAC,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,kBAAkB;QAC1D,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC,CAC9D,CAAC;IACF,OAAO;QACL,OAAO;QACP,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;QAC7C,OAAO,EAAE;YACP,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;YAC5C,GAAG,CAAC,KAAK,CAAC,uBAAuB,KAAK,SAAS;gBAC7C,CAAC,CAAC,EAAE,uBAAuB,EAAE,KAAK,CAAC,uBAAuB,EAAE;gBAC5D,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,sBAAsB,KAAK,SAAS;gBAC5C,CAAC,CAAC,EAAE,sBAAsB,EAAE,KAAK,CAAC,sBAAsB,EAAE;gBAC1D,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,wBAAwB,KAAK,SAAS;gBAC9C,CAAC,CAAC,EAAE,wBAAwB,EAAE,KAAK,CAAC,wBAAwB,EAAE;gBAC9D,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,iBAAiB,KAAK,SAAS;gBACvC,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE;gBAChD,CAAC,CAAC,EAAE,CAAC;SACR;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `tierRoute` — model routing by quality tier (§6.13). Nodes ask for a
3
+ * tier (`fast` · `balanced` · `best`); `resolve` turns it into catalog
4
+ * keys for the call's context (the tenant's *Quality vs cost* setting,
5
+ * BYOK vs AI-included), best first: the first is the primary, the rest
6
+ * the fallback chain across providers.
7
+ *
8
+ * createLlmGateway({
9
+ * route: tierRoute({ resolve: ({ tier, context }) => tierKeys(context.tenantId, tier) }),
10
+ * …
11
+ * })
12
+ */
13
+ import type { GatewayContext, GatewayRequest, LlmGatewayConfig, ModelTier } from './types.js';
14
+ export interface TierRouteOptions {
15
+ /** Catalog keys for a tier, best first. An empty list leaves the call's own candidates. */
16
+ resolve(args: {
17
+ tier: ModelTier;
18
+ context: GatewayContext;
19
+ request: GatewayRequest;
20
+ }): string[] | Promise<string[]>;
21
+ /** When true the tier wins over an explicit `model`. Default false: an explicit model is kept. */
22
+ override?: boolean;
23
+ }
24
+ export declare function tierRoute(options: TierRouteOptions): NonNullable<LlmGatewayConfig['route']>;
25
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/gateway/routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE9F,MAAM,WAAW,gBAAgB;IAC/B,2FAA2F;IAC3F,OAAO,CAAC,IAAI,EAAE;QACZ,IAAI,EAAE,SAAS,CAAC;QAChB,OAAO,EAAE,cAAc,CAAC;QACxB,OAAO,EAAE,cAAc,CAAC;KACzB,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,kGAAkG;IAClG,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,WAAW,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAO3F"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `tierRoute` — model routing by quality tier (§6.13). Nodes ask for a
3
+ * tier (`fast` · `balanced` · `best`); `resolve` turns it into catalog
4
+ * keys for the call's context (the tenant's *Quality vs cost* setting,
5
+ * BYOK vs AI-included), best first: the first is the primary, the rest
6
+ * the fallback chain across providers.
7
+ *
8
+ * createLlmGateway({
9
+ * route: tierRoute({ resolve: ({ tier, context }) => tierKeys(context.tenantId, tier) }),
10
+ * …
11
+ * })
12
+ */
13
+ export function tierRoute(options) {
14
+ return async ({ context, request, candidates }) => {
15
+ if (!request.tier || (request.model && !options.override))
16
+ return candidates;
17
+ const keys = await options.resolve({ tier: request.tier, context, request });
18
+ if (keys.length === 0)
19
+ return candidates;
20
+ return [...keys, ...(request.fallbacks ?? [])];
21
+ };
22
+ }
23
+ //# sourceMappingURL=routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.js","sourceRoot":"","sources":["../../src/gateway/routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,MAAM,UAAU,SAAS,CAAC,OAAyB;IACjD,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE;QAChD,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;YAAE,OAAO,UAAU,CAAC;QAC7E,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QACzC,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * LLM gateway types — the single path every text-model call takes:
3
+ * route → resolve (catalog) → policies → credentials → call (retries +
4
+ * fallback) → record (cost ledger + audit trail).
5
+ */
6
+ import type { ChatProvider } from '../chat/types.js';
7
+ import type { ModelDescriptor } from '../cost/types.js';
8
+ import type { GenerateClient, GenerateRequest, GenerateResult, GenerateStreamEvent, GenerateUsage } from '../generate/types.js';
9
+ import type { AiTracer } from '../tracing/index.js';
10
+ export interface GatewayActor {
11
+ type: string;
12
+ id?: string;
13
+ }
14
+ /** Who a call is for — carried onto the ledger row and the audit trail. */
15
+ export interface GatewayContext {
16
+ /** `null` for platform calls. */
17
+ tenantId: string | null;
18
+ /** What made the call (`'workflow-runner'`, `'editorial.workflow/step'`): the ledger `source`. */
19
+ feature: string;
20
+ actor?: GatewayActor;
21
+ /** The row the call works on. */
22
+ target?: {
23
+ type: string;
24
+ id: string;
25
+ };
26
+ /** Threads the calls of one operation (a run). */
27
+ correlationId?: string;
28
+ /** Small, PII-free labels stored on the audit row. */
29
+ labels?: Record<string, string | number | boolean>;
30
+ }
31
+ /** Model quality tiers nodes declare (§6.13); any string works with a custom `route`. */
32
+ export type ModelTier = 'fast' | 'balanced' | 'best' | (string & {});
33
+ /** A `generate` request where `model` is a catalog key. */
34
+ export interface GatewayRequest extends Omit<GenerateRequest, 'model'> {
35
+ /** Catalog key. May be left out when `tier` is set and the gateway's `route` maps tiers to keys. */
36
+ model?: string;
37
+ /** Quality tier; the `route` hook (see `tierRoute`) turns it into catalog keys. */
38
+ tier?: ModelTier;
39
+ /** Catalog keys tried in order when the model can't serve the call. */
40
+ fallbacks?: string[];
41
+ }
42
+ export interface GatewayPricing {
43
+ costPer1kInputUsd: number;
44
+ costPer1kOutputUsd: number;
45
+ costPer1kCachedInputUsd?: number;
46
+ costPer1kCacheWriteUsd?: number;
47
+ costPer1kCacheWrite1hUsd?: number;
48
+ webSearchPer1kUsd?: number;
49
+ }
50
+ export interface GatewayCost {
51
+ costUsd: number;
52
+ costMicroUsd: number;
53
+ pricing?: GatewayPricing;
54
+ }
55
+ export type GatewayCredentialSource = 'platform' | 'tenant';
56
+ export interface GatewayCredential {
57
+ apiKey: string;
58
+ /** `platform` = the operator's key (the app pays), `tenant` = the customer's own key. */
59
+ source: GatewayCredentialSource;
60
+ baseUrl?: string;
61
+ }
62
+ export type GatewayAttemptOutcome = 'succeeded' | 'failed' | 'skipped' | 'denied';
63
+ /** One candidate model the gateway tried for a call. */
64
+ export interface GatewayAttempt {
65
+ modelKey: string;
66
+ provider?: ChatProvider;
67
+ outcome: GatewayAttemptOutcome;
68
+ /** Why it was skipped / denied / failed (`unknown_model`, `disabled`, policy code, `no_credentials`, …). */
69
+ reason?: string;
70
+ error?: string;
71
+ /** Vendor calls made for this candidate (retries included). */
72
+ calls?: number;
73
+ latencyMs?: number;
74
+ }
75
+ export interface GatewayPolicyDecision {
76
+ policy: string;
77
+ modelKey: string;
78
+ allowed: boolean;
79
+ code?: string;
80
+ message?: string;
81
+ }
82
+ export interface GatewayResult extends GenerateResult {
83
+ callId: string;
84
+ /** Catalog key that served the call. */
85
+ modelKey: string;
86
+ /** `null` when the model has no price or the vendor reported no usage. */
87
+ cost: GatewayCost | null;
88
+ attempts: GatewayAttempt[];
89
+ /** True when a fallback served the call. */
90
+ fellBack: boolean;
91
+ credentialSource: GatewayCredentialSource;
92
+ }
93
+ /** A gateway stream: the provider's events, then one `done` with the priced, recorded result. */
94
+ export type GatewayStreamEvent = Exclude<GenerateStreamEvent, {
95
+ type: 'done';
96
+ }> | {
97
+ type: 'done';
98
+ result: GatewayResult;
99
+ };
100
+ export interface GatewayPolicyCheck {
101
+ context: GatewayContext;
102
+ model: ModelDescriptor;
103
+ request: GatewayRequest;
104
+ /** True when this candidate is a fallback. */
105
+ isFallback: boolean;
106
+ }
107
+ /** Throw a `GatewayPolicyError` from `check` to deny the candidate. */
108
+ export interface GatewayPolicy {
109
+ name: string;
110
+ check(args: GatewayPolicyCheck): void | Promise<void>;
111
+ }
112
+ export type LlmCallStatus = 'succeeded' | 'failed' | 'denied' | 'cancelled';
113
+ /** What the audit trail keeps of a request: content in full, file bytes as size + hash. */
114
+ export interface LlmCallRequestRecord {
115
+ /** The catalog key asked for (`''` when only a tier was). */
116
+ model: string;
117
+ tier?: string;
118
+ fallbacks?: string[];
119
+ messages: unknown[];
120
+ tools?: string[];
121
+ toolChoice?: unknown;
122
+ webSearch?: unknown;
123
+ responseFormat?: unknown;
124
+ cache?: unknown;
125
+ maxTokens?: number;
126
+ temperature?: number;
127
+ topP?: number;
128
+ }
129
+ export interface LlmCallResponseRecord {
130
+ text: string;
131
+ json?: unknown;
132
+ toolCalls: unknown[];
133
+ citations: unknown[];
134
+ searchQueries: string[];
135
+ finishReason: string | null;
136
+ }
137
+ /** One gateway call, as the sinks receive it. */
138
+ export interface LlmCallRecord {
139
+ id: string;
140
+ context: GatewayContext;
141
+ status: LlmCallStatus;
142
+ modelKey: string | null;
143
+ provider: ChatProvider | null;
144
+ /** Wire model. */
145
+ model: string | null;
146
+ credentialSource: GatewayCredentialSource | null;
147
+ fellBack: boolean;
148
+ attempts: GatewayAttempt[];
149
+ policyDecisions: GatewayPolicyDecision[];
150
+ usage: GenerateUsage | null;
151
+ cost: GatewayCost | null;
152
+ latencyMs: number;
153
+ request: LlmCallRequestRecord;
154
+ response: LlmCallResponseRecord | null;
155
+ error: {
156
+ message: string;
157
+ code?: string;
158
+ } | null;
159
+ startedAt: string;
160
+ finishedAt: string;
161
+ }
162
+ /**
163
+ * Where calls are recorded. A sink failure is reported to `onSinkError`
164
+ * and never thrown: failing a call the vendor already served (and billed)
165
+ * would re-run it and bill it twice.
166
+ */
167
+ export interface GatewaySinks {
168
+ /** The audit trail: every call, served or not. */
169
+ recordCall?(record: LlmCallRecord): Promise<void>;
170
+ /** The cost ledger: calls the vendor billed (usage reported). */
171
+ recordCost?(record: LlmCallRecord): Promise<void>;
172
+ }
173
+ export interface GatewayCatalog {
174
+ find(key: string): ModelDescriptor | undefined | Promise<ModelDescriptor | undefined>;
175
+ }
176
+ export interface LlmGatewayConfig {
177
+ catalog: GatewayCatalog;
178
+ /** The API key for a candidate; throw (or reject) when there is none — the gateway moves on. */
179
+ credentials(args: {
180
+ context: GatewayContext;
181
+ model: ModelDescriptor;
182
+ }): GatewayCredential | Promise<GatewayCredential>;
183
+ policies?: GatewayPolicy[];
184
+ sinks?: GatewaySinks;
185
+ onSinkError?(error: unknown, info: {
186
+ sink: 'recordCall' | 'recordCost';
187
+ callId: string;
188
+ }): void;
189
+ /** Rewrite the candidate list (tier map, kill switches). Receives `[model, ...fallbacks]`. See `tierRoute`. */
190
+ route?(args: {
191
+ context: GatewayContext;
192
+ request: GatewayRequest;
193
+ candidates: string[];
194
+ }): string[] | Promise<string[]>;
195
+ /** OpenTelemetry tracer: one `chat <model>` span per call (see `../tracing`). */
196
+ tracer?: AiTracer;
197
+ /** Test seam / custom transport. Defaults to `createGenerateClient`. */
198
+ createClient?(args: {
199
+ provider: ChatProvider;
200
+ credential: GatewayCredential;
201
+ }): GenerateClient;
202
+ /** Vendor retries per candidate on 429 / 5xx / network. Default 3 attempts. */
203
+ retry?: {
204
+ maxAttempts?: number;
205
+ initialDelayMs?: number;
206
+ maxDelayMs?: number;
207
+ sleep?: (ms: number) => Promise<void>;
208
+ };
209
+ /** Default request timeout when the catalog has none. Default 120 s. */
210
+ defaultTimeoutMs?: number;
211
+ generateId?(): string;
212
+ }
213
+ /** A gateway bound to one context — what agents take as their `client`. */
214
+ export interface GatewayClient {
215
+ generate(request: GatewayRequest): Promise<GatewayResult>;
216
+ /** Streams the call; agents use it when asked to stream. */
217
+ stream?(request: GatewayRequest): AsyncIterable<GatewayStreamEvent>;
218
+ }
219
+ export interface LlmGateway {
220
+ generate(context: GatewayContext, request: GatewayRequest): Promise<GatewayResult>;
221
+ /** The same pipeline, streamed. Recorded once the stream ends (or is closed). */
222
+ stream(context: GatewayContext, request: GatewayRequest): AsyncIterable<GatewayStreamEvent>;
223
+ client(context: GatewayContext): GatewayClient;
224
+ }
225
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * LLM gateway types — the single path every text-model call takes:
3
+ * route → resolve (catalog) → policies → credentials → call (retries +
4
+ * fallback) → record (cost ledger + audit trail).
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Anthropic `generate` adapter — Messages API with function tools, the
3
+ * native web search tool (`web_search_20250305`), document / image inputs,
4
+ * prompt caching (`cache_control` breakpoints, 5-minute or 1-hour) and
5
+ * streaming.
6
+ *
7
+ * Structured output: when the call has no other tools, the schema becomes
8
+ * one forced tool whose input IS the answer (exact schema adherence);
9
+ * otherwise the schema is stated in the system prompt and the reply parsed.
10
+ *
11
+ * The assistant's raw content blocks are returned as `providerState` and
12
+ * replayed verbatim on the next turn — server-tool blocks (searches and
13
+ * their results) must travel with the conversation.
14
+ */
15
+ import type { CacheOptions, GenerateAdapterConfig, GenerateMessage, GenerateRequest, GenerateResult, GenerateStreamEvent } from './types.js';
16
+ type Block = Record<string, unknown> & {
17
+ type: string;
18
+ };
19
+ export declare function generateWithAnthropic(config: GenerateAdapterConfig, request: GenerateRequest): Promise<GenerateResult>;
20
+ /** Streams a Messages call; the final `done` result is built exactly as `generateWithAnthropic` builds it. */
21
+ export declare function streamWithAnthropic(config: GenerateAdapterConfig, request: GenerateRequest): AsyncGenerator<GenerateStreamEvent>;
22
+ /**
23
+ * Provider-neutral history → Anthropic messages: system split out, tool
24
+ * results grouped into one user turn, consecutive same-role turns merged.
25
+ * Messages marked `cache: true` get a `cache_control` breakpoint on their
26
+ * last block — the system one plus the latest three (Anthropic's limit).
27
+ */
28
+ export declare function toAnthropicMessages(input: GenerateMessage[], cache?: CacheOptions): {
29
+ system: string | undefined;
30
+ systemCache: boolean;
31
+ messages: Array<{
32
+ role: 'user' | 'assistant';
33
+ content: Block[];
34
+ }>;
35
+ breakpoints: number;
36
+ };
37
+ export {};
38
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/generate/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,OAAO,KAAK,EACV,YAAY,EAGZ,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,cAAc,EACd,mBAAmB,EAGpB,MAAM,YAAY,CAAC;AASpB,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAqHxD,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED,8GAA8G;AAC9G,wBAAuB,mBAAmB,CACxC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,eAAe,GACvB,cAAc,CAAC,mBAAmB,CAAC,CAsFrC;AA0KD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,eAAe,EAAE,EACxB,KAAK,CAAC,EAAE,YAAY,GACnB;IACD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,OAAO,EAAE,KAAK,EAAE,CAAA;KAAE,CAAC,CAAC;IAClE,WAAW,EAAE,MAAM,CAAC;CACrB,CA4EA"}