activo 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FINAL_SIMPLIFIED_SPEC.md +456 -0
- package/README.md +62 -0
- package/TODO.md +193 -0
- package/dist/cli/banner.d.ts +3 -0
- package/dist/cli/banner.d.ts.map +1 -0
- package/dist/cli/banner.js +30 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/headless.d.ts +3 -0
- package/dist/cli/headless.d.ts.map +1 -0
- package/dist/cli/headless.js +34 -0
- package/dist/cli/headless.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +42 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/agent.d.ts +23 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +171 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/config.d.ts +24 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +66 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/llm/ollama.d.ts +30 -0
- package/dist/core/llm/ollama.d.ts.map +1 -0
- package/dist/core/llm/ollama.js +173 -0
- package/dist/core/llm/ollama.js.map +1 -0
- package/dist/core/mcp/client.d.ts +22 -0
- package/dist/core/mcp/client.d.ts.map +1 -0
- package/dist/core/mcp/client.js +116 -0
- package/dist/core/mcp/client.js.map +1 -0
- package/dist/core/tools/builtIn.d.ts +9 -0
- package/dist/core/tools/builtIn.d.ts.map +1 -0
- package/dist/core/tools/builtIn.js +219 -0
- package/dist/core/tools/builtIn.js.map +1 -0
- package/dist/core/tools/index.d.ts +13 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/index.js +43 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/standards.d.ts +6 -0
- package/dist/core/tools/standards.d.ts.map +1 -0
- package/dist/core/tools/standards.js +215 -0
- package/dist/core/tools/standards.js.map +1 -0
- package/dist/core/tools/types.d.ts +34 -0
- package/dist/core/tools/types.d.ts.map +1 -0
- package/dist/core/tools/types.js +2 -0
- package/dist/core/tools/types.js.map +1 -0
- package/dist/ui/App.d.ts +10 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +167 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/components/InputBox.d.ts +11 -0
- package/dist/ui/components/InputBox.d.ts.map +1 -0
- package/dist/ui/components/InputBox.js +7 -0
- package/dist/ui/components/InputBox.js.map +1 -0
- package/dist/ui/components/MessageList.d.ts +17 -0
- package/dist/ui/components/MessageList.d.ts.map +1 -0
- package/dist/ui/components/MessageList.js +18 -0
- package/dist/ui/components/MessageList.js.map +1 -0
- package/dist/ui/components/StatusBar.d.ts +9 -0
- package/dist/ui/components/StatusBar.d.ts.map +1 -0
- package/dist/ui/components/StatusBar.js +6 -0
- package/dist/ui/components/StatusBar.js.map +1 -0
- package/dist/ui/components/ToolStatus.d.ts +8 -0
- package/dist/ui/components/ToolStatus.d.ts.map +1 -0
- package/dist/ui/components/ToolStatus.js +7 -0
- package/dist/ui/components/ToolStatus.js.map +1 -0
- package/package.json +64 -0
- package/screenshot.png +0 -0
- package/src/cli/banner.ts +34 -0
- package/src/cli/headless.ts +37 -0
- package/src/cli/index.ts +53 -0
- package/src/core/agent.ts +235 -0
- package/src/core/config.ts +98 -0
- package/src/core/llm/ollama.ts +238 -0
- package/src/core/mcp/client.ts +143 -0
- package/src/core/tools/builtIn.ts +221 -0
- package/src/core/tools/index.ts +53 -0
- package/src/core/tools/standards.ts +246 -0
- package/src/core/tools/types.ts +37 -0
- package/src/ui/App.tsx +238 -0
- package/src/ui/components/InputBox.tsx +37 -0
- package/src/ui/components/MessageList.tsx +80 -0
- package/src/ui/components/StatusBar.tsx +36 -0
- package/src/ui/components/ToolStatus.tsx +38 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import gradient from "gradient-string";
|
|
2
|
+
const ACTIVO_ASCII = `
|
|
3
|
+
_ ____ _____ _____ _____
|
|
4
|
+
/ \\ / ___|_ _|_ _\\ \\ / / _ \\
|
|
5
|
+
/ _ \\| | | | | | \\ \\ / / | | |
|
|
6
|
+
/ ___ \\ |___ | | | | \\ V /| |_| |
|
|
7
|
+
/_/ \\_\\____| |_| |___| \\_/ \\___/
|
|
8
|
+
`;
|
|
9
|
+
const SUBTITLE = "AI-Powered Code Quality Analyzer";
|
|
10
|
+
const VERSION = "v0.2.0";
|
|
11
|
+
export function showBanner() {
|
|
12
|
+
const activoGradient = gradient(["#00d4ff", "#7b2ff7", "#f107a3"]);
|
|
13
|
+
console.log(activoGradient.multiline(ACTIVO_ASCII));
|
|
14
|
+
console.log();
|
|
15
|
+
console.log(` ${gradient(["#7b2ff7", "#00d4ff"])(SUBTITLE)} ${VERSION}`);
|
|
16
|
+
console.log();
|
|
17
|
+
console.log(" Type your request in natural language.");
|
|
18
|
+
console.log(" Examples:");
|
|
19
|
+
console.log(" • 이 프로젝트의 코드 품질을 분석해줘");
|
|
20
|
+
console.log(" • PDF 파일을 마크다운 규칙으로 변환해줘");
|
|
21
|
+
console.log(" • src 폴더의 명명규칙 위반을 찾아줘");
|
|
22
|
+
console.log();
|
|
23
|
+
console.log(" Press Ctrl+C twice to exit");
|
|
24
|
+
console.log("─".repeat(50));
|
|
25
|
+
console.log();
|
|
26
|
+
}
|
|
27
|
+
export function getShortBanner() {
|
|
28
|
+
return gradient(["#00d4ff", "#7b2ff7"])("ACTIVO") + " - Code Quality Analyzer";
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=banner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banner.js","sourceRoot":"","sources":["../../src/cli/banner.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AAEvC,MAAM,YAAY,GAAG;;;;;;CAMpB,CAAC;AAEF,MAAM,QAAQ,GAAG,kCAAkC,CAAC;AACpD,MAAM,OAAO,GAAG,QAAQ,CAAC;AAEzB,MAAM,UAAU,UAAU;IACxB,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAEnE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,QAAQ,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,0BAA0B,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B3F"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { OllamaClient } from "../core/llm/ollama.js";
|
|
2
|
+
import { processMessage } from "../core/agent.js";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
export async function runHeadless(prompt, config) {
|
|
5
|
+
if (!prompt) {
|
|
6
|
+
console.error(chalk.red("Error: Prompt is required in headless mode"));
|
|
7
|
+
console.error(chalk.yellow("Usage: activo -p \"your prompt here\""));
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
const client = new OllamaClient(config.ollama);
|
|
11
|
+
// Check connection
|
|
12
|
+
const isConnected = await client.isConnected();
|
|
13
|
+
if (!isConnected) {
|
|
14
|
+
console.error(chalk.red("Error: Cannot connect to Ollama"));
|
|
15
|
+
console.error(chalk.yellow(`Make sure Ollama is running at ${config.ollama.baseUrl}`));
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const result = await processMessage(prompt, [], client, config, (event) => {
|
|
20
|
+
if (event.type === "tool_use") {
|
|
21
|
+
console.error(chalk.dim(`[Tool] ${event.tool}: ${event.status}`));
|
|
22
|
+
}
|
|
23
|
+
else if (event.type === "thinking") {
|
|
24
|
+
// Skip thinking in headless mode
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
console.log(result.content);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error(chalk.red(`Error: ${error}`));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=headless.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAA0B,EAAE,MAAc;IAC1E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,uCAAuC,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/C,mBAAmB;IACnB,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IAC/C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC,CAAC;QAC5D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,kCAAkC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YACxE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACrC,iCAAiC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { render } from "ink";
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { App } from "../ui/App.js";
|
|
6
|
+
import { showBanner } from "./banner.js";
|
|
7
|
+
import { loadConfig } from "../core/config.js";
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program
|
|
10
|
+
.name("activo")
|
|
11
|
+
.description("AI-powered code quality analyzer with Tool Calling and MCP support")
|
|
12
|
+
.version("0.2.0", "-v, --version", "Display version number");
|
|
13
|
+
program
|
|
14
|
+
.option("-p, --print", "Non-interactive mode (print and exit)")
|
|
15
|
+
.option("--headless", "Headless mode for CI/CD")
|
|
16
|
+
.option("--resume", "Resume from last session")
|
|
17
|
+
.option("--model <model>", "Specify Ollama model")
|
|
18
|
+
.argument("[prompt]", "Initial prompt")
|
|
19
|
+
.action(async (prompt, options) => {
|
|
20
|
+
// Show ASCII banner
|
|
21
|
+
showBanner();
|
|
22
|
+
// Load config
|
|
23
|
+
const config = loadConfig();
|
|
24
|
+
if (options.model) {
|
|
25
|
+
config.ollama.model = options.model;
|
|
26
|
+
}
|
|
27
|
+
// Headless/print mode
|
|
28
|
+
if (options.print || options.headless) {
|
|
29
|
+
const { runHeadless } = await import("./headless.js");
|
|
30
|
+
await runHeadless(prompt, config);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Interactive TUI mode
|
|
34
|
+
const { waitUntilExit } = render(React.createElement(App, {
|
|
35
|
+
initialPrompt: prompt,
|
|
36
|
+
config,
|
|
37
|
+
resume: options.resume,
|
|
38
|
+
}));
|
|
39
|
+
await waitUntilExit();
|
|
40
|
+
});
|
|
41
|
+
program.parse();
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,oEAAoE,CAAC;KACjF,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,wBAAwB,CAAC,CAAC;AAE/D,OAAO;KACJ,MAAM,CAAC,aAAa,EAAE,uCAAuC,CAAC;KAC9D,MAAM,CAAC,YAAY,EAAE,yBAAyB,CAAC;KAC/C,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;KACjD,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;KACtC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;IAChC,oBAAoB;IACpB,UAAU,EAAE,CAAC;IAEb,cAAc;IACd,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IACtC,CAAC;IAED,sBAAsB;IACtB,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QACtD,MAAM,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,uBAAuB;IACvB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE;QACvB,aAAa,EAAE,MAAM;QACrB,MAAM;QACN,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CACH,CAAC;IAEF,MAAM,aAAa,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { OllamaClient, ChatMessage } from "./llm/ollama.js";
|
|
2
|
+
import { Config } from "./config.js";
|
|
3
|
+
import { ToolResult } from "./tools/index.js";
|
|
4
|
+
export interface AgentEvent {
|
|
5
|
+
type: "thinking" | "content" | "tool_use" | "tool_result" | "done" | "error";
|
|
6
|
+
content?: string;
|
|
7
|
+
tool?: string;
|
|
8
|
+
status?: "start" | "complete" | "error";
|
|
9
|
+
args?: Record<string, unknown>;
|
|
10
|
+
result?: ToolResult;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface AgentResult {
|
|
14
|
+
content: string;
|
|
15
|
+
toolCalls: Array<{
|
|
16
|
+
tool: string;
|
|
17
|
+
args: Record<string, unknown>;
|
|
18
|
+
result: ToolResult;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
export declare function processMessage(userMessage: string, history: ChatMessage[], client: OllamaClient, config: Config, onEvent?: (event: AgentEvent) => void): Promise<AgentResult>;
|
|
22
|
+
export declare function streamProcessMessage(userMessage: string, history: ChatMessage[], client: OllamaClient, config: Config, abortSignal?: AbortSignal): AsyncGenerator<AgentEvent>;
|
|
23
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/core/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAsC,UAAU,EAAQ,MAAM,kBAAkB,CAAC;AAExF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,MAAM,EAAE,UAAU,CAAC;KACpB,CAAC,CAAC;CACJ;AA+BD,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GACpC,OAAO,CAAC,WAAW,CAAC,CA+EtB;AAED,wBAAuB,oBAAoB,CACzC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,cAAc,CAAC,UAAU,CAAC,CAyF5B"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { getAllTools, executeTool } from "./tools/index.js";
|
|
2
|
+
const SYSTEM_PROMPT = `You are ACTIVO, an AI-powered code quality analyzer.
|
|
3
|
+
|
|
4
|
+
You help developers:
|
|
5
|
+
1. Analyze code quality and find issues
|
|
6
|
+
2. Import development standards from PDFs
|
|
7
|
+
3. Check code against standards
|
|
8
|
+
4. Navigate and understand codebases
|
|
9
|
+
|
|
10
|
+
You have access to these tools:
|
|
11
|
+
- read_file: Read file contents
|
|
12
|
+
- write_file: Write content to files
|
|
13
|
+
- list_directory: List directory contents
|
|
14
|
+
- grep_search: Search for patterns in files
|
|
15
|
+
- glob_search: Find files by pattern
|
|
16
|
+
- run_command: Execute shell commands
|
|
17
|
+
- import_pdf_standards: Convert PDF to markdown rules
|
|
18
|
+
- list_standards: List loaded standards
|
|
19
|
+
- check_code_quality: Check code against standards
|
|
20
|
+
|
|
21
|
+
When users ask in natural language, use the appropriate tools to help them.
|
|
22
|
+
Examples:
|
|
23
|
+
- "이 프로젝트 분석해줘" → Use list_directory, read_file to explore
|
|
24
|
+
- "PDF 규칙으로 변환해줘" → Use import_pdf_standards
|
|
25
|
+
- "코드 품질 검사해줘" → Use check_code_quality
|
|
26
|
+
- "UserService 찾아줘" → Use grep_search or glob_search
|
|
27
|
+
|
|
28
|
+
Always explain what you're doing and provide helpful insights.
|
|
29
|
+
Respond in the same language as the user's input.`;
|
|
30
|
+
export async function processMessage(userMessage, history, client, config, onEvent) {
|
|
31
|
+
const tools = getAllTools();
|
|
32
|
+
const toolDefinitions = tools.map((t) => ({
|
|
33
|
+
name: t.name,
|
|
34
|
+
description: t.description,
|
|
35
|
+
parameters: t.parameters,
|
|
36
|
+
}));
|
|
37
|
+
const messages = [
|
|
38
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
39
|
+
...history,
|
|
40
|
+
{ role: "user", content: userMessage },
|
|
41
|
+
];
|
|
42
|
+
const toolCallResults = [];
|
|
43
|
+
let finalContent = "";
|
|
44
|
+
let iterations = 0;
|
|
45
|
+
const maxIterations = 10;
|
|
46
|
+
while (iterations < maxIterations) {
|
|
47
|
+
iterations++;
|
|
48
|
+
onEvent?.({ type: "thinking" });
|
|
49
|
+
const response = await client.chat(messages, tools);
|
|
50
|
+
messages.push(response);
|
|
51
|
+
// If no tool calls, we're done
|
|
52
|
+
if (!response.toolCalls?.length) {
|
|
53
|
+
finalContent = response.content;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
// Process tool calls
|
|
57
|
+
for (const toolCall of response.toolCalls) {
|
|
58
|
+
onEvent?.({
|
|
59
|
+
type: "tool_use",
|
|
60
|
+
tool: toolCall.name,
|
|
61
|
+
status: "start",
|
|
62
|
+
args: toolCall.arguments,
|
|
63
|
+
});
|
|
64
|
+
const result = await executeTool(toolCall);
|
|
65
|
+
onEvent?.({
|
|
66
|
+
type: "tool_result",
|
|
67
|
+
tool: toolCall.name,
|
|
68
|
+
status: result.success ? "complete" : "error",
|
|
69
|
+
result,
|
|
70
|
+
});
|
|
71
|
+
toolCallResults.push({
|
|
72
|
+
tool: toolCall.name,
|
|
73
|
+
args: toolCall.arguments,
|
|
74
|
+
result,
|
|
75
|
+
});
|
|
76
|
+
// Add tool result to messages
|
|
77
|
+
messages.push({
|
|
78
|
+
role: "tool",
|
|
79
|
+
content: result.success ? result.content : `Error: ${result.error}`,
|
|
80
|
+
toolCallId: toolCall.id,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// Continue the conversation with tool results
|
|
84
|
+
onEvent?.({ type: "content", content: response.content });
|
|
85
|
+
}
|
|
86
|
+
if (iterations >= maxIterations) {
|
|
87
|
+
onEvent?.({ type: "error", error: "Maximum iterations reached" });
|
|
88
|
+
}
|
|
89
|
+
onEvent?.({ type: "done" });
|
|
90
|
+
return {
|
|
91
|
+
content: finalContent,
|
|
92
|
+
toolCalls: toolCallResults,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function* streamProcessMessage(userMessage, history, client, config, abortSignal) {
|
|
96
|
+
const tools = getAllTools();
|
|
97
|
+
const messages = [
|
|
98
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
99
|
+
...history,
|
|
100
|
+
{ role: "user", content: userMessage },
|
|
101
|
+
];
|
|
102
|
+
let iterations = 0;
|
|
103
|
+
const maxIterations = 10;
|
|
104
|
+
while (iterations < maxIterations) {
|
|
105
|
+
// Check if aborted
|
|
106
|
+
if (abortSignal?.aborted) {
|
|
107
|
+
yield { type: "error", error: "Operation cancelled" };
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
iterations++;
|
|
111
|
+
yield { type: "thinking" };
|
|
112
|
+
let fullContent = "";
|
|
113
|
+
const pendingToolCalls = [];
|
|
114
|
+
for await (const event of client.streamChat(messages, tools, abortSignal)) {
|
|
115
|
+
// Check if aborted during streaming
|
|
116
|
+
if (abortSignal?.aborted) {
|
|
117
|
+
yield { type: "error", error: "Operation cancelled" };
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (event.type === "content" && event.content) {
|
|
121
|
+
fullContent += event.content;
|
|
122
|
+
yield { type: "content", content: event.content };
|
|
123
|
+
}
|
|
124
|
+
else if (event.type === "tool_call" && event.toolCall) {
|
|
125
|
+
pendingToolCalls.push(event.toolCall);
|
|
126
|
+
}
|
|
127
|
+
else if (event.type === "error") {
|
|
128
|
+
yield { type: "error", error: event.error };
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
messages.push({ role: "assistant", content: fullContent, toolCalls: pendingToolCalls.length > 0 ? pendingToolCalls : undefined });
|
|
133
|
+
// If no tool calls, we're done
|
|
134
|
+
if (pendingToolCalls.length === 0) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
// Process tool calls
|
|
138
|
+
for (const toolCall of pendingToolCalls) {
|
|
139
|
+
// Check if aborted before each tool call
|
|
140
|
+
if (abortSignal?.aborted) {
|
|
141
|
+
yield { type: "error", error: "Operation cancelled" };
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
yield {
|
|
145
|
+
type: "tool_use",
|
|
146
|
+
tool: toolCall.name,
|
|
147
|
+
status: "start",
|
|
148
|
+
args: toolCall.arguments,
|
|
149
|
+
};
|
|
150
|
+
const result = await executeTool(toolCall);
|
|
151
|
+
// Check if aborted after tool execution
|
|
152
|
+
if (abortSignal?.aborted) {
|
|
153
|
+
yield { type: "error", error: "Operation cancelled" };
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
yield {
|
|
157
|
+
type: "tool_result",
|
|
158
|
+
tool: toolCall.name,
|
|
159
|
+
status: result.success ? "complete" : "error",
|
|
160
|
+
result,
|
|
161
|
+
};
|
|
162
|
+
messages.push({
|
|
163
|
+
role: "tool",
|
|
164
|
+
content: result.success ? result.content : `Error: ${result.error}`,
|
|
165
|
+
toolCallId: toolCall.id,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
yield { type: "done" };
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/core/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface OllamaConfig {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
model: string;
|
|
4
|
+
contextLength: number;
|
|
5
|
+
keepAlive: number;
|
|
6
|
+
}
|
|
7
|
+
export interface Config {
|
|
8
|
+
ollama: OllamaConfig;
|
|
9
|
+
standards: {
|
|
10
|
+
directory: string;
|
|
11
|
+
};
|
|
12
|
+
mcp: {
|
|
13
|
+
servers: Record<string, MCPServerConfig>;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface MCPServerConfig {
|
|
17
|
+
command: string;
|
|
18
|
+
args?: string[];
|
|
19
|
+
env?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export declare function loadConfig(): Config;
|
|
22
|
+
export declare function saveConfig(config: Config): void;
|
|
23
|
+
export declare function getProjectConfig(): Config;
|
|
24
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,GAAG,EAAE;QACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;KAC1C,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAqBD,wBAAgB,UAAU,IAAI,MAAM,CAkBnC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAS/C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAoBzC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
ollama: {
|
|
6
|
+
baseUrl: "http://localhost:11434",
|
|
7
|
+
model: "mistral:latest",
|
|
8
|
+
contextLength: 8192,
|
|
9
|
+
keepAlive: 1800, // 30 minutes
|
|
10
|
+
},
|
|
11
|
+
standards: {
|
|
12
|
+
directory: ".activo/standards",
|
|
13
|
+
},
|
|
14
|
+
mcp: {
|
|
15
|
+
servers: {},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
function getConfigPath() {
|
|
19
|
+
return path.join(os.homedir(), ".activo", "config.json");
|
|
20
|
+
}
|
|
21
|
+
export function loadConfig() {
|
|
22
|
+
const configPath = getConfigPath();
|
|
23
|
+
if (fs.existsSync(configPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const data = fs.readFileSync(configPath, "utf-8");
|
|
26
|
+
const loaded = JSON.parse(data);
|
|
27
|
+
return {
|
|
28
|
+
ollama: { ...DEFAULT_CONFIG.ollama, ...loaded.ollama },
|
|
29
|
+
standards: { ...DEFAULT_CONFIG.standards, ...loaded.standards },
|
|
30
|
+
mcp: { ...DEFAULT_CONFIG.mcp, ...loaded.mcp },
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return DEFAULT_CONFIG;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return DEFAULT_CONFIG;
|
|
38
|
+
}
|
|
39
|
+
export function saveConfig(config) {
|
|
40
|
+
const configPath = getConfigPath();
|
|
41
|
+
const configDir = path.dirname(configPath);
|
|
42
|
+
if (!fs.existsSync(configDir)) {
|
|
43
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
46
|
+
}
|
|
47
|
+
export function getProjectConfig() {
|
|
48
|
+
const projectConfigPath = path.join(process.cwd(), ".activo", "config.json");
|
|
49
|
+
if (fs.existsSync(projectConfigPath)) {
|
|
50
|
+
try {
|
|
51
|
+
const data = fs.readFileSync(projectConfigPath, "utf-8");
|
|
52
|
+
const projectConfig = JSON.parse(data);
|
|
53
|
+
const globalConfig = loadConfig();
|
|
54
|
+
return {
|
|
55
|
+
ollama: { ...globalConfig.ollama, ...projectConfig.ollama },
|
|
56
|
+
standards: { ...globalConfig.standards, ...projectConfig.standards },
|
|
57
|
+
mcp: { ...globalConfig.mcp, ...projectConfig.mcp },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return loadConfig();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return loadConfig();
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { OllamaConfig } from "../config.js";
|
|
2
|
+
import { Tool, ToolCall } from "../tools/types.js";
|
|
3
|
+
export interface ChatMessage {
|
|
4
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
5
|
+
content: string;
|
|
6
|
+
toolCalls?: ToolCall[];
|
|
7
|
+
toolCallId?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface StreamEvent {
|
|
10
|
+
type: "content" | "tool_call" | "done" | "error";
|
|
11
|
+
content?: string;
|
|
12
|
+
toolCall?: ToolCall;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class OllamaClient {
|
|
16
|
+
private baseUrl;
|
|
17
|
+
private model;
|
|
18
|
+
private contextLength;
|
|
19
|
+
private keepAlive;
|
|
20
|
+
constructor(config: OllamaConfig);
|
|
21
|
+
isConnected(): Promise<boolean>;
|
|
22
|
+
listModels(): Promise<string[]>;
|
|
23
|
+
chat(messages: ChatMessage[], tools?: Tool[]): Promise<ChatMessage>;
|
|
24
|
+
streamChat(messages: ChatMessage[], tools?: Tool[], abortSignal?: AbortSignal): AsyncGenerator<StreamEvent>;
|
|
25
|
+
private convertMessages;
|
|
26
|
+
private parseResponse;
|
|
27
|
+
getModel(): string;
|
|
28
|
+
setModel(model: string): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=ollama.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../../src/core/llm/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiBD,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,YAAY;IAO1B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/B,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAO/B,IAAI,CACR,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,CAAC,EAAE,IAAI,EAAE,GACb,OAAO,CAAC,WAAW,CAAC;IAwChB,UAAU,CACf,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,CAAC,EAAE,IAAI,EAAE,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,cAAc,CAAC,WAAW,CAAC;IAuF9B,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,aAAa;IAiBrB,QAAQ,IAAI,MAAM;IAIlB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAG9B"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
export class OllamaClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
model;
|
|
4
|
+
contextLength;
|
|
5
|
+
keepAlive;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.baseUrl = config.baseUrl;
|
|
8
|
+
this.model = config.model;
|
|
9
|
+
this.contextLength = config.contextLength;
|
|
10
|
+
this.keepAlive = config.keepAlive;
|
|
11
|
+
}
|
|
12
|
+
async isConnected() {
|
|
13
|
+
try {
|
|
14
|
+
const response = await fetch(`${this.baseUrl}/api/tags`);
|
|
15
|
+
return response.ok;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async listModels() {
|
|
22
|
+
const response = await fetch(`${this.baseUrl}/api/tags`);
|
|
23
|
+
if (!response.ok)
|
|
24
|
+
throw new Error("Failed to list models");
|
|
25
|
+
const data = (await response.json());
|
|
26
|
+
return data.models.map((m) => m.name);
|
|
27
|
+
}
|
|
28
|
+
async chat(messages, tools) {
|
|
29
|
+
const ollamaMessages = this.convertMessages(messages);
|
|
30
|
+
const body = {
|
|
31
|
+
model: this.model,
|
|
32
|
+
messages: ollamaMessages,
|
|
33
|
+
stream: false,
|
|
34
|
+
options: {
|
|
35
|
+
num_ctx: this.contextLength,
|
|
36
|
+
},
|
|
37
|
+
keep_alive: this.keepAlive,
|
|
38
|
+
};
|
|
39
|
+
// Add tools if last message is from user
|
|
40
|
+
if (tools?.length && messages[messages.length - 1]?.role === "user") {
|
|
41
|
+
body.tools = tools.map((tool) => ({
|
|
42
|
+
type: "function",
|
|
43
|
+
function: {
|
|
44
|
+
name: tool.name,
|
|
45
|
+
description: tool.description,
|
|
46
|
+
parameters: tool.parameters,
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
const response = await fetch(`${this.baseUrl}/api/chat`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "Content-Type": "application/json" },
|
|
53
|
+
body: JSON.stringify(body),
|
|
54
|
+
});
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const error = await response.text();
|
|
57
|
+
throw new Error(`Ollama error: ${error}`);
|
|
58
|
+
}
|
|
59
|
+
const data = (await response.json());
|
|
60
|
+
return this.parseResponse(data);
|
|
61
|
+
}
|
|
62
|
+
async *streamChat(messages, tools, abortSignal) {
|
|
63
|
+
const ollamaMessages = this.convertMessages(messages);
|
|
64
|
+
const body = {
|
|
65
|
+
model: this.model,
|
|
66
|
+
messages: ollamaMessages,
|
|
67
|
+
stream: true,
|
|
68
|
+
options: {
|
|
69
|
+
num_ctx: this.contextLength,
|
|
70
|
+
},
|
|
71
|
+
keep_alive: this.keepAlive,
|
|
72
|
+
};
|
|
73
|
+
if (tools?.length && messages[messages.length - 1]?.role === "user") {
|
|
74
|
+
body.tools = tools.map((tool) => ({
|
|
75
|
+
type: "function",
|
|
76
|
+
function: {
|
|
77
|
+
name: tool.name,
|
|
78
|
+
description: tool.description,
|
|
79
|
+
parameters: tool.parameters,
|
|
80
|
+
},
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
const response = await fetch(`${this.baseUrl}/api/chat`, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify(body),
|
|
87
|
+
signal: abortSignal,
|
|
88
|
+
});
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
const error = await response.text();
|
|
91
|
+
yield { type: "error", error: `Ollama error: ${error}` };
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const reader = response.body?.getReader();
|
|
95
|
+
if (!reader) {
|
|
96
|
+
yield { type: "error", error: "No response body" };
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const decoder = new TextDecoder();
|
|
100
|
+
let buffer = "";
|
|
101
|
+
let accumulatedToolCalls = [];
|
|
102
|
+
while (true) {
|
|
103
|
+
const { done, value } = await reader.read();
|
|
104
|
+
if (done)
|
|
105
|
+
break;
|
|
106
|
+
buffer += decoder.decode(value, { stream: true });
|
|
107
|
+
const lines = buffer.split("\n");
|
|
108
|
+
buffer = lines.pop() || "";
|
|
109
|
+
for (const line of lines) {
|
|
110
|
+
if (!line.trim())
|
|
111
|
+
continue;
|
|
112
|
+
try {
|
|
113
|
+
const data = JSON.parse(line);
|
|
114
|
+
if (data.message?.content) {
|
|
115
|
+
yield { type: "content", content: data.message.content };
|
|
116
|
+
}
|
|
117
|
+
if (data.message?.tool_calls?.length) {
|
|
118
|
+
for (const tc of data.message.tool_calls) {
|
|
119
|
+
const toolCall = {
|
|
120
|
+
id: `tc_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
121
|
+
name: tc.function.name,
|
|
122
|
+
arguments: tc.function.arguments,
|
|
123
|
+
};
|
|
124
|
+
accumulatedToolCalls.push(toolCall);
|
|
125
|
+
yield { type: "tool_call", toolCall };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (data.done) {
|
|
129
|
+
yield { type: "done" };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Skip invalid JSON
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
convertMessages(messages) {
|
|
139
|
+
return messages.map((msg) => {
|
|
140
|
+
if (msg.role === "tool") {
|
|
141
|
+
return {
|
|
142
|
+
role: "tool",
|
|
143
|
+
content: msg.content,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
role: msg.role,
|
|
148
|
+
content: msg.content,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
parseResponse(data) {
|
|
153
|
+
const result = {
|
|
154
|
+
role: "assistant",
|
|
155
|
+
content: data.message.content || "",
|
|
156
|
+
};
|
|
157
|
+
if (data.message.tool_calls?.length) {
|
|
158
|
+
result.toolCalls = data.message.tool_calls.map((tc, idx) => ({
|
|
159
|
+
id: `tc_${Date.now()}_${idx}`,
|
|
160
|
+
name: tc.function.name,
|
|
161
|
+
arguments: tc.function.arguments,
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
getModel() {
|
|
167
|
+
return this.model;
|
|
168
|
+
}
|
|
169
|
+
setModel(model) {
|
|
170
|
+
this.model = model;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=ollama.js.map
|