v2.4.1-sidecar-routing: route per-agent flags to llama-sidecar + tool gap fix

Batch 3c: when an agent has llama_extra_args in AGENTS.md, provider.ts
routes inference through LLAMA_SIDECAR_URL instead of LLAMA_SWAP_URL.
X-Agent-Flags header built from the agent's flags. Boot-time guard
refuses to start if any agent has llama_extra_args but LLAMA_SIDECAR_URL
is unset. PrefixFingerprint gains a route field (swap/sidecar) for
per-turn visibility. 9 provider tests.

AGENTS.md tool gap: all agents (except Prompt Builder) were missing 8
tools that were added after the original tool lists were written:
request_read_access, view_truncated_output, ask_user_input, git_status,
get_blast_radius, get_hot_files, get_middleware, get_routes. The missing
request_read_access caused silent "permission denied" when reading files
outside the project root.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 19:28:08 +00:00
parent 90a6761b07
commit bcfc94fa47
8 changed files with 155 additions and 26 deletions

View File

@@ -0,0 +1,58 @@
import { describe, expect, it } from 'vitest';
import { resolveRoute, upstreamModel } from '../inference/provider.js';
describe('resolveRoute', () => {
it('routes to swap when agent is null', () => {
expect(resolveRoute(null)).toEqual({ route: 'swap', flags: null });
});
it('routes to swap when agent has no llama_extra_args', () => {
expect(resolveRoute({ llama_extra_args: null })).toEqual({ route: 'swap', flags: null });
});
it('routes to swap when agent has empty llama_extra_args', () => {
expect(resolveRoute({ llama_extra_args: [] })).toEqual({ route: 'swap', flags: null });
});
it('routes to sidecar when agent has llama_extra_args', () => {
const result = resolveRoute({ llama_extra_args: ['--top-k', '20'] });
expect(result.route).toBe('sidecar');
expect(result.flags).toEqual(['--top-k', '20']);
});
});
describe('upstreamModel', () => {
const swapConfig = { LLAMA_SWAP_URL: 'http://localhost:8401' };
const fullConfig = {
LLAMA_SWAP_URL: 'http://localhost:8401',
LLAMA_SIDECAR_URL: 'http://localhost:8402',
};
it('returns a model for swap route (no agent)', () => {
const model = upstreamModel(swapConfig, 'test-model');
expect(model).toBeDefined();
expect((model as any).modelId).toBe('test-model');
});
it('returns a model for swap route (agent without extra args)', () => {
const model = upstreamModel(swapConfig, 'test-model', { llama_extra_args: null });
expect(model).toBeDefined();
});
it('returns a model for sidecar route', () => {
const model = upstreamModel(fullConfig, 'test-model', { llama_extra_args: ['--top-k', '20'] });
expect(model).toBeDefined();
expect((model as any).modelId).toBe('test-model');
});
it('throws when sidecar route requested but URL missing', () => {
expect(() =>
upstreamModel(swapConfig, 'test-model', { llama_extra_args: ['--top-k', '20'] }),
).toThrow(/LLAMA_SIDECAR_URL/);
});
it('routes to swap for empty llama_extra_args array', () => {
const model = upstreamModel(swapConfig, 'test-model', { llama_extra_args: [] });
expect(model).toBeDefined();
});
});