opencode-usage-coach 0.3.0 → 0.3.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/agents/usage-coach-harness.md +6 -1
- package/dist/index.js +35 -10
- package/package.json +1 -1
|
@@ -36,7 +36,12 @@ The user's message is the task source. If it has multiple distinct parts, decomp
|
|
|
36
36
|
|
|
37
37
|
**Multi-model, 1 terminal:** the work runs via the plugin tools `generate` and `grade`, which use the configured models (generator/grader from harness.config.json) on the same server — so you get e.g. a paid generator + a free grader without a second terminal. Do NOT use the `task` tool for harness work; use `generate`/`grade`.
|
|
38
38
|
|
|
39
|
-
**
|
|
39
|
+
**Quota-aware loop strategy (the tools handle this):** the quota coaching injected into your system prompt drives loop strategy. You do NOT pick the model — `generate`/`generate_batch` auto-switch to a lighter model on THROTTLE (if `lighterModel` is configured) and refuse on STOP. You pick the **task size and parallelism**:
|
|
40
|
+
- **GO + headroom** → big tasks OK, use `generate_batch` for independent tasks (full parallel).
|
|
41
|
+
- **THROTTLE** → small tasks only, sequential or limited parallelism. Tools cap concurrency at 2 and use a lighter model automatically.
|
|
42
|
+
- **STOP** → finish the in-progress task, then halt. `generate_batch` returns an error on STOP — call `task_update(current, "halted_quota")` and stop.
|
|
43
|
+
|
|
44
|
+
DEPENDENT tasks (B needs A) → always sequential `generate` calls, regardless of quota.
|
|
40
45
|
|
|
41
46
|
1. Call `harness_start(name, N)` to register the run on the panel.
|
|
42
47
|
2. For each task i (1..N):
|
package/dist/index.js
CHANGED
|
@@ -375,28 +375,53 @@ async function UsageCoachPlugin(input) {
|
|
|
375
375
|
return "Harness complete.";
|
|
376
376
|
}
|
|
377
377
|
}),
|
|
378
|
-
// Per-role model execution (config-driven, same server, no deadlock).
|
|
378
|
+
// Per-role model execution (config-driven, quota-aware, same server, no deadlock).
|
|
379
|
+
// P1: quota decision drives model selection + concurrency.
|
|
379
380
|
generate: tool({
|
|
380
|
-
description: "Run the GENERATOR model on a prompt.
|
|
381
|
+
description: "Run the GENERATOR model on a prompt. Quota-aware: on THROTTLE, auto-switches to lighterModel if configured. Returns the model's text response.",
|
|
381
382
|
args: { prompt: tool.schema.string() },
|
|
382
383
|
async execute(args, ctx) {
|
|
383
384
|
const cfg = readHarnessCfg(ctx.directory);
|
|
384
385
|
if (!cfg.generator) return 'ERROR: no generator model configured. Set "generator" in harness.config.json (see harness.config.example.json).';
|
|
385
|
-
|
|
386
|
-
|
|
386
|
+
let decision = "GO";
|
|
387
|
+
try {
|
|
388
|
+
decision = current().decision;
|
|
389
|
+
} catch {
|
|
390
|
+
}
|
|
391
|
+
const throttle = decision === "THROTTLE" && cfg.lighterModel;
|
|
392
|
+
const model = throttle ? cfg.lighterModel : cfg.generator;
|
|
393
|
+
const out = await runModel(input.client, model, args.prompt, ctx.directory);
|
|
394
|
+
return out + (throttle ? `
|
|
395
|
+
[usage-coach] quota THROTTLE \u2014 used lighter model ${cfg.lighterModel}` : "");
|
|
387
396
|
}
|
|
388
397
|
}),
|
|
389
398
|
generate_batch: tool({
|
|
390
|
-
description: "Run the GENERATOR model on MULTIPLE tasks
|
|
399
|
+
description: "Run the GENERATOR model on MULTIPLE tasks. Quota-aware: GO = full parallel; THROTTLE = lighter model + concurrency capped at 2; STOP = refused. Use for INDEPENDENT tasks.",
|
|
391
400
|
args: { tasks: tool.schema.array(tool.schema.object({ id: tool.schema.number(), prompt: tool.schema.string() })) },
|
|
392
401
|
async execute(args, ctx) {
|
|
393
402
|
const cfg = readHarnessCfg(ctx.directory);
|
|
394
403
|
if (!cfg.generator) return 'ERROR: no generator model configured. Set "generator" in harness.config.json (see harness.config.example.json).';
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
|
|
404
|
+
let decision = "GO";
|
|
405
|
+
try {
|
|
406
|
+
decision = current().decision;
|
|
407
|
+
} catch {
|
|
408
|
+
}
|
|
409
|
+
if (decision === "STOP") return 'ERROR: quota STOP \u2014 halt the harness loop now. Call task_update(current, "halted_quota") and stop.';
|
|
410
|
+
const throttle = decision === "THROTTLE" && cfg.lighterModel;
|
|
411
|
+
const model = throttle ? cfg.lighterModel : cfg.generator;
|
|
412
|
+
const limit = decision === "THROTTLE" ? 2 : args.tasks.length;
|
|
413
|
+
const results = [];
|
|
414
|
+
for (let i = 0; i < args.tasks.length; i += limit) {
|
|
415
|
+
const batch = args.tasks.slice(i, i + limit);
|
|
416
|
+
const out = await Promise.all(batch.map(async (t) => {
|
|
417
|
+
const r = await runModel(input.client, model, t.prompt, ctx.directory);
|
|
418
|
+
return `[task ${t.id}] ${r}`;
|
|
419
|
+
}));
|
|
420
|
+
results.push(...out);
|
|
421
|
+
}
|
|
422
|
+
const note = throttle ? `
|
|
423
|
+
[usage-coach] quota THROTTLE \u2014 lighter model ${cfg.lighterModel}, concurrency capped at ${limit}` : "";
|
|
424
|
+
return results.join("\n\n") + note;
|
|
400
425
|
}
|
|
401
426
|
}),
|
|
402
427
|
grade: tool({
|
package/package.json
CHANGED