diff --git a/packages/cli/bin/agent.ts b/packages/cli/bin/agent.ts index 8b00547..e8fe43d 100644 --- a/packages/cli/bin/agent.ts +++ b/packages/cli/bin/agent.ts @@ -1,29 +1,29 @@ import { useAgentBrain } from "@agent-smith/brain"; import { LmTaskBuilder } from "@agent-smith/lmtask"; import { MarkedExtension, marked } from 'marked'; -import { markedTerminal } from 'marked-terminal'; +import { markedTerminal } from "marked-terminal"; import { FeatureType, RunMode } from "./interfaces.js"; marked.use(markedTerminal() as MarkedExtension); let brain = useAgentBrain(); -const modelsForExpert: Record = {}; const taskBuilder = new LmTaskBuilder(brain); async function initExperts() { brain.experts.forEach((ex) => { - ex.backend.setOnStartEmit(() => console.log("")) + //ex.backend.setOnStartEmit(() => console.log("")) ex.backend.setOnToken((t) => { process.stdout.write(t) }); }); } -async function initAgent(mode: RunMode, isVerbose = false): Promise { +async function initAgent(isVerbose = false): Promise { if (!brain.state.get().isOn) { brain.resetExperts(); - await brain.initLocal(); + //console.log("Init", isVerbose); + await brain.initLocal(true, isVerbose); await initExperts(); /*console.log("Backends:", brain.backends.map(x => x.name)); console.log("Experts:", brain.experts.map(x => x.name)); @@ -32,15 +32,20 @@ async function initAgent(mode: RunMode, isVerbose = false): Promise { const brainUp = brain.state.get().isOn; if (isVerbose) { if (!brainUp) { - console.log("❌ No experts found for inference"); + console.log("❌ No backends found for inference"); } else { - brain.experts.forEach((ex) => { - console.log(`✅ Expert ${ex.name} is up`) + brain.backends.forEach((b) => { + console.log(`✅ Backend ${b.name} is up`); + if (b.lm.providerType == "ollama") { + console.log(" Models:", b.lm.models.map(x => x.name)) + } else { + console.log(" Model:", b.lm.model.name) + } }) } } return brainUp } -export { brain, initAgent, marked, modelsForExpert, taskBuilder }; +export { brain, initAgent, marked, taskBuilder }; diff --git a/packages/cli/bin/cli.ts b/packages/cli/bin/cli.ts index 4c16f82..4deedda 100644 --- a/packages/cli/bin/cli.ts +++ b/packages/cli/bin/cli.ts @@ -1,8 +1,9 @@ import { input } from '@inquirer/prompts'; -import { runCmd } from './cmd/cmds.js'; -import { lastCmd, inputMode } from './state/state.js'; -import { readPromptFile } from './cmd/lib/utils.js'; +import { chat, runCmd } from './cmd/cmds.js'; +import { lastCmd, inputMode, isChatMode } from './state/state.js'; +import { readPromptFile, setOptions } from './cmd/lib/utils.js'; import { readClipboard } from './cmd/sys/clipboard.js'; +import { modes } from './cmd/clicmds/modes.js'; /** * Parses a string of parameters, which may include quoted strings and standalone words. @@ -32,28 +33,41 @@ function parseParams(params: string): Array { } async function dispatch(input: string) { - let buf = new Array(); - buf = parseParams(input); - const cmd = buf.shift()!; - if (inputMode.value == "promptfile") { - const p = readPromptFile(); - buf.push(p) - } else if (inputMode.value == "clipboard") { - const p = await readClipboard(); - buf.push(p) + //console.log("Dispatch", input); + // modes + if (input.startsWith("-")) { + try { + const _cmd = modes[input].cmd; + await _cmd([], {}); + return + } catch (e) { + throw new Error(`Option error ${e}`) + } } - await runCmd(cmd, buf) + // args + const buf = new Array(); + let params = parseParams(input); + const cmd = params.shift()!; + const opts: Record = {}; + params.forEach((p) => { + if (p.startsWith("-")) { + opts[p.substring(1)] = true; + } else { + buf.push(p) + } + }); + const args = await setOptions(buf, opts); + await runCmd(cmd, args) } -async function query(_default?: string) { - const data = { message: '>', default: "" }; - if (_default) { - data.default = _default +async function query(sign = "$") { + const data = { message: sign, default: "" }; + const q = await input(data); + await dispatch(q); + if (isChatMode.value) { + await chat() } - const answer = await input(data); - await dispatch(answer); - const lc = lastCmd.name + " " + lastCmd.args.join(" "); - await query(lc) + await query(sign) } export { query } diff --git a/packages/cli/bin/cmd/clicmds/cmds.ts b/packages/cli/bin/cmd/clicmds/cmds.ts index 33dd8aa..1a9b5b1 100644 --- a/packages/cli/bin/cmd/clicmds/cmds.ts +++ b/packages/cli/bin/cmd/clicmds/cmds.ts @@ -1,11 +1,11 @@ import { Cmd, FeatureType } from "../../interfaces.js"; -import { formatMode, runMode } from "../../state/state.js"; +import { formatMode, isChatMode, runMode } from "../../state/state.js"; import { getFeatureSpec, readFeaturesDirs } from "../../state/features.js"; import { readAliases, readFeatures } from "../../db/read.js"; import { cleanupFeaturePaths, updateAliases, updateFeatures } from "../../db/write.js"; import { processConfPath } from "../../conf.js"; import { executeActionCmd } from "../lib/execute_action.js"; -import { initAgent, marked, taskBuilder } from "../../agent.js"; +import { brain, initAgent, marked, taskBuilder } from "../../agent.js"; import { executeJobCmd, readJob } from "../lib/execute_job.js"; import { executeTaskCmd } from "../lib/execute_task.js"; import { readCmds } from "../sys/read_cmds.js"; @@ -98,11 +98,8 @@ async function initCmds(): Promise> { } async function pingCmd(args: Array = [], options: any): Promise { - let _isVerbose = false; - if (args.length > 0) { - _isVerbose = args[0] == "verbose" - } - const isUp = await initAgent(runMode.value, _isVerbose); + const isUp = await initAgent(true); + //console.log(brain.backends); return isUp } @@ -137,7 +134,7 @@ async function _executeTaskCmd(args: Array = [], options: any): Promise< console.warn("Provide a task name"); return } - const { ok, data, error } = await executeTaskCmd(args, options); + const { ok, data, conf, error } = await executeTaskCmd(args, options); if (!ok) { console.warn(error) } @@ -147,8 +144,11 @@ async function _executeTaskCmd(args: Array = [], options: any): Promise< } else { console.log() } + if (isChatMode.value) { + + } + //console.log("ENDRES", data); return data - //console.log("ENDRES", t); } async function _executeJobCmd(args: Array = [], options: any): Promise { diff --git a/packages/cli/bin/cmd/clicmds/modes.ts b/packages/cli/bin/cmd/clicmds/modes.ts index 0639b92..8697134 100644 --- a/packages/cli/bin/cmd/clicmds/modes.ts +++ b/packages/cli/bin/cmd/clicmds/modes.ts @@ -1,13 +1,21 @@ import { Cmd } from "../../interfaces.js"; -import { formatMode, inputMode, isDebug, outputMode, runMode } from "../../state/state.js"; +import { formatMode, inputMode, isChatMode, isDebug, outputMode, runMode } from "../../state/state.js"; const modes: Record = { "-d": { cmd: async () => { isDebug.value = true; + if (runMode.value == "cli") { console.log("Debug mode is on") } }, description: "use debug mode", }, + "-c": { + cmd: async () => { + isChatMode.value = true; + if (runMode.value == "cli") { console.log("Chat mode is on") } + }, + description: "use chat mode for tasks", + }, "-if": { cmd: async () => { inputMode.value = "promptfile"; diff --git a/packages/cli/bin/cmd/cmds.ts b/packages/cli/bin/cmd/cmds.ts index e74710c..4c06fe7 100644 --- a/packages/cli/bin/cmd/cmds.ts +++ b/packages/cli/bin/cmd/cmds.ts @@ -1,14 +1,36 @@ +import { input } from "@inquirer/prompts"; import { Command } from "commander"; -import { lastCmd } from "../state/state.js"; +import { brain } from "../agent.js"; +import { Cmd } from "../interfaces.js"; +import { isChatMode, lastCmd, runMode } from "../state/state.js"; +import { cmds, initAliases, initCmds } from "./clicmds/cmds.js"; import { modes } from "./clicmds/modes.js"; import { processOutput, setOptions } from "./lib/utils.js"; -import { cmds, initAliases, initCmds } from "./clicmds/cmds.js"; -import { Cmd } from "../interfaces.js"; +import { query } from "../cli.js"; let cliCmds: Record = {}; +async function chat() { + const data = { message: '>', default: "" }; + const prompt = await input(data); + if (prompt == "/q") { + isChatMode.value = false; + if (runMode.value == "cmd") { + process.exit(0) + } else { + await query() + } + } + //console.log("EX", brain.ex); + await brain.ex.think(prompt); + console.log(); + await chat(); +} + async function initCliCmds() { - cliCmds = await initCmds() + const _cmds = await initCmds(); + const _alias = initAliases(); + cliCmds = { ..._cmds, ..._alias } } async function runCmd(cmdName: string, args: Array = []) { @@ -20,20 +42,18 @@ async function runCmd(cmdName: string, args: Array = []) { //console.log("Running cmd", cmds[cmdName]); await cmd(args, {}); lastCmd.name = cmdName; - /*if (inputMode.value != "manual") { - args.pop() - }*/ lastCmd.args = args; } async function buildCmds(): Promise { const program = new Command(); const aliases = initAliases(); - for (const [name, spec] of Object.entries({ ...cmds, ...aliases })) { + const excmds = await initCmds(); + for (const [name, spec] of Object.entries({ ...cmds, ...excmds, ...aliases })) { const cmd = program.command(name); const _cmd = async (args: Array = [], options: any = {}): Promise => { //console.log("CMD OPTS", options); - const _args = await setOptions(options, args); + const _args = await setOptions(args, options); const res = await spec.cmd(_args, options); //console.log("RES", res); await processOutput(res); @@ -63,6 +83,10 @@ async function buildCmds(): Promise { async function parseCmd() { const program = await buildCmds(); await program.parseAsync(); + if (isChatMode.value) { + await chat() + } } -export { runCmd, buildCmds, parseCmd, initCliCmds } \ No newline at end of file +export { buildCmds, initCliCmds, parseCmd, runCmd, chat }; +; \ No newline at end of file diff --git a/packages/cli/bin/cmd/lib/execute_task.ts b/packages/cli/bin/cmd/lib/execute_task.ts index ea1b727..27da485 100644 --- a/packages/cli/bin/cmd/lib/execute_task.ts +++ b/packages/cli/bin/cmd/lib/execute_task.ts @@ -1,12 +1,12 @@ import { brain, initAgent, taskBuilder } from "../../agent.js"; import { getFeatureSpec } from "../../state/features.js"; import { FeatureType } from "../../interfaces.js"; -import { inputMode, isDebug, runMode } from "../../state/state.js"; +import { inputMode, isChatMode, isDebug } from "../../state/state.js"; import { initTaskVars, readPromptFile, readTask } from "./utils.js"; import { readClipboard } from "../sys/clipboard.js"; async function executeTaskCmd(args: Array = [], options: any = {}): Promise { - await initAgent(runMode.value); + await initAgent(); if (isDebug.value) { console.log("Task args:", args); console.log("Task options:", options); @@ -28,7 +28,7 @@ async function executeTaskCmd(args: Array = [], options: any = {}): Prom } const { found, path } = getFeatureSpec(name, "task" as FeatureType); if (!found) { - return { ok: false, data: {}, error: `Task ${name} not found` }; + return { ok: false, data: "", conf: {}, error: `Task ${name} not found` }; } //console.log("EFM", brain.expertsForModels); const res = readTask(path); @@ -69,9 +69,17 @@ async function executeTaskCmd(args: Array = [], options: any = {}): Prom } const data = await task.run({ prompt: pr, ...vars }, conf) as Record; if (data?.error) { - return { ok: false, data: {}, error: `Error executing task: ${data.error}` } + return { ok: false, data: "", conf: conf, error: `Error executing task: ${data.error}` } } - return { ok: true, data: data.text, error: "" } + conf.prompt = pr; + // chat mode + if (isChatMode.value) { + if (brain.ex.name != ex.name) { + brain.setDefaultExpert(ex); + } + brain.ex.template.pushToHistory({ user: pr, assistant: data.text }); + } + return { ok: true, data: data.text, conf: conf, error: "" } } export { executeTaskCmd } \ No newline at end of file diff --git a/packages/cli/bin/cmd/lib/utils.ts b/packages/cli/bin/cmd/lib/utils.ts index 97c6721..460748e 100644 --- a/packages/cli/bin/cmd/lib/utils.ts +++ b/packages/cli/bin/cmd/lib/utils.ts @@ -6,9 +6,13 @@ import { readClipboard, writeToClipboard } from "../sys/clipboard.js"; import { modes } from "../clicmds/modes.js"; async function setOptions( - options: Record, args: Array = [] + args: Array = [], options: Record, ): Promise> { - if (runMode.value == "cli") { return args }; + //console.log("Args:", args); + //console.log("Opts", options); + /*if (runMode.value == "cli") { + return args + };*/ //console.log("OPTIONS", options); for (const k of Object.keys(options)) { const opt = modes["-" + k.toLowerCase()]; diff --git a/packages/cli/bin/index.ts b/packages/cli/bin/index.ts index 17d6fa4..528d869 100644 --- a/packages/cli/bin/index.ts +++ b/packages/cli/bin/index.ts @@ -3,17 +3,17 @@ import { argv } from 'process'; import { query } from "./cli.js"; import { initState, runMode } from './state/state.js'; import { initAgent } from './agent.js'; -import { initCliCmds, parseCmd } from './cmd/cmds.js'; +import { buildCmds, initCliCmds, parseCmd } from './cmd/cmds.js'; async function main() { if (argv.length == 2) { runMode.value = "cli"; } await initState(); - await initCliCmds(); - await initAgent(runMode.value); + await initAgent(); switch (runMode.value) { case "cli": + await initCliCmds(); await query() break; default: diff --git a/packages/cli/bin/main.ts b/packages/cli/bin/main.ts index 12f1a5e..faea156 100644 --- a/packages/cli/bin/main.ts +++ b/packages/cli/bin/main.ts @@ -2,6 +2,7 @@ import { execute, run } from "./cmd/sys/execute.js"; import { executeJobCmd } from "./cmd/lib/execute_job.js"; import { writeToClipboard } from "./cmd/sys/clipboard.js"; import { pingCmd } from "./cmd/clicmds/cmds.js"; +import { initAgent } from "./agent.js"; export { execute, @@ -9,4 +10,5 @@ export { pingCmd, executeJobCmd, writeToClipboard, + initAgent, } \ No newline at end of file diff --git a/packages/cli/bin/state/state.ts b/packages/cli/bin/state/state.ts index 945b5fb..3d62c47 100644 --- a/packages/cli/bin/state/state.ts +++ b/packages/cli/bin/state/state.ts @@ -14,6 +14,7 @@ const inputMode = ref("manual"); const outputMode = ref("txt"); const runMode = ref("cmd"); const formatMode = ref("text"); +const isChatMode = ref(false); const isDebug = ref(false); const promptfile = ref(""); @@ -50,6 +51,7 @@ async function initState() { export { inputMode, outputMode, + isChatMode, runMode, formatMode, lastCmd, diff --git a/packages/cli/package.json b/packages/cli/package.json index 02cd6c5..e2c1faa 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -2,7 +2,7 @@ "name": "@agent-smith/cli", "description": "Agent Smith: terminal client for language model agents", "repository": "https://github.com/synw/agent-smith", - "version": "0.0.18", + "version": "0.0.20", "scripts": { "buildrl": "rm -rf dist/* && rollup -c", "build": "rm -rf dist/* && tsc", @@ -10,18 +10,18 @@ "watch": "tsc -p . -w" }, "dependencies": { - "@agent-smith/brain": "^0.0.32", + "@agent-smith/brain": "^0.0.33", "@agent-smith/jobs": "^0.0.11", - "@agent-smith/lmtask": "^0.0.23", - "@inquirer/prompts": "^7.0.0", - "@inquirer/select": "^4.0.0", + "@agent-smith/lmtask": "^0.0.24", + "@inquirer/prompts": "^7.0.1", + "@inquirer/select": "^4.0.1", "@vue/reactivity": "^3.5.12", "better-sqlite3": "^11.5.0", "clipboardy": "^4.0.0", "commander": "^12.1.0", "draftlog": "^1.0.13", - "marked-terminal": "^7.1.0", - "modprompt": "^0.9.0", + "marked-terminal": "^7.2.1", + "modprompt": "^0.9.1", "python-shell": "^5.0.0", "yaml": "^2.6.0" }, @@ -33,9 +33,9 @@ "@rollup/plugin-typescript": "^12.1.1", "@types/better-sqlite3": "^7.6.11", "@types/marked-terminal": "^6.1.1", - "@types/node": "^22.7.9", + "@types/node": "^22.8.5", "restmix": "^0.5.0", - "rollup": "^4.24.0", + "rollup": "^4.24.3", "ts-node": "^10.9.2", "tslib": "2.8.0", "typescript": "^5.6.3"