refactor(agent-runner): decouple provider interface from Claude specifics

Reshape AgentProvider so provider-specific assumptions stop leaking into
the generic layer. No change to what reaches sdkQuery() — same values,
different plumbing.

- QueryInput: opaque `continuation` replaces `sessionId` + `resumeAt`;
  `systemContext.instructions` replaces ambiguous `systemPrompt`;
  `mcpServers`, `env`, `additionalDirectories` move to `ProviderOptions`
  at construction time.
- AgentProvider gains `isSessionInvalid(err)` and
  `supportsNativeSlashCommands` so the poll-loop stops regex-matching
  Claude error strings and gates passthrough slash commands per provider.
- ClaudeProvider owns `CLAUDE_CODE_AUTO_COMPACT_WINDOW` and the
  stale-session regex internally.
- ProviderEvent.activity kept and documented as the liveness signal
  (fires on every SDK message so the idle timer stays honest during
  long tool runs); init carries `continuation` instead of `sessionId`.
- poll-loop drops mcpServers/env/systemPrompt from its config; admin
  user id now passed explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-13 10:25:29 +03:00
parent e07158e194
commit b63dd186df
8 changed files with 156 additions and 114 deletions

View File

@@ -104,12 +104,10 @@ describe('routing', () => {
describe('mock provider', () => {
it('should produce init + result events', async () => {
const provider = new MockProvider((prompt) => `Echo: ${prompt}`);
const provider = new MockProvider({}, (prompt) => `Echo: ${prompt}`);
const query = provider.query({
prompt: 'Hello',
cwd: '/tmp',
mcpServers: {},
env: {},
});
const events: Array<{ type: string }> = [];
@@ -127,12 +125,10 @@ describe('mock provider', () => {
});
it('should handle push() during active query', async () => {
const provider = new MockProvider((prompt) => `Re: ${prompt}`);
const provider = new MockProvider({}, (prompt) => `Re: ${prompt}`);
const query = provider.query({
prompt: 'First',
cwd: '/tmp',
mcpServers: {},
env: {},
});
const events: Array<{ type: string; text?: string }> = [];
@@ -164,12 +160,10 @@ describe('end-to-end with mock provider', () => {
const prompt = formatMessages(messages);
// Create mock provider and run query
const provider = new MockProvider(() => 'The answer is 4');
const provider = new MockProvider({}, () => 'The answer is 4');
const query = provider.query({
prompt,
cwd: '/tmp',
mcpServers: {},
env: {},
});
// Process events — simulate what poll-loop does