@jmanuelcorral/openteam 0.17.0 → 0.17.1
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/.opencode/openteam.example.json +7 -2
- package/README.es.md +4 -3
- package/README.md +4 -3
- 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 +258 -38
- package/dist/commands/doctor.d.ts +12 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +62 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/config/errors.d.ts.map +1 -1
- package/dist/config/schema.d.ts +3 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +192 -32
- package/dist/local/lemonade.d.ts +5 -1
- package/dist/local/lemonade.d.ts.map +1 -1
- package/dist/local/slotPool.d.ts +58 -0
- package/dist/local/slotPool.d.ts.map +1 -0
- package/dist/local/types.d.ts +19 -0
- package/dist/local/types.d.ts.map +1 -1
- package/dist/orchestrator/coordinator.d.ts.map +1 -1
- package/dist/orchestrator/runtimeSelection.d.ts +7 -1
- package/dist/orchestrator/runtimeSelection.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -36,13 +36,18 @@
|
|
|
36
36
|
{
|
|
37
37
|
"id": "lemonade",
|
|
38
38
|
"enabled": false,
|
|
39
|
-
"baseURL": "http://localhost:
|
|
39
|
+
"baseURL": "http://localhost:13305/api/v1",
|
|
40
40
|
"defaultModel": {
|
|
41
41
|
"providerID": "lemonade",
|
|
42
42
|
"modelID": "Qwen3-Coder-30B-A3B-Instruct-GGUF"
|
|
43
43
|
},
|
|
44
44
|
"thinkingModel": "Qwen3-30B-A3B-Thinking-GGUF",
|
|
45
|
-
"coderModel": "Qwen3-Coder-30B-A3B-Instruct-GGUF"
|
|
45
|
+
"coderModel": "Qwen3-Coder-30B-A3B-Instruct-GGUF",
|
|
46
|
+
"maxConcurrency": 3,
|
|
47
|
+
"modelConcurrency": {
|
|
48
|
+
"Qwen3-Coder-30B-A3B-Instruct-GGUF": 3,
|
|
49
|
+
"Qwen3-30B-A3B-Thinking-GGUF": 1
|
|
50
|
+
}
|
|
46
51
|
},
|
|
47
52
|
{
|
|
48
53
|
"id": "foundry-local",
|
package/README.es.md
CHANGED
|
@@ -52,7 +52,7 @@ El router mantiene una garantía de privacidad: con `privacyMode: "forceLocalOnS
|
|
|
52
52
|
- Runtimes locales opcionales:
|
|
53
53
|
- Ollama en `http://localhost:11434/v1`.
|
|
54
54
|
- LM Studio en `http://localhost:1234/v1`.
|
|
55
|
-
- Lemonade Server en `http://localhost:
|
|
55
|
+
- Lemonade Server en `http://localhost:13305/api/v1`.
|
|
56
56
|
- Foundry Local con puerto dinámico descubierto por CLI en Windows.
|
|
57
57
|
|
|
58
58
|
## Instalación
|
|
@@ -373,6 +373,7 @@ ejecutas desde un subdirectorio verás "provider not configured" y debes hacer
|
|
|
373
373
|
| `local.runtimes[].discovery` | `"cli" \| "sdk" \| "manual"` opcional | sin default por item | Discovery de Foundry Local; el registry usa CLI si está configurado y no es `manual`. |
|
|
374
374
|
| `local.runtimes[].defaultModel` | `ModelRef` | requerido | Modelo por defecto de ese runtime. |
|
|
375
375
|
| `local.runtimes[].maxConcurrency` | entero positivo opcional | `4` | Límite de generaciones concurrentes de esta instancia (su número real de slots). Se aplica por instancia. |
|
|
376
|
+
| `local.runtimes[].modelConcurrency` | `Record<modelID, entero positivo>` opcional | ninguno | Slots por modelo, porque los slots pertenecen al modelo cargado y no al servidor: un mismo host Lemonade puede servir un modelo con `--parallel 3` y otro con `--parallel 1` a la vez. Cada modelo declarado obtiene su propia cola; el resto comparte el pool de `maxConcurrency` de la instancia. `openteam setup` lo rellena solo cuando el runtime informa de sus slots. |
|
|
376
377
|
| `budgets.sessionUSD` | `number` positivo opcional | sin límite | Presupuesto frontier por sesión. |
|
|
377
378
|
| `budgets.monthlyUSD` | `number` positivo opcional | sin límite | Presupuesto frontier mensual. |
|
|
378
379
|
| `budgets.frontierTokensPerSession` | `number` entero positivo opcional | sin límite | Límite de tokens frontier por sesión. |
|
|
@@ -729,7 +730,7 @@ Invoke-RestMethod -Uri "http://localhost:1234/v1/models" -Method Get
|
|
|
729
730
|
### Lemonade Server
|
|
730
731
|
|
|
731
732
|
```powershell
|
|
732
|
-
Invoke-RestMethod -Uri "http://localhost:
|
|
733
|
+
Invoke-RestMethod -Uri "http://localhost:13305/api/v1/models" -Method Get
|
|
733
734
|
```
|
|
734
735
|
|
|
735
736
|
### Foundry Local
|
|
@@ -824,7 +825,7 @@ Consulta [docs/compatibility.md](docs/compatibility.md). Resumen verificado el `
|
|
|
824
825
|
|
|
825
826
|
| Superficie | Versión / contrato |
|
|
826
827
|
| --- | --- |
|
|
827
|
-
| openteam | `0.17.
|
|
828
|
+
| openteam | `0.17.1`; versión actual del paquete |
|
|
828
829
|
| `@opencode-ai/plugin` | `1.18.19` |
|
|
829
830
|
| `@opencode-ai/sdk` | `1.18.19` |
|
|
830
831
|
| Hook de routing | `chat.message`; no `chat.params` para cambiar modelo |
|
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ The router keeps a privacy guarantee: with `privacyMode: "forceLocalOnSensitive"
|
|
|
61
61
|
- Optional local runtimes:
|
|
62
62
|
- Ollama at `http://localhost:11434/v1`.
|
|
63
63
|
- LM Studio at `http://localhost:1234/v1`.
|
|
64
|
-
- Lemonade Server at `http://localhost:
|
|
64
|
+
- Lemonade Server at `http://localhost:13305/api/v1`.
|
|
65
65
|
- Foundry Local with a dynamic port discovered via CLI on Windows.
|
|
66
66
|
|
|
67
67
|
> Local runtimes are **optional**. You can run openteam **frontier-only**, or point it at an Ollama / LM Studio / Lemonade Server running on **another machine on your LAN**.
|
|
@@ -325,6 +325,7 @@ configured" and should `cd` to the project root first.
|
|
|
325
325
|
| `local.runtimes[].discovery` | `"cli" \| "sdk" \| "manual"` optional | none per item | Foundry Local discovery; the registry uses CLI when configured and not `manual`. |
|
|
326
326
|
| `local.runtimes[].defaultModel` | `ModelRef` | required | Default model for that runtime. |
|
|
327
327
|
| `local.runtimes[].maxConcurrency` | positive integer, optional | `4` | Concurrent-generation cap for this instance (its real slot count). Applied per instance. |
|
|
328
|
+
| `local.runtimes[].modelConcurrency` | `Record<modelID, positive integer>`, optional | none | Per-model slot counts, because slots belong to the loaded model rather than to the server: a single Lemonade host can serve one model at `--parallel 3` and another at `--parallel 1` simultaneously. Each declared model gets its own queue; every other model shares the instance-wide `maxConcurrency` pool. Populated automatically by `openteam setup` when the runtime reports its slots. |
|
|
328
329
|
| `budgets.sessionUSD` | positive number, optional | unlimited | Frontier budget per session. |
|
|
329
330
|
| `budgets.monthlyUSD` | positive number, optional | unlimited | Monthly frontier budget. |
|
|
330
331
|
| `budgets.frontierTokensPerSession` | positive integer, optional | unlimited | Frontier token limit per session. |
|
|
@@ -622,7 +623,7 @@ Invoke-RestMethod -Uri "http://localhost:1234/v1/models" -Method Get
|
|
|
622
623
|
### Lemonade Server
|
|
623
624
|
|
|
624
625
|
```powershell
|
|
625
|
-
Invoke-RestMethod -Uri "http://localhost:
|
|
626
|
+
Invoke-RestMethod -Uri "http://localhost:13305/api/v1/models" -Method Get
|
|
626
627
|
```
|
|
627
628
|
|
|
628
629
|
### Foundry Local
|
|
@@ -713,7 +714,7 @@ See [docs/compatibility.md](docs/compatibility.md). Verified summary as of `2026
|
|
|
713
714
|
|
|
714
715
|
| Surface | Version / contract |
|
|
715
716
|
| --- | --- |
|
|
716
|
-
| openteam | `0.17.
|
|
717
|
+
| openteam | `0.17.1`; current package version |
|
|
717
718
|
| `@opencode-ai/plugin` | `1.18.19` |
|
|
718
719
|
| `@opencode-ai/sdk` | `1.18.19` |
|
|
719
720
|
| Routing hook | `chat.message`; not `chat.params` for model changes |
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"idempotent": true
|
|
35
35
|
},
|
|
36
36
|
"performance": {
|
|
37
|
-
"p95Millis": 0.
|
|
37
|
+
"p95Millis": 0.34230600000000777,
|
|
38
38
|
"budgetMillis": 50,
|
|
39
39
|
"samples": 100
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"verdict": "pass",
|
|
43
43
|
"failedGates": [],
|
|
44
|
-
"digest": "
|
|
44
|
+
"digest": "3ae52181594e67aee315d4d71b6fd3a58dc34e2b5e74677464b24b57f30e3d8c"
|
|
45
45
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"rawFindings": 0
|
|
21
21
|
},
|
|
22
22
|
"overhead": {
|
|
23
|
-
"p95Millis": 0.
|
|
23
|
+
"p95Millis": 0.26040199999999913,
|
|
24
24
|
"budgetMillis": 25,
|
|
25
25
|
"samples": 1000
|
|
26
26
|
},
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
},
|
|
36
36
|
"verdict": "pass",
|
|
37
37
|
"failedGates": [],
|
|
38
|
-
"digest": "
|
|
38
|
+
"digest": "7372b6e7a11519a55b6db9255ea7132ab3d5244c8659bff981368879f13dffbd"
|
|
39
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setupAdapters.d.ts","sourceRoot":"","sources":["../../src/cli/setupAdapters.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EACV,eAAe,EAEf,QAAQ,EAET,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,KAAK,QAAQ,EAEd,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAyBrD,qDAAqD;AACrD,eAAO,MAAM,aAAa,EAAE,QA8E3B,CAAC;AA6BF;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,OAAO,CACzD,sBAAsB,EAAE,CACzB,CAcA;AACD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"setupAdapters.d.ts","sourceRoot":"","sources":["../../src/cli/setupAdapters.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EACV,eAAe,EAEf,QAAQ,EAET,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,KAAK,QAAQ,EAEd,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAyBrD,qDAAqD;AACrD,eAAO,MAAM,aAAa,EAAE,QA8E3B,CAAC;AA6BF;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,OAAO,CACzD,sBAAsB,EAAE,CACzB,CAcA;AACD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CA6B7E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,GACb,CAAC,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,CAAC,CA8BnE"}
|
package/dist/cli.js
CHANGED
|
@@ -461,6 +461,7 @@ var LocalRuntimeSchema = z2.object({
|
|
|
461
461
|
discovery: z2.enum(["cli", "sdk", "manual"]).optional(),
|
|
462
462
|
defaultModel: ModelRefSchema,
|
|
463
463
|
maxConcurrency: z2.number().int().positive().optional(),
|
|
464
|
+
modelConcurrency: z2.record(z2.string().min(1), z2.number().int().positive()).optional(),
|
|
464
465
|
reservedInteractiveSlots: z2.number().int().nonnegative().optional(),
|
|
465
466
|
thinkingModel: z2.string().min(1).optional(),
|
|
466
467
|
coderModel: z2.string().min(1).optional()
|
|
@@ -682,6 +683,16 @@ function classifyHeuristic(task) {
|
|
|
682
683
|
};
|
|
683
684
|
}
|
|
684
685
|
|
|
686
|
+
// src/local/slotPool.ts
|
|
687
|
+
var POOL_SEPARATOR = "::";
|
|
688
|
+
function slotPoolKey(runtime, modelID) {
|
|
689
|
+
if (modelID === undefined) {
|
|
690
|
+
return runtime.id;
|
|
691
|
+
}
|
|
692
|
+
const declared = runtime.modelConcurrency?.[modelID];
|
|
693
|
+
return declared === undefined ? runtime.id : `${runtime.id}${POOL_SEPARATOR}${modelID}`;
|
|
694
|
+
}
|
|
695
|
+
|
|
685
696
|
// src/capabilities/budget.ts
|
|
686
697
|
var WARNING_UTILIZATION = 0.8;
|
|
687
698
|
function projectedSpend(current, estimatedCostUSD) {
|
|
@@ -2290,18 +2301,19 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch) {
|
|
|
2290
2301
|
if (runtimeId !== undefined && deps.runtimeLimiter !== undefined) {
|
|
2291
2302
|
const limiter = deps.runtimeLimiter;
|
|
2292
2303
|
const priority = priorityForRole(role);
|
|
2293
|
-
|
|
2304
|
+
const poolKey = slotPoolKey(configuredRuntime(runtimeId, input.config) ?? { id: runtimeId }, decision2.selected.modelID);
|
|
2305
|
+
release = limiter.tryAcquire(poolKey, priority);
|
|
2294
2306
|
let waitedMs = 0;
|
|
2295
2307
|
if (release === undefined) {
|
|
2296
|
-
const acquisition = await limiter.acquire(
|
|
2308
|
+
const acquisition = await limiter.acquire(poolKey, priority);
|
|
2297
2309
|
release = acquisition.release;
|
|
2298
2310
|
waitedMs = acquisition.waitedMs;
|
|
2299
2311
|
}
|
|
2300
2312
|
queueObservation = {
|
|
2301
2313
|
runtimeId,
|
|
2302
2314
|
waitedMs,
|
|
2303
|
-
activeCount: limiter.activeCount(
|
|
2304
|
-
queuedCount: limiter.queuedCount(
|
|
2315
|
+
activeCount: limiter.activeCount(poolKey),
|
|
2316
|
+
queuedCount: limiter.queuedCount(poolKey)
|
|
2305
2317
|
};
|
|
2306
2318
|
}
|
|
2307
2319
|
try {
|
|
@@ -3102,6 +3114,7 @@ var KNOWN_CONFIG_KEYS_BY_PATH = new Map([
|
|
|
3102
3114
|
"discovery",
|
|
3103
3115
|
"defaultModel",
|
|
3104
3116
|
"maxConcurrency",
|
|
3117
|
+
"modelConcurrency",
|
|
3105
3118
|
"reservedInteractiveSlots",
|
|
3106
3119
|
"thinkingModel",
|
|
3107
3120
|
"coderModel"
|
|
@@ -10024,24 +10037,141 @@ function ensureFoundryV1BaseURL(endpoint) {
|
|
|
10024
10037
|
}
|
|
10025
10038
|
|
|
10026
10039
|
// src/local/lemonade.ts
|
|
10027
|
-
var LEMONADE_DEFAULT_BASE_URL = "http://localhost:
|
|
10040
|
+
var LEMONADE_DEFAULT_BASE_URL = "http://localhost:13305/api/v1";
|
|
10041
|
+
var NON_TEXT_LABELS = new Set([
|
|
10042
|
+
"image",
|
|
10043
|
+
"tts",
|
|
10044
|
+
"transcription",
|
|
10045
|
+
"embedding",
|
|
10046
|
+
"reranking"
|
|
10047
|
+
]);
|
|
10048
|
+
var PARALLEL_ARG = /(?:^|\s)(?:--parallel|-np)[\s=]+(\d+)(?!\d)/;
|
|
10028
10049
|
function createLemonadeAdapter() {
|
|
10050
|
+
const listModels = async (options) => {
|
|
10051
|
+
const baseURL = normalizeBaseURL(options.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
|
|
10052
|
+
const downloaded = await listLemonadeModels(baseURL, options.fetch);
|
|
10053
|
+
const loaded = await readLoadedModels(baseURL, options.fetch);
|
|
10054
|
+
return enrichWithLoadState(downloaded, loaded);
|
|
10055
|
+
};
|
|
10029
10056
|
return {
|
|
10030
10057
|
id: "lemonade",
|
|
10031
10058
|
defaultBaseURL: LEMONADE_DEFAULT_BASE_URL,
|
|
10032
|
-
listModels
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10059
|
+
listModels,
|
|
10060
|
+
async probe(options) {
|
|
10061
|
+
const baseURL = normalizeBaseURL(options.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
|
|
10062
|
+
try {
|
|
10063
|
+
return {
|
|
10064
|
+
id: "lemonade",
|
|
10065
|
+
baseURL,
|
|
10066
|
+
reachable: true,
|
|
10067
|
+
models: await listModels({ ...options, baseURL }),
|
|
10068
|
+
probedAt: options.probedAt
|
|
10069
|
+
};
|
|
10070
|
+
} catch (error) {
|
|
10071
|
+
return unavailableSnapshot({
|
|
10072
|
+
id: "lemonade",
|
|
10073
|
+
baseURL,
|
|
10074
|
+
probedAt: options.probedAt,
|
|
10075
|
+
error
|
|
10076
|
+
});
|
|
10077
|
+
}
|
|
10042
10078
|
}
|
|
10043
10079
|
};
|
|
10044
10080
|
}
|
|
10081
|
+
async function listLemonadeModels(baseURL, fetch2) {
|
|
10082
|
+
const response = await fetch2(`${baseURL}/models`, {
|
|
10083
|
+
method: "GET",
|
|
10084
|
+
headers: { accept: "application/json" }
|
|
10085
|
+
});
|
|
10086
|
+
if (!response.ok) {
|
|
10087
|
+
throw new Error(`GET /models failed with HTTP ${response.status}`);
|
|
10088
|
+
}
|
|
10089
|
+
let payload;
|
|
10090
|
+
try {
|
|
10091
|
+
payload = await response.json();
|
|
10092
|
+
} catch (error) {
|
|
10093
|
+
throw new Error(`Malformed JSON from /models: ${errorMessage(error)}`);
|
|
10094
|
+
}
|
|
10095
|
+
const nonText = readNonTextModelIDs(payload);
|
|
10096
|
+
return parseOpenAIModels(payload).filter((model) => !nonText.has(model.modelID));
|
|
10097
|
+
}
|
|
10098
|
+
function readNonTextModelIDs(payload) {
|
|
10099
|
+
const ids = new Set;
|
|
10100
|
+
if (!isObject3(payload) || !Array.isArray(payload.data)) {
|
|
10101
|
+
return ids;
|
|
10102
|
+
}
|
|
10103
|
+
for (const entry of payload.data) {
|
|
10104
|
+
if (!isObject3(entry) || typeof entry.id !== "string") {
|
|
10105
|
+
continue;
|
|
10106
|
+
}
|
|
10107
|
+
if (isNonTextModel(entry)) {
|
|
10108
|
+
ids.add(entry.id);
|
|
10109
|
+
}
|
|
10110
|
+
}
|
|
10111
|
+
return ids;
|
|
10112
|
+
}
|
|
10113
|
+
function isNonTextModel(entry) {
|
|
10114
|
+
if (!Array.isArray(entry.labels)) {
|
|
10115
|
+
return false;
|
|
10116
|
+
}
|
|
10117
|
+
return entry.labels.some((label) => typeof label === "string" && NON_TEXT_LABELS.has(label));
|
|
10118
|
+
}
|
|
10119
|
+
async function readLoadedModels(baseURL, fetch2) {
|
|
10120
|
+
let payload;
|
|
10121
|
+
try {
|
|
10122
|
+
const response = await fetch2(`${baseURL}/health`, {
|
|
10123
|
+
method: "GET",
|
|
10124
|
+
headers: { accept: "application/json" }
|
|
10125
|
+
});
|
|
10126
|
+
if (!response.ok) {
|
|
10127
|
+
return;
|
|
10128
|
+
}
|
|
10129
|
+
payload = await response.json();
|
|
10130
|
+
} catch {
|
|
10131
|
+
return;
|
|
10132
|
+
}
|
|
10133
|
+
if (!isObject3(payload) || !Array.isArray(payload.all_models_loaded)) {
|
|
10134
|
+
return;
|
|
10135
|
+
}
|
|
10136
|
+
const loaded = new Map;
|
|
10137
|
+
for (const entry of payload.all_models_loaded) {
|
|
10138
|
+
if (!isObject3(entry) || typeof entry.model_name !== "string") {
|
|
10139
|
+
continue;
|
|
10140
|
+
}
|
|
10141
|
+
if (entry.loaded === false) {
|
|
10142
|
+
continue;
|
|
10143
|
+
}
|
|
10144
|
+
loaded.set(entry.model_name, { slots: readSlotCount(entry) });
|
|
10145
|
+
}
|
|
10146
|
+
return loaded;
|
|
10147
|
+
}
|
|
10148
|
+
function readSlotCount(entry) {
|
|
10149
|
+
const options = entry.recipe_options;
|
|
10150
|
+
if (!isObject3(options) || typeof options.llamacpp_args !== "string") {
|
|
10151
|
+
return;
|
|
10152
|
+
}
|
|
10153
|
+
const match = PARALLEL_ARG.exec(options.llamacpp_args);
|
|
10154
|
+
if (match === null) {
|
|
10155
|
+
return;
|
|
10156
|
+
}
|
|
10157
|
+
const parsed = Number.parseInt(match[1], 10);
|
|
10158
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
10159
|
+
}
|
|
10160
|
+
function enrichWithLoadState(models, loaded) {
|
|
10161
|
+
if (loaded === undefined) {
|
|
10162
|
+
return [...models];
|
|
10163
|
+
}
|
|
10164
|
+
return models.map((model) => {
|
|
10165
|
+
const hit = loaded.get(model.modelID);
|
|
10166
|
+
if (hit === undefined) {
|
|
10167
|
+
return { ...model, loaded: false };
|
|
10168
|
+
}
|
|
10169
|
+
return hit.slots === undefined ? { ...model, loaded: true } : { ...model, loaded: true, slots: hit.slots };
|
|
10170
|
+
});
|
|
10171
|
+
}
|
|
10172
|
+
function isObject3(value) {
|
|
10173
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10174
|
+
}
|
|
10045
10175
|
|
|
10046
10176
|
// src/local/lmstudio.ts
|
|
10047
10177
|
var LMSTUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
|
|
@@ -10270,6 +10400,9 @@ function createDetect(exec) {
|
|
|
10270
10400
|
reachable: snapshot.reachable,
|
|
10271
10401
|
models: snapshot.models.map((model) => model.modelID)
|
|
10272
10402
|
};
|
|
10403
|
+
if (snapshot.models.some((model) => model.loaded !== undefined)) {
|
|
10404
|
+
detected.modelInfo = snapshot.models;
|
|
10405
|
+
}
|
|
10273
10406
|
if (snapshot.error !== undefined) {
|
|
10274
10407
|
detected.error = snapshot.error;
|
|
10275
10408
|
}
|
|
@@ -10297,6 +10430,9 @@ function createProbeRuntime(exec) {
|
|
|
10297
10430
|
reachable: snapshot?.reachable ?? false,
|
|
10298
10431
|
models: snapshot?.models.map((model) => model.modelID) ?? []
|
|
10299
10432
|
};
|
|
10433
|
+
if (snapshot?.models.some((model) => model.loaded !== undefined) === true) {
|
|
10434
|
+
detected.modelInfo = snapshot.models;
|
|
10435
|
+
}
|
|
10300
10436
|
if (snapshot?.error !== undefined) {
|
|
10301
10437
|
detected.error = snapshot.error;
|
|
10302
10438
|
}
|
|
@@ -11049,6 +11185,14 @@ function runtimeLine(snapshot, runtime) {
|
|
|
11049
11185
|
const slots = declared === undefined ? ` · ${DEFAULT_LOCAL_MAX_CONCURRENCY} slot(s) (default)` : ` · ${declared} slot(s) (declared)`;
|
|
11050
11186
|
return ` ${mark} ${snapshot.id.padEnd(14)} ${snapshot.baseURL || "(no baseURL)"} — ${detail}${slots}`;
|
|
11051
11187
|
}
|
|
11188
|
+
function runtimeModelSlotsLine(runtime) {
|
|
11189
|
+
const entries = Object.entries(runtime?.modelConcurrency ?? {});
|
|
11190
|
+
if (entries.length === 0) {
|
|
11191
|
+
return;
|
|
11192
|
+
}
|
|
11193
|
+
const detail = entries.map(([modelID, slots]) => `${modelID} ${slots} slot(s)`).join(" · ");
|
|
11194
|
+
return ` ↳ per-model slots: ${detail}`;
|
|
11195
|
+
}
|
|
11052
11196
|
function isNetworkRuntime(baseURL) {
|
|
11053
11197
|
if (baseURL.length === 0) {
|
|
11054
11198
|
return false;
|
|
@@ -11304,6 +11448,10 @@ function renderDoctor(input) {
|
|
|
11304
11448
|
if (classLine !== undefined) {
|
|
11305
11449
|
lines.push(classLine);
|
|
11306
11450
|
}
|
|
11451
|
+
const modelSlots = runtimeModelSlotsLine(runtime);
|
|
11452
|
+
if (modelSlots !== undefined) {
|
|
11453
|
+
lines.push(modelSlots);
|
|
11454
|
+
}
|
|
11307
11455
|
}
|
|
11308
11456
|
}
|
|
11309
11457
|
for (const snapshot of input.snapshots) {
|
|
@@ -12039,6 +12187,9 @@ function buildOpenTeamConfig(answers) {
|
|
|
12039
12187
|
},
|
|
12040
12188
|
maxConcurrency: choice.maxConcurrency ?? DEFAULT_LOCAL_MAX_CONCURRENCY
|
|
12041
12189
|
};
|
|
12190
|
+
if (choice.modelConcurrency !== undefined && Object.keys(choice.modelConcurrency).length > 0) {
|
|
12191
|
+
runtime.modelConcurrency = { ...choice.modelConcurrency };
|
|
12192
|
+
}
|
|
12042
12193
|
if (choice.thinkingModelID !== undefined && choice.thinkingModelID !== choice.defaultModelID) {
|
|
12043
12194
|
runtime.thinkingModel = choice.thinkingModelID;
|
|
12044
12195
|
}
|
|
@@ -12235,7 +12386,40 @@ async function chooseFrontier(prompt, profiles) {
|
|
|
12235
12386
|
}
|
|
12236
12387
|
return parseFrontierRef(selected);
|
|
12237
12388
|
}
|
|
12238
|
-
|
|
12389
|
+
function orderModelChoices(models, modelInfo) {
|
|
12390
|
+
const byID = new Map((modelInfo ?? []).map((model) => [model.modelID, model]));
|
|
12391
|
+
const anyLoadState = (modelInfo ?? []).some((model) => model.loaded !== undefined);
|
|
12392
|
+
const decorated = models.map((modelID, index) => {
|
|
12393
|
+
const info = byID.get(modelID);
|
|
12394
|
+
return {
|
|
12395
|
+
modelID,
|
|
12396
|
+
index,
|
|
12397
|
+
loaded: info?.loaded === true,
|
|
12398
|
+
slots: info?.slots
|
|
12399
|
+
};
|
|
12400
|
+
});
|
|
12401
|
+
if (!anyLoadState) {
|
|
12402
|
+
return decorated.map((entry) => ({
|
|
12403
|
+
value: entry.modelID,
|
|
12404
|
+
label: entry.modelID
|
|
12405
|
+
}));
|
|
12406
|
+
}
|
|
12407
|
+
return [...decorated].sort((a, b) => a.loaded === b.loaded ? a.index - b.index : a.loaded ? -1 : 1).map((entry) => ({
|
|
12408
|
+
value: entry.modelID,
|
|
12409
|
+
label: `${entry.modelID} ${modelStateSuffix(entry.loaded, entry.slots)}`
|
|
12410
|
+
}));
|
|
12411
|
+
}
|
|
12412
|
+
function modelStateSuffix(loaded, slots) {
|
|
12413
|
+
if (!loaded) {
|
|
12414
|
+
return "(not loaded)";
|
|
12415
|
+
}
|
|
12416
|
+
return slots === undefined ? "(loaded)" : `(loaded · ${slots} slot${slots === 1 ? "" : "s"})`;
|
|
12417
|
+
}
|
|
12418
|
+
function preferredModelID(models, modelInfo) {
|
|
12419
|
+
const loaded = (modelInfo ?? []).find((model) => model.loaded === true && models.includes(model.modelID));
|
|
12420
|
+
return loaded?.modelID ?? models[0];
|
|
12421
|
+
}
|
|
12422
|
+
async function chooseRuntimeModel(prompt, models, meta, modelInfo) {
|
|
12239
12423
|
if (models.length === 0) {
|
|
12240
12424
|
return prompt.text({
|
|
12241
12425
|
message: `Default model for ${meta.label} (no models detected)`,
|
|
@@ -12243,13 +12427,10 @@ async function chooseRuntimeModel(prompt, models, meta) {
|
|
|
12243
12427
|
initial: meta.fallbackModelID
|
|
12244
12428
|
});
|
|
12245
12429
|
}
|
|
12246
|
-
const first = models
|
|
12430
|
+
const first = preferredModelID(models, modelInfo);
|
|
12247
12431
|
const opts = {
|
|
12248
12432
|
message: `Default local model for ${meta.label}`,
|
|
12249
|
-
choices: models
|
|
12250
|
-
value: modelID,
|
|
12251
|
-
label: modelID
|
|
12252
|
-
}))
|
|
12433
|
+
choices: orderModelChoices(models, modelInfo)
|
|
12253
12434
|
};
|
|
12254
12435
|
if (first !== undefined) {
|
|
12255
12436
|
opts.initial = first;
|
|
@@ -12285,9 +12466,13 @@ function normalizeRemoteBaseURL(raw, defaultBaseURL) {
|
|
|
12285
12466
|
}
|
|
12286
12467
|
return `${url.origin}${url.pathname.replace(/\/+$/, "")}`;
|
|
12287
12468
|
}
|
|
12469
|
+
function connectionOf(info) {
|
|
12470
|
+
const models = info?.models ?? [];
|
|
12471
|
+
return info?.modelInfo === undefined ? { models } : { models, modelInfo: info.modelInfo };
|
|
12472
|
+
}
|
|
12288
12473
|
async function resolveRuntimeConnection(deps, meta, info) {
|
|
12289
12474
|
if (meta.defaultBaseURL === undefined) {
|
|
12290
|
-
return
|
|
12475
|
+
return connectionOf(info);
|
|
12291
12476
|
}
|
|
12292
12477
|
const location = await deps.prompt.select({
|
|
12293
12478
|
message: `Where does ${meta.label} run?`,
|
|
@@ -12306,23 +12491,22 @@ async function resolveRuntimeConnection(deps, meta, info) {
|
|
|
12306
12491
|
});
|
|
12307
12492
|
if (location === RUNTIME_LOCATION_LOCAL) {
|
|
12308
12493
|
const baseURL2 = info?.baseURL !== undefined && info.baseURL.length > 0 ? info.baseURL : meta.defaultBaseURL;
|
|
12309
|
-
return { baseURL: baseURL2,
|
|
12494
|
+
return { baseURL: baseURL2, ...connectionOf(info) };
|
|
12310
12495
|
}
|
|
12311
12496
|
const entered = await deps.prompt.text({
|
|
12312
12497
|
message: `${meta.label} URL on the network (OpenAI-compatible endpoint)`,
|
|
12313
12498
|
placeholder: remoteBaseURLExample(meta)
|
|
12314
12499
|
});
|
|
12315
12500
|
const baseURL = normalizeRemoteBaseURL(entered, meta.defaultBaseURL);
|
|
12316
|
-
let
|
|
12501
|
+
let probedRuntime;
|
|
12317
12502
|
if (deps.probeRuntime !== undefined) {
|
|
12318
12503
|
try {
|
|
12319
|
-
|
|
12320
|
-
models = probed.models;
|
|
12504
|
+
probedRuntime = await deps.probeRuntime(meta.id, baseURL);
|
|
12321
12505
|
} catch {}
|
|
12322
12506
|
}
|
|
12323
|
-
return { baseURL,
|
|
12507
|
+
return { baseURL, ...connectionOf(probedRuntime) };
|
|
12324
12508
|
}
|
|
12325
|
-
async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass) {
|
|
12509
|
+
async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass, modelInfo) {
|
|
12326
12510
|
const label = modelClass === "thinking" ? `Thinking model for ${meta.label} (design, analysis, review reasoning)` : `Coder model for ${meta.label} (writing and editing code)`;
|
|
12327
12511
|
if (models.length === 0) {
|
|
12328
12512
|
const raw = await prompt.text({
|
|
@@ -12334,18 +12518,18 @@ async function chooseClassModel(prompt, models, meta, defaultModelID, modelClass
|
|
|
12334
12518
|
}
|
|
12335
12519
|
return prompt.select({
|
|
12336
12520
|
message: label,
|
|
12337
|
-
choices: models.map((
|
|
12338
|
-
value:
|
|
12339
|
-
label:
|
|
12521
|
+
choices: orderModelChoices(models, modelInfo).map((choice) => ({
|
|
12522
|
+
value: choice.value,
|
|
12523
|
+
label: choice.value === defaultModelID ? `${choice.label} — default` : choice.label
|
|
12340
12524
|
})),
|
|
12341
12525
|
initial: defaultModelID
|
|
12342
12526
|
});
|
|
12343
12527
|
}
|
|
12344
12528
|
async function resolveEnabledRuntime(deps, meta, info) {
|
|
12345
12529
|
const connection = await resolveRuntimeConnection(deps, meta, info);
|
|
12346
|
-
const defaultModelID = await chooseRuntimeModel(deps.prompt, connection.models, meta);
|
|
12347
|
-
const thinkingModelID = await chooseClassModel(deps.prompt, connection.models, meta, defaultModelID, "thinking");
|
|
12348
|
-
const coderModelID = await chooseClassModel(deps.prompt, connection.models, meta, defaultModelID, "coder");
|
|
12530
|
+
const defaultModelID = await chooseRuntimeModel(deps.prompt, connection.models, meta, connection.modelInfo);
|
|
12531
|
+
const thinkingModelID = await chooseClassModel(deps.prompt, connection.models, meta, defaultModelID, "thinking", connection.modelInfo);
|
|
12532
|
+
const coderModelID = await chooseClassModel(deps.prompt, connection.models, meta, defaultModelID, "coder", connection.modelInfo);
|
|
12349
12533
|
const choice = {
|
|
12350
12534
|
id: meta.id,
|
|
12351
12535
|
enabled: true,
|
|
@@ -12357,12 +12541,38 @@ async function resolveEnabledRuntime(deps, meta, info) {
|
|
|
12357
12541
|
if (connection.baseURL !== undefined) {
|
|
12358
12542
|
choice.baseURL = connection.baseURL;
|
|
12359
12543
|
}
|
|
12544
|
+
const modelConcurrency = reportedModelSlots(connection.modelInfo, [
|
|
12545
|
+
defaultModelID,
|
|
12546
|
+
thinkingModelID,
|
|
12547
|
+
coderModelID
|
|
12548
|
+
]);
|
|
12549
|
+
if (modelConcurrency !== undefined) {
|
|
12550
|
+
choice.modelConcurrency = modelConcurrency;
|
|
12551
|
+
}
|
|
12360
12552
|
return choice;
|
|
12361
12553
|
}
|
|
12554
|
+
function reportedModelSlots(modelInfo, usedModelIDs) {
|
|
12555
|
+
if (modelInfo === undefined) {
|
|
12556
|
+
return;
|
|
12557
|
+
}
|
|
12558
|
+
const used = new Set(usedModelIDs);
|
|
12559
|
+
const slots = {};
|
|
12560
|
+
for (const model of modelInfo) {
|
|
12561
|
+
if (model.slots !== undefined && used.has(model.modelID)) {
|
|
12562
|
+
slots[model.modelID] = model.slots;
|
|
12563
|
+
}
|
|
12564
|
+
}
|
|
12565
|
+
return Object.keys(slots).length > 0 ? slots : undefined;
|
|
12566
|
+
}
|
|
12362
12567
|
function instanceSuffix(index) {
|
|
12363
12568
|
return index < 26 ? String.fromCharCode(97 + index) : String(index + 1);
|
|
12364
12569
|
}
|
|
12365
|
-
async function promptSlotCount(prompt, meta) {
|
|
12570
|
+
async function promptSlotCount(prompt, meta, reported) {
|
|
12571
|
+
const detected = reportedSlotSummary(reported);
|
|
12572
|
+
if (detected !== undefined) {
|
|
12573
|
+
prompt.note(`${meta.label} reported its slots per model: ${detected.summary}. ` + "Slots belong to the loaded model, not the server, so openteam queues " + "each model against its own capacity instead of one shared number.", "Detected concurrency");
|
|
12574
|
+
return detected.max;
|
|
12575
|
+
}
|
|
12366
12576
|
const raw = await prompt.text({
|
|
12367
12577
|
message: `How many concurrent generation slots does ${meta.label} have? (match its real capacity; leaving one free keeps interactive work responsive)`,
|
|
12368
12578
|
placeholder: String(DEFAULT_LOCAL_MAX_CONCURRENCY),
|
|
@@ -12371,6 +12581,16 @@ async function promptSlotCount(prompt, meta) {
|
|
|
12371
12581
|
const parsed = Number.parseInt(raw.trim(), 10);
|
|
12372
12582
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_LOCAL_MAX_CONCURRENCY;
|
|
12373
12583
|
}
|
|
12584
|
+
function reportedSlotSummary(reported) {
|
|
12585
|
+
const entries = Object.entries(reported ?? {});
|
|
12586
|
+
if (entries.length === 0) {
|
|
12587
|
+
return;
|
|
12588
|
+
}
|
|
12589
|
+
return {
|
|
12590
|
+
summary: entries.map(([modelID, slots]) => `${modelID} = ${slots}`).join(", "),
|
|
12591
|
+
max: Math.max(...entries.map(([, slots]) => slots))
|
|
12592
|
+
};
|
|
12593
|
+
}
|
|
12374
12594
|
async function promptInstanceId(prompt, meta, defaultId, usedIds) {
|
|
12375
12595
|
for (;; ) {
|
|
12376
12596
|
const raw = await prompt.text({
|
|
@@ -12392,7 +12612,7 @@ async function resolveRuntimeInstances(deps, meta, info, usedIds) {
|
|
|
12392
12612
|
});
|
|
12393
12613
|
if (!fleet) {
|
|
12394
12614
|
const choice = await resolveEnabledRuntime(deps, meta, info);
|
|
12395
|
-
choice.maxConcurrency = await promptSlotCount(deps.prompt, meta);
|
|
12615
|
+
choice.maxConcurrency = await promptSlotCount(deps.prompt, meta, choice.modelConcurrency);
|
|
12396
12616
|
usedIds.add(choice.id);
|
|
12397
12617
|
return [choice];
|
|
12398
12618
|
}
|
|
@@ -12403,7 +12623,7 @@ async function resolveRuntimeInstances(deps, meta, info, usedIds) {
|
|
|
12403
12623
|
const choice = await resolveEnabledRuntime(deps, meta, info);
|
|
12404
12624
|
choice.id = id;
|
|
12405
12625
|
choice.kind = meta.id;
|
|
12406
|
-
choice.maxConcurrency = await promptSlotCount(deps.prompt, meta);
|
|
12626
|
+
choice.maxConcurrency = await promptSlotCount(deps.prompt, meta, choice.modelConcurrency);
|
|
12407
12627
|
usedIds.add(id);
|
|
12408
12628
|
instances.push(choice);
|
|
12409
12629
|
const another = await deps.prompt.confirm({
|
|
@@ -16239,7 +16459,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
16239
16459
|
// package.json
|
|
16240
16460
|
var package_default = {
|
|
16241
16461
|
name: "@jmanuelcorral/openteam",
|
|
16242
|
-
version: "0.17.
|
|
16462
|
+
version: "0.17.1",
|
|
16243
16463
|
packageManager: "bun@1.3.14",
|
|
16244
16464
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
16245
16465
|
license: "MIT",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LegacyLayoutFinding } from "../config/legacyPaths";
|
|
2
|
-
import { type OpenTeamConfig } from "../config/schema";
|
|
2
|
+
import { type LocalRuntime, type OpenTeamConfig } from "../config/schema";
|
|
3
3
|
import type { LocalRuntimeSnapshot } from "../local/types";
|
|
4
4
|
import { type DiagnosticCode } from "../telemetry/diagnostics";
|
|
5
5
|
import type { GraphViewHealth } from "../telemetry/graphView";
|
|
@@ -136,6 +136,17 @@ export type DoctorRosterAudit = {
|
|
|
136
136
|
readonly misassignedGuaranteedRoleEntries?: readonly DoctorRosterAuditEntry[];
|
|
137
137
|
readonly unprofiledRoleEntries?: readonly DoctorRosterAuditEntry[];
|
|
138
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* Reports the per-model slot split when a runtime declares one.
|
|
141
|
+
*
|
|
142
|
+
* Without this the `N slot(s)` figure above reads as the whole truth, hiding the
|
|
143
|
+
* case that motivated per-model pools: a host declaring 4 server slots may serve
|
|
144
|
+
* its coder model at 3 and its thinking model at 1, so the roles routed to the
|
|
145
|
+
* thinking model serialise on a single slot. Returns `undefined` when the
|
|
146
|
+
* runtime declares no per-model slots, so nothing is printed for the runtimes
|
|
147
|
+
* that cannot report them. Pure.
|
|
148
|
+
*/
|
|
149
|
+
export declare function runtimeModelSlotsLine(runtime: LocalRuntime | undefined): string | undefined;
|
|
139
150
|
/**
|
|
140
151
|
* Doctor's view of local-runtime queue-wait telemetry (#144). Presence of this
|
|
141
152
|
* object means queue telemetry was consulted; `summary === undefined` means it
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|