feat(cli): port Fase 4 CLI — parser arg, mode dispatch, single-process composition root + REPL loop, bootstrap seed
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Single-process composition root — wires every concrete implementation once.
|
||||
* Mirrors the `run_single_process` composition in the Rust gateway/TUI.
|
||||
*
|
||||
* Assembles: Store → Settings/AppConfig repos → LLM provider → ToolCtx +
|
||||
* executor → AgentTurnServiceImpl.
|
||||
*/
|
||||
import {
|
||||
newStore,
|
||||
ensureStoreDirs,
|
||||
type AgentTurnParams,
|
||||
type TurnEvent,
|
||||
type TurnEventSink,
|
||||
type ChatMessage,
|
||||
type Store,
|
||||
userMessage,
|
||||
resolveEffectiveModel,
|
||||
} from "@zesdex/domain";
|
||||
import {
|
||||
JsonSettingsRepository,
|
||||
JsonAppConfigRepository,
|
||||
LlmClient,
|
||||
resolveApiKey,
|
||||
InfrastructureToolExecutor,
|
||||
allTools,
|
||||
toolDefs,
|
||||
} from "@zesdex/infrastructure";
|
||||
import type { ToolCtx } from "@zesdex/infrastructure";
|
||||
import { AgentTurnServiceImpl } from "@zesdex/application";
|
||||
|
||||
/** Wired runtime for single-process mode. */
|
||||
export interface WiredRuntime {
|
||||
store: Store;
|
||||
executor: InfrastructureToolExecutor;
|
||||
turnService: AgentTurnServiceImpl;
|
||||
apiKey: string;
|
||||
model: string;
|
||||
apiBase?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire all layers together once.
|
||||
* Returns the assembled runtime that both the REPL loop and future
|
||||
* interface servers share.
|
||||
*/
|
||||
export async function runSingleProcess(): Promise<WiredRuntime> {
|
||||
const store = newStore();
|
||||
await ensureStoreDirs(store);
|
||||
|
||||
// Load settings + app config from the store directory (repos are async).
|
||||
const settingsRepo = new JsonSettingsRepository();
|
||||
const appConfigRepo = new JsonAppConfigRepository();
|
||||
const settings = await settingsRepo.load(store.base_dir);
|
||||
const appConfig = await appConfigRepo.load(store.base_dir);
|
||||
|
||||
// Resolve the effective provider / model / base URL / API key.
|
||||
const provider = settings.provider;
|
||||
const model = resolveEffectiveModel(settings, appConfig);
|
||||
const baseUrl = appConfig.providers[provider]?.api_base ?? undefined;
|
||||
const apiKey = resolveApiKey(settings, appConfig);
|
||||
|
||||
// Build the LLM provider service (implements the ProviderService port).
|
||||
const llmClient = new LlmClient(apiKey, model, baseUrl);
|
||||
|
||||
// Build the tool context + executor.
|
||||
const executor = new InfrastructureToolExecutor(buildToolCtx(store));
|
||||
|
||||
// Assemble the turn service (provider + executor + tool definitions).
|
||||
const turnService = new AgentTurnServiceImpl(
|
||||
llmClient,
|
||||
executor,
|
||||
toolDefs(allTools()) as never,
|
||||
);
|
||||
|
||||
return { store, executor, turnService, apiKey, model, apiBase: baseUrl };
|
||||
}
|
||||
|
||||
/** Rooted, long-lived event sink that collects events into an array. */
|
||||
export class ArrayTurnEventSink implements TurnEventSink {
|
||||
constructor(public events: TurnEvent[] = []) {}
|
||||
push(event: TurnEvent): void {
|
||||
this.events.push(event);
|
||||
}
|
||||
drain(): TurnEvent[] {
|
||||
const out = this.events;
|
||||
this.events = [];
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
/** Build a fresh set of turn params for a single user query. */
|
||||
export function buildTurnParams(
|
||||
runtime: WiredRuntime,
|
||||
userText: string,
|
||||
events: TurnEvent[],
|
||||
abort: AbortController,
|
||||
): AgentTurnParams {
|
||||
const sink = new ArrayTurnEventSink(events);
|
||||
const messages: ChatMessage[] = [userMessage(userText)];
|
||||
return {
|
||||
messages,
|
||||
session_dir: runtime.store.base_dir,
|
||||
workspace_roots: [process.cwd()],
|
||||
turn_events: sink,
|
||||
in_flight: { value: false },
|
||||
abort,
|
||||
api_key: runtime.apiKey,
|
||||
model: runtime.model,
|
||||
api_base: runtime.apiBase,
|
||||
};
|
||||
}
|
||||
|
||||
/** Build a ToolCtx with the standard fields. */
|
||||
function buildToolCtx(store: Store): ToolCtx {
|
||||
return {
|
||||
sessionDir: store.base_dir,
|
||||
workspaces: [process.cwd()],
|
||||
turnEvents: new ArrayTurnEventSink(),
|
||||
workflowFindings: [],
|
||||
} as unknown as ToolCtx;
|
||||
}
|
||||
Reference in New Issue
Block a user