llm-cli-gateway 2.12.0 → 2.12.2
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/CHANGELOG.md +29 -0
- package/README.md +132 -5
- package/dist/api-provider.d.ts +1 -0
- package/dist/api-provider.js +13 -0
- package/dist/async-job-manager.d.ts +34 -2
- package/dist/async-job-manager.js +344 -46
- package/dist/config.d.ts +34 -0
- package/dist/config.js +91 -0
- package/dist/doctor.d.ts +30 -2
- package/dist/doctor.js +78 -6
- package/dist/endpoint-exposure.js +15 -3
- package/dist/http-transport.d.ts +3 -0
- package/dist/http-transport.js +138 -8
- package/dist/index.d.ts +15 -0
- package/dist/index.js +221 -74
- package/dist/provider-login-guidance.d.ts +12 -0
- package/dist/provider-login-guidance.js +28 -0
- package/dist/provider-status.d.ts +12 -0
- package/dist/provider-status.js +14 -0
- package/dist/provider-tool-capabilities.d.ts +4 -1
- package/dist/provider-tool-capabilities.js +225 -11
- package/dist/resources.d.ts +6 -2
- package/dist/resources.js +72 -8
- package/dist/validation-normalizer.js +5 -4
- package/npm-shrinkwrap.json +5 -5
- package/package.json +2 -1
- package/setup/status.schema.json +65 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CliType } from "./session-manager.js";
|
|
2
|
+
import type { ApiProviderConfig } from "./config.js";
|
|
2
3
|
export interface ProviderLoginGuidance {
|
|
3
4
|
provider: CliType;
|
|
4
5
|
displayName: string;
|
|
@@ -19,3 +20,14 @@ export interface ProviderLoginGuidance {
|
|
|
19
20
|
}
|
|
20
21
|
export declare function getProviderLoginGuidance(provider: CliType): ProviderLoginGuidance;
|
|
21
22
|
export declare function getAllProviderLoginGuidance(): Record<CliType, ProviderLoginGuidance>;
|
|
23
|
+
export interface ApiProviderLoginGuidance {
|
|
24
|
+
provider: string;
|
|
25
|
+
displayName: string;
|
|
26
|
+
kind: ApiProviderConfig["kind"];
|
|
27
|
+
baseUrl: string;
|
|
28
|
+
apiKeyEnv: string | null;
|
|
29
|
+
summary: string;
|
|
30
|
+
steps: string[];
|
|
31
|
+
credentialHandling: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function getApiProviderLoginGuidance(provider: ApiProviderConfig): ApiProviderLoginGuidance;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { redactDiagnosticUrl } from "./endpoint-exposure.js";
|
|
1
2
|
const GUIDANCE = {
|
|
2
3
|
claude: {
|
|
3
4
|
provider: "claude",
|
|
@@ -122,3 +123,30 @@ export function getProviderLoginGuidance(provider) {
|
|
|
122
123
|
export function getAllProviderLoginGuidance() {
|
|
123
124
|
return { ...GUIDANCE };
|
|
124
125
|
}
|
|
126
|
+
export function getApiProviderLoginGuidance(provider) {
|
|
127
|
+
const keyless = provider.apiKeyEnv === null;
|
|
128
|
+
const baseUrl = redactDiagnosticUrl(provider.baseUrl) ?? provider.baseUrl;
|
|
129
|
+
const summary = keyless
|
|
130
|
+
? `Keyless-local API provider "${provider.name}" (kind: ${provider.kind}); no credential is required for its loopback endpoint.`
|
|
131
|
+
: `API provider "${provider.name}" (kind: ${provider.kind}) authenticates with a key read from the ${provider.apiKeyEnv} environment variable.`;
|
|
132
|
+
const steps = keyless
|
|
133
|
+
? [
|
|
134
|
+
`Ensure the local endpoint at ${baseUrl} is running (e.g. Ollama or llama.cpp).`,
|
|
135
|
+
`No API key is needed; the provider is enabled as soon as the loopback endpoint is reachable.`,
|
|
136
|
+
]
|
|
137
|
+
: [
|
|
138
|
+
`Obtain an API key from the provider that serves ${baseUrl}.`,
|
|
139
|
+
`Export it as ${provider.apiKeyEnv} in the gateway's environment (the value is read only at request time).`,
|
|
140
|
+
`Confirm [providers.${provider.name}] in the gateway config points at the intended base_url and default_model.`,
|
|
141
|
+
];
|
|
142
|
+
return {
|
|
143
|
+
provider: provider.name,
|
|
144
|
+
displayName: provider.name,
|
|
145
|
+
kind: provider.kind,
|
|
146
|
+
baseUrl,
|
|
147
|
+
apiKeyEnv: provider.apiKeyEnv,
|
|
148
|
+
summary,
|
|
149
|
+
steps,
|
|
150
|
+
credentialHandling: "Set the API key only via the named environment variable. Do not paste the key into the gateway config, prompts, or a remote chat.",
|
|
151
|
+
};
|
|
152
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CliType } from "./session-manager.js";
|
|
2
2
|
import { type ProviderLoginGuidance } from "./provider-login-guidance.js";
|
|
3
|
+
import { type ApiProviderConfig } from "./config.js";
|
|
3
4
|
export type ProviderLoginStatus = "authenticated" | "not_authenticated" | "unknown" | "not_checked";
|
|
4
5
|
export interface ProviderRuntimeStatus {
|
|
5
6
|
provider: CliType;
|
|
@@ -17,6 +18,17 @@ export interface ProviderRuntimeStatus {
|
|
|
17
18
|
};
|
|
18
19
|
guidance: ProviderLoginGuidance;
|
|
19
20
|
}
|
|
21
|
+
export interface ApiProviderRuntimeStatus {
|
|
22
|
+
provider: string;
|
|
23
|
+
kind: ApiProviderConfig["kind"];
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
defaultModel: string;
|
|
26
|
+
models: string[] | null;
|
|
27
|
+
apiKeyEnv: string | null;
|
|
28
|
+
apiKeyPresent: boolean;
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function getApiProviderStatus(provider: ApiProviderConfig, env?: NodeJS.ProcessEnv): ApiProviderRuntimeStatus;
|
|
20
32
|
export declare const PROVIDER_COMMANDS: Record<CliType, string>;
|
|
21
33
|
export declare function listProviderRuntimeStatuses(): Record<CliType, ProviderRuntimeStatus>;
|
|
22
34
|
export declare function getProviderRuntimeStatus(provider: CliType): ProviderRuntimeStatus;
|
package/dist/provider-status.js
CHANGED
|
@@ -3,7 +3,21 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { getProviderLoginGuidance } from "./provider-login-guidance.js";
|
|
6
|
+
import { apiProviderKeyPresent, isApiProviderEnabled } from "./config.js";
|
|
7
|
+
import { redactDiagnosticUrl } from "./endpoint-exposure.js";
|
|
6
8
|
import { envWithExtendedPath, getExtendedPath, providerCommandName, resolveCommandForSpawn, } from "./executor.js";
|
|
9
|
+
export function getApiProviderStatus(provider, env = process.env) {
|
|
10
|
+
return {
|
|
11
|
+
provider: provider.name,
|
|
12
|
+
kind: provider.kind,
|
|
13
|
+
baseUrl: redactDiagnosticUrl(provider.baseUrl) ?? provider.baseUrl,
|
|
14
|
+
defaultModel: provider.defaultModel,
|
|
15
|
+
models: provider.models ?? null,
|
|
16
|
+
apiKeyEnv: provider.apiKeyEnv,
|
|
17
|
+
apiKeyPresent: apiProviderKeyPresent(provider, env),
|
|
18
|
+
enabled: isApiProviderEnabled(provider, env),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
7
21
|
const PROVIDERS = ["claude", "codex", "gemini", "grok", "mistral", "devin"];
|
|
8
22
|
const VERSION_ARGS = {
|
|
9
23
|
claude: ["--version"],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CliInfo } from "./model-registry.js";
|
|
2
2
|
import { type CliType } from "./session-manager.js";
|
|
3
|
+
import { type ProvidersConfig } from "./config.js";
|
|
3
4
|
export interface ProviderToolControl {
|
|
4
5
|
name?: string;
|
|
5
6
|
supported: boolean;
|
|
@@ -128,6 +129,7 @@ export interface ProviderCapabilityQuery {
|
|
|
128
129
|
includeUnsupported?: boolean;
|
|
129
130
|
includePaths?: boolean;
|
|
130
131
|
refresh?: boolean;
|
|
132
|
+
providersConfig?: ProvidersConfig;
|
|
131
133
|
}
|
|
132
134
|
export type ProviderToolCapabilitiesMap = Partial<Record<ProviderCapabilityId, ProviderToolCapabilities>>;
|
|
133
135
|
export declare function getProviderToolCapabilities(queryOrCli?: ProviderCapabilityQuery | ProviderCapabilityId): ProviderToolCapabilitiesMap;
|
|
@@ -137,4 +139,5 @@ export declare function _getCapabilityCacheForTest(): Map<string, {
|
|
|
137
139
|
loadedAt: number;
|
|
138
140
|
value: ProviderToolCapabilities;
|
|
139
141
|
}>;
|
|
140
|
-
export declare function providerCapabilityIds(): readonly
|
|
142
|
+
export declare function providerCapabilityIds(providersConfig?: ProvidersConfig): readonly ProviderCapabilityId[];
|
|
143
|
+
export declare function knownProviderCapabilityIds(): readonly KnownProviderCapabilityId[];
|
|
@@ -5,7 +5,8 @@ import { parse as parseToml } from "smol-toml";
|
|
|
5
5
|
import { CLAUDE_MCP_SERVER_NAMES } from "./claude-mcp-config.js";
|
|
6
6
|
import { getAvailableCliInfo } from "./model-registry.js";
|
|
7
7
|
import { CLI_TYPES } from "./session-manager.js";
|
|
8
|
-
import { isXaiProviderEnabled, loadProvidersConfig } from "./config.js";
|
|
8
|
+
import { enabledApiProviders, isXaiProviderEnabled, loadProvidersConfig, } from "./config.js";
|
|
9
|
+
import { apiContinuityForKind } from "./api-provider.js";
|
|
9
10
|
const MAX_SKILLS_PER_DIR = 100;
|
|
10
11
|
const MAX_SKILL_BYTES = 64 * 1024;
|
|
11
12
|
const MAX_CONFIG_BYTES = 128 * 1024;
|
|
@@ -809,7 +810,7 @@ const TOOL_CONTROLS = {
|
|
|
809
810
|
const CAPABILITY_CACHE = new Map();
|
|
810
811
|
export function getProviderToolCapabilities(queryOrCli = {}) {
|
|
811
812
|
const query = normalizeQuery(queryOrCli);
|
|
812
|
-
const providers = query.cli ? [query.cli] :
|
|
813
|
+
const providers = query.cli ? [query.cli] : allProviderCapabilityIds(query.providersConfig);
|
|
813
814
|
const entries = providers.map(provider => [
|
|
814
815
|
provider,
|
|
815
816
|
getOneProviderToolCapabilities(provider, query),
|
|
@@ -833,14 +834,35 @@ export function clearProviderToolCapabilitiesCache() {
|
|
|
833
834
|
export function _getCapabilityCacheForTest() {
|
|
834
835
|
return CAPABILITY_CACHE;
|
|
835
836
|
}
|
|
836
|
-
|
|
837
|
+
function providersConfigForQuery(query) {
|
|
838
|
+
return query.providersConfig ?? loadProvidersConfig();
|
|
839
|
+
}
|
|
840
|
+
function enabledApiCapabilityIds(providersConfig) {
|
|
841
|
+
return enabledApiProviders(providersConfig ?? loadProvidersConfig()).map(provider => provider.name);
|
|
842
|
+
}
|
|
843
|
+
function allProviderCapabilityIds(providersConfig) {
|
|
844
|
+
return [
|
|
845
|
+
...new Set([
|
|
846
|
+
...PROVIDER_CAPABILITY_IDS,
|
|
847
|
+
...enabledApiCapabilityIds(providersConfig),
|
|
848
|
+
]),
|
|
849
|
+
];
|
|
850
|
+
}
|
|
851
|
+
export function providerCapabilityIds(providersConfig) {
|
|
852
|
+
return allProviderCapabilityIds(providersConfig);
|
|
853
|
+
}
|
|
854
|
+
export function knownProviderCapabilityIds() {
|
|
837
855
|
return PROVIDER_CAPABILITY_IDS;
|
|
838
856
|
}
|
|
839
857
|
function buildOneProviderToolCapabilities(cli, query) {
|
|
840
858
|
const warnings = [];
|
|
841
859
|
if (!isKnownProviderCapabilityId(cli)) {
|
|
842
|
-
|
|
843
|
-
|
|
860
|
+
const runtime = enabledApiProviders(providersConfigForQuery(query)).find(provider => provider.name === cli);
|
|
861
|
+
if (!runtime) {
|
|
862
|
+
throw new Error(`No tool-capability metadata for provider "${cli}". ` +
|
|
863
|
+
`Known providers: ${allProviderCapabilityIds(query.providersConfig).join(", ")}.`);
|
|
864
|
+
}
|
|
865
|
+
return buildApiProviderToolCapabilities(runtime, query);
|
|
844
866
|
}
|
|
845
867
|
const definition = TOOL_CONTROLS[cli];
|
|
846
868
|
const discoveredSkills = query.includeSkills && cli !== "grok_api" ? discoverSkills(cli, warnings, query) : [];
|
|
@@ -848,7 +870,7 @@ function buildOneProviderToolCapabilities(cli, query) {
|
|
|
848
870
|
? extractProviderTools(cli, discoveredSkills)
|
|
849
871
|
: [];
|
|
850
872
|
const features = { ...definition.features };
|
|
851
|
-
const gatewayRequestTools = cli === "grok_api" && !isXaiProviderEnabled(
|
|
873
|
+
const gatewayRequestTools = cli === "grok_api" && !isXaiProviderEnabled(providersConfigForQuery(query))
|
|
852
874
|
? []
|
|
853
875
|
: [...definition.gatewayRequestTools];
|
|
854
876
|
if (cli === "grok") {
|
|
@@ -864,7 +886,7 @@ function buildOneProviderToolCapabilities(cli, query) {
|
|
|
864
886
|
providerKind: definition.providerKind,
|
|
865
887
|
gatewayRequestTools,
|
|
866
888
|
gatewayRequestTool: gatewayRequestTools[0] ?? definition.gatewayRequestTools[0],
|
|
867
|
-
modelInfo: getModelInfo(cli, query
|
|
889
|
+
modelInfo: getModelInfo(cli, query),
|
|
868
890
|
summary: definition.summary,
|
|
869
891
|
acpContract: { ...ACP_CONTRACT.providers[cli] },
|
|
870
892
|
acp: cloneAcpCapability(ACP_CAPABILITIES[cli]),
|
|
@@ -883,6 +905,172 @@ function buildOneProviderToolCapabilities(cli, query) {
|
|
|
883
905
|
},
|
|
884
906
|
};
|
|
885
907
|
}
|
|
908
|
+
function apiProviderCapabilityDefinition(runtime) {
|
|
909
|
+
const { name, kind } = runtime;
|
|
910
|
+
const forwardsReasoning = kind === "xai-responses";
|
|
911
|
+
const continuity = apiContinuityForKind(kind);
|
|
912
|
+
const continuityTracked = continuity !== "none";
|
|
913
|
+
return {
|
|
914
|
+
providerKind: "api",
|
|
915
|
+
gatewayRequestTools: [`api_${name}_request`],
|
|
916
|
+
summary: `Generic ${kind} API provider "${name}" configured through [providers.${name}]. ` +
|
|
917
|
+
"HTTP request tool only: no local CLI tools, skills, MCP servers, or workspaces.",
|
|
918
|
+
controls: {
|
|
919
|
+
allowlist: {
|
|
920
|
+
supported: false,
|
|
921
|
+
behavior: `api_${name}_request has no CLI tool allow-list input.`,
|
|
922
|
+
},
|
|
923
|
+
denylist: {
|
|
924
|
+
supported: false,
|
|
925
|
+
behavior: `api_${name}_request has no CLI tool deny-list input.`,
|
|
926
|
+
},
|
|
927
|
+
mcpServers: {
|
|
928
|
+
supported: false,
|
|
929
|
+
behavior: "API requests do not configure or expose MCP servers.",
|
|
930
|
+
},
|
|
931
|
+
nativeSkills: {
|
|
932
|
+
supported: false,
|
|
933
|
+
behavior: "API requests do not read local provider skills.",
|
|
934
|
+
},
|
|
935
|
+
reasoningEffort: forwardsReasoning
|
|
936
|
+
? {
|
|
937
|
+
supported: true,
|
|
938
|
+
requestField: "reasoningEffort",
|
|
939
|
+
behavior: "Passed to the xAI Responses API reasoning.effort field.",
|
|
940
|
+
}
|
|
941
|
+
: {
|
|
942
|
+
supported: false,
|
|
943
|
+
requestField: "reasoningEffort",
|
|
944
|
+
behavior: `Accepted by the schema but ignored by the ${kind} adapter.`,
|
|
945
|
+
},
|
|
946
|
+
maxOutputTokens: {
|
|
947
|
+
supported: true,
|
|
948
|
+
requestField: "maxOutputTokens",
|
|
949
|
+
behavior: "Bounds the provider API max output tokens.",
|
|
950
|
+
},
|
|
951
|
+
sampling: {
|
|
952
|
+
supported: true,
|
|
953
|
+
requestField: "temperature/topP",
|
|
954
|
+
behavior: "Sampling controls are passed through to the provider API.",
|
|
955
|
+
},
|
|
956
|
+
timeout: {
|
|
957
|
+
supported: true,
|
|
958
|
+
requestField: "timeoutMs",
|
|
959
|
+
behavior: "Bounds the API HTTP request timeout.",
|
|
960
|
+
},
|
|
961
|
+
session: continuityTracked
|
|
962
|
+
? {
|
|
963
|
+
supported: true,
|
|
964
|
+
requestField: "sessionId/createNewSession",
|
|
965
|
+
behavior: continuity === "server-side-id"
|
|
966
|
+
? "Gateway stores the provider continuation handle (previous_response_id) in session metadata."
|
|
967
|
+
: "Gateway tracks the session (active/owner); stateless adapters resend prior context caller-side without storing conversation content.",
|
|
968
|
+
}
|
|
969
|
+
: {
|
|
970
|
+
supported: false,
|
|
971
|
+
requestField: "sessionId/createNewSession",
|
|
972
|
+
behavior: "This provider kind does not support multi-turn continuity.",
|
|
973
|
+
},
|
|
974
|
+
},
|
|
975
|
+
features: baseFeatures({
|
|
976
|
+
apiProvider: true,
|
|
977
|
+
structuredTextResponses: true,
|
|
978
|
+
sessionContinuity: continuityTracked,
|
|
979
|
+
}),
|
|
980
|
+
unsupportedInputs: [
|
|
981
|
+
{
|
|
982
|
+
input: "localSkills",
|
|
983
|
+
behavior: "not_supported",
|
|
984
|
+
details: `api_${name}_request does not inspect local CLI skills.`,
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
input: "allowedTools/disallowedTools",
|
|
988
|
+
behavior: "not_supported",
|
|
989
|
+
details: "Tool allow/deny controls are CLI-only and are not routed to the API.",
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
input: "workspace/worktree",
|
|
993
|
+
behavior: "not_supported",
|
|
994
|
+
details: "API providers have no local workspace or worktree controls.",
|
|
995
|
+
},
|
|
996
|
+
],
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
function apiProviderModelInfo(runtime) {
|
|
1000
|
+
const list = runtime.models && runtime.models.length > 0 ? runtime.models : [runtime.defaultModel];
|
|
1001
|
+
const models = {};
|
|
1002
|
+
for (const model of list) {
|
|
1003
|
+
models[model] =
|
|
1004
|
+
model === runtime.defaultModel ? "Configured default model" : "Configured allowlisted model";
|
|
1005
|
+
}
|
|
1006
|
+
if (!(runtime.defaultModel in models)) {
|
|
1007
|
+
models[runtime.defaultModel] = "Configured default model (always permitted)";
|
|
1008
|
+
}
|
|
1009
|
+
return {
|
|
1010
|
+
description: `Generic ${runtime.kind} API provider configured through [providers.${runtime.name}].`,
|
|
1011
|
+
models,
|
|
1012
|
+
defaultModel: runtime.defaultModel,
|
|
1013
|
+
defaultModelSource: `[providers.${runtime.name}].default_model`,
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
function apiProviderConfigSurfaces(runtime) {
|
|
1017
|
+
return [
|
|
1018
|
+
{
|
|
1019
|
+
name: `providers.${runtime.name}`,
|
|
1020
|
+
kind: "gateway",
|
|
1021
|
+
present: true,
|
|
1022
|
+
details: `Generic ${runtime.kind} API provider; secret key material is read only from the named environment variable at request time.`,
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
name: "api_key_env",
|
|
1026
|
+
kind: "env",
|
|
1027
|
+
present: runtime.apiKey.length > 0,
|
|
1028
|
+
entries: runtime.apiKeyEnv ? [runtime.apiKeyEnv] : [],
|
|
1029
|
+
details: "Reports only the configured environment variable name and whether a key is resolved (keyless-local providers report false); never the value.",
|
|
1030
|
+
},
|
|
1031
|
+
];
|
|
1032
|
+
}
|
|
1033
|
+
function buildApiProviderToolCapabilities(runtime, query) {
|
|
1034
|
+
const definition = apiProviderCapabilityDefinition(runtime);
|
|
1035
|
+
return {
|
|
1036
|
+
schemaVersion: "provider-tool-capabilities.v2",
|
|
1037
|
+
generatedAt: new Date().toISOString(),
|
|
1038
|
+
cli: runtime.name,
|
|
1039
|
+
providerKind: "api",
|
|
1040
|
+
gatewayRequestTools: [...definition.gatewayRequestTools],
|
|
1041
|
+
gatewayRequestTool: definition.gatewayRequestTools[0],
|
|
1042
|
+
modelInfo: apiProviderModelInfo(runtime),
|
|
1043
|
+
summary: definition.summary,
|
|
1044
|
+
acpContract: {
|
|
1045
|
+
classification: "absent_watchlist",
|
|
1046
|
+
summary: `${runtime.name} is an HTTP API provider with no ACP process transport; watchlist item only.`,
|
|
1047
|
+
},
|
|
1048
|
+
acp: {
|
|
1049
|
+
status: "not_applicable",
|
|
1050
|
+
mediation: "none",
|
|
1051
|
+
targetVersion: `${runtime.kind} API`,
|
|
1052
|
+
entrypoint: null,
|
|
1053
|
+
runtimeEnabled: false,
|
|
1054
|
+
smokeSupported: false,
|
|
1055
|
+
smokeStatus: "unsupported",
|
|
1056
|
+
caveats: ["ACP is a CLI-stdio transport; the HTTP API provider has no ACP surface."],
|
|
1057
|
+
docs: ACP_DOCS_REFERENCE,
|
|
1058
|
+
},
|
|
1059
|
+
controls: cloneControls(definition.controls),
|
|
1060
|
+
features: { ...definition.features },
|
|
1061
|
+
discoveredSkills: [],
|
|
1062
|
+
discoveredProviderTools: [],
|
|
1063
|
+
configSurfaces: apiProviderConfigSurfaces(runtime),
|
|
1064
|
+
unsupportedInputs: query.includeUnsupported ? [...definition.unsupportedInputs] : [],
|
|
1065
|
+
warnings: [],
|
|
1066
|
+
metadata: {
|
|
1067
|
+
deprecatedFields: {
|
|
1068
|
+
gatewayRequestTool: "Use gatewayRequestTools instead.",
|
|
1069
|
+
},
|
|
1070
|
+
cacheTtlMs: CAPABILITY_CACHE_TTL_MS,
|
|
1071
|
+
},
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
886
1074
|
function discoverSkills(cli, warnings, query) {
|
|
887
1075
|
const skills = [];
|
|
888
1076
|
for (const root of skillRoots(cli)) {
|
|
@@ -960,6 +1148,7 @@ function normalizeQuery(queryOrCli) {
|
|
|
960
1148
|
includeUnsupported: query.includeUnsupported ?? true,
|
|
961
1149
|
includePaths: query.includePaths ?? false,
|
|
962
1150
|
refresh: query.refresh ?? false,
|
|
1151
|
+
providersConfig: query.providersConfig,
|
|
963
1152
|
};
|
|
964
1153
|
}
|
|
965
1154
|
function capabilityCacheKey(cli, query) {
|
|
@@ -969,8 +1158,33 @@ function capabilityCacheKey(cli, query) {
|
|
|
969
1158
|
includeProviderTools: query.includeProviderTools,
|
|
970
1159
|
includeUnsupported: query.includeUnsupported,
|
|
971
1160
|
includePaths: query.includePaths,
|
|
1161
|
+
providersConfig: query.providersConfig ? providerConfigCacheKey(query.providersConfig) : null,
|
|
972
1162
|
});
|
|
973
1163
|
}
|
|
1164
|
+
function providerConfigCacheKey(config) {
|
|
1165
|
+
return {
|
|
1166
|
+
xai: config.xai
|
|
1167
|
+
? {
|
|
1168
|
+
apiKeyEnv: config.xai.apiKeyEnv,
|
|
1169
|
+
baseUrl: config.xai.baseUrl,
|
|
1170
|
+
defaultModel: config.xai.defaultModel,
|
|
1171
|
+
}
|
|
1172
|
+
: null,
|
|
1173
|
+
providers: Object.fromEntries(Object.entries(config.providers ?? {})
|
|
1174
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
1175
|
+
.map(([name, provider]) => [
|
|
1176
|
+
name,
|
|
1177
|
+
{
|
|
1178
|
+
kind: provider.kind,
|
|
1179
|
+
apiKeyEnv: provider.apiKeyEnv,
|
|
1180
|
+
baseUrl: provider.baseUrl,
|
|
1181
|
+
defaultModel: provider.defaultModel,
|
|
1182
|
+
models: provider.models ?? null,
|
|
1183
|
+
usageInclude: provider.usageInclude ?? null,
|
|
1184
|
+
},
|
|
1185
|
+
])),
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
974
1188
|
function baseFeatures(overrides) {
|
|
975
1189
|
const names = [
|
|
976
1190
|
"gatewayRequestTools",
|
|
@@ -1012,11 +1226,11 @@ function baseFeatures(overrides) {
|
|
|
1012
1226
|
function cloneControls(controls) {
|
|
1013
1227
|
return Object.fromEntries(Object.entries(controls).map(([name, control]) => [name, { name, ...control }]));
|
|
1014
1228
|
}
|
|
1015
|
-
function getModelInfo(cli,
|
|
1229
|
+
function getModelInfo(cli, query) {
|
|
1016
1230
|
if (cli !== "grok_api") {
|
|
1017
|
-
return getAvailableCliInfo(refresh)[cli];
|
|
1231
|
+
return getAvailableCliInfo(query.refresh)[cli];
|
|
1018
1232
|
}
|
|
1019
|
-
const providers =
|
|
1233
|
+
const providers = providersConfigForQuery(query);
|
|
1020
1234
|
const enabled = isXaiProviderEnabled(providers);
|
|
1021
1235
|
const defaultModel = providers.xai?.defaultModel;
|
|
1022
1236
|
return {
|
|
@@ -1031,7 +1245,7 @@ function getModelInfo(cli, refresh) {
|
|
|
1031
1245
|
}
|
|
1032
1246
|
function discoverConfigSurfaces(cli, query, discoveredSkills) {
|
|
1033
1247
|
if (cli === "grok_api") {
|
|
1034
|
-
const providers =
|
|
1248
|
+
const providers = providersConfigForQuery(query);
|
|
1035
1249
|
return [
|
|
1036
1250
|
{
|
|
1037
1251
|
name: "providers.xai",
|
package/dist/resources.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { ISessionManager } from "./session-manager.js";
|
|
|
2
2
|
import { PerformanceMetrics } from "./metrics.js";
|
|
3
3
|
import { FlightRecorderQuery } from "./flight-recorder.js";
|
|
4
4
|
import { type GlobalCacheStats, type PrefixCacheStats, type SessionCacheStats } from "./cache-stats.js";
|
|
5
|
-
import type
|
|
5
|
+
import { type CacheAwarenessConfig, type ProvidersConfig } from "./config.js";
|
|
6
6
|
export interface ResourceDefinition {
|
|
7
7
|
uri: string;
|
|
8
8
|
name: string;
|
|
@@ -25,8 +25,12 @@ export declare class ResourceProvider {
|
|
|
25
25
|
private performanceMetrics;
|
|
26
26
|
private flightRecorder;
|
|
27
27
|
private cacheAwareness;
|
|
28
|
-
|
|
28
|
+
private providers;
|
|
29
|
+
constructor(sessionManager: ISessionManager, performanceMetrics: PerformanceMetrics, flightRecorder?: FlightRecorderQuery, cacheAwareness?: CacheAwarenessConfig | null, providers?: ProvidersConfig | null);
|
|
29
30
|
getFlightRecorderQuery(): FlightRecorderQuery;
|
|
31
|
+
private apiRuntimes;
|
|
32
|
+
private continuityTrackedApiRuntimes;
|
|
33
|
+
private providerCapabilityIds;
|
|
30
34
|
readCacheStateGlobal(opts?: {
|
|
31
35
|
lastNHours?: number;
|
|
32
36
|
}): GlobalCacheStats;
|
package/dist/resources.js
CHANGED
|
@@ -2,22 +2,36 @@ import { CLI_TYPES, PROVIDER_TYPES } from "./session-manager.js";
|
|
|
2
2
|
import { getRequestContext, principalCanAccess, resolveOwnerPrincipal } from "./request-context.js";
|
|
3
3
|
import { getAvailableCliInfo } from "./model-registry.js";
|
|
4
4
|
import { computeGlobalCacheStats, computePrefixCacheStats, computeSessionCacheStats, computeTtlRemaining, } from "./cache-stats.js";
|
|
5
|
+
import { enabledApiProviders, } from "./config.js";
|
|
6
|
+
import { apiContinuityForKind } from "./api-provider.js";
|
|
7
|
+
import { apiProviderCatalogEntry } from "./api-request.js";
|
|
5
8
|
import { buildProviderSubcommandsCompactCatalog, getCliSubcommandContract, serializeCliSubcommandContract, } from "./upstream-contracts.js";
|
|
6
|
-
import { getOneProviderToolCapabilities, getProviderToolCapabilities, providerCapabilityIds, } from "./provider-tool-capabilities.js";
|
|
9
|
+
import { getOneProviderToolCapabilities, getProviderToolCapabilities, knownProviderCapabilityIds, providerCapabilityIds, } from "./provider-tool-capabilities.js";
|
|
7
10
|
export class ResourceProvider {
|
|
8
11
|
sessionManager;
|
|
9
12
|
performanceMetrics;
|
|
10
13
|
flightRecorder;
|
|
11
14
|
cacheAwareness;
|
|
12
|
-
|
|
15
|
+
providers;
|
|
16
|
+
constructor(sessionManager, performanceMetrics, flightRecorder = { queryRequests: () => [] }, cacheAwareness = null, providers = null) {
|
|
13
17
|
this.sessionManager = sessionManager;
|
|
14
18
|
this.performanceMetrics = performanceMetrics;
|
|
15
19
|
this.flightRecorder = flightRecorder;
|
|
16
20
|
this.cacheAwareness = cacheAwareness;
|
|
21
|
+
this.providers = providers;
|
|
17
22
|
}
|
|
18
23
|
getFlightRecorderQuery() {
|
|
19
24
|
return this.flightRecorder;
|
|
20
25
|
}
|
|
26
|
+
apiRuntimes() {
|
|
27
|
+
return this.providers ? enabledApiProviders(this.providers) : [];
|
|
28
|
+
}
|
|
29
|
+
continuityTrackedApiRuntimes() {
|
|
30
|
+
return this.apiRuntimes().filter(rt => apiContinuityForKind(rt.kind) !== "none");
|
|
31
|
+
}
|
|
32
|
+
providerCapabilityIds() {
|
|
33
|
+
return this.providers ? providerCapabilityIds(this.providers) : knownProviderCapabilityIds();
|
|
34
|
+
}
|
|
21
35
|
readCacheStateGlobal(opts = {}) {
|
|
22
36
|
return computeGlobalCacheStats(this.flightRecorder, opts);
|
|
23
37
|
}
|
|
@@ -101,6 +115,17 @@ export class ResourceProvider {
|
|
|
101
115
|
priority: 0.6,
|
|
102
116
|
},
|
|
103
117
|
},
|
|
118
|
+
...this.continuityTrackedApiRuntimes().map(rt => ({
|
|
119
|
+
uri: `sessions://${rt.name}`,
|
|
120
|
+
name: `${rt.name} Sessions`,
|
|
121
|
+
title: `${rt.name} Sessions`,
|
|
122
|
+
description: `List of ${rt.name} API provider conversation sessions`,
|
|
123
|
+
mimeType: "application/json",
|
|
124
|
+
annotations: {
|
|
125
|
+
audience: ["user", "assistant"],
|
|
126
|
+
priority: 0.6,
|
|
127
|
+
},
|
|
128
|
+
})),
|
|
104
129
|
{
|
|
105
130
|
uri: "models://claude",
|
|
106
131
|
name: "Claude Models",
|
|
@@ -156,6 +181,17 @@ export class ResourceProvider {
|
|
|
156
181
|
priority: 0.8,
|
|
157
182
|
},
|
|
158
183
|
},
|
|
184
|
+
...this.apiRuntimes().map(rt => ({
|
|
185
|
+
uri: `models://${rt.name}`,
|
|
186
|
+
name: `${rt.name} Models`,
|
|
187
|
+
title: `${rt.name} Models & Capabilities`,
|
|
188
|
+
description: `Configured ${rt.name} API provider model catalog`,
|
|
189
|
+
mimeType: "application/json",
|
|
190
|
+
annotations: {
|
|
191
|
+
audience: ["user", "assistant"],
|
|
192
|
+
priority: 0.8,
|
|
193
|
+
},
|
|
194
|
+
})),
|
|
159
195
|
{
|
|
160
196
|
uri: "metrics://performance",
|
|
161
197
|
name: "Performance Metrics",
|
|
@@ -189,7 +225,7 @@ export class ResourceProvider {
|
|
|
189
225
|
priority: 0.8,
|
|
190
226
|
},
|
|
191
227
|
},
|
|
192
|
-
...providerCapabilityIds().map(cli => ({
|
|
228
|
+
...this.providerCapabilityIds().map(cli => ({
|
|
193
229
|
uri: `provider-tools://${cli}`,
|
|
194
230
|
name: `${cli} Tool Capabilities`,
|
|
195
231
|
title: `${cli} Tool Capabilities`,
|
|
@@ -338,6 +374,32 @@ export class ResourceProvider {
|
|
|
338
374
|
text: JSON.stringify(cliInfo.mistral, null, 2),
|
|
339
375
|
};
|
|
340
376
|
}
|
|
377
|
+
if (uri.startsWith("models://")) {
|
|
378
|
+
const runtime = this.apiRuntimes().find(rt => `models://${rt.name}` === uri);
|
|
379
|
+
if (runtime) {
|
|
380
|
+
return {
|
|
381
|
+
uri,
|
|
382
|
+
mimeType: "application/json",
|
|
383
|
+
text: JSON.stringify(apiProviderCatalogEntry(runtime), null, 2),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (uri.startsWith("sessions://")) {
|
|
388
|
+
const runtime = this.continuityTrackedApiRuntimes().find(rt => `sessions://${rt.name}` === uri);
|
|
389
|
+
if (runtime) {
|
|
390
|
+
const sessions = this.ownedSessions(await this.sessionManager.listSessions(runtime.name));
|
|
391
|
+
return {
|
|
392
|
+
uri,
|
|
393
|
+
mimeType: "application/json",
|
|
394
|
+
text: JSON.stringify({
|
|
395
|
+
cli: runtime.name,
|
|
396
|
+
total: sessions.length,
|
|
397
|
+
sessions,
|
|
398
|
+
activeSession: await this.ownedActiveId(runtime.name),
|
|
399
|
+
}, null, 2),
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
}
|
|
341
403
|
if (uri === "metrics://performance") {
|
|
342
404
|
return {
|
|
343
405
|
uri,
|
|
@@ -356,15 +418,17 @@ export class ResourceProvider {
|
|
|
356
418
|
return {
|
|
357
419
|
uri,
|
|
358
420
|
mimeType: "application/json",
|
|
359
|
-
text: JSON.stringify(getProviderToolCapabilities(), null, 2),
|
|
421
|
+
text: JSON.stringify(getProviderToolCapabilities({ providersConfig: this.providers ?? undefined }), null, 2),
|
|
360
422
|
};
|
|
361
423
|
}
|
|
362
|
-
const providerToolsResource = parseProviderToolsUri(uri);
|
|
424
|
+
const providerToolsResource = parseProviderToolsUri(uri, this.providerCapabilityIds());
|
|
363
425
|
if (providerToolsResource) {
|
|
364
426
|
return {
|
|
365
427
|
uri,
|
|
366
428
|
mimeType: "application/json",
|
|
367
|
-
text: JSON.stringify(getOneProviderToolCapabilities(providerToolsResource.provider
|
|
429
|
+
text: JSON.stringify(getOneProviderToolCapabilities(providerToolsResource.provider, {
|
|
430
|
+
providersConfig: this.providers ?? undefined,
|
|
431
|
+
}), null, 2),
|
|
368
432
|
};
|
|
369
433
|
}
|
|
370
434
|
const subcommandResource = parseProviderSubcommandUri(uri);
|
|
@@ -401,7 +465,7 @@ function parseProviderSubcommandUri(uri) {
|
|
|
401
465
|
commandPath: pathParts.map(part => decodeURIComponent(part)).filter(Boolean),
|
|
402
466
|
};
|
|
403
467
|
}
|
|
404
|
-
function parseProviderToolsUri(uri) {
|
|
468
|
+
function parseProviderToolsUri(uri, providerIds) {
|
|
405
469
|
const prefix = uri.startsWith("provider-tools://")
|
|
406
470
|
? "provider-tools://"
|
|
407
471
|
: uri.startsWith("provider_tools://")
|
|
@@ -410,7 +474,7 @@ function parseProviderToolsUri(uri) {
|
|
|
410
474
|
if (!prefix || uri === `${prefix}catalog`)
|
|
411
475
|
return null;
|
|
412
476
|
const provider = uri.slice(prefix.length);
|
|
413
|
-
if (!
|
|
477
|
+
if (!providerIds.includes(provider))
|
|
414
478
|
return null;
|
|
415
479
|
return { provider: provider };
|
|
416
480
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export function normalizeStartedJob(provider, model, snapshot, warning) {
|
|
2
|
+
const inProgress = snapshot.status === "running" || snapshot.status === "queued";
|
|
2
3
|
return {
|
|
3
4
|
provider,
|
|
4
5
|
model,
|
|
5
|
-
status: snapshot.status,
|
|
6
|
-
verdict:
|
|
7
|
-
rationale:
|
|
6
|
+
status: snapshot.status === "queued" ? "running" : snapshot.status,
|
|
7
|
+
verdict: inProgress ? "pending" : null,
|
|
8
|
+
rationale: inProgress ? "Provider job is running asynchronously." : null,
|
|
8
9
|
risks: [],
|
|
9
10
|
rawJobReference: {
|
|
10
11
|
jobId: snapshot.id,
|
|
@@ -34,7 +35,7 @@ export function normalizeJobResult(provider, model, result) {
|
|
|
34
35
|
return {
|
|
35
36
|
provider,
|
|
36
37
|
model,
|
|
37
|
-
status: result.status,
|
|
38
|
+
status: result.status === "queued" ? "running" : result.status,
|
|
38
39
|
verdict: inferVerdict(output, result.status),
|
|
39
40
|
rationale: output ? excerpt(output, 1800) : error,
|
|
40
41
|
risks: extractRisks(output, error),
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-cli-gateway",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "llm-cli-gateway",
|
|
9
|
-
"version": "2.12.
|
|
9
|
+
"version": "2.12.2",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -451,9 +451,9 @@
|
|
|
451
451
|
"license": "MIT"
|
|
452
452
|
},
|
|
453
453
|
"node_modules/fast-uri": {
|
|
454
|
-
"version": "3.1.
|
|
455
|
-
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.
|
|
456
|
-
"integrity": "sha512-
|
|
454
|
+
"version": "3.1.3",
|
|
455
|
+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz",
|
|
456
|
+
"integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==",
|
|
457
457
|
"funding": [
|
|
458
458
|
{
|
|
459
459
|
"type": "github",
|