three turns in a row could not look at a calendar while holding the calendar skill, and each failure had a different cause. FIRST: opencode's built-in `build` agent opens with "You are an AI coding agent. Help the user accomplish software engineering tasks." asked about a calendar it reasoned, in its own words, "this isn't a coding task, and I don't have access to any calendar" and never called the skill tool. the index was in its context the whole time. the plumbing was right and the identity was wrong, which is the harder of the two to see. so officer defines its own primary agent — mode primary, `default_agent`, and named explicitly on session create because a default is a preference and this is a requirement. only NEW sessions: a resumed one keeps the agent it was made with. SECOND: setting a custom `prompt` traded one problem for the other. with the built-in agent the index was there and the framing was wrong; with ours the framing was right and the index was gone, so the turn went looking for .ics files in the home directory. `prompt` replaces the assembled system text rather than adding to it. the index is now compiled INTO the prompt by `skillsBlock()` — the same function a claude session uses — so both halves arrive together. ours also carries the PATH to each SKILL.md, which opencode's own block does not: a path can be opened with the file tools every harness already has. WHAT IS NOT FIXED, AND IS NOT THIS FILE'S FAULT. a third attempt still failed, and a diagnostic turn reported system instructions beginning "Tool infrastructure You can call" — not ours — and named a skill (`frontend-design`) that exists nowhere in this install. the only provider this machine can reach is opencode's own hosted gateway on free models; there is no auth.json here. so either the gateway supplies its own system prompt, or a free model is confabulating about its instructions. those are different problems and neither can be told apart without a model whose credential we own. verified: the agent is registered and its prompt is 4,717 characters containing "Calendar and contacts" and the SKILL.md paths; the serve's credential works (a tool process fetched the owner's collections); 10 skills discovered. NOT verified: that any of it reaches the model on this box. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
34 lines
1.8 KiB
TypeScript
34 lines
1.8 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import { serveConfigContent, affordancesPath } from './serve-env';
|
|
|
|
// The config shape is a contract with the OpenCode binary, and the cost of a wrong key name is SILENCE:
|
|
// no error, no warning, just an agent that never sees a skill. So the keys are asserted literally.
|
|
|
|
describe('serveConfigContent', () => {
|
|
test('names skills.paths and instructions exactly', () => {
|
|
const parsed = JSON.parse(serveConfigContent(['/a/skills', '/b/skills'], ['/tmp/aff.md'], 'PROMPT'));
|
|
expect(parsed.skills).toEqual({ paths: ['/a/skills', '/b/skills'] });
|
|
expect(parsed.instructions).toEqual(['/tmp/aff.md']);
|
|
// The agent is what a session is created with; a config without it silently falls back to
|
|
// OpenCode's coding-agent framing, which is the bug this whole file exists to stop.
|
|
expect(parsed.default_agent).toBe('officer');
|
|
expect(parsed.agent.officer.prompt).toBe('PROMPT');
|
|
expect(parsed.agent.officer.mode).toBe('primary');
|
|
});
|
|
|
|
// An empty array is not the same as an absent key: `skills: {paths: []}` is a claim that there are none,
|
|
// and merged over a config that sets some it would erase them.
|
|
test('omits a key rather than sending it empty', () => {
|
|
expect(JSON.parse(serveConfigContent([], [], 'P')).skills).toBeUndefined();
|
|
expect(JSON.parse(serveConfigContent(['/a'], [], 'P')).skills).toEqual({ paths: ['/a'] });
|
|
});
|
|
|
|
test('is valid JSON for an env var — no newlines to be mangled by a shell', () => {
|
|
expect(serveConfigContent(['/a/skills'], ['/tmp/aff.md'], 'P')).not.toContain('\n');
|
|
});
|
|
|
|
test('the affordances file sits beside the serve state, not in a home', () => {
|
|
expect(affordancesPath('/data/opencode_server')).toBe('/data/opencode_server/officer-affordances.md');
|
|
});
|
|
});
|