@juno-ai/bind 1.0.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.
@@ -0,0 +1,81 @@
1
+ import { z } from "zod";
2
+ import { type CanonicalModelId, type ProviderId } from "./canonical-model";
3
+ /**
4
+ * Policy order and semantics are versioned; the version string travels into
5
+ * telemetry (LLM Provider Routing PRD §4.2) so a routing-behavior change is
6
+ * distinguishable from a configuration change after the fact.
7
+ */
8
+ export declare const ROUTE_POLICY_VERSION = "provider-router-v1";
9
+ export type RoutePolicyVersion = typeof ROUTE_POLICY_VERSION;
10
+ /**
11
+ * `ordered` tries each listed provider in order, skipping unavailable or
12
+ * incapable endpoints. `only` is a hard fence: the marked canonical model is
13
+ * never attempted through another provider. A separately configured fallback
14
+ * model still expands under its own policy (PRD §4.2).
15
+ */
16
+ export declare const providerPolicySchema: z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
17
+ mode: z.ZodLiteral<"ordered">;
18
+ providers: z.ZodArray<z.core.$ZodBranded<z.ZodString, "ProviderId", "out">>;
19
+ }, z.core.$strict>>, z.ZodReadonly<z.ZodObject<{
20
+ mode: z.ZodLiteral<"only">;
21
+ provider: z.core.$ZodBranded<z.ZodString, "ProviderId", "out">;
22
+ }, z.core.$strict>>], "mode">;
23
+ export type ProviderPolicy = z.infer<typeof providerPolicySchema>;
24
+ /**
25
+ * The checked-in route registry. It contains policy only — never endpoints,
26
+ * deployment names, credentials, prices, quota, or tenant-specific values.
27
+ *
28
+ * Naming note: the PRD draft called the bound default `azureBoundDefault`.
29
+ * The harness is provider-agnostic, so the registry generalizes it to
30
+ * `boundDefault`, applied when the host reports at least one provider
31
+ * binding for the model (see `resolveProviderPolicy`).
32
+ */
33
+ export declare const modelRouteRegistrySchema: z.ZodReadonly<z.ZodObject<{
34
+ version: z.ZodLiteral<"provider-router-v1">;
35
+ /** Used when a model has no explicit policy and no provider binding. */
36
+ unboundDefault: z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
37
+ mode: z.ZodLiteral<"ordered">;
38
+ providers: z.ZodArray<z.core.$ZodBranded<z.ZodString, "ProviderId", "out">>;
39
+ }, z.core.$strict>>, z.ZodReadonly<z.ZodObject<{
40
+ mode: z.ZodLiteral<"only">;
41
+ provider: z.core.$ZodBranded<z.ZodString, "ProviderId", "out">;
42
+ }, z.core.$strict>>], "mode">;
43
+ /** Used when a model has no explicit policy but has ≥1 provider binding. */
44
+ boundDefault: z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
45
+ mode: z.ZodLiteral<"ordered">;
46
+ providers: z.ZodArray<z.core.$ZodBranded<z.ZodString, "ProviderId", "out">>;
47
+ }, z.core.$strict>>, z.ZodReadonly<z.ZodObject<{
48
+ mode: z.ZodLiteral<"only">;
49
+ provider: z.core.$ZodBranded<z.ZodString, "ProviderId", "out">;
50
+ }, z.core.$strict>>], "mode">;
51
+ /** Keys are canonical model ids; parsing rejects deployment names. */
52
+ models: z.ZodRecord<z.core.$ZodBranded<z.ZodString, "CanonicalModelId", "out">, z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
53
+ mode: z.ZodLiteral<"ordered">;
54
+ providers: z.ZodArray<z.core.$ZodBranded<z.ZodString, "ProviderId", "out">>;
55
+ }, z.core.$strict>>, z.ZodReadonly<z.ZodObject<{
56
+ mode: z.ZodLiteral<"only">;
57
+ provider: z.core.$ZodBranded<z.ZodString, "ProviderId", "out">;
58
+ }, z.core.$strict>>], "mode">>;
59
+ }, z.core.$strict>>;
60
+ export type ModelRouteRegistry = z.infer<typeof modelRouteRegistrySchema>;
61
+ /**
62
+ * Parse and freeze a checked-in registry object at module initialization.
63
+ * `satisfies` on the literal is not a runtime-validation substitute
64
+ * (PRD §4.2) — hosts must call this on their checked-in object.
65
+ */
66
+ export declare function parseModelRouteRegistry(input: unknown): ModelRouteRegistry;
67
+ /**
68
+ * Policy precedence (PRD §4.2): exact canonical-model entry, then the bound
69
+ * default when the host reports a provider binding for this model, then the
70
+ * unbound default. An explicit policy always wins — in particular, an
71
+ * explicit single-provider model does not become bound-first merely because
72
+ * a binding is later added.
73
+ *
74
+ * `boundProviders` is the host's report of which providers have an explicit
75
+ * binding for this model (e.g. an Azure deployment mapping). A catch-all
76
+ * transport that serves every model without per-model configuration should
77
+ * not be reported as a binding.
78
+ */
79
+ export declare function resolveProviderPolicy(registry: ModelRouteRegistry, model: CanonicalModelId, boundProviders: ReadonlySet<ProviderId>): ProviderPolicy;
80
+ /** The provider order a policy prescribes; `only` is a single-entry order. */
81
+ export declare function policyProviderOrder(policy: ProviderPolicy): readonly ProviderId[];
@@ -0,0 +1,99 @@
1
+ import { z } from "zod";
2
+ import { canonicalModelIdSchema, providerIdSchema, } from "./canonical-model";
3
+ /**
4
+ * Policy order and semantics are versioned; the version string travels into
5
+ * telemetry (LLM Provider Routing PRD §4.2) so a routing-behavior change is
6
+ * distinguishable from a configuration change after the fact.
7
+ */
8
+ export const ROUTE_POLICY_VERSION = "provider-router-v1";
9
+ const orderedPolicySchema = z
10
+ .strictObject({
11
+ mode: z.literal("ordered"),
12
+ providers: z
13
+ .array(providerIdSchema)
14
+ .min(1)
15
+ .refine((providers) => new Set(providers).size === providers.length, "duplicate provider ids in ordered policy"),
16
+ })
17
+ .readonly();
18
+ const onlyPolicySchema = z
19
+ .strictObject({
20
+ mode: z.literal("only"),
21
+ provider: providerIdSchema,
22
+ })
23
+ .readonly();
24
+ /**
25
+ * `ordered` tries each listed provider in order, skipping unavailable or
26
+ * incapable endpoints. `only` is a hard fence: the marked canonical model is
27
+ * never attempted through another provider. A separately configured fallback
28
+ * model still expands under its own policy (PRD §4.2).
29
+ */
30
+ export const providerPolicySchema = z.discriminatedUnion("mode", [
31
+ orderedPolicySchema,
32
+ onlyPolicySchema,
33
+ ]);
34
+ /**
35
+ * The checked-in route registry. It contains policy only — never endpoints,
36
+ * deployment names, credentials, prices, quota, or tenant-specific values.
37
+ *
38
+ * Naming note: the PRD draft called the bound default `azureBoundDefault`.
39
+ * The harness is provider-agnostic, so the registry generalizes it to
40
+ * `boundDefault`, applied when the host reports at least one provider
41
+ * binding for the model (see `resolveProviderPolicy`).
42
+ */
43
+ export const modelRouteRegistrySchema = z
44
+ .strictObject({
45
+ version: z.literal(ROUTE_POLICY_VERSION),
46
+ /** Used when a model has no explicit policy and no provider binding. */
47
+ unboundDefault: providerPolicySchema,
48
+ /** Used when a model has no explicit policy but has ≥1 provider binding. */
49
+ boundDefault: providerPolicySchema,
50
+ /** Keys are canonical model ids; parsing rejects deployment names. */
51
+ models: z.record(canonicalModelIdSchema, providerPolicySchema),
52
+ })
53
+ .readonly();
54
+ /**
55
+ * Parse and freeze a checked-in registry object at module initialization.
56
+ * `satisfies` on the literal is not a runtime-validation substitute
57
+ * (PRD §4.2) — hosts must call this on their checked-in object.
58
+ */
59
+ export function parseModelRouteRegistry(input) {
60
+ const registry = modelRouteRegistrySchema.parse(input);
61
+ for (const policy of Object.values(registry.models)) {
62
+ if (policy.mode === "ordered")
63
+ Object.freeze(policy.providers);
64
+ Object.freeze(policy);
65
+ }
66
+ Object.freeze(registry.models);
67
+ return Object.freeze(registry);
68
+ }
69
+ /**
70
+ * Policy precedence (PRD §4.2): exact canonical-model entry, then the bound
71
+ * default when the host reports a provider binding for this model, then the
72
+ * unbound default. An explicit policy always wins — in particular, an
73
+ * explicit single-provider model does not become bound-first merely because
74
+ * a binding is later added.
75
+ *
76
+ * `boundProviders` is the host's report of which providers have an explicit
77
+ * binding for this model (e.g. an Azure deployment mapping). A catch-all
78
+ * transport that serves every model without per-model configuration should
79
+ * not be reported as a binding.
80
+ */
81
+ export function resolveProviderPolicy(registry, model, boundProviders) {
82
+ const explicit = registry.models[model];
83
+ if (explicit !== undefined)
84
+ return explicit;
85
+ return boundProviders.size > 0 ? registry.boundDefault : registry.unboundDefault;
86
+ }
87
+ /** The provider order a policy prescribes; `only` is a single-entry order. */
88
+ export function policyProviderOrder(policy) {
89
+ switch (policy.mode) {
90
+ case "ordered":
91
+ return policy.providers;
92
+ case "only":
93
+ return [policy.provider];
94
+ default: {
95
+ const _exhaustive = policy;
96
+ throw new Error(`unknown policy mode: ${JSON.stringify(_exhaustive)}`);
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,40 @@
1
+ import type { CanonicalModelId, ProviderId } from "./canonical-model";
2
+ import type { InferenceRequirements, RouteCandidate, RouteSkip } from "./plan";
3
+ export type TransportAvailability = Readonly<{
4
+ available: true;
5
+ }> | Readonly<{
6
+ available: false;
7
+ reason: string;
8
+ }>;
9
+ /**
10
+ * What a transport reports when the planner asks it for an endpoint:
11
+ * - `candidate` — a concrete, attemptable endpoint.
12
+ * - `skip` — the transport knows about the model but cannot serve it
13
+ * (malformed binding, capability gap it detects itself); recorded as a
14
+ * plan diagnostic.
15
+ * - `unserved` — the transport has no knowledge of this model (e.g. no Azure
16
+ * deployment mapping). Omitted silently, matching PRD §5.1's "wholly
17
+ * absent configuration is omitted" behavior.
18
+ */
19
+ export type CandidateResolution = Readonly<{
20
+ kind: "candidate";
21
+ candidate: RouteCandidate;
22
+ }> | Readonly<{
23
+ kind: "skip";
24
+ skip: RouteSkip;
25
+ }> | Readonly<{
26
+ kind: "unserved";
27
+ }>;
28
+ /**
29
+ * The planner-facing surface of an inference transport. This is the harness
30
+ * subset of the PRD's `InferenceTransportContribution` (§4.3): request
31
+ * construction (`createClient` / `buildRequest`) and provider error
32
+ * classification stay with the host's transport adapters, because they
33
+ * depend on the wire client. The planner needs only availability and
34
+ * endpoint resolution.
35
+ */
36
+ export interface PlannerTransport {
37
+ readonly id: ProviderId;
38
+ getAvailability(): TransportAvailability;
39
+ resolveCandidate(model: CanonicalModelId, requirements: InferenceRequirements): CandidateResolution;
40
+ }
@@ -0,0 +1 @@
1
+ export {};