@jmanuelcorral/openteam 0.24.1 → 0.26.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/README.es.md +42 -10
- package/README.md +37 -8
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/cli/setupAdapters.d.ts.map +1 -1
- package/dist/cli.js +1200 -384
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +20 -15
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/config/schema.d.ts +101 -7
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/console/assets.d.ts.map +1 -1
- package/dist/console/conversation.d.ts +5 -1
- package/dist/console/conversation.d.ts.map +1 -1
- package/dist/console/credentials.d.ts +4 -0
- package/dist/console/credentials.d.ts.map +1 -0
- package/dist/console/inspector.d.ts +1 -1
- package/dist/console/inspector.d.ts.map +1 -1
- package/dist/console/refresh.d.ts +1 -1
- package/dist/console/refresh.d.ts.map +1 -1
- package/dist/console/render.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +657 -128
- package/dist/local/lemonadeResidency.d.ts +2 -14
- package/dist/local/lemonadeResidency.d.ts.map +1 -1
- package/dist/local/llamaSwap.d.ts +5 -0
- package/dist/local/llamaSwap.d.ts.map +1 -0
- package/dist/local/llamaSwapRequestGuard.d.ts +11 -0
- package/dist/local/llamaSwapRequestGuard.d.ts.map +1 -0
- package/dist/local/llamaSwapResidency.d.ts +9 -0
- package/dist/local/llamaSwapResidency.d.ts.map +1 -0
- package/dist/local/modelResidency.d.ts +1 -0
- package/dist/local/modelResidency.d.ts.map +1 -1
- package/dist/local/registry.d.ts.map +1 -1
- package/dist/local/residency.d.ts +16 -0
- package/dist/local/residency.d.ts.map +1 -0
- package/dist/local/types.d.ts +10 -2
- package/dist/local/types.d.ts.map +1 -1
- package/dist/messages/consoleDetail.d.ts +8 -5
- package/dist/messages/consoleDetail.d.ts.map +1 -1
- package/dist/messages/executionSetup.d.ts +22 -3
- package/dist/messages/executionSetup.d.ts.map +1 -1
- package/dist/messages/memoryRuntime.d.ts +6 -0
- package/dist/messages/memoryRuntime.d.ts.map +1 -0
- package/dist/messages/memoryTool.d.ts +1 -1
- package/dist/messages/memoryTool.d.ts.map +1 -1
- package/dist/messages/modelResidency.d.ts +20 -2
- package/dist/messages/modelResidency.d.ts.map +1 -1
- package/dist/plugin/availability.d.ts.map +1 -1
- package/dist/plugin/memoryTool.d.ts.map +1 -1
- package/dist/plugin/modelResidency.d.ts.map +1 -1
- package/dist/storage/index/memoryRuntime.d.ts.map +1 -1
- package/dist/web/conversationRoute.d.ts +2 -2
- package/dist/web/conversationRoute.d.ts.map +1 -1
- package/dist/web/server.d.ts +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -786,6 +786,9 @@ function migrateConfig(raw) {
|
|
|
786
786
|
var consoleDetailMessages = {
|
|
787
787
|
follow: "Follow new activity",
|
|
788
788
|
metadataOnly: "Lifecycle and telemetry stay metadata-only.",
|
|
789
|
+
logsDescription: "Current recorded conversations load automatically. Lifecycle and telemetry remain metadata-only; credentials are masked.",
|
|
790
|
+
credentialMasked: "[credential masked]",
|
|
791
|
+
offscreen: "Messages load automatically when this conversation is visible.",
|
|
789
792
|
filter: "Filter sessions",
|
|
790
793
|
incoming: "New activity available — show updates",
|
|
791
794
|
refreshError: "Live updates unavailable; retrying.",
|
|
@@ -806,7 +809,7 @@ var consoleDetailMessages = {
|
|
|
806
809
|
partialMetadata: "Some current session titles are unavailable or outside the bounded batch; fallback labels remain.",
|
|
807
810
|
rootCurrent: "Current whole orchestrator session; may contain multiple batches. Not a historical or batch-only transcript.",
|
|
808
811
|
recovered: "Read-only association verified from current opencode history; not an immutable lifecycle event.",
|
|
809
|
-
rootUnlinked: "Orchestrator session not recorded.
|
|
812
|
+
rootUnlinked: "Orchestrator session not recorded. A bounded, read-only relationship search is attempted when visible.",
|
|
810
813
|
rootUnavailable: "Orchestrator session unavailable: no unique, verifiable relationship was found in local history.",
|
|
811
814
|
rootAmbiguous: "Orchestrator session unavailable: conflicting or copied relationships are ambiguous.",
|
|
812
815
|
searchIncomplete: "Orchestrator association search incomplete or exceeded its bounded budget. No session was guessed.",
|
|
@@ -819,9 +822,9 @@ var consoleDetailMessages = {
|
|
|
819
822
|
arguments: "Arguments",
|
|
820
823
|
result: "Result",
|
|
821
824
|
loading: "Loading local conversation…",
|
|
822
|
-
current: "Present-day session, not a timeline reconstruction
|
|
823
|
-
historical: "Historical cursor: conversation content is hidden to avoid showing future mutable text. Return to live
|
|
824
|
-
disabled: "Content is disabled
|
|
825
|
+
current: "Present-day whole session, not a timeline reconstruction or per-attempt transcript. Visible messages update automatically while live.",
|
|
826
|
+
historical: "Historical cursor: conversation content is hidden to avoid showing future mutable text. Return to live to read current messages.",
|
|
827
|
+
disabled: "Content is disabled by console.sessionHistory.contentEnabled: false. Lifecycle and telemetry remain metadata-only.",
|
|
825
828
|
unavailable: "Conversation unavailable. Start an operator-owned local opencode serve against the same workspace and user history, configure console.sessionHistory.endpoint, then retry. No inference was requested.",
|
|
826
829
|
empty: "No readable user messages, assistant output or tool calls remain in this session.",
|
|
827
830
|
invalid: "This attempt has no recorded session in the selected run, or its history is incomplete.",
|
|
@@ -831,7 +834,7 @@ var consoleDetailMessages = {
|
|
|
831
834
|
invalidEndpoint: "Expected a loopback HTTP origin without credentials, path, query or fragment.",
|
|
832
835
|
readFailed: "Local session history could not be read.",
|
|
833
836
|
oversized: "Conversation exceeds the local size limit (4 MiB). No content was loaded.",
|
|
834
|
-
truncated: "Conversation display is truncated by local safety limits
|
|
837
|
+
truncated: "Conversation display is truncated by local safety limits. The newest bounded message window is shown; older messages or oversized fields may be omitted, not empty history.",
|
|
835
838
|
truncatedMarker: `
|
|
836
839
|
[truncated]`,
|
|
837
840
|
terminalGap: "Live collection was interrupted; events during the gap are unavailable. This is not complete session history.",
|
|
@@ -908,7 +911,7 @@ var ConsoleConfigSchema = z3.object({
|
|
|
908
911
|
openBrowser: z3.boolean().default(false),
|
|
909
912
|
remoteStorage: z3.boolean().default(false),
|
|
910
913
|
sessionHistory: z3.object({
|
|
911
|
-
contentEnabled: z3.boolean().default(
|
|
914
|
+
contentEnabled: z3.boolean().default(true),
|
|
912
915
|
endpoint: z3.string().refine(isLocalHistoryEndpoint, consoleDetailMessages.invalidEndpoint).optional()
|
|
913
916
|
}).strict().optional(),
|
|
914
917
|
terminal: z3.object({
|
|
@@ -1046,7 +1049,8 @@ var LocalRuntimeKindSchema = z3.enum([
|
|
|
1046
1049
|
"ollama",
|
|
1047
1050
|
"lmstudio",
|
|
1048
1051
|
"foundry-local",
|
|
1049
|
-
"lemonade"
|
|
1052
|
+
"lemonade",
|
|
1053
|
+
"llama-swap"
|
|
1050
1054
|
]);
|
|
1051
1055
|
var LocalRuntimeSchema = z3.object({
|
|
1052
1056
|
id: z3.string().min(1),
|
|
@@ -1066,15 +1070,25 @@ var LocalRuntimeSchema = z3.object({
|
|
|
1066
1070
|
ctx.addIssue({
|
|
1067
1071
|
code: z3.ZodIssueCode.custom,
|
|
1068
1072
|
path: ["kind"],
|
|
1069
|
-
message: `local runtime "${runtime.id}" has no resolvable kind: add "kind" ` + "(one of ollama, lmstudio, foundry-local, lemonade), since the id is
|
|
1073
|
+
message: `local runtime "${runtime.id}" has no resolvable kind: add "kind" ` + "(one of ollama, lmstudio, foundry-local, lemonade, llama-swap), " + "since the id is not itself a runtime kind."
|
|
1070
1074
|
});
|
|
1071
1075
|
}
|
|
1076
|
+
}).transform((runtime) => {
|
|
1077
|
+
const resolvedKind = runtime.kind ?? runtime.id;
|
|
1078
|
+
if (resolvedKind !== "llama-swap" || runtime.maxConcurrency !== undefined) {
|
|
1079
|
+
return runtime;
|
|
1080
|
+
}
|
|
1081
|
+
return { ...runtime, maxConcurrency: 1 };
|
|
1072
1082
|
});
|
|
1073
1083
|
function localRuntimeKind(runtime) {
|
|
1074
1084
|
return runtime.kind ?? runtime.id;
|
|
1075
1085
|
}
|
|
1076
1086
|
function effectiveMaxConcurrency(runtime) {
|
|
1077
|
-
|
|
1087
|
+
if (runtime.maxConcurrency !== undefined) {
|
|
1088
|
+
return runtime.maxConcurrency;
|
|
1089
|
+
}
|
|
1090
|
+
const kind = runtime.kind ?? (runtime.id !== undefined && LocalRuntimeKindSchema.safeParse(runtime.id).success ? runtime.id : undefined);
|
|
1091
|
+
return kind === "llama-swap" ? 1 : DEFAULT_LOCAL_MAX_CONCURRENCY;
|
|
1078
1092
|
}
|
|
1079
1093
|
var MemoryScopeSchema = z3.enum(["project", "user"]);
|
|
1080
1094
|
var MemoryExtractionModeSchema = z3.enum([
|
|
@@ -5743,7 +5757,7 @@ import { z as z15 } from "zod";
|
|
|
5743
5757
|
// package.json
|
|
5744
5758
|
var package_default = {
|
|
5745
5759
|
name: "@jmanuelcorral/openteam",
|
|
5746
|
-
version: "0.
|
|
5760
|
+
version: "0.26.0",
|
|
5747
5761
|
packageManager: "bun@1.3.14",
|
|
5748
5762
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
5749
5763
|
license: "MIT",
|
|
@@ -6100,6 +6114,23 @@ var executionSetupMessages = {
|
|
|
6100
6114
|
`),
|
|
6101
6115
|
localOnlyTitle: "Local execution",
|
|
6102
6116
|
localRequiredError: "local execution requires an enabled local runtime",
|
|
6117
|
+
llamaSwap: {
|
|
6118
|
+
label: "llama-swap",
|
|
6119
|
+
noLoadedModels: "llama-swap has no canonical models verified as ready with no active routing profile. Keep the intended model ready through the operator's existing runtime controls, then rerun setup; manual IDs cannot bypass admission.",
|
|
6120
|
+
modelNotLoaded: (model) => `llama-swap model "${model}" is not positively verified as canonical and ready without an active routing profile. No substitute was selected.`,
|
|
6121
|
+
probeRequired: "llama-swap setup requires a fresh read-only residency probe before writing configuration. Manual model IDs cannot bypass this requirement.",
|
|
6122
|
+
probeFailed: "llama-swap readiness could not be verified. Check the configured /v1/models catalog and origin /running and /api/profiles endpoints; authenticated runtimes are not supported.",
|
|
6123
|
+
endpointMismatch: "llama-swap endpoint/provider mapping differs from the selected runtime. Reconcile the configured origin or /v1 URL and provider; no configuration was written.",
|
|
6124
|
+
modelIdentityUnknown: (model) => `llama-swap model "${model}" has no usable registered physical identity. Fix its model declaration; setup will not guess an alias.`,
|
|
6125
|
+
declaredLimits: "llama-swap context and output limits are operator-declared metadata, not measured per-slot capacities. Missing output metadata uses openteam's client policy default, not a guessed model cap. Unknown context remains 0 and disables automatic compaction. Tool support remains unknown without evidence.",
|
|
6126
|
+
declaredLimitsTitle: "Declared llama-swap limits",
|
|
6127
|
+
outputReduction: (model, previous, ceiling) => `${model}: reducing limit.output from ${previous} to ${ceiling} to respect the declared runtime ceiling. Smaller operator limits are preserved.`,
|
|
6128
|
+
outputReductionTitle: "Declared output ceiling",
|
|
6129
|
+
outputChanged: (model, ceiling) => `${model}: fresh runtime metadata declares an output ceiling of ${ceiling} below the prepared configuration. Rerun setup to review the updated limit; no configuration was written.`
|
|
6130
|
+
},
|
|
6131
|
+
residencyV2Title: "Resident runtime transport compatibility",
|
|
6132
|
+
residencyV2Restriction: (providers) => `Project policies disable opencode's separate native/core V2 transport for resident-only providers: ${providers.join(", ")}. Guarded V1 provider transport remains supported; this does not ban the public SDK v2 client library. Higher-precedence policies can override project restrictions. Readiness preflight is not an atomic no-autoload guarantee.`,
|
|
6133
|
+
retainedResidencyProviderUnprotected: (providerID) => `Cannot safely retain resident-only provider "${providerID}": the effective configuration must retain its matching runtime, disabled when deselected. Reconcile the runtime/provider configuration; no configuration was written.`,
|
|
6103
6134
|
lemonadeDetectedHint: (loaded, advertised) => `detected - ${loaded} confirmed loaded of ${advertised} advertised text model(s)`,
|
|
6104
6135
|
lemonadeNoLoadedModels: "Lemonade has no text models verified as loaded and ready. Keep the intended model active in Lemonade and rerun setup; inactive or unknown models cannot be selected or entered manually.",
|
|
6105
6136
|
lemonadeModelNotLoaded: (model) => `Lemonade model "${model}" is not positively verified as loaded and ready. Keep that exact text model active and rerun setup; no substitute was selected and no implicit loading is allowed.`,
|
|
@@ -6114,11 +6145,11 @@ var executionSetupMessages = {
|
|
|
6114
6145
|
lemonadeV2InvalidPolicies: "Cannot safely preserve experimental.policies: experimental must be an object and policies must be an array of provider.use statements with a string resource and allow/deny effect. Fix the project configuration before rerunning setup.",
|
|
6115
6146
|
lemonadeV2Title: "Lemonade transport compatibility",
|
|
6116
6147
|
lemonadeV2Restriction: (providers) => `Project policies disable native V2 Lemonade access for: ${providers.join(", ")}. Ordinary guarded V1 configuration remains supported; V2 is not an openteam-hook execution path. Higher-precedence or global policies can override this project restriction; it is not a server-atomic no-autoload guarantee.`,
|
|
6117
|
-
lemonadeInventory: (instanceID, providerID, models) => {
|
|
6148
|
+
lemonadeInventory: (instanceID, providerID, models, runtime = "Lemonade") => {
|
|
6118
6149
|
const inventory = models.map((model) => `${model.modelID} (${model.loaded === true ? "loaded" : model.loaded === false ? "inactive" : "residency unknown"})`).join(", ");
|
|
6119
|
-
return
|
|
6150
|
+
return `${runtime} inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
|
|
6120
6151
|
},
|
|
6121
|
-
lemonadeAgentResidency: (agent, model, state) =>
|
|
6152
|
+
lemonadeAgentResidency: (agent, model, state, runtime = "Lemonade") => `${runtime} readiness: ${agent} (${model}): ${state === "not-loaded" ? "inactive (not ready)" : "residency unknown"}; advertised inventory is not loaded readiness. Keep this exact model active and verify residency before use; requests without verified readiness are blocked.`,
|
|
6122
6153
|
mixedPrimaryQuestion: "Primary coordinator model",
|
|
6123
6154
|
mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
|
|
6124
6155
|
mixedPrimaryFrontier: "Choose a frontier model",
|
|
@@ -6222,6 +6253,8 @@ var executionPolicyMessages = {
|
|
|
6222
6253
|
primaryLocalMismatchRemedy: (sourceFile) => ` remedy: re-run \`openteam setup\` to regenerate ${sourceFile} and opencode.json from the same primary policy, then re-run \`openteam doctor\`.`
|
|
6223
6254
|
};
|
|
6224
6255
|
var doctorMessages = {
|
|
6256
|
+
defaultRuntimeSlots: (slots) => ` · ${slots} slot(s) (default)`,
|
|
6257
|
+
llamaSwapConcurrency: " llama-swap does not report per-model slots; openteam uses the configured runtime-wide concurrency limit. No per-model capacity was inferred.",
|
|
6225
6258
|
localModelLimits: {
|
|
6226
6259
|
section: " local model limits:",
|
|
6227
6260
|
healthy: " ✓ enabled local provider models declare valid output and context limits in opencode.json.",
|
|
@@ -6238,7 +6271,7 @@ var doctorMessages = {
|
|
|
6238
6271
|
invalidInput: "invalid limit.input (expected a positive integer token count)",
|
|
6239
6272
|
outputExceedsContext: "limit.output is greater than or equal to limit.context, so the configured context leaves no usable input window",
|
|
6240
6273
|
outputExceedsInput: "limit.input is less than or equal to the reserved output budget, so compaction would have no usable input threshold",
|
|
6241
|
-
outputRemedy: " remedy: re-run `openteam setup` to write openteam's 8 192
|
|
6274
|
+
outputRemedy: " remedy: re-run `openteam setup` to write openteam's local output policy (at most 8 192 tokens, narrowed by declared runtime ceilings and smaller context/input budgets), then re-run `openteam doctor`.",
|
|
6242
6275
|
unconfiguredLimitRemedy: " remedy: the optional limit block may remain absent; to configure explicit limits, manually add a complete limit object in opencode.json with positive output and non-negative context (0 means unknown), because setup fills an absent limit block only for models the runtime currently discovers. Then re-run `openteam doctor`.",
|
|
6243
6276
|
detectedContextRemedy: " remedy: re-run `openteam setup` while the runtime is reachable to copy the detected usable context budget, then re-run `openteam doctor`.",
|
|
6244
6277
|
unknownContextRemedy: " remedy: re-run `openteam setup` to write the required context:0 sentinel; automatic compaction remains disabled until a positive context is configured.",
|
|
@@ -9950,14 +9983,12 @@ function ensureFoundryV1BaseURL(endpoint) {
|
|
|
9950
9983
|
}
|
|
9951
9984
|
}
|
|
9952
9985
|
|
|
9953
|
-
// src/local/lemonadeResidency.ts
|
|
9954
|
-
import { z as z19 } from "zod";
|
|
9955
|
-
|
|
9956
9986
|
// src/messages/modelResidency.ts
|
|
9957
9987
|
var reasons = {
|
|
9958
9988
|
unknown: "fresh residency metadata is unavailable, malformed, or ambiguous",
|
|
9959
9989
|
inactive: "the requested model is not verified as resident and serving",
|
|
9960
9990
|
identity: "the requested model identity can be rewritten or is ambiguous",
|
|
9991
|
+
"authentication-unsupported": "authentication is required but unsupported by this integration",
|
|
9961
9992
|
destination: "the request destination does not match its configured runtime",
|
|
9962
9993
|
transport: "this provider execution path cannot enforce the residency guard",
|
|
9963
9994
|
request: "this is not a supported, explicit model inference request",
|
|
@@ -9966,22 +9997,328 @@ var reasons = {
|
|
|
9966
9997
|
configuration: "the residency guard configuration is invalid"
|
|
9967
9998
|
};
|
|
9968
9999
|
var modelResidencyMessages = {
|
|
9969
|
-
blocked: (reason) => `[openteam]
|
|
9970
|
-
providerDisabled: (providerID) => `[openteam]
|
|
9971
|
-
extractionRuntimeUnavailable: "[openteam] Memory extraction requires one enabled local runtime matching the configured extraction provider."
|
|
10000
|
+
blocked: (reason, runtimeLabel = "Lemonade", detail) => `[openteam] ${runtimeLabel} model request blocked: ${reasons[reason]}${detail === undefined ? "" : ` (${detail})`}.`,
|
|
10001
|
+
providerDisabled: (providerID, runtimeLabel = "Lemonade") => `[openteam] ${runtimeLabel} provider "${providerID}" is disabled because its configured transport or runtime mapping cannot enforce loaded-only requests.`,
|
|
10002
|
+
extractionRuntimeUnavailable: "[openteam] Memory extraction requires one enabled local runtime matching the configured extraction provider.",
|
|
10003
|
+
extractionRuntimeUnavailableFor: (runtimeLabel) => `[openteam] Memory extraction requires one enabled ${runtimeLabel} local runtime matching the configured extraction provider.`
|
|
10004
|
+
};
|
|
10005
|
+
var llamaSwapResidencyMessages = {
|
|
10006
|
+
catalogModelDetail: (id, detail) => `catalog model "${id}" ${detail}`,
|
|
10007
|
+
invalidCatalogField: (field) => `declares an invalid ${field}`,
|
|
10008
|
+
catalogEntryMustExposeStringId: "catalog entries must expose a string id",
|
|
10009
|
+
catalogModelIdsMustBeNonEmptyTrimmedStrings: "catalog model ids must be non-empty, trimmed strings",
|
|
10010
|
+
expectedDataArray: (path2) => `GET ${path2} must return an object with a data array`,
|
|
10011
|
+
duplicateCanonicalModelId: (modelID, path2) => `duplicate canonical model id "${modelID}" in ${path2}`,
|
|
10012
|
+
httpFailure: (path2, status) => `GET ${path2} failed with HTTP ${status}`,
|
|
10013
|
+
unverifiableResponse: (path2) => `GET ${path2} failed before a verifiable response`,
|
|
10014
|
+
expectedProfilesArray: (path2) => `GET ${path2} must return an object with a profiles array`,
|
|
10015
|
+
activeProfileRewrite: (profile) => `active profile "${profile}" can rewrite canonical model routing`,
|
|
10016
|
+
invalidActiveProfileValue: (path2) => `GET ${path2} reported an invalid active profile value`,
|
|
10017
|
+
expectedRunningArray: (path2) => `GET ${path2} must return an object with a running array`,
|
|
10018
|
+
malformedRunningEvidence: (path2) => `GET ${path2} returned malformed model/state evidence`,
|
|
10019
|
+
duplicateRunningEvidence: (path2, modelID) => `GET ${path2} returned duplicate evidence for "${modelID}"`
|
|
9972
10020
|
};
|
|
9973
10021
|
|
|
9974
|
-
// src/local/
|
|
10022
|
+
// src/local/residency.ts
|
|
9975
10023
|
class ModelResidencyError extends Error {
|
|
9976
10024
|
code;
|
|
9977
10025
|
statusCode = 400;
|
|
9978
10026
|
isRetryable = false;
|
|
9979
|
-
constructor(code) {
|
|
9980
|
-
super(modelResidencyMessages.blocked(code));
|
|
10027
|
+
constructor(code, runtimeLabel = "Lemonade", detail) {
|
|
10028
|
+
super(modelResidencyMessages.blocked(code, runtimeLabel, detail));
|
|
9981
10029
|
this.code = code;
|
|
9982
10030
|
this.name = "ModelResidencyError";
|
|
9983
10031
|
}
|
|
9984
10032
|
}
|
|
10033
|
+
async function withResidencyDeadline(operation, options) {
|
|
10034
|
+
const timeoutMs = options.timeoutMs ?? 5000;
|
|
10035
|
+
const runtimeLabel = options.runtimeLabel;
|
|
10036
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
10037
|
+
throw new ModelResidencyError("configuration", runtimeLabel);
|
|
10038
|
+
}
|
|
10039
|
+
const controller = new AbortController;
|
|
10040
|
+
const cancel = () => controller.abort(new ModelResidencyError("cancelled", runtimeLabel));
|
|
10041
|
+
if (options.signal?.aborted)
|
|
10042
|
+
throw new ModelResidencyError("cancelled", runtimeLabel);
|
|
10043
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
10044
|
+
const schedule = options.scheduleTimeout ?? ((callback, ms) => {
|
|
10045
|
+
const timer = setTimeout(callback, ms);
|
|
10046
|
+
return () => clearTimeout(timer);
|
|
10047
|
+
});
|
|
10048
|
+
let onAbort = () => {};
|
|
10049
|
+
const aborted = new Promise((_, reject) => {
|
|
10050
|
+
onAbort = () => reject(controller.signal.reason);
|
|
10051
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
10052
|
+
});
|
|
10053
|
+
const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout", runtimeLabel)), timeoutMs);
|
|
10054
|
+
try {
|
|
10055
|
+
controller.signal.throwIfAborted();
|
|
10056
|
+
return await Promise.race([operation(controller.signal), aborted]);
|
|
10057
|
+
} finally {
|
|
10058
|
+
clearTimer();
|
|
10059
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
10060
|
+
controller.signal.removeEventListener("abort", onAbort);
|
|
10061
|
+
controller.abort();
|
|
10062
|
+
}
|
|
10063
|
+
}
|
|
10064
|
+
|
|
10065
|
+
// src/local/llamaSwapResidency.ts
|
|
10066
|
+
function isObject2(value) {
|
|
10067
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10068
|
+
}
|
|
10069
|
+
function readPositiveSafeInteger(value) {
|
|
10070
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
10071
|
+
}
|
|
10072
|
+
function readSupportsTools2(model) {
|
|
10073
|
+
const direct = readBoolean2(model, [
|
|
10074
|
+
"tool_call",
|
|
10075
|
+
"tool_calls",
|
|
10076
|
+
"toolCalling",
|
|
10077
|
+
"supportsToolCalling",
|
|
10078
|
+
"supports_tools",
|
|
10079
|
+
"supportsTools"
|
|
10080
|
+
]);
|
|
10081
|
+
if (direct !== undefined) {
|
|
10082
|
+
return direct;
|
|
10083
|
+
}
|
|
10084
|
+
const capabilities = readCapabilityBoolean2(model.capabilities);
|
|
10085
|
+
if (capabilities !== undefined) {
|
|
10086
|
+
return capabilities;
|
|
10087
|
+
}
|
|
10088
|
+
const features = readCapabilityBoolean2(model.features);
|
|
10089
|
+
if (features !== undefined) {
|
|
10090
|
+
return features;
|
|
10091
|
+
}
|
|
10092
|
+
const labels = readCapabilityBoolean2(model.labels);
|
|
10093
|
+
if (labels !== undefined) {
|
|
10094
|
+
return labels;
|
|
10095
|
+
}
|
|
10096
|
+
return "unknown";
|
|
10097
|
+
}
|
|
10098
|
+
function readCapabilityBoolean2(value) {
|
|
10099
|
+
if (Array.isArray(value)) {
|
|
10100
|
+
if (value.some((entry) => typeof entry === "string" && ["tools", "tool_call", "tool-calling", "function_calling"].includes(entry))) {
|
|
10101
|
+
return true;
|
|
10102
|
+
}
|
|
10103
|
+
return;
|
|
10104
|
+
}
|
|
10105
|
+
if (!isObject2(value)) {
|
|
10106
|
+
return;
|
|
10107
|
+
}
|
|
10108
|
+
return readBoolean2(value, [
|
|
10109
|
+
"tools",
|
|
10110
|
+
"tool_call",
|
|
10111
|
+
"tool_calls",
|
|
10112
|
+
"toolCalling",
|
|
10113
|
+
"function_calling",
|
|
10114
|
+
"supportsToolCalling"
|
|
10115
|
+
]);
|
|
10116
|
+
}
|
|
10117
|
+
function readBoolean2(value, keys) {
|
|
10118
|
+
for (const key of keys) {
|
|
10119
|
+
if (typeof value[key] === "boolean") {
|
|
10120
|
+
return value[key];
|
|
10121
|
+
}
|
|
10122
|
+
}
|
|
10123
|
+
return;
|
|
10124
|
+
}
|
|
10125
|
+
function modelDetail(id, detail) {
|
|
10126
|
+
return llamaSwapResidencyMessages.catalogModelDetail(id, detail);
|
|
10127
|
+
}
|
|
10128
|
+
function llamaSwapBaseURL(value) {
|
|
10129
|
+
let url;
|
|
10130
|
+
try {
|
|
10131
|
+
url = new URL(value);
|
|
10132
|
+
} catch {
|
|
10133
|
+
throw new ModelResidencyError("destination", "llama-swap");
|
|
10134
|
+
}
|
|
10135
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "") {
|
|
10136
|
+
throw new ModelResidencyError("destination", "llama-swap");
|
|
10137
|
+
}
|
|
10138
|
+
if (url.pathname === "/" || url.pathname === "") {
|
|
10139
|
+
return `${url.origin}/v1`;
|
|
10140
|
+
}
|
|
10141
|
+
if (url.pathname === "/v1" || url.pathname === "/v1/") {
|
|
10142
|
+
return `${url.origin}/v1`;
|
|
10143
|
+
}
|
|
10144
|
+
throw new ModelResidencyError("destination", "llama-swap");
|
|
10145
|
+
}
|
|
10146
|
+
function parseCanonicalType(entry, id) {
|
|
10147
|
+
if (!isObject2(entry.meta) || !isObject2(entry.meta.llamaswap)) {
|
|
10148
|
+
return;
|
|
10149
|
+
}
|
|
10150
|
+
const type = entry.meta.llamaswap.type;
|
|
10151
|
+
if (type === undefined) {
|
|
10152
|
+
return;
|
|
10153
|
+
}
|
|
10154
|
+
if (typeof type !== "string" || type.length === 0 || type !== type.trim()) {
|
|
10155
|
+
throw new ModelResidencyError("unknown", "llama-swap", modelDetail(id, llamaSwapResidencyMessages.invalidCatalogField("meta.llamaswap.type")));
|
|
10156
|
+
}
|
|
10157
|
+
return type === "model" ? "model" : undefined;
|
|
10158
|
+
}
|
|
10159
|
+
function readContextCandidates(entry) {
|
|
10160
|
+
const values = [
|
|
10161
|
+
readPositiveSafeInteger(entry.context_length),
|
|
10162
|
+
readPositiveSafeInteger(entry.context_window),
|
|
10163
|
+
isObject2(entry.meta) ? readPositiveSafeInteger(entry.meta.n_ctx) : undefined
|
|
10164
|
+
];
|
|
10165
|
+
return values.filter((value) => value !== undefined);
|
|
10166
|
+
}
|
|
10167
|
+
function readDeclaredMaxOutput(entry, id) {
|
|
10168
|
+
if (!isObject2(entry.meta) || !isObject2(entry.meta.llamaswap)) {
|
|
10169
|
+
return;
|
|
10170
|
+
}
|
|
10171
|
+
if (!Object.hasOwn(entry.meta.llamaswap, "max_output_tokens")) {
|
|
10172
|
+
return;
|
|
10173
|
+
}
|
|
10174
|
+
const maxOutputTokens = readPositiveSafeInteger(entry.meta.llamaswap.max_output_tokens);
|
|
10175
|
+
if (maxOutputTokens === undefined) {
|
|
10176
|
+
throw new ModelResidencyError("unknown", "llama-swap", modelDetail(id, llamaSwapResidencyMessages.invalidCatalogField("meta.llamaswap.max_output_tokens")));
|
|
10177
|
+
}
|
|
10178
|
+
return maxOutputTokens;
|
|
10179
|
+
}
|
|
10180
|
+
function parseCatalogModel(value) {
|
|
10181
|
+
if (!isObject2(value) || typeof value.id !== "string") {
|
|
10182
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.catalogEntryMustExposeStringId);
|
|
10183
|
+
}
|
|
10184
|
+
const id = value.id;
|
|
10185
|
+
if (id.length === 0 || id !== id.trim()) {
|
|
10186
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.catalogModelIdsMustBeNonEmptyTrimmedStrings);
|
|
10187
|
+
}
|
|
10188
|
+
if (parseCanonicalType(value, id) !== "model") {
|
|
10189
|
+
return;
|
|
10190
|
+
}
|
|
10191
|
+
const model = {
|
|
10192
|
+
modelID: id,
|
|
10193
|
+
supportsTools: readSupportsTools2(value)
|
|
10194
|
+
};
|
|
10195
|
+
const contexts = readContextCandidates(value);
|
|
10196
|
+
if (contexts.length > 0) {
|
|
10197
|
+
model.contextWindow = Math.min(...contexts);
|
|
10198
|
+
model.contextWindowProvenance = "declared";
|
|
10199
|
+
}
|
|
10200
|
+
const maxOutputTokens = readDeclaredMaxOutput(value, id);
|
|
10201
|
+
if (maxOutputTokens !== undefined) {
|
|
10202
|
+
model.maxOutputTokens = maxOutputTokens;
|
|
10203
|
+
model.maxOutputTokensProvenance = "declared";
|
|
10204
|
+
}
|
|
10205
|
+
return model;
|
|
10206
|
+
}
|
|
10207
|
+
function parseCatalog(payload) {
|
|
10208
|
+
if (!isObject2(payload) || !Array.isArray(payload.data)) {
|
|
10209
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.expectedDataArray("/v1/models"));
|
|
10210
|
+
}
|
|
10211
|
+
const seen = new Set;
|
|
10212
|
+
const models = [];
|
|
10213
|
+
for (const entry of payload.data) {
|
|
10214
|
+
const model = parseCatalogModel(entry);
|
|
10215
|
+
if (model === undefined) {
|
|
10216
|
+
continue;
|
|
10217
|
+
}
|
|
10218
|
+
if (seen.has(model.modelID)) {
|
|
10219
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.duplicateCanonicalModelId(model.modelID, "/v1/models"));
|
|
10220
|
+
}
|
|
10221
|
+
seen.add(model.modelID);
|
|
10222
|
+
models.push(model);
|
|
10223
|
+
}
|
|
10224
|
+
return models;
|
|
10225
|
+
}
|
|
10226
|
+
async function metadata(url, fetch, signal, headers) {
|
|
10227
|
+
signal.throwIfAborted();
|
|
10228
|
+
try {
|
|
10229
|
+
const response = await fetch(url, {
|
|
10230
|
+
method: "GET",
|
|
10231
|
+
headers,
|
|
10232
|
+
signal,
|
|
10233
|
+
redirect: "error",
|
|
10234
|
+
cache: "no-store"
|
|
10235
|
+
});
|
|
10236
|
+
signal.throwIfAborted();
|
|
10237
|
+
if (response.status === 401 || response.status === 403) {
|
|
10238
|
+
throw new ModelResidencyError("authentication-unsupported", "llama-swap");
|
|
10239
|
+
}
|
|
10240
|
+
if (!response.ok || response.redirected || response.url !== "" && response.url !== url) {
|
|
10241
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.httpFailure(new URL(url).pathname, response.status));
|
|
10242
|
+
}
|
|
10243
|
+
return await response.json();
|
|
10244
|
+
} catch (error) {
|
|
10245
|
+
signal.throwIfAborted();
|
|
10246
|
+
if (error instanceof ModelResidencyError) {
|
|
10247
|
+
throw error;
|
|
10248
|
+
}
|
|
10249
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.unverifiableResponse(new URL(url).pathname));
|
|
10250
|
+
}
|
|
10251
|
+
}
|
|
10252
|
+
function readProfiles(payload) {
|
|
10253
|
+
if (!isObject2(payload) || !Array.isArray(payload.profiles)) {
|
|
10254
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.expectedProfilesArray("/api/profiles"));
|
|
10255
|
+
}
|
|
10256
|
+
if (payload.active === null) {
|
|
10257
|
+
return;
|
|
10258
|
+
}
|
|
10259
|
+
if (typeof payload.active === "string" && payload.active.length > 0 && payload.active === payload.active.trim()) {
|
|
10260
|
+
throw new ModelResidencyError("identity", "llama-swap", llamaSwapResidencyMessages.activeProfileRewrite(payload.active));
|
|
10261
|
+
}
|
|
10262
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.invalidActiveProfileValue("/api/profiles"));
|
|
10263
|
+
}
|
|
10264
|
+
function readRunning(payload, modelIDs) {
|
|
10265
|
+
if (!isObject2(payload) || !Array.isArray(payload.running)) {
|
|
10266
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.expectedRunningArray("/running"));
|
|
10267
|
+
}
|
|
10268
|
+
const result = new Map;
|
|
10269
|
+
for (const modelID of modelIDs) {
|
|
10270
|
+
result.set(modelID, { loaded: false });
|
|
10271
|
+
}
|
|
10272
|
+
const seen = new Set;
|
|
10273
|
+
for (const entry of payload.running) {
|
|
10274
|
+
if (!isObject2(entry) || typeof entry.model !== "string" || entry.model.length === 0 || entry.model !== entry.model.trim() || typeof entry.state !== "string" || entry.state.length === 0 || entry.state !== entry.state.trim()) {
|
|
10275
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.malformedRunningEvidence("/running"));
|
|
10276
|
+
}
|
|
10277
|
+
if (seen.has(entry.model)) {
|
|
10278
|
+
throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.duplicateRunningEvidence("/running", entry.model));
|
|
10279
|
+
}
|
|
10280
|
+
seen.add(entry.model);
|
|
10281
|
+
if (!modelIDs.has(entry.model)) {
|
|
10282
|
+
continue;
|
|
10283
|
+
}
|
|
10284
|
+
result.set(entry.model, { loaded: entry.state === "ready" });
|
|
10285
|
+
}
|
|
10286
|
+
return result;
|
|
10287
|
+
}
|
|
10288
|
+
function requestHeaders(headers) {
|
|
10289
|
+
const result = new Headers(headers);
|
|
10290
|
+
result.delete("content-type");
|
|
10291
|
+
result.delete("content-length");
|
|
10292
|
+
result.set("accept", "application/json");
|
|
10293
|
+
result.set("cache-control", "no-cache, no-store");
|
|
10294
|
+
result.delete("if-none-match");
|
|
10295
|
+
result.delete("if-modified-since");
|
|
10296
|
+
return result;
|
|
10297
|
+
}
|
|
10298
|
+
function llamaSwapResidencyOptions(options) {
|
|
10299
|
+
return { ...options, runtimeLabel: "llama-swap" };
|
|
10300
|
+
}
|
|
10301
|
+
async function readLlamaSwapCatalog(baseURL, fetch, options = {}) {
|
|
10302
|
+
const base = llamaSwapBaseURL(baseURL);
|
|
10303
|
+
const headers = requestHeaders(options.headers);
|
|
10304
|
+
return withResidencyDeadline(async (signal) => parseCatalog(await metadata(`${base}/models`, fetch, signal, headers)), llamaSwapResidencyOptions(options));
|
|
10305
|
+
}
|
|
10306
|
+
async function readLlamaSwapResidency(baseURL, fetch, options = {}) {
|
|
10307
|
+
const base = llamaSwapBaseURL(baseURL);
|
|
10308
|
+
const origin = new URL(base).origin;
|
|
10309
|
+
const headers = requestHeaders(options.headers);
|
|
10310
|
+
return withResidencyDeadline(async (signal) => {
|
|
10311
|
+
const models = await readLlamaSwapCatalog(base, fetch, {
|
|
10312
|
+
...llamaSwapResidencyOptions(options),
|
|
10313
|
+
signal
|
|
10314
|
+
});
|
|
10315
|
+
readProfiles(await metadata(`${origin}/api/profiles`, fetch, signal, headers));
|
|
10316
|
+
return readRunning(await metadata(`${origin}/running`, fetch, signal, headers), new Set(models.map((model) => model.modelID)));
|
|
10317
|
+
}, llamaSwapResidencyOptions(options));
|
|
10318
|
+
}
|
|
10319
|
+
|
|
10320
|
+
// src/local/lemonadeResidency.ts
|
|
10321
|
+
import { z as z19 } from "zod";
|
|
9985
10322
|
var modelName = z19.string().min(1).refine((name) => name === name.trim());
|
|
9986
10323
|
var LoadedModelSchema = z19.object({
|
|
9987
10324
|
model_name: modelName,
|
|
@@ -10118,37 +10455,7 @@ function lemonadeBaseURL(value) {
|
|
|
10118
10455
|
}
|
|
10119
10456
|
return `${url.origin}${url.pathname.replace(/\/$/, "")}`;
|
|
10120
10457
|
}
|
|
10121
|
-
async function
|
|
10122
|
-
const timeoutMs = options.timeoutMs ?? 5000;
|
|
10123
|
-
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
10124
|
-
throw new ModelResidencyError("configuration");
|
|
10125
|
-
}
|
|
10126
|
-
const controller = new AbortController;
|
|
10127
|
-
const cancel = () => controller.abort(new ModelResidencyError("cancelled"));
|
|
10128
|
-
if (options.signal?.aborted)
|
|
10129
|
-
throw new ModelResidencyError("cancelled");
|
|
10130
|
-
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
10131
|
-
const schedule = options.scheduleTimeout ?? ((callback, ms) => {
|
|
10132
|
-
const timer = setTimeout(callback, ms);
|
|
10133
|
-
return () => clearTimeout(timer);
|
|
10134
|
-
});
|
|
10135
|
-
let onAbort = () => {};
|
|
10136
|
-
const aborted = new Promise((_, reject) => {
|
|
10137
|
-
onAbort = () => reject(controller.signal.reason);
|
|
10138
|
-
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
10139
|
-
});
|
|
10140
|
-
const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout")), timeoutMs);
|
|
10141
|
-
try {
|
|
10142
|
-
controller.signal.throwIfAborted();
|
|
10143
|
-
return await Promise.race([operation(controller.signal), aborted]);
|
|
10144
|
-
} finally {
|
|
10145
|
-
clearTimer();
|
|
10146
|
-
options.signal?.removeEventListener("abort", cancel);
|
|
10147
|
-
controller.signal.removeEventListener("abort", onAbort);
|
|
10148
|
-
controller.abort();
|
|
10149
|
-
}
|
|
10150
|
-
}
|
|
10151
|
-
async function metadata(url, fetch, signal, headers) {
|
|
10458
|
+
async function metadata2(url, fetch, signal, headers) {
|
|
10152
10459
|
signal.throwIfAborted();
|
|
10153
10460
|
let payload;
|
|
10154
10461
|
try {
|
|
@@ -10181,8 +10488,8 @@ async function readLemonadeResidency(baseURL, fetch, options = {}) {
|
|
|
10181
10488
|
headers.delete("if-none-match");
|
|
10182
10489
|
headers.delete("if-modified-since");
|
|
10183
10490
|
return withResidencyDeadline(async (signal) => {
|
|
10184
|
-
const aliases = await
|
|
10185
|
-
const health = await
|
|
10491
|
+
const aliases = await metadata2(`${new URL(base).origin}/internal/aliases`, fetch, signal, headers);
|
|
10492
|
+
const health = await metadata2(`${base}/health`, fetch, signal, headers);
|
|
10186
10493
|
return parseResidency(health, aliases);
|
|
10187
10494
|
}, options);
|
|
10188
10495
|
}
|
|
@@ -10253,11 +10560,11 @@ async function listLemonadeModels(baseURL, fetch) {
|
|
|
10253
10560
|
}
|
|
10254
10561
|
function readNonTextModelIDs(payload) {
|
|
10255
10562
|
const ids = new Set;
|
|
10256
|
-
if (!
|
|
10563
|
+
if (!isObject3(payload) || !Array.isArray(payload.data)) {
|
|
10257
10564
|
return ids;
|
|
10258
10565
|
}
|
|
10259
10566
|
for (const entry of payload.data) {
|
|
10260
|
-
if (!
|
|
10567
|
+
if (!isObject3(entry) || typeof entry.id !== "string") {
|
|
10261
10568
|
continue;
|
|
10262
10569
|
}
|
|
10263
10570
|
if (isNonTextModel(entry)) {
|
|
@@ -10295,7 +10602,7 @@ function readLoadedContextWindow(entry) {
|
|
|
10295
10602
|
}
|
|
10296
10603
|
function slotsFromLlamacppArgs(entry) {
|
|
10297
10604
|
const options = entry.recipe_options;
|
|
10298
|
-
if (!
|
|
10605
|
+
if (!isObject3(options) || typeof options.llamacpp_args !== "string") {
|
|
10299
10606
|
return;
|
|
10300
10607
|
}
|
|
10301
10608
|
const match = PARALLEL_ARG.exec(options.llamacpp_args);
|
|
@@ -10331,7 +10638,7 @@ function slotsFromLaunchCommand(entry) {
|
|
|
10331
10638
|
}
|
|
10332
10639
|
function contextWindowFromRecipeOptions(entry) {
|
|
10333
10640
|
const options = entry.recipe_options;
|
|
10334
|
-
if (!
|
|
10641
|
+
if (!isObject3(options) || !hasLlamacppEvidence(entry)) {
|
|
10335
10642
|
return;
|
|
10336
10643
|
}
|
|
10337
10644
|
const direct = positiveIntegerValue(options.ctx_size);
|
|
@@ -10391,7 +10698,7 @@ function hasLlamacppEvidence(entry) {
|
|
|
10391
10698
|
return true;
|
|
10392
10699
|
}
|
|
10393
10700
|
const options = entry.recipe_options;
|
|
10394
|
-
if (
|
|
10701
|
+
if (isObject3(options) && typeof options.llamacpp_args === "string") {
|
|
10395
10702
|
return true;
|
|
10396
10703
|
}
|
|
10397
10704
|
return Array.isArray(entry.launch_command) && launchCommandLooksLikeLlamacpp(entry.launch_command);
|
|
@@ -10447,10 +10754,57 @@ function enrichWithLoadState(models, loaded) {
|
|
|
10447
10754
|
};
|
|
10448
10755
|
});
|
|
10449
10756
|
}
|
|
10450
|
-
function
|
|
10757
|
+
function isObject3(value) {
|
|
10451
10758
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10452
10759
|
}
|
|
10453
10760
|
|
|
10761
|
+
// src/local/llamaSwap.ts
|
|
10762
|
+
var LLAMA_SWAP_DEFAULT_BASE_URL = "http://localhost:8080/v1";
|
|
10763
|
+
function withLoadedState(models, residency) {
|
|
10764
|
+
return models.map((model) => {
|
|
10765
|
+
const loaded = residency.get(model.modelID)?.loaded;
|
|
10766
|
+
return loaded === undefined ? model : { ...model, loaded };
|
|
10767
|
+
});
|
|
10768
|
+
}
|
|
10769
|
+
function createLlamaSwapAdapter() {
|
|
10770
|
+
const listModels = async (options) => {
|
|
10771
|
+
const baseURL = llamaSwapBaseURL(options.baseURL ?? LLAMA_SWAP_DEFAULT_BASE_URL);
|
|
10772
|
+
const models = await readLlamaSwapCatalog(baseURL, options.fetch);
|
|
10773
|
+
try {
|
|
10774
|
+
return withLoadedState(models, await readLlamaSwapResidency(baseURL, options.fetch));
|
|
10775
|
+
} catch (error) {
|
|
10776
|
+
if (error instanceof ModelResidencyError && (error.code === "identity" || error.code === "unknown")) {
|
|
10777
|
+
return models;
|
|
10778
|
+
}
|
|
10779
|
+
throw error;
|
|
10780
|
+
}
|
|
10781
|
+
};
|
|
10782
|
+
return {
|
|
10783
|
+
id: "llama-swap",
|
|
10784
|
+
defaultBaseURL: LLAMA_SWAP_DEFAULT_BASE_URL,
|
|
10785
|
+
listModels,
|
|
10786
|
+
async probe(options) {
|
|
10787
|
+
const baseURL = llamaSwapBaseURL(options.baseURL ?? LLAMA_SWAP_DEFAULT_BASE_URL);
|
|
10788
|
+
try {
|
|
10789
|
+
return {
|
|
10790
|
+
id: "llama-swap",
|
|
10791
|
+
baseURL,
|
|
10792
|
+
reachable: true,
|
|
10793
|
+
models: await listModels({ ...options, baseURL }),
|
|
10794
|
+
probedAt: options.probedAt
|
|
10795
|
+
};
|
|
10796
|
+
} catch (error) {
|
|
10797
|
+
return unavailableSnapshot({
|
|
10798
|
+
id: "llama-swap",
|
|
10799
|
+
baseURL,
|
|
10800
|
+
probedAt: options.probedAt,
|
|
10801
|
+
error
|
|
10802
|
+
});
|
|
10803
|
+
}
|
|
10804
|
+
}
|
|
10805
|
+
};
|
|
10806
|
+
}
|
|
10807
|
+
|
|
10454
10808
|
// src/local/lmstudio.ts
|
|
10455
10809
|
var LMSTUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
|
|
10456
10810
|
function createLMStudioAdapter() {
|
|
@@ -10503,6 +10857,7 @@ class RuntimeRegistry {
|
|
|
10503
10857
|
lmstudio: createLMStudioAdapter(),
|
|
10504
10858
|
"foundry-local": createFoundryLocalAdapter(),
|
|
10505
10859
|
lemonade: createLemonadeAdapter(),
|
|
10860
|
+
"llama-swap": createLlamaSwapAdapter(),
|
|
10506
10861
|
...options.adapters
|
|
10507
10862
|
};
|
|
10508
10863
|
this.clock = options.clock;
|
|
@@ -10969,7 +11324,7 @@ var TRUNCATED_REASON_SUFFIX = "…[truncated]";
|
|
|
10969
11324
|
var MAX_SERIALIZED_ARRAY_ITEMS = 20;
|
|
10970
11325
|
var MAX_SERIALIZED_OBJECT_PROPERTIES = 25;
|
|
10971
11326
|
var MAX_SERIALIZED_DEPTH = 4;
|
|
10972
|
-
function
|
|
11327
|
+
function isObject4(value) {
|
|
10973
11328
|
return typeof value === "object" && value !== null;
|
|
10974
11329
|
}
|
|
10975
11330
|
function isError(value) {
|
|
@@ -10999,7 +11354,7 @@ function stringProperty(value, key) {
|
|
|
10999
11354
|
}
|
|
11000
11355
|
function nestedMessage(value, key) {
|
|
11001
11356
|
const container = safeGet(value, key);
|
|
11002
|
-
if (!
|
|
11357
|
+
if (!isObject4(container)) {
|
|
11003
11358
|
return;
|
|
11004
11359
|
}
|
|
11005
11360
|
const message = stringProperty(container, "message");
|
|
@@ -11083,7 +11438,7 @@ function errorReason(error) {
|
|
|
11083
11438
|
return message;
|
|
11084
11439
|
}
|
|
11085
11440
|
}
|
|
11086
|
-
if (
|
|
11441
|
+
if (isObject4(error)) {
|
|
11087
11442
|
const message = stringProperty(error, "message");
|
|
11088
11443
|
if (message !== undefined) {
|
|
11089
11444
|
return message;
|
|
@@ -11101,7 +11456,7 @@ function errorReason(error) {
|
|
|
11101
11456
|
return safeToString(error);
|
|
11102
11457
|
}
|
|
11103
11458
|
function isNormalizedSessionFailure(value) {
|
|
11104
|
-
return
|
|
11459
|
+
return isObject4(value) && safeGet(value, "kind") === "normalized-session-failure" && typeof safeGet(value, "failureClass") === "string" && typeof safeGet(value, "retryable") === "boolean";
|
|
11105
11460
|
}
|
|
11106
11461
|
function createArgs(req) {
|
|
11107
11462
|
const body = {};
|
|
@@ -11228,7 +11583,7 @@ async function confirmSessionStopped(client, sessionID, directory, deps, deadlin
|
|
|
11228
11583
|
return { confirmed: false, cause: "status-error" };
|
|
11229
11584
|
}
|
|
11230
11585
|
const statuses = statusOutcome.value;
|
|
11231
|
-
if (!
|
|
11586
|
+
if (!isObject4(statuses)) {
|
|
11232
11587
|
return { confirmed: false, cause: "status-error" };
|
|
11233
11588
|
}
|
|
11234
11589
|
if (safeGet(statuses, "error") !== undefined) {
|
|
@@ -11378,8 +11733,11 @@ async function runSubsession(client, req, deps) {
|
|
|
11378
11733
|
}
|
|
11379
11734
|
|
|
11380
11735
|
// src/local/modelResidency.ts
|
|
11736
|
+
function runtimeRequiresModelResidency(kind) {
|
|
11737
|
+
return kind === "lemonade" || kind === "llama-swap";
|
|
11738
|
+
}
|
|
11381
11739
|
function hasRequiredModelResidency(kind, model) {
|
|
11382
|
-
return kind
|
|
11740
|
+
return !runtimeRequiresModelResidency(kind) || model?.loaded === true;
|
|
11383
11741
|
}
|
|
11384
11742
|
|
|
11385
11743
|
// src/plugin/availability.ts
|
|
@@ -11388,9 +11746,9 @@ function modelKey2(model) {
|
|
|
11388
11746
|
}
|
|
11389
11747
|
function availabilityMetadata({
|
|
11390
11748
|
apiModelID: _apiModelID,
|
|
11391
|
-
...
|
|
11749
|
+
...metadata3
|
|
11392
11750
|
}) {
|
|
11393
|
-
return
|
|
11751
|
+
return metadata3;
|
|
11394
11752
|
}
|
|
11395
11753
|
function compareAvailableModels(left, right) {
|
|
11396
11754
|
const kindOrder = Number(left.kind === "frontier") - Number(right.kind === "frontier");
|
|
@@ -11410,7 +11768,7 @@ function isConfiguredLocalModel(config, model) {
|
|
|
11410
11768
|
return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID);
|
|
11411
11769
|
}
|
|
11412
11770
|
function requiresModelResidency(config, model) {
|
|
11413
|
-
return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID &&
|
|
11771
|
+
return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID && runtimeRequiresModelResidency(localRuntimeKind(runtime)));
|
|
11414
11772
|
}
|
|
11415
11773
|
function configuredFrontierProviderIDs(config) {
|
|
11416
11774
|
const providerIDs = new Set([config.baseline.hardDefault.providerID]);
|
|
@@ -12036,6 +12394,7 @@ var PROVIDER_LABELS = {
|
|
|
12036
12394
|
ollama: "Ollama",
|
|
12037
12395
|
lmstudio: "LM Studio",
|
|
12038
12396
|
lemonade: "Lemonade Server",
|
|
12397
|
+
"llama-swap": executionSetupMessages.llamaSwap.label,
|
|
12039
12398
|
"foundry-local": "Foundry Local"
|
|
12040
12399
|
};
|
|
12041
12400
|
function providerLabel(providerID) {
|
|
@@ -12257,7 +12616,8 @@ var KNOWN_LOCAL_PROVIDER_IDS = new Set([
|
|
|
12257
12616
|
"ollama",
|
|
12258
12617
|
"lmstudio",
|
|
12259
12618
|
"foundry-local",
|
|
12260
|
-
"lemonade"
|
|
12619
|
+
"lemonade",
|
|
12620
|
+
"llama-swap"
|
|
12261
12621
|
]);
|
|
12262
12622
|
var KNOWN_FRONTIER_PROVIDER_IDS = new Set([
|
|
12263
12623
|
"github-copilot",
|
|
@@ -12603,7 +12963,7 @@ function runtimeLine(snapshot, runtime) {
|
|
|
12603
12963
|
const mark = snapshot.reachable ? "✓" : "✗";
|
|
12604
12964
|
const detail = snapshot.reachable ? `${snapshot.models.length} model(s)` : snapshot.error ?? "unreachable";
|
|
12605
12965
|
const declared = runtime?.maxConcurrency;
|
|
12606
|
-
const slots = declared === undefined ?
|
|
12966
|
+
const slots = declared === undefined ? doctorMessages.defaultRuntimeSlots(effectiveMaxConcurrency(runtime ?? {})) : ` · ${declared} slot(s) (declared)`;
|
|
12607
12967
|
return ` ${mark} ${snapshot.id.padEnd(14)} ${snapshot.baseURL || "(no baseURL)"} — ${detail}${slots}`;
|
|
12608
12968
|
}
|
|
12609
12969
|
function runtimeModelSlotsLine(runtime, snapshot) {
|
|
@@ -12615,6 +12975,8 @@ function runtimeModelSlotsLine(runtime, snapshot) {
|
|
|
12615
12975
|
if (runtime === undefined || snapshot === undefined || !snapshot.reachable || snapshot.models.length === 0) {
|
|
12616
12976
|
return [];
|
|
12617
12977
|
}
|
|
12978
|
+
if (localRuntimeKind(runtime) === "llama-swap")
|
|
12979
|
+
return [doctorMessages.llamaSwapConcurrency];
|
|
12618
12980
|
const reported = snapshot.models.flatMap((model) => model.slots === undefined ? [] : [`${model.modelID} ${model.slots} slot(s)`]);
|
|
12619
12981
|
if (reported.length > 0) {
|
|
12620
12982
|
return [
|
|
@@ -13018,7 +13380,7 @@ function renderDoctor(input) {
|
|
|
13018
13380
|
continue;
|
|
13019
13381
|
}
|
|
13020
13382
|
const runtime = enabledRuntimes.find((r) => r.id === snapshot.id);
|
|
13021
|
-
const cap = runtime
|
|
13383
|
+
const cap = effectiveMaxConcurrency(runtime ?? {});
|
|
13022
13384
|
lines.push(` ⚠ ${snapshot.id} is reached over the network: its ${cap}-slot cap is enforced per openteam process, so`, " two processes at once (an opencode session plus 'openteam console') can together exceed it.");
|
|
13023
13385
|
}
|
|
13024
13386
|
lines.push(` telemetry: ${input.telemetryPath} — ${input.telemetryRecords} record(s)`);
|
|
@@ -13630,6 +13992,38 @@ function missingGeneratedStateRules(gitignore) {
|
|
|
13630
13992
|
const present = new Set(activeGitignoreRules(gitignore));
|
|
13631
13993
|
return OPENCODE_GITIGNORE_GENERATED_STATE_RULES.filter((rule) => !present.has(rule));
|
|
13632
13994
|
}
|
|
13995
|
+
var KNOWN_RUNTIMES = [
|
|
13996
|
+
{
|
|
13997
|
+
id: "ollama",
|
|
13998
|
+
label: "Ollama",
|
|
13999
|
+
defaultBaseURL: "http://localhost:11434/v1",
|
|
14000
|
+
fallbackModelID: "qwen3:8b"
|
|
14001
|
+
},
|
|
14002
|
+
{
|
|
14003
|
+
id: "lmstudio",
|
|
14004
|
+
label: "LM Studio",
|
|
14005
|
+
defaultBaseURL: "http://localhost:1234/v1",
|
|
14006
|
+
fallbackModelID: "qwen2.5-coder"
|
|
14007
|
+
},
|
|
14008
|
+
{
|
|
14009
|
+
id: "lemonade",
|
|
14010
|
+
label: "Lemonade Server",
|
|
14011
|
+
defaultBaseURL: LEMONADE_DEFAULT_BASE_URL,
|
|
14012
|
+
fallbackModelID: "Qwen3-Coder-30B-A3B-Instruct-GGUF"
|
|
14013
|
+
},
|
|
14014
|
+
{
|
|
14015
|
+
id: "llama-swap",
|
|
14016
|
+
label: executionSetupMessages.llamaSwap.label,
|
|
14017
|
+
defaultBaseURL: LLAMA_SWAP_DEFAULT_BASE_URL,
|
|
14018
|
+
fallbackModelID: ""
|
|
14019
|
+
},
|
|
14020
|
+
{
|
|
14021
|
+
id: "foundry-local",
|
|
14022
|
+
label: "Foundry Local",
|
|
14023
|
+
fallbackModelID: "Phi-4-mini-instruct",
|
|
14024
|
+
dynamicPort: true
|
|
14025
|
+
}
|
|
14026
|
+
];
|
|
13633
14027
|
|
|
13634
14028
|
// src/commands/purge.ts
|
|
13635
14029
|
var PURGE_CATEGORY_IDS = [
|
|
@@ -14658,7 +15052,7 @@ function liveModelsFromSnapshots(snapshots, config) {
|
|
|
14658
15052
|
map.set(runtime.defaultModel.providerID, {
|
|
14659
15053
|
reachable: snapshot.reachable,
|
|
14660
15054
|
modelIDs: new Set(snapshot.models.filter((model) => hasRequiredModelResidency(kind, model)).map((model) => model.modelID)),
|
|
14661
|
-
...kind
|
|
15055
|
+
...runtimeRequiresModelResidency(kind) ? {
|
|
14662
15056
|
residency: new Map(snapshot.models.map((model) => [model.modelID, model.loaded]))
|
|
14663
15057
|
} : {}
|
|
14664
15058
|
});
|
|
@@ -14988,9 +15382,9 @@ async function runCli(argv, deps) {
|
|
|
14988
15382
|
const inventoryNotes = [];
|
|
14989
15383
|
const readySnapshots = snapshots.map((snapshot) => {
|
|
14990
15384
|
const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
|
|
14991
|
-
if (runtime === undefined || localRuntimeKind(runtime)
|
|
15385
|
+
if (runtime === undefined || !runtimeRequiresModelResidency(localRuntimeKind(runtime)))
|
|
14992
15386
|
return snapshot;
|
|
14993
|
-
inventoryNotes.push(executionSetupMessages.lemonadeInventory(runtime.id, runtime.defaultModel.providerID, snapshot.models));
|
|
15387
|
+
inventoryNotes.push(executionSetupMessages.lemonadeInventory(runtime.id, runtime.defaultModel.providerID, snapshot.models, localRuntimeKind(runtime) === "llama-swap" ? "llama-swap" : "Lemonade"));
|
|
14994
15388
|
return {
|
|
14995
15389
|
...snapshot,
|
|
14996
15390
|
models: snapshot.models.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model))
|
|
@@ -15001,7 +15395,7 @@ async function runCli(argv, deps) {
|
|
|
15001
15395
|
if (agent.model === undefined || live !== "not-loaded" && live !== "residency-unknown")
|
|
15002
15396
|
return [];
|
|
15003
15397
|
return [
|
|
15004
|
-
executionSetupMessages.lemonadeAgentResidency(agent.name, `${agent.model.providerID}/${agent.model.modelID}`, live)
|
|
15398
|
+
executionSetupMessages.lemonadeAgentResidency(agent.name, `${agent.model.providerID}/${agent.model.modelID}`, live, config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === agent.model?.providerID && localRuntimeKind(runtime) === "llama-swap") ? "llama-swap" : "Lemonade")
|
|
15005
15399
|
];
|
|
15006
15400
|
});
|
|
15007
15401
|
return {
|
|
@@ -17231,6 +17625,84 @@ function createLemonadeGuardedFetch(options) {
|
|
|
17231
17625
|
});
|
|
17232
17626
|
}
|
|
17233
17627
|
|
|
17628
|
+
// src/local/llamaSwapRequestGuard.ts
|
|
17629
|
+
var inferencePaths2 = new Set([
|
|
17630
|
+
"/chat/completions",
|
|
17631
|
+
"/completions",
|
|
17632
|
+
"/embeddings",
|
|
17633
|
+
"/responses"
|
|
17634
|
+
]);
|
|
17635
|
+
async function validatedModelID(payload, modelIDs) {
|
|
17636
|
+
if (typeof payload !== "object" || payload === null || !("model" in payload) || typeof payload.model !== "string" || payload.model.length === 0 || payload.model !== payload.model.trim()) {
|
|
17637
|
+
throw new ModelResidencyError("request", "llama-swap");
|
|
17638
|
+
}
|
|
17639
|
+
if (modelIDs === undefined) {
|
|
17640
|
+
return payload.model;
|
|
17641
|
+
}
|
|
17642
|
+
const ids = typeof modelIDs === "function" ? await modelIDs() : modelIDs;
|
|
17643
|
+
if (ids.has(payload.model)) {
|
|
17644
|
+
return payload.model;
|
|
17645
|
+
}
|
|
17646
|
+
throw new ModelResidencyError("identity", "llama-swap");
|
|
17647
|
+
}
|
|
17648
|
+
function createLlamaSwapGuardedFetch(options) {
|
|
17649
|
+
const base = llamaSwapBaseURL(options.baseURL);
|
|
17650
|
+
const upstream = options.fetch;
|
|
17651
|
+
const healthFetch = options.healthFetch ?? upstream;
|
|
17652
|
+
return Object.assign(async (input, init) => {
|
|
17653
|
+
const request = new Request(input, init);
|
|
17654
|
+
const url = new URL(request.url);
|
|
17655
|
+
if (url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !request.url.startsWith(`${base}/`)) {
|
|
17656
|
+
throw new ModelResidencyError("destination", "llama-swap");
|
|
17657
|
+
}
|
|
17658
|
+
const path4 = request.url.slice(base.length);
|
|
17659
|
+
const metadataOnly = request.method === "GET" && /^\/models(?:\/[^/]+)?$/.test(path4);
|
|
17660
|
+
if (!metadataOnly && (request.method !== "POST" || !inferencePaths2.has(path4))) {
|
|
17661
|
+
throw new ModelResidencyError("request", "llama-swap");
|
|
17662
|
+
}
|
|
17663
|
+
if (!metadataOnly) {
|
|
17664
|
+
await withResidencyDeadline(async (signal) => {
|
|
17665
|
+
signal.throwIfAborted();
|
|
17666
|
+
let payload;
|
|
17667
|
+
try {
|
|
17668
|
+
payload = await request.clone().json();
|
|
17669
|
+
} catch {
|
|
17670
|
+
signal.throwIfAborted();
|
|
17671
|
+
throw new ModelResidencyError("request", "llama-swap");
|
|
17672
|
+
}
|
|
17673
|
+
signal.throwIfAborted();
|
|
17674
|
+
const model = await validatedModelID(payload, options.modelIDs);
|
|
17675
|
+
const residency = await readLlamaSwapResidency(base, healthFetch, {
|
|
17676
|
+
...options,
|
|
17677
|
+
signal,
|
|
17678
|
+
headers: request.headers
|
|
17679
|
+
});
|
|
17680
|
+
signal.throwIfAborted();
|
|
17681
|
+
if (!residency.has(model)) {
|
|
17682
|
+
throw new ModelResidencyError("identity", "llama-swap");
|
|
17683
|
+
}
|
|
17684
|
+
if (residency.get(model)?.loaded !== true) {
|
|
17685
|
+
throw new ModelResidencyError("inactive", "llama-swap");
|
|
17686
|
+
}
|
|
17687
|
+
}, { ...options, signal: request.signal, runtimeLabel: "llama-swap" });
|
|
17688
|
+
}
|
|
17689
|
+
if (request.signal.aborted) {
|
|
17690
|
+
throw new ModelResidencyError("cancelled", "llama-swap");
|
|
17691
|
+
}
|
|
17692
|
+
const {
|
|
17693
|
+
body: _body,
|
|
17694
|
+
headers: _headers,
|
|
17695
|
+
method: _method,
|
|
17696
|
+
signal: _signal,
|
|
17697
|
+
redirect: _redirect,
|
|
17698
|
+
...transportOptions
|
|
17699
|
+
} = init ?? {};
|
|
17700
|
+
return upstream(request, { ...transportOptions, redirect: "error" });
|
|
17701
|
+
}, {
|
|
17702
|
+
preconnect: (...args) => upstream.preconnect?.(...args)
|
|
17703
|
+
});
|
|
17704
|
+
}
|
|
17705
|
+
|
|
17234
17706
|
// src/plugin/modelResidency.ts
|
|
17235
17707
|
function isFetch(value) {
|
|
17236
17708
|
return typeof value === "function";
|
|
@@ -17270,20 +17742,29 @@ function providerRoutes(provider) {
|
|
|
17270
17742
|
npm: model?.provider?.npm ?? provider.npm
|
|
17271
17743
|
}));
|
|
17272
17744
|
}
|
|
17273
|
-
function wireID(key, model) {
|
|
17745
|
+
function wireID(key, model, runtimeLabel = "Lemonade") {
|
|
17274
17746
|
const id = model?.id ?? key;
|
|
17275
17747
|
if (id.length === 0 || id !== id.trim())
|
|
17276
|
-
throw new ModelResidencyError("identity");
|
|
17748
|
+
throw new ModelResidencyError("identity", runtimeLabel);
|
|
17277
17749
|
return id;
|
|
17278
17750
|
}
|
|
17279
17751
|
function nativeEligibleID(id) {
|
|
17280
17752
|
return id === "openai" || id === "anthropic" || id.startsWith("opencode");
|
|
17281
17753
|
}
|
|
17754
|
+
function normalizedBase(kind, baseURL) {
|
|
17755
|
+
return kind === "llama-swap" ? llamaSwapBaseURL(baseURL) : lemonadeBaseURL(baseURL);
|
|
17756
|
+
}
|
|
17757
|
+
function runtimeBase(runtime) {
|
|
17758
|
+
return runtime.baseURL ?? (localRuntimeKind(runtime) === "llama-swap" ? LLAMA_SWAP_DEFAULT_BASE_URL : LEMONADE_DEFAULT_BASE_URL);
|
|
17759
|
+
}
|
|
17760
|
+
function residencyRuntimeLabel(config, providerID) {
|
|
17761
|
+
return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === providerID && localRuntimeKind(runtime) === "llama-swap") ? "llama-swap" : "Lemonade";
|
|
17762
|
+
}
|
|
17282
17763
|
function configuredRuntime(config, providerID) {
|
|
17283
17764
|
const runtimes = config.local.runtimes.filter((runtime2) => runtime2.defaultModel.providerID === providerID);
|
|
17284
17765
|
const runtime = runtimes[0];
|
|
17285
17766
|
if (runtimes.length !== 1 || runtime === undefined || !runtime.enabled) {
|
|
17286
|
-
throw new ModelResidencyError("destination");
|
|
17767
|
+
throw new ModelResidencyError("destination", residencyRuntimeLabel(config, providerID));
|
|
17287
17768
|
}
|
|
17288
17769
|
return runtime;
|
|
17289
17770
|
}
|
|
@@ -17292,8 +17773,9 @@ function createModelResidencyGuard(config, options) {
|
|
|
17292
17773
|
const blocked = new Set;
|
|
17293
17774
|
let hostConfig;
|
|
17294
17775
|
const readEnv = options.readEnv ?? ((name) => process.env[name]);
|
|
17295
|
-
const
|
|
17296
|
-
const
|
|
17776
|
+
const failure = (code, providerID) => new ModelResidencyError(code, residencyRuntimeLabel(config, providerID));
|
|
17777
|
+
const residentRuntimes = () => config.local.runtimes.filter((runtime) => runtimeRequiresModelResidency(localRuntimeKind(runtime)));
|
|
17778
|
+
const protects = (providerID, baseURL) => residentRuntimes().some((runtime) => {
|
|
17297
17779
|
if (runtime.defaultModel.providerID === providerID)
|
|
17298
17780
|
return true;
|
|
17299
17781
|
if (baseURL === undefined)
|
|
@@ -17301,13 +17783,13 @@ function createModelResidencyGuard(config, options) {
|
|
|
17301
17783
|
const binding = endpointBinding(baseURL, readEnv);
|
|
17302
17784
|
if (binding.ambiguous)
|
|
17303
17785
|
return true;
|
|
17304
|
-
return binding.origin !== undefined && binding.origin === origin(runtime
|
|
17786
|
+
return binding.origin !== undefined && binding.origin === origin(runtimeBase(runtime));
|
|
17305
17787
|
});
|
|
17306
17788
|
const resolvedWireID = (model, declaredID) => {
|
|
17307
17789
|
const id = options.resolveApiModelID === undefined ? declaredID : options.resolveApiModelID(model);
|
|
17308
17790
|
if (id === undefined)
|
|
17309
|
-
throw
|
|
17310
|
-
return wireID(id, undefined);
|
|
17791
|
+
throw failure("identity", model.providerID);
|
|
17792
|
+
return wireID(id, undefined, residencyRuntimeLabel(config, model.providerID));
|
|
17311
17793
|
};
|
|
17312
17794
|
const configHook = async (host) => {
|
|
17313
17795
|
hostConfig = host;
|
|
@@ -17327,21 +17809,22 @@ function createModelResidencyGuard(config, options) {
|
|
|
17327
17809
|
...new Set([...host.disabled_providers ?? [], providerID])
|
|
17328
17810
|
];
|
|
17329
17811
|
const reject = Object.assign(async () => {
|
|
17330
|
-
throw
|
|
17812
|
+
throw failure("transport", providerID);
|
|
17331
17813
|
}, { preconnect: () => {} });
|
|
17332
17814
|
provider.options = { ...provider.options, fetch: reject };
|
|
17333
17815
|
try {
|
|
17334
17816
|
const runtime = configuredRuntime(config, providerID);
|
|
17335
|
-
const
|
|
17336
|
-
|
|
17337
|
-
|
|
17817
|
+
const kind = localRuntimeKind(runtime);
|
|
17818
|
+
const baseURL = normalizedBase(kind, runtimeBase(runtime));
|
|
17819
|
+
if (!runtimeRequiresModelResidency(kind) || routes.some((route) => route.baseURL === undefined || normalizedBase(kind, route.baseURL) !== baseURL))
|
|
17820
|
+
throw failure("destination", providerID);
|
|
17338
17821
|
if (routes.some((route) => route.npm !== "@ai-sdk/openai-compatible") || nativeEligibleID(providerID) || !isFetch(originalFetch))
|
|
17339
|
-
throw
|
|
17822
|
+
throw failure("transport", providerID);
|
|
17340
17823
|
const modelKeys = new Map;
|
|
17341
17824
|
for (const [key, model] of Object.entries(provider.models ?? {})) {
|
|
17342
|
-
if (model.options?.fetch !== undefined || model.options?.baseURL !== undefined && (typeof model.options.baseURL !== "string" ||
|
|
17343
|
-
throw
|
|
17344
|
-
modelKeys.set(key, wireID(key, model));
|
|
17825
|
+
if (model.options?.fetch !== undefined || model.options?.baseURL !== undefined && (typeof model.options.baseURL !== "string" || normalizedBase(kind, model.options.baseURL) !== baseURL))
|
|
17826
|
+
throw failure("transport", providerID);
|
|
17827
|
+
modelKeys.set(key, wireID(key, model, residencyRuntimeLabel(config, providerID)));
|
|
17345
17828
|
}
|
|
17346
17829
|
if (!modelKeys.has(runtime.defaultModel.modelID))
|
|
17347
17830
|
modelKeys.set(runtime.defaultModel.modelID, undefined);
|
|
@@ -17350,11 +17833,12 @@ function createModelResidencyGuard(config, options) {
|
|
|
17350
17833
|
for (const [modelID2, declaredID] of modelKeys) {
|
|
17351
17834
|
const id = options.resolveApiModelID === undefined ? declaredID : options.resolveApiModelID({ providerID, modelID: modelID2 });
|
|
17352
17835
|
if (id !== undefined)
|
|
17353
|
-
ids.add(wireID(id, undefined));
|
|
17836
|
+
ids.add(wireID(id, undefined, residencyRuntimeLabel(config, providerID)));
|
|
17354
17837
|
}
|
|
17355
17838
|
return ids;
|
|
17356
17839
|
};
|
|
17357
|
-
const
|
|
17840
|
+
const guardFetch = kind === "llama-swap" ? createLlamaSwapGuardedFetch : createLemonadeGuardedFetch;
|
|
17841
|
+
const fetch = guardFetch({
|
|
17358
17842
|
...options,
|
|
17359
17843
|
baseURL,
|
|
17360
17844
|
modelIDs: async () => {
|
|
@@ -17365,7 +17849,10 @@ function createModelResidencyGuard(config, options) {
|
|
|
17365
17849
|
healthFetch: options.fetch
|
|
17366
17850
|
});
|
|
17367
17851
|
provider.options.fetch = fetch;
|
|
17852
|
+
if (kind === "llama-swap")
|
|
17853
|
+
provider.options.baseURL = baseURL;
|
|
17368
17854
|
guarded.set(providerID, {
|
|
17855
|
+
kind,
|
|
17369
17856
|
baseURL,
|
|
17370
17857
|
fetch,
|
|
17371
17858
|
originalFetch,
|
|
@@ -17379,7 +17866,7 @@ function createModelResidencyGuard(config, options) {
|
|
|
17379
17866
|
} catch (error) {
|
|
17380
17867
|
if (!(error instanceof ModelResidencyError))
|
|
17381
17868
|
throw error;
|
|
17382
|
-
(options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(providerID));
|
|
17869
|
+
(options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(providerID, residencyRuntimeLabel(config, providerID)));
|
|
17383
17870
|
}
|
|
17384
17871
|
}
|
|
17385
17872
|
};
|
|
@@ -17389,48 +17876,52 @@ function createModelResidencyGuard(config, options) {
|
|
|
17389
17876
|
return;
|
|
17390
17877
|
const provider = guarded.get(input.model.providerID);
|
|
17391
17878
|
if (provider === undefined || blocked.has(input.model.providerID) || input.provider.options.fetch !== provider.fetch || input.model.api.npm !== "@ai-sdk/openai-compatible" || nativeEligibleID(input.model.providerID))
|
|
17392
|
-
throw
|
|
17393
|
-
if (
|
|
17394
|
-
throw
|
|
17879
|
+
throw failure("transport", input.model.providerID);
|
|
17880
|
+
if (normalizedBase(provider.kind, base) !== provider.baseURL) {
|
|
17881
|
+
throw failure("destination", input.model.providerID);
|
|
17395
17882
|
}
|
|
17883
|
+
if (input.model.options.fetch !== undefined || input.model.options.baseURL !== undefined && (typeof input.model.options.baseURL !== "string" || normalizedBase(provider.kind, input.model.options.baseURL) !== provider.baseURL))
|
|
17884
|
+
throw failure("transport", input.model.providerID);
|
|
17396
17885
|
const id = resolvedWireID({ providerID: input.model.providerID, modelID: input.model.id }, provider.modelKeys.get(input.model.id));
|
|
17397
17886
|
if (id !== input.model.api.id)
|
|
17398
|
-
throw
|
|
17887
|
+
throw failure("identity", input.model.providerID);
|
|
17399
17888
|
if (!provider.modelKeys.has(input.model.id))
|
|
17400
17889
|
provider.modelKeys.set(input.model.id, undefined);
|
|
17401
17890
|
};
|
|
17402
17891
|
const localTarget = (model) => {
|
|
17403
17892
|
const runtime = configuredRuntime(config, model.providerID);
|
|
17893
|
+
const kind = localRuntimeKind(runtime);
|
|
17894
|
+
const needsResidency = runtimeRequiresModelResidency(kind);
|
|
17404
17895
|
if (hostConfig?.disabled_providers?.includes(model.providerID)) {
|
|
17405
|
-
throw
|
|
17896
|
+
throw failure("transport", model.providerID);
|
|
17406
17897
|
}
|
|
17407
17898
|
if (runtime.baseURL === undefined)
|
|
17408
|
-
throw
|
|
17899
|
+
throw failure("destination", model.providerID);
|
|
17409
17900
|
const provider = hostConfig?.provider?.[model.providerID];
|
|
17410
17901
|
const entry = Object.hasOwn(provider?.models ?? {}, model.modelID) ? provider?.models?.[model.modelID] : undefined;
|
|
17411
17902
|
const configuredURL = provider === undefined ? undefined : providerBase(provider, entry);
|
|
17412
|
-
if (configuredURL !== undefined && new URL(configuredURL).href.replace(/\/$/, "") !== new URL(runtime.baseURL).href.replace(/\/$/, "")) {
|
|
17413
|
-
throw
|
|
17903
|
+
if (configuredURL !== undefined && (needsResidency ? normalizedBase(kind, configuredURL) !== normalizedBase(kind, runtime.baseURL) : new URL(configuredURL).href.replace(/\/$/, "") !== new URL(runtime.baseURL).href.replace(/\/$/, ""))) {
|
|
17904
|
+
throw failure("destination", model.providerID);
|
|
17414
17905
|
}
|
|
17415
|
-
const modelID2 = resolvedWireID(model, entry === undefined &&
|
|
17906
|
+
const modelID2 = resolvedWireID(model, entry === undefined && needsResidency ? undefined : wireID(model.modelID, entry, residencyRuntimeLabel(config, model.providerID)));
|
|
17416
17907
|
let fetch = options.fetch;
|
|
17417
|
-
if (
|
|
17908
|
+
if (needsResidency) {
|
|
17418
17909
|
const installed = guarded.get(model.providerID);
|
|
17419
17910
|
if (installed === undefined || blocked.has(model.providerID)) {
|
|
17420
|
-
throw
|
|
17911
|
+
throw failure("transport", model.providerID);
|
|
17421
17912
|
}
|
|
17422
|
-
if (installed.baseURL !==
|
|
17423
|
-
throw
|
|
17913
|
+
if (installed.baseURL !== normalizedBase(kind, runtime.baseURL)) {
|
|
17914
|
+
throw failure("destination", model.providerID);
|
|
17424
17915
|
}
|
|
17425
17916
|
if (!installed.modelKeys.has(model.modelID))
|
|
17426
17917
|
installed.modelKeys.set(model.modelID, undefined);
|
|
17427
17918
|
if (!installed.modelIDs().has(modelID2))
|
|
17428
|
-
throw
|
|
17919
|
+
throw failure("identity", model.providerID);
|
|
17429
17920
|
fetch = installed.fetch;
|
|
17430
17921
|
}
|
|
17431
17922
|
const configuredHeaders = z25.record(z25.string(), z25.string()).safeParse(provider?.options?.headers ?? {});
|
|
17432
17923
|
if (!configuredHeaders.success)
|
|
17433
|
-
throw
|
|
17924
|
+
throw failure("configuration", model.providerID);
|
|
17434
17925
|
const headers = new Headers(configuredHeaders.data);
|
|
17435
17926
|
if (typeof provider?.options?.apiKey === "string" && !headers.has("authorization")) {
|
|
17436
17927
|
headers.set("authorization", `Bearer ${provider.options.apiKey}`);
|
|
@@ -17439,7 +17930,7 @@ function createModelResidencyGuard(config, options) {
|
|
|
17439
17930
|
headers.set(name, value);
|
|
17440
17931
|
const upstream = fetch;
|
|
17441
17932
|
return {
|
|
17442
|
-
baseURL: runtime.baseURL,
|
|
17933
|
+
baseURL: needsResidency ? normalizedBase(kind, runtime.baseURL) : runtime.baseURL,
|
|
17443
17934
|
modelID: modelID2,
|
|
17444
17935
|
fetch: [...headers].length === 0 ? fetch : Object.assign(async (input, init) => {
|
|
17445
17936
|
const request = new Request(input, init);
|
|
@@ -18562,7 +19053,7 @@ var memoryToolMessages = {
|
|
|
18562
19053
|
scribeOnly: (actualRoleID) => `openteam memory: refused — memory records may only be written by the "scribe" role, not "${actualRoleID}".`,
|
|
18563
19054
|
disabled: "openteam memory: semantic memory is disabled; nothing was recorded.",
|
|
18564
19055
|
frontierDomainRefusal: 'openteam memory: refused — memory extraction requires local model execution, but router.executionMode is "frontier". Set router.executionMode to "local" or "mixed" and configure a reachable local runtime.',
|
|
18565
|
-
localRuntimeUnavailable: "openteam memory: memory extraction requires a local runtime that is reachable and will not fall back to a frontier provider. Configure Ollama, LM Studio, Lemonade, or Foundry Local and run `openteam doctor`.",
|
|
19056
|
+
localRuntimeUnavailable: "openteam memory: memory extraction requires a local runtime that is reachable and will not fall back to a frontier provider. Configure Ollama, LM Studio, Lemonade, llama-swap, or Foundry Local and run `openteam doctor`.",
|
|
18566
19057
|
localRuntimeBaseURLMissing: "openteam memory: refused — no local runtime with a base URL is configured and enabled; memory extraction is local-only.",
|
|
18567
19058
|
extractionFailure: (reason) => `openteam memory: extraction failed; nothing was recorded (${reason}).`,
|
|
18568
19059
|
noRecords: "openteam memory: no records were extracted; nothing was recorded.",
|
|
@@ -18632,14 +19123,16 @@ function createMemoryTool(deps) {
|
|
|
18632
19123
|
if (runtime?.baseURL === undefined || runtime.baseURL.length === 0) {
|
|
18633
19124
|
return memoryToolMessages.localRuntimeBaseURLMissing;
|
|
18634
19125
|
}
|
|
18635
|
-
const
|
|
19126
|
+
const kind = localRuntimeKind(runtime);
|
|
19127
|
+
const baseURL = kind === "llama-swap" ? llamaSwapBaseURL(runtime.baseURL) : runtime.baseURL;
|
|
18636
19128
|
const model = configuredModel ?? runtime.defaultModel;
|
|
18637
19129
|
const selectedRuntime = runtime;
|
|
18638
19130
|
const deadline = {
|
|
18639
19131
|
...deps.residencyOptions,
|
|
19132
|
+
...kind === "llama-swap" ? { runtimeLabel: "llama-swap" } : {},
|
|
18640
19133
|
...signal === undefined ? {} : { signal }
|
|
18641
19134
|
};
|
|
18642
|
-
const reachable =
|
|
19135
|
+
const reachable = runtimeRequiresModelResidency(kind) ? await withResidencyDeadline((signal2) => deps.localRuntimeReachable(selectedRuntime, signal2), deadline) : await deps.localRuntimeReachable(runtime);
|
|
18643
19136
|
throwIfAborted();
|
|
18644
19137
|
if (!reachable)
|
|
18645
19138
|
return memoryToolMessages.localRuntimeUnavailable;
|
|
@@ -18647,7 +19140,7 @@ function createMemoryTool(deps) {
|
|
|
18647
19140
|
const target = resolveTarget ? await withResidencyDeadline(async () => resolveTarget(model), deadline) : {
|
|
18648
19141
|
baseURL,
|
|
18649
19142
|
modelID: model.modelID,
|
|
18650
|
-
fetch:
|
|
19143
|
+
fetch: runtimeRequiresModelResidency(kind) ? (kind === "llama-swap" ? createLlamaSwapGuardedFetch : createLemonadeGuardedFetch)({
|
|
18651
19144
|
baseURL,
|
|
18652
19145
|
fetch: deps.fetch,
|
|
18653
19146
|
modelIDs: new Set([model.modelID]),
|
|
@@ -21566,6 +22059,13 @@ function createLocalEmbedder(request, deps) {
|
|
|
21566
22059
|
return (texts) => embedTexts({ ...request, texts }, deps);
|
|
21567
22060
|
}
|
|
21568
22061
|
|
|
22062
|
+
// src/messages/memoryRuntime.ts
|
|
22063
|
+
var memoryRuntimeMessages = {
|
|
22064
|
+
providerUnavailable: "[openteam] Semantic memory requires exactly one enabled local runtime matching the configured embeddings provider. No embedding request was sent.",
|
|
22065
|
+
unavailable: "[openteam] Semantic memory initialization failed; recall and memory injection are unavailable.",
|
|
22066
|
+
rejectedLines: (count) => `[openteam] memory log rejected ${count} line(s); semantic memory may be incomplete.`
|
|
22067
|
+
};
|
|
22068
|
+
|
|
21569
22069
|
// src/storage/index/bunSqlite.ts
|
|
21570
22070
|
async function createBunSqliteDatabase(path4) {
|
|
21571
22071
|
const mod = await import("bun:sqlite");
|
|
@@ -21649,7 +22149,14 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
21649
22149
|
if (options.requireInjectionEnabled === true && !semantic.injection.enabled) {
|
|
21650
22150
|
return;
|
|
21651
22151
|
}
|
|
21652
|
-
const
|
|
22152
|
+
const warn = deps.warn ?? console.warn;
|
|
22153
|
+
const configuredModel = semantic.embeddings.model;
|
|
22154
|
+
const candidates = configuredModel == null ? config.local.runtimes.filter((rt) => rt.enabled && rt.baseURL !== undefined) : config.local.runtimes.filter((rt) => rt.defaultModel.providerID === configuredModel.providerID);
|
|
22155
|
+
const runtime = candidates[0];
|
|
22156
|
+
if (configuredModel != null && (candidates.length !== 1 || runtime?.enabled !== true)) {
|
|
22157
|
+
warn(memoryRuntimeMessages.providerUnavailable);
|
|
22158
|
+
return;
|
|
22159
|
+
}
|
|
21653
22160
|
if (runtime?.baseURL === undefined) {
|
|
21654
22161
|
return;
|
|
21655
22162
|
}
|
|
@@ -21658,15 +22165,22 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
21658
22165
|
const makeEmbedder = deps.createEmbedder ?? createLocalEmbedder;
|
|
21659
22166
|
const fetchImpl = deps.fetch ?? globalThis.fetch;
|
|
21660
22167
|
const now = deps.now ?? (() => Date.now());
|
|
21661
|
-
const
|
|
22168
|
+
const kind = localRuntimeKind(runtime);
|
|
21662
22169
|
try {
|
|
22170
|
+
const baseURL = kind === "llama-swap" ? llamaSwapBaseURL(runtime.baseURL) : runtime.baseURL;
|
|
22171
|
+
const guardedFetch = runtimeRequiresModelResidency(kind) ? (kind === "llama-swap" ? createLlamaSwapGuardedFetch : createLemonadeGuardedFetch)({
|
|
22172
|
+
baseURL,
|
|
22173
|
+
fetch: fetchImpl,
|
|
22174
|
+
healthFetch: fetchImpl,
|
|
22175
|
+
modelIDs: new Set([modelID2])
|
|
22176
|
+
}) : fetchImpl;
|
|
21663
22177
|
const db = await openDatabase(semantic.indexPath);
|
|
21664
22178
|
const index = createMemoryIndex(db, warn);
|
|
21665
22179
|
const rebuildResult = await rebuildMemoryIndexFromStorage(index, semantic.logPath, { storage: deps.storage });
|
|
21666
22180
|
if (rebuildResult.rejectedLines > 0) {
|
|
21667
|
-
warn(
|
|
22181
|
+
warn(memoryRuntimeMessages.rejectedLines(rebuildResult.rejectedLines));
|
|
21668
22182
|
}
|
|
21669
|
-
const embedder = makeEmbedder({ baseURL
|
|
22183
|
+
const embedder = makeEmbedder({ baseURL, modelID: modelID2 }, { fetch: guardedFetch });
|
|
21670
22184
|
await ensureMemoryEmbeddings({ index, embedder, model: modelID2, warn });
|
|
21671
22185
|
return {
|
|
21672
22186
|
index,
|
|
@@ -21676,6 +22190,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
21676
22190
|
semantic
|
|
21677
22191
|
};
|
|
21678
22192
|
} catch {
|
|
22193
|
+
warn(memoryRuntimeMessages.unavailable);
|
|
21679
22194
|
return;
|
|
21680
22195
|
}
|
|
21681
22196
|
}
|
|
@@ -22046,8 +22561,8 @@ function readRun(runDir, runID) {
|
|
|
22046
22561
|
if (metadataText === undefined || eventsText === undefined) {
|
|
22047
22562
|
throw new LifecycleFsError("corrupt");
|
|
22048
22563
|
}
|
|
22049
|
-
const
|
|
22050
|
-
if (
|
|
22564
|
+
const metadata3 = parseJson(metadataText, parseLifecycleRunMetadata);
|
|
22565
|
+
if (metadata3.runID !== runID) {
|
|
22051
22566
|
throw new LifecycleFsError("corrupt");
|
|
22052
22567
|
}
|
|
22053
22568
|
let decoded;
|
|
@@ -22062,10 +22577,10 @@ function readRun(runDir, runID) {
|
|
|
22062
22577
|
}
|
|
22063
22578
|
}
|
|
22064
22579
|
const first = decoded.events[0];
|
|
22065
|
-
if (first === undefined || first.type !== "run.started" || first.source !==
|
|
22580
|
+
if (first === undefined || first.type !== "run.started" || first.source !== metadata3.source || first.executionAuthority !== metadata3.executionAuthority || first.root.operationID !== metadata3.root.operationID || first.root.taskID !== metadata3.root.taskID) {
|
|
22066
22581
|
throw new LifecycleFsError("corrupt");
|
|
22067
22582
|
}
|
|
22068
|
-
return { metadata:
|
|
22583
|
+
return { metadata: metadata3, decoded };
|
|
22069
22584
|
}
|
|
22070
22585
|
function terminalOutcome(events) {
|
|
22071
22586
|
const last = events.at(-1);
|
|
@@ -22143,7 +22658,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
22143
22658
|
mkdirSync3(stagingPath);
|
|
22144
22659
|
const writerToken = issueWriterToken();
|
|
22145
22660
|
const eventAt = now();
|
|
22146
|
-
const
|
|
22661
|
+
const metadata3 = parseLifecycleRunMetadata({
|
|
22147
22662
|
...parsedInput,
|
|
22148
22663
|
version: 1,
|
|
22149
22664
|
createdAt: eventAt
|
|
@@ -22159,7 +22674,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
22159
22674
|
executionAuthority: parsedInput.executionAuthority,
|
|
22160
22675
|
root: parsedInput.root
|
|
22161
22676
|
});
|
|
22162
|
-
writeDurable2(join15(stagingPath, METADATA_FILE), `${JSON.stringify(
|
|
22677
|
+
writeDurable2(join15(stagingPath, METADATA_FILE), `${JSON.stringify(metadata3)}
|
|
22163
22678
|
`);
|
|
22164
22679
|
writeDurable2(join15(stagingPath, EVENTS_FILE), encodeLifecycleJournal([event]));
|
|
22165
22680
|
writeDurable2(join15(stagingPath, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
@@ -22175,7 +22690,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
22175
22690
|
stagingPath = undefined;
|
|
22176
22691
|
return ok({
|
|
22177
22692
|
handle: { runID, writerToken },
|
|
22178
|
-
metadata:
|
|
22693
|
+
metadata: metadata3,
|
|
22179
22694
|
event,
|
|
22180
22695
|
lease,
|
|
22181
22696
|
head: 1
|
|
@@ -23296,6 +23811,20 @@ var server = async (ctx, rawOptions) => {
|
|
|
23296
23811
|
storage,
|
|
23297
23812
|
now,
|
|
23298
23813
|
localRuntimeReachable: async (runtime, signal) => {
|
|
23814
|
+
if (localRuntimeKind(runtime) === "llama-swap") {
|
|
23815
|
+
if (ctx.client.config?.providers !== undefined)
|
|
23816
|
+
await ensureAvailability();
|
|
23817
|
+
signal?.throwIfAborted();
|
|
23818
|
+
const target = modelResidency.localTarget(resolveMemorySemantic(config).extraction.model ?? runtime.defaultModel);
|
|
23819
|
+
const residency = await readLlamaSwapResidency(target.baseURL, globalThis.fetch, {
|
|
23820
|
+
...signal === undefined ? {} : { signal }
|
|
23821
|
+
});
|
|
23822
|
+
if (!residency.has(target.modelID))
|
|
23823
|
+
throw new ModelResidencyError("identity", "llama-swap");
|
|
23824
|
+
if (residency.get(target.modelID)?.loaded !== true)
|
|
23825
|
+
throw new ModelResidencyError("inactive", "llama-swap");
|
|
23826
|
+
return true;
|
|
23827
|
+
}
|
|
23299
23828
|
if (localRuntimeKind(runtime) === "lemonade") {
|
|
23300
23829
|
if (ctx.client.config?.providers !== undefined)
|
|
23301
23830
|
await ensureAvailability();
|