opencode-usage-coach 0.9.1 → 0.10.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/README.md +12 -0
- package/dist/index.js +81 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,18 @@ For local dev without npm: `bun install && bun run build`, then point both confi
|
|
|
49
49
|
|
|
50
50
|
Four config surfaces; only the first two (install config + codexbar) are required to run. The **harness config** (`harness.config.json`) maps roles to models so per-model quota is tracked — set `generator` (required) and optionally `grader`, `lighterModel`, and `provider`. Thresholds and tuning live in env vars (`UC_STOP_5H`, `UC_THROTTLE_5H`, …).
|
|
51
51
|
|
|
52
|
+
### Changing models at runtime
|
|
53
|
+
|
|
54
|
+
Type `/coach-config` in the TUI to view or update harness models interactively. The AI calls the `coach_config` tool, which reads/writes `harness.config.json` with merge semantics — no manual JSON editing required:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
/coach-config # view current config
|
|
58
|
+
"change generator to anthropic/claude-sonnet-4-20250514"
|
|
59
|
+
"set grader and lighterModel to opencode/mimo-v2.5-free"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Changes take effect immediately for new `generate` / `grade` calls.
|
|
63
|
+
|
|
52
64
|
See **[docs/configuration.md](docs/configuration.md)** for the full reference (env var table, harness config fields, agent-mode scoping, local dev setup).
|
|
53
65
|
|
|
54
66
|
## Harness Loop
|
package/dist/index.js
CHANGED
|
@@ -909,6 +909,25 @@ function readHarnessCfg(dir) {
|
|
|
909
909
|
...tryRead(join2(dir, "harness.config.json"))
|
|
910
910
|
};
|
|
911
911
|
}
|
|
912
|
+
function writeHarnessCfg(updates) {
|
|
913
|
+
const configDir = join2(homedir(), ".config", "opencode-usage-coach");
|
|
914
|
+
const configPath = join2(configDir, "harness.config.json");
|
|
915
|
+
try {
|
|
916
|
+
mkdirSync2(configDir, { recursive: true });
|
|
917
|
+
const existing = (() => {
|
|
918
|
+
try {
|
|
919
|
+
return JSON.parse(readFileSync2(configPath, "utf8"));
|
|
920
|
+
} catch {
|
|
921
|
+
return {};
|
|
922
|
+
}
|
|
923
|
+
})();
|
|
924
|
+
const merged = { ...existing, ...updates };
|
|
925
|
+
writeFileSync2(configPath, JSON.stringify(merged, null, 2) + "\n");
|
|
926
|
+
return configPath;
|
|
927
|
+
} catch (e) {
|
|
928
|
+
throw new Error(`Failed to write harness config: ${String(e)}`, { cause: e });
|
|
929
|
+
}
|
|
930
|
+
}
|
|
912
931
|
async function runModel(client, model, prompt, directory, track, maxSteps = DEFAULT_MAX_STEPS) {
|
|
913
932
|
const t0 = Date.now();
|
|
914
933
|
const subStart = Date.now();
|
|
@@ -1245,6 +1264,7 @@ function isHarnessAgent(agent) {
|
|
|
1245
1264
|
}
|
|
1246
1265
|
var LOADING = { decision: "GO", advice: "quota loading\u2026", weekly: -1, monthly: -1, fiveHour: -1 };
|
|
1247
1266
|
async function UsageCoachPlugin(input) {
|
|
1267
|
+
pipeLog(`UsageCoachPlugin CALLED | dir=${input.directory} | worktree=${input.worktree}`);
|
|
1248
1268
|
try {
|
|
1249
1269
|
setStateDir(input.directory);
|
|
1250
1270
|
initDomain(STATE_DIR);
|
|
@@ -2139,10 +2159,67 @@ If the task is already well-specified with no significant ambiguities, return {"
|
|
|
2139
2159
|
const qNum = state.currentIndex + 1;
|
|
2140
2160
|
return formatQuestionOutput(qNum, total, q);
|
|
2141
2161
|
}
|
|
2162
|
+
}),
|
|
2163
|
+
coach_config: tool({
|
|
2164
|
+
description: 'View or update harness model configuration (generator, grader, lighterModel, provider). Call with no args to view current config. Pass any combination of generator/grader/lighterModel/provider to update. Example: coach_config({ generator: "anthropic/claude-sonnet-4-20250514", grader: "opencode/mimo-v2.5-free" })',
|
|
2165
|
+
args: {
|
|
2166
|
+
generator: tool.schema.string().optional(),
|
|
2167
|
+
grader: tool.schema.string().optional(),
|
|
2168
|
+
lighterModel: tool.schema.string().optional(),
|
|
2169
|
+
provider: tool.schema.string().optional()
|
|
2170
|
+
},
|
|
2171
|
+
async execute(args, ctx) {
|
|
2172
|
+
const dir = ctx?.directory ?? input.directory;
|
|
2173
|
+
const current2 = readHarnessCfg(dir);
|
|
2174
|
+
const hasUpdates = args.generator !== void 0 || args.grader !== void 0 || args.lighterModel !== void 0 || args.provider !== void 0;
|
|
2175
|
+
if (!hasUpdates) {
|
|
2176
|
+
const envOverrides = [];
|
|
2177
|
+
if (process.env.UC_PROVIDER) envOverrides.push(`UC_PROVIDER=${process.env.UC_PROVIDER}`);
|
|
2178
|
+
if (process.env.UC_LIGHTER_MODEL) envOverrides.push(`UC_LIGHTER_MODEL=${process.env.UC_LIGHTER_MODEL}`);
|
|
2179
|
+
return [
|
|
2180
|
+
`Harness Configuration`,
|
|
2181
|
+
`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
2182
|
+
` generator: ${current2.generator ?? "(not set \u2014 harness won't work!)"}`,
|
|
2183
|
+
` grader: ${current2.grader ?? "(defaults to generator)"}`,
|
|
2184
|
+
` lighterModel: ${current2.lighterModel ?? "(not set \u2014 no THROTTLE fallback)"}`,
|
|
2185
|
+
` provider: ${current2.provider ?? "(auto-detected from model)"}`,
|
|
2186
|
+
`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
2187
|
+
envOverrides.length > 0 ? `
|
|
2188
|
+
Environment overrides (take precedence):
|
|
2189
|
+
${envOverrides.join("\n ")}` : "",
|
|
2190
|
+
`
|
|
2191
|
+
Config file: ~/.config/opencode-usage-coach/harness.config.json`,
|
|
2192
|
+
`
|
|
2193
|
+
To update, call: coach_config({ generator: "provider/model-id", ... })`
|
|
2194
|
+
].filter(Boolean).join("\n");
|
|
2195
|
+
}
|
|
2196
|
+
const updates = {};
|
|
2197
|
+
if (args.generator !== void 0) updates.generator = args.generator.trim();
|
|
2198
|
+
if (args.grader !== void 0) updates.grader = args.grader.trim();
|
|
2199
|
+
if (args.lighterModel !== void 0) updates.lighterModel = args.lighterModel.trim();
|
|
2200
|
+
if (args.provider !== void 0) updates.provider = args.provider.trim();
|
|
2201
|
+
const writtenPath = writeHarnessCfg(updates);
|
|
2202
|
+
const updated = readHarnessCfg(dir);
|
|
2203
|
+
return [
|
|
2204
|
+
`\u2705 Harness config updated successfully!`,
|
|
2205
|
+
`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
2206
|
+
` generator: ${updated.generator ?? "(not set)"}`,
|
|
2207
|
+
` grader: ${updated.grader ?? "(defaults to generator)"}`,
|
|
2208
|
+
` lighterModel: ${updated.lighterModel ?? "(not set)"}`,
|
|
2209
|
+
` provider: ${updated.provider ?? "(auto-detected)"}`,
|
|
2210
|
+
`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
2211
|
+
`
|
|
2212
|
+
Saved to: ${writtenPath}`,
|
|
2213
|
+
`
|
|
2214
|
+
Note: Changes take effect immediately for new generate/grade calls.`,
|
|
2215
|
+
` A running harness will pick up the new config on the next tool call.`
|
|
2216
|
+
].join("\n");
|
|
2217
|
+
}
|
|
2142
2218
|
})
|
|
2143
2219
|
}
|
|
2144
2220
|
};
|
|
2145
2221
|
} catch (e) {
|
|
2222
|
+
pipeLog(`PLUGIN INIT FAILED (no-op): ${String(e)}`);
|
|
2146
2223
|
log(`PLUGIN INIT FAILED (no-op): ${String(e)}`);
|
|
2147
2224
|
return NOOP_HOOKS;
|
|
2148
2225
|
}
|
|
@@ -2168,8 +2245,11 @@ export {
|
|
|
2168
2245
|
providerAdvice,
|
|
2169
2246
|
providerToCodexbar,
|
|
2170
2247
|
readHarness,
|
|
2248
|
+
readHarnessCfg,
|
|
2171
2249
|
readRules,
|
|
2250
|
+
UsageCoachPlugin as server,
|
|
2172
2251
|
setStateDir,
|
|
2173
2252
|
updateSubSession,
|
|
2174
|
-
writeHarness
|
|
2253
|
+
writeHarness,
|
|
2254
|
+
writeHarnessCfg
|
|
2175
2255
|
};
|
package/package.json
CHANGED