@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.
- package/README.es.md +29 -6
- package/README.md +29 -7
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/cli/setupAdapters.d.ts.map +1 -1
- package/dist/cli.js +775 -128
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +20 -15
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/config/schema.d.ts +101 -7
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +648 -122
- package/dist/local/lemonadeResidency.d.ts +2 -14
- package/dist/local/lemonadeResidency.d.ts.map +1 -1
- package/dist/local/llamaSwap.d.ts +5 -0
- package/dist/local/llamaSwap.d.ts.map +1 -0
- package/dist/local/llamaSwapRequestGuard.d.ts +11 -0
- package/dist/local/llamaSwapRequestGuard.d.ts.map +1 -0
- package/dist/local/llamaSwapResidency.d.ts +9 -0
- package/dist/local/llamaSwapResidency.d.ts.map +1 -0
- package/dist/local/modelResidency.d.ts +1 -0
- package/dist/local/modelResidency.d.ts.map +1 -1
- package/dist/local/registry.d.ts.map +1 -1
- package/dist/local/residency.d.ts +16 -0
- package/dist/local/residency.d.ts.map +1 -0
- package/dist/local/types.d.ts +10 -2
- package/dist/local/types.d.ts.map +1 -1
- package/dist/messages/executionSetup.d.ts +22 -3
- package/dist/messages/executionSetup.d.ts.map +1 -1
- package/dist/messages/memoryRuntime.d.ts +6 -0
- package/dist/messages/memoryRuntime.d.ts.map +1 -0
- package/dist/messages/memoryTool.d.ts +1 -1
- package/dist/messages/memoryTool.d.ts.map +1 -1
- package/dist/messages/modelResidency.d.ts +20 -2
- package/dist/messages/modelResidency.d.ts.map +1 -1
- package/dist/plugin/availability.d.ts.map +1 -1
- package/dist/plugin/memoryTool.d.ts.map +1 -1
- package/dist/plugin/modelResidency.d.ts.map +1 -1
- package/dist/storage/index/memoryRuntime.d.ts.map +1 -1
- package/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
|
|
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
|
|
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) =>
|
|
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
|
|
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]
|
|
16224
|
-
providerDisabled: (providerID) => `[openteam]
|
|
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/
|
|
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
|
|
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 ?
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
19115
|
+
throw new Error(residencySetupMessages(localRuntimeKind(choice)).modelNotLoaded(`${answers.primaryModel.providerID}/${answers.primaryModel.modelID}`));
|
|
18716
19116
|
}
|
|
18717
19117
|
}
|
|
18718
19118
|
}
|
|
18719
|
-
function
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
19006
|
-
throw new Error(
|
|
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
|
|
19023
|
-
throw new Error(
|
|
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
|
|
19080
|
-
throw new Error(
|
|
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 {
|
|
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
|
|
19091
|
-
throw new Error(
|
|
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
|
|
19097
|
-
throw new Error(
|
|
19500
|
+
if (runtimeRequiresModelResidency(meta.id))
|
|
19501
|
+
throw new Error(residencySetupMessages(meta.id).probeFailed, { cause });
|
|
19098
19502
|
}
|
|
19099
|
-
if (meta.id
|
|
19100
|
-
throw new Error(
|
|
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
|
|
19109
|
-
throw new Error(
|
|
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
|
|
19126
|
-
throw new Error(
|
|
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(
|
|
19190
|
-
initial: String(
|
|
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 :
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
20457
|
+
function preserveRetainedResidentRuntimes(generated, previous, opencode) {
|
|
20015
20458
|
const providers = recordAt2(opencode, "provider") ?? {};
|
|
20016
|
-
const retained = (previous?.local.runtimes ?? []).filter((runtime) => localRuntimeKind(runtime)
|
|
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
|
|
20057
|
-
const
|
|
20058
|
-
if (
|
|
20059
|
-
throw new Error(
|
|
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
|
|
20505
|
+
async function verifyResidencyBeforeWrite(deps, answers, config, opencode) {
|
|
20063
20506
|
for (const choice of answers.runtimes) {
|
|
20064
|
-
if (choice.enabled && localRuntimeKind(choice)
|
|
20065
|
-
throw new Error(
|
|
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
|
-
|
|
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" ||
|
|
20076
|
-
throw new Error(
|
|
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(
|
|
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(
|
|
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(
|
|
20570
|
+
throw new Error(messages.probeFailed, { cause });
|
|
20126
20571
|
}
|
|
20127
|
-
if (!fresh.reachable || fresh.id !== localRuntimeKind(runtime) || fresh.baseURL
|
|
20128
|
-
throw new Error(
|
|
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(
|
|
20132
|
-
throw new Error(
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
20290
|
-
} =
|
|
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
|
|
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])
|
|
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 =
|
|
20768
|
+
const v2Denials = residentV2Policies([
|
|
20300
20769
|
...opencodeConfig.experimental?.policies.map((policy) => policy.resource) ?? [],
|
|
20301
|
-
...effectiveOpenTeamConfig.local.runtimes.filter((runtime) => localRuntimeKind(runtime)
|
|
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.
|
|
20774
|
+
const v2Notice = v2Denials.length > 0 ? executionSetupMessages.residencyV2Restriction(v2Denials.map((policy) => policy.resource)) : undefined;
|
|
20306
20775
|
if (v2Notice !== undefined)
|
|
20307
|
-
prompt.note(v2Notice, executionSetupMessages.
|
|
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 =
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
26386
|
+
warn(memoryRuntimeMessages.rejectedLines(rebuildResult.rejectedLines));
|
|
25741
26387
|
}
|
|
25742
|
-
const embedder = makeEmbedder({ baseURL
|
|
25743
|
-
await ensureMemoryEmbeddings({ index, embedder, model:
|
|
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
|
}
|