@jmanuelcorral/openteam 0.1.6 → 0.1.8
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.md +8 -2
- package/dist/cli/initAdapters.d.ts +6 -1
- package/dist/cli/initAdapters.d.ts.map +1 -1
- package/dist/cli.js +492 -150
- package/dist/commands/init.d.ts +14 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/orchestratorAgent.d.ts +3 -2
- package/dist/commands/orchestratorAgent.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -197,7 +197,7 @@ El asistente:
|
|
|
197
197
|
|
|
198
198
|
1. Sondea los runtimes locales y marca los detectados.
|
|
199
199
|
2. Te deja habilitar runtimes y elegir el modelo por defecto de cada uno (o escribirlo si no se detectan modelos).
|
|
200
|
-
3. Ofrece el modelo frontier baseline
|
|
200
|
+
3. Ofrece el modelo frontier baseline a partir del **catálogo completo de [Models.dev](https://models.dev)** que openteam ya integra: una lista rápida con los más **baratos-capaces primero** (incluidos los **gratuitos**, etiquetados como `gratis`), una opción **«Ver todos los modelos por proveedor…»** para navegar el catálogo completo, y **«Otro (custom)»** para escribir un `provider/model`. Si el catálogo no se puede cargar (offline), cae a la lista curada.
|
|
201
201
|
4. Pregunta el modo de routing (`balanced`/`economy`/`quality`) y la política de privacidad.
|
|
202
202
|
5. Si ya existe `opencode.json` o `.opencode/openteam.json`, pide confirmación antes de sobrescribir.
|
|
203
203
|
|
|
@@ -207,7 +207,13 @@ Tras `init`, autentica el provider frontier (`opencode auth login`), arranca tu
|
|
|
207
207
|
|
|
208
208
|
`openteam init` genera un único **agente primario** llamado `openteam` (`.opencode/agent/openteam.md`). Pulsa **Tab** en opencode para seleccionarlo: así sabes explícitamente que estás en modo openteam, mientras el plugin sigue optimizando el modelo por debajo.
|
|
209
209
|
|
|
210
|
-
Ese orquestador funciona al estilo [Squad](https://bradygaster.github.io/squad/): **no trae subagentes precreados**. A partir de tu primer prompt analiza el objetivo y el repositorio, diseña el equipo mínimo de especialistas y **crea cada subagente a demanda** (escribiendo `.opencode/agent/<
|
|
210
|
+
Ese orquestador funciona al estilo [Squad](https://bradygaster.github.io/squad/): **no trae subagentes precreados**. A partir de tu primer prompt analiza el objetivo y el repositorio, diseña el equipo mínimo de especialistas y **crea cada subagente a demanda** (escribiendo `.opencode/agent/<nombre>.md` con `mode: subagent`), reutilizando los existentes antes de crear nuevos. Los roles mecánicos/bulk se dejan enrutar a modelos locales y solo se escala a frontier para arquitectura, seguridad o debugging ambiguo.
|
|
211
|
+
|
|
212
|
+
Como Squad, el equipo tiene **identidad temática**: el orquestador elige (o te pregunta) un **universo** y nombra a cada agente con un personaje de ese universo, registrando el reparto en `.opencode/agent/roster.md` para que los nombres **persistan** entre sesiones. Además de los roles específicos del proyecto, contempla tres **roles estándar** creados a demanda:
|
|
213
|
+
|
|
214
|
+
- **scribe** — memoria silenciosa: registra decisiones y aprendizajes en `.opencode/openteam-decisions.md` sin tocar el código (modelo local).
|
|
215
|
+
- **ralph** — automatización y triage: monitoriza el trabajo pendiente, lo prioriza, coordina la ejecución y **escala al humano** ante bloqueos o aprobaciones.
|
|
216
|
+
- **guardian** — seguridad y privacidad: **detecta y enmascara datos sensibles** (PII, secretos, API keys, tokens) antes de que salgan a frontier y hace revisión de seguridad; corre siempre en local y respeta `forceLocalOnSensitive`.
|
|
211
217
|
|
|
212
218
|
## Probar en otra máquina
|
|
213
219
|
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import type { ModelCapabilityProfile } from "../capabilities/types";
|
|
1
2
|
import type { DetectedRuntime, Prompter } from "../commands/init";
|
|
2
3
|
import { type ExecLike } from "../local/foundry-local";
|
|
3
4
|
/** Prompter interactivo basado en @clack/prompts. */
|
|
4
5
|
export declare const clackPrompter: Prompter;
|
|
5
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Carga el catálogo frontier de Models.dev (incluidos modelos gratuitos) para
|
|
8
|
+
* el selector de `init`. Cae a los perfiles curados si la red falla.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createLoadFrontierProfiles(): () => Promise<ModelCapabilityProfile[]>;
|
|
6
11
|
export declare function createDetect(exec: ExecLike): () => Promise<DetectedRuntime[]>;
|
|
7
12
|
//# sourceMappingURL=initAdapters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initAdapters.d.ts","sourceRoot":"","sources":["../../src/cli/initAdapters.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"initAdapters.d.ts","sourceRoot":"","sources":["../../src/cli/initAdapters.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EACV,eAAe,EAEf,QAAQ,EAET,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,KAAK,QAAQ,EAEd,MAAM,wBAAwB,CAAC;AA2BhC,qDAAqD;AACrD,eAAO,MAAM,aAAa,EAAE,QA8D3B,CAAC;AAuBF;;;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,CAuB7E"}
|
package/dist/cli.js
CHANGED
|
@@ -19,6 +19,313 @@ import {
|
|
|
19
19
|
text
|
|
20
20
|
} from "@clack/prompts";
|
|
21
21
|
|
|
22
|
+
// src/capabilities/curated.ts
|
|
23
|
+
var CURATED_FRONTIER_PROFILES = [
|
|
24
|
+
{
|
|
25
|
+
ref: { providerID: "openai", modelID: "gpt-5.4-mini" },
|
|
26
|
+
kind: "frontier",
|
|
27
|
+
contextWindow: 128000,
|
|
28
|
+
maxOutputTokens: 16384,
|
|
29
|
+
supportsToolCalling: true,
|
|
30
|
+
supportsVision: true,
|
|
31
|
+
reasoningTier: 3,
|
|
32
|
+
codeQualityTier: 3,
|
|
33
|
+
costPer1M: { inputUSD: 0.8, outputUSD: 3.2 },
|
|
34
|
+
availability: "available"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
ref: { providerID: "google", modelID: "gemini-3.5-flash" },
|
|
38
|
+
kind: "frontier",
|
|
39
|
+
contextWindow: 1e6,
|
|
40
|
+
maxOutputTokens: 65536,
|
|
41
|
+
supportsToolCalling: true,
|
|
42
|
+
supportsVision: true,
|
|
43
|
+
reasoningTier: 3,
|
|
44
|
+
codeQualityTier: 3,
|
|
45
|
+
costPer1M: { inputUSD: 0.35, outputUSD: 1.25 },
|
|
46
|
+
availability: "available"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
ref: { providerID: "anthropic", modelID: "claude-sonnet-4-5" },
|
|
50
|
+
kind: "frontier",
|
|
51
|
+
contextWindow: 200000,
|
|
52
|
+
maxOutputTokens: 64000,
|
|
53
|
+
supportsToolCalling: true,
|
|
54
|
+
supportsVision: true,
|
|
55
|
+
reasoningTier: 4,
|
|
56
|
+
codeQualityTier: 5,
|
|
57
|
+
costPer1M: { inputUSD: 3, outputUSD: 15 },
|
|
58
|
+
availability: "available"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
ref: { providerID: "openai", modelID: "gpt-5.3-codex" },
|
|
62
|
+
kind: "frontier",
|
|
63
|
+
contextWindow: 400000,
|
|
64
|
+
maxOutputTokens: 64000,
|
|
65
|
+
supportsToolCalling: true,
|
|
66
|
+
supportsVision: true,
|
|
67
|
+
reasoningTier: 5,
|
|
68
|
+
codeQualityTier: 5,
|
|
69
|
+
costPer1M: { inputUSD: 5, outputUSD: 20 },
|
|
70
|
+
availability: "available"
|
|
71
|
+
}
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
// src/capabilities/types.ts
|
|
75
|
+
import { z } from "zod";
|
|
76
|
+
var CapabilityTierSchema = z.union([
|
|
77
|
+
z.literal(0),
|
|
78
|
+
z.literal(1),
|
|
79
|
+
z.literal(2),
|
|
80
|
+
z.literal(3),
|
|
81
|
+
z.literal(4),
|
|
82
|
+
z.literal(5)
|
|
83
|
+
]);
|
|
84
|
+
var ComplexityTierSchema = z.enum([
|
|
85
|
+
"trivial",
|
|
86
|
+
"simple",
|
|
87
|
+
"moderate",
|
|
88
|
+
"hard"
|
|
89
|
+
]);
|
|
90
|
+
var ModelCapabilityProfileSchema = z.object({
|
|
91
|
+
ref: z.object({
|
|
92
|
+
providerID: z.string().min(1),
|
|
93
|
+
modelID: z.string().min(1)
|
|
94
|
+
}),
|
|
95
|
+
kind: z.enum(["local", "frontier", "router"]),
|
|
96
|
+
contextWindow: z.number().int().positive(),
|
|
97
|
+
maxOutputTokens: z.number().int().positive(),
|
|
98
|
+
supportsToolCalling: z.boolean(),
|
|
99
|
+
supportsVision: z.boolean(),
|
|
100
|
+
reasoningTier: CapabilityTierSchema,
|
|
101
|
+
codeQualityTier: CapabilityTierSchema,
|
|
102
|
+
costPer1M: z.object({
|
|
103
|
+
inputUSD: z.number().min(0),
|
|
104
|
+
outputUSD: z.number().min(0)
|
|
105
|
+
}),
|
|
106
|
+
availability: z.enum(["available", "degraded", "unavailable"])
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// src/capabilities/normalize.ts
|
|
110
|
+
function isRecord(value) {
|
|
111
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
112
|
+
}
|
|
113
|
+
function stringValue(value) {
|
|
114
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
115
|
+
}
|
|
116
|
+
function numberValue(value) {
|
|
117
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
121
|
+
const parsed = Number(value);
|
|
122
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
function boolValue(value) {
|
|
127
|
+
return value === true;
|
|
128
|
+
}
|
|
129
|
+
function nestedRecord(value, key) {
|
|
130
|
+
const nested = value[key];
|
|
131
|
+
return isRecord(nested) ? nested : undefined;
|
|
132
|
+
}
|
|
133
|
+
function nestedBoolean(value, firstKey, secondKey) {
|
|
134
|
+
const nested = nestedRecord(value, firstKey);
|
|
135
|
+
return nested !== undefined && boolValue(nested[secondKey]);
|
|
136
|
+
}
|
|
137
|
+
function includesImage(value) {
|
|
138
|
+
if (typeof value === "string") {
|
|
139
|
+
return value.toLowerCase().includes("image");
|
|
140
|
+
}
|
|
141
|
+
if (Array.isArray(value)) {
|
|
142
|
+
return value.some(includesImage);
|
|
143
|
+
}
|
|
144
|
+
if (isRecord(value)) {
|
|
145
|
+
return Object.values(value).some(includesImage);
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
function costPair(model) {
|
|
150
|
+
const cost = nestedRecord(model, "cost") ?? nestedRecord(model, "pricing");
|
|
151
|
+
if (cost === undefined) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const inputUSD = numberValue(cost.inputUSD) ?? numberValue(cost.input) ?? numberValue(cost.prompt);
|
|
155
|
+
const outputUSD = numberValue(cost.outputUSD) ?? numberValue(cost.output) ?? numberValue(cost.completion);
|
|
156
|
+
return inputUSD === undefined || outputUSD === undefined ? undefined : { inputUSD, outputUSD };
|
|
157
|
+
}
|
|
158
|
+
function tierFromModelName(modelID, reasoning) {
|
|
159
|
+
const normalized = modelID.toLowerCase();
|
|
160
|
+
if (typeof reasoning === "number") {
|
|
161
|
+
return Math.max(0, Math.min(5, Math.trunc(reasoning)));
|
|
162
|
+
}
|
|
163
|
+
if (reasoning === true || isRecord(reasoning)) {
|
|
164
|
+
return normalized.includes("flash") || normalized.includes("mini") ? 3 : 4;
|
|
165
|
+
}
|
|
166
|
+
if (normalized.includes("opus") || normalized.includes("codex")) {
|
|
167
|
+
return 5;
|
|
168
|
+
}
|
|
169
|
+
if (normalized.includes("sonnet") || normalized.includes("gpt-5")) {
|
|
170
|
+
return 4;
|
|
171
|
+
}
|
|
172
|
+
if (normalized.includes("flash") || normalized.includes("mini")) {
|
|
173
|
+
return 3;
|
|
174
|
+
}
|
|
175
|
+
return 2;
|
|
176
|
+
}
|
|
177
|
+
function codeTierFromModelName(modelID) {
|
|
178
|
+
const normalized = modelID.toLowerCase();
|
|
179
|
+
if (normalized.includes("codex") || normalized.includes("sonnet")) {
|
|
180
|
+
return 5;
|
|
181
|
+
}
|
|
182
|
+
if (normalized.includes("gpt-5") || normalized.includes("opus")) {
|
|
183
|
+
return 4;
|
|
184
|
+
}
|
|
185
|
+
if (normalized.includes("flash") || normalized.includes("mini")) {
|
|
186
|
+
return 3;
|
|
187
|
+
}
|
|
188
|
+
return 2;
|
|
189
|
+
}
|
|
190
|
+
function availability(value) {
|
|
191
|
+
return value === "degraded" || value === "unavailable" ? value : "available";
|
|
192
|
+
}
|
|
193
|
+
function modelEntriesFromProvider(providerID, provider) {
|
|
194
|
+
const models = provider.models;
|
|
195
|
+
if (Array.isArray(models)) {
|
|
196
|
+
return models.filter(isRecord).map((model) => ({
|
|
197
|
+
providerID,
|
|
198
|
+
modelID: stringValue(model.id) ?? stringValue(model.modelID) ?? "",
|
|
199
|
+
value: model
|
|
200
|
+
})).filter((entry) => entry.modelID.length > 0);
|
|
201
|
+
}
|
|
202
|
+
if (isRecord(models)) {
|
|
203
|
+
return Object.entries(models).filter(([, model]) => isRecord(model)).map(([modelID, model]) => ({
|
|
204
|
+
providerID,
|
|
205
|
+
modelID,
|
|
206
|
+
value: model
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
function catalogEntries(raw) {
|
|
212
|
+
if (!isRecord(raw)) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
const providers = isRecord(raw.providers) ? raw.providers : raw;
|
|
216
|
+
return Object.entries(providers).flatMap(([providerKey, provider]) => {
|
|
217
|
+
if (!isRecord(provider)) {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
const providerID = stringValue(provider.id) ?? stringValue(provider.providerID) ?? providerKey;
|
|
221
|
+
return modelEntriesFromProvider(providerID, provider);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function normalizeEntry(entry) {
|
|
225
|
+
const limit = nestedRecord(entry.value, "limit");
|
|
226
|
+
const contextWindow = numberValue(entry.value.contextWindow) ?? numberValue(entry.value.context_window) ?? (limit === undefined ? undefined : numberValue(limit.context));
|
|
227
|
+
const maxOutputTokens = numberValue(entry.value.maxOutputTokens) ?? numberValue(entry.value.max_output_tokens) ?? (limit === undefined ? undefined : numberValue(limit.output));
|
|
228
|
+
const costPer1M = costPair(entry.value);
|
|
229
|
+
if (contextWindow === undefined || maxOutputTokens === undefined || costPer1M === undefined) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const profile = {
|
|
233
|
+
ref: { providerID: entry.providerID, modelID: entry.modelID },
|
|
234
|
+
kind: "frontier",
|
|
235
|
+
contextWindow,
|
|
236
|
+
maxOutputTokens,
|
|
237
|
+
supportsToolCalling: boolValue(entry.value.tool_call) || boolValue(entry.value.toolCall) || nestedBoolean(entry.value, "features", "tool_call"),
|
|
238
|
+
supportsVision: boolValue(entry.value.vision) || includesImage(entry.value.modalities) || includesImage(entry.value.input_modalities),
|
|
239
|
+
reasoningTier: tierFromModelName(entry.modelID, entry.value.reasoning),
|
|
240
|
+
codeQualityTier: codeTierFromModelName(entry.modelID),
|
|
241
|
+
costPer1M,
|
|
242
|
+
availability: availability(entry.value.availability)
|
|
243
|
+
};
|
|
244
|
+
const parsed = ModelCapabilityProfileSchema.safeParse(profile);
|
|
245
|
+
return parsed.success ? parsed.data : undefined;
|
|
246
|
+
}
|
|
247
|
+
function normalizeModelsDevCatalog(raw) {
|
|
248
|
+
return catalogEntries(raw).map(normalizeEntry).filter((profile) => profile !== undefined).sort((left, right) => `${left.ref.providerID}/${left.ref.modelID}`.localeCompare(`${right.ref.providerID}/${right.ref.modelID}`));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/capabilities/catalog.ts
|
|
252
|
+
var DEFAULT_MODELS_DEV_CATALOG_URL = "https://models.dev/api.json";
|
|
253
|
+
var DEFAULT_CATALOG_TTL_MS = 60 * 60 * 1000;
|
|
254
|
+
async function loadCapabilityProfiles(deps, opts = {}) {
|
|
255
|
+
const fetchedAt = deps.now();
|
|
256
|
+
const ttlMs = opts.ttlMs ?? DEFAULT_CATALOG_TTL_MS;
|
|
257
|
+
const cachedEntry = opts.cache?.entry;
|
|
258
|
+
if (cachedEntry !== undefined && ttlMs > 0 && fetchedAt - cachedEntry.fetchedAt < ttlMs) {
|
|
259
|
+
return {
|
|
260
|
+
profiles: cloneProfiles(cachedEntry.profiles),
|
|
261
|
+
source: "cache",
|
|
262
|
+
fetchedAt: cachedEntry.fetchedAt
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const response = await deps.fetch(opts.url ?? DEFAULT_MODELS_DEV_CATALOG_URL, {
|
|
267
|
+
method: "GET",
|
|
268
|
+
headers: { accept: "application/json" }
|
|
269
|
+
});
|
|
270
|
+
if (!response.ok) {
|
|
271
|
+
return curatedResult(fetchedAt);
|
|
272
|
+
}
|
|
273
|
+
const profiles = mergeCuratedCosts(normalizeModelsDevCatalog(await response.json()));
|
|
274
|
+
if (profiles.length === 0) {
|
|
275
|
+
return curatedResult(fetchedAt);
|
|
276
|
+
}
|
|
277
|
+
if (opts.cache !== undefined) {
|
|
278
|
+
opts.cache.entry = {
|
|
279
|
+
profiles: cloneProfiles(profiles),
|
|
280
|
+
fetchedAt
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
profiles,
|
|
285
|
+
source: "models.dev",
|
|
286
|
+
fetchedAt
|
|
287
|
+
};
|
|
288
|
+
} catch {
|
|
289
|
+
return curatedResult(fetchedAt);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function curatedResult(fetchedAt) {
|
|
293
|
+
return {
|
|
294
|
+
profiles: cloneProfiles(CURATED_FRONTIER_PROFILES),
|
|
295
|
+
source: "curated",
|
|
296
|
+
fetchedAt
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
function mergeCuratedCosts(profiles) {
|
|
300
|
+
const curatedByRef = new Map(CURATED_FRONTIER_PROFILES.map((profile) => [profileKey(profile), profile]));
|
|
301
|
+
return profiles.map((profile) => {
|
|
302
|
+
const curated = curatedByRef.get(profileKey(profile));
|
|
303
|
+
if (curated === undefined || !hasUnknownCost(profile)) {
|
|
304
|
+
return cloneProfile(profile);
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
...cloneProfile(profile),
|
|
308
|
+
costPer1M: { ...curated.costPer1M }
|
|
309
|
+
};
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
function hasUnknownCost(profile) {
|
|
313
|
+
return profile.costPer1M.inputUSD === 0 || profile.costPer1M.outputUSD === 0;
|
|
314
|
+
}
|
|
315
|
+
function profileKey(profile) {
|
|
316
|
+
return `${profile.ref.providerID}/${profile.ref.modelID}`;
|
|
317
|
+
}
|
|
318
|
+
function cloneProfiles(profiles) {
|
|
319
|
+
return profiles.map(cloneProfile);
|
|
320
|
+
}
|
|
321
|
+
function cloneProfile(profile) {
|
|
322
|
+
return {
|
|
323
|
+
...profile,
|
|
324
|
+
ref: { ...profile.ref },
|
|
325
|
+
costPer1M: { ...profile.costPer1M }
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
22
329
|
// src/local/openai-compatible.ts
|
|
23
330
|
function normalizeBaseURL(baseURL) {
|
|
24
331
|
return baseURL.replace(/\/+$/, "");
|
|
@@ -448,6 +755,19 @@ var DETECTION_RUNTIMES = [
|
|
|
448
755
|
defaultModel: { providerID: "foundry-local", modelID: "probe" }
|
|
449
756
|
}
|
|
450
757
|
];
|
|
758
|
+
function createLoadFrontierProfiles() {
|
|
759
|
+
return async () => {
|
|
760
|
+
try {
|
|
761
|
+
const result = await loadCapabilityProfiles({
|
|
762
|
+
fetch: globalThis.fetch,
|
|
763
|
+
now: () => Date.now()
|
|
764
|
+
});
|
|
765
|
+
return result.profiles.length > 0 ? result.profiles : [...CURATED_FRONTIER_PROFILES];
|
|
766
|
+
} catch {
|
|
767
|
+
return [...CURATED_FRONTIER_PROFILES];
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
}
|
|
451
771
|
function createDetect(exec) {
|
|
452
772
|
return async () => {
|
|
453
773
|
const registry = new RuntimeRegistry({
|
|
@@ -472,18 +792,18 @@ function createDetect(exec) {
|
|
|
472
792
|
}
|
|
473
793
|
|
|
474
794
|
// src/config/schema.ts
|
|
475
|
-
import { z } from "zod";
|
|
476
|
-
var ModelRefSchema =
|
|
477
|
-
providerID:
|
|
478
|
-
modelID:
|
|
795
|
+
import { z as z2 } from "zod";
|
|
796
|
+
var ModelRefSchema = z2.object({
|
|
797
|
+
providerID: z2.string().min(1),
|
|
798
|
+
modelID: z2.string().min(1)
|
|
479
799
|
});
|
|
480
|
-
var RouterModeSchema =
|
|
481
|
-
var PrivacyModeSchema =
|
|
800
|
+
var RouterModeSchema = z2.enum(["economy", "balanced", "quality"]);
|
|
801
|
+
var PrivacyModeSchema = z2.enum([
|
|
482
802
|
"forceLocalOnSensitive",
|
|
483
803
|
"consentBeforeFrontier",
|
|
484
804
|
"off"
|
|
485
805
|
]);
|
|
486
|
-
var BaselineModeSchema =
|
|
806
|
+
var BaselineModeSchema = z2.enum(["auto", "pinned"]);
|
|
487
807
|
var defaultLocalModel = {
|
|
488
808
|
providerID: "ollama",
|
|
489
809
|
modelID: "qwen3:8b"
|
|
@@ -492,15 +812,15 @@ var defaultFrontierModel = {
|
|
|
492
812
|
providerID: "anthropic",
|
|
493
813
|
modelID: "claude-sonnet-4-5"
|
|
494
814
|
};
|
|
495
|
-
var LocalRuntimeSchema =
|
|
496
|
-
id:
|
|
497
|
-
enabled:
|
|
498
|
-
baseURL:
|
|
499
|
-
discovery:
|
|
815
|
+
var LocalRuntimeSchema = z2.object({
|
|
816
|
+
id: z2.enum(["ollama", "lmstudio", "foundry-local"]),
|
|
817
|
+
enabled: z2.boolean().default(true),
|
|
818
|
+
baseURL: z2.string().url().optional(),
|
|
819
|
+
discovery: z2.enum(["cli", "sdk", "manual"]).optional(),
|
|
500
820
|
defaultModel: ModelRefSchema
|
|
501
821
|
});
|
|
502
|
-
var OpenTeamConfigSchema =
|
|
503
|
-
baseline:
|
|
822
|
+
var OpenTeamConfigSchema = z2.object({
|
|
823
|
+
baseline: z2.object({
|
|
504
824
|
mode: BaselineModeSchema.default("auto"),
|
|
505
825
|
pinnedModel: ModelRefSchema.nullable().default(null),
|
|
506
826
|
hardDefault: ModelRefSchema.default(defaultFrontierModel)
|
|
@@ -509,19 +829,19 @@ var OpenTeamConfigSchema = z.object({
|
|
|
509
829
|
pinnedModel: null,
|
|
510
830
|
hardDefault: defaultFrontierModel
|
|
511
831
|
}),
|
|
512
|
-
router:
|
|
832
|
+
router: z2.object({
|
|
513
833
|
mode: RouterModeSchema.default("balanced"),
|
|
514
834
|
localDefault: ModelRefSchema.default(defaultLocalModel),
|
|
515
|
-
trivialPromptMaxChars:
|
|
516
|
-
frontierPromptMinChars:
|
|
835
|
+
trivialPromptMaxChars: z2.number().int().positive().default(280),
|
|
836
|
+
frontierPromptMinChars: z2.number().int().positive().default(2000)
|
|
517
837
|
}).default({
|
|
518
838
|
mode: "balanced",
|
|
519
839
|
localDefault: defaultLocalModel,
|
|
520
840
|
trivialPromptMaxChars: 280,
|
|
521
841
|
frontierPromptMinChars: 2000
|
|
522
842
|
}),
|
|
523
|
-
local:
|
|
524
|
-
runtimes:
|
|
843
|
+
local: z2.object({
|
|
844
|
+
runtimes: z2.array(LocalRuntimeSchema).min(1).default([
|
|
525
845
|
{
|
|
526
846
|
id: "ollama",
|
|
527
847
|
enabled: true,
|
|
@@ -539,11 +859,11 @@ var OpenTeamConfigSchema = z.object({
|
|
|
539
859
|
}
|
|
540
860
|
]
|
|
541
861
|
}),
|
|
542
|
-
budgets:
|
|
543
|
-
sessionUSD:
|
|
544
|
-
monthlyUSD:
|
|
545
|
-
frontierTokensPerSession:
|
|
546
|
-
hardStopOnBudgetExhaustion:
|
|
862
|
+
budgets: z2.object({
|
|
863
|
+
sessionUSD: z2.number().positive().optional(),
|
|
864
|
+
monthlyUSD: z2.number().positive().optional(),
|
|
865
|
+
frontierTokensPerSession: z2.number().int().positive().optional(),
|
|
866
|
+
hardStopOnBudgetExhaustion: z2.boolean().default(false)
|
|
547
867
|
}).default({ hardStopOnBudgetExhaustion: false }),
|
|
548
868
|
privacyMode: PrivacyModeSchema.default("forceLocalOnSensitive")
|
|
549
869
|
});
|
|
@@ -837,58 +1157,6 @@ ${HELP}`
|
|
|
837
1157
|
// src/commands/init.ts
|
|
838
1158
|
import { join } from "node:path";
|
|
839
1159
|
|
|
840
|
-
// src/capabilities/curated.ts
|
|
841
|
-
var CURATED_FRONTIER_PROFILES = [
|
|
842
|
-
{
|
|
843
|
-
ref: { providerID: "openai", modelID: "gpt-5.4-mini" },
|
|
844
|
-
kind: "frontier",
|
|
845
|
-
contextWindow: 128000,
|
|
846
|
-
maxOutputTokens: 16384,
|
|
847
|
-
supportsToolCalling: true,
|
|
848
|
-
supportsVision: true,
|
|
849
|
-
reasoningTier: 3,
|
|
850
|
-
codeQualityTier: 3,
|
|
851
|
-
costPer1M: { inputUSD: 0.8, outputUSD: 3.2 },
|
|
852
|
-
availability: "available"
|
|
853
|
-
},
|
|
854
|
-
{
|
|
855
|
-
ref: { providerID: "google", modelID: "gemini-3.5-flash" },
|
|
856
|
-
kind: "frontier",
|
|
857
|
-
contextWindow: 1e6,
|
|
858
|
-
maxOutputTokens: 65536,
|
|
859
|
-
supportsToolCalling: true,
|
|
860
|
-
supportsVision: true,
|
|
861
|
-
reasoningTier: 3,
|
|
862
|
-
codeQualityTier: 3,
|
|
863
|
-
costPer1M: { inputUSD: 0.35, outputUSD: 1.25 },
|
|
864
|
-
availability: "available"
|
|
865
|
-
},
|
|
866
|
-
{
|
|
867
|
-
ref: { providerID: "anthropic", modelID: "claude-sonnet-4-5" },
|
|
868
|
-
kind: "frontier",
|
|
869
|
-
contextWindow: 200000,
|
|
870
|
-
maxOutputTokens: 64000,
|
|
871
|
-
supportsToolCalling: true,
|
|
872
|
-
supportsVision: true,
|
|
873
|
-
reasoningTier: 4,
|
|
874
|
-
codeQualityTier: 5,
|
|
875
|
-
costPer1M: { inputUSD: 3, outputUSD: 15 },
|
|
876
|
-
availability: "available"
|
|
877
|
-
},
|
|
878
|
-
{
|
|
879
|
-
ref: { providerID: "openai", modelID: "gpt-5.3-codex" },
|
|
880
|
-
kind: "frontier",
|
|
881
|
-
contextWindow: 400000,
|
|
882
|
-
maxOutputTokens: 64000,
|
|
883
|
-
supportsToolCalling: true,
|
|
884
|
-
supportsVision: true,
|
|
885
|
-
reasoningTier: 5,
|
|
886
|
-
codeQualityTier: 5,
|
|
887
|
-
costPer1M: { inputUSD: 5, outputUSD: 20 },
|
|
888
|
-
availability: "available"
|
|
889
|
-
}
|
|
890
|
-
];
|
|
891
|
-
|
|
892
1160
|
// src/config/persist.ts
|
|
893
1161
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
894
1162
|
import { dirname } from "node:path";
|
|
@@ -934,38 +1202,70 @@ function buildOrchestratorAgent(frontier) {
|
|
|
934
1202
|
"primario: no existe un equipo precreado. Tú **construyes el equipo de",
|
|
935
1203
|
"subagentes a demanda** según el objetivo del usuario y del repositorio.",
|
|
936
1204
|
"",
|
|
1205
|
+
"## Casting: elige un universo y nombra al equipo",
|
|
1206
|
+
"",
|
|
1207
|
+
"Como Squad, el equipo tiene una identidad temática persistente:",
|
|
1208
|
+
"",
|
|
1209
|
+
"1. En el primer arranque, **elige un universo** temático (p. ej. una",
|
|
1210
|
+
" película, serie, cómic o mitología). Si el usuario tiene preferencia,",
|
|
1211
|
+
" pregúntasela; si no, propón uno y confírmalo.",
|
|
1212
|
+
"2. Asigna a cada subagente el **nombre de un personaje** de ese universo; el",
|
|
1213
|
+
" nombre del fichero (`.opencode/agent/<nombre>.md`) es su alias para",
|
|
1214
|
+
" `@mención`, y su rol queda claro en el `description`.",
|
|
1215
|
+
"3. **Registra el casting** en `.opencode/agent/roster.md` (universo + tabla",
|
|
1216
|
+
" nombre → rol → modelo) para que los nombres **persistan** entre sesiones.",
|
|
1217
|
+
" Reutiliza siempre el mismo reparto; no vuelvas a castear sin motivo.",
|
|
1218
|
+
"",
|
|
937
1219
|
"## Primer arranque (primer prompt de la sesión)",
|
|
938
1220
|
"",
|
|
939
|
-
"1. Analiza el objetivo y explora el repositorio (`read`/`glob`/`grep`)
|
|
940
|
-
" entender stack, dominio y alcance real.",
|
|
1221
|
+
"1. Analiza el objetivo y explora el repositorio (`read`/`glob`/`grep`).",
|
|
941
1222
|
"2. Diseña el **equipo mínimo** necesario: define solo los roles que el",
|
|
942
|
-
" trabajo requiera (p. ej.
|
|
943
|
-
"
|
|
944
|
-
"3. Crea cada subagente **a demanda** escribiendo `.opencode/agent/<
|
|
945
|
-
" - Frontmatter: `description` (obligatorio
|
|
946
|
-
" `temperature`, `permission` con lo mínimo necesario,
|
|
947
|
-
" **opcional**.",
|
|
1223
|
+
" trabajo requiera (p. ej. arquitecto, backend, frontend, reviewer,",
|
|
1224
|
+
" tester, docs). No inventes roles que no vayas a usar.",
|
|
1225
|
+
"3. Crea cada subagente **a demanda** escribiendo `.opencode/agent/<nombre>.md`:",
|
|
1226
|
+
" - Frontmatter: `description` (obligatorio, incluye rol y universo),",
|
|
1227
|
+
" `mode: subagent`, `temperature`, `permission` con lo mínimo necesario,",
|
|
1228
|
+
" y `model` **opcional**.",
|
|
948
1229
|
" - Deja `model` sin fijar para que herede el default y openteam lo enrute",
|
|
949
1230
|
" local-first, o fija un modelo local para roles mecánicos/bulk. Reserva",
|
|
950
1231
|
" frontier solo para arquitectura, seguridad o debugging ambiguo:",
|
|
951
1232
|
" openteam ya enruta cheapest-capable automáticamente.",
|
|
952
1233
|
" - Un prompt de rol enfocado y accionable.",
|
|
953
1234
|
"",
|
|
1235
|
+
"## Roles estándar del equipo",
|
|
1236
|
+
"",
|
|
1237
|
+
"Además de los roles específicos del proyecto, incluye estos roles estándar",
|
|
1238
|
+
"(créalos a demanda, con su nombre del universo) cuando aporten valor:",
|
|
1239
|
+
"",
|
|
1240
|
+
"- **scribe** — memoria silenciosa del equipo. Registra decisiones y",
|
|
1241
|
+
" aprendizajes en un log compartido (`.opencode/openteam-decisions.md`) sin",
|
|
1242
|
+
" ejecutar cambios de código. Modelo **local**; permisos de solo lectura más",
|
|
1243
|
+
" edición de ese log.",
|
|
1244
|
+
"- **ralph** — automatización y triage. Monitoriza el trabajo pendiente",
|
|
1245
|
+
" (issues/tareas), lo prioriza, coordina la ejecución delegando en los",
|
|
1246
|
+
" especialistas y **escala al humano** ante bloqueos, riesgos o aprobaciones.",
|
|
1247
|
+
"- **guardian** — seguridad y privacidad. **Detecta y enmascara datos",
|
|
1248
|
+
" sensibles** (PII, secretos, API keys, tokens, credenciales) antes de que",
|
|
1249
|
+
" salgan del repo o a frontier, y hace revisión de seguridad. Corre",
|
|
1250
|
+
" **siempre en local** y respeta `privacyMode`/`forceLocalOnSensitive`: nunca",
|
|
1251
|
+
" deja pasar datos sensibles a frontier. Revisa las entradas y salidas de los",
|
|
1252
|
+
" demás agentes cuando toquen datos sensibles.",
|
|
1253
|
+
"",
|
|
954
1254
|
"## Operación",
|
|
955
1255
|
"",
|
|
956
1256
|
"- Delega el trabajo con la herramienta `task` al subagente adecuado; tú te",
|
|
957
1257
|
" mantienes como coordinador y no implementas lo que puede hacer un subagente.",
|
|
958
1258
|
"- Crea subagentes **justo cuando el trabajo lo pide**, nunca “por si acaso”.",
|
|
959
|
-
" Revisa `.opencode/agent/` y reutiliza los
|
|
960
|
-
" crear uno nuevo.",
|
|
961
|
-
"- Respeta el routing y la privacidad de openteam
|
|
962
|
-
"
|
|
963
|
-
"- Resume al usuario qué equipo has creado y por qu
|
|
1259
|
+
" Revisa `.opencode/agent/` y el `roster.md`, y reutiliza los existentes antes",
|
|
1260
|
+
" de crear uno nuevo.",
|
|
1261
|
+
"- Respeta el routing y la privacidad de openteam; el `guardian` es la última",
|
|
1262
|
+
" línea antes de enviar nada sensible a frontier.",
|
|
1263
|
+
"- Resume al usuario qué universo elegiste, qué equipo has creado y por qué.",
|
|
964
1264
|
"",
|
|
965
1265
|
"## Límites",
|
|
966
1266
|
"",
|
|
967
1267
|
"- Un único primario (tú); todo lo demás son subagentes creados a demanda.",
|
|
968
|
-
"- No borres ni sobrescribas subagentes
|
|
1268
|
+
"- No borres ni sobrescribas subagentes ni el `roster.md` sin confirmarlo.",
|
|
969
1269
|
"- Los subagentes nuevos quedan disponibles para `@mención` y para la",
|
|
970
1270
|
" herramienta `task` una vez opencode recarga los agentes del proyecto.",
|
|
971
1271
|
""
|
|
@@ -1002,11 +1302,26 @@ var KNOWN_RUNTIMES = [
|
|
|
1002
1302
|
function weightedCost(inputUSD, outputUSD) {
|
|
1003
1303
|
return 0.75 * inputUSD + 0.25 * outputUSD;
|
|
1004
1304
|
}
|
|
1005
|
-
function
|
|
1006
|
-
return
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1305
|
+
function profileWeightedCost(profile) {
|
|
1306
|
+
return weightedCost(profile.costPer1M.inputUSD, profile.costPer1M.outputUSD);
|
|
1307
|
+
}
|
|
1308
|
+
function sortFrontierByCost(profiles) {
|
|
1309
|
+
return [...profiles].sort((a, b) => profileWeightedCost(a) - profileWeightedCost(b));
|
|
1310
|
+
}
|
|
1311
|
+
function isFreeFrontier(profile) {
|
|
1312
|
+
return profile.costPer1M.inputUSD === 0 && profile.costPer1M.outputUSD === 0;
|
|
1313
|
+
}
|
|
1314
|
+
function frontierCostLabel(profile) {
|
|
1315
|
+
if (isFreeFrontier(profile)) {
|
|
1316
|
+
return "gratis";
|
|
1317
|
+
}
|
|
1318
|
+
return `$${profile.costPer1M.inputUSD}/$${profile.costPer1M.outputUSD} por 1M`;
|
|
1319
|
+
}
|
|
1320
|
+
function frontierProviders(profiles) {
|
|
1321
|
+
return [...new Set(profiles.map((profile) => profile.ref.providerID))].sort((a, b) => a.localeCompare(b));
|
|
1322
|
+
}
|
|
1323
|
+
function frontierModelsForProvider(profiles, providerID) {
|
|
1324
|
+
return sortFrontierByCost(profiles.filter((profile) => profile.ref.providerID === providerID));
|
|
1010
1325
|
}
|
|
1011
1326
|
function knownRuntime(id) {
|
|
1012
1327
|
const found = KNOWN_RUNTIMES.find((runtime) => runtime.id === id);
|
|
@@ -1093,31 +1408,87 @@ function serializeOpencodeConfig(config) {
|
|
|
1093
1408
|
`;
|
|
1094
1409
|
}
|
|
1095
1410
|
var CUSTOM_FRONTIER = "__custom__";
|
|
1096
|
-
|
|
1097
|
-
|
|
1411
|
+
var BROWSE_FRONTIER = "__browse__";
|
|
1412
|
+
var QUICK_FRONTIER_LIMIT = 12;
|
|
1413
|
+
function frontierRefKey(choice) {
|
|
1414
|
+
return `${choice.providerID}/${choice.modelID}`;
|
|
1415
|
+
}
|
|
1416
|
+
function parseFrontierRef(ref) {
|
|
1417
|
+
const slash = ref.indexOf("/");
|
|
1418
|
+
if (slash <= 0 || slash === ref.length - 1) {
|
|
1419
|
+
throw new Error(`modelo frontier inválido: "${ref}" (usa provider/model)`);
|
|
1420
|
+
}
|
|
1421
|
+
return { providerID: ref.slice(0, slash), modelID: ref.slice(slash + 1) };
|
|
1422
|
+
}
|
|
1423
|
+
async function browseFrontier(prompt, profiles) {
|
|
1424
|
+
const providers = frontierProviders(profiles);
|
|
1425
|
+
if (providers.length === 0) {
|
|
1426
|
+
const ref = await prompt.text({
|
|
1427
|
+
message: "Modelo frontier en formato provider/model",
|
|
1428
|
+
placeholder: "anthropic/claude-sonnet-4-5"
|
|
1429
|
+
});
|
|
1430
|
+
return parseFrontierRef(ref);
|
|
1431
|
+
}
|
|
1432
|
+
const providerID = await prompt.select({
|
|
1433
|
+
message: "Proveedor",
|
|
1434
|
+
choices: providers.map((id) => ({
|
|
1435
|
+
value: id,
|
|
1436
|
+
label: `${id} (${frontierModelsForProvider(profiles, id).length} modelos)`
|
|
1437
|
+
})),
|
|
1438
|
+
initial: providers[0] ?? ""
|
|
1439
|
+
});
|
|
1440
|
+
const models = frontierModelsForProvider(profiles, providerID);
|
|
1441
|
+
const first = models[0];
|
|
1442
|
+
const opts = {
|
|
1443
|
+
message: `Modelo de ${providerID}`,
|
|
1444
|
+
choices: models.map((profile) => ({
|
|
1445
|
+
value: profile.ref.modelID,
|
|
1446
|
+
label: profile.ref.modelID,
|
|
1447
|
+
hint: frontierCostLabel(profile)
|
|
1448
|
+
}))
|
|
1449
|
+
};
|
|
1450
|
+
if (first !== undefined) {
|
|
1451
|
+
opts.initial = first.ref.modelID;
|
|
1452
|
+
}
|
|
1453
|
+
const modelID = await prompt.select(opts);
|
|
1454
|
+
return { providerID, modelID };
|
|
1455
|
+
}
|
|
1456
|
+
async function chooseFrontier(prompt, profiles) {
|
|
1457
|
+
const sorted = sortFrontierByCost(profiles);
|
|
1458
|
+
const quick = sorted.slice(0, QUICK_FRONTIER_LIMIT);
|
|
1098
1459
|
const selected = await prompt.select({
|
|
1099
1460
|
message: "Modelo frontier baseline (cheapest-capable primero)",
|
|
1100
1461
|
choices: [
|
|
1101
|
-
...
|
|
1102
|
-
value:
|
|
1103
|
-
|
|
1462
|
+
...quick.map((profile) => ({
|
|
1463
|
+
value: frontierRefKey({
|
|
1464
|
+
providerID: profile.ref.providerID,
|
|
1465
|
+
modelID: profile.ref.modelID
|
|
1466
|
+
}),
|
|
1467
|
+
label: `${profile.ref.providerID}/${profile.ref.modelID}`,
|
|
1468
|
+
hint: frontierCostLabel(profile)
|
|
1104
1469
|
})),
|
|
1470
|
+
{
|
|
1471
|
+
value: BROWSE_FRONTIER,
|
|
1472
|
+
label: "Ver todos los modelos por proveedor…"
|
|
1473
|
+
},
|
|
1105
1474
|
{ value: CUSTOM_FRONTIER, label: "Otro (introducir provider/model)" }
|
|
1106
1475
|
],
|
|
1107
|
-
initial:
|
|
1476
|
+
initial: quick[0] ? frontierRefKey({
|
|
1477
|
+
providerID: quick[0].ref.providerID,
|
|
1478
|
+
modelID: quick[0].ref.modelID
|
|
1479
|
+
}) : BROWSE_FRONTIER
|
|
1108
1480
|
});
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
placeholder: "anthropic/claude-sonnet-4-5"
|
|
1112
|
-
}) : selected;
|
|
1113
|
-
const slash = ref.indexOf("/");
|
|
1114
|
-
if (slash <= 0 || slash === ref.length - 1) {
|
|
1115
|
-
throw new Error(`modelo frontier inválido: "${ref}" (usa provider/model)`);
|
|
1481
|
+
if (selected === BROWSE_FRONTIER) {
|
|
1482
|
+
return browseFrontier(prompt, profiles);
|
|
1116
1483
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1484
|
+
if (selected === CUSTOM_FRONTIER) {
|
|
1485
|
+
const ref = await prompt.text({
|
|
1486
|
+
message: "Modelo frontier en formato provider/model",
|
|
1487
|
+
placeholder: "anthropic/claude-sonnet-4-5"
|
|
1488
|
+
});
|
|
1489
|
+
return parseFrontierRef(ref);
|
|
1490
|
+
}
|
|
1491
|
+
return parseFrontierRef(selected);
|
|
1121
1492
|
}
|
|
1122
1493
|
async function chooseRuntimeModel(prompt, detected, meta) {
|
|
1123
1494
|
if (detected.models.length === 0) {
|
|
@@ -1197,7 +1568,14 @@ async function runInit(deps) {
|
|
|
1197
1568
|
}
|
|
1198
1569
|
runtimes.push(choice);
|
|
1199
1570
|
}
|
|
1200
|
-
|
|
1571
|
+
let frontierProfiles;
|
|
1572
|
+
try {
|
|
1573
|
+
const loaded = await deps.loadFrontierProfiles();
|
|
1574
|
+
frontierProfiles = loaded.length > 0 ? loaded : [...CURATED_FRONTIER_PROFILES];
|
|
1575
|
+
} catch {
|
|
1576
|
+
frontierProfiles = [...CURATED_FRONTIER_PROFILES];
|
|
1577
|
+
}
|
|
1578
|
+
const frontier = await chooseFrontier(prompt, frontierProfiles);
|
|
1201
1579
|
const routerMode = await prompt.select({
|
|
1202
1580
|
message: "Modo de routing",
|
|
1203
1581
|
choices: [
|
|
@@ -1290,43 +1668,6 @@ import { readFile } from "node:fs/promises";
|
|
|
1290
1668
|
|
|
1291
1669
|
// src/telemetry/types.ts
|
|
1292
1670
|
import { z as z3 } from "zod";
|
|
1293
|
-
|
|
1294
|
-
// src/capabilities/types.ts
|
|
1295
|
-
import { z as z2 } from "zod";
|
|
1296
|
-
var CapabilityTierSchema = z2.union([
|
|
1297
|
-
z2.literal(0),
|
|
1298
|
-
z2.literal(1),
|
|
1299
|
-
z2.literal(2),
|
|
1300
|
-
z2.literal(3),
|
|
1301
|
-
z2.literal(4),
|
|
1302
|
-
z2.literal(5)
|
|
1303
|
-
]);
|
|
1304
|
-
var ComplexityTierSchema = z2.enum([
|
|
1305
|
-
"trivial",
|
|
1306
|
-
"simple",
|
|
1307
|
-
"moderate",
|
|
1308
|
-
"hard"
|
|
1309
|
-
]);
|
|
1310
|
-
var ModelCapabilityProfileSchema = z2.object({
|
|
1311
|
-
ref: z2.object({
|
|
1312
|
-
providerID: z2.string().min(1),
|
|
1313
|
-
modelID: z2.string().min(1)
|
|
1314
|
-
}),
|
|
1315
|
-
kind: z2.enum(["local", "frontier", "router"]),
|
|
1316
|
-
contextWindow: z2.number().int().positive(),
|
|
1317
|
-
maxOutputTokens: z2.number().int().positive(),
|
|
1318
|
-
supportsToolCalling: z2.boolean(),
|
|
1319
|
-
supportsVision: z2.boolean(),
|
|
1320
|
-
reasoningTier: CapabilityTierSchema,
|
|
1321
|
-
codeQualityTier: CapabilityTierSchema,
|
|
1322
|
-
costPer1M: z2.object({
|
|
1323
|
-
inputUSD: z2.number().min(0),
|
|
1324
|
-
outputUSD: z2.number().min(0)
|
|
1325
|
-
}),
|
|
1326
|
-
availability: z2.enum(["available", "degraded", "unavailable"])
|
|
1327
|
-
});
|
|
1328
|
-
|
|
1329
|
-
// src/telemetry/types.ts
|
|
1330
1671
|
var CostRecordSchema = z3.object({
|
|
1331
1672
|
ts: z3.number().finite(),
|
|
1332
1673
|
sessionID: z3.string().min(1).optional(),
|
|
@@ -1431,6 +1772,7 @@ function createInitDeps() {
|
|
|
1431
1772
|
return {
|
|
1432
1773
|
cwd: process.cwd(),
|
|
1433
1774
|
detect: createDetect(nodeExec),
|
|
1775
|
+
loadFrontierProfiles: createLoadFrontierProfiles(),
|
|
1434
1776
|
prompt: clackPrompter,
|
|
1435
1777
|
writeFile: async (path, contents) => {
|
|
1436
1778
|
await mkdir2(dirname2(path), { recursive: true });
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ModelCapabilityProfile } from "../capabilities/types";
|
|
1
2
|
import { type OpenTeamConfig, type PrivacyMode, type RouterMode } from "../config/schema";
|
|
2
3
|
import type { LocalRuntimeId } from "../local/types";
|
|
3
4
|
import type { CliResult } from "./dispatch";
|
|
@@ -58,11 +59,20 @@ export type OpencodeConfig = {
|
|
|
58
59
|
model: string;
|
|
59
60
|
small_model?: string;
|
|
60
61
|
};
|
|
62
|
+
/** `true` cuando el modelo no tiene coste de entrada ni de salida (gratis). */
|
|
63
|
+
export declare function isFreeFrontier(profile: ModelCapabilityProfile): boolean;
|
|
64
|
+
/** Etiqueta de coste legible: "gratis" o "$in/$out por 1M". Pure. */
|
|
65
|
+
export declare function frontierCostLabel(profile: ModelCapabilityProfile): string;
|
|
61
66
|
/**
|
|
62
|
-
* Modelos frontier ofrecidos por `init`, del más barato-capaz al más caro
|
|
63
|
-
*
|
|
67
|
+
* Modelos frontier ofrecidos por `init`, del más barato-capaz al más caro.
|
|
68
|
+
* Por defecto usa el catálogo curado; `init` le pasa el catálogo real de
|
|
69
|
+
* Models.dev (incluidos los modelos gratuitos). Pure/determinista.
|
|
64
70
|
*/
|
|
65
|
-
export declare function frontierChoices(): FrontierChoice[];
|
|
71
|
+
export declare function frontierChoices(profiles?: readonly ModelCapabilityProfile[]): FrontierChoice[];
|
|
72
|
+
/** Providers presentes en el catálogo, ordenados alfabéticamente. Pure. */
|
|
73
|
+
export declare function frontierProviders(profiles: readonly ModelCapabilityProfile[]): string[];
|
|
74
|
+
/** Perfiles frontier de un provider, del más barato al más caro. Pure. */
|
|
75
|
+
export declare function frontierModelsForProvider(profiles: readonly ModelCapabilityProfile[], providerID: string): ModelCapabilityProfile[];
|
|
66
76
|
/**
|
|
67
77
|
* Construye y valida el OpenTeamConfig a partir de las respuestas del init.
|
|
68
78
|
* Pure: no I/O.
|
|
@@ -113,6 +123,7 @@ export type Prompter = {
|
|
|
113
123
|
export type InitDeps = {
|
|
114
124
|
cwd: string;
|
|
115
125
|
detect: () => Promise<DetectedRuntime[]>;
|
|
126
|
+
loadFrontierProfiles: () => Promise<ModelCapabilityProfile[]>;
|
|
116
127
|
prompt: Prompter;
|
|
117
128
|
writeFile: (path: string, contents: string) => Promise<void>;
|
|
118
129
|
fileExists: (path: string) => Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,9 @@ import type { FrontierChoice } from "./init";
|
|
|
6
6
|
export declare const ORCHESTRATOR_AGENT_PATH = ".opencode/agent/openteam.md";
|
|
7
7
|
/**
|
|
8
8
|
* Construye el Markdown del agente primario `openteam` (estilo Squad): un
|
|
9
|
-
* orquestador que aparece en el Tab-switcher
|
|
10
|
-
* subagentes a demanda
|
|
9
|
+
* orquestador que aparece en el Tab-switcher, elige un universo temático y
|
|
10
|
+
* castea al equipo, y crea los subagentes a demanda (incluidos los roles
|
|
11
|
+
* estándar scribe, ralph y guardian). Pure: no I/O.
|
|
11
12
|
*
|
|
12
13
|
* `frontier` fija el `model` del orquestador (baseline cheapest-capable), un
|
|
13
14
|
* `provider/model` real y resoluble; el plugin de openteam sigue enrutando por
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestratorAgent.d.ts","sourceRoot":"","sources":["../../src/commands/orchestratorAgent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAErE
|
|
1
|
+
{"version":3,"file":"orchestratorAgent.d.ts","sourceRoot":"","sources":["../../src/commands/orchestratorAgent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAErE;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAkGvE"}
|