@agent-smith/cli 0.0.102 → 0.0.103

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.
@@ -2,9 +2,32 @@ import { allOptions } from "../options.js";
2
2
  import { executeTaskCmd } from "../lib/tasks/cmd.js";
3
3
  import { executeActionCmd } from "../lib/actions/cmd.js";
4
4
  import { executeWorkflowCmd } from "../lib/workflows/cmd.js";
5
+ import { executeAgentCmd } from "../lib/agents/cmd.js";
5
6
  function initCommandsFromAliases(program, aliases, features) {
6
7
  aliases.forEach((alias) => {
7
8
  switch (alias.type) {
9
+ case "agent":
10
+ const agcmd = program.command(`${alias.name} [prompt_and_vars...]`)
11
+ .description("agent: " + alias.name)
12
+ .action(async (...args) => {
13
+ await executeAgentCmd(alias.name, args);
14
+ });
15
+ allOptions.forEach(o => agcmd.addOption(o));
16
+ if (features.agent[alias.name]?.variables) {
17
+ const rtv = features.agent[alias.name].variables?.required;
18
+ if (rtv) {
19
+ for (const name of Object.keys(rtv)) {
20
+ agcmd.option(`--${name} <value>`);
21
+ }
22
+ }
23
+ const otv = features.agent[alias.name].variables?.optional;
24
+ if (otv) {
25
+ for (const name of Object.keys(otv)) {
26
+ agcmd.option(`--${name} <value>`);
27
+ }
28
+ }
29
+ }
30
+ break;
8
31
  case "task":
9
32
  const tcmd = program.command(`${alias.name} [prompt_and_vars...]`)
10
33
  .description("task: " + alias.name)
@@ -0,0 +1,3 @@
1
+ import type { TaskOutput } from "@agent-smith/task";
2
+ declare function executeAgentCmd(name: string, targs?: Array<any>): Promise<TaskOutput>;
3
+ export { executeAgentCmd, };
@@ -0,0 +1,10 @@
1
+ import { parseCommandArgs } from "../options_parsers.js";
2
+ import { getTaskPrompt } from "../tasks/utils.js";
3
+ import { executeTask } from "../tasks/cmd.js";
4
+ async function executeAgentCmd(name, targs = []) {
5
+ const ca = parseCommandArgs(targs);
6
+ const prompt = await getTaskPrompt(name, ca.args, ca.options);
7
+ ca.options.isAgent = true;
8
+ return await executeTask(name, { prompt: prompt }, ca.options);
9
+ }
10
+ export { executeAgentCmd, };
@@ -10,7 +10,7 @@ import { initTaskSettings, isTaskSettingsInitialized, tasksSettings } from "../.
10
10
  import { chat, program } from "../../cmds.js";
11
11
  import { parseCommandArgs } from "../options_parsers.js";
12
12
  import { runtimeDataError, runtimeError, runtimeWarning } from "../user_msgs.js";
13
- import { formatStats, processOutput } from "../utils.js";
13
+ import { processOutput } from "../utils.js";
14
14
  import { readTask } from "./read.js";
15
15
  import { getTaskPrompt } from "./utils.js";
16
16
  async function executeTask(name, payload, options) {
@@ -86,17 +86,18 @@ async function executeTask(name, payload, options) {
86
86
  console.log("Task model:", model);
87
87
  console.log("Task vars:", vars);
88
88
  }
89
+ let emittedTokens = 0;
89
90
  const printToken = (t) => {
90
91
  if (options?.tokens === true) {
91
92
  let txt = t;
92
93
  txt = c ? t : `\x1b[100m${t}\x1b[0m`;
93
94
  process.stdout.write(txt);
94
- ++i;
95
95
  c = !c;
96
96
  }
97
97
  else {
98
98
  process.stdout.write(t);
99
99
  }
100
+ ++emittedTokens;
100
101
  };
101
102
  let hasTools = false;
102
103
  if (task.def?.tools) {
@@ -113,12 +114,11 @@ async function executeTask(name, payload, options) {
113
114
  return `${ts} ${color.bold(i.toString())} ${te}`;
114
115
  };
115
116
  const perfTimer = usePerfTimer(false);
116
- let i = 0;
117
117
  const processToken = (t) => {
118
- if (i == 0) {
118
+ if (emittedTokens == 0) {
119
119
  perfTimer.start();
120
120
  }
121
- spinner.text = formatTokenCount(i);
121
+ spinner.text = formatTokenCount(emittedTokens);
122
122
  if (!options?.verbose && !options?.debug) {
123
123
  if (hasThink && tpl) {
124
124
  if (t == tpl.tags.think?.start) {
@@ -129,7 +129,7 @@ async function executeTask(name, payload, options) {
129
129
  else if (t == tpl.tags.think?.end) {
130
130
  continueWrite = true;
131
131
  skipNextEmptyLinesToken = true;
132
- let msg = color.dim("Thinking:") + ` ${i} ${color.dim("tokens")}`;
132
+ let msg = color.dim("Thinking:") + ` ${emittedTokens} ${color.dim("tokens")}`;
133
133
  msg = msg + " " + color.dim(perfTimer.time());
134
134
  spinner.info(msg);
135
135
  return;
@@ -139,7 +139,7 @@ async function executeTask(name, payload, options) {
139
139
  else {
140
140
  if (tpl) {
141
141
  if (t == tpl.tags.think?.end) {
142
- let msg = color.dim("Thinking:") + ` ${i} ${color.dim("tokens")}`;
142
+ let msg = color.dim("Thinking:") + ` ${emittedTokens} ${color.dim("tokens")}`;
143
143
  msg = msg + " " + color.dim(perfTimer.time());
144
144
  console.log(msg);
145
145
  }
@@ -165,17 +165,15 @@ async function executeTask(name, payload, options) {
165
165
  }
166
166
  printToken(t);
167
167
  }
168
- ++i;
168
+ ++emittedTokens;
169
169
  };
170
- const spinnerInit = (name) => ora(`Executing ${name} tool ...\n`);
171
- let tcspinner;
172
170
  const onToolCall = (tc) => {
173
171
  console.log("⚒️ ", color.bold(name), "=>", `${color.yellowBright(tc.name)}`, tc.arguments);
174
- tcspinner = spinnerInit(tc.name);
175
- tcspinner.start();
176
172
  };
177
173
  const onToolCallEnd = (tr) => {
178
- tcspinner.stop();
174
+ if (options?.debug) {
175
+ console.log(tr);
176
+ }
179
177
  };
180
178
  if (options?.onToken) {
181
179
  task.agent.lm.onToken = options.onToken;
@@ -250,7 +248,7 @@ async function executeTask(name, payload, options) {
250
248
  }
251
249
  if (options?.debug === true || options?.verbose === true) {
252
250
  try {
253
- console.log("\n", formatStats(out.answer.stats));
251
+ console.log(emittedTokens.toString(), color.dim("tokens"), out.answer.stats.tokensPerSecond, color.dim("tps"));
254
252
  if (options?.debug === true) {
255
253
  console.log(out.answer.stats);
256
254
  }
@@ -16,7 +16,7 @@ async function readTask(name, payload, options, agent) {
16
16
  console.log("Payload:", payload);
17
17
  console.log("Task options:", options);
18
18
  }
19
- const { taskFileSpec, taskPath } = openTaskSpec(name);
19
+ const { taskFileSpec, taskPath } = openTaskSpec(name, options?.isAgent);
20
20
  const taskDir = path.dirname(taskPath);
21
21
  const opts = payload?.inferParams ? { ...options, ...payload.inferParams } : options;
22
22
  const conf = parseTaskConfigOptions(opts);
@@ -98,9 +98,19 @@ async function readTask(name, payload, options, agent) {
98
98
  return res;
99
99
  case "task":
100
100
  options.isToolCall = true;
101
+ options.isAgent = false;
101
102
  const tres = await executeTask(toolName, params, options);
102
103
  options.isToolCall = false;
103
104
  return tres.answer.text;
105
+ case "agent":
106
+ options.isToolCall = true;
107
+ options.isAgent = true;
108
+ const agres = await executeTask(toolName, params, options);
109
+ options.isToolCall = false;
110
+ if (agres?.answer?.text) {
111
+ return agres.answer.text;
112
+ }
113
+ return agres;
104
114
  case "workflow":
105
115
  const wres = await executeWorkflow(toolName, params, options);
106
116
  return wres;
@@ -1,5 +1,5 @@
1
1
  import { LmTaskFileSpec } from "../../../interfaces.js";
2
- declare function openTaskSpec(name: string): {
2
+ declare function openTaskSpec(name: string, isAgent?: boolean): {
3
3
  taskFileSpec: LmTaskFileSpec;
4
4
  taskPath: string;
5
5
  };
@@ -4,14 +4,15 @@ import { readTask } from "../../../cmd/sys/read_task.js";
4
4
  import { getFeatureSpec } from "../../../state/features.js";
5
5
  import { runtimeDataError } from '../user_msgs.js';
6
6
  import { readPromptFile } from '../utils.js';
7
- function openTaskSpec(name) {
8
- const { found, path } = getFeatureSpec(name, "task");
7
+ function openTaskSpec(name, isAgent = false) {
8
+ const ft = isAgent ? "agent" : "task";
9
+ const { found, path } = getFeatureSpec(name, ft);
9
10
  if (!found) {
10
- throw new Error(`Task ${name} not found`);
11
+ throw new Error(`${ft} ${name} not found`);
11
12
  }
12
13
  const res = readTask(path);
13
14
  if (!res.found) {
14
- throw new Error(`Task ${name}, ${path} not found`);
15
+ throw new Error(`${ft} ${name}, ${path} not found`);
15
16
  }
16
17
  const taskFileSpec = YAML.parse(res.ymlTask);
17
18
  taskFileSpec.name = name;
@@ -1,5 +1,3 @@
1
- import { InferenceStats } from "@locallm/types";
2
1
  declare function readPromptFile(): string;
3
2
  declare function processOutput(res: any): Promise<void>;
4
- declare function formatStats(stats: InferenceStats): string;
5
- export { formatStats, processOutput, readPromptFile, };
3
+ export { processOutput, readPromptFile, };
@@ -46,12 +46,4 @@ async function processOutput(res) {
46
46
  }
47
47
  }
48
48
  }
49
- function formatStats(stats) {
50
- const buf = new Array();
51
- buf.push(`${stats.tokensPerSecond} tps`);
52
- buf.push(`- ${stats.totalTimeSeconds}s`);
53
- buf.push(`(${stats.ingestionTimeSeconds}s ingestion /`);
54
- buf.push(`${stats.inferenceTimeSeconds}s inference)`);
55
- return buf.join(" ");
56
- }
57
- export { formatStats, processOutput, readPromptFile, };
49
+ export { processOutput, readPromptFile, };
@@ -27,26 +27,22 @@ async function executeWorkflow(wname, args, options = {}) {
27
27
  switch (step.type) {
28
28
  case "task":
29
29
  try {
30
- let pr = null;
30
+ let tdata = {};
31
31
  if (i == 0) {
32
- pr = await getTaskPrompt(step.name, taskRes.cmdArgs, options);
32
+ tdata.prompt = await getTaskPrompt(step.name, taskRes.cmdArgs, options);
33
33
  }
34
34
  else {
35
35
  if (prevStepType) {
36
36
  if (prevStepType == "task") {
37
- pr = taskRes.answer.text;
38
- }
39
- }
40
- if (!pr) {
41
- if (taskRes?.prompt) {
42
- pr = taskRes.prompt;
37
+ tdata.prompt = taskRes.answer.text;
43
38
  }
44
39
  }
40
+ tdata = taskRes;
45
41
  }
46
- if (!pr) {
42
+ if (!tdata?.prompt) {
47
43
  throw new Error(`Workflow ${wname} step ${i + 1}: provide a prompt for the task ${step.name}`);
48
44
  }
49
- const tr = await executeTask(step.name, { prompt: pr }, options);
45
+ const tr = await executeTask(step.name, tdata, options);
50
46
  taskRes = { ...tr, ...taskRes };
51
47
  }
52
48
  catch (e) {
@@ -6,10 +6,8 @@ function _readDir(dir, ext) {
6
6
  const filepath = path.join(dir, filename);
7
7
  const isDir = fs.statSync(filepath).isDirectory();
8
8
  if (!isDir) {
9
- for (let extension of ext) {
10
- if (filename.endsWith(extension)) {
11
- fileNames.push(filename);
12
- }
9
+ if (ext.includes(path.extname(filename))) {
10
+ fileNames.push(filename);
13
11
  }
14
12
  }
15
13
  });
@@ -22,6 +20,7 @@ function readFeaturesDir(dir) {
22
20
  cmd: [],
23
21
  workflow: [],
24
22
  adaptater: [],
23
+ agent: [],
25
24
  };
26
25
  let dirpath = path.join(dir, "tasks");
27
26
  if (fs.existsSync(dirpath)) {
@@ -37,6 +36,20 @@ function readFeaturesDir(dir) {
37
36
  });
38
37
  });
39
38
  }
39
+ dirpath = path.join(dir, "agents");
40
+ if (fs.existsSync(dirpath)) {
41
+ const data = _readDir(dirpath, [".yml"]);
42
+ data.forEach((filename) => {
43
+ const parts = filename.split(".");
44
+ const ext = parts.pop();
45
+ const name = parts.join("");
46
+ feats.agent.push({
47
+ name: name,
48
+ path: path.join(dirpath),
49
+ ext: ext,
50
+ });
51
+ });
52
+ }
40
53
  dirpath = path.join(dir, "workflows");
41
54
  if (fs.existsSync(dirpath)) {
42
55
  const data = _readDir(dirpath, [".yml"]);
package/dist/db/read.js CHANGED
@@ -43,8 +43,9 @@ function readFeaturesType(type) {
43
43
  }
44
44
  function readFeatures() {
45
45
  const feats = {
46
- task: {}, action: {}, cmd: {}, workflow: {}, adaptater: {}
46
+ task: {}, action: {}, cmd: {}, workflow: {}, adaptater: {}, agent: {}
47
47
  };
48
+ feats.agent = readFeaturesType("agent");
48
49
  feats.task = readFeaturesType("task");
49
50
  feats.action = readFeaturesType("action");
50
51
  feats.cmd = readFeaturesType("cmd");
@@ -19,6 +19,13 @@ const tasks = `CREATE TABLE IF NOT EXISTS task (
19
19
  variables TEXT,
20
20
  ext TEXT NOT NULL CHECK ( ext IN ('yml') )
21
21
  );`;
22
+ const agents = `CREATE TABLE IF NOT EXISTS agent (
23
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
24
+ name TEXT UNIQUE NOT NULL,
25
+ path TEXT NOT NULL,
26
+ variables TEXT,
27
+ ext TEXT NOT NULL CHECK ( ext IN ('yml') )
28
+ );`;
22
29
  const workflow = `CREATE TABLE IF NOT EXISTS workflow (
23
30
  id INTEGER PRIMARY KEY AUTOINCREMENT,
24
31
  name TEXT UNIQUE NOT NULL,
@@ -51,12 +58,12 @@ const tool = `CREATE TABLE IF NOT EXISTS tool (
51
58
  id INTEGER PRIMARY KEY AUTOINCREMENT,
52
59
  name TEXT UNIQUE NOT NULL,
53
60
  spec TEXT NOT NULL,
54
- type TEXT NOT NULL CHECK ( type IN ('task', 'action', 'workflow') )
61
+ type TEXT NOT NULL CHECK ( type IN ('agent', 'task', 'action', 'workflow') )
55
62
  );`;
56
63
  const alias = `CREATE TABLE IF NOT EXISTS aliases (
57
64
  id INTEGER PRIMARY KEY AUTOINCREMENT,
58
65
  name TEXT UNIQUE NOT NULL,
59
- type TEXT NOT NULL CHECK ( type IN ('task', 'action', 'workflow') )
66
+ type TEXT NOT NULL CHECK ( type IN ('agent', 'task', 'action', 'workflow') )
60
67
  );`;
61
68
  const backend = `CREATE TABLE IF NOT EXISTS backend (
62
69
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -93,5 +100,6 @@ const schemas = [
93
100
  adaptater,
94
101
  backend,
95
102
  tasksSettings,
103
+ agents,
96
104
  ];
97
105
  export { schemas };
package/dist/db/write.js CHANGED
@@ -96,6 +96,9 @@ function updateAliases(feats) {
96
96
  const deleteStmt = db.prepare("DELETE FROM aliases");
97
97
  deleteStmt.run();
98
98
  let existingAliases = new Array();
99
+ feats.agent.forEach((feat) => {
100
+ existingAliases = _updateAlias(existingAliases, feat.name, "agent");
101
+ });
99
102
  feats.task.forEach((feat) => {
100
103
  existingAliases = _updateAlias(existingAliases, feat.name, "task");
101
104
  });
@@ -158,6 +161,16 @@ function upsertTool(name, type, toolDoc) {
158
161
  }
159
162
  }
160
163
  function updateFeatures(feats) {
164
+ upsertAndCleanFeatures(feats.agent, "agent");
165
+ feats.agent.forEach((feat) => {
166
+ const { toolDoc, variables } = extractTaskToolDocAndVariables(feat.name, feat.ext, feat.path);
167
+ if (toolDoc.length > 0) {
168
+ upsertTool(feat.name, "agent", toolDoc);
169
+ }
170
+ if (Object.keys(variables.required).length > 0 || Object.keys(variables.optional).length > 0) {
171
+ updateVariables(feat.name, JSON.stringify(variables, null, " "));
172
+ }
173
+ });
161
174
  upsertAndCleanFeatures(feats.task, "task");
162
175
  feats.task.forEach((feat) => {
163
176
  const { toolDoc, variables } = extractTaskToolDocAndVariables(feat.name, feat.ext, feat.path);
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { query } from "./cli.js";
4
4
  import { buildCmds, parseCmd } from './cmd/cmds.js';
5
5
  import { formatMode, init, inputMode, isChatMode, outputMode, runMode } from './state/state.js';
6
6
  import { updateConfCmd } from './cmd/clicmds/updateconf.js';
7
+ import { resetDbCmd } from './cmd/clicmds/cmds.js';
7
8
  async function main() {
8
9
  const nargs = argv.length;
9
10
  if (nargs == 2) {
@@ -14,6 +15,10 @@ async function main() {
14
15
  await updateConfCmd(argv.slice(-1));
15
16
  return;
16
17
  }
18
+ else if (argv[2] == "reset") {
19
+ await resetDbCmd();
20
+ return;
21
+ }
17
22
  }
18
23
  await init();
19
24
  const program = await buildCmds();
@@ -8,6 +8,11 @@ interface FeatureSpec {
8
8
  variables?: TaskVariables;
9
9
  }
10
10
  interface Features {
11
+ agent: Array<{
12
+ name: string;
13
+ path: string;
14
+ ext: AgentExtension;
15
+ }>;
11
16
  task: Array<{
12
17
  name: string;
13
18
  path: string;
@@ -136,14 +141,15 @@ type OutputMode = "txt" | "clipboard";
136
141
  type RunMode = "cli" | "cmd";
137
142
  type FormatMode = "text" | "markdown";
138
143
  type VerbosityMode = "quiet" | "verbose" | "debug";
139
- type FeatureType = "task" | "action" | "cmd" | "workflow" | "adaptater";
140
- type ToolType = "task" | "action" | "cmd" | "workflow";
144
+ type FeatureType = "task" | "agent" | "action" | "cmd" | "workflow" | "adaptater";
145
+ type ToolType = "task" | "agent" | "action" | "cmd" | "workflow";
141
146
  type ActionExtension = "js" | "mjs" | "py" | "yml";
142
147
  type TaskExtension = "yml";
148
+ type AgentExtension = "yml";
143
149
  type AdaptaterExtension = "js";
144
150
  type WorkflowExtension = "yml";
145
151
  type CmdExtension = "js";
146
- type FeatureExtension = TaskExtension | CmdExtension | ActionExtension | WorkflowExtension;
147
- type AliasType = "task" | "action" | "workflow";
152
+ type FeatureExtension = TaskExtension | AgentExtension | CmdExtension | ActionExtension | WorkflowExtension;
153
+ type AliasType = "task" | "agent" | "action" | "workflow";
148
154
  type FeatureExecutor<I = any, O = any> = (params: I, options: Record<string, any>) => Promise<O>;
149
- export { InputMode, VerbosityMode, OutputMode, RunMode, FormatMode, FeatureType, ActionExtension, TaskExtension, WorkflowExtension, AdaptaterExtension, CmdExtension, FeatureSpec, Features, ConfigFile, FeatureExtension, AliasType, ToolType, Settings, DbModelDef, ModelSpec, ModelfileSpec, ModelPack, LmTaskFileSpec, LmTaskConfig, FinalLmTaskConfig, McpServerSpec, McpServerTool, InferenceBackend, ConfInferenceBackend, FeatureExecutor, WorkflowStep, TaskSettings, };
155
+ export { InputMode, VerbosityMode, OutputMode, RunMode, FormatMode, FeatureType, ActionExtension, TaskExtension, AgentExtension, WorkflowExtension, AdaptaterExtension, CmdExtension, FeatureSpec, Features, ConfigFile, FeatureExtension, AliasType, ToolType, Settings, DbModelDef, ModelSpec, ModelfileSpec, ModelPack, LmTaskFileSpec, LmTaskConfig, FinalLmTaskConfig, McpServerSpec, McpServerTool, InferenceBackend, ConfInferenceBackend, FeatureExecutor, WorkflowStep, TaskSettings, };
@@ -1,2 +1,9 @@
1
- const cmds = new Array();
2
- export { cmds };
1
+ import { cmd as c1 } from "file:///home/ggg/dev/js/agent-smith-plugins/system/fs/dist/cmds/lsdir.js";
2
+ import { cmd as c2 } from "file:///home/ggg/dev/js/agent-smith-plugins/code/git/dist/cmds/commit.js";
3
+ import { cmd as c3 } from "file:///home/ggg/dev/js/agent-smith-plugins/code/git/dist/cmds/commita.js";
4
+ import { cmd as c4 } from "file:///home/ggg/dev/js/snowind-astro/features/cmds/design-component.js";
5
+ import { cmd as c5 } from "file:///home/ggg/dev/js/docdundee/package/features/dist/cmds/tsdoccmd.js";
6
+
7
+ const cmds = [ c1, c2, c3, c4, c5 ]
8
+
9
+ export { cmds }
@@ -8,9 +8,11 @@ function readFeaturesDirs(featuresPaths) {
8
8
  cmd: [],
9
9
  workflow: [],
10
10
  adaptater: [],
11
+ agent: [],
11
12
  };
12
13
  featuresPaths.forEach((dir) => {
13
14
  const _f = readFeaturesDir(dir);
15
+ _f.agent.forEach((item) => feats.agent.push(item));
14
16
  _f.task.forEach((item) => feats.task.push(item));
15
17
  _f.action.forEach((item) => feats.action.push(item));
16
18
  _f.cmd.forEach((item) => feats.cmd.push(item));
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@agent-smith/cli",
3
3
  "description": "Agent Smith: terminal client for language model agents",
4
4
  "repository": "https://github.com/synw/agent-smith",
5
- "version": "0.0.102",
5
+ "version": "0.0.103",
6
6
  "scripts": {
7
7
  "buildrl": "rm -rf dist/* && rollup -c",
8
8
  "build": "rm -rf dist/* && tsc",
@@ -17,7 +17,7 @@
17
17
  "@inquirer/prompts": "^8.1.0",
18
18
  "@intrinsicai/gbnfgen": "0.12.0",
19
19
  "@locallm/api": "^0.7.3",
20
- "@modelcontextprotocol/sdk": "^1.25.1",
20
+ "@modelcontextprotocol/sdk": "^1.25.2",
21
21
  "@vue/reactivity": "^3.5.26",
22
22
  "ansi-colors": "^4.1.3",
23
23
  "better-sqlite3": "^12.5.0",
@@ -40,7 +40,7 @@
40
40
  "@types/node": "^25.0.3",
41
41
  "openai": "^6.15.0",
42
42
  "restmix": "^0.6.1",
43
- "rollup": "^4.54.0",
43
+ "rollup": "^4.55.1",
44
44
  "ts-node": "^10.9.2",
45
45
  "tslib": "2.8.1",
46
46
  "typescript": "^5.9.3"