Skip to content

Commit

Permalink
Cli: add a chat mode
Browse files Browse the repository at this point in the history
- Added support for chat mode in CLI, allowing users to interact with language models through a conversational interface
- Modified `initAgent` function to handle chat mode initialization
- Introduced new `isChatMode` state variable to track whether the user is in chat mode
- Updated `runCmd` and `parseCmd` functions to handle chat mode commands
- Added `chat` function to handle chat mode interactions with language models
- Modified `executeTaskCmd` function to handle chat mode task execution
  • Loading branch information
synw committed Nov 1, 2024
1 parent c073644 commit 97fdced
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 69 deletions.
23 changes: 14 additions & 9 deletions packages/cli/bin/agent.ts
Original file line number Diff line number Diff line change
@@ -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<string, string> = {};

const taskBuilder = new LmTaskBuilder<FeatureType>(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<boolean> {
async function initAgent(isVerbose = false): Promise<boolean> {
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));
Expand All @@ -32,15 +32,20 @@ async function initAgent(mode: RunMode, isVerbose = false): Promise<boolean> {
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 };
56 changes: 35 additions & 21 deletions packages/cli/bin/cli.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -32,28 +33,41 @@ function parseParams(params: string): Array<string> {
}

async function dispatch(input: string) {
let buf = new Array<string>();
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<string>();
let params = parseParams(input);
const cmd = params.shift()!;
const opts: Record<string, any> = {};
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 }
18 changes: 9 additions & 9 deletions packages/cli/bin/cmd/clicmds/cmds.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -98,11 +98,8 @@ async function initCmds(): Promise<Record<string, Cmd>> {
}

async function pingCmd(args: Array<string> = [], options: any): Promise<boolean> {
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
}

Expand Down Expand Up @@ -137,7 +134,7 @@ async function _executeTaskCmd(args: Array<string> = [], 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)
}
Expand All @@ -147,8 +144,11 @@ async function _executeTaskCmd(args: Array<string> = [], options: any): Promise<
} else {
console.log()
}
if (isChatMode.value) {

}
//console.log("ENDRES", data);
return data
//console.log("ENDRES", t);
}

async function _executeJobCmd(args: Array<string> = [], options: any): Promise<any> {
Expand Down
10 changes: 9 additions & 1 deletion packages/cli/bin/cmd/clicmds/modes.ts
Original file line number Diff line number Diff line change
@@ -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<string, Cmd> = {
"-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";
Expand Down
44 changes: 34 additions & 10 deletions packages/cli/bin/cmd/cmds.ts
Original file line number Diff line number Diff line change
@@ -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<string, Cmd> = {};

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<string> = []) {
Expand All @@ -20,20 +42,18 @@ async function runCmd(cmdName: string, args: Array<string> = []) {
//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<Command> {
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<string> = [], options: any = {}): Promise<any> => {
//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);
Expand Down Expand Up @@ -63,6 +83,10 @@ async function buildCmds(): Promise<Command> {
async function parseCmd() {
const program = await buildCmds();
await program.parseAsync();
if (isChatMode.value) {
await chat()
}
}

export { runCmd, buildCmds, parseCmd, initCliCmds }
export { buildCmds, initCliCmds, parseCmd, runCmd, chat };
;
18 changes: 13 additions & 5 deletions packages/cli/bin/cmd/lib/execute_task.ts
Original file line number Diff line number Diff line change
@@ -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<string> = [], options: any = {}): Promise<any> {
await initAgent(runMode.value);
await initAgent();
if (isDebug.value) {
console.log("Task args:", args);
console.log("Task options:", options);
Expand All @@ -28,7 +28,7 @@ async function executeTaskCmd(args: Array<string> = [], 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);
Expand Down Expand Up @@ -69,9 +69,17 @@ async function executeTaskCmd(args: Array<string> = [], options: any = {}): Prom
}
const data = await task.run({ prompt: pr, ...vars }, conf) as Record<string, any>;
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 }
8 changes: 6 additions & 2 deletions packages/cli/bin/cmd/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import { readClipboard, writeToClipboard } from "../sys/clipboard.js";
import { modes } from "../clicmds/modes.js";

async function setOptions(
options: Record<string, any>, args: Array<string> = []
args: Array<string> = [], options: Record<string, any>,
): Promise<Array<string>> {
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()];
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/bin/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ 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,
run,
pingCmd,
executeJobCmd,
writeToClipboard,
initAgent,
}
2 changes: 2 additions & 0 deletions packages/cli/bin/state/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const inputMode = ref<InputMode>("manual");
const outputMode = ref<OutputMode>("txt");
const runMode = ref<RunMode>("cmd");
const formatMode = ref<FormatMode>("text");
const isChatMode = ref(false);
const isDebug = ref(false);
const promptfile = ref("");

Expand Down Expand Up @@ -50,6 +51,7 @@ async function initState() {
export {
inputMode,
outputMode,
isChatMode,
runMode,
formatMode,
lastCmd,
Expand Down
Loading

0 comments on commit 97fdced

Please sign in to comment.