feat: deepseek agent adapter for pipeline — Ollama-based model runtime

runDeepSeekAgent() implements the runAgent callback for execution-pipeline.ts.
Configurable endpoint/model/temperature. Uses fetch (Node 18+), no new deps.
Exports from index.ts.
This commit is contained in:
artale 2026-07-05 00:58:31 +02:00
parent e59700325a
commit 6a0e4cd9d9
2 changed files with 94 additions and 0 deletions

View File

@ -0,0 +1,92 @@
/**
* Agent adapter for DeepSeek models via Ollama.
* Uses fetch (Node 18+ built-in, no new deps).
* Designed as the runAgent callback for execution-pipeline.ts.
*
* Configurable endpoint defaults to localhost:11434.
* Point at 77.42.112.29:11434 when Ollama is reachable externally.
*/
export interface DeepSeekAgentConfig {
/** Ollama endpoint, e.g. "http://localhost:11434" */
endpoint?: string;
/** Model name, e.g. "deepseek-coder-v2" or "deepseek-r1:32b" */
model?: string;
/** Sampling temperature. Default 0.2 for coding tasks. */
temperature?: number;
/** System prompt injected before the user prompt. */
systemPrompt?: string;
/** Max tokens to generate. Default 4096. */
maxTokens?: number;
}
const DEFAULTS = {
endpoint: "http://localhost:11434",
model: "deepseek-coder-v2",
temperature: 0.2,
systemPrompt: "You are a coding agent. Read the repo map and user prompt, then produce the required output.",
maxTokens: 4096,
};
export interface ChatMessage {
role: "system" | "user" | "assistant";
content: string;
}
export function buildDeepSeekMessages(
systemPrompt: string,
prompt: string
): ChatMessage[] {
return [
{ role: "system", content: systemPrompt },
{ role: "user", content: prompt },
];
}
/**
* Run a DeepSeek model via Ollama's /api/chat endpoint.
* Returns the assistant's response text.
* Throws on HTTP error or empty response.
*/
export async function runDeepSeekAgent(
config: DeepSeekAgentConfig,
_cwd: string,
prompt: string
): Promise<string> {
const endpoint = config.endpoint ?? DEFAULTS.endpoint;
const model = config.model ?? DEFAULTS.model;
const temperature = config.temperature ?? DEFAULTS.temperature;
const systemPrompt = config.systemPrompt ?? DEFAULTS.systemPrompt;
const maxTokens = config.maxTokens ?? DEFAULTS.maxTokens;
const messages = buildDeepSeekMessages(systemPrompt, prompt);
const response = await fetch(`${endpoint}/api/chat`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model,
messages,
options: {
temperature,
num_predict: maxTokens,
},
stream: false,
}),
signal: AbortSignal.timeout(120_000), // 2-minute timeout
});
if (!response.ok) {
const body = await response.text().catch(() => "");
throw new Error(`deepseek-agent: HTTP ${response.status}${body.slice(0, 200)}`);
}
const data: any = await response.json();
const text = data?.message?.content ?? "";
if (!text) {
throw new Error("deepseek-agent: empty response from model");
}
return text;
}

View File

@ -55,6 +55,8 @@ export { buildRepoMap, repoTreeString, minifiedTree, gitLsTree } from "./repo-ma
export type { RepoMap, RepoNode } from "./repo-mapper.js"; export type { RepoMap, RepoNode } from "./repo-mapper.js";
export { runPipeline } from "./execution-pipeline.js"; export { runPipeline } from "./execution-pipeline.js";
export type { PipelineSpec, PipelineResult } from "./execution-pipeline.js"; export type { PipelineSpec, PipelineResult } from "./execution-pipeline.js";
export { runDeepSeekAgent, buildDeepSeekMessages } from "./deepseek-agent.js";
export type { DeepSeekAgentConfig, ChatMessage } from "./deepseek-agent.js";
export { formatCapabilityReport, loadFactoryCapabilities, parseFactoryCapabilities, probeFactoryCapabilities } from "./factory-capabilities.js"; export { formatCapabilityReport, loadFactoryCapabilities, parseFactoryCapabilities, probeFactoryCapabilities } from "./factory-capabilities.js";
export type { CapabilityProbeResult, CapabilityReport, FactoryCapabilityService } from "./factory-capabilities.js"; export type { CapabilityProbeResult, CapabilityReport, FactoryCapabilityService } from "./factory-capabilities.js";