@jmanuelcorral/openteam 0.25.0 → 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.
Files changed (43) hide show
  1. package/README.es.md +29 -6
  2. package/README.md +29 -7
  3. package/dist/certificates/graph-release-certificate.json +2 -2
  4. package/dist/certificates/graph-shadow-certificate.json +2 -2
  5. package/dist/cli/setupAdapters.d.ts.map +1 -1
  6. package/dist/cli.js +775 -128
  7. package/dist/commands/agents.d.ts.map +1 -1
  8. package/dist/commands/dispatch.d.ts.map +1 -1
  9. package/dist/commands/doctor.d.ts.map +1 -1
  10. package/dist/commands/setup.d.ts +20 -15
  11. package/dist/commands/setup.d.ts.map +1 -1
  12. package/dist/config/schema.d.ts +101 -7
  13. package/dist/config/schema.d.ts.map +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +648 -122
  16. package/dist/local/lemonadeResidency.d.ts +2 -14
  17. package/dist/local/lemonadeResidency.d.ts.map +1 -1
  18. package/dist/local/llamaSwap.d.ts +5 -0
  19. package/dist/local/llamaSwap.d.ts.map +1 -0
  20. package/dist/local/llamaSwapRequestGuard.d.ts +11 -0
  21. package/dist/local/llamaSwapRequestGuard.d.ts.map +1 -0
  22. package/dist/local/llamaSwapResidency.d.ts +9 -0
  23. package/dist/local/llamaSwapResidency.d.ts.map +1 -0
  24. package/dist/local/modelResidency.d.ts +1 -0
  25. package/dist/local/modelResidency.d.ts.map +1 -1
  26. package/dist/local/registry.d.ts.map +1 -1
  27. package/dist/local/residency.d.ts +16 -0
  28. package/dist/local/residency.d.ts.map +1 -0
  29. package/dist/local/types.d.ts +10 -2
  30. package/dist/local/types.d.ts.map +1 -1
  31. package/dist/messages/executionSetup.d.ts +22 -3
  32. package/dist/messages/executionSetup.d.ts.map +1 -1
  33. package/dist/messages/memoryRuntime.d.ts +6 -0
  34. package/dist/messages/memoryRuntime.d.ts.map +1 -0
  35. package/dist/messages/memoryTool.d.ts +1 -1
  36. package/dist/messages/memoryTool.d.ts.map +1 -1
  37. package/dist/messages/modelResidency.d.ts +20 -2
  38. package/dist/messages/modelResidency.d.ts.map +1 -1
  39. package/dist/plugin/availability.d.ts.map +1 -1
  40. package/dist/plugin/memoryTool.d.ts.map +1 -1
  41. package/dist/plugin/modelResidency.d.ts.map +1 -1
  42. package/dist/storage/index/memoryRuntime.d.ts.map +1 -1
  43. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1049,7 +1049,8 @@ var LocalRuntimeKindSchema = z3.enum([
1049
1049
  "ollama",
1050
1050
  "lmstudio",
1051
1051
  "foundry-local",
1052
- "lemonade"
1052
+ "lemonade",
1053
+ "llama-swap"
1053
1054
  ]);
1054
1055
  var LocalRuntimeSchema = z3.object({
1055
1056
  id: z3.string().min(1),
@@ -1069,15 +1070,25 @@ var LocalRuntimeSchema = z3.object({
1069
1070
  ctx.addIssue({
1070
1071
  code: z3.ZodIssueCode.custom,
1071
1072
  path: ["kind"],
1072
- message: `local runtime "${runtime.id}" has no resolvable kind: add "kind" ` + "(one of ollama, lmstudio, foundry-local, lemonade), since the id is " + "not itself a runtime kind."
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."
1073
1074
  });
1074
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 };
1075
1082
  });
1076
1083
  function localRuntimeKind(runtime) {
1077
1084
  return runtime.kind ?? runtime.id;
1078
1085
  }
1079
1086
  function effectiveMaxConcurrency(runtime) {
1080
- return runtime.maxConcurrency ?? DEFAULT_LOCAL_MAX_CONCURRENCY;
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;
1081
1092
  }
1082
1093
  var MemoryScopeSchema = z3.enum(["project", "user"]);
1083
1094
  var MemoryExtractionModeSchema = z3.enum([
@@ -5746,7 +5757,7 @@ import { z as z15 } from "zod";
5746
5757
  // package.json
5747
5758
  var package_default = {
5748
5759
  name: "@jmanuelcorral/openteam",
5749
- version: "0.25.0",
5760
+ version: "0.26.0",
5750
5761
  packageManager: "bun@1.3.14",
5751
5762
  description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
5752
5763
  license: "MIT",
@@ -6103,6 +6114,23 @@ var executionSetupMessages = {
6103
6114
  `),
6104
6115
  localOnlyTitle: "Local execution",
6105
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.`,
6106
6134
  lemonadeDetectedHint: (loaded, advertised) => `detected - ${loaded} confirmed loaded of ${advertised} advertised text model(s)`,
6107
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.",
6108
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.`,
@@ -6117,11 +6145,11 @@ var executionSetupMessages = {
6117
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.",
6118
6146
  lemonadeV2Title: "Lemonade transport compatibility",
6119
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.`,
6120
- lemonadeInventory: (instanceID, providerID, models) => {
6148
+ lemonadeInventory: (instanceID, providerID, models, runtime = "Lemonade") => {
6121
6149
  const inventory = models.map((model) => `${model.modelID} (${model.loaded === true ? "loaded" : model.loaded === false ? "inactive" : "residency unknown"})`).join(", ");
6122
- return `Lemonade inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
6150
+ return `${runtime} inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
6123
6151
  },
6124
- lemonadeAgentResidency: (agent, model, state) => `Lemonade 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.`,
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.`,
6125
6153
  mixedPrimaryQuestion: "Primary coordinator model",
6126
6154
  mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
6127
6155
  mixedPrimaryFrontier: "Choose a frontier model",
@@ -6225,6 +6253,8 @@ var executionPolicyMessages = {
6225
6253
  primaryLocalMismatchRemedy: (sourceFile) => ` remedy: re-run \`openteam setup\` to regenerate ${sourceFile} and opencode.json from the same primary policy, then re-run \`openteam doctor\`.`
6226
6254
  };
6227
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.",
6228
6258
  localModelLimits: {
6229
6259
  section: " local model limits:",
6230
6260
  healthy: " ✓ enabled local provider models declare valid output and context limits in opencode.json.",
@@ -6241,7 +6271,7 @@ var doctorMessages = {
6241
6271
  invalidInput: "invalid limit.input (expected a positive integer token count)",
6242
6272
  outputExceedsContext: "limit.output is greater than or equal to limit.context, so the configured context leaves no usable input window",
6243
6273
  outputExceedsInput: "limit.input is less than or equal to the reserved output budget, so compaction would have no usable input threshold",
6244
- outputRemedy: " remedy: re-run `openteam setup` to write openteam's 8 192-token local output default, then re-run `openteam doctor`.",
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`.",
6245
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`.",
6246
6276
  detectedContextRemedy: " remedy: re-run `openteam setup` while the runtime is reachable to copy the detected usable context budget, then re-run `openteam doctor`.",
6247
6277
  unknownContextRemedy: " remedy: re-run `openteam setup` to write the required context:0 sentinel; automatic compaction remains disabled until a positive context is configured.",
@@ -9953,14 +9983,12 @@ function ensureFoundryV1BaseURL(endpoint) {
9953
9983
  }
9954
9984
  }
9955
9985
 
9956
- // src/local/lemonadeResidency.ts
9957
- import { z as z19 } from "zod";
9958
-
9959
9986
  // src/messages/modelResidency.ts
9960
9987
  var reasons = {
9961
9988
  unknown: "fresh residency metadata is unavailable, malformed, or ambiguous",
9962
9989
  inactive: "the requested model is not verified as resident and serving",
9963
9990
  identity: "the requested model identity can be rewritten or is ambiguous",
9991
+ "authentication-unsupported": "authentication is required but unsupported by this integration",
9964
9992
  destination: "the request destination does not match its configured runtime",
9965
9993
  transport: "this provider execution path cannot enforce the residency guard",
9966
9994
  request: "this is not a supported, explicit model inference request",
@@ -9969,22 +9997,328 @@ var reasons = {
9969
9997
  configuration: "the residency guard configuration is invalid"
9970
9998
  };
9971
9999
  var modelResidencyMessages = {
9972
- blocked: (reason) => `[openteam] Lemonade model request blocked: ${reasons[reason]}.`,
9973
- providerDisabled: (providerID) => `[openteam] Lemonade provider "${providerID}" is disabled because its configured transport or runtime mapping cannot enforce loaded-only requests.`,
9974
- 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}"`
9975
10020
  };
9976
10021
 
9977
- // src/local/lemonadeResidency.ts
10022
+ // src/local/residency.ts
9978
10023
  class ModelResidencyError extends Error {
9979
10024
  code;
9980
10025
  statusCode = 400;
9981
10026
  isRetryable = false;
9982
- constructor(code) {
9983
- super(modelResidencyMessages.blocked(code));
10027
+ constructor(code, runtimeLabel = "Lemonade", detail) {
10028
+ super(modelResidencyMessages.blocked(code, runtimeLabel, detail));
9984
10029
  this.code = code;
9985
10030
  this.name = "ModelResidencyError";
9986
10031
  }
9987
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";
9988
10322
  var modelName = z19.string().min(1).refine((name) => name === name.trim());
9989
10323
  var LoadedModelSchema = z19.object({
9990
10324
  model_name: modelName,
@@ -10121,37 +10455,7 @@ function lemonadeBaseURL(value) {
10121
10455
  }
10122
10456
  return `${url.origin}${url.pathname.replace(/\/$/, "")}`;
10123
10457
  }
10124
- async function withResidencyDeadline(operation, options) {
10125
- const timeoutMs = options.timeoutMs ?? 5000;
10126
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
10127
- throw new ModelResidencyError("configuration");
10128
- }
10129
- const controller = new AbortController;
10130
- const cancel = () => controller.abort(new ModelResidencyError("cancelled"));
10131
- if (options.signal?.aborted)
10132
- throw new ModelResidencyError("cancelled");
10133
- options.signal?.addEventListener("abort", cancel, { once: true });
10134
- const schedule = options.scheduleTimeout ?? ((callback, ms) => {
10135
- const timer = setTimeout(callback, ms);
10136
- return () => clearTimeout(timer);
10137
- });
10138
- let onAbort = () => {};
10139
- const aborted = new Promise((_, reject) => {
10140
- onAbort = () => reject(controller.signal.reason);
10141
- controller.signal.addEventListener("abort", onAbort, { once: true });
10142
- });
10143
- const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout")), timeoutMs);
10144
- try {
10145
- controller.signal.throwIfAborted();
10146
- return await Promise.race([operation(controller.signal), aborted]);
10147
- } finally {
10148
- clearTimer();
10149
- options.signal?.removeEventListener("abort", cancel);
10150
- controller.signal.removeEventListener("abort", onAbort);
10151
- controller.abort();
10152
- }
10153
- }
10154
- async function metadata(url, fetch, signal, headers) {
10458
+ async function metadata2(url, fetch, signal, headers) {
10155
10459
  signal.throwIfAborted();
10156
10460
  let payload;
10157
10461
  try {
@@ -10184,8 +10488,8 @@ async function readLemonadeResidency(baseURL, fetch, options = {}) {
10184
10488
  headers.delete("if-none-match");
10185
10489
  headers.delete("if-modified-since");
10186
10490
  return withResidencyDeadline(async (signal) => {
10187
- const aliases = await metadata(`${new URL(base).origin}/internal/aliases`, fetch, signal, headers);
10188
- const health = await metadata(`${base}/health`, fetch, signal, headers);
10491
+ const aliases = await metadata2(`${new URL(base).origin}/internal/aliases`, fetch, signal, headers);
10492
+ const health = await metadata2(`${base}/health`, fetch, signal, headers);
10189
10493
  return parseResidency(health, aliases);
10190
10494
  }, options);
10191
10495
  }
@@ -10256,11 +10560,11 @@ async function listLemonadeModels(baseURL, fetch) {
10256
10560
  }
10257
10561
  function readNonTextModelIDs(payload) {
10258
10562
  const ids = new Set;
10259
- if (!isObject2(payload) || !Array.isArray(payload.data)) {
10563
+ if (!isObject3(payload) || !Array.isArray(payload.data)) {
10260
10564
  return ids;
10261
10565
  }
10262
10566
  for (const entry of payload.data) {
10263
- if (!isObject2(entry) || typeof entry.id !== "string") {
10567
+ if (!isObject3(entry) || typeof entry.id !== "string") {
10264
10568
  continue;
10265
10569
  }
10266
10570
  if (isNonTextModel(entry)) {
@@ -10298,7 +10602,7 @@ function readLoadedContextWindow(entry) {
10298
10602
  }
10299
10603
  function slotsFromLlamacppArgs(entry) {
10300
10604
  const options = entry.recipe_options;
10301
- if (!isObject2(options) || typeof options.llamacpp_args !== "string") {
10605
+ if (!isObject3(options) || typeof options.llamacpp_args !== "string") {
10302
10606
  return;
10303
10607
  }
10304
10608
  const match = PARALLEL_ARG.exec(options.llamacpp_args);
@@ -10334,7 +10638,7 @@ function slotsFromLaunchCommand(entry) {
10334
10638
  }
10335
10639
  function contextWindowFromRecipeOptions(entry) {
10336
10640
  const options = entry.recipe_options;
10337
- if (!isObject2(options) || !hasLlamacppEvidence(entry)) {
10641
+ if (!isObject3(options) || !hasLlamacppEvidence(entry)) {
10338
10642
  return;
10339
10643
  }
10340
10644
  const direct = positiveIntegerValue(options.ctx_size);
@@ -10394,7 +10698,7 @@ function hasLlamacppEvidence(entry) {
10394
10698
  return true;
10395
10699
  }
10396
10700
  const options = entry.recipe_options;
10397
- if (isObject2(options) && typeof options.llamacpp_args === "string") {
10701
+ if (isObject3(options) && typeof options.llamacpp_args === "string") {
10398
10702
  return true;
10399
10703
  }
10400
10704
  return Array.isArray(entry.launch_command) && launchCommandLooksLikeLlamacpp(entry.launch_command);
@@ -10450,10 +10754,57 @@ function enrichWithLoadState(models, loaded) {
10450
10754
  };
10451
10755
  });
10452
10756
  }
10453
- function isObject2(value) {
10757
+ function isObject3(value) {
10454
10758
  return typeof value === "object" && value !== null && !Array.isArray(value);
10455
10759
  }
10456
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
+
10457
10808
  // src/local/lmstudio.ts
10458
10809
  var LMSTUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
10459
10810
  function createLMStudioAdapter() {
@@ -10506,6 +10857,7 @@ class RuntimeRegistry {
10506
10857
  lmstudio: createLMStudioAdapter(),
10507
10858
  "foundry-local": createFoundryLocalAdapter(),
10508
10859
  lemonade: createLemonadeAdapter(),
10860
+ "llama-swap": createLlamaSwapAdapter(),
10509
10861
  ...options.adapters
10510
10862
  };
10511
10863
  this.clock = options.clock;
@@ -10972,7 +11324,7 @@ var TRUNCATED_REASON_SUFFIX = "…[truncated]";
10972
11324
  var MAX_SERIALIZED_ARRAY_ITEMS = 20;
10973
11325
  var MAX_SERIALIZED_OBJECT_PROPERTIES = 25;
10974
11326
  var MAX_SERIALIZED_DEPTH = 4;
10975
- function isObject3(value) {
11327
+ function isObject4(value) {
10976
11328
  return typeof value === "object" && value !== null;
10977
11329
  }
10978
11330
  function isError(value) {
@@ -11002,7 +11354,7 @@ function stringProperty(value, key) {
11002
11354
  }
11003
11355
  function nestedMessage(value, key) {
11004
11356
  const container = safeGet(value, key);
11005
- if (!isObject3(container)) {
11357
+ if (!isObject4(container)) {
11006
11358
  return;
11007
11359
  }
11008
11360
  const message = stringProperty(container, "message");
@@ -11086,7 +11438,7 @@ function errorReason(error) {
11086
11438
  return message;
11087
11439
  }
11088
11440
  }
11089
- if (isObject3(error)) {
11441
+ if (isObject4(error)) {
11090
11442
  const message = stringProperty(error, "message");
11091
11443
  if (message !== undefined) {
11092
11444
  return message;
@@ -11104,7 +11456,7 @@ function errorReason(error) {
11104
11456
  return safeToString(error);
11105
11457
  }
11106
11458
  function isNormalizedSessionFailure(value) {
11107
- return isObject3(value) && safeGet(value, "kind") === "normalized-session-failure" && typeof safeGet(value, "failureClass") === "string" && typeof safeGet(value, "retryable") === "boolean";
11459
+ return isObject4(value) && safeGet(value, "kind") === "normalized-session-failure" && typeof safeGet(value, "failureClass") === "string" && typeof safeGet(value, "retryable") === "boolean";
11108
11460
  }
11109
11461
  function createArgs(req) {
11110
11462
  const body = {};
@@ -11231,7 +11583,7 @@ async function confirmSessionStopped(client, sessionID, directory, deps, deadlin
11231
11583
  return { confirmed: false, cause: "status-error" };
11232
11584
  }
11233
11585
  const statuses = statusOutcome.value;
11234
- if (!isObject3(statuses)) {
11586
+ if (!isObject4(statuses)) {
11235
11587
  return { confirmed: false, cause: "status-error" };
11236
11588
  }
11237
11589
  if (safeGet(statuses, "error") !== undefined) {
@@ -11381,8 +11733,11 @@ async function runSubsession(client, req, deps) {
11381
11733
  }
11382
11734
 
11383
11735
  // src/local/modelResidency.ts
11736
+ function runtimeRequiresModelResidency(kind) {
11737
+ return kind === "lemonade" || kind === "llama-swap";
11738
+ }
11384
11739
  function hasRequiredModelResidency(kind, model) {
11385
- return kind !== "lemonade" || model?.loaded === true;
11740
+ return !runtimeRequiresModelResidency(kind) || model?.loaded === true;
11386
11741
  }
11387
11742
 
11388
11743
  // src/plugin/availability.ts
@@ -11391,9 +11746,9 @@ function modelKey2(model) {
11391
11746
  }
11392
11747
  function availabilityMetadata({
11393
11748
  apiModelID: _apiModelID,
11394
- ...metadata2
11749
+ ...metadata3
11395
11750
  }) {
11396
- return metadata2;
11751
+ return metadata3;
11397
11752
  }
11398
11753
  function compareAvailableModels(left, right) {
11399
11754
  const kindOrder = Number(left.kind === "frontier") - Number(right.kind === "frontier");
@@ -11413,7 +11768,7 @@ function isConfiguredLocalModel(config, model) {
11413
11768
  return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID);
11414
11769
  }
11415
11770
  function requiresModelResidency(config, model) {
11416
- return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID && !hasRequiredModelResidency(localRuntimeKind(runtime), undefined));
11771
+ return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID && runtimeRequiresModelResidency(localRuntimeKind(runtime)));
11417
11772
  }
11418
11773
  function configuredFrontierProviderIDs(config) {
11419
11774
  const providerIDs = new Set([config.baseline.hardDefault.providerID]);
@@ -12039,6 +12394,7 @@ var PROVIDER_LABELS = {
12039
12394
  ollama: "Ollama",
12040
12395
  lmstudio: "LM Studio",
12041
12396
  lemonade: "Lemonade Server",
12397
+ "llama-swap": executionSetupMessages.llamaSwap.label,
12042
12398
  "foundry-local": "Foundry Local"
12043
12399
  };
12044
12400
  function providerLabel(providerID) {
@@ -12260,7 +12616,8 @@ var KNOWN_LOCAL_PROVIDER_IDS = new Set([
12260
12616
  "ollama",
12261
12617
  "lmstudio",
12262
12618
  "foundry-local",
12263
- "lemonade"
12619
+ "lemonade",
12620
+ "llama-swap"
12264
12621
  ]);
12265
12622
  var KNOWN_FRONTIER_PROVIDER_IDS = new Set([
12266
12623
  "github-copilot",
@@ -12606,7 +12963,7 @@ function runtimeLine(snapshot, runtime) {
12606
12963
  const mark = snapshot.reachable ? "✓" : "✗";
12607
12964
  const detail = snapshot.reachable ? `${snapshot.models.length} model(s)` : snapshot.error ?? "unreachable";
12608
12965
  const declared = runtime?.maxConcurrency;
12609
- const slots = declared === undefined ? ` · ${DEFAULT_LOCAL_MAX_CONCURRENCY} slot(s) (default)` : ` · ${declared} slot(s) (declared)`;
12966
+ const slots = declared === undefined ? doctorMessages.defaultRuntimeSlots(effectiveMaxConcurrency(runtime ?? {})) : ` · ${declared} slot(s) (declared)`;
12610
12967
  return ` ${mark} ${snapshot.id.padEnd(14)} ${snapshot.baseURL || "(no baseURL)"} — ${detail}${slots}`;
12611
12968
  }
12612
12969
  function runtimeModelSlotsLine(runtime, snapshot) {
@@ -12618,6 +12975,8 @@ function runtimeModelSlotsLine(runtime, snapshot) {
12618
12975
  if (runtime === undefined || snapshot === undefined || !snapshot.reachable || snapshot.models.length === 0) {
12619
12976
  return [];
12620
12977
  }
12978
+ if (localRuntimeKind(runtime) === "llama-swap")
12979
+ return [doctorMessages.llamaSwapConcurrency];
12621
12980
  const reported = snapshot.models.flatMap((model) => model.slots === undefined ? [] : [`${model.modelID} ${model.slots} slot(s)`]);
12622
12981
  if (reported.length > 0) {
12623
12982
  return [
@@ -13021,7 +13380,7 @@ function renderDoctor(input) {
13021
13380
  continue;
13022
13381
  }
13023
13382
  const runtime = enabledRuntimes.find((r) => r.id === snapshot.id);
13024
- const cap = runtime?.maxConcurrency ?? DEFAULT_LOCAL_MAX_CONCURRENCY;
13383
+ const cap = effectiveMaxConcurrency(runtime ?? {});
13025
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.");
13026
13385
  }
13027
13386
  lines.push(` telemetry: ${input.telemetryPath} — ${input.telemetryRecords} record(s)`);
@@ -13633,6 +13992,38 @@ function missingGeneratedStateRules(gitignore) {
13633
13992
  const present = new Set(activeGitignoreRules(gitignore));
13634
13993
  return OPENCODE_GITIGNORE_GENERATED_STATE_RULES.filter((rule) => !present.has(rule));
13635
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
+ ];
13636
14027
 
13637
14028
  // src/commands/purge.ts
13638
14029
  var PURGE_CATEGORY_IDS = [
@@ -14661,7 +15052,7 @@ function liveModelsFromSnapshots(snapshots, config) {
14661
15052
  map.set(runtime.defaultModel.providerID, {
14662
15053
  reachable: snapshot.reachable,
14663
15054
  modelIDs: new Set(snapshot.models.filter((model) => hasRequiredModelResidency(kind, model)).map((model) => model.modelID)),
14664
- ...kind === "lemonade" ? {
15055
+ ...runtimeRequiresModelResidency(kind) ? {
14665
15056
  residency: new Map(snapshot.models.map((model) => [model.modelID, model.loaded]))
14666
15057
  } : {}
14667
15058
  });
@@ -14991,9 +15382,9 @@ async function runCli(argv, deps) {
14991
15382
  const inventoryNotes = [];
14992
15383
  const readySnapshots = snapshots.map((snapshot) => {
14993
15384
  const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
14994
- if (runtime === undefined || localRuntimeKind(runtime) !== "lemonade")
15385
+ if (runtime === undefined || !runtimeRequiresModelResidency(localRuntimeKind(runtime)))
14995
15386
  return snapshot;
14996
- 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"));
14997
15388
  return {
14998
15389
  ...snapshot,
14999
15390
  models: snapshot.models.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model))
@@ -15004,7 +15395,7 @@ async function runCli(argv, deps) {
15004
15395
  if (agent.model === undefined || live !== "not-loaded" && live !== "residency-unknown")
15005
15396
  return [];
15006
15397
  return [
15007
- 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")
15008
15399
  ];
15009
15400
  });
15010
15401
  return {
@@ -17234,6 +17625,84 @@ function createLemonadeGuardedFetch(options) {
17234
17625
  });
17235
17626
  }
17236
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
+
17237
17706
  // src/plugin/modelResidency.ts
17238
17707
  function isFetch(value) {
17239
17708
  return typeof value === "function";
@@ -17273,20 +17742,29 @@ function providerRoutes(provider) {
17273
17742
  npm: model?.provider?.npm ?? provider.npm
17274
17743
  }));
17275
17744
  }
17276
- function wireID(key, model) {
17745
+ function wireID(key, model, runtimeLabel = "Lemonade") {
17277
17746
  const id = model?.id ?? key;
17278
17747
  if (id.length === 0 || id !== id.trim())
17279
- throw new ModelResidencyError("identity");
17748
+ throw new ModelResidencyError("identity", runtimeLabel);
17280
17749
  return id;
17281
17750
  }
17282
17751
  function nativeEligibleID(id) {
17283
17752
  return id === "openai" || id === "anthropic" || id.startsWith("opencode");
17284
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
+ }
17285
17763
  function configuredRuntime(config, providerID) {
17286
17764
  const runtimes = config.local.runtimes.filter((runtime2) => runtime2.defaultModel.providerID === providerID);
17287
17765
  const runtime = runtimes[0];
17288
17766
  if (runtimes.length !== 1 || runtime === undefined || !runtime.enabled) {
17289
- throw new ModelResidencyError("destination");
17767
+ throw new ModelResidencyError("destination", residencyRuntimeLabel(config, providerID));
17290
17768
  }
17291
17769
  return runtime;
17292
17770
  }
@@ -17295,8 +17773,9 @@ function createModelResidencyGuard(config, options) {
17295
17773
  const blocked = new Set;
17296
17774
  let hostConfig;
17297
17775
  const readEnv = options.readEnv ?? ((name) => process.env[name]);
17298
- const lemonadeRuntimes = () => config.local.runtimes.filter((runtime) => localRuntimeKind(runtime) === "lemonade");
17299
- const protects = (providerID, baseURL) => lemonadeRuntimes().some((runtime) => {
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) => {
17300
17779
  if (runtime.defaultModel.providerID === providerID)
17301
17780
  return true;
17302
17781
  if (baseURL === undefined)
@@ -17304,13 +17783,13 @@ function createModelResidencyGuard(config, options) {
17304
17783
  const binding = endpointBinding(baseURL, readEnv);
17305
17784
  if (binding.ambiguous)
17306
17785
  return true;
17307
- return binding.origin !== undefined && binding.origin === origin(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
17786
+ return binding.origin !== undefined && binding.origin === origin(runtimeBase(runtime));
17308
17787
  });
17309
17788
  const resolvedWireID = (model, declaredID) => {
17310
17789
  const id = options.resolveApiModelID === undefined ? declaredID : options.resolveApiModelID(model);
17311
17790
  if (id === undefined)
17312
- throw new ModelResidencyError("identity");
17313
- return wireID(id, undefined);
17791
+ throw failure("identity", model.providerID);
17792
+ return wireID(id, undefined, residencyRuntimeLabel(config, model.providerID));
17314
17793
  };
17315
17794
  const configHook = async (host) => {
17316
17795
  hostConfig = host;
@@ -17330,21 +17809,22 @@ function createModelResidencyGuard(config, options) {
17330
17809
  ...new Set([...host.disabled_providers ?? [], providerID])
17331
17810
  ];
17332
17811
  const reject = Object.assign(async () => {
17333
- throw new ModelResidencyError("transport");
17812
+ throw failure("transport", providerID);
17334
17813
  }, { preconnect: () => {} });
17335
17814
  provider.options = { ...provider.options, fetch: reject };
17336
17815
  try {
17337
17816
  const runtime = configuredRuntime(config, providerID);
17338
- const baseURL = lemonadeBaseURL(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
17339
- if (localRuntimeKind(runtime) !== "lemonade" || routes.some((route) => route.baseURL === undefined || lemonadeBaseURL(route.baseURL) !== baseURL))
17340
- throw new ModelResidencyError("destination");
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);
17341
17821
  if (routes.some((route) => route.npm !== "@ai-sdk/openai-compatible") || nativeEligibleID(providerID) || !isFetch(originalFetch))
17342
- throw new ModelResidencyError("transport");
17822
+ throw failure("transport", providerID);
17343
17823
  const modelKeys = new Map;
17344
17824
  for (const [key, model] of Object.entries(provider.models ?? {})) {
17345
- if (model.options?.fetch !== undefined || model.options?.baseURL !== undefined && (typeof model.options.baseURL !== "string" || lemonadeBaseURL(model.options.baseURL) !== baseURL))
17346
- throw new ModelResidencyError("transport");
17347
- 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)));
17348
17828
  }
17349
17829
  if (!modelKeys.has(runtime.defaultModel.modelID))
17350
17830
  modelKeys.set(runtime.defaultModel.modelID, undefined);
@@ -17353,11 +17833,12 @@ function createModelResidencyGuard(config, options) {
17353
17833
  for (const [modelID2, declaredID] of modelKeys) {
17354
17834
  const id = options.resolveApiModelID === undefined ? declaredID : options.resolveApiModelID({ providerID, modelID: modelID2 });
17355
17835
  if (id !== undefined)
17356
- ids.add(wireID(id, undefined));
17836
+ ids.add(wireID(id, undefined, residencyRuntimeLabel(config, providerID)));
17357
17837
  }
17358
17838
  return ids;
17359
17839
  };
17360
- const fetch = createLemonadeGuardedFetch({
17840
+ const guardFetch = kind === "llama-swap" ? createLlamaSwapGuardedFetch : createLemonadeGuardedFetch;
17841
+ const fetch = guardFetch({
17361
17842
  ...options,
17362
17843
  baseURL,
17363
17844
  modelIDs: async () => {
@@ -17368,7 +17849,10 @@ function createModelResidencyGuard(config, options) {
17368
17849
  healthFetch: options.fetch
17369
17850
  });
17370
17851
  provider.options.fetch = fetch;
17852
+ if (kind === "llama-swap")
17853
+ provider.options.baseURL = baseURL;
17371
17854
  guarded.set(providerID, {
17855
+ kind,
17372
17856
  baseURL,
17373
17857
  fetch,
17374
17858
  originalFetch,
@@ -17382,7 +17866,7 @@ function createModelResidencyGuard(config, options) {
17382
17866
  } catch (error) {
17383
17867
  if (!(error instanceof ModelResidencyError))
17384
17868
  throw error;
17385
- (options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(providerID));
17869
+ (options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(providerID, residencyRuntimeLabel(config, providerID)));
17386
17870
  }
17387
17871
  }
17388
17872
  };
@@ -17392,48 +17876,52 @@ function createModelResidencyGuard(config, options) {
17392
17876
  return;
17393
17877
  const provider = guarded.get(input.model.providerID);
17394
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))
17395
- throw new ModelResidencyError("transport");
17396
- if (lemonadeBaseURL(base) !== provider.baseURL) {
17397
- throw new ModelResidencyError("destination");
17879
+ throw failure("transport", input.model.providerID);
17880
+ if (normalizedBase(provider.kind, base) !== provider.baseURL) {
17881
+ throw failure("destination", input.model.providerID);
17398
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);
17399
17885
  const id = resolvedWireID({ providerID: input.model.providerID, modelID: input.model.id }, provider.modelKeys.get(input.model.id));
17400
17886
  if (id !== input.model.api.id)
17401
- throw new ModelResidencyError("identity");
17887
+ throw failure("identity", input.model.providerID);
17402
17888
  if (!provider.modelKeys.has(input.model.id))
17403
17889
  provider.modelKeys.set(input.model.id, undefined);
17404
17890
  };
17405
17891
  const localTarget = (model) => {
17406
17892
  const runtime = configuredRuntime(config, model.providerID);
17893
+ const kind = localRuntimeKind(runtime);
17894
+ const needsResidency = runtimeRequiresModelResidency(kind);
17407
17895
  if (hostConfig?.disabled_providers?.includes(model.providerID)) {
17408
- throw new ModelResidencyError("transport");
17896
+ throw failure("transport", model.providerID);
17409
17897
  }
17410
17898
  if (runtime.baseURL === undefined)
17411
- throw new ModelResidencyError("destination");
17899
+ throw failure("destination", model.providerID);
17412
17900
  const provider = hostConfig?.provider?.[model.providerID];
17413
17901
  const entry = Object.hasOwn(provider?.models ?? {}, model.modelID) ? provider?.models?.[model.modelID] : undefined;
17414
17902
  const configuredURL = provider === undefined ? undefined : providerBase(provider, entry);
17415
- if (configuredURL !== undefined && new URL(configuredURL).href.replace(/\/$/, "") !== new URL(runtime.baseURL).href.replace(/\/$/, "")) {
17416
- throw new ModelResidencyError("destination");
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);
17417
17905
  }
17418
- const modelID2 = resolvedWireID(model, entry === undefined && localRuntimeKind(runtime) === "lemonade" ? undefined : wireID(model.modelID, entry));
17906
+ const modelID2 = resolvedWireID(model, entry === undefined && needsResidency ? undefined : wireID(model.modelID, entry, residencyRuntimeLabel(config, model.providerID)));
17419
17907
  let fetch = options.fetch;
17420
- if (localRuntimeKind(runtime) === "lemonade") {
17908
+ if (needsResidency) {
17421
17909
  const installed = guarded.get(model.providerID);
17422
17910
  if (installed === undefined || blocked.has(model.providerID)) {
17423
- throw new ModelResidencyError("transport");
17911
+ throw failure("transport", model.providerID);
17424
17912
  }
17425
- if (installed.baseURL !== lemonadeBaseURL(runtime.baseURL)) {
17426
- throw new ModelResidencyError("destination");
17913
+ if (installed.baseURL !== normalizedBase(kind, runtime.baseURL)) {
17914
+ throw failure("destination", model.providerID);
17427
17915
  }
17428
17916
  if (!installed.modelKeys.has(model.modelID))
17429
17917
  installed.modelKeys.set(model.modelID, undefined);
17430
17918
  if (!installed.modelIDs().has(modelID2))
17431
- throw new ModelResidencyError("identity");
17919
+ throw failure("identity", model.providerID);
17432
17920
  fetch = installed.fetch;
17433
17921
  }
17434
17922
  const configuredHeaders = z25.record(z25.string(), z25.string()).safeParse(provider?.options?.headers ?? {});
17435
17923
  if (!configuredHeaders.success)
17436
- throw new ModelResidencyError("configuration");
17924
+ throw failure("configuration", model.providerID);
17437
17925
  const headers = new Headers(configuredHeaders.data);
17438
17926
  if (typeof provider?.options?.apiKey === "string" && !headers.has("authorization")) {
17439
17927
  headers.set("authorization", `Bearer ${provider.options.apiKey}`);
@@ -17442,7 +17930,7 @@ function createModelResidencyGuard(config, options) {
17442
17930
  headers.set(name, value);
17443
17931
  const upstream = fetch;
17444
17932
  return {
17445
- baseURL: runtime.baseURL,
17933
+ baseURL: needsResidency ? normalizedBase(kind, runtime.baseURL) : runtime.baseURL,
17446
17934
  modelID: modelID2,
17447
17935
  fetch: [...headers].length === 0 ? fetch : Object.assign(async (input, init) => {
17448
17936
  const request = new Request(input, init);
@@ -18565,7 +19053,7 @@ var memoryToolMessages = {
18565
19053
  scribeOnly: (actualRoleID) => `openteam memory: refused — memory records may only be written by the "scribe" role, not "${actualRoleID}".`,
18566
19054
  disabled: "openteam memory: semantic memory is disabled; nothing was recorded.",
18567
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.',
18568
- 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`.",
18569
19057
  localRuntimeBaseURLMissing: "openteam memory: refused — no local runtime with a base URL is configured and enabled; memory extraction is local-only.",
18570
19058
  extractionFailure: (reason) => `openteam memory: extraction failed; nothing was recorded (${reason}).`,
18571
19059
  noRecords: "openteam memory: no records were extracted; nothing was recorded.",
@@ -18635,14 +19123,16 @@ function createMemoryTool(deps) {
18635
19123
  if (runtime?.baseURL === undefined || runtime.baseURL.length === 0) {
18636
19124
  return memoryToolMessages.localRuntimeBaseURLMissing;
18637
19125
  }
18638
- const baseURL = runtime.baseURL;
19126
+ const kind = localRuntimeKind(runtime);
19127
+ const baseURL = kind === "llama-swap" ? llamaSwapBaseURL(runtime.baseURL) : runtime.baseURL;
18639
19128
  const model = configuredModel ?? runtime.defaultModel;
18640
19129
  const selectedRuntime = runtime;
18641
19130
  const deadline = {
18642
19131
  ...deps.residencyOptions,
19132
+ ...kind === "llama-swap" ? { runtimeLabel: "llama-swap" } : {},
18643
19133
  ...signal === undefined ? {} : { signal }
18644
19134
  };
18645
- const reachable = localRuntimeKind(runtime) === "lemonade" ? await withResidencyDeadline((signal2) => deps.localRuntimeReachable(selectedRuntime, signal2), deadline) : await deps.localRuntimeReachable(runtime);
19135
+ const reachable = runtimeRequiresModelResidency(kind) ? await withResidencyDeadline((signal2) => deps.localRuntimeReachable(selectedRuntime, signal2), deadline) : await deps.localRuntimeReachable(runtime);
18646
19136
  throwIfAborted();
18647
19137
  if (!reachable)
18648
19138
  return memoryToolMessages.localRuntimeUnavailable;
@@ -18650,7 +19140,7 @@ function createMemoryTool(deps) {
18650
19140
  const target = resolveTarget ? await withResidencyDeadline(async () => resolveTarget(model), deadline) : {
18651
19141
  baseURL,
18652
19142
  modelID: model.modelID,
18653
- fetch: localRuntimeKind(runtime) === "lemonade" ? createLemonadeGuardedFetch({
19143
+ fetch: runtimeRequiresModelResidency(kind) ? (kind === "llama-swap" ? createLlamaSwapGuardedFetch : createLemonadeGuardedFetch)({
18654
19144
  baseURL,
18655
19145
  fetch: deps.fetch,
18656
19146
  modelIDs: new Set([model.modelID]),
@@ -21569,6 +22059,13 @@ function createLocalEmbedder(request, deps) {
21569
22059
  return (texts) => embedTexts({ ...request, texts }, deps);
21570
22060
  }
21571
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
+
21572
22069
  // src/storage/index/bunSqlite.ts
21573
22070
  async function createBunSqliteDatabase(path4) {
21574
22071
  const mod = await import("bun:sqlite");
@@ -21652,7 +22149,14 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
21652
22149
  if (options.requireInjectionEnabled === true && !semantic.injection.enabled) {
21653
22150
  return;
21654
22151
  }
21655
- const runtime = config.local.runtimes.find((rt) => rt.enabled && rt.baseURL !== undefined);
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
+ }
21656
22160
  if (runtime?.baseURL === undefined) {
21657
22161
  return;
21658
22162
  }
@@ -21661,15 +22165,22 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
21661
22165
  const makeEmbedder = deps.createEmbedder ?? createLocalEmbedder;
21662
22166
  const fetchImpl = deps.fetch ?? globalThis.fetch;
21663
22167
  const now = deps.now ?? (() => Date.now());
21664
- const warn = deps.warn ?? console.warn;
22168
+ const kind = localRuntimeKind(runtime);
21665
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;
21666
22177
  const db = await openDatabase(semantic.indexPath);
21667
22178
  const index = createMemoryIndex(db, warn);
21668
22179
  const rebuildResult = await rebuildMemoryIndexFromStorage(index, semantic.logPath, { storage: deps.storage });
21669
22180
  if (rebuildResult.rejectedLines > 0) {
21670
- warn(`[openteam] memory log rejected ${rebuildResult.rejectedLines} line(s); semantic memory may be incomplete.`);
22181
+ warn(memoryRuntimeMessages.rejectedLines(rebuildResult.rejectedLines));
21671
22182
  }
21672
- const embedder = makeEmbedder({ baseURL: runtime.baseURL, modelID: modelID2 }, { fetch: fetchImpl });
22183
+ const embedder = makeEmbedder({ baseURL, modelID: modelID2 }, { fetch: guardedFetch });
21673
22184
  await ensureMemoryEmbeddings({ index, embedder, model: modelID2, warn });
21674
22185
  return {
21675
22186
  index,
@@ -21679,6 +22190,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
21679
22190
  semantic
21680
22191
  };
21681
22192
  } catch {
22193
+ warn(memoryRuntimeMessages.unavailable);
21682
22194
  return;
21683
22195
  }
21684
22196
  }
@@ -22049,8 +22561,8 @@ function readRun(runDir, runID) {
22049
22561
  if (metadataText === undefined || eventsText === undefined) {
22050
22562
  throw new LifecycleFsError("corrupt");
22051
22563
  }
22052
- const metadata2 = parseJson(metadataText, parseLifecycleRunMetadata);
22053
- if (metadata2.runID !== runID) {
22564
+ const metadata3 = parseJson(metadataText, parseLifecycleRunMetadata);
22565
+ if (metadata3.runID !== runID) {
22054
22566
  throw new LifecycleFsError("corrupt");
22055
22567
  }
22056
22568
  let decoded;
@@ -22065,10 +22577,10 @@ function readRun(runDir, runID) {
22065
22577
  }
22066
22578
  }
22067
22579
  const first = decoded.events[0];
22068
- if (first === undefined || first.type !== "run.started" || first.source !== metadata2.source || first.executionAuthority !== metadata2.executionAuthority || first.root.operationID !== metadata2.root.operationID || first.root.taskID !== metadata2.root.taskID) {
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) {
22069
22581
  throw new LifecycleFsError("corrupt");
22070
22582
  }
22071
- return { metadata: metadata2, decoded };
22583
+ return { metadata: metadata3, decoded };
22072
22584
  }
22073
22585
  function terminalOutcome(events) {
22074
22586
  const last = events.at(-1);
@@ -22146,7 +22658,7 @@ var createFsLifecycleJournal = (options) => {
22146
22658
  mkdirSync3(stagingPath);
22147
22659
  const writerToken = issueWriterToken();
22148
22660
  const eventAt = now();
22149
- const metadata2 = parseLifecycleRunMetadata({
22661
+ const metadata3 = parseLifecycleRunMetadata({
22150
22662
  ...parsedInput,
22151
22663
  version: 1,
22152
22664
  createdAt: eventAt
@@ -22162,7 +22674,7 @@ var createFsLifecycleJournal = (options) => {
22162
22674
  executionAuthority: parsedInput.executionAuthority,
22163
22675
  root: parsedInput.root
22164
22676
  });
22165
- writeDurable2(join15(stagingPath, METADATA_FILE), `${JSON.stringify(metadata2)}
22677
+ writeDurable2(join15(stagingPath, METADATA_FILE), `${JSON.stringify(metadata3)}
22166
22678
  `);
22167
22679
  writeDurable2(join15(stagingPath, EVENTS_FILE), encodeLifecycleJournal([event]));
22168
22680
  writeDurable2(join15(stagingPath, OWNER_FILE2), `${JSON.stringify(lease)}
@@ -22178,7 +22690,7 @@ var createFsLifecycleJournal = (options) => {
22178
22690
  stagingPath = undefined;
22179
22691
  return ok({
22180
22692
  handle: { runID, writerToken },
22181
- metadata: metadata2,
22693
+ metadata: metadata3,
22182
22694
  event,
22183
22695
  lease,
22184
22696
  head: 1
@@ -23299,6 +23811,20 @@ var server = async (ctx, rawOptions) => {
23299
23811
  storage,
23300
23812
  now,
23301
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
+ }
23302
23828
  if (localRuntimeKind(runtime) === "lemonade") {
23303
23829
  if (ctx.client.config?.providers !== undefined)
23304
23830
  await ensureAvailability();