@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/cli.js CHANGED
@@ -687,7 +687,8 @@ var LocalRuntimeKindSchema = z2.enum([
687
687
  "ollama",
688
688
  "lmstudio",
689
689
  "foundry-local",
690
- "lemonade"
690
+ "lemonade",
691
+ "llama-swap"
691
692
  ]);
692
693
  var LocalRuntimeSchema = z2.object({
693
694
  id: z2.string().min(1),
@@ -707,13 +708,26 @@ var LocalRuntimeSchema = z2.object({
707
708
  ctx.addIssue({
708
709
  code: z2.ZodIssueCode.custom,
709
710
  path: ["kind"],
710
- 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."
711
+ 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."
711
712
  });
712
713
  }
714
+ }).transform((runtime) => {
715
+ const resolvedKind = runtime.kind ?? runtime.id;
716
+ if (resolvedKind !== "llama-swap" || runtime.maxConcurrency !== undefined) {
717
+ return runtime;
718
+ }
719
+ return { ...runtime, maxConcurrency: 1 };
713
720
  });
714
721
  function localRuntimeKind(runtime) {
715
722
  return runtime.kind ?? runtime.id;
716
723
  }
724
+ function effectiveMaxConcurrency(runtime) {
725
+ if (runtime.maxConcurrency !== undefined) {
726
+ return runtime.maxConcurrency;
727
+ }
728
+ const kind = runtime.kind ?? (runtime.id !== undefined && LocalRuntimeKindSchema.safeParse(runtime.id).success ? runtime.id : undefined);
729
+ return kind === "llama-swap" ? 1 : DEFAULT_LOCAL_MAX_CONCURRENCY;
730
+ }
717
731
  var MemoryScopeSchema = z2.enum(["project", "user"]);
718
732
  var MemoryExtractionModeSchema = z2.enum([
719
733
  "local",
@@ -3411,6 +3425,23 @@ var executionSetupMessages = {
3411
3425
  `),
3412
3426
  localOnlyTitle: "Local execution",
3413
3427
  localRequiredError: "local execution requires an enabled local runtime",
3428
+ llamaSwap: {
3429
+ label: "llama-swap",
3430
+ 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.",
3431
+ modelNotLoaded: (model) => `llama-swap model "${model}" is not positively verified as canonical and ready without an active routing profile. No substitute was selected.`,
3432
+ probeRequired: "llama-swap setup requires a fresh read-only residency probe before writing configuration. Manual model IDs cannot bypass this requirement.",
3433
+ 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.",
3434
+ endpointMismatch: "llama-swap endpoint/provider mapping differs from the selected runtime. Reconcile the configured origin or /v1 URL and provider; no configuration was written.",
3435
+ modelIdentityUnknown: (model) => `llama-swap model "${model}" has no usable registered physical identity. Fix its model declaration; setup will not guess an alias.`,
3436
+ 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.",
3437
+ declaredLimitsTitle: "Declared llama-swap limits",
3438
+ outputReduction: (model, previous, ceiling) => `${model}: reducing limit.output from ${previous} to ${ceiling} to respect the declared runtime ceiling. Smaller operator limits are preserved.`,
3439
+ outputReductionTitle: "Declared output ceiling",
3440
+ 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.`
3441
+ },
3442
+ residencyV2Title: "Resident runtime transport compatibility",
3443
+ 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.`,
3444
+ 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.`,
3414
3445
  lemonadeDetectedHint: (loaded, advertised) => `detected - ${loaded} confirmed loaded of ${advertised} advertised text model(s)`,
3415
3446
  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.",
3416
3447
  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.`,
@@ -3425,11 +3456,11 @@ var executionSetupMessages = {
3425
3456
  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.",
3426
3457
  lemonadeV2Title: "Lemonade transport compatibility",
3427
3458
  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.`,
3428
- lemonadeInventory: (instanceID, providerID, models) => {
3459
+ lemonadeInventory: (instanceID, providerID, models, runtime = "Lemonade") => {
3429
3460
  const inventory = models.map((model) => `${model.modelID} (${model.loaded === true ? "loaded" : model.loaded === false ? "inactive" : "residency unknown"})`).join(", ");
3430
- return `Lemonade inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
3461
+ return `${runtime} inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
3431
3462
  },
3432
- 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.`,
3463
+ 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.`,
3433
3464
  mixedPrimaryQuestion: "Primary coordinator model",
3434
3465
  mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
3435
3466
  mixedPrimaryFrontier: "Choose a frontier model",
@@ -3533,6 +3564,8 @@ var executionPolicyMessages = {
3533
3564
  primaryLocalMismatchRemedy: (sourceFile) => ` remedy: re-run \`openteam setup\` to regenerate ${sourceFile} and opencode.json from the same primary policy, then re-run \`openteam doctor\`.`
3534
3565
  };
3535
3566
  var doctorMessages = {
3567
+ defaultRuntimeSlots: (slots) => ` · ${slots} slot(s) (default)`,
3568
+ llamaSwapConcurrency: " llama-swap does not report per-model slots; openteam uses the configured runtime-wide concurrency limit. No per-model capacity was inferred.",
3536
3569
  localModelLimits: {
3537
3570
  section: " local model limits:",
3538
3571
  healthy: " ✓ enabled local provider models declare valid output and context limits in opencode.json.",
@@ -3549,7 +3582,7 @@ var doctorMessages = {
3549
3582
  invalidInput: "invalid limit.input (expected a positive integer token count)",
3550
3583
  outputExceedsContext: "limit.output is greater than or equal to limit.context, so the configured context leaves no usable input window",
3551
3584
  outputExceedsInput: "limit.input is less than or equal to the reserved output budget, so compaction would have no usable input threshold",
3552
- outputRemedy: " remedy: re-run `openteam setup` to write openteam's 8 192-token local output default, then re-run `openteam doctor`.",
3585
+ 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`.",
3553
3586
  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`.",
3554
3587
  detectedContextRemedy: " remedy: re-run `openteam setup` while the runtime is reachable to copy the detected usable context budget, then re-run `openteam doctor`.",
3555
3588
  unknownContextRemedy: " remedy: re-run `openteam setup` to write the required context:0 sentinel; automatic compaction remains disabled until a positive context is configured.",
@@ -9183,6 +9216,7 @@ var PROVIDER_LABELS = {
9183
9216
  ollama: "Ollama",
9184
9217
  lmstudio: "LM Studio",
9185
9218
  lemonade: "Lemonade Server",
9219
+ "llama-swap": executionSetupMessages.llamaSwap.label,
9186
9220
  "foundry-local": "Foundry Local"
9187
9221
  };
9188
9222
  function providerLabel(providerID) {
@@ -9404,7 +9438,8 @@ var KNOWN_LOCAL_PROVIDER_IDS = new Set([
9404
9438
  "ollama",
9405
9439
  "lmstudio",
9406
9440
  "foundry-local",
9407
- "lemonade"
9441
+ "lemonade",
9442
+ "llama-swap"
9408
9443
  ]);
9409
9444
  var KNOWN_FRONTIER_PROVIDER_IDS = new Set([
9410
9445
  "github-copilot",
@@ -16212,6 +16247,7 @@ var reasons = {
16212
16247
  unknown: "fresh residency metadata is unavailable, malformed, or ambiguous",
16213
16248
  inactive: "the requested model is not verified as resident and serving",
16214
16249
  identity: "the requested model identity can be rewritten or is ambiguous",
16250
+ "authentication-unsupported": "authentication is required but unsupported by this integration",
16215
16251
  destination: "the request destination does not match its configured runtime",
16216
16252
  transport: "this provider execution path cannot enforce the residency guard",
16217
16253
  request: "this is not a supported, explicit model inference request",
@@ -16220,22 +16256,72 @@ var reasons = {
16220
16256
  configuration: "the residency guard configuration is invalid"
16221
16257
  };
16222
16258
  var modelResidencyMessages = {
16223
- blocked: (reason) => `[openteam] Lemonade model request blocked: ${reasons[reason]}.`,
16224
- providerDisabled: (providerID) => `[openteam] Lemonade provider "${providerID}" is disabled because its configured transport or runtime mapping cannot enforce loaded-only requests.`,
16225
- extractionRuntimeUnavailable: "[openteam] Memory extraction requires one enabled local runtime matching the configured extraction provider."
16259
+ blocked: (reason, runtimeLabel = "Lemonade", detail) => `[openteam] ${runtimeLabel} model request blocked: ${reasons[reason]}${detail === undefined ? "" : ` (${detail})`}.`,
16260
+ providerDisabled: (providerID, runtimeLabel = "Lemonade") => `[openteam] ${runtimeLabel} provider "${providerID}" is disabled because its configured transport or runtime mapping cannot enforce loaded-only requests.`,
16261
+ extractionRuntimeUnavailable: "[openteam] Memory extraction requires one enabled local runtime matching the configured extraction provider.",
16262
+ extractionRuntimeUnavailableFor: (runtimeLabel) => `[openteam] Memory extraction requires one enabled ${runtimeLabel} local runtime matching the configured extraction provider.`
16263
+ };
16264
+ var llamaSwapResidencyMessages = {
16265
+ catalogModelDetail: (id, detail) => `catalog model "${id}" ${detail}`,
16266
+ invalidCatalogField: (field) => `declares an invalid ${field}`,
16267
+ catalogEntryMustExposeStringId: "catalog entries must expose a string id",
16268
+ catalogModelIdsMustBeNonEmptyTrimmedStrings: "catalog model ids must be non-empty, trimmed strings",
16269
+ expectedDataArray: (path) => `GET ${path} must return an object with a data array`,
16270
+ duplicateCanonicalModelId: (modelID, path) => `duplicate canonical model id "${modelID}" in ${path}`,
16271
+ httpFailure: (path, status) => `GET ${path} failed with HTTP ${status}`,
16272
+ unverifiableResponse: (path) => `GET ${path} failed before a verifiable response`,
16273
+ expectedProfilesArray: (path) => `GET ${path} must return an object with a profiles array`,
16274
+ activeProfileRewrite: (profile) => `active profile "${profile}" can rewrite canonical model routing`,
16275
+ invalidActiveProfileValue: (path) => `GET ${path} reported an invalid active profile value`,
16276
+ expectedRunningArray: (path) => `GET ${path} must return an object with a running array`,
16277
+ malformedRunningEvidence: (path) => `GET ${path} returned malformed model/state evidence`,
16278
+ duplicateRunningEvidence: (path, modelID) => `GET ${path} returned duplicate evidence for "${modelID}"`
16226
16279
  };
16227
16280
 
16228
- // src/local/lemonadeResidency.ts
16281
+ // src/local/residency.ts
16229
16282
  class ModelResidencyError extends Error {
16230
16283
  code;
16231
16284
  statusCode = 400;
16232
16285
  isRetryable = false;
16233
- constructor(code) {
16234
- super(modelResidencyMessages.blocked(code));
16286
+ constructor(code, runtimeLabel = "Lemonade", detail) {
16287
+ super(modelResidencyMessages.blocked(code, runtimeLabel, detail));
16235
16288
  this.code = code;
16236
16289
  this.name = "ModelResidencyError";
16237
16290
  }
16238
16291
  }
16292
+ async function withResidencyDeadline(operation, options) {
16293
+ const timeoutMs = options.timeoutMs ?? 5000;
16294
+ const runtimeLabel = options.runtimeLabel;
16295
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
16296
+ throw new ModelResidencyError("configuration", runtimeLabel);
16297
+ }
16298
+ const controller = new AbortController;
16299
+ const cancel = () => controller.abort(new ModelResidencyError("cancelled", runtimeLabel));
16300
+ if (options.signal?.aborted)
16301
+ throw new ModelResidencyError("cancelled", runtimeLabel);
16302
+ options.signal?.addEventListener("abort", cancel, { once: true });
16303
+ const schedule = options.scheduleTimeout ?? ((callback, ms2) => {
16304
+ const timer = setTimeout(callback, ms2);
16305
+ return () => clearTimeout(timer);
16306
+ });
16307
+ let onAbort = () => {};
16308
+ const aborted = new Promise((_, reject) => {
16309
+ onAbort = () => reject(controller.signal.reason);
16310
+ controller.signal.addEventListener("abort", onAbort, { once: true });
16311
+ });
16312
+ const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout", runtimeLabel)), timeoutMs);
16313
+ try {
16314
+ controller.signal.throwIfAborted();
16315
+ return await Promise.race([operation(controller.signal), aborted]);
16316
+ } finally {
16317
+ clearTimer();
16318
+ options.signal?.removeEventListener("abort", cancel);
16319
+ controller.signal.removeEventListener("abort", onAbort);
16320
+ controller.abort();
16321
+ }
16322
+ }
16323
+
16324
+ // src/local/lemonadeResidency.ts
16239
16325
  var modelName = z22.string().min(1).refine((name) => name === name.trim());
16240
16326
  var LoadedModelSchema = z22.object({
16241
16327
  model_name: modelName,
@@ -16372,36 +16458,6 @@ function lemonadeBaseURL(value) {
16372
16458
  }
16373
16459
  return `${url.origin}${url.pathname.replace(/\/$/, "")}`;
16374
16460
  }
16375
- async function withResidencyDeadline(operation, options) {
16376
- const timeoutMs = options.timeoutMs ?? 5000;
16377
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
16378
- throw new ModelResidencyError("configuration");
16379
- }
16380
- const controller = new AbortController;
16381
- const cancel = () => controller.abort(new ModelResidencyError("cancelled"));
16382
- if (options.signal?.aborted)
16383
- throw new ModelResidencyError("cancelled");
16384
- options.signal?.addEventListener("abort", cancel, { once: true });
16385
- const schedule = options.scheduleTimeout ?? ((callback, ms2) => {
16386
- const timer = setTimeout(callback, ms2);
16387
- return () => clearTimeout(timer);
16388
- });
16389
- let onAbort = () => {};
16390
- const aborted = new Promise((_, reject) => {
16391
- onAbort = () => reject(controller.signal.reason);
16392
- controller.signal.addEventListener("abort", onAbort, { once: true });
16393
- });
16394
- const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout")), timeoutMs);
16395
- try {
16396
- controller.signal.throwIfAborted();
16397
- return await Promise.race([operation(controller.signal), aborted]);
16398
- } finally {
16399
- clearTimer();
16400
- options.signal?.removeEventListener("abort", cancel);
16401
- controller.signal.removeEventListener("abort", onAbort);
16402
- controller.abort();
16403
- }
16404
- }
16405
16461
  async function metadata(url, fetch2, signal, headers) {
16406
16462
  signal.throwIfAborted();
16407
16463
  let payload;
@@ -16705,9 +16761,314 @@ function isObject2(value) {
16705
16761
  return typeof value === "object" && value !== null && !Array.isArray(value);
16706
16762
  }
16707
16763
 
16764
+ // src/local/llamaSwapResidency.ts
16765
+ function isObject3(value) {
16766
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16767
+ }
16768
+ function readPositiveSafeInteger(value) {
16769
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
16770
+ }
16771
+ function readSupportsTools2(model) {
16772
+ const direct = readBoolean2(model, [
16773
+ "tool_call",
16774
+ "tool_calls",
16775
+ "toolCalling",
16776
+ "supportsToolCalling",
16777
+ "supports_tools",
16778
+ "supportsTools"
16779
+ ]);
16780
+ if (direct !== undefined) {
16781
+ return direct;
16782
+ }
16783
+ const capabilities = readCapabilityBoolean2(model.capabilities);
16784
+ if (capabilities !== undefined) {
16785
+ return capabilities;
16786
+ }
16787
+ const features = readCapabilityBoolean2(model.features);
16788
+ if (features !== undefined) {
16789
+ return features;
16790
+ }
16791
+ const labels = readCapabilityBoolean2(model.labels);
16792
+ if (labels !== undefined) {
16793
+ return labels;
16794
+ }
16795
+ return "unknown";
16796
+ }
16797
+ function readCapabilityBoolean2(value) {
16798
+ if (Array.isArray(value)) {
16799
+ if (value.some((entry) => typeof entry === "string" && ["tools", "tool_call", "tool-calling", "function_calling"].includes(entry))) {
16800
+ return true;
16801
+ }
16802
+ return;
16803
+ }
16804
+ if (!isObject3(value)) {
16805
+ return;
16806
+ }
16807
+ return readBoolean2(value, [
16808
+ "tools",
16809
+ "tool_call",
16810
+ "tool_calls",
16811
+ "toolCalling",
16812
+ "function_calling",
16813
+ "supportsToolCalling"
16814
+ ]);
16815
+ }
16816
+ function readBoolean2(value, keys) {
16817
+ for (const key of keys) {
16818
+ if (typeof value[key] === "boolean") {
16819
+ return value[key];
16820
+ }
16821
+ }
16822
+ return;
16823
+ }
16824
+ function modelDetail(id, detail) {
16825
+ return llamaSwapResidencyMessages.catalogModelDetail(id, detail);
16826
+ }
16827
+ function llamaSwapBaseURL(value) {
16828
+ let url;
16829
+ try {
16830
+ url = new URL(value);
16831
+ } catch {
16832
+ throw new ModelResidencyError("destination", "llama-swap");
16833
+ }
16834
+ if (url.protocol !== "http:" && url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "") {
16835
+ throw new ModelResidencyError("destination", "llama-swap");
16836
+ }
16837
+ if (url.pathname === "/" || url.pathname === "") {
16838
+ return `${url.origin}/v1`;
16839
+ }
16840
+ if (url.pathname === "/v1" || url.pathname === "/v1/") {
16841
+ return `${url.origin}/v1`;
16842
+ }
16843
+ throw new ModelResidencyError("destination", "llama-swap");
16844
+ }
16845
+ function parseCanonicalType(entry, id) {
16846
+ if (!isObject3(entry.meta) || !isObject3(entry.meta.llamaswap)) {
16847
+ return;
16848
+ }
16849
+ const type = entry.meta.llamaswap.type;
16850
+ if (type === undefined) {
16851
+ return;
16852
+ }
16853
+ if (typeof type !== "string" || type.length === 0 || type !== type.trim()) {
16854
+ throw new ModelResidencyError("unknown", "llama-swap", modelDetail(id, llamaSwapResidencyMessages.invalidCatalogField("meta.llamaswap.type")));
16855
+ }
16856
+ return type === "model" ? "model" : undefined;
16857
+ }
16858
+ function readContextCandidates(entry) {
16859
+ const values = [
16860
+ readPositiveSafeInteger(entry.context_length),
16861
+ readPositiveSafeInteger(entry.context_window),
16862
+ isObject3(entry.meta) ? readPositiveSafeInteger(entry.meta.n_ctx) : undefined
16863
+ ];
16864
+ return values.filter((value) => value !== undefined);
16865
+ }
16866
+ function readDeclaredMaxOutput(entry, id) {
16867
+ if (!isObject3(entry.meta) || !isObject3(entry.meta.llamaswap)) {
16868
+ return;
16869
+ }
16870
+ if (!Object.hasOwn(entry.meta.llamaswap, "max_output_tokens")) {
16871
+ return;
16872
+ }
16873
+ const maxOutputTokens = readPositiveSafeInteger(entry.meta.llamaswap.max_output_tokens);
16874
+ if (maxOutputTokens === undefined) {
16875
+ throw new ModelResidencyError("unknown", "llama-swap", modelDetail(id, llamaSwapResidencyMessages.invalidCatalogField("meta.llamaswap.max_output_tokens")));
16876
+ }
16877
+ return maxOutputTokens;
16878
+ }
16879
+ function parseCatalogModel(value) {
16880
+ if (!isObject3(value) || typeof value.id !== "string") {
16881
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.catalogEntryMustExposeStringId);
16882
+ }
16883
+ const id = value.id;
16884
+ if (id.length === 0 || id !== id.trim()) {
16885
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.catalogModelIdsMustBeNonEmptyTrimmedStrings);
16886
+ }
16887
+ if (parseCanonicalType(value, id) !== "model") {
16888
+ return;
16889
+ }
16890
+ const model = {
16891
+ modelID: id,
16892
+ supportsTools: readSupportsTools2(value)
16893
+ };
16894
+ const contexts = readContextCandidates(value);
16895
+ if (contexts.length > 0) {
16896
+ model.contextWindow = Math.min(...contexts);
16897
+ model.contextWindowProvenance = "declared";
16898
+ }
16899
+ const maxOutputTokens = readDeclaredMaxOutput(value, id);
16900
+ if (maxOutputTokens !== undefined) {
16901
+ model.maxOutputTokens = maxOutputTokens;
16902
+ model.maxOutputTokensProvenance = "declared";
16903
+ }
16904
+ return model;
16905
+ }
16906
+ function parseCatalog(payload) {
16907
+ if (!isObject3(payload) || !Array.isArray(payload.data)) {
16908
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.expectedDataArray("/v1/models"));
16909
+ }
16910
+ const seen = new Set;
16911
+ const models = [];
16912
+ for (const entry of payload.data) {
16913
+ const model = parseCatalogModel(entry);
16914
+ if (model === undefined) {
16915
+ continue;
16916
+ }
16917
+ if (seen.has(model.modelID)) {
16918
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.duplicateCanonicalModelId(model.modelID, "/v1/models"));
16919
+ }
16920
+ seen.add(model.modelID);
16921
+ models.push(model);
16922
+ }
16923
+ return models;
16924
+ }
16925
+ async function metadata2(url, fetch2, signal, headers) {
16926
+ signal.throwIfAborted();
16927
+ try {
16928
+ const response = await fetch2(url, {
16929
+ method: "GET",
16930
+ headers,
16931
+ signal,
16932
+ redirect: "error",
16933
+ cache: "no-store"
16934
+ });
16935
+ signal.throwIfAborted();
16936
+ if (response.status === 401 || response.status === 403) {
16937
+ throw new ModelResidencyError("authentication-unsupported", "llama-swap");
16938
+ }
16939
+ if (!response.ok || response.redirected || response.url !== "" && response.url !== url) {
16940
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.httpFailure(new URL(url).pathname, response.status));
16941
+ }
16942
+ return await response.json();
16943
+ } catch (error) {
16944
+ signal.throwIfAborted();
16945
+ if (error instanceof ModelResidencyError) {
16946
+ throw error;
16947
+ }
16948
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.unverifiableResponse(new URL(url).pathname));
16949
+ }
16950
+ }
16951
+ function readProfiles(payload) {
16952
+ if (!isObject3(payload) || !Array.isArray(payload.profiles)) {
16953
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.expectedProfilesArray("/api/profiles"));
16954
+ }
16955
+ if (payload.active === null) {
16956
+ return;
16957
+ }
16958
+ if (typeof payload.active === "string" && payload.active.length > 0 && payload.active === payload.active.trim()) {
16959
+ throw new ModelResidencyError("identity", "llama-swap", llamaSwapResidencyMessages.activeProfileRewrite(payload.active));
16960
+ }
16961
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.invalidActiveProfileValue("/api/profiles"));
16962
+ }
16963
+ function readRunning(payload, modelIDs) {
16964
+ if (!isObject3(payload) || !Array.isArray(payload.running)) {
16965
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.expectedRunningArray("/running"));
16966
+ }
16967
+ const result = new Map;
16968
+ for (const modelID of modelIDs) {
16969
+ result.set(modelID, { loaded: false });
16970
+ }
16971
+ const seen = new Set;
16972
+ for (const entry of payload.running) {
16973
+ if (!isObject3(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()) {
16974
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.malformedRunningEvidence("/running"));
16975
+ }
16976
+ if (seen.has(entry.model)) {
16977
+ throw new ModelResidencyError("unknown", "llama-swap", llamaSwapResidencyMessages.duplicateRunningEvidence("/running", entry.model));
16978
+ }
16979
+ seen.add(entry.model);
16980
+ if (!modelIDs.has(entry.model)) {
16981
+ continue;
16982
+ }
16983
+ result.set(entry.model, { loaded: entry.state === "ready" });
16984
+ }
16985
+ return result;
16986
+ }
16987
+ function requestHeaders(headers) {
16988
+ const result = new Headers(headers);
16989
+ result.delete("content-type");
16990
+ result.delete("content-length");
16991
+ result.set("accept", "application/json");
16992
+ result.set("cache-control", "no-cache, no-store");
16993
+ result.delete("if-none-match");
16994
+ result.delete("if-modified-since");
16995
+ return result;
16996
+ }
16997
+ function llamaSwapResidencyOptions(options) {
16998
+ return { ...options, runtimeLabel: "llama-swap" };
16999
+ }
17000
+ async function readLlamaSwapCatalog(baseURL, fetch2, options = {}) {
17001
+ const base = llamaSwapBaseURL(baseURL);
17002
+ const headers = requestHeaders(options.headers);
17003
+ return withResidencyDeadline(async (signal) => parseCatalog(await metadata2(`${base}/models`, fetch2, signal, headers)), llamaSwapResidencyOptions(options));
17004
+ }
17005
+ async function readLlamaSwapResidency(baseURL, fetch2, options = {}) {
17006
+ const base = llamaSwapBaseURL(baseURL);
17007
+ const origin = new URL(base).origin;
17008
+ const headers = requestHeaders(options.headers);
17009
+ return withResidencyDeadline(async (signal) => {
17010
+ const models = await readLlamaSwapCatalog(base, fetch2, {
17011
+ ...llamaSwapResidencyOptions(options),
17012
+ signal
17013
+ });
17014
+ readProfiles(await metadata2(`${origin}/api/profiles`, fetch2, signal, headers));
17015
+ return readRunning(await metadata2(`${origin}/running`, fetch2, signal, headers), new Set(models.map((model) => model.modelID)));
17016
+ }, llamaSwapResidencyOptions(options));
17017
+ }
17018
+
17019
+ // src/local/llamaSwap.ts
17020
+ var LLAMA_SWAP_DEFAULT_BASE_URL = "http://localhost:8080/v1";
17021
+ function withLoadedState(models, residency) {
17022
+ return models.map((model) => {
17023
+ const loaded = residency.get(model.modelID)?.loaded;
17024
+ return loaded === undefined ? model : { ...model, loaded };
17025
+ });
17026
+ }
17027
+ function createLlamaSwapAdapter() {
17028
+ const listModels = async (options) => {
17029
+ const baseURL = llamaSwapBaseURL(options.baseURL ?? LLAMA_SWAP_DEFAULT_BASE_URL);
17030
+ const models = await readLlamaSwapCatalog(baseURL, options.fetch);
17031
+ try {
17032
+ return withLoadedState(models, await readLlamaSwapResidency(baseURL, options.fetch));
17033
+ } catch (error) {
17034
+ if (error instanceof ModelResidencyError && (error.code === "identity" || error.code === "unknown")) {
17035
+ return models;
17036
+ }
17037
+ throw error;
17038
+ }
17039
+ };
17040
+ return {
17041
+ id: "llama-swap",
17042
+ defaultBaseURL: LLAMA_SWAP_DEFAULT_BASE_URL,
17043
+ listModels,
17044
+ async probe(options) {
17045
+ const baseURL = llamaSwapBaseURL(options.baseURL ?? LLAMA_SWAP_DEFAULT_BASE_URL);
17046
+ try {
17047
+ return {
17048
+ id: "llama-swap",
17049
+ baseURL,
17050
+ reachable: true,
17051
+ models: await listModels({ ...options, baseURL }),
17052
+ probedAt: options.probedAt
17053
+ };
17054
+ } catch (error) {
17055
+ return unavailableSnapshot({
17056
+ id: "llama-swap",
17057
+ baseURL,
17058
+ probedAt: options.probedAt,
17059
+ error
17060
+ });
17061
+ }
17062
+ }
17063
+ };
17064
+ }
17065
+
16708
17066
  // src/local/modelResidency.ts
17067
+ function runtimeRequiresModelResidency(kind) {
17068
+ return kind === "lemonade" || kind === "llama-swap";
17069
+ }
16709
17070
  function hasRequiredModelResidency(kind, model) {
16710
- return kind !== "lemonade" || model?.loaded === true;
17071
+ return !runtimeRequiresModelResidency(kind) || model?.loaded === true;
16711
17072
  }
16712
17073
 
16713
17074
  // src/local/lmstudio.ts
@@ -16762,6 +17123,7 @@ class RuntimeRegistry {
16762
17123
  lmstudio: createLMStudioAdapter(),
16763
17124
  "foundry-local": createFoundryLocalAdapter(),
16764
17125
  lemonade: createLemonadeAdapter(),
17126
+ "llama-swap": createLlamaSwapAdapter(),
16765
17127
  ...options.adapters
16766
17128
  };
16767
17129
  this.clock = options.clock;
@@ -16899,6 +17261,12 @@ var DETECTION_RUNTIMES = [
16899
17261
  baseURL: LEMONADE_DEFAULT_BASE_URL,
16900
17262
  defaultModel: { providerID: "lemonade", modelID: "probe" }
16901
17263
  },
17264
+ {
17265
+ id: "llama-swap",
17266
+ enabled: true,
17267
+ baseURL: LLAMA_SWAP_DEFAULT_BASE_URL,
17268
+ defaultModel: { providerID: "llama-swap", modelID: "probe" }
17269
+ },
16902
17270
  {
16903
17271
  id: "foundry-local",
16904
17272
  enabled: true,
@@ -17397,7 +17765,7 @@ function runtimeLine(snapshot, runtime) {
17397
17765
  const mark = snapshot.reachable ? "✓" : "✗";
17398
17766
  const detail = snapshot.reachable ? `${snapshot.models.length} model(s)` : snapshot.error ?? "unreachable";
17399
17767
  const declared = runtime?.maxConcurrency;
17400
- const slots = declared === undefined ? ` · ${DEFAULT_LOCAL_MAX_CONCURRENCY} slot(s) (default)` : ` · ${declared} slot(s) (declared)`;
17768
+ const slots = declared === undefined ? doctorMessages.defaultRuntimeSlots(effectiveMaxConcurrency(runtime ?? {})) : ` · ${declared} slot(s) (declared)`;
17401
17769
  return ` ${mark} ${snapshot.id.padEnd(14)} ${snapshot.baseURL || "(no baseURL)"} — ${detail}${slots}`;
17402
17770
  }
17403
17771
  function runtimeModelSlotsLine(runtime, snapshot) {
@@ -17409,6 +17777,8 @@ function runtimeModelSlotsLine(runtime, snapshot) {
17409
17777
  if (runtime === undefined || snapshot === undefined || !snapshot.reachable || snapshot.models.length === 0) {
17410
17778
  return [];
17411
17779
  }
17780
+ if (localRuntimeKind(runtime) === "llama-swap")
17781
+ return [doctorMessages.llamaSwapConcurrency];
17412
17782
  const reported = snapshot.models.flatMap((model) => model.slots === undefined ? [] : [`${model.modelID} ${model.slots} slot(s)`]);
17413
17783
  if (reported.length > 0) {
17414
17784
  return [
@@ -17812,7 +18182,7 @@ function renderDoctor(input) {
17812
18182
  continue;
17813
18183
  }
17814
18184
  const runtime = enabledRuntimes.find((r) => r.id === snapshot.id);
17815
- const cap = runtime?.maxConcurrency ?? DEFAULT_LOCAL_MAX_CONCURRENCY;
18185
+ const cap = effectiveMaxConcurrency(runtime ?? {});
17816
18186
  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.");
17817
18187
  }
17818
18188
  lines.push(` telemetry: ${input.telemetryPath} — ${input.telemetryRecords} record(s)`);
@@ -18215,7 +18585,7 @@ import { posix as pathPosix, win32 as pathWin32 } from "node:path";
18215
18585
  // package.json
18216
18586
  var package_default = {
18217
18587
  name: "@jmanuelcorral/openteam",
18218
- version: "0.25.0",
18588
+ version: "0.26.0",
18219
18589
  packageManager: "bun@1.3.14",
18220
18590
  description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
18221
18591
  license: "MIT",
@@ -18534,14 +18904,25 @@ function frontierModelsForProvider(profiles, providerID) {
18534
18904
  var OPENCODE_GITIGNORE_PATH = ".opencode/.gitignore";
18535
18905
  var DEFAULT_LOCAL_OUTPUT_TOKENS = 8192;
18536
18906
  var MIN_USABLE_INPUT_TOKENS = 1024;
18537
- function computeModelLimit(contextWindow, inputBudget) {
18907
+ function computeModelLimit(contextWindow, inputBudget, maxOutputTokens) {
18538
18908
  const context = contextWindow ?? 0;
18539
18909
  const contextBudget = context > 0 ? context : undefined;
18540
18910
  const validInputBudget = inputBudget !== undefined && inputBudget > 0 ? inputBudget : undefined;
18541
18911
  const effectiveBudget = contextBudget === undefined ? validInputBudget : validInputBudget === undefined ? contextBudget : Math.min(contextBudget, validInputBudget);
18542
- const output = effectiveBudget !== undefined && effectiveBudget - DEFAULT_LOCAL_OUTPUT_TOKENS < MIN_USABLE_INPUT_TOKENS ? Math.max(1, Math.floor(effectiveBudget / 2)) : DEFAULT_LOCAL_OUTPUT_TOKENS;
18912
+ const desired = Math.min(DEFAULT_LOCAL_OUTPUT_TOKENS, positiveInteger3(maxOutputTokens) ?? DEFAULT_LOCAL_OUTPUT_TOKENS);
18913
+ const output = Math.min(desired, effectiveBudget !== undefined && effectiveBudget - desired < MIN_USABLE_INPUT_TOKENS ? Math.max(1, Math.floor(effectiveBudget / 2)) : desired);
18543
18914
  return { context, output };
18544
18915
  }
18916
+ function collectMaxOutputTokens(modelInfo, usedModelIDs) {
18917
+ const used = new Set(usedModelIDs);
18918
+ const ceilings = {};
18919
+ for (const model of modelInfo ?? []) {
18920
+ const ceiling = positiveInteger3(model.maxOutputTokens);
18921
+ if (ceiling !== undefined && used.has(model.modelID))
18922
+ ceilings[model.modelID] = ceiling;
18923
+ }
18924
+ return Object.keys(ceilings).length > 0 ? ceilings : undefined;
18925
+ }
18545
18926
  function collectContextWindows(modelInfo, usedModelIDs) {
18546
18927
  if (modelInfo === undefined) {
18547
18928
  return;
@@ -18658,6 +19039,12 @@ var KNOWN_RUNTIMES = [
18658
19039
  defaultBaseURL: LEMONADE_DEFAULT_BASE_URL,
18659
19040
  fallbackModelID: "Qwen3-Coder-30B-A3B-Instruct-GGUF"
18660
19041
  },
19042
+ {
19043
+ id: "llama-swap",
19044
+ label: executionSetupMessages.llamaSwap.label,
19045
+ defaultBaseURL: LLAMA_SWAP_DEFAULT_BASE_URL,
19046
+ fallbackModelID: ""
19047
+ },
18661
19048
  {
18662
19049
  id: "foundry-local",
18663
19050
  label: "Foundry Local",
@@ -18665,7 +19052,7 @@ var KNOWN_RUNTIMES = [
18665
19052
  dynamicPort: true
18666
19053
  }
18667
19054
  ];
18668
- var LEMONADE_PROJECT_CONFIG_CANDIDATES = [
19055
+ var RESIDENT_PROJECT_CONFIG_CANDIDATES = [
18669
19056
  ".opencode/opencode.jsonc",
18670
19057
  ".opencode/opencode.json",
18671
19058
  "opencode.jsonc",
@@ -18687,6 +19074,19 @@ function choiceKind(choice) {
18687
19074
  function choiceProviderID(choice) {
18688
19075
  return choice.providerID ?? choice.id;
18689
19076
  }
19077
+ function residencySetupMessages(kind) {
19078
+ return kind === "llama-swap" ? executionSetupMessages.llamaSwap : {
19079
+ noLoadedModels: executionSetupMessages.lemonadeNoLoadedModels,
19080
+ modelNotLoaded: executionSetupMessages.lemonadeModelNotLoaded,
19081
+ probeRequired: executionSetupMessages.lemonadeProbeRequired,
19082
+ probeFailed: executionSetupMessages.lemonadeProbeFailed,
19083
+ endpointMismatch: executionSetupMessages.lemonadeEndpointMismatch,
19084
+ modelIdentityUnknown: executionSetupMessages.lemonadeModelIdentityUnknown
19085
+ };
19086
+ }
19087
+ function residencyBaseURL(kind, value) {
19088
+ return kind === "llama-swap" ? llamaSwapBaseURL(value ?? LLAMA_SWAP_DEFAULT_BASE_URL) : lemonadeBaseURL(value ?? LEMONADE_DEFAULT_BASE_URL);
19089
+ }
18690
19090
  function selectableModelIDs(models, modelInfo, kind) {
18691
19091
  const byID = new Map(modelInfo?.map((model) => [model.modelID, model]));
18692
19092
  return models.filter((id) => hasRequiredModelResidency(kind, byID.get(id)));
@@ -18704,7 +19104,7 @@ function assertRuntimeResidency(choice, primary) {
18704
19104
  continue;
18705
19105
  const info = choice.models.includes(id) ? choice.modelInfo?.find((model) => model.modelID === id) : undefined;
18706
19106
  if (!hasRequiredModelResidency(kind, info))
18707
- throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${choiceProviderID(choice)}/${id}`));
19107
+ throw new Error(residencySetupMessages(kind).modelNotLoaded(`${choiceProviderID(choice)}/${id}`));
18708
19108
  }
18709
19109
  }
18710
19110
  function assertSetupResidency(answers) {
@@ -18712,11 +19112,11 @@ function assertSetupResidency(answers) {
18712
19112
  if (choice.enabled) {
18713
19113
  assertRuntimeResidency(choice, answers.primaryModel);
18714
19114
  } else if (choiceProviderID(choice) === answers.primaryModel.providerID && !hasRequiredModelResidency(localRuntimeKind(choice), undefined)) {
18715
- throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
19115
+ throw new Error(residencySetupMessages(localRuntimeKind(choice)).modelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
18716
19116
  }
18717
19117
  }
18718
19118
  }
18719
- function lemonadeV2Policies(providers) {
19119
+ function residentV2Policies(providers) {
18720
19120
  return [...new Set(providers)].sort().map((providerID) => {
18721
19121
  if (providerID.length === 0 || /[*?\\/\s]/.test(providerID))
18722
19122
  throw new Error(executionSetupMessages.lemonadeV2InvalidProvider(providerID));
@@ -18733,7 +19133,7 @@ function buildOpenTeamConfig(answers) {
18733
19133
  providerID: choiceProviderID(choice),
18734
19134
  modelID: choice.defaultModelID
18735
19135
  },
18736
- maxConcurrency: choice.maxConcurrency ?? DEFAULT_LOCAL_MAX_CONCURRENCY
19136
+ maxConcurrency: effectiveMaxConcurrency(choice)
18737
19137
  };
18738
19138
  if (choice.modelConcurrency !== undefined && Object.keys(choice.modelConcurrency).length > 0) {
18739
19139
  runtime.modelConcurrency = { ...choice.modelConcurrency };
@@ -18748,7 +19148,7 @@ function buildOpenTeamConfig(answers) {
18748
19148
  runtime.kind = choice.kind;
18749
19149
  }
18750
19150
  if (choice.baseURL !== undefined) {
18751
- runtime.baseURL = choice.baseURL;
19151
+ runtime.baseURL = localRuntimeKind(choice) === "llama-swap" ? llamaSwapBaseURL(choice.baseURL) : choice.baseURL;
18752
19152
  } else if (knownRuntime(choiceKind(choice)).dynamicPort === true) {
18753
19153
  runtime.discovery = "cli";
18754
19154
  }
@@ -18794,7 +19194,7 @@ function orchestratorAgentModel(answers) {
18794
19194
  }
18795
19195
  function buildOpencodeConfig(answers) {
18796
19196
  assertSetupResidency(answers);
18797
- const policies = lemonadeV2Policies(answers.runtimes.filter((choice) => choice.enabled && choiceKind(choice) === "lemonade").map(choiceProviderID));
19197
+ const policies = residentV2Policies(answers.runtimes.filter((choice) => choice.enabled && runtimeRequiresModelResidency(localRuntimeKind(choice))).map(choiceProviderID));
18798
19198
  const provider = {};
18799
19199
  const providerOwner = new Map;
18800
19200
  for (const choice of answers.runtimes) {
@@ -18802,7 +19202,8 @@ function buildOpencodeConfig(answers) {
18802
19202
  continue;
18803
19203
  }
18804
19204
  const meta = knownRuntime(choiceKind(choice));
18805
- const baseURL = choice.baseURL ?? meta.defaultBaseURL;
19205
+ const configuredBaseURL = choice.baseURL ?? meta.defaultBaseURL;
19206
+ const baseURL = meta.id === "llama-swap" ? llamaSwapBaseURL(configuredBaseURL ?? LLAMA_SWAP_DEFAULT_BASE_URL) : configuredBaseURL;
18806
19207
  if (baseURL === undefined) {
18807
19208
  continue;
18808
19209
  }
@@ -18821,7 +19222,7 @@ function buildOpencodeConfig(answers) {
18821
19222
  const models = {};
18822
19223
  for (const modelID of modelIDs) {
18823
19224
  const contextWindow = choice.modelContextWindows?.[modelID];
18824
- const limit = computeModelLimit(contextWindow);
19225
+ const limit = computeModelLimit(contextWindow, undefined, choice.modelMaxOutputTokens?.[modelID]);
18825
19226
  models[modelID] = { name: modelID, limit };
18826
19227
  }
18827
19228
  const owner = providerOwner.get(providerID);
@@ -19002,8 +19403,8 @@ function preferredModelID(models, modelInfo, kind) {
19002
19403
  async function chooseRuntimeModel(prompt, models, meta, modelInfo) {
19003
19404
  const offered = selectableModelIDs(models, modelInfo, meta.id);
19004
19405
  if (offered.length === 0) {
19005
- if (meta.id === "lemonade")
19006
- throw new Error(executionSetupMessages.lemonadeNoLoadedModels);
19406
+ if (runtimeRequiresModelResidency(meta.id))
19407
+ throw new Error(residencySetupMessages(meta.id).noLoadedModels);
19007
19408
  return prompt.text({
19008
19409
  message: `Default model for ${meta.label} (no models detected)`,
19009
19410
  placeholder: meta.fallbackModelID,
@@ -19019,8 +19420,8 @@ async function chooseRuntimeModel(prompt, models, meta, modelInfo) {
19019
19420
  opts.initial = first;
19020
19421
  }
19021
19422
  const selected = await prompt.select(opts);
19022
- if (meta.id === "lemonade" && !offered.includes(selected))
19023
- throw new Error(executionSetupMessages.lemonadeModelNotLoaded(selected));
19423
+ if (runtimeRequiresModelResidency(meta.id) && !offered.includes(selected))
19424
+ throw new Error(residencySetupMessages(meta.id).modelNotLoaded(selected));
19024
19425
  return selected;
19025
19426
  }
19026
19427
  function remoteBaseURLExample(meta) {
@@ -19076,28 +19477,31 @@ async function resolveRuntimeConnection(deps, meta, info) {
19076
19477
  initial: RUNTIME_LOCATION_LOCAL
19077
19478
  });
19078
19479
  if (location === RUNTIME_LOCATION_LOCAL) {
19079
- if (meta.id === "lemonade" && info?.reachable !== true)
19080
- throw new Error(executionSetupMessages.lemonadeProbeFailed);
19480
+ if (runtimeRequiresModelResidency(meta.id) && info?.reachable !== true)
19481
+ throw new Error(info?.error ?? residencySetupMessages(meta.id).probeFailed);
19081
19482
  const baseURL2 = info?.baseURL !== undefined && info.baseURL.length > 0 ? info.baseURL : meta.defaultBaseURL;
19082
- return { baseURL: baseURL2, ...connectionOf(info) };
19483
+ return {
19484
+ baseURL: meta.id === "llama-swap" ? llamaSwapBaseURL(baseURL2) : baseURL2,
19485
+ ...connectionOf(info)
19486
+ };
19083
19487
  }
19084
19488
  const entered = await deps.prompt.text({
19085
19489
  message: `${meta.label} URL on the network (OpenAI-compatible endpoint)`,
19086
19490
  placeholder: remoteBaseURLExample(meta)
19087
19491
  });
19088
- const baseURL = normalizeRemoteBaseURL(entered, meta.defaultBaseURL);
19492
+ const baseURL = meta.id === "llama-swap" ? llamaSwapBaseURL(entered) : normalizeRemoteBaseURL(entered, meta.defaultBaseURL);
19089
19493
  let probedRuntime;
19090
- if (meta.id === "lemonade" && deps.probeRuntime === undefined)
19091
- throw new Error(executionSetupMessages.lemonadeProbeRequired);
19494
+ if (runtimeRequiresModelResidency(meta.id) && deps.probeRuntime === undefined)
19495
+ throw new Error(residencySetupMessages(meta.id).probeRequired);
19092
19496
  if (deps.probeRuntime !== undefined) {
19093
19497
  try {
19094
19498
  probedRuntime = await deps.probeRuntime(meta.id, baseURL);
19095
19499
  } catch (cause) {
19096
- if (meta.id === "lemonade")
19097
- throw new Error(executionSetupMessages.lemonadeProbeFailed, { cause });
19500
+ if (runtimeRequiresModelResidency(meta.id))
19501
+ throw new Error(residencySetupMessages(meta.id).probeFailed, { cause });
19098
19502
  }
19099
- if (meta.id === "lemonade" && probedRuntime?.reachable !== true)
19100
- throw new Error(executionSetupMessages.lemonadeProbeFailed);
19503
+ if (runtimeRequiresModelResidency(meta.id) && probedRuntime?.reachable !== true)
19504
+ throw new Error(probedRuntime?.error ?? residencySetupMessages(meta.id).probeFailed);
19101
19505
  }
19102
19506
  return { baseURL, ...connectionOf(probedRuntime) };
19103
19507
  }
@@ -19105,8 +19509,8 @@ async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass
19105
19509
  const label = modelClass === "thinking" ? `Thinking model for ${meta.label} (design, analysis, review reasoning)` : `Coder model for ${meta.label} (writing and editing code)`;
19106
19510
  const offered = selectableModelIDs(models, modelInfo, meta.id);
19107
19511
  if (offered.length === 0) {
19108
- if (meta.id === "lemonade")
19109
- throw new Error(executionSetupMessages.lemonadeNoLoadedModels);
19512
+ if (runtimeRequiresModelResidency(meta.id))
19513
+ throw new Error(residencySetupMessages(meta.id).noLoadedModels);
19110
19514
  const raw = await prompt.text({
19111
19515
  message: `${label} — enter to reuse the default`,
19112
19516
  placeholder: defaultModelID,
@@ -19122,8 +19526,8 @@ async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass
19122
19526
  })),
19123
19527
  initial: defaultModelID
19124
19528
  });
19125
- if (meta.id === "lemonade" && !offered.includes(selected))
19126
- throw new Error(executionSetupMessages.lemonadeModelNotLoaded(selected));
19529
+ if (runtimeRequiresModelResidency(meta.id) && !offered.includes(selected))
19530
+ throw new Error(residencySetupMessages(meta.id).modelNotLoaded(selected));
19127
19531
  return selected;
19128
19532
  }
19129
19533
  async function resolveEnabledRuntime(deps, meta, info) {
@@ -19160,6 +19564,16 @@ async function resolveEnabledRuntime(deps, meta, info) {
19160
19564
  if (modelContextWindows !== undefined) {
19161
19565
  choice.modelContextWindows = modelContextWindows;
19162
19566
  }
19567
+ const modelMaxOutputTokens = collectMaxOutputTokens(connection.modelInfo, [
19568
+ defaultModelID,
19569
+ thinkingModelID,
19570
+ coderModelID,
19571
+ ...connection.models
19572
+ ]);
19573
+ if (modelMaxOutputTokens !== undefined)
19574
+ choice.modelMaxOutputTokens = modelMaxOutputTokens;
19575
+ if (meta.id === "llama-swap")
19576
+ deps.prompt.note(executionSetupMessages.llamaSwap.declaredLimits, executionSetupMessages.llamaSwap.declaredLimitsTitle);
19163
19577
  return choice;
19164
19578
  }
19165
19579
  function reportedModelSlots(modelInfo, usedModelIDs) {
@@ -19186,11 +19600,11 @@ async function promptSlotCount(prompt, meta, reported) {
19186
19600
  }
19187
19601
  const raw = await prompt.text({
19188
19602
  message: `How many concurrent generation slots does ${meta.label} have? (match its real capacity; leaving one free keeps interactive work responsive)`,
19189
- placeholder: String(DEFAULT_LOCAL_MAX_CONCURRENCY),
19190
- initial: String(DEFAULT_LOCAL_MAX_CONCURRENCY)
19603
+ placeholder: String(effectiveMaxConcurrency({ id: meta.id })),
19604
+ initial: String(effectiveMaxConcurrency({ id: meta.id }))
19191
19605
  });
19192
19606
  const parsed = Number.parseInt(raw.trim(), 10);
19193
- return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_LOCAL_MAX_CONCURRENCY;
19607
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : effectiveMaxConcurrency({ id: meta.id });
19194
19608
  }
19195
19609
  function reportedSlotSummary(reported) {
19196
19610
  const entries = Object.entries(reported ?? {});
@@ -19249,6 +19663,29 @@ async function resolveRuntimeInstances(deps, meta, info, usedIds) {
19249
19663
  function isRecord6(value) {
19250
19664
  return typeof value === "object" && value !== null && !Array.isArray(value);
19251
19665
  }
19666
+ function setupOutputCeilings(answers, existing) {
19667
+ const result = {};
19668
+ const providers = recordAt2(existing, "provider");
19669
+ for (const choice of answers.runtimes.filter((runtime) => runtime.enabled)) {
19670
+ const physical = choice.modelMaxOutputTokens;
19671
+ if (physical === undefined)
19672
+ continue;
19673
+ const providerID = choiceProviderID(choice);
19674
+ const ceilings = { ...physical };
19675
+ const models = recordAt2(recordAt2(providers, providerID), "models");
19676
+ for (const [alias, value] of Object.entries(models ?? {})) {
19677
+ if (!isRecord6(value))
19678
+ continue;
19679
+ const id = typeof value.id === "string" ? value.id : alias;
19680
+ delete ceilings[alias];
19681
+ const ceiling = physical[id];
19682
+ if (ceiling !== undefined)
19683
+ ceilings[alias] = ceiling;
19684
+ }
19685
+ result[providerID] = ceilings;
19686
+ }
19687
+ return result;
19688
+ }
19252
19689
  var LIMIT_FIELDS = [
19253
19690
  "context",
19254
19691
  "input",
@@ -19738,7 +20175,7 @@ function readModelLimitValues(limit) {
19738
20175
  function mergeModelLimitForRerun(input) {
19739
20176
  const target = readModelLimitValues(input.targetLimit);
19740
20177
  const effective = readModelLimitValues(input.effectiveLimit);
19741
- const computed = computeModelLimit(effective.context ?? input.generatedLimit?.context, effective.input);
20178
+ const computed = computeModelLimit(effective.context ?? input.generatedLimit?.context, effective.input, input.maxOutputTokens);
19742
20179
  const merged = { ...input.targetLimit ?? {} };
19743
20180
  const targetOutputIsGeneratedDefault = target.output === DEFAULT_LOCAL_OUTPUT_TOKENS;
19744
20181
  if (targetOutputIsGeneratedDefault && effective.output !== undefined && effective.output !== DEFAULT_LOCAL_OUTPUT_TOKENS) {
@@ -19752,6 +20189,8 @@ function mergeModelLimitForRerun(input) {
19752
20189
  } else {
19753
20190
  merged.output = computed.output;
19754
20191
  }
20192
+ if (input.maxOutputTokens !== undefined && typeof merged.output === "number")
20193
+ merged.output = Math.min(merged.output, input.maxOutputTokens);
19755
20194
  if (target.context !== undefined) {
19756
20195
  merged.context = target.context;
19757
20196
  } else if (effective.context !== undefined) {
@@ -19771,7 +20210,8 @@ function completePhysicalModelLimit(input) {
19771
20210
  const target = readModelLimitValues(input.targetLimit);
19772
20211
  const effective = readModelLimitValues(input.effectiveLimit);
19773
20212
  const context = target.context ?? effective.context ?? input.generatedLimit?.context ?? 0;
19774
- const output = target.output ?? effective.output ?? computeModelLimit(context, effective.input).output;
20213
+ const requestedOutput = target.output ?? effective.output ?? computeModelLimit(context, effective.input, input.maxOutputTokens).output;
20214
+ const output = input.maxOutputTokens === undefined ? requestedOutput : Math.min(requestedOutput, input.maxOutputTokens);
19775
20215
  return { ...input.targetLimit, context, output };
19776
20216
  }
19777
20217
  function repairManagedModelLimits(input) {
@@ -19792,16 +20232,18 @@ function repairManagedModelLimits(input) {
19792
20232
  let providerChanged = false;
19793
20233
  const repairedModels = { ...targetModels };
19794
20234
  for (const [modelID, modelValue] of Object.entries(targetModels)) {
19795
- if (!isRecord6(modelValue) || !hasOwn2(modelValue, "limit")) {
20235
+ const ceiling = input.modelOutputCeilings?.[providerID]?.[modelID];
20236
+ if (!isRecord6(modelValue) || !hasOwn2(modelValue, "limit") && ceiling === undefined) {
19796
20237
  continue;
19797
20238
  }
19798
- const targetLimit = recordAt2(modelValue, "limit");
20239
+ const targetLimit = recordAt2(modelValue, "limit") ?? (ceiling === undefined ? undefined : {});
19799
20240
  if (targetLimit === undefined) {
19800
20241
  continue;
19801
20242
  }
19802
20243
  const effectiveLimit = recordAt2(recordAt2(effectiveModels, modelID), "limit");
19803
20244
  const generatedLimit = generatedModelLimit(input.generated, providerID, modelID);
19804
20245
  const repairedLimit = completePhysicalModelLimit({
20246
+ maxOutputTokens: ceiling,
19805
20247
  ...generatedLimit !== undefined ? { generatedLimit } : {},
19806
20248
  targetLimit,
19807
20249
  ...effectiveLimit !== undefined ? { effectiveLimit } : {}
@@ -19860,7 +20302,7 @@ function highestExistingPinVersion(files) {
19860
20302
  }
19861
20303
  return highest;
19862
20304
  }
19863
- function reconcileLemonadeV2Policies(raw, denials) {
20305
+ function reconcileResidentV2Policies(raw, denials) {
19864
20306
  if (denials.length === 0)
19865
20307
  return raw;
19866
20308
  const experimental = raw.experimental;
@@ -19919,6 +20361,7 @@ function mergeOpencodeConfigForRerun(generated, targetRaw, options) {
19919
20361
  const targetLimit = recordAt2(targetModel, "limit");
19920
20362
  const effectiveLimit = recordAt2(effectiveModel, "limit");
19921
20363
  const mergedLimit = mergeModelLimitForRerun({
20364
+ maxOutputTokens: options.modelOutputCeilings?.[providerID]?.[modelID],
19922
20365
  ...modelConfig.limit !== undefined ? { generatedLimit: modelConfig.limit } : {},
19923
20366
  ...targetLimit !== undefined ? { targetLimit } : {},
19924
20367
  ...effectiveLimit !== undefined ? { effectiveLimit } : {}
@@ -19961,7 +20404,7 @@ function mergeOpencodeConfigForRerun(generated, targetRaw, options) {
19961
20404
  if (managesV2Policies && hasOwn2(targetRaw, "experimental")) {
19962
20405
  result.experimental = targetRaw.experimental;
19963
20406
  }
19964
- return reconcileLemonadeV2Policies(result, generated.experimental?.policies ?? []);
20407
+ return reconcileResidentV2Policies(result, generated.experimental?.policies ?? []);
19965
20408
  }
19966
20409
  function mergeOpenTeamConfigForRerun(generated, existing) {
19967
20410
  const existingOrch = existing.orchestrator;
@@ -20011,9 +20454,9 @@ function mergeOpenTeamConfigForRerun(generated, existing) {
20011
20454
  assertEffectiveConfigModelDomains(merged);
20012
20455
  return merged;
20013
20456
  }
20014
- function preserveRetainedLemonadeRuntimes(generated, previous, opencode) {
20457
+ function preserveRetainedResidentRuntimes(generated, previous, opencode) {
20015
20458
  const providers = recordAt2(opencode, "provider") ?? {};
20016
- const retained = (previous?.local.runtimes ?? []).filter((runtime) => localRuntimeKind(runtime) === "lemonade" && hasOwn2(providers, runtime.defaultModel.providerID));
20459
+ const retained = (previous?.local.runtimes ?? []).filter((runtime) => runtimeRequiresModelResidency(localRuntimeKind(runtime)) && hasOwn2(providers, runtime.defaultModel.providerID));
20017
20460
  const deselected = retained.filter((runtime) => !generated.local.runtimes.some((selected) => selected.defaultModel.providerID === runtime.defaultModel.providerID)).map((runtime) => ({ ...runtime, enabled: false }));
20018
20461
  return {
20019
20462
  config: deselected.length === 0 ? generated : OpenTeamConfigSchema.parse({
@@ -20053,31 +20496,33 @@ async function confirmJsonNormalization(prompt, path2, format) {
20053
20496
  initial: false
20054
20497
  });
20055
20498
  }
20056
- function assertPreviousLemonadePrimary(answers, previousConfig) {
20057
- const priorLemonadePrimary = previousConfig?.local.runtimes.some((runtime) => runtime.defaultModel.providerID === answers.primaryModel.providerID && localRuntimeKind(runtime) === "lemonade");
20058
- if (priorLemonadePrimary && !answers.runtimes.some((choice) => choice.enabled && choiceProviderID(choice) === answers.primaryModel.providerID)) {
20059
- throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
20499
+ function assertPreviousResidentPrimary(answers, previousConfig) {
20500
+ const priorResidentPrimary = previousConfig?.local.runtimes.find((runtime) => runtime.defaultModel.providerID === answers.primaryModel.providerID && runtimeRequiresModelResidency(localRuntimeKind(runtime)));
20501
+ if (priorResidentPrimary && !answers.runtimes.some((choice) => choice.enabled && choiceProviderID(choice) === answers.primaryModel.providerID)) {
20502
+ throw new Error(residencySetupMessages(localRuntimeKind(priorResidentPrimary)).modelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
20060
20503
  }
20061
20504
  }
20062
- async function verifyLemonadeBeforeWrite(deps, answers, config, opencode) {
20505
+ async function verifyResidencyBeforeWrite(deps, answers, config, opencode) {
20063
20506
  for (const choice of answers.runtimes) {
20064
- if (choice.enabled && localRuntimeKind(choice) === "lemonade" && !config.local.runtimes.some((runtime) => runtime.enabled && runtime.defaultModel.providerID === choiceProviderID(choice) && localRuntimeKind(runtime) === "lemonade"))
20065
- throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
20507
+ if (choice.enabled && runtimeRequiresModelResidency(localRuntimeKind(choice)) && !config.local.runtimes.some((runtime) => runtime.enabled && runtime.defaultModel.providerID === choiceProviderID(choice) && localRuntimeKind(runtime) === localRuntimeKind(choice)))
20508
+ throw new Error(residencySetupMessages(localRuntimeKind(choice)).endpointMismatch);
20066
20509
  }
20067
20510
  for (const runtime of config.local.runtimes) {
20068
- if (localRuntimeKind(runtime) !== "lemonade")
20511
+ const kind = localRuntimeKind(runtime);
20512
+ if (!runtimeRequiresModelResidency(kind))
20069
20513
  continue;
20514
+ const messages = residencySetupMessages(kind);
20070
20515
  const providerID = runtime.defaultModel.providerID;
20071
20516
  const provider = isRecord6(opencode.provider) ? opencode.provider[providerID] : undefined;
20072
20517
  if (!runtime.enabled && provider === undefined)
20073
20518
  continue;
20074
20519
  const endpoint = isRecord6(provider) ? (isRecord6(provider.options) ? provider.options.baseURL : undefined) ?? provider.api : undefined;
20075
- if (typeof endpoint !== "string" || lemonadeBaseURL(endpoint) !== lemonadeBaseURL(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL) || config.local.runtimes.filter((candidate) => candidate.defaultModel.providerID === providerID).length !== 1)
20076
- throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
20520
+ if (typeof endpoint !== "string" || residencyBaseURL(kind, endpoint) !== residencyBaseURL(kind, runtime.baseURL) || config.local.runtimes.filter((candidate) => candidate.defaultModel.providerID === providerID).length !== 1)
20521
+ throw new Error(messages.endpointMismatch);
20077
20522
  if (!runtime.enabled)
20078
20523
  continue;
20079
20524
  if (deps.probeRuntime === undefined)
20080
- throw new Error(executionSetupMessages.lemonadeProbeRequired);
20525
+ throw new Error(messages.probeRequired);
20081
20526
  const references2 = new Set([
20082
20527
  runtime.defaultModel.modelID,
20083
20528
  runtime.thinkingModel,
@@ -20115,21 +20560,30 @@ async function verifyLemonadeBeforeWrite(deps, answers, config, opencode) {
20115
20560
  const declaration = recordAt2(models, alias);
20116
20561
  const wireID = declaration !== undefined && hasOwn2(declaration, "id") ? declaration.id : alias;
20117
20562
  if (declaration === undefined || typeof wireID !== "string" || wireID.length === 0 || wireID !== wireID.trim())
20118
- throw new Error(executionSetupMessages.lemonadeModelIdentityUnknown(`${providerID}/${alias}`));
20563
+ throw new Error(messages.modelIdentityUnknown(`${providerID}/${alias}`));
20119
20564
  wireIDs.add(wireID);
20120
20565
  }
20121
20566
  let fresh;
20122
20567
  try {
20123
20568
  fresh = await deps.probeRuntime(localRuntimeKind(runtime), endpoint);
20124
20569
  } catch (cause) {
20125
- throw new Error(executionSetupMessages.lemonadeProbeFailed, { cause });
20570
+ throw new Error(messages.probeFailed, { cause });
20126
20571
  }
20127
- if (!fresh.reachable || fresh.id !== localRuntimeKind(runtime) || fresh.baseURL.replace(/\/+$/, "") !== endpoint.replace(/\/+$/, ""))
20128
- throw new Error(executionSetupMessages.lemonadeProbeFailed);
20572
+ if (!fresh.reachable || fresh.id !== localRuntimeKind(runtime) || residencyBaseURL(kind, fresh.baseURL) !== residencyBaseURL(kind, endpoint))
20573
+ throw new Error(fresh.error ?? messages.probeFailed);
20129
20574
  for (const wireID of wireIDs) {
20130
20575
  const info = fresh.models.includes(wireID) ? fresh.modelInfo?.find((model) => model.modelID === wireID) : undefined;
20131
- if (!hasRequiredModelResidency("lemonade", info))
20132
- throw new Error(executionSetupMessages.lemonadeModelNotLoaded(`${providerID}/${wireID}`));
20576
+ if (!hasRequiredModelResidency(kind, info))
20577
+ throw new Error(messages.modelNotLoaded(`${providerID}/${wireID}`));
20578
+ }
20579
+ for (const [alias, declaration] of Object.entries(models ?? {})) {
20580
+ if (!isRecord6(declaration))
20581
+ continue;
20582
+ const wireID = typeof declaration.id === "string" ? declaration.id : alias;
20583
+ const ceiling = fresh.modelInfo?.find((model) => model.modelID === wireID)?.maxOutputTokens;
20584
+ const output = positiveInteger3(recordAt2(declaration, "limit")?.output);
20585
+ if (ceiling !== undefined && output !== undefined && output > ceiling)
20586
+ throw new Error(executionSetupMessages.llamaSwap.outputChanged(`${providerID}/${alias}`, ceiling));
20133
20587
  }
20134
20588
  }
20135
20589
  }
@@ -20144,7 +20598,7 @@ async function runSetup(deps) {
20144
20598
  return {
20145
20599
  value: meta.id,
20146
20600
  label: meta.label,
20147
- hint: info?.reachable ? meta.id === "lemonade" ? executionSetupMessages.lemonadeDetectedHint(selectableModelIDs(info.models, info.modelInfo, meta.id).length, info.modelInfo?.length ?? info.models.length) : `detected · ${info.models.length} model(s)` : "not detected (you can point it to another machine)",
20601
+ hint: info?.reachable ? runtimeRequiresModelResidency(meta.id) ? executionSetupMessages.lemonadeDetectedHint(selectableModelIDs(info.models, info.modelInfo, meta.id).length, info.modelInfo?.length ?? info.models.length) : `detected · ${info.models.length} model(s)` : "not detected (you can point it to another machine)",
20148
20602
  selected: info?.reachable ?? false
20149
20603
  };
20150
20604
  });
@@ -20261,7 +20715,7 @@ async function runSetup(deps) {
20261
20715
  };
20262
20716
  const openTeamConfig = buildOpenTeamConfig(answers);
20263
20717
  const opencodeConfig = buildOpencodeConfig(answers);
20264
- const opencodeConfigPaths = LEMONADE_PROJECT_CONFIG_CANDIDATES;
20718
+ const opencodeConfigPaths = RESIDENT_PROJECT_CONFIG_CANDIDATES;
20265
20719
  const orchestratorAgent = buildOrchestratorAgent(orchestratorAgentModel(answers), { yolo });
20266
20720
  const slashCommands = buildOpenteamCommands();
20267
20721
  const openTeamPath = DEFAULT_CONFIG_PATH;
@@ -20282,29 +20736,44 @@ async function runSetup(deps) {
20282
20736
  }
20283
20737
  throw error;
20284
20738
  }
20285
- assertPreviousLemonadePrimary(answers, existingOpenTeamConfig);
20739
+ assertPreviousResidentPrimary(answers, existingOpenTeamConfig);
20286
20740
  const effectiveExistingOpencode = mergeExistingOpencodeConfigFiles(existingOpencodeFiles, opencodeConfigPaths);
20741
+ const modelOutputCeilings = setupOutputCeilings(answers, effectiveExistingOpencode);
20742
+ const reductions = new Set;
20743
+ for (const file of existingOpencodeFiles) {
20744
+ for (const [providerID, ceilings] of Object.entries(modelOutputCeilings)) {
20745
+ const models = recordAt2(recordAt2(recordAt2(file.raw, "provider"), providerID), "models");
20746
+ for (const [modelID, ceiling] of Object.entries(ceilings)) {
20747
+ const output = positiveInteger3(recordAt2(recordAt2(models, modelID), "limit")?.output);
20748
+ if (output !== undefined && output > ceiling)
20749
+ reductions.add(executionSetupMessages.llamaSwap.outputReduction(`${providerID}/${modelID}`, output, ceiling));
20750
+ }
20751
+ }
20752
+ }
20753
+ if (reductions.size > 0)
20754
+ prompt.note([...reductions].join(`
20755
+ `), executionSetupMessages.llamaSwap.outputReductionTitle);
20287
20756
  const {
20288
20757
  config: finalOpenTeamConfig,
20289
- providerIDs: retainedLemonadeProviderIDs
20290
- } = preserveRetainedLemonadeRuntimes(existingOpenTeamConfig !== undefined ? mergeOpenTeamConfigForRerun(openTeamConfig, existingOpenTeamConfig) : openTeamConfig, existingOpenTeamConfig, effectiveExistingOpencode);
20758
+ providerIDs: retainedResidentProviderIDs
20759
+ } = preserveRetainedResidentRuntimes(existingOpenTeamConfig !== undefined ? mergeOpenTeamConfigForRerun(openTeamConfig, existingOpenTeamConfig) : openTeamConfig, existingOpenTeamConfig, effectiveExistingOpencode);
20291
20760
  assertEffectiveConfigModelDomains(finalOpenTeamConfig);
20292
20761
  const effectiveOpenTeamConfig = await effectiveSetupConfig(finalOpenTeamConfig, existingOpencodeFiles, deps);
20293
20762
  assertEffectiveConfigModelDomains(effectiveOpenTeamConfig);
20294
- for (const providerID of retainedLemonadeProviderIDs) {
20763
+ for (const providerID of retainedResidentProviderIDs) {
20295
20764
  const matches = effectiveOpenTeamConfig.local.runtimes.filter((runtime) => runtime.defaultModel.providerID === providerID);
20296
- if (matches.length !== 1 || matches[0] === undefined || localRuntimeKind(matches[0]) !== "lemonade")
20297
- throw new Error(executionSetupMessages.lemonadeRetainedProviderUnprotected(providerID));
20765
+ if (matches.length !== 1 || matches[0] === undefined || !runtimeRequiresModelResidency(localRuntimeKind(matches[0])))
20766
+ throw new Error(finalOpenTeamConfig.local.runtimes.some((runtime) => runtime.defaultModel.providerID === providerID && localRuntimeKind(runtime) === "lemonade") ? executionSetupMessages.lemonadeRetainedProviderUnprotected(providerID) : executionSetupMessages.retainedResidencyProviderUnprotected(providerID));
20298
20767
  }
20299
- const v2Denials = lemonadeV2Policies([
20768
+ const v2Denials = residentV2Policies([
20300
20769
  ...opencodeConfig.experimental?.policies.map((policy) => policy.resource) ?? [],
20301
- ...effectiveOpenTeamConfig.local.runtimes.filter((runtime) => localRuntimeKind(runtime) === "lemonade").map((runtime) => runtime.defaultModel.providerID)
20770
+ ...effectiveOpenTeamConfig.local.runtimes.filter((runtime) => runtimeRequiresModelResidency(localRuntimeKind(runtime))).map((runtime) => runtime.defaultModel.providerID)
20302
20771
  ]);
20303
20772
  if (v2Denials.length > 0)
20304
20773
  opencodeConfig.experimental = { policies: v2Denials };
20305
- const v2Notice = v2Denials.length > 0 ? executionSetupMessages.lemonadeV2Restriction(v2Denials.map((policy) => policy.resource)) : undefined;
20774
+ const v2Notice = v2Denials.length > 0 ? executionSetupMessages.residencyV2Restriction(v2Denials.map((policy) => policy.resource)) : undefined;
20306
20775
  if (v2Notice !== undefined)
20307
- prompt.note(v2Notice, executionSetupMessages.lemonadeV2Title);
20776
+ prompt.note(v2Notice, executionSetupMessages.residencyV2Title);
20308
20777
  const relevantProviderIDs = relevantLocalProviderIDs(opencodeConfig, existingOpenTeamConfig);
20309
20778
  for (const file of existingOpencodeFiles) {
20310
20779
  assertRelevantLimitNumbers(file, relevantProviderIDs);
@@ -20335,12 +20804,14 @@ async function runSetup(deps) {
20335
20804
  const includePluginInDataFile = pluginOwnerPath === opencodeDataPath;
20336
20805
  const dataTargetRaw = opencodeFileAt(existingOpencodeFiles, opencodeDataPath)?.raw ?? {};
20337
20806
  const mergedOpencodeRaw = mergeOpencodeConfigForRerun(opencodeConfig, dataTargetRaw, {
20807
+ modelOutputCeilings,
20338
20808
  ...effectiveExistingOpencode !== undefined ? { effectiveRaw: effectiveExistingOpencode } : {},
20339
20809
  includePlugin: includePluginInDataFile,
20340
20810
  ...includePluginInDataFile ? { pluginEntries: pluginPlan.plugins } : {},
20341
20811
  yolo
20342
20812
  });
20343
20813
  const repairedDataTarget = repairManagedModelLimits({
20814
+ modelOutputCeilings,
20344
20815
  raw: mergedOpencodeRaw,
20345
20816
  effectiveRaw: effectiveExistingOpencode,
20346
20817
  generated: opencodeConfig,
@@ -20354,12 +20825,13 @@ async function runSetup(deps) {
20354
20825
  continue;
20355
20826
  }
20356
20827
  const repaired = repairManagedModelLimits({
20828
+ modelOutputCeilings,
20357
20829
  raw: file.raw,
20358
20830
  effectiveRaw: effectiveExistingOpencode,
20359
20831
  generated: opencodeConfig,
20360
20832
  providerIDs: relevantProviderIDs
20361
20833
  });
20362
- let plannedRaw = reconcileLemonadeV2Policies(repaired.raw, v2Denials);
20834
+ let plannedRaw = reconcileResidentV2Policies(repaired.raw, v2Denials);
20363
20835
  let changed = repaired.changed || plannedRaw !== repaired.raw;
20364
20836
  if (file.path === pluginOwnerPath && !includePluginInDataFile && pluginPlan.changed) {
20365
20837
  plannedRaw = { ...plannedRaw, plugin: [...pluginPlan.plugins] };
@@ -20433,7 +20905,7 @@ async function runSetup(deps) {
20433
20905
  const effectivePlannedOpencode = mergeExistingOpencodeConfigFiles(existingOpencodeFiles, opencodeConfigPaths, opencodeWritePlan);
20434
20906
  if (effectivePlannedOpencode === undefined)
20435
20907
  throw new Error(executionSetupMessages.lemonadeEndpointMismatch);
20436
- await verifyLemonadeBeforeWrite(deps, answers, effectiveOpenTeamConfig, effectivePlannedOpencode);
20908
+ await verifyResidencyBeforeWrite(deps, answers, effectiveOpenTeamConfig, effectivePlannedOpencode);
20437
20909
  await deps.writeFile(openTeamPath, serializeOpenTeamConfig(finalOpenTeamConfig));
20438
20910
  for (const [path2, contents] of opencodeWritePlan) {
20439
20911
  await deps.writeFile(path2, serializeOpencodeConfig(contents));
@@ -22816,7 +23288,7 @@ function liveModelsFromSnapshots(snapshots, config) {
22816
23288
  map.set(runtime.defaultModel.providerID, {
22817
23289
  reachable: snapshot.reachable,
22818
23290
  modelIDs: new Set(snapshot.models.filter((model) => hasRequiredModelResidency(kind, model)).map((model) => model.modelID)),
22819
- ...kind === "lemonade" ? {
23291
+ ...runtimeRequiresModelResidency(kind) ? {
22820
23292
  residency: new Map(snapshot.models.map((model) => [model.modelID, model.loaded]))
22821
23293
  } : {}
22822
23294
  });
@@ -23146,9 +23618,9 @@ async function runCli(argv, deps) {
23146
23618
  const inventoryNotes = [];
23147
23619
  const readySnapshots = snapshots.map((snapshot) => {
23148
23620
  const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
23149
- if (runtime === undefined || localRuntimeKind(runtime) !== "lemonade")
23621
+ if (runtime === undefined || !runtimeRequiresModelResidency(localRuntimeKind(runtime)))
23150
23622
  return snapshot;
23151
- inventoryNotes.push(executionSetupMessages.lemonadeInventory(runtime.id, runtime.defaultModel.providerID, snapshot.models));
23623
+ inventoryNotes.push(executionSetupMessages.lemonadeInventory(runtime.id, runtime.defaultModel.providerID, snapshot.models, localRuntimeKind(runtime) === "llama-swap" ? "llama-swap" : "Lemonade"));
23152
23624
  return {
23153
23625
  ...snapshot,
23154
23626
  models: snapshot.models.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model))
@@ -23159,7 +23631,7 @@ async function runCli(argv, deps) {
23159
23631
  if (agent.model === undefined || live !== "not-loaded" && live !== "residency-unknown")
23160
23632
  return [];
23161
23633
  return [
23162
- executionSetupMessages.lemonadeAgentResidency(agent.name, `${agent.model.providerID}/${agent.model.modelID}`, live)
23634
+ 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")
23163
23635
  ];
23164
23636
  });
23165
23637
  return {
@@ -24981,6 +25453,159 @@ var realCacheAdapter = {
24981
25453
  isReparsePath
24982
25454
  };
24983
25455
 
25456
+ // src/local/lemonadeRequestGuard.ts
25457
+ var inferencePaths = new Set([
25458
+ "/chat/completions",
25459
+ "/completions",
25460
+ "/embeddings",
25461
+ "/responses"
25462
+ ]);
25463
+ function modelID(payload) {
25464
+ if (typeof payload !== "object" || payload === null || !("model" in payload) || typeof payload.model !== "string" || payload.model.length === 0 || payload.model !== payload.model.trim()) {
25465
+ throw new ModelResidencyError("request");
25466
+ }
25467
+ if (payload.model.endsWith(":latest"))
25468
+ throw new ModelResidencyError("identity");
25469
+ return payload.model;
25470
+ }
25471
+ function createLemonadeGuardedFetch(options) {
25472
+ const base = lemonadeBaseURL(options.baseURL);
25473
+ const upstream = options.fetch;
25474
+ const healthFetch = options.healthFetch ?? upstream;
25475
+ return Object.assign(async (input, init) => {
25476
+ const request = new Request(input, init);
25477
+ const url = new URL(request.url);
25478
+ if (url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !request.url.startsWith(`${base}/`)) {
25479
+ throw new ModelResidencyError("destination");
25480
+ }
25481
+ const path4 = request.url.slice(base.length);
25482
+ const metadataOnly = request.method === "GET" && (path4 === "/health" || /^\/models(?:\/[^/]+)?$/.test(path4));
25483
+ if (!metadataOnly && (request.method !== "POST" || !inferencePaths.has(path4))) {
25484
+ throw new ModelResidencyError("request");
25485
+ }
25486
+ if (!metadataOnly) {
25487
+ await withResidencyDeadline(async (signal) => {
25488
+ signal.throwIfAborted();
25489
+ let payload;
25490
+ try {
25491
+ payload = await request.clone().json();
25492
+ } catch {
25493
+ signal.throwIfAborted();
25494
+ throw new ModelResidencyError("request");
25495
+ }
25496
+ signal.throwIfAborted();
25497
+ const model = modelID(payload);
25498
+ const modelIDs = typeof options.modelIDs === "function" ? await options.modelIDs() : options.modelIDs;
25499
+ signal.throwIfAborted();
25500
+ if (modelIDs !== undefined && !modelIDs.has(model)) {
25501
+ throw new ModelResidencyError("identity");
25502
+ }
25503
+ const residency = await readLemonadeResidency(base, healthFetch, {
25504
+ ...options,
25505
+ signal,
25506
+ headers: request.headers
25507
+ });
25508
+ signal.throwIfAborted();
25509
+ const entry = residency.get(model);
25510
+ if (entry?.loaded !== true) {
25511
+ throw new ModelResidencyError(entry?.loaded === undefined && entry !== undefined ? "unknown" : "inactive");
25512
+ }
25513
+ }, { ...options, signal: request.signal });
25514
+ }
25515
+ if (request.signal.aborted)
25516
+ throw new ModelResidencyError("cancelled");
25517
+ const {
25518
+ body: _body,
25519
+ headers: _headers,
25520
+ method: _method,
25521
+ signal: _signal,
25522
+ redirect: _redirect,
25523
+ ...transportOptions
25524
+ } = init ?? {};
25525
+ return upstream(request, { ...transportOptions, redirect: "error" });
25526
+ }, {
25527
+ preconnect: (...args) => upstream.preconnect?.(...args)
25528
+ });
25529
+ }
25530
+
25531
+ // src/local/llamaSwapRequestGuard.ts
25532
+ var inferencePaths2 = new Set([
25533
+ "/chat/completions",
25534
+ "/completions",
25535
+ "/embeddings",
25536
+ "/responses"
25537
+ ]);
25538
+ async function validatedModelID(payload, modelIDs) {
25539
+ if (typeof payload !== "object" || payload === null || !("model" in payload) || typeof payload.model !== "string" || payload.model.length === 0 || payload.model !== payload.model.trim()) {
25540
+ throw new ModelResidencyError("request", "llama-swap");
25541
+ }
25542
+ if (modelIDs === undefined) {
25543
+ return payload.model;
25544
+ }
25545
+ const ids = typeof modelIDs === "function" ? await modelIDs() : modelIDs;
25546
+ if (ids.has(payload.model)) {
25547
+ return payload.model;
25548
+ }
25549
+ throw new ModelResidencyError("identity", "llama-swap");
25550
+ }
25551
+ function createLlamaSwapGuardedFetch(options) {
25552
+ const base = llamaSwapBaseURL(options.baseURL);
25553
+ const upstream = options.fetch;
25554
+ const healthFetch = options.healthFetch ?? upstream;
25555
+ return Object.assign(async (input, init) => {
25556
+ const request = new Request(input, init);
25557
+ const url = new URL(request.url);
25558
+ if (url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !request.url.startsWith(`${base}/`)) {
25559
+ throw new ModelResidencyError("destination", "llama-swap");
25560
+ }
25561
+ const path4 = request.url.slice(base.length);
25562
+ const metadataOnly = request.method === "GET" && /^\/models(?:\/[^/]+)?$/.test(path4);
25563
+ if (!metadataOnly && (request.method !== "POST" || !inferencePaths2.has(path4))) {
25564
+ throw new ModelResidencyError("request", "llama-swap");
25565
+ }
25566
+ if (!metadataOnly) {
25567
+ await withResidencyDeadline(async (signal) => {
25568
+ signal.throwIfAborted();
25569
+ let payload;
25570
+ try {
25571
+ payload = await request.clone().json();
25572
+ } catch {
25573
+ signal.throwIfAborted();
25574
+ throw new ModelResidencyError("request", "llama-swap");
25575
+ }
25576
+ signal.throwIfAborted();
25577
+ const model = await validatedModelID(payload, options.modelIDs);
25578
+ const residency = await readLlamaSwapResidency(base, healthFetch, {
25579
+ ...options,
25580
+ signal,
25581
+ headers: request.headers
25582
+ });
25583
+ signal.throwIfAborted();
25584
+ if (!residency.has(model)) {
25585
+ throw new ModelResidencyError("identity", "llama-swap");
25586
+ }
25587
+ if (residency.get(model)?.loaded !== true) {
25588
+ throw new ModelResidencyError("inactive", "llama-swap");
25589
+ }
25590
+ }, { ...options, signal: request.signal, runtimeLabel: "llama-swap" });
25591
+ }
25592
+ if (request.signal.aborted) {
25593
+ throw new ModelResidencyError("cancelled", "llama-swap");
25594
+ }
25595
+ const {
25596
+ body: _body,
25597
+ headers: _headers,
25598
+ method: _method,
25599
+ signal: _signal,
25600
+ redirect: _redirect,
25601
+ ...transportOptions
25602
+ } = init ?? {};
25603
+ return upstream(request, { ...transportOptions, redirect: "error" });
25604
+ }, {
25605
+ preconnect: (...args) => upstream.preconnect?.(...args)
25606
+ });
25607
+ }
25608
+
24984
25609
  // src/memory/types.ts
24985
25610
  import { z as z28 } from "zod";
24986
25611
  var SHARED_OWNER_KEY = "*";
@@ -25645,6 +26270,13 @@ function createLocalEmbedder(request, deps) {
25645
26270
  return (texts) => embedTexts({ ...request, texts }, deps);
25646
26271
  }
25647
26272
 
26273
+ // src/messages/memoryRuntime.ts
26274
+ var memoryRuntimeMessages = {
26275
+ providerUnavailable: "[openteam] Semantic memory requires exactly one enabled local runtime matching the configured embeddings provider. No embedding request was sent.",
26276
+ unavailable: "[openteam] Semantic memory initialization failed; recall and memory injection are unavailable.",
26277
+ rejectedLines: (count) => `[openteam] memory log rejected ${count} line(s); semantic memory may be incomplete.`
26278
+ };
26279
+
25648
26280
  // src/memory/embedText.ts
25649
26281
  function normalize3(parts) {
25650
26282
  return parts.map((part) => part.trim()).filter((part) => part.length > 0).join(" ");
@@ -25722,25 +26354,39 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
25722
26354
  if (options.requireInjectionEnabled === true && !semantic.injection.enabled) {
25723
26355
  return;
25724
26356
  }
25725
- const runtime = config.local.runtimes.find((rt) => rt.enabled && rt.baseURL !== undefined);
26357
+ const warn = deps.warn ?? console.warn;
26358
+ const configuredModel = semantic.embeddings.model;
26359
+ const candidates = configuredModel == null ? config.local.runtimes.filter((rt) => rt.enabled && rt.baseURL !== undefined) : config.local.runtimes.filter((rt) => rt.defaultModel.providerID === configuredModel.providerID);
26360
+ const runtime = candidates[0];
26361
+ if (configuredModel != null && (candidates.length !== 1 || runtime?.enabled !== true)) {
26362
+ warn(memoryRuntimeMessages.providerUnavailable);
26363
+ return;
26364
+ }
25726
26365
  if (runtime?.baseURL === undefined) {
25727
26366
  return;
25728
26367
  }
25729
- const modelID = semantic.embeddings.model?.modelID ?? runtime.defaultModel.modelID;
26368
+ const modelID2 = semantic.embeddings.model?.modelID ?? runtime.defaultModel.modelID;
25730
26369
  const openDatabase = deps.openDatabase ?? createBunSqliteDatabase;
25731
26370
  const makeEmbedder = deps.createEmbedder ?? createLocalEmbedder;
25732
26371
  const fetchImpl = deps.fetch ?? globalThis.fetch;
25733
26372
  const now = deps.now ?? (() => Date.now());
25734
- const warn = deps.warn ?? console.warn;
26373
+ const kind = localRuntimeKind(runtime);
25735
26374
  try {
26375
+ const baseURL = kind === "llama-swap" ? llamaSwapBaseURL(runtime.baseURL) : runtime.baseURL;
26376
+ const guardedFetch = runtimeRequiresModelResidency(kind) ? (kind === "llama-swap" ? createLlamaSwapGuardedFetch : createLemonadeGuardedFetch)({
26377
+ baseURL,
26378
+ fetch: fetchImpl,
26379
+ healthFetch: fetchImpl,
26380
+ modelIDs: new Set([modelID2])
26381
+ }) : fetchImpl;
25736
26382
  const db = await openDatabase(semantic.indexPath);
25737
26383
  const index = createMemoryIndex(db, warn);
25738
26384
  const rebuildResult = await rebuildMemoryIndexFromStorage(index, semantic.logPath, { storage: deps.storage });
25739
26385
  if (rebuildResult.rejectedLines > 0) {
25740
- warn(`[openteam] memory log rejected ${rebuildResult.rejectedLines} line(s); semantic memory may be incomplete.`);
26386
+ warn(memoryRuntimeMessages.rejectedLines(rebuildResult.rejectedLines));
25741
26387
  }
25742
- const embedder = makeEmbedder({ baseURL: runtime.baseURL, modelID }, { fetch: fetchImpl });
25743
- await ensureMemoryEmbeddings({ index, embedder, model: modelID, warn });
26388
+ const embedder = makeEmbedder({ baseURL, modelID: modelID2 }, { fetch: guardedFetch });
26389
+ await ensureMemoryEmbeddings({ index, embedder, model: modelID2, warn });
25744
26390
  return {
25745
26391
  index,
25746
26392
  embedder,
@@ -25749,6 +26395,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
25749
26395
  semantic
25750
26396
  };
25751
26397
  } catch {
26398
+ warn(memoryRuntimeMessages.unavailable);
25752
26399
  return;
25753
26400
  }
25754
26401
  }