pi-smart-router 0.1.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/.pi/extensions/smart-router/command-formatters.ts +167 -0
- package/.pi/extensions/smart-router/commands.ts +242 -0
- package/.pi/extensions/smart-router/dataset-export.ts +142 -0
- package/.pi/extensions/smart-router/delegate-stream.ts +105 -0
- package/.pi/extensions/smart-router/delegation-runtime.ts +355 -0
- package/.pi/extensions/smart-router/extension-setup.ts +115 -0
- package/.pi/extensions/smart-router/fleet-bootstrap.ts +244 -0
- package/.pi/extensions/smart-router/index.ts +115 -0
- package/.pi/extensions/smart-router/package.json +3 -0
- package/.pi/extensions/smart-router/pi-model-scope.ts +55 -0
- package/.pi/extensions/smart-router/pricing-lifecycle.ts +43 -0
- package/.pi/extensions/smart-router/route-and-delegate.ts +562 -0
- package/.pi/extensions/smart-router/routing-context.ts +171 -0
- package/.pi/extensions/smart-router/routing-outcomes.ts +44 -0
- package/.pi/extensions/smart-router/session-lifecycle.ts +140 -0
- package/.pi/extensions/smart-router/stream-delegation.ts +75 -0
- package/.pi/extensions/smart-router/types.ts +90 -0
- package/.pi/extensions/smart-router/utils.ts +58 -0
- package/README.md +593 -0
- package/bin/pi-smart-router.mjs +79 -0
- package/config/.gitkeep +0 -0
- package/config/hydra-projection-weights.json.example +1169 -0
- package/config/models.yaml.example +58 -0
- package/config/p-success-weights.json.example +19 -0
- package/config/routing-calibration.json.example +1605 -0
- package/config/routing-centroids.json.example +1570 -0
- package/config/routing-clusters.yaml.example +41 -0
- package/data/contrib/example.json +25 -0
- package/dist/api/explain/router-explain.d.ts +47 -0
- package/dist/api/explain/router-explain.d.ts.map +1 -0
- package/dist/api/explain/router-explain.js +101 -0
- package/dist/api/explain/router-explain.js.map +1 -0
- package/dist/api/middleware/pi-router-middleware.d.ts +86 -0
- package/dist/api/middleware/pi-router-middleware.d.ts.map +1 -0
- package/dist/api/middleware/pi-router-middleware.js +83 -0
- package/dist/api/middleware/pi-router-middleware.js.map +1 -0
- package/dist/cli/smart-router-cli.d.ts +85 -0
- package/dist/cli/smart-router-cli.d.ts.map +1 -0
- package/dist/cli/smart-router-cli.js +293 -0
- package/dist/cli/smart-router-cli.js.map +1 -0
- package/dist/config/defaults.d.ts +7 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +33 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/models-loader.d.ts +22 -0
- package/dist/config/models-loader.d.ts.map +1 -0
- package/dist/config/models-loader.js +51 -0
- package/dist/config/models-loader.js.map +1 -0
- package/dist/config/pi-model-mapper.d.ts +40 -0
- package/dist/config/pi-model-mapper.d.ts.map +1 -0
- package/dist/config/pi-model-mapper.js +216 -0
- package/dist/config/pi-model-mapper.js.map +1 -0
- package/dist/config/routing-clusters-loader.d.ts +35 -0
- package/dist/config/routing-clusters-loader.d.ts.map +1 -0
- package/dist/config/routing-clusters-loader.js +100 -0
- package/dist/config/routing-clusters-loader.js.map +1 -0
- package/dist/domain/delegation/delegation-context.d.ts +23 -0
- package/dist/domain/delegation/delegation-context.d.ts.map +1 -0
- package/dist/domain/delegation/delegation-context.js +73 -0
- package/dist/domain/delegation/delegation-context.js.map +1 -0
- package/dist/domain/delegation/execution-ledger.d.ts +19 -0
- package/dist/domain/delegation/execution-ledger.d.ts.map +1 -0
- package/dist/domain/delegation/execution-ledger.js +23 -0
- package/dist/domain/delegation/execution-ledger.js.map +1 -0
- package/dist/domain/delegation/output-headroom.d.ts +39 -0
- package/dist/domain/delegation/output-headroom.d.ts.map +1 -0
- package/dist/domain/delegation/output-headroom.js +78 -0
- package/dist/domain/delegation/output-headroom.js.map +1 -0
- package/dist/domain/matching/cluster-matcher.d.ts +69 -0
- package/dist/domain/matching/cluster-matcher.d.ts.map +1 -0
- package/dist/domain/matching/cluster-matcher.js +294 -0
- package/dist/domain/matching/cluster-matcher.js.map +1 -0
- package/dist/domain/matching/embedding-provider.d.ts +21 -0
- package/dist/domain/matching/embedding-provider.d.ts.map +1 -0
- package/dist/domain/matching/embedding-provider.js +42 -0
- package/dist/domain/matching/embedding-provider.js.map +1 -0
- package/dist/domain/matching/hydra-input.d.ts +18 -0
- package/dist/domain/matching/hydra-input.d.ts.map +1 -0
- package/dist/domain/matching/hydra-input.js +40 -0
- package/dist/domain/matching/hydra-input.js.map +1 -0
- package/dist/domain/matching/hydra-matcher.d.ts +103 -0
- package/dist/domain/matching/hydra-matcher.d.ts.map +1 -0
- package/dist/domain/matching/hydra-matcher.js +275 -0
- package/dist/domain/matching/hydra-matcher.js.map +1 -0
- package/dist/domain/pinning/cache-economics.d.ts +53 -0
- package/dist/domain/pinning/cache-economics.d.ts.map +1 -0
- package/dist/domain/pinning/cache-economics.js +72 -0
- package/dist/domain/pinning/cache-economics.js.map +1 -0
- package/dist/domain/pinning/loop-escalation.d.ts +41 -0
- package/dist/domain/pinning/loop-escalation.d.ts.map +1 -0
- package/dist/domain/pinning/loop-escalation.js +137 -0
- package/dist/domain/pinning/loop-escalation.js.map +1 -0
- package/dist/domain/pinning/session-pinner.d.ts +81 -0
- package/dist/domain/pinning/session-pinner.d.ts.map +1 -0
- package/dist/domain/pinning/session-pinner.js +237 -0
- package/dist/domain/pinning/session-pinner.js.map +1 -0
- package/dist/domain/pinning/sub-route-policy.d.ts +41 -0
- package/dist/domain/pinning/sub-route-policy.d.ts.map +1 -0
- package/dist/domain/pinning/sub-route-policy.js +72 -0
- package/dist/domain/pinning/sub-route-policy.js.map +1 -0
- package/dist/domain/pipeline/router-pipeline.d.ts +180 -0
- package/dist/domain/pipeline/router-pipeline.d.ts.map +1 -0
- package/dist/domain/pipeline/router-pipeline.js +807 -0
- package/dist/domain/pipeline/router-pipeline.js.map +1 -0
- package/dist/domain/pipeline/safe-default.d.ts +25 -0
- package/dist/domain/pipeline/safe-default.d.ts.map +1 -0
- package/dist/domain/pipeline/safe-default.js +41 -0
- package/dist/domain/pipeline/safe-default.js.map +1 -0
- package/dist/domain/refactor-guardrails.d.ts +48 -0
- package/dist/domain/refactor-guardrails.d.ts.map +1 -0
- package/dist/domain/refactor-guardrails.js +129 -0
- package/dist/domain/refactor-guardrails.js.map +1 -0
- package/dist/domain/routing/context-fit.d.ts +53 -0
- package/dist/domain/routing/context-fit.d.ts.map +1 -0
- package/dist/domain/routing/context-fit.js +142 -0
- package/dist/domain/routing/context-fit.js.map +1 -0
- package/dist/domain/routing/expected-cost.d.ts +63 -0
- package/dist/domain/routing/expected-cost.d.ts.map +1 -0
- package/dist/domain/routing/expected-cost.js +177 -0
- package/dist/domain/routing/expected-cost.js.map +1 -0
- package/dist/domain/routing/p-success-classifier.d.ts +130 -0
- package/dist/domain/routing/p-success-classifier.d.ts.map +1 -0
- package/dist/domain/routing/p-success-classifier.js +350 -0
- package/dist/domain/routing/p-success-classifier.js.map +1 -0
- package/dist/domain/routing/tier-features.d.ts +70 -0
- package/dist/domain/routing/tier-features.d.ts.map +1 -0
- package/dist/domain/routing/tier-features.js +174 -0
- package/dist/domain/routing/tier-features.js.map +1 -0
- package/dist/domain/routing/tool-history-guard.d.ts +32 -0
- package/dist/domain/routing/tool-history-guard.d.ts.map +1 -0
- package/dist/domain/routing/tool-history-guard.js +110 -0
- package/dist/domain/routing/tool-history-guard.js.map +1 -0
- package/dist/domain/scoring/multi-objective.d.ts +48 -0
- package/dist/domain/scoring/multi-objective.d.ts.map +1 -0
- package/dist/domain/scoring/multi-objective.js +116 -0
- package/dist/domain/scoring/multi-objective.js.map +1 -0
- package/dist/domain/triage/triage-engine.d.ts +43 -0
- package/dist/domain/triage/triage-engine.d.ts.map +1 -0
- package/dist/domain/triage/triage-engine.js +317 -0
- package/dist/domain/triage/triage-engine.js.map +1 -0
- package/dist/domain/triage/turn-envelope.d.ts +17 -0
- package/dist/domain/triage/turn-envelope.d.ts.map +1 -0
- package/dist/domain/triage/turn-envelope.js +81 -0
- package/dist/domain/triage/turn-envelope.js.map +1 -0
- package/dist/domain/types/entities.d.ts +303 -0
- package/dist/domain/types/entities.d.ts.map +1 -0
- package/dist/domain/types/entities.js +6 -0
- package/dist/domain/types/entities.js.map +1 -0
- package/dist/domain/types/index.d.ts +4 -0
- package/dist/domain/types/index.d.ts.map +1 -0
- package/dist/domain/types/index.js +2 -0
- package/dist/domain/types/index.js.map +1 -0
- package/dist/domain/types/schemas.d.ts +346 -0
- package/dist/domain/types/schemas.d.ts.map +1 -0
- package/dist/domain/types/schemas.js +241 -0
- package/dist/domain/types/schemas.js.map +1 -0
- package/dist/domain/types/store-port.d.ts +44 -0
- package/dist/domain/types/store-port.d.ts.map +1 -0
- package/dist/domain/types/store-port.js +6 -0
- package/dist/domain/types/store-port.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/gemini-provider.d.ts +28 -0
- package/dist/infra/gemini-provider.d.ts.map +1 -0
- package/dist/infra/gemini-provider.js +112 -0
- package/dist/infra/gemini-provider.js.map +1 -0
- package/dist/infra/telemetry.d.ts +51 -0
- package/dist/infra/telemetry.d.ts.map +1 -0
- package/dist/infra/telemetry.js +100 -0
- package/dist/infra/telemetry.js.map +1 -0
- package/dist/infrastructure/delegation/provider-error.d.ts +44 -0
- package/dist/infrastructure/delegation/provider-error.d.ts.map +1 -0
- package/dist/infrastructure/delegation/provider-error.js +179 -0
- package/dist/infrastructure/delegation/provider-error.js.map +1 -0
- package/dist/infrastructure/gateway/circuit-breaker.d.ts +68 -0
- package/dist/infrastructure/gateway/circuit-breaker.d.ts.map +1 -0
- package/dist/infrastructure/gateway/circuit-breaker.js +150 -0
- package/dist/infrastructure/gateway/circuit-breaker.js.map +1 -0
- package/dist/infrastructure/gateway/gateway-dispatch.d.ts +138 -0
- package/dist/infrastructure/gateway/gateway-dispatch.d.ts.map +1 -0
- package/dist/infrastructure/gateway/gateway-dispatch.js +308 -0
- package/dist/infrastructure/gateway/gateway-dispatch.js.map +1 -0
- package/dist/infrastructure/hardware/hardware-probe.d.ts +32 -0
- package/dist/infrastructure/hardware/hardware-probe.d.ts.map +1 -0
- package/dist/infrastructure/hardware/hardware-probe.js +199 -0
- package/dist/infrastructure/hardware/hardware-probe.js.map +1 -0
- package/dist/infrastructure/local/local-zero-tier.d.ts +47 -0
- package/dist/infrastructure/local/local-zero-tier.d.ts.map +1 -0
- package/dist/infrastructure/local/local-zero-tier.js +92 -0
- package/dist/infrastructure/local/local-zero-tier.js.map +1 -0
- package/dist/infrastructure/persistence/memory-store.d.ts +31 -0
- package/dist/infrastructure/persistence/memory-store.d.ts.map +1 -0
- package/dist/infrastructure/persistence/memory-store.js +87 -0
- package/dist/infrastructure/persistence/memory-store.js.map +1 -0
- package/dist/infrastructure/persistence/sqlite-store.d.ts +81 -0
- package/dist/infrastructure/persistence/sqlite-store.d.ts.map +1 -0
- package/dist/infrastructure/persistence/sqlite-store.js +658 -0
- package/dist/infrastructure/persistence/sqlite-store.js.map +1 -0
- package/dist/infrastructure/pricing/litellm-fetch.d.ts +46 -0
- package/dist/infrastructure/pricing/litellm-fetch.d.ts.map +1 -0
- package/dist/infrastructure/pricing/litellm-fetch.js +145 -0
- package/dist/infrastructure/pricing/litellm-fetch.js.map +1 -0
- package/dist/infrastructure/pricing/price-broker.d.ts +56 -0
- package/dist/infrastructure/pricing/price-broker.d.ts.map +1 -0
- package/dist/infrastructure/pricing/price-broker.js +133 -0
- package/dist/infrastructure/pricing/price-broker.js.map +1 -0
- package/dist/infrastructure/pricing/pricing-monitor.d.ts +27 -0
- package/dist/infrastructure/pricing/pricing-monitor.d.ts.map +1 -0
- package/dist/infrastructure/pricing/pricing-monitor.js +46 -0
- package/dist/infrastructure/pricing/pricing-monitor.js.map +1 -0
- package/dist/infrastructure/telemetry/dataset-limits.d.ts +13 -0
- package/dist/infrastructure/telemetry/dataset-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/dataset-limits.js +28 -0
- package/dist/infrastructure/telemetry/dataset-limits.js.map +1 -0
- package/dist/infrastructure/telemetry/dataset-recorder.d.ts +48 -0
- package/dist/infrastructure/telemetry/dataset-recorder.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/dataset-recorder.js +154 -0
- package/dist/infrastructure/telemetry/dataset-recorder.js.map +1 -0
- package/dist/infrastructure/telemetry/outcome-limits.d.ts +12 -0
- package/dist/infrastructure/telemetry/outcome-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/outcome-limits.js +28 -0
- package/dist/infrastructure/telemetry/outcome-limits.js.map +1 -0
- package/dist/infrastructure/telemetry/outcome-recorder.d.ts +29 -0
- package/dist/infrastructure/telemetry/outcome-recorder.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/outcome-recorder.js +49 -0
- package/dist/infrastructure/telemetry/outcome-recorder.js.map +1 -0
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts +115 -0
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/routing-telemetry.js +529 -0
- package/dist/infrastructure/telemetry/routing-telemetry.js.map +1 -0
- package/dist/infrastructure/telemetry/telemetry-limits.d.ts +16 -0
- package/dist/infrastructure/telemetry/telemetry-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/telemetry-limits.js +35 -0
- package/dist/infrastructure/telemetry/telemetry-limits.js.map +1 -0
- package/package.json +110 -0
- package/skills/router-backlog-orchestrator/SKILL.md +183 -0
- package/skills/router-backlog-orchestrator/references/github-router-issue-template.md +78 -0
- package/skills/router-backlog-orchestrator/references/packet-from-issue.md +99 -0
- package/skills/router-backlog-orchestrator/references/prioritization-rubric.md +65 -0
- package/skills/router-backlog-orchestrator/scripts/collect-backlog.sh +44 -0
- package/specs/001-build-smart-router/contracts/telemetry-contrib.schema.json +151 -0
- package/src/api/explain/.gitkeep +0 -0
- package/src/api/explain/router-explain.ts +146 -0
- package/src/api/middleware/.gitkeep +0 -0
- package/src/api/middleware/pi-router-middleware.ts +169 -0
- package/src/cli/smart-router-cli.ts +436 -0
- package/src/config/.gitkeep +0 -0
- package/src/config/defaults.ts +35 -0
- package/src/config/models-loader.ts +68 -0
- package/src/config/pi-model-mapper.ts +285 -0
- package/src/config/routing-clusters-loader.ts +148 -0
- package/src/domain/delegation/delegation-context.ts +111 -0
- package/src/domain/delegation/execution-ledger.ts +34 -0
- package/src/domain/delegation/output-headroom.ts +131 -0
- package/src/domain/matching/.gitkeep +0 -0
- package/src/domain/matching/cluster-matcher.ts +474 -0
- package/src/domain/matching/embedding-provider.ts +79 -0
- package/src/domain/matching/hydra-input.ts +53 -0
- package/src/domain/matching/hydra-matcher.ts +454 -0
- package/src/domain/pinning/.gitkeep +0 -0
- package/src/domain/pinning/cache-economics.ts +128 -0
- package/src/domain/pinning/loop-escalation.ts +181 -0
- package/src/domain/pinning/session-pinner.ts +388 -0
- package/src/domain/pinning/sub-route-policy.ts +119 -0
- package/src/domain/pipeline/.gitkeep +0 -0
- package/src/domain/pipeline/router-pipeline.ts +1139 -0
- package/src/domain/pipeline/safe-default.ts +70 -0
- package/src/domain/refactor-guardrails.ts +202 -0
- package/src/domain/routing/context-fit.ts +221 -0
- package/src/domain/routing/expected-cost.ts +320 -0
- package/src/domain/routing/p-success-classifier.ts +511 -0
- package/src/domain/routing/tier-features.ts +290 -0
- package/src/domain/routing/tool-history-guard.ts +159 -0
- package/src/domain/scoring/.gitkeep +0 -0
- package/src/domain/scoring/multi-objective.ts +175 -0
- package/src/domain/triage/.gitkeep +0 -0
- package/src/domain/triage/triage-engine.ts +373 -0
- package/src/domain/triage/turn-envelope.ts +104 -0
- package/src/domain/types/.gitkeep +0 -0
- package/src/domain/types/entities.ts +384 -0
- package/src/domain/types/index.ts +41 -0
- package/src/domain/types/schemas.ts +289 -0
- package/src/domain/types/store-port.ts +59 -0
- package/src/index.ts +103 -0
- package/src/infra/gemini-provider.ts +142 -0
- package/src/infra/telemetry.ts +169 -0
- package/src/infrastructure/delegation/provider-error.ts +251 -0
- package/src/infrastructure/gateway/.gitkeep +0 -0
- package/src/infrastructure/gateway/circuit-breaker.ts +196 -0
- package/src/infrastructure/gateway/gateway-dispatch.ts +444 -0
- package/src/infrastructure/hardware/.gitkeep +0 -0
- package/src/infrastructure/hardware/hardware-probe.ts +276 -0
- package/src/infrastructure/local/.gitkeep +0 -0
- package/src/infrastructure/local/local-zero-tier.ts +151 -0
- package/src/infrastructure/persistence/.gitkeep +0 -0
- package/src/infrastructure/persistence/memory-store.ts +122 -0
- package/src/infrastructure/persistence/sqlite-store.ts +900 -0
- package/src/infrastructure/pricing/.gitkeep +0 -0
- package/src/infrastructure/pricing/litellm-fetch.ts +215 -0
- package/src/infrastructure/pricing/price-broker.ts +183 -0
- package/src/infrastructure/pricing/pricing-monitor.ts +65 -0
- package/src/infrastructure/telemetry/.gitkeep +0 -0
- package/src/infrastructure/telemetry/dataset-limits.ts +39 -0
- package/src/infrastructure/telemetry/dataset-recorder.ts +215 -0
- package/src/infrastructure/telemetry/outcome-limits.ts +42 -0
- package/src/infrastructure/telemetry/outcome-recorder.ts +118 -0
- package/src/infrastructure/telemetry/routing-telemetry.ts +824 -0
- package/src/infrastructure/telemetry/telemetry-limits.ts +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public package exports — pi-smart-router.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the router factory (T022) and pi lifecycle hook registrar (T021).
|
|
5
|
+
* Full pi integration uses `.pi/extensions/smart-router/`; library embedders
|
|
6
|
+
* route via `dispatch.dispatch()` after calling `register(hooks)`.
|
|
7
|
+
*/
|
|
8
|
+
import type { ModelProfile, RoutingDecision } from './domain/types/index.js';
|
|
9
|
+
import { type FleetCatalog } from './config/models-loader.js';
|
|
10
|
+
import { loadRoutingClusters, clusterReasonCode, type TextEmbedder } from './config/routing-clusters-loader.js';
|
|
11
|
+
import { GatewayDispatch, type GatewayDispatchOptions } from './infrastructure/gateway/gateway-dispatch.js';
|
|
12
|
+
import { LifecycleHookState, type PiRouterMiddleware, type PiExtensionHooks } from './api/middleware/pi-router-middleware.js';
|
|
13
|
+
/** Package identifier for diagnostics and telemetry. */
|
|
14
|
+
export declare const PACKAGE_NAME: "pi-smart-router";
|
|
15
|
+
export interface RouterFactoryOptions {
|
|
16
|
+
readonly modelsPath?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface RouterHandle {
|
|
19
|
+
readonly version: string;
|
|
20
|
+
readonly middleware: PiRouterMiddleware;
|
|
21
|
+
readonly dispatch: GatewayDispatch;
|
|
22
|
+
readonly fleet: readonly ModelProfile[];
|
|
23
|
+
readonly register: (hooks: PiExtensionHooks) => void;
|
|
24
|
+
}
|
|
25
|
+
export declare function createRouter(options?: RouterFactoryOptions): RouterHandle;
|
|
26
|
+
export declare function createRouterFromCatalog(catalog: FleetCatalog): RouterHandle;
|
|
27
|
+
export interface CreateRouterFromFleetOptions extends GatewayDispatchOptions {
|
|
28
|
+
readonly lifecycleHookState?: LifecycleHookState;
|
|
29
|
+
}
|
|
30
|
+
export declare function createRouterFromFleet(fleet: ModelProfile[], options?: CreateRouterFromFleetOptions): RouterHandle;
|
|
31
|
+
export type { RoutingDecision, ModelProfile };
|
|
32
|
+
export { loadRoutingClusters, clusterReasonCode, };
|
|
33
|
+
export type { TextEmbedder };
|
|
34
|
+
export type { RoutingClusterCatalog } from './domain/types/index.js';
|
|
35
|
+
export type { PiRouterMiddleware, PiRouterMiddlewareOptions, PiExtensionHooks, PiExtensionContext, PiProviderRequestEvent, PiContextEvent, PiModelSelectEvent, PiSessionManager, LifecycleFlags, } from './api/middleware/pi-router-middleware.js';
|
|
36
|
+
export { createPiRouterMiddleware, LifecycleHookState } from './api/middleware/pi-router-middleware.js';
|
|
37
|
+
export type { GatewayDispatchOptions } from './infrastructure/gateway/gateway-dispatch.js';
|
|
38
|
+
export type { PipelineOptions } from './domain/pipeline/router-pipeline.js';
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,YAAY,EAClB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC5B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAEL,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACtB,MAAM,0CAA0C,CAAC;AAElD,wDAAwD;AACxD,eAAO,MAAM,YAAY,EAAG,iBAA0B,CAAC;AAIvD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACtD;AAID,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,YAAY,CAMzE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,CAE3E;AAED,MAAM,WAAW,4BAA6B,SAAQ,sBAAsB;IAC1E,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CAClD;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAcd;AAID,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAC9C,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAClB,CAAC;AACF,YAAY,EAAE,YAAY,EAAE,CAAC;AAC7B,YAAY,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACrE,YAAY,EACV,kBAAkB,EAClB,yBAAyB,EACzB,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,GACf,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AACxG,YAAY,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AAC3F,YAAY,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public package exports — pi-smart-router.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the router factory (T022) and pi lifecycle hook registrar (T021).
|
|
5
|
+
* Full pi integration uses `.pi/extensions/smart-router/`; library embedders
|
|
6
|
+
* route via `dispatch.dispatch()` after calling `register(hooks)`.
|
|
7
|
+
*/
|
|
8
|
+
import { loadModels } from './config/models-loader.js';
|
|
9
|
+
import { loadRoutingClusters, clusterReasonCode, } from './config/routing-clusters-loader.js';
|
|
10
|
+
import { GatewayDispatch, } from './infrastructure/gateway/gateway-dispatch.js';
|
|
11
|
+
import { createPiRouterMiddleware, } from './api/middleware/pi-router-middleware.js';
|
|
12
|
+
/** Package identifier for diagnostics and telemetry. */
|
|
13
|
+
export const PACKAGE_NAME = 'pi-smart-router';
|
|
14
|
+
// ─── Router factory (T022) ───────────────────────────────────────────────────
|
|
15
|
+
export function createRouter(options) {
|
|
16
|
+
const catalog = loadModels(options?.modelsPath ? { filePath: options.modelsPath } : undefined);
|
|
17
|
+
return createRouterFromCatalog(catalog);
|
|
18
|
+
}
|
|
19
|
+
export function createRouterFromCatalog(catalog) {
|
|
20
|
+
return createRouterFromFleet([...catalog.models]);
|
|
21
|
+
}
|
|
22
|
+
export function createRouterFromFleet(fleet, options) {
|
|
23
|
+
const { lifecycleHookState, ...dispatchOptions } = options ?? {};
|
|
24
|
+
const dispatch = new GatewayDispatch(fleet, dispatchOptions);
|
|
25
|
+
const middleware = createPiRouterMiddleware(lifecycleHookState !== undefined ? { lifecycleHookState } : undefined);
|
|
26
|
+
return {
|
|
27
|
+
version: 'pi-smart-router',
|
|
28
|
+
middleware,
|
|
29
|
+
dispatch,
|
|
30
|
+
fleet,
|
|
31
|
+
register: middleware.register,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export { loadRoutingClusters, clusterReasonCode, };
|
|
35
|
+
export { createPiRouterMiddleware, LifecycleHookState } from './api/middleware/pi-router-middleware.js';
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,UAAU,EAAqB,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAElB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,eAAe,GAEhB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACL,wBAAwB,GAIzB,MAAM,0CAA0C,CAAC;AAElD,wDAAwD;AACxD,MAAM,CAAC,MAAM,YAAY,GAAG,iBAA0B,CAAC;AAgBvD,gFAAgF;AAEhF,MAAM,UAAU,YAAY,CAAC,OAA8B;IACzD,MAAM,OAAO,GAAG,UAAU,CACxB,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,SAAS,CACnE,CAAC;IAEF,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAqB;IAC3D,OAAO,qBAAqB,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACpD,CAAC;AAMD,MAAM,UAAU,qBAAqB,CACnC,KAAqB,EACrB,OAAsC;IAEtC,MAAM,EAAE,kBAAkB,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,wBAAwB,CACzC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,SAAS,CACtE,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,iBAAiB;QAC1B,UAAU;QACV,QAAQ;QACR,KAAK;QACL,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAC9B,CAAC;AACJ,CAAC;AAKD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAClB,CAAC;AAcF,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini provider error classification and failover policy.
|
|
3
|
+
*
|
|
4
|
+
* thought_signature 400s are client/protocol validation errors (FR-018),
|
|
5
|
+
* not infrastructure outages — they must return terminal errors, not trigger
|
|
6
|
+
* stream delegation failover.
|
|
7
|
+
*/
|
|
8
|
+
import type { AssistantMessage } from '@earendil-works/pi-ai/compat';
|
|
9
|
+
export interface GeminiProviderError {
|
|
10
|
+
readonly statusCode?: number;
|
|
11
|
+
readonly code?: string;
|
|
12
|
+
readonly message?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Gemini returns 400 INVALID_ARGUMENT when tool-call replay omits thought_signature.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isGeminiThoughtSignatureError(parsed: GeminiProviderError): boolean;
|
|
18
|
+
export declare function isGeminiThoughtSignatureAssistantError(message: AssistantMessage): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Returns true when a Gemini provider error should trigger failover.
|
|
21
|
+
* thought_signature validation failures are terminal — never failover.
|
|
22
|
+
*/
|
|
23
|
+
export declare function shouldFailoverOnGeminiError(parsed: GeminiProviderError): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Format a Gemini thought_signature validation error with operator workarounds.
|
|
26
|
+
*/
|
|
27
|
+
export declare function formatGeminiThoughtSignatureErrorMessage(errorMessage: string): string;
|
|
28
|
+
//# sourceMappingURL=gemini-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-provider.d.ts","sourceRoot":"","sources":["../../src/infra/gemini-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAKlF;AAED,wBAAgB,sCAAsC,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAKzF;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAKhF;AAMD;;GAEG;AACH,wBAAgB,wCAAwC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAsBrF"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini provider error classification and failover policy.
|
|
3
|
+
*
|
|
4
|
+
* thought_signature 400s are client/protocol validation errors (FR-018),
|
|
5
|
+
* not infrastructure outages — they must return terminal errors, not trigger
|
|
6
|
+
* stream delegation failover.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Gemini returns 400 INVALID_ARGUMENT when tool-call replay omits thought_signature.
|
|
10
|
+
*/
|
|
11
|
+
export function isGeminiThoughtSignatureError(parsed) {
|
|
12
|
+
return (parsed.statusCode === 400 &&
|
|
13
|
+
parsed.message?.includes('thought_signature') === true);
|
|
14
|
+
}
|
|
15
|
+
export function isGeminiThoughtSignatureAssistantError(message) {
|
|
16
|
+
if (message.stopReason !== 'error' || !message.errorMessage) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return isGeminiThoughtSignatureError(parseGeminiErrorBlob(message.errorMessage));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Returns true when a Gemini provider error should trigger failover.
|
|
23
|
+
* thought_signature validation failures are terminal — never failover.
|
|
24
|
+
*/
|
|
25
|
+
export function shouldFailoverOnGeminiError(parsed) {
|
|
26
|
+
if (isGeminiThoughtSignatureError(parsed)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return parsed.statusCode !== undefined && (parsed.statusCode >= 500 || parsed.statusCode === 429);
|
|
30
|
+
}
|
|
31
|
+
const GEMINI_THOUGHT_SIGNATURE_DOCS = 'https://ai.google.dev/gemini-api/docs/generate-content/thought-signatures';
|
|
32
|
+
const PI_THOUGHT_SIGNATURE_ISSUE = 'https://github.com/earendil-works/pi/issues/6342';
|
|
33
|
+
/**
|
|
34
|
+
* Format a Gemini thought_signature validation error with operator workarounds.
|
|
35
|
+
*/
|
|
36
|
+
export function formatGeminiThoughtSignatureErrorMessage(errorMessage) {
|
|
37
|
+
const parsed = parseGeminiErrorBlob(errorMessage);
|
|
38
|
+
const prefixParts = [];
|
|
39
|
+
if (parsed.statusCode !== undefined) {
|
|
40
|
+
prefixParts.push(String(parsed.statusCode));
|
|
41
|
+
}
|
|
42
|
+
if (parsed.code) {
|
|
43
|
+
prefixParts.push(parsed.code);
|
|
44
|
+
}
|
|
45
|
+
const summary = parsed.message && prefixParts.length > 0
|
|
46
|
+
? `${prefixParts.join(' ')}: ${parsed.message}`
|
|
47
|
+
: parsed.message ?? 'Provider error (thought_signature validation)';
|
|
48
|
+
return [
|
|
49
|
+
summary,
|
|
50
|
+
'',
|
|
51
|
+
'Gemini rejected this request because a prior tool call is missing its thought_signature (protocol validation, not provider outage).',
|
|
52
|
+
'Workarounds: start a fresh session with /new, or route to a non-Google model until pi preserves thought signatures in replay.',
|
|
53
|
+
`Docs: ${GEMINI_THOUGHT_SIGNATURE_DOCS}`,
|
|
54
|
+
`Upstream: ${PI_THOUGHT_SIGNATURE_ISSUE}`,
|
|
55
|
+
].join('\n');
|
|
56
|
+
}
|
|
57
|
+
function parseGeminiErrorBlob(errorMessage) {
|
|
58
|
+
const trimmed = errorMessage.trim();
|
|
59
|
+
if (!trimmed.startsWith('{')) {
|
|
60
|
+
return trimmed.includes('thought_signature') ? { statusCode: 400, message: trimmed } : {};
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const parsed = JSON.parse(trimmed);
|
|
64
|
+
const nested = parsed.error;
|
|
65
|
+
const statusCode = parseNumericCode(nested?.code) ??
|
|
66
|
+
parseNumericCode(nested?.status) ??
|
|
67
|
+
parseNumericCode(parsed.code) ??
|
|
68
|
+
parseNumericCode(parsed.status);
|
|
69
|
+
const code = typeof nested?.status === 'string'
|
|
70
|
+
? nested.status
|
|
71
|
+
: typeof parsed.status === 'string'
|
|
72
|
+
? parsed.status
|
|
73
|
+
: undefined;
|
|
74
|
+
let message = typeof nested?.message === 'string'
|
|
75
|
+
? nested.message
|
|
76
|
+
: typeof parsed.message === 'string'
|
|
77
|
+
? parsed.message
|
|
78
|
+
: undefined;
|
|
79
|
+
if (message?.trim().startsWith('{')) {
|
|
80
|
+
try {
|
|
81
|
+
const inner = JSON.parse(message);
|
|
82
|
+
if (typeof inner.error?.message === 'string') {
|
|
83
|
+
message = inner.error.message;
|
|
84
|
+
}
|
|
85
|
+
else if (typeof inner.message === 'string') {
|
|
86
|
+
message = inner.message;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// keep outer message
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
...(statusCode !== undefined ? { statusCode } : {}),
|
|
95
|
+
...(code ? { code } : {}),
|
|
96
|
+
...(message ? { message } : {}),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function parseNumericCode(value) {
|
|
104
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
if (typeof value === 'string' && /^\d+$/.test(value)) {
|
|
108
|
+
return Number.parseInt(value, 10);
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=gemini-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-provider.js","sourceRoot":"","sources":["../../src/infra/gemini-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy-safe community telemetry export (SP-082).
|
|
3
|
+
*
|
|
4
|
+
* Maps routing telemetry rows to anonymized community export shapes and
|
|
5
|
+
* HyDRA calibration batches. Never exports prompt text, messages, request_id,
|
|
6
|
+
* or raw session_id — session identifiers are one-way hashed only.
|
|
7
|
+
*/
|
|
8
|
+
import type { RoutingFeatureSidecar, RoutingTelemetry } from '../domain/types/index.js';
|
|
9
|
+
export declare const COMMUNITY_TELEMETRY_ENABLED_ENV = "SMART_ROUTER_COMMUNITY_TELEMETRY";
|
|
10
|
+
export declare const COMMUNITY_TELEMETRY_ENABLED_NOTIFY_MESSAGE = "Smart Router community telemetry export is enabled. Only anonymized routing metadata is exported \u2014 no prompt text, messages, or raw session identifiers.";
|
|
11
|
+
export declare const TELEMETRY_EXPORT_FORBIDDEN_KEYS: readonly ["session_id", "request_id", "prompt_text", "messages", "prompt", "pepper", "install_pepper", "dataset_pepper", "dataset_key", "prompt_fingerprint"];
|
|
12
|
+
export declare const HYDRA_CALIBRATION_STAGE: "hydra_match";
|
|
13
|
+
export declare function isCommunityTelemetryExportEnabled(): boolean;
|
|
14
|
+
/** One-way hash for session correlation without exporting raw session_id. */
|
|
15
|
+
export declare function hashSessionIdForTelemetryExport(sessionId: string): string;
|
|
16
|
+
export interface CommunityTelemetryRecord {
|
|
17
|
+
readonly timestamp: string;
|
|
18
|
+
readonly session_id_hash: string;
|
|
19
|
+
readonly turn_type: string;
|
|
20
|
+
readonly stage: string;
|
|
21
|
+
readonly reason_code: string;
|
|
22
|
+
readonly selected_model_id: string;
|
|
23
|
+
readonly estimated_cost_usd: number;
|
|
24
|
+
readonly routing_latency_ms: number;
|
|
25
|
+
readonly pin_reason: string | null;
|
|
26
|
+
}
|
|
27
|
+
/** HyDRA calibration row — routing signals only, no prompt content. */
|
|
28
|
+
export interface HydraCalibrationRecord {
|
|
29
|
+
readonly timestamp: string;
|
|
30
|
+
readonly session_id_hash: string;
|
|
31
|
+
readonly turn_type: string;
|
|
32
|
+
readonly reason_code: string;
|
|
33
|
+
readonly selected_model_id: string;
|
|
34
|
+
readonly routing_latency_ms: number;
|
|
35
|
+
readonly requirement_reasoning: number | null;
|
|
36
|
+
readonly requirement_code_gen: number | null;
|
|
37
|
+
readonly requirement_tool_use: number | null;
|
|
38
|
+
readonly top_candidate_model_id: string | null;
|
|
39
|
+
readonly top_candidate_score: number | null;
|
|
40
|
+
}
|
|
41
|
+
export declare function isHydraMatchTelemetry(record: RoutingTelemetry): boolean;
|
|
42
|
+
export declare function selectHydraMatchTelemetry(records: readonly RoutingTelemetry[]): readonly RoutingTelemetry[];
|
|
43
|
+
/** Map a telemetry row to a privacy-safe community export object. */
|
|
44
|
+
export declare function toCommunityTelemetryRecord(record: RoutingTelemetry): CommunityTelemetryRecord;
|
|
45
|
+
/** Map a hydra_match telemetry row to a collaborative calibration export row. */
|
|
46
|
+
export declare function toHydraCalibrationRecord(record: RoutingTelemetry, features?: RoutingFeatureSidecar): HydraCalibrationRecord;
|
|
47
|
+
export declare function formatCommunityTelemetryJsonl(records: readonly RoutingTelemetry[]): string;
|
|
48
|
+
export declare function formatHydraCalibrationJsonl(records: readonly RoutingTelemetry[], featuresByRequestId?: ReadonlyMap<string, RoutingFeatureSidecar>): string;
|
|
49
|
+
/** Defense-in-depth scrub for loose export objects. */
|
|
50
|
+
export declare function scrubTelemetryExportObject(value: Record<string, unknown>): Record<string, unknown>;
|
|
51
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/infra/telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAElC,eAAO,MAAM,+BAA+B,qCAAqC,CAAC;AAElF,eAAO,MAAM,0CAA0C,kKACqG,CAAC;AAE7J,eAAO,MAAM,+BAA+B,+JAWlC,CAAC;AAEX,eAAO,MAAM,uBAAuB,EAAG,aAAsB,CAAC;AAE9D,wBAAgB,iCAAiC,IAAI,OAAO,CAE3D;AAED,6EAA6E;AAC7E,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,uEAAuE;AACvE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAEvE;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GACnC,SAAS,gBAAgB,EAAE,CAE7B;AAED,qEAAqE;AACrE,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,gBAAgB,GACvB,wBAAwB,CAY1B;AAoBD,iFAAiF;AACjF,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,gBAAgB,EACxB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,sBAAsB,CAiBxB;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,SAAS,gBAAgB,EAAE,GACnC,MAAM,CAIR;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,mBAAmB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,qBAAqB,CAAC,GAC/D,MAAM,CAOR;AAED,uDAAuD;AACvD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy-safe community telemetry export (SP-082).
|
|
3
|
+
*
|
|
4
|
+
* Maps routing telemetry rows to anonymized community export shapes and
|
|
5
|
+
* HyDRA calibration batches. Never exports prompt text, messages, request_id,
|
|
6
|
+
* or raw session_id — session identifiers are one-way hashed only.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from 'node:crypto';
|
|
9
|
+
export const COMMUNITY_TELEMETRY_ENABLED_ENV = 'SMART_ROUTER_COMMUNITY_TELEMETRY';
|
|
10
|
+
export const COMMUNITY_TELEMETRY_ENABLED_NOTIFY_MESSAGE = 'Smart Router community telemetry export is enabled. Only anonymized routing metadata is exported — no prompt text, messages, or raw session identifiers.';
|
|
11
|
+
export const TELEMETRY_EXPORT_FORBIDDEN_KEYS = [
|
|
12
|
+
'session_id',
|
|
13
|
+
'request_id',
|
|
14
|
+
'prompt_text',
|
|
15
|
+
'messages',
|
|
16
|
+
'prompt',
|
|
17
|
+
'pepper',
|
|
18
|
+
'install_pepper',
|
|
19
|
+
'dataset_pepper',
|
|
20
|
+
'dataset_key',
|
|
21
|
+
'prompt_fingerprint',
|
|
22
|
+
];
|
|
23
|
+
export const HYDRA_CALIBRATION_STAGE = 'hydra_match';
|
|
24
|
+
export function isCommunityTelemetryExportEnabled() {
|
|
25
|
+
return process.env[COMMUNITY_TELEMETRY_ENABLED_ENV] === '1';
|
|
26
|
+
}
|
|
27
|
+
/** One-way hash for session correlation without exporting raw session_id. */
|
|
28
|
+
export function hashSessionIdForTelemetryExport(sessionId) {
|
|
29
|
+
return createHash('sha256').update(sessionId).digest('hex');
|
|
30
|
+
}
|
|
31
|
+
export function isHydraMatchTelemetry(record) {
|
|
32
|
+
return record.stage === HYDRA_CALIBRATION_STAGE;
|
|
33
|
+
}
|
|
34
|
+
export function selectHydraMatchTelemetry(records) {
|
|
35
|
+
return records.filter(isHydraMatchTelemetry);
|
|
36
|
+
}
|
|
37
|
+
/** Map a telemetry row to a privacy-safe community export object. */
|
|
38
|
+
export function toCommunityTelemetryRecord(record) {
|
|
39
|
+
return {
|
|
40
|
+
timestamp: record.timestamp,
|
|
41
|
+
session_id_hash: hashSessionIdForTelemetryExport(record.session_id),
|
|
42
|
+
turn_type: record.turn_type,
|
|
43
|
+
stage: record.stage,
|
|
44
|
+
reason_code: record.reason_code,
|
|
45
|
+
selected_model_id: record.selected_model_id,
|
|
46
|
+
estimated_cost_usd: record.estimated_cost_usd,
|
|
47
|
+
routing_latency_ms: record.routing_latency_ms,
|
|
48
|
+
pin_reason: record.pin_reason,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function topViableCandidate(features) {
|
|
52
|
+
const candidates = features?.candidates;
|
|
53
|
+
if (!candidates || candidates.length === 0) {
|
|
54
|
+
return { model_id: null, score: null };
|
|
55
|
+
}
|
|
56
|
+
const viable = candidates.filter((candidate) => candidate.rejected_reason === null);
|
|
57
|
+
const pool = viable.length > 0 ? viable : [...candidates];
|
|
58
|
+
const best = pool.reduce((leading, candidate) => candidate.score > leading.score ? candidate : leading);
|
|
59
|
+
return { model_id: best.model_id, score: best.score };
|
|
60
|
+
}
|
|
61
|
+
/** Map a hydra_match telemetry row to a collaborative calibration export row. */
|
|
62
|
+
export function toHydraCalibrationRecord(record, features) {
|
|
63
|
+
const requirements = features?.requirements ?? null;
|
|
64
|
+
const top = topViableCandidate(features);
|
|
65
|
+
return {
|
|
66
|
+
timestamp: record.timestamp,
|
|
67
|
+
session_id_hash: hashSessionIdForTelemetryExport(record.session_id),
|
|
68
|
+
turn_type: record.turn_type,
|
|
69
|
+
reason_code: record.reason_code,
|
|
70
|
+
selected_model_id: record.selected_model_id,
|
|
71
|
+
routing_latency_ms: record.routing_latency_ms,
|
|
72
|
+
requirement_reasoning: requirements?.reasoning ?? null,
|
|
73
|
+
requirement_code_gen: requirements?.code_gen ?? null,
|
|
74
|
+
requirement_tool_use: requirements?.tool_use ?? null,
|
|
75
|
+
top_candidate_model_id: top.model_id,
|
|
76
|
+
top_candidate_score: top.score,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function formatCommunityTelemetryJsonl(records) {
|
|
80
|
+
return records
|
|
81
|
+
.map((record) => JSON.stringify(toCommunityTelemetryRecord(record)))
|
|
82
|
+
.join('\n');
|
|
83
|
+
}
|
|
84
|
+
export function formatHydraCalibrationJsonl(records, featuresByRequestId) {
|
|
85
|
+
return selectHydraMatchTelemetry(records)
|
|
86
|
+
.map((record) => {
|
|
87
|
+
const features = featuresByRequestId?.get(record.request_id);
|
|
88
|
+
return JSON.stringify(toHydraCalibrationRecord(record, features));
|
|
89
|
+
})
|
|
90
|
+
.join('\n');
|
|
91
|
+
}
|
|
92
|
+
/** Defense-in-depth scrub for loose export objects. */
|
|
93
|
+
export function scrubTelemetryExportObject(value) {
|
|
94
|
+
const scrubbed = { ...value };
|
|
95
|
+
for (const key of TELEMETRY_EXPORT_FORBIDDEN_KEYS) {
|
|
96
|
+
delete scrubbed[key];
|
|
97
|
+
}
|
|
98
|
+
return scrubbed;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/infra/telemetry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse provider error payloads from pi-ai assistant errorMessage strings.
|
|
3
|
+
*/
|
|
4
|
+
import type { AssistantMessage } from '@earendil-works/pi-ai/compat';
|
|
5
|
+
import { formatGeminiThoughtSignatureErrorMessage, isGeminiThoughtSignatureAssistantError, isGeminiThoughtSignatureError } from '../../infra/gemini-provider.js';
|
|
6
|
+
export { formatGeminiThoughtSignatureErrorMessage, isGeminiThoughtSignatureAssistantError, isGeminiThoughtSignatureError, };
|
|
7
|
+
export interface ParsedProviderError {
|
|
8
|
+
readonly statusCode?: number;
|
|
9
|
+
readonly code?: string;
|
|
10
|
+
readonly message?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extract HTTP status / error code from JSON provider error blobs.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseProviderError(errorMessage: string): ParsedProviderError | undefined;
|
|
16
|
+
export declare function parseAssistantMessageError(message: AssistantMessage): ParsedProviderError | undefined;
|
|
17
|
+
export declare function isInfraAssistantError(message: AssistantMessage): boolean;
|
|
18
|
+
/** Output tokens at or below this count are treated as no usable generation. */
|
|
19
|
+
export declare const NEGLIGIBLE_OUTPUT_TOKEN_MAX = 4;
|
|
20
|
+
/** Input ratio of context window that signals context pressure on length stops. */
|
|
21
|
+
export declare const LENGTH_STOP_CONTEXT_PRESSURE_RATIO = 0.99;
|
|
22
|
+
export type LengthStopKind = 'context_pressure' | 'output_truncation';
|
|
23
|
+
export interface LengthStopHints {
|
|
24
|
+
readonly contextWindow?: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function isNegligibleOutputTokens(outputTokens: number): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Classify a `stopReason: length` assistant message as context pressure vs output truncation.
|
|
29
|
+
*/
|
|
30
|
+
export declare function classifyLengthStop(message: AssistantMessage, hints?: LengthStopHints): LengthStopKind | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* User-facing text for length stops — distinct wording for context pressure vs truncation.
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatLengthStopMessage(message: AssistantMessage, hints?: LengthStopHints): string;
|
|
35
|
+
/**
|
|
36
|
+
* Rewrite context-pressure length stops as errors so pi surfaces the overflow message.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sanitizeLengthStopMessage(message: AssistantMessage, hints?: LengthStopHints): AssistantMessage;
|
|
39
|
+
/**
|
|
40
|
+
* Format a provider error blob for user-facing display (terminal/session).
|
|
41
|
+
* Never returns raw nested JSON.
|
|
42
|
+
*/
|
|
43
|
+
export declare function formatProviderErrorMessage(errorMessage: string): string;
|
|
44
|
+
//# sourceMappingURL=provider-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-error.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/delegation/provider-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,OAAO,EACL,wCAAwC,EACxC,sCAAsC,EACtC,6BAA6B,EAC9B,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,wCAAwC,EACxC,sCAAsC,EACtC,6BAA6B,GAC9B,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAYD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAgExF;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,gBAAgB,GACxB,mBAAmB,GAAG,SAAS,CAKjC;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAMxE;AAID,gFAAgF;AAChF,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,mFAAmF;AACnF,eAAO,MAAM,kCAAkC,OAAO,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAEtE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAEtE;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,gBAAgB,EACzB,KAAK,CAAC,EAAE,eAAe,GACtB,cAAc,GAAG,SAAS,CAsB5B;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,gBAAgB,EACzB,KAAK,CAAC,EAAE,eAAe,GACtB,MAAM,CAkBR;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gBAAgB,EACzB,KAAK,CAAC,EAAE,eAAe,GACtB,gBAAgB,CAUlB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CA2BvE"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse provider error payloads from pi-ai assistant errorMessage strings.
|
|
3
|
+
*/
|
|
4
|
+
import { isContextOverflow } from '@earendil-works/pi-ai';
|
|
5
|
+
import { formatGeminiThoughtSignatureErrorMessage, isGeminiThoughtSignatureAssistantError, isGeminiThoughtSignatureError, } from '../../infra/gemini-provider.js';
|
|
6
|
+
import { isInfraError } from '../gateway/circuit-breaker.js';
|
|
7
|
+
export { formatGeminiThoughtSignatureErrorMessage, isGeminiThoughtSignatureAssistantError, isGeminiThoughtSignatureError, };
|
|
8
|
+
function parseNumericCode(value) {
|
|
9
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
if (typeof value === 'string' && /^\d+$/.test(value)) {
|
|
13
|
+
return Number.parseInt(value, 10);
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract HTTP status / error code from JSON provider error blobs.
|
|
19
|
+
*/
|
|
20
|
+
export function parseProviderError(errorMessage) {
|
|
21
|
+
const trimmed = errorMessage.trim();
|
|
22
|
+
if (!trimmed.startsWith('{')) {
|
|
23
|
+
const statusMatch = trimmed.match(/\b(429|5\d{2})\b/);
|
|
24
|
+
if (statusMatch) {
|
|
25
|
+
return { statusCode: Number.parseInt(statusMatch[1], 10) };
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(trimmed);
|
|
31
|
+
const nested = parsed.error;
|
|
32
|
+
const statusCode = parseNumericCode(nested?.code) ??
|
|
33
|
+
parseNumericCode(nested?.status) ??
|
|
34
|
+
parseNumericCode(parsed.code) ??
|
|
35
|
+
parseNumericCode(parsed.status);
|
|
36
|
+
const code = typeof nested?.status === 'string'
|
|
37
|
+
? nested.status
|
|
38
|
+
: typeof parsed.status === 'string'
|
|
39
|
+
? parsed.status
|
|
40
|
+
: undefined;
|
|
41
|
+
let message = typeof nested?.message === 'string'
|
|
42
|
+
? nested.message
|
|
43
|
+
: typeof parsed.message === 'string'
|
|
44
|
+
? parsed.message
|
|
45
|
+
: undefined;
|
|
46
|
+
if (message && message.trim().startsWith('{')) {
|
|
47
|
+
try {
|
|
48
|
+
const inner = JSON.parse(message);
|
|
49
|
+
if (typeof inner.error?.message === 'string') {
|
|
50
|
+
message = inner.error.message;
|
|
51
|
+
}
|
|
52
|
+
else if (typeof inner.message === 'string') {
|
|
53
|
+
message = inner.message;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Nested provider error payloads may be malformed JSON — keep outer message.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (statusCode === undefined && code === undefined && message === undefined) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
...(statusCode !== undefined ? { statusCode } : {}),
|
|
65
|
+
...(code ? { code } : {}),
|
|
66
|
+
...(message ? { message } : {}),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function parseAssistantMessageError(message) {
|
|
74
|
+
if (message.stopReason !== 'error' || !message.errorMessage) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return parseProviderError(message.errorMessage);
|
|
78
|
+
}
|
|
79
|
+
export function isInfraAssistantError(message) {
|
|
80
|
+
const parsed = parseAssistantMessageError(message);
|
|
81
|
+
if (!parsed) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return isInfraError(parsed);
|
|
85
|
+
}
|
|
86
|
+
const FORMATTED_ERROR_MAX_LENGTH = 200;
|
|
87
|
+
/** Output tokens at or below this count are treated as no usable generation. */
|
|
88
|
+
export const NEGLIGIBLE_OUTPUT_TOKEN_MAX = 4;
|
|
89
|
+
/** Input ratio of context window that signals context pressure on length stops. */
|
|
90
|
+
export const LENGTH_STOP_CONTEXT_PRESSURE_RATIO = 0.99;
|
|
91
|
+
export function isNegligibleOutputTokens(outputTokens) {
|
|
92
|
+
return outputTokens <= NEGLIGIBLE_OUTPUT_TOKEN_MAX;
|
|
93
|
+
}
|
|
94
|
+
function inputTokensUsed(message) {
|
|
95
|
+
return message.usage.input + message.usage.cacheRead;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Classify a `stopReason: length` assistant message as context pressure vs output truncation.
|
|
99
|
+
*/
|
|
100
|
+
export function classifyLengthStop(message, hints) {
|
|
101
|
+
if (message.stopReason !== 'length') {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
if (!isNegligibleOutputTokens(message.usage.output)) {
|
|
105
|
+
return 'output_truncation';
|
|
106
|
+
}
|
|
107
|
+
const contextWindow = hints?.contextWindow;
|
|
108
|
+
if (contextWindow !== undefined) {
|
|
109
|
+
if (isContextOverflow(message, contextWindow)) {
|
|
110
|
+
return 'context_pressure';
|
|
111
|
+
}
|
|
112
|
+
const inputTokens = inputTokensUsed(message);
|
|
113
|
+
if (inputTokens >= contextWindow * LENGTH_STOP_CONTEXT_PRESSURE_RATIO) {
|
|
114
|
+
return 'context_pressure';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return 'output_truncation';
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* User-facing text for length stops — distinct wording for context pressure vs truncation.
|
|
121
|
+
*/
|
|
122
|
+
export function formatLengthStopMessage(message, hints) {
|
|
123
|
+
const kind = classifyLengthStop(message, hints);
|
|
124
|
+
if (kind === 'context_pressure') {
|
|
125
|
+
const inputTokens = inputTokensUsed(message);
|
|
126
|
+
const limitSuffix = hints?.contextWindow !== undefined
|
|
127
|
+
? ` (context limit: ${hints.contextWindow.toLocaleString()} tokens)`
|
|
128
|
+
: '';
|
|
129
|
+
return (`Context window exceeded: ${inputTokens.toLocaleString()} input tokens used${limitSuffix}, ` +
|
|
130
|
+
'leaving no room for output. Try compacting history or switching to a larger-context model.');
|
|
131
|
+
}
|
|
132
|
+
return ('Model stopped because it reached the maximum output token limit. ' +
|
|
133
|
+
'The response may be incomplete.');
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Rewrite context-pressure length stops as errors so pi surfaces the overflow message.
|
|
137
|
+
*/
|
|
138
|
+
export function sanitizeLengthStopMessage(message, hints) {
|
|
139
|
+
if (classifyLengthStop(message, hints) !== 'context_pressure') {
|
|
140
|
+
return message;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
...message,
|
|
144
|
+
stopReason: 'error',
|
|
145
|
+
errorMessage: formatLengthStopMessage(message, hints),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Format a provider error blob for user-facing display (terminal/session).
|
|
150
|
+
* Never returns raw nested JSON.
|
|
151
|
+
*/
|
|
152
|
+
export function formatProviderErrorMessage(errorMessage) {
|
|
153
|
+
const parsed = parseProviderError(errorMessage);
|
|
154
|
+
if (parsed) {
|
|
155
|
+
const prefixParts = [];
|
|
156
|
+
if (parsed.statusCode !== undefined) {
|
|
157
|
+
prefixParts.push(String(parsed.statusCode));
|
|
158
|
+
}
|
|
159
|
+
if (parsed.code) {
|
|
160
|
+
prefixParts.push(parsed.code);
|
|
161
|
+
}
|
|
162
|
+
const prefix = prefixParts.length > 0 ? `${prefixParts.join(' ')}: ` : '';
|
|
163
|
+
if (parsed.message) {
|
|
164
|
+
return `${prefix}${parsed.message}`;
|
|
165
|
+
}
|
|
166
|
+
if (prefixParts.length > 0) {
|
|
167
|
+
return `Provider error (${prefixParts.join(' ')})`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const trimmed = errorMessage.trim();
|
|
171
|
+
if (trimmed.startsWith('{')) {
|
|
172
|
+
return 'Provider error (unparseable response)';
|
|
173
|
+
}
|
|
174
|
+
if (trimmed.length > FORMATTED_ERROR_MAX_LENGTH) {
|
|
175
|
+
return `${trimmed.slice(0, FORMATTED_ERROR_MAX_LENGTH)}…`;
|
|
176
|
+
}
|
|
177
|
+
return trimmed;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=provider-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-error.js","sourceRoot":"","sources":["../../../src/infrastructure/delegation/provider-error.ts"],"names":[],"mappings":"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"}
|