@velum-labs/routekit-daemon 1.3.2 → 1.5.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/dist/account-enroll-service.d.ts +1 -3
- package/dist/account-enroll-service.js +262 -262
- package/dist/account-mutation-service.d.ts +1 -3
- package/dist/account-mutation-service.js +302 -283
- package/dist/account-query-service.d.ts +1 -3
- package/dist/account-query-service.js +88 -86
- package/dist/call-attribution-store.js +544 -1
- package/dist/control-dispatch.js +9 -15
- package/dist/daemon-bootstrap-preflight.js +1 -1
- package/dist/daemon-control-handlers.d.ts +1 -1
- package/dist/daemon-control-handlers.js +24 -27
- package/dist/daemon-generations.d.ts +14 -28
- package/dist/daemon-generations.js +114 -53
- package/dist/daemon-lifecycle-service.d.ts +1 -3
- package/dist/daemon-lifecycle-service.js +88 -94
- package/dist/daemon-maintenance.d.ts +27 -49
- package/dist/daemon-maintenance.js +5 -1
- package/dist/daemon-options.d.ts +3 -2
- package/dist/daemon-policy-context.d.ts +1 -0
- package/dist/daemon-policy-context.js +1 -0
- package/dist/daemon-runtime-state.d.ts +1 -1
- package/dist/daemon-runtime-state.js +2 -3
- package/dist/daemon-state-context.d.ts +1 -1
- package/dist/daemon-state-context.js +1 -38
- package/dist/doctor-service.d.ts +1 -3
- package/dist/doctor-service.js +87 -91
- package/dist/effect/daemon-live.d.ts +7 -6
- package/dist/effect/daemon-live.js +57 -135
- package/dist/eval-routing-service.d.ts +1 -3
- package/dist/eval-routing-service.js +45 -69
- package/dist/eval-session-execution-store.d.ts +24 -0
- package/dist/eval-session-execution-store.js +253 -0
- package/dist/host-protocol.d.ts +1 -0
- package/dist/host.js +3 -0
- package/dist/internal-providers/provider-anthropic/index.d.ts +23 -0
- package/dist/internal-providers/provider-anthropic/index.js +42 -0
- package/dist/internal-providers/provider-anthropic/test/provider.test.js +33 -0
- package/dist/internal-providers/provider-azure/index.d.ts +25 -0
- package/dist/internal-providers/provider-azure/index.js +101 -0
- package/dist/internal-providers/provider-azure/test/provider.test.js +83 -0
- package/dist/internal-providers/provider-bedrock/codec.d.ts +11 -0
- package/dist/internal-providers/provider-bedrock/codec.js +484 -0
- package/dist/internal-providers/provider-bedrock/connection-settings.d.ts +6 -0
- package/dist/internal-providers/provider-bedrock/connection-settings.js +41 -0
- package/dist/internal-providers/provider-bedrock/connection.d.ts +17 -0
- package/dist/internal-providers/provider-bedrock/connection.js +143 -0
- package/dist/internal-providers/provider-bedrock/index.d.ts +27 -0
- package/dist/internal-providers/provider-bedrock/index.js +47 -0
- package/dist/internal-providers/provider-bedrock/source.d.ts +39 -0
- package/dist/internal-providers/provider-bedrock/source.js +454 -0
- package/dist/internal-providers/provider-bedrock/test/bedrock-source.test.d.ts +1 -0
- package/dist/internal-providers/provider-bedrock/test/bedrock-source.test.js +786 -0
- package/dist/internal-providers/provider-bedrock/test/connection.test.d.ts +1 -0
- package/dist/internal-providers/provider-bedrock/test/connection.test.js +249 -0
- package/dist/internal-providers/provider-bedrock/test/workload-credentials.test.d.ts +1 -0
- package/dist/internal-providers/provider-bedrock/test/workload-credentials.test.js +29 -0
- package/dist/internal-providers/provider-bedrock/workload-credentials.d.ts +5 -0
- package/dist/internal-providers/provider-bedrock/workload-credentials.js +14 -0
- package/dist/internal-providers/provider-claude-code/index.d.ts +6 -0
- package/dist/internal-providers/provider-claude-code/index.js +4 -0
- package/dist/internal-providers/provider-claude-code/module-api.d.ts +25 -0
- package/dist/internal-providers/provider-claude-code/module-api.js +31 -0
- package/dist/internal-providers/provider-claude-code/relay.d.ts +20 -0
- package/dist/internal-providers/provider-claude-code/relay.js +115 -0
- package/dist/internal-providers/provider-claude-code/subscription.d.ts +2 -0
- package/dist/internal-providers/provider-claude-code/subscription.js +194 -0
- package/dist/internal-providers/provider-claude-code/test/http-submission.test.d.ts +1 -0
- package/dist/internal-providers/provider-claude-code/test/http-submission.test.js +140 -0
- package/dist/internal-providers/provider-claude-code/test/relay.test.d.ts +1 -0
- package/dist/internal-providers/provider-claude-code/test/relay.test.js +379 -0
- package/dist/internal-providers/provider-claude-code/test/subscription.test.d.ts +1 -0
- package/dist/internal-providers/provider-claude-code/test/subscription.test.js +256 -0
- package/dist/internal-providers/provider-cliproxy/index.d.ts +9 -0
- package/dist/internal-providers/provider-cliproxy/index.js +15 -0
- package/dist/internal-providers/provider-codex/index.d.ts +6 -0
- package/dist/internal-providers/provider-codex/index.js +7 -0
- package/dist/internal-providers/provider-codex/module-api.d.ts +25 -0
- package/dist/internal-providers/provider-codex/module-api.js +31 -0
- package/dist/internal-providers/provider-codex/relay.d.ts +123 -0
- package/dist/internal-providers/provider-codex/relay.js +261 -0
- package/dist/internal-providers/provider-codex/subscription.d.ts +2 -0
- package/dist/internal-providers/provider-codex/subscription.js +555 -0
- package/dist/internal-providers/provider-codex/test/http-submission.test.d.ts +1 -0
- package/dist/internal-providers/provider-codex/test/http-submission.test.js +142 -0
- package/dist/internal-providers/provider-codex/test/relay.test.d.ts +1 -0
- package/dist/internal-providers/provider-codex/test/relay.test.js +600 -0
- package/dist/internal-providers/provider-codex/test/subscription.test.d.ts +1 -0
- package/dist/internal-providers/provider-codex/test/subscription.test.js +70 -0
- package/dist/internal-providers/provider-codex/test/translated-content.test.d.ts +1 -0
- package/dist/internal-providers/provider-codex/test/translated-content.test.js +91 -0
- package/dist/internal-providers/provider-custom/index.d.ts +9 -0
- package/dist/internal-providers/provider-custom/index.js +15 -0
- package/dist/internal-providers/provider-google/index.d.ts +23 -0
- package/dist/internal-providers/provider-google/index.js +43 -0
- package/dist/internal-providers/provider-google/test/provider.test.d.ts +1 -0
- package/dist/internal-providers/provider-google/test/provider.test.js +34 -0
- package/dist/internal-providers/provider-google-vertex/index.d.ts +28 -0
- package/dist/internal-providers/provider-google-vertex/index.js +137 -0
- package/dist/internal-providers/provider-google-vertex/test/provider.test.d.ts +1 -0
- package/dist/internal-providers/provider-google-vertex/test/provider.test.js +85 -0
- package/dist/internal-providers/provider-openai/documented-reasoning.d.ts +9 -0
- package/dist/internal-providers/provider-openai/documented-reasoning.js +26 -0
- package/dist/internal-providers/provider-openai/index.d.ts +23 -0
- package/dist/internal-providers/provider-openai/index.js +74 -0
- package/dist/internal-providers/provider-openai/test/provider.test.d.ts +1 -0
- package/dist/internal-providers/provider-openai/test/provider.test.js +268 -0
- package/dist/internal-providers/provider-openai-compatible/index.d.ts +9 -0
- package/dist/internal-providers/provider-openai-compatible/index.js +15 -0
- package/dist/internal-providers/provider-openai-compatible/test/provider.test.d.ts +1 -0
- package/dist/internal-providers/provider-openai-compatible/test/provider.test.js +40 -0
- package/dist/internal-providers/provider-openrouter/connection.d.ts +5 -0
- package/dist/internal-providers/provider-openrouter/connection.js +143 -0
- package/dist/internal-providers/provider-openrouter/index.d.ts +28 -0
- package/dist/internal-providers/provider-openrouter/index.js +42 -0
- package/dist/internal-providers/provider-openrouter/pricing.d.ts +4 -0
- package/dist/internal-providers/provider-openrouter/pricing.js +108 -0
- package/dist/internal-providers/provider-openrouter/test/connection.test.d.ts +1 -0
- package/dist/internal-providers/provider-openrouter/test/connection.test.js +71 -0
- package/dist/internal-providers/provider-openrouter/test/pricing.test.d.ts +1 -0
- package/dist/internal-providers/provider-openrouter/test/pricing.test.js +45 -0
- package/dist/internal-providers/provider-openrouter/test/provider.test.d.ts +1 -0
- package/dist/internal-providers/provider-openrouter/test/provider.test.js +141 -0
- package/dist/internal-providers/provider-openrouter/test/validation.test.d.ts +1 -0
- package/dist/internal-providers/provider-openrouter/test/validation.test.js +225 -0
- package/dist/launcher-service.d.ts +3 -7
- package/dist/launcher-service.js +144 -133
- package/dist/provider-modules.d.ts +6 -0
- package/dist/provider-modules.js +55 -0
- package/dist/provider-query-service.d.ts +1 -3
- package/dist/provider-query-service.js +140 -143
- package/dist/router-generation-service.d.ts +1 -3
- package/dist/router-generation-service.js +83 -78
- package/dist/services/eval-session/service.d.ts +20 -8
- package/dist/services/eval-session/service.js +410 -40
- package/dist/services/gateway-generation/service.d.ts +7 -3
- package/dist/services/gateway-generation/service.js +126 -63
- package/dist/services/generations/service.d.ts +3 -3
- package/dist/services/generations/service.js +5 -1
- package/dist/telemetry-application-service.d.ts +1 -3
- package/dist/telemetry-application-service.js +41 -45
- package/dist/test/call-attribution-store.test.js +186 -0
- package/dist/test/daemon-accounts.test.js +2 -2
- package/dist/test/daemon-data-plane.test.js +24 -45
- package/dist/test/daemon-fixtures.js +1 -1
- package/dist/test/daemon-generation-transaction.test.js +66 -2
- package/dist/test/daemon-runtime-state.test.js +28 -1
- package/dist/test/effect-daemon.test.js +38 -0
- package/dist/test/eval-routing-application-service.test.js +6 -6
- package/dist/test/eval-session-execution.test.d.ts +1 -0
- package/dist/test/eval-session-execution.test.js +356 -0
- package/dist/test/eval-session-service.test.js +70 -1
- package/dist/test/host-worker-session.test.js +1 -0
- package/dist/test/launcher-session.test.d.ts +1 -0
- package/dist/test/launcher-session.test.js +87 -0
- package/dist/test/leaderboard.test.js +25 -1
- package/dist/test/provider-modules.test.d.ts +1 -0
- package/dist/test/provider-modules.test.js +65 -0
- package/dist/test/routekit-upstream-sources.test.d.ts +1 -0
- package/dist/test/routekit-upstream-sources.test.js +40 -0
- package/dist/test/runtime-composition-types.test.js +11 -0
- package/dist/token-application-service.d.ts +1 -3
- package/dist/token-application-service.js +38 -44
- package/dist/worker.js +5 -3
- package/package.json +35 -11
- package/dist/application-services.d.ts +0 -10
- package/dist/application-services.js +0 -22
- package/dist/daemon-lifecycle.d.ts +0 -54
- package/dist/daemon-lifecycle.js +0 -177
- package/dist/test/application-services.test.js +0 -135
- package/dist/test/daemon-lifecycle.test.js +0 -182
- /package/dist/{test/application-services.test.d.ts → internal-providers/provider-anthropic/test/provider.test.d.ts} +0 -0
- /package/dist/{test/daemon-lifecycle.test.d.ts → internal-providers/provider-azure/test/provider.test.d.ts} +0 -0
package/dist/launcher-service.js
CHANGED
|
@@ -6,144 +6,155 @@ import { Effect } from "effect";
|
|
|
6
6
|
import { ActiveGateway } from "./services/active-gateway/service.js";
|
|
7
7
|
import { LauncherSessions } from "./services/launcher-session/service.js";
|
|
8
8
|
import { Tokens } from "./services/tokens/service.js";
|
|
9
|
-
/**
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const modelProfile = requestedModel?.toLowerCase().startsWith("auto:")
|
|
26
|
-
? requestedModel.slice("auto:".length)
|
|
27
|
-
: undefined;
|
|
28
|
-
const routingProfile = params.routingProfile ?? modelProfile;
|
|
29
|
-
if (params.routingProfile !== undefined && modelProfile !== undefined) {
|
|
30
|
-
if (params.routingProfile !== modelProfile) {
|
|
31
|
-
return yield* Effect.fail(new ControlError({
|
|
32
|
-
code: "bad_request",
|
|
33
|
-
message: "routingProfile conflicts with the model profile selector"
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
else if (params.routingProfile !== undefined &&
|
|
38
|
-
requestedModel !== undefined &&
|
|
39
|
-
requestedModel.toLowerCase() !== "auto") {
|
|
9
|
+
/** Bind coding-tool launch preparation to the live catalog's handler. */
|
|
10
|
+
export function launcherHandlers({ listModels }) {
|
|
11
|
+
return {
|
|
12
|
+
"launcher.prepare": (params, context) => Effect.gen(function* () {
|
|
13
|
+
const listed = yield* listModels({}, {
|
|
14
|
+
signal: context.signal,
|
|
15
|
+
requestId: "internal"
|
|
16
|
+
});
|
|
17
|
+
return yield* Effect.gen(function* () {
|
|
18
|
+
const requestedModel = params.model?.trim();
|
|
19
|
+
const modelProfile = requestedModel?.toLowerCase().startsWith("auto:")
|
|
20
|
+
? requestedModel.slice("auto:".length)
|
|
21
|
+
: undefined;
|
|
22
|
+
const routingProfile = params.routingProfile ?? modelProfile;
|
|
23
|
+
if (params.routingProfile !== undefined && modelProfile !== undefined) {
|
|
24
|
+
if (params.routingProfile !== modelProfile) {
|
|
40
25
|
return yield* Effect.fail(new ControlError({
|
|
41
26
|
code: "bad_request",
|
|
42
|
-
message: "routingProfile
|
|
43
|
-
}));
|
|
44
|
-
}
|
|
45
|
-
let launcherAuthToken;
|
|
46
|
-
if (routingProfile !== undefined) {
|
|
47
|
-
const cwd = resolve(params.cwd ?? ".");
|
|
48
|
-
const repositoryRoot = yield* Effect.try({
|
|
49
|
-
try: () => {
|
|
50
|
-
const root = findRepositoryRoutingProfileRoot(cwd, routingProfile);
|
|
51
|
-
if (root === undefined) {
|
|
52
|
-
throw new Error(`routing profile ${JSON.stringify(routingProfile)} was not found from ${cwd}`);
|
|
53
|
-
}
|
|
54
|
-
loadRepositoryRoutingProfile({ repositoryRoot: root, name: routingProfile });
|
|
55
|
-
return root;
|
|
56
|
-
},
|
|
57
|
-
catch: (cause) => new ControlError({
|
|
58
|
-
code: "not_found",
|
|
59
|
-
message: cause instanceof Error
|
|
60
|
-
? cause.message
|
|
61
|
-
: `routing profile ${JSON.stringify(routingProfile)} was not found`
|
|
62
|
-
})
|
|
63
|
-
});
|
|
64
|
-
const launcherSessions = yield* LauncherSessions;
|
|
65
|
-
launcherAuthToken = launcherSessions.open({
|
|
66
|
-
repositoryRoot,
|
|
67
|
-
profileName: routingProfile,
|
|
68
|
-
role: context.principal === undefined || context.principal.role === "ephemeral"
|
|
69
|
-
? "owner"
|
|
70
|
-
: context.principal.role
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
let model = routingProfile === undefined
|
|
74
|
-
? (params.model ?? listed.defaultModel ?? listed.models[0]?.id)
|
|
75
|
-
: `auto:${routingProfile}`;
|
|
76
|
-
let codexSelection;
|
|
77
|
-
if (params.tool === "codex" && routingProfile === undefined) {
|
|
78
|
-
const gateway = yield* ActiveGateway;
|
|
79
|
-
const candidates = listed.models.flatMap((entry) => {
|
|
80
|
-
const info = gateway.router().modelInfo(entry.id);
|
|
81
|
-
if (info === undefined)
|
|
82
|
-
return [];
|
|
83
|
-
return [
|
|
84
|
-
{
|
|
85
|
-
id: info.id,
|
|
86
|
-
nativeId: info.nativeModel,
|
|
87
|
-
provider: info.provider,
|
|
88
|
-
billingScope: info.billingMode,
|
|
89
|
-
...(info.createdAt !== undefined ? { createdAt: info.createdAt } : {}),
|
|
90
|
-
...(info.providerPriority !== undefined
|
|
91
|
-
? { providerPriority: info.providerPriority }
|
|
92
|
-
: {}),
|
|
93
|
-
...(info.metadata?.architecture !== undefined
|
|
94
|
-
? { architecture: info.metadata.architecture }
|
|
95
|
-
: {}),
|
|
96
|
-
...(info.metadata?.supportedParameters !== undefined
|
|
97
|
-
? { supportedParameters: info.metadata.supportedParameters }
|
|
98
|
-
: {}),
|
|
99
|
-
...(info.reasoning !== null ? { reasoning: info.reasoning } : {})
|
|
100
|
-
}
|
|
101
|
-
];
|
|
102
|
-
});
|
|
103
|
-
const selected = yield* resolveCodexStartupModel({
|
|
104
|
-
models: candidates,
|
|
105
|
-
...(listed.defaultModel !== undefined
|
|
106
|
-
? { preferredModel: listed.defaultModel }
|
|
107
|
-
: {}),
|
|
108
|
-
...(params.model !== undefined ? { requestedModel: params.model } : {}),
|
|
109
|
-
signal: context.signal
|
|
110
|
-
}).pipe(Effect.mapError((error) => {
|
|
111
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
112
|
-
return new ControlError({
|
|
113
|
-
code: params.model !== undefined && message.startsWith("unknown model")
|
|
114
|
-
? "not_found"
|
|
115
|
-
: "unavailable",
|
|
116
|
-
message
|
|
117
|
-
});
|
|
27
|
+
message: "routingProfile conflicts with the model profile selector"
|
|
118
28
|
}));
|
|
119
|
-
model = selected.model;
|
|
120
|
-
codexSelection = {
|
|
121
|
-
compatibleModelIds: [...selected.compatibleModelIds],
|
|
122
|
-
models: [...selected.models]
|
|
123
|
-
};
|
|
124
29
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
30
|
+
}
|
|
31
|
+
else if (params.routingProfile !== undefined &&
|
|
32
|
+
requestedModel !== undefined &&
|
|
33
|
+
requestedModel.toLowerCase() !== "auto") {
|
|
34
|
+
return yield* Effect.fail(new ControlError({
|
|
35
|
+
code: "bad_request",
|
|
36
|
+
message: "routingProfile may be used only with model auto or an omitted model"
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
let routingContext;
|
|
40
|
+
if (routingProfile !== undefined) {
|
|
41
|
+
const cwd = resolve(params.cwd ?? ".");
|
|
42
|
+
const repositoryRoot = yield* Effect.try({
|
|
43
|
+
try: () => {
|
|
44
|
+
const root = findRepositoryRoutingProfileRoot(cwd, routingProfile);
|
|
45
|
+
if (root === undefined) {
|
|
46
|
+
throw new Error(`routing profile ${JSON.stringify(routingProfile)} was not found from ${cwd}`);
|
|
47
|
+
}
|
|
48
|
+
loadRepositoryRoutingProfile({ repositoryRoot: root, name: routingProfile });
|
|
49
|
+
return root;
|
|
50
|
+
},
|
|
51
|
+
catch: (cause) => new ControlError({
|
|
128
52
|
code: "not_found",
|
|
129
|
-
message:
|
|
130
|
-
?
|
|
131
|
-
: `
|
|
132
|
-
})
|
|
133
|
-
}
|
|
53
|
+
message: cause instanceof Error
|
|
54
|
+
? cause.message
|
|
55
|
+
: `routing profile ${JSON.stringify(routingProfile)} was not found`
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
routingContext = { repositoryRoot, profileName: routingProfile };
|
|
59
|
+
}
|
|
60
|
+
let model = routingProfile === undefined
|
|
61
|
+
? (params.model ?? listed.defaultModel ?? listed.models[0]?.id)
|
|
62
|
+
: `auto:${routingProfile}`;
|
|
63
|
+
let codexSelection;
|
|
64
|
+
if (params.tool === "codex" && routingProfile === undefined) {
|
|
134
65
|
const gateway = yield* ActiveGateway;
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
66
|
+
const candidates = listed.models.flatMap((entry) => {
|
|
67
|
+
const info = gateway.router().modelInfo(entry.id);
|
|
68
|
+
if (info === undefined)
|
|
69
|
+
return [];
|
|
70
|
+
const candidate = {
|
|
71
|
+
id: info.id,
|
|
72
|
+
nativeId: info.nativeModel,
|
|
73
|
+
provider: info.provider,
|
|
74
|
+
billingScope: info.billingMode
|
|
75
|
+
};
|
|
76
|
+
if (info.createdAt !== undefined)
|
|
77
|
+
candidate.createdAt = info.createdAt;
|
|
78
|
+
if (info.providerPriority !== undefined) {
|
|
79
|
+
candidate.providerPriority = info.providerPriority;
|
|
80
|
+
}
|
|
81
|
+
if (info.metadata?.architecture !== undefined) {
|
|
82
|
+
candidate.architecture = info.metadata.architecture;
|
|
83
|
+
}
|
|
84
|
+
if (info.metadata?.supportedParameters !== undefined) {
|
|
85
|
+
candidate.supportedParameters = info.metadata.supportedParameters;
|
|
86
|
+
}
|
|
87
|
+
const capabilities = {};
|
|
88
|
+
for (const name of ["responses", "tools"]) {
|
|
89
|
+
const status = info.capabilities[name];
|
|
90
|
+
if (status === "supported" ||
|
|
91
|
+
status === "unsupported" ||
|
|
92
|
+
status === "degraded" ||
|
|
93
|
+
status === "unknown") {
|
|
94
|
+
capabilities[name] = status;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (Object.keys(capabilities).length > 0) {
|
|
98
|
+
candidate.capabilities = capabilities;
|
|
99
|
+
}
|
|
100
|
+
if (info.reasoning !== null)
|
|
101
|
+
candidate.reasoning = info.reasoning;
|
|
102
|
+
return [candidate];
|
|
103
|
+
});
|
|
104
|
+
const selected = yield* resolveCodexStartupModel({
|
|
105
|
+
models: candidates,
|
|
106
|
+
...(listed.defaultModel !== undefined ? { preferredModel: listed.defaultModel } : {}),
|
|
107
|
+
...(params.model !== undefined ? { requestedModel: params.model } : {}),
|
|
108
|
+
signal: context.signal
|
|
109
|
+
}).pipe(Effect.mapError((error) => {
|
|
110
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
111
|
+
return new ControlError({
|
|
112
|
+
code: params.model !== undefined && message.startsWith("unknown model")
|
|
113
|
+
? "not_found"
|
|
114
|
+
: "unavailable",
|
|
115
|
+
message
|
|
116
|
+
});
|
|
117
|
+
}));
|
|
118
|
+
model = selected.model;
|
|
119
|
+
codexSelection = {
|
|
120
|
+
compatibleModelIds: [...selected.compatibleModelIds],
|
|
121
|
+
models: [...selected.models]
|
|
144
122
|
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
123
|
+
}
|
|
124
|
+
if (model === undefined ||
|
|
125
|
+
(routingProfile === undefined && !listed.models.some((entry) => entry.id === model))) {
|
|
126
|
+
return yield* Effect.fail(new ControlError({
|
|
127
|
+
code: "not_found",
|
|
128
|
+
message: params.model === undefined
|
|
129
|
+
? "no model is available"
|
|
130
|
+
: `unknown model: ${params.model}`
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
const gateway = yield* ActiveGateway;
|
|
134
|
+
const tokens = yield* Tokens;
|
|
135
|
+
const gatewayUrl = gateway.dataUrl() ?? "";
|
|
136
|
+
let authToken;
|
|
137
|
+
if (routingContext === undefined) {
|
|
138
|
+
authToken = yield* tokens.dataTokenForPrincipal(context.principal);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const launcherSessions = yield* LauncherSessions;
|
|
142
|
+
authToken = launcherSessions.open({
|
|
143
|
+
...routingContext,
|
|
144
|
+
role: context.principal === undefined || context.principal.role === "ephemeral"
|
|
145
|
+
? "owner"
|
|
146
|
+
: context.principal.role
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
tool: params.tool,
|
|
151
|
+
model,
|
|
152
|
+
gatewayUrl,
|
|
153
|
+
authToken,
|
|
154
|
+
env: {},
|
|
155
|
+
...(codexSelection !== undefined ? { codexSelection } : {})
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
})
|
|
159
|
+
};
|
|
149
160
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ProviderModuleRegistry } from "@velum-labs/routekit-provider-core";
|
|
2
|
+
export declare const providerModules: ProviderModuleRegistry;
|
|
3
|
+
export declare function validateProviderModules(registry: ProviderModuleRegistry): ProviderModuleRegistry;
|
|
4
|
+
export declare function currentProviderModules(): ProviderModuleRegistry;
|
|
5
|
+
/** Install an alternate registry for one in-process test and return its restore operation. */
|
|
6
|
+
export declare function installProviderModulesForTest(registry: ProviderModuleRegistry): () => void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { anthropic } from "./internal-providers/provider-anthropic/index.js";
|
|
2
|
+
import { azure } from "./internal-providers/provider-azure/index.js";
|
|
3
|
+
import { bedrock } from "./internal-providers/provider-bedrock/index.js";
|
|
4
|
+
import { claudeCode } from "./internal-providers/provider-claude-code/index.js";
|
|
5
|
+
import { cliproxy } from "./internal-providers/provider-cliproxy/index.js";
|
|
6
|
+
import { codex } from "./internal-providers/provider-codex/index.js";
|
|
7
|
+
import { ProviderModuleRegistry } from "@velum-labs/routekit-provider-core";
|
|
8
|
+
import { custom } from "./internal-providers/provider-custom/index.js";
|
|
9
|
+
import { google } from "./internal-providers/provider-google/index.js";
|
|
10
|
+
import { googleVertex } from "./internal-providers/provider-google-vertex/index.js";
|
|
11
|
+
import { openai } from "./internal-providers/provider-openai/index.js";
|
|
12
|
+
import { openaiCompatible } from "./internal-providers/provider-openai-compatible/index.js";
|
|
13
|
+
import { openrouter } from "./internal-providers/provider-openrouter/index.js";
|
|
14
|
+
import { providerModuleInfo } from "@velum-labs/routekit-registry";
|
|
15
|
+
export const providerModules = new ProviderModuleRegistry([
|
|
16
|
+
openai,
|
|
17
|
+
anthropic,
|
|
18
|
+
bedrock,
|
|
19
|
+
google,
|
|
20
|
+
openrouter,
|
|
21
|
+
cliproxy,
|
|
22
|
+
claudeCode,
|
|
23
|
+
codex,
|
|
24
|
+
openaiCompatible,
|
|
25
|
+
custom,
|
|
26
|
+
azure,
|
|
27
|
+
googleVertex
|
|
28
|
+
]);
|
|
29
|
+
export function validateProviderModules(registry) {
|
|
30
|
+
for (const module of registry.list()) {
|
|
31
|
+
const catalog = providerModuleInfo(module.id);
|
|
32
|
+
if (catalog === undefined) {
|
|
33
|
+
throw new Error(`provider module "${module.id}" is missing its catalog row`);
|
|
34
|
+
}
|
|
35
|
+
if (catalog.protocol !== module.protocol ||
|
|
36
|
+
catalog.accountClass !== module.accountClass ||
|
|
37
|
+
catalog.billingMode !== module.billingMode) {
|
|
38
|
+
throw new Error(`provider module "${module.id}" disagrees with its catalog row`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return registry;
|
|
42
|
+
}
|
|
43
|
+
validateProviderModules(providerModules);
|
|
44
|
+
let activeProviderModules = providerModules;
|
|
45
|
+
export function currentProviderModules() {
|
|
46
|
+
return activeProviderModules;
|
|
47
|
+
}
|
|
48
|
+
/** Install an alternate registry for one in-process test and return its restore operation. */
|
|
49
|
+
export function installProviderModulesForTest(registry) {
|
|
50
|
+
const previous = activeProviderModules;
|
|
51
|
+
activeProviderModules = validateProviderModules(registry);
|
|
52
|
+
return () => {
|
|
53
|
+
activeProviderModules = previous;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { EffectRouteKitControlHandlers } from "@velum-labs/routekit-control/effect";
|
|
2
2
|
type ProviderHandlers = Pick<EffectRouteKitControlHandlers, "providers.status" | "models.list" | "models.info" | "calls.inspect" | "calls.leaderboard">;
|
|
3
3
|
/** Owns provider health, catalog, inspection, and leaderboard queries. */
|
|
4
|
-
export declare
|
|
5
|
-
handlers(): ProviderHandlers;
|
|
6
|
-
}
|
|
4
|
+
export declare const providerHandlers: ProviderHandlers;
|
|
7
5
|
export {};
|
|
@@ -10,150 +10,147 @@ import { accountEntriesEffect, providerCredentialAvailable } from "./daemon-main
|
|
|
10
10
|
import { writeSnapshotEffect } from "./daemon-state.js";
|
|
11
11
|
import { aggregateInspections, buildLeaderboardResult, defaultLeaderboardWindow } from "./leaderboard.js";
|
|
12
12
|
/** Owns provider health, catalog, inspection, and leaderboard queries. */
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const status = live.find((entry) => entry.provider === provider);
|
|
25
|
-
return {
|
|
26
|
-
provider,
|
|
27
|
-
configured: true,
|
|
28
|
-
credentialAvailable: providerCredentialAvailable(provider, accounts, env.env),
|
|
29
|
-
models: status?.models ?? [],
|
|
30
|
-
...(status?.error !== undefined ? { error: status.error } : {})
|
|
31
|
-
};
|
|
32
|
-
})
|
|
33
|
-
};
|
|
34
|
-
yield* writeSnapshotEffect(env.home, "health", "providers", {
|
|
35
|
-
checkedAt: new Date().toISOString(),
|
|
36
|
-
providers: result.providers
|
|
37
|
-
});
|
|
38
|
-
return result;
|
|
39
|
-
}),
|
|
40
|
-
"models.list": (params) => Effect.gen(function* () {
|
|
41
|
-
const env = yield* DaemonEnv;
|
|
42
|
-
const state = yield* DaemonState;
|
|
43
|
-
const gateway = yield* ActiveGateway;
|
|
44
|
-
const catalog = gateway.router().modelCatalog();
|
|
45
|
-
const models = catalog
|
|
46
|
-
.filter((model) => params.provider === undefined || model.id.startsWith(`${params.provider}/`))
|
|
47
|
-
.map((model) => ({
|
|
48
|
-
id: model.id,
|
|
49
|
-
provider: model.provider,
|
|
50
|
-
owned_by: model.provider,
|
|
51
|
-
routekit_provider_priority: model.providerPriority,
|
|
52
|
-
capabilities: { ...model.capabilities },
|
|
53
|
-
...(model.metadata?.architecture !== undefined
|
|
54
|
-
? {
|
|
55
|
-
architecture: {
|
|
56
|
-
modality: model.metadata.architecture.modality,
|
|
57
|
-
input_modalities: model.metadata.architecture.inputModalities,
|
|
58
|
-
output_modalities: model.metadata.architecture.outputModalities
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
: {}),
|
|
62
|
-
...(model.metadata?.supportedParameters !== undefined
|
|
63
|
-
? { supported_parameters: model.metadata.supportedParameters }
|
|
64
|
-
: {}),
|
|
65
|
-
reasoning: model.reasoning === null || model.reasoning === undefined
|
|
66
|
-
? undefined
|
|
67
|
-
: { ...model.reasoning }
|
|
68
|
-
}));
|
|
69
|
-
const result = {
|
|
70
|
-
models,
|
|
71
|
-
...(state.config.defaultModel !== undefined
|
|
72
|
-
? { defaultModel: state.config.defaultModel }
|
|
73
|
-
: catalog.some((model) => model.default)
|
|
74
|
-
? { defaultModel: catalog.find((model) => model.default)?.id }
|
|
75
|
-
: {}),
|
|
76
|
-
revision: state.revisions.config
|
|
77
|
-
};
|
|
78
|
-
yield* writeSnapshotEffect(env.home, "catalog", "models", {
|
|
79
|
-
updatedAt: new Date().toISOString(),
|
|
80
|
-
defaultModel: result.defaultModel,
|
|
81
|
-
models
|
|
82
|
-
});
|
|
83
|
-
return result;
|
|
84
|
-
}),
|
|
85
|
-
"models.info": (params) => Effect.gen(function* () {
|
|
86
|
-
const gateway = yield* ActiveGateway;
|
|
87
|
-
const model = gateway.router().modelInfo(params.model);
|
|
88
|
-
if (model === undefined) {
|
|
89
|
-
return yield* Effect.fail(new ControlError({
|
|
90
|
-
code: "not_found",
|
|
91
|
-
message: `unknown model: ${params.model}`
|
|
92
|
-
}));
|
|
93
|
-
}
|
|
13
|
+
export const providerHandlers = {
|
|
14
|
+
"providers.status": (_params, context) => Effect.gen(function* () {
|
|
15
|
+
const env = yield* DaemonEnv;
|
|
16
|
+
const state = yield* DaemonState;
|
|
17
|
+
const gateway = yield* ActiveGateway;
|
|
18
|
+
const accounts = yield* accountEntriesEffect(env.env);
|
|
19
|
+
const live = yield* gateway.router().providerStatuses(context.signal);
|
|
20
|
+
const result = {
|
|
21
|
+
providers: configuredProviderIds(state.config).map((provider) => {
|
|
22
|
+
const source = state.config.sources[provider];
|
|
23
|
+
const status = live.find((entry) => entry.provider === provider);
|
|
94
24
|
return {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
25
|
+
provider,
|
|
26
|
+
configured: true,
|
|
27
|
+
credentialAvailable: providerCredentialAvailable(source, accounts, env.env),
|
|
28
|
+
models: status?.models ?? [],
|
|
29
|
+
...(status?.error !== undefined ? { error: status.error } : {})
|
|
98
30
|
};
|
|
99
|
-
}),
|
|
100
|
-
"calls.inspect": (params) => Effect.gen(function* () {
|
|
101
|
-
const attributions = yield* CallAttributions;
|
|
102
|
-
const inspection = attributions.get(params.callId);
|
|
103
|
-
if (inspection === undefined) {
|
|
104
|
-
return yield* Effect.fail(new ControlError({
|
|
105
|
-
code: "not_found",
|
|
106
|
-
message: `unknown or expired model call: ${params.callId}`
|
|
107
|
-
}));
|
|
108
|
-
}
|
|
109
|
-
return inspection;
|
|
110
|
-
}),
|
|
111
|
-
"calls.leaderboard": (params) => Effect.gen(function* () {
|
|
112
|
-
const attributions = yield* CallAttributions;
|
|
113
|
-
const leaderboard = yield* Leaderboard;
|
|
114
|
-
const config = leaderboard.config();
|
|
115
|
-
const by = params.by ?? "principal";
|
|
116
|
-
const sort = params.sort ?? "cost";
|
|
117
|
-
const limit = params.limit ?? 20;
|
|
118
|
-
const window = params.window ?? defaultLeaderboardWindow(config);
|
|
119
|
-
const nowIso = new Date().toISOString();
|
|
120
|
-
if (window === "live") {
|
|
121
|
-
const aggregated = aggregateInspections(attributions.list(), {
|
|
122
|
-
by,
|
|
123
|
-
sort,
|
|
124
|
-
limit
|
|
125
|
-
});
|
|
126
|
-
return buildLeaderboardResult({
|
|
127
|
-
by,
|
|
128
|
-
sort,
|
|
129
|
-
source: "live",
|
|
130
|
-
windowStart: aggregated.windowStart ?? nowIso,
|
|
131
|
-
windowEnd: aggregated.windowEnd ?? nowIso,
|
|
132
|
-
sampleSize: aggregated.sampleSize,
|
|
133
|
-
truncated: attributions.truncated(),
|
|
134
|
-
budget: config,
|
|
135
|
-
rows: aggregated.rows
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
if (!config.durable) {
|
|
139
|
-
return yield* Effect.fail(new ControlError({
|
|
140
|
-
code: "bad_request",
|
|
141
|
-
message: "durable leaderboard rollups are disabled; set leaderboard.durable: true in router.yaml"
|
|
142
|
-
}));
|
|
143
|
-
}
|
|
144
|
-
const aggregated = leaderboard.rollups.query({ by, sort, limit, window });
|
|
145
|
-
return buildLeaderboardResult({
|
|
146
|
-
by,
|
|
147
|
-
sort,
|
|
148
|
-
source: "durable",
|
|
149
|
-
windowStart: aggregated.windowStart,
|
|
150
|
-
windowEnd: aggregated.windowEnd,
|
|
151
|
-
sampleSize: aggregated.sampleSize,
|
|
152
|
-
truncated: false,
|
|
153
|
-
budget: config,
|
|
154
|
-
rows: aggregated.rows
|
|
155
|
-
});
|
|
156
31
|
})
|
|
157
32
|
};
|
|
158
|
-
|
|
159
|
-
|
|
33
|
+
yield* writeSnapshotEffect(env.home, "health", "providers", {
|
|
34
|
+
checkedAt: new Date().toISOString(),
|
|
35
|
+
providers: result.providers
|
|
36
|
+
});
|
|
37
|
+
return result;
|
|
38
|
+
}),
|
|
39
|
+
"models.list": (params) => Effect.gen(function* () {
|
|
40
|
+
const env = yield* DaemonEnv;
|
|
41
|
+
const state = yield* DaemonState;
|
|
42
|
+
const gateway = yield* ActiveGateway;
|
|
43
|
+
const catalog = gateway.router().modelCatalog();
|
|
44
|
+
const models = catalog
|
|
45
|
+
.filter((model) => params.provider === undefined || model.id.startsWith(`${params.provider}/`))
|
|
46
|
+
.map((model) => ({
|
|
47
|
+
id: model.id,
|
|
48
|
+
provider: model.provider,
|
|
49
|
+
owned_by: model.provider,
|
|
50
|
+
routekit_provider_priority: model.providerPriority,
|
|
51
|
+
capabilities: { ...model.capabilities },
|
|
52
|
+
...(model.metadata?.architecture !== undefined
|
|
53
|
+
? {
|
|
54
|
+
architecture: {
|
|
55
|
+
modality: model.metadata.architecture.modality,
|
|
56
|
+
input_modalities: model.metadata.architecture.inputModalities,
|
|
57
|
+
output_modalities: model.metadata.architecture.outputModalities
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
: {}),
|
|
61
|
+
...(model.metadata?.supportedParameters !== undefined
|
|
62
|
+
? { supported_parameters: model.metadata.supportedParameters }
|
|
63
|
+
: {}),
|
|
64
|
+
reasoning: model.reasoning === null || model.reasoning === undefined
|
|
65
|
+
? undefined
|
|
66
|
+
: { ...model.reasoning }
|
|
67
|
+
}));
|
|
68
|
+
const result = {
|
|
69
|
+
models,
|
|
70
|
+
...(state.config.defaultModel !== undefined
|
|
71
|
+
? { defaultModel: state.config.defaultModel }
|
|
72
|
+
: catalog.some((model) => model.default)
|
|
73
|
+
? { defaultModel: catalog.find((model) => model.default)?.id }
|
|
74
|
+
: {}),
|
|
75
|
+
revision: state.revisions.config
|
|
76
|
+
};
|
|
77
|
+
yield* writeSnapshotEffect(env.home, "catalog", "models", {
|
|
78
|
+
updatedAt: new Date().toISOString(),
|
|
79
|
+
defaultModel: result.defaultModel,
|
|
80
|
+
models
|
|
81
|
+
});
|
|
82
|
+
return result;
|
|
83
|
+
}),
|
|
84
|
+
"models.info": (params) => Effect.gen(function* () {
|
|
85
|
+
const gateway = yield* ActiveGateway;
|
|
86
|
+
const model = gateway.router().modelInfo(params.model);
|
|
87
|
+
if (model === undefined) {
|
|
88
|
+
return yield* Effect.fail(new ControlError({
|
|
89
|
+
code: "not_found",
|
|
90
|
+
message: `unknown model: ${params.model}`
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
...model,
|
|
95
|
+
capabilities: { ...model.capabilities },
|
|
96
|
+
reasoning: model.reasoning === null ? null : { ...model.reasoning }
|
|
97
|
+
};
|
|
98
|
+
}),
|
|
99
|
+
"calls.inspect": (params) => Effect.gen(function* () {
|
|
100
|
+
const attributions = yield* CallAttributions;
|
|
101
|
+
const inspection = attributions.get(params.callId);
|
|
102
|
+
if (inspection === undefined) {
|
|
103
|
+
return yield* Effect.fail(new ControlError({
|
|
104
|
+
code: "not_found",
|
|
105
|
+
message: `unknown or expired model call: ${params.callId}`
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
return inspection;
|
|
109
|
+
}),
|
|
110
|
+
"calls.leaderboard": (params) => Effect.gen(function* () {
|
|
111
|
+
const attributions = yield* CallAttributions;
|
|
112
|
+
const leaderboard = yield* Leaderboard;
|
|
113
|
+
const config = leaderboard.config();
|
|
114
|
+
const by = params.by ?? "principal";
|
|
115
|
+
const sort = params.sort ?? "cost";
|
|
116
|
+
const limit = params.limit ?? 20;
|
|
117
|
+
const window = params.window ?? defaultLeaderboardWindow(config);
|
|
118
|
+
const nowIso = new Date().toISOString();
|
|
119
|
+
if (window === "live") {
|
|
120
|
+
const aggregated = aggregateInspections(attributions.list(), {
|
|
121
|
+
by,
|
|
122
|
+
sort,
|
|
123
|
+
limit
|
|
124
|
+
});
|
|
125
|
+
return buildLeaderboardResult({
|
|
126
|
+
by,
|
|
127
|
+
sort,
|
|
128
|
+
source: "live",
|
|
129
|
+
windowStart: aggregated.windowStart ?? nowIso,
|
|
130
|
+
windowEnd: aggregated.windowEnd ?? nowIso,
|
|
131
|
+
sampleSize: aggregated.sampleSize,
|
|
132
|
+
truncated: attributions.truncated(),
|
|
133
|
+
budget: config,
|
|
134
|
+
rows: aggregated.rows
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (!config.durable) {
|
|
138
|
+
return yield* Effect.fail(new ControlError({
|
|
139
|
+
code: "bad_request",
|
|
140
|
+
message: "durable leaderboard rollups are disabled; set leaderboard.durable: true in router.yaml"
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
const aggregated = leaderboard.rollups.query({ by, sort, limit, window });
|
|
144
|
+
return buildLeaderboardResult({
|
|
145
|
+
by,
|
|
146
|
+
sort,
|
|
147
|
+
source: "durable",
|
|
148
|
+
windowStart: aggregated.windowStart,
|
|
149
|
+
windowEnd: aggregated.windowEnd,
|
|
150
|
+
sampleSize: aggregated.sampleSize,
|
|
151
|
+
truncated: false,
|
|
152
|
+
budget: config,
|
|
153
|
+
rows: aggregated.rows
|
|
154
|
+
});
|
|
155
|
+
})
|
|
156
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { EffectRouteKitControlHandlers } from "@velum-labs/routekit-control/effect";
|
|
2
2
|
type RouterHandlers = Pick<EffectRouteKitControlHandlers, "daemon.reload" | "config.get" | "config.update" | "config.import" | "providers.set">;
|
|
3
3
|
/** Owns config mutations and generation publication use cases. */
|
|
4
|
-
export declare
|
|
5
|
-
handlers(): RouterHandlers;
|
|
6
|
-
}
|
|
4
|
+
export declare const routerGenerationHandlers: RouterHandlers;
|
|
7
5
|
export {};
|