fix(grok): make the opencode runtime actually load — proven live on grok-build-0.1

Live verification (opencode 1.17.8 + grok-build-0.1, funded key) showed the Grok
runtime was loading INERT, three ways:

1. The provider override `provider.xai.npm=@ai-sdk/openai` failed model
   resolution (ProviderModelNotFoundError) — opencode can't resolve that package
   from its module path. Worse, ANY custom `provider.xai` block (even just
   options) breaks plugin-tool registration. opencode's BUILT-IN xai provider
   drives grok-build-0.1 with working tool-calls, so emit NO provider block; the
   key + base reach it via XAI_API_KEY / XAI_BASE_URL env (provider.options.apiKey
   alone does NOT authenticate).
2. Plugins referenced by absolute path in the config `plugin:` array never
   registered their hooks/tools. opencode 1.17.8 only registers from the plugin
   AUTO-DISCOVERY dir (~/.config/opencode/plugin/). Bake all plugins there.
3. Plugins must use a NAMED export, not `export default`.

Changes:
- opencode_config: no `provider` block, no `plugin` array; drop the dead
  XaiTarget + timeout machinery; build_opencode_config now takes a model string.
- GrokProvider / orchestrator interactive env: inject XAI_API_KEY + XAI_BASE_URL
  (drop the now-unused OPENAI_*).
- secret-scrub / budget-feed / secretary-tools / intake-tools: named exports;
  baked into /home/agent/.config/opencode/plugin/ (drop the EXTRA_PLUGINS env).
- agent-grok* Dockerfiles: plugin dir + agent ownership; drop the unneeded
  @ai-sdk/openai global install.

Verified live end-to-end: grok-build-0.1 calls read_company_state AND
submit_directive through secretary-tools.js and the backend receives both with
the agent token; a tool.execute.before guard fires; built-in tool-calls work.
Targeted gate green (ruff/mypy/xenon + opencode_config/providers/interactive
tests; node --check the plugins).
This commit is contained in:
Renn F
2026-06-18 21:14:06 +02:00
parent f314723c98
commit e29168653a
13 changed files with 150 additions and 251 deletions
+4 -1
View File
@@ -77,7 +77,10 @@ function bareVerb(tool) {
return tool;
}
export default async () => {
// Named export + loaded from the plugin auto-discovery dir
// (~/.config/opencode/plugin/) — opencode 1.17.8 ignores config `plugin:`-array
// absolute paths for hook/tool registration (verified live).
export const RobocoBudgetFeed = async () => {
return {
"tool.execute.before": async (input) => {
const status = await sdk("GET", "/budget/status", null);
+5 -1
View File
@@ -20,7 +20,11 @@
import { tool } from "@opencode-ai/plugin";
export default async () => ({
// Named export + loaded from the plugin auto-discovery dir
// (~/.config/opencode/plugin/) — opencode 1.17.8 only registers Hooks.tool from
// directory auto-discovery, not a config `plugin:`-array absolute path
// (verified live).
export const RobocoIntakeTools = async () => ({
tool: {
propose_draft: tool({
description:
+5 -1
View File
@@ -164,7 +164,11 @@ function denyBash(command) {
return null;
}
export default async () => {
// Named export + loaded from opencode's plugin auto-discovery dir
// (~/.config/opencode/plugin/). opencode 1.17.8 does NOT register a plugin's
// hooks/tools when it's listed by absolute path in the config `plugin:` array —
// only directory auto-discovery works (verified live against grok-build-0.1).
export const RobocoSecretScrub = async () => {
return {
"tool.execute.before": async (input, output) => {
const tool = input?.tool;
+6 -1
View File
@@ -66,7 +66,12 @@ async function callBackend(method, path, body) {
const asText = (data) => JSON.stringify(data);
export default async () => ({
// Named export + loaded from the plugin auto-discovery dir
// (~/.config/opencode/plugin/) — opencode 1.17.8 does NOT register tools from a
// config `plugin:`-array absolute path; only directory auto-discovery + a named
// export registers Hooks.tool (verified live: the model called the tool and the
// backend received the request).
export const RobocoSecretaryTools = async () => ({
tool: {
read_company_state: tool({
description: