mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-16 08:25:14 +02:00
feat: wire claude-code agent runner backend
This commit is contained in:
parent
eb90d2f32c
commit
3de32c43a1
16 changed files with 229 additions and 21 deletions
|
|
@ -12,7 +12,6 @@ import {
|
|||
agentToolOutputToText,
|
||||
assertAgentToolSet,
|
||||
type AgentToolDefinition,
|
||||
type AgentToolSet,
|
||||
} from './agent-tool.js';
|
||||
import type { AgentRunnerPort, RunLoopParams, RunLoopResult, RunLoopStopReason } from './agent-runner.service.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { AgentRunnerService } from '../agent/index.js';
|
|||
import { initKtxProject, type KtxLocalProject, loadKtxProject } from '../project/index.js';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { FakeSourceAdapter } from './adapters/fake/fake.adapter.js';
|
||||
import { createLocalBundleIngestRuntime } from './local-bundle-runtime.js';
|
||||
import { createLocalBundleIngestRuntime, resolveAgentRunnerForTest } from './local-bundle-runtime.js';
|
||||
|
||||
type RuntimeWithConnectionDeps = {
|
||||
deps: {
|
||||
|
|
@ -55,7 +55,7 @@ describe('createLocalBundleIngestRuntime', () => {
|
|||
}),
|
||||
).toThrow(
|
||||
[
|
||||
'ktx ingest requires llm.provider.backend: anthropic, vertex, or gateway, or an injected agentRunner.',
|
||||
'ktx ingest requires llm.provider.backend: anthropic, vertex, or gateway; llm.agentRunner.backend: claude-code; or an injected agentRunner.',
|
||||
`Configure an Anthropic provider, then rerun ingest:`,
|
||||
` ktx setup --project-dir ${project.projectDir} --anthropic-api-key-env ANTHROPIC_API_KEY --anthropic-model claude-sonnet-4-6 --no-input`,
|
||||
].join('\n'),
|
||||
|
|
@ -84,6 +84,18 @@ describe('createLocalBundleIngestRuntime', () => {
|
|||
await mkdir(runtime.storage.resolveUploadDir('job-1'), { recursive: true });
|
||||
});
|
||||
|
||||
it('constructs a Claude Agent SDK runner when llm.agentRunner.backend is claude-code', () => {
|
||||
project.config.llm = {
|
||||
provider: { backend: 'none' },
|
||||
models: { default: 'claude-sonnet-4-6' },
|
||||
agentRunner: { backend: 'claude-code' },
|
||||
};
|
||||
|
||||
const resolved = resolveAgentRunnerForTest({ project, adapters: [] });
|
||||
|
||||
expect(resolved.agentRunner.constructor.name).toBe('ClaudeAgentSdkRunnerService');
|
||||
});
|
||||
|
||||
it('exposes canonical warehouse connection types to local ingest SL tools', async () => {
|
||||
project.config.connections.warehouse = {
|
||||
driver: 'postgres',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url';
|
|||
import type { KtxLlmProvider } from '@ktx/llm';
|
||||
import YAML from 'yaml';
|
||||
import type { AgentRunnerPort, AgentToolSet } from '../agent/index.js';
|
||||
import { AgentRunnerService as DefaultAgentRunnerService } from '../agent/index.js';
|
||||
import { AgentRunnerService as DefaultAgentRunnerService, ClaudeAgentSdkRunnerService } from '../agent/index.js';
|
||||
import { localConnectionInfoFromConfig, type KtxSqlQueryExecutorPort } from '../connections/index.js';
|
||||
import type { KtxEmbeddingPort, KtxLogger } from '../core/index.js';
|
||||
import { noopLogger, SessionWorktreeService } from '../core/index.js';
|
||||
|
|
@ -570,7 +570,7 @@ function nextLocalJobId(): string {
|
|||
|
||||
function localIngestLlmProviderGuardMessage(projectDir: string): string {
|
||||
return [
|
||||
'ktx ingest requires llm.provider.backend: anthropic, vertex, or gateway, or an injected agentRunner.',
|
||||
'ktx ingest requires llm.provider.backend: anthropic, vertex, or gateway; llm.agentRunner.backend: claude-code; or an injected agentRunner.',
|
||||
'Configure an Anthropic provider, then rerun ingest:',
|
||||
` ktx setup --project-dir ${projectDir} --anthropic-api-key-env ANTHROPIC_API_KEY --anthropic-model claude-sonnet-4-6 --no-input`,
|
||||
].join('\n');
|
||||
|
|
@ -587,6 +587,17 @@ function resolveAgentRunner(options: CreateLocalBundleIngestRuntimeOptions): {
|
|||
return { agentRunner: options.agentRunner, ...(llmProvider ? { llmProvider } : {}) };
|
||||
}
|
||||
|
||||
if (options.project.config.llm.agentRunner.backend === 'claude-code') {
|
||||
return {
|
||||
agentRunner: new ClaudeAgentSdkRunnerService({
|
||||
projectDir: options.project.projectDir,
|
||||
modelSlots: options.project.config.llm.models,
|
||||
logger: options.logger ?? noopLogger,
|
||||
}),
|
||||
...(llmProvider ? { llmProvider } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
if (!llmProvider) {
|
||||
throw new Error(localIngestLlmProviderGuardMessage(options.project.projectDir));
|
||||
}
|
||||
|
|
@ -603,6 +614,8 @@ function resolveAgentRunner(options: CreateLocalBundleIngestRuntimeOptions): {
|
|||
};
|
||||
}
|
||||
|
||||
export const resolveAgentRunnerForTest = resolveAgentRunner;
|
||||
|
||||
export function createLocalBundleIngestRuntime(
|
||||
options: CreateLocalBundleIngestRuntimeOptions,
|
||||
): LocalBundleIngestRuntime {
|
||||
|
|
|
|||
|
|
@ -143,6 +143,17 @@ describe('createLocalProjectMemoryCapture', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('constructs local memory capture with Claude Agent SDK runner config', async () => {
|
||||
const project = await initKtxProject({ projectDir: tempDir });
|
||||
project.config.llm = {
|
||||
provider: { backend: 'none' },
|
||||
models: { default: 'claude-sonnet-4-6' },
|
||||
agentRunner: { backend: 'claude-code' },
|
||||
};
|
||||
|
||||
expect(() => createLocalProjectMemoryCapture(project)).not.toThrow();
|
||||
});
|
||||
|
||||
it('captures a semantic-layer source for a named local connection id', async () => {
|
||||
const project = await initKtxProject({ projectDir: tempDir });
|
||||
project.config.connections.warehouse = { driver: 'postgres' };
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { join } from 'node:path';
|
|||
import { fileURLToPath } from 'node:url';
|
||||
import type { KtxLlmProvider } from '@ktx/llm';
|
||||
import YAML from 'yaml';
|
||||
import { AgentRunnerService, type AgentRunnerPort } from '../agent/index.js';
|
||||
import { AgentRunnerService, ClaudeAgentSdkRunnerService, type AgentRunnerPort } from '../agent/index.js';
|
||||
import { localConnectionInfoFromConfig } from '../connections/index.js';
|
||||
import type { KtxEmbeddingPort, KtxFileStorePort, KtxFileWriteResult } from '../core/index.js';
|
||||
import { type KtxLogger, noopLogger, SessionWorktreeService } from '../core/index.js';
|
||||
|
|
@ -104,10 +104,16 @@ export function createLocalProjectMemoryCapture(
|
|||
});
|
||||
const agentRunner =
|
||||
options.agentRunner ??
|
||||
new AgentRunnerService({
|
||||
llmProvider: requireLlmProvider(llmProvider),
|
||||
logger,
|
||||
});
|
||||
(project.config.llm.agentRunner.backend === 'claude-code'
|
||||
? new ClaudeAgentSdkRunnerService({
|
||||
projectDir: project.projectDir,
|
||||
modelSlots: project.config.llm.models,
|
||||
logger,
|
||||
})
|
||||
: new AgentRunnerService({
|
||||
llmProvider: requireLlmProvider(llmProvider),
|
||||
logger,
|
||||
}));
|
||||
const memoryAgent = new MemoryAgentService({
|
||||
settings: {
|
||||
knowledge: { userScopedKnowledgeEnabled: false },
|
||||
|
|
@ -145,7 +151,9 @@ export function createLocalProjectMemoryCapture(
|
|||
|
||||
function requireLlmProvider(provider: KtxLlmProvider | null | undefined): KtxLlmProvider {
|
||||
if (!provider) {
|
||||
throw new Error('createLocalProjectMemoryCapture requires llm.provider.backend or an injected agentRunner');
|
||||
throw new Error(
|
||||
'createLocalProjectMemoryCapture requires llm.provider.backend, llm.agentRunner.backend: claude-code, or an injected agentRunner',
|
||||
);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue