@lazyingart/agintiflow 0.8.5 → 0.8.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a resumable Playwright website-control agent with OpenAI-compatible tool calling.",
6
6
  "license": "Apache-2.0",
@@ -329,6 +329,16 @@ function createObservers(config) {
329
329
  };
330
330
  }
331
331
 
332
+ function emitConsole(config, value = "", options = {}) {
333
+ if (typeof config.onConsole === "function") {
334
+ config.onConsole(String(value), options);
335
+ return;
336
+ }
337
+
338
+ if (options.error) console.error(value);
339
+ else console.log(value);
340
+ }
341
+
332
342
  function createBrowserState() {
333
343
  return {
334
344
  browser: null,
@@ -1033,25 +1043,27 @@ export async function runAgent(config) {
1033
1043
  startUrl: config.startUrl,
1034
1044
  });
1035
1045
 
1036
- console.log(`Session: ${sessionId}`);
1037
- console.log(`Provider: ${config.provider}`);
1038
- console.log(`Model: ${config.model}`);
1039
- console.log(`Routing: ${config.routingMode} (${config.routeReason})`);
1040
- console.log(`Workspace: ${config.commandCwd}`);
1041
- console.log(`Sessions: ${config.sessionsDir}`);
1046
+ emitConsole(config, `Session: ${sessionId}`, { kind: "meta" });
1047
+ emitConsole(config, `Provider: ${config.provider}`, { kind: "meta" });
1048
+ emitConsole(config, `Model: ${config.model}`, { kind: "meta" });
1049
+ emitConsole(config, `Routing: ${config.routingMode} (${config.routeReason})`, { kind: "meta" });
1050
+ emitConsole(config, `Workspace: ${config.commandCwd}`, { kind: "meta" });
1051
+ emitConsole(config, `Sessions: ${config.sessionsDir}`, { kind: "meta" });
1042
1052
  if (config.useDockerSandbox) {
1043
- console.log(
1044
- `Docker: image=${config.dockerSandboxImage} mode=${config.sandboxMode} packagePolicy=${config.packageInstallPolicy}`
1053
+ emitConsole(
1054
+ config,
1055
+ `Docker: image=${config.dockerSandboxImage} mode=${config.sandboxMode} packagePolicy=${config.packageInstallPolicy}`,
1056
+ { kind: "meta" }
1045
1057
  );
1046
- console.log(`Docker workspace: /workspace -> ${config.commandCwd}`);
1047
- console.log("Docker env: /aginti-env persistent toolchain; /aginti-cache persistent caches");
1058
+ emitConsole(config, `Docker workspace: /workspace -> ${config.commandCwd}`, { kind: "meta" });
1059
+ emitConsole(config, "Docker env: /aginti-env persistent toolchain; /aginti-cache persistent caches", { kind: "meta" });
1048
1060
  } else if (config.allowShellTool) {
1049
- console.log(`Shell: host policy=${config.packageInstallPolicy}`);
1061
+ emitConsole(config, `Shell: host policy=${config.packageInstallPolicy}`, { kind: "meta" });
1050
1062
  }
1051
1063
  if (state.plan) {
1052
- console.log("\nPlan:");
1053
- console.log(state.plan);
1054
- console.log("");
1064
+ emitConsole(config, "\nPlan:", { kind: "heading" });
1065
+ emitConsole(config, state.plan, { kind: "plan", markdown: true });
1066
+ emitConsole(config, "", { kind: "meta" });
1055
1067
  }
1056
1068
 
1057
1069
  for (let step = state.stepsCompleted + 1; step <= config.maxSteps; step += 1) {
@@ -1139,7 +1151,7 @@ export async function runAgent(config) {
1139
1151
  result: fallback,
1140
1152
  sessionId,
1141
1153
  });
1142
- console.log(fallback);
1154
+ emitConsole(config, fallback, { kind: "assistant", markdown: true });
1143
1155
  state.stepsCompleted = step;
1144
1156
  state.updatedAt = new Date().toISOString();
1145
1157
  await store.saveState(state);
@@ -1209,7 +1221,7 @@ export async function runAgent(config) {
1209
1221
  result: toolResult.result,
1210
1222
  sessionId,
1211
1223
  });
1212
- console.log(toolResult.result);
1224
+ emitConsole(config, toolResult.result, { kind: "assistant", markdown: true });
1213
1225
  return {
1214
1226
  sessionId,
1215
1227
  result: toolResult.result,
@@ -1232,7 +1244,7 @@ export async function runAgent(config) {
1232
1244
  reason: "max_steps_reached",
1233
1245
  sessionId,
1234
1246
  });
1235
- console.error(`Stopped after ${config.maxSteps} steps without finish().`);
1247
+ emitConsole(config, `Stopped after ${config.maxSteps} steps without finish().`, { kind: "error", error: true });
1236
1248
  return {
1237
1249
  sessionId,
1238
1250
  result: "",
@@ -7,8 +7,96 @@ import { initProject, listProjectSessions } from "./project.js";
7
7
  import { normalizePackageInstallPolicy, normalizeSandboxMode } from "./command-policy.js";
8
8
  import { normalizeTaskProfile } from "./task-profiles.js";
9
9
 
10
+ const useColor = Boolean(input.isTTY && output.isTTY && !process.env.NO_COLOR);
11
+ const ansi = {
12
+ reset: "\x1b[0m",
13
+ bold: "\x1b[1m",
14
+ dim: "\x1b[2m",
15
+ cyan: "\x1b[36m",
16
+ green: "\x1b[32m",
17
+ yellow: "\x1b[33m",
18
+ red: "\x1b[31m",
19
+ userBg: "\x1b[48;5;24m\x1b[38;5;231m",
20
+ agentBg: "\x1b[48;5;29m\x1b[38;5;231m",
21
+ systemBg: "\x1b[48;5;236m\x1b[38;5;245m",
22
+ };
23
+
24
+ function color(value, ...codes) {
25
+ if (!useColor || codes.length === 0) return String(value);
26
+ return `${codes.join("")}${value}${ansi.reset}`;
27
+ }
28
+
29
+ function label(name, bgCode) {
30
+ return color(` ${name} `, bgCode, ansi.bold);
31
+ }
32
+
33
+ function userPrompt() {
34
+ return `\n${label("user>", ansi.userBg)} `;
35
+ }
36
+
37
+ function stripMarkdown(text) {
38
+ const lines = String(text || "").split(/\r?\n/);
39
+ let inFence = false;
40
+ const rendered = [];
41
+
42
+ for (const rawLine of lines) {
43
+ let line = rawLine;
44
+ if (/^\s*```/.test(line)) {
45
+ inFence = !inFence;
46
+ if (inFence) rendered.push(color("code", ansi.dim));
47
+ continue;
48
+ }
49
+
50
+ if (!inFence) {
51
+ if (/^\s*[-*_]{3,}\s*$/.test(line)) {
52
+ rendered.push("");
53
+ continue;
54
+ }
55
+ line = line.replace(/^\s{0,3}#{1,6}\s+/, "");
56
+ line = line.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)");
57
+ line = line.replace(/\*\*([^*]+)\*\*/g, (_, value) => color(value, ansi.bold));
58
+ line = line.replace(/__([^_]+)__/g, (_, value) => color(value, ansi.bold));
59
+ line = line.replace(/(^|[^\w])\*([^*\n]+)\*/g, "$1$2");
60
+ line = line.replace(/(^|[^\w])_([^_\n]+)_/g, "$1$2");
61
+ line = line.replace(/`([^`]+)`/g, (_, value) => color(value, ansi.yellow));
62
+ line = line.replace(/^(\s*)[-*+]\s+/, "$1- ");
63
+ line = line.replace(/^\s*>\s?/, " ");
64
+ }
65
+
66
+ rendered.push(line);
67
+ }
68
+
69
+ return rendered.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
70
+ }
71
+
72
+ function printWrapped(prefix, text) {
73
+ const rendered = stripMarkdown(text);
74
+ const lines = rendered.split("\n");
75
+ const gutter = " ".repeat(useColor ? 9 : prefix.length);
76
+ console.log(`${prefix}${lines[0] || ""}`);
77
+ for (const line of lines.slice(1)) {
78
+ console.log(`${gutter}${line}`);
79
+ }
80
+ }
81
+
82
+ function printAgentMessage(text) {
83
+ printWrapped(`${label("aginti>", ansi.agentBg)} `, text);
84
+ }
85
+
86
+ function printSystemLine(text) {
87
+ if (!String(text || "").trim()) {
88
+ console.log("");
89
+ return;
90
+ }
91
+ console.log(`${label("state", ansi.systemBg)} ${color(text, ansi.dim)}`);
92
+ }
93
+
94
+ function printHeading(text) {
95
+ console.log(color(stripMarkdown(text), ansi.bold, ansi.cyan));
96
+ }
97
+
10
98
  function printHelp() {
11
- console.log(
99
+ printAgentMessage(
12
100
  [
13
101
  "Commands:",
14
102
  " /help Show this help.",
@@ -34,18 +122,18 @@ function printHelp() {
34
122
  }
35
123
 
36
124
  function printStatus(state) {
37
- console.log(`project=${process.cwd()}`);
38
- console.log(`cwd=${state.commandCwd || process.cwd()}`);
39
- console.log(`session=${state.sessionId || "new"}`);
40
- console.log(`status=${state.status || "idle"}${state.activeGoal ? ` workingOn=${state.activeGoal}` : ""}`);
41
- if (state.lastEvent) console.log(`last=${state.lastEvent}`);
42
- console.log(`provider=${state.provider || "auto"} routing=${state.routingMode} model=${state.model || "auto"}`);
43
- console.log(`profile=${state.taskProfile} maxSteps=${state.maxSteps}`);
44
- console.log(
125
+ printSystemLine(`project=${process.cwd()}`);
126
+ printSystemLine(`cwd=${state.commandCwd || process.cwd()}`);
127
+ printSystemLine(`session=${state.sessionId || "new"}`);
128
+ printSystemLine(`status=${state.status || "idle"}${state.activeGoal ? ` workingOn=${state.activeGoal}` : ""}`);
129
+ if (state.lastEvent) printSystemLine(`last=${state.lastEvent}`);
130
+ printSystemLine(`provider=${state.provider || "auto"} routing=${state.routingMode} model=${state.model || "auto"}`);
131
+ printSystemLine(`profile=${state.taskProfile} maxSteps=${state.maxSteps}`);
132
+ printSystemLine(
45
133
  `shell=${state.allowShellTool} files=${state.allowFileTools} sandbox=${state.sandboxMode} installs=${state.packageInstallPolicy}`
46
134
  );
47
135
  if (state.sandboxMode !== "host") {
48
- console.log(`dockerWorkspace=/workspace -> ${state.commandCwd || process.cwd()}`);
136
+ printSystemLine(`dockerWorkspace=/workspace -> ${state.commandCwd || process.cwd()}`);
49
137
  }
50
138
  }
51
139
 
@@ -65,7 +153,7 @@ async function latestSession() {
65
153
 
66
154
  function printStatusEvent(state, label, details = "") {
67
155
  state.lastEvent = details ? `${label}: ${details}` : label;
68
- console.log(`status=${state.status || "running"} ${state.lastEvent}`);
156
+ printSystemLine(`status=${state.status || "running"} ${state.lastEvent}`);
69
157
  }
70
158
 
71
159
  function attachRunInterrupts(controller) {
@@ -80,7 +168,7 @@ function attachRunInterrupts(controller) {
80
168
  if (!isEscape && !isCtrlC) return;
81
169
  if (controller.signal.aborted) return;
82
170
  const reason = isEscape ? "escape" : "ctrl-c";
83
- console.log(`\nstatus=stopping reason=${reason}`);
171
+ printSystemLine(`status=stopping reason=${reason}`);
84
172
  controller.abort(new Error(`Interrupted by ${reason}.`));
85
173
  };
86
174
  input.on("keypress", handler);
@@ -96,19 +184,21 @@ async function printResumeHint(state) {
96
184
  const sessionId = state.sessionId || "";
97
185
  console.log("");
98
186
  if (sessionId) {
99
- console.log("Interrupted. Session saved.");
100
- console.log(`Resume: aginti resume ${sessionId}`);
101
- console.log(`One-shot: aginti resume ${sessionId} "continue"`);
187
+ printAgentMessage(["Interrupted. Session saved.", `Resume: aginti resume ${sessionId}`, `One-shot: aginti resume ${sessionId} "continue"`].join("\n"));
102
188
  } else {
103
- console.log("Interrupted. No active session yet.");
189
+ printAgentMessage("Interrupted. No active session yet.");
104
190
  const sessions = await listProjectSessions(process.cwd(), 5).catch(() => []);
105
191
  if (sessions.length > 0) {
106
- console.log("Recent sessions:");
107
- for (const session of sessions) console.log(` ${formatSessionLine(session)}`);
108
- console.log(`Resume latest: aginti resume ${sessions[0].sessionId}`);
109
- console.log("List all: aginti sessions list");
192
+ printAgentMessage(
193
+ [
194
+ "Recent sessions:",
195
+ ...sessions.map((session) => ` ${formatSessionLine(session)}`),
196
+ `Resume latest: aginti resume ${sessions[0].sessionId}`,
197
+ "List all: aginti sessions list",
198
+ ].join("\n")
199
+ );
110
200
  } else {
111
- console.log("Restart: aginti");
201
+ printAgentMessage("Restart: aginti");
112
202
  }
113
203
  }
114
204
  }
@@ -148,71 +238,75 @@ async function handleCommand(line, state, packageDir) {
148
238
  }
149
239
  if (command === "new") {
150
240
  state.sessionId = "";
151
- console.log("Next message will start a new session.");
241
+ printAgentMessage("Next message will start a new session.");
152
242
  return true;
153
243
  }
154
244
  if (command === "resume") {
155
245
  if (!value || value === "latest") {
156
246
  const latest = await latestSession();
157
247
  if (!latest) {
158
- console.log("No project-local sessions found. Use /new or type a request to start one.");
248
+ printAgentMessage("No project-local sessions found. Use /new or type a request to start one.");
159
249
  } else {
160
250
  state.sessionId = latest.sessionId;
161
- console.log(`Resuming latest ${formatSessionLine(latest)}`);
251
+ printAgentMessage(`Resuming latest ${formatSessionLine(latest)}`);
162
252
  }
163
253
  } else {
164
254
  state.sessionId = value;
165
- console.log(`Resuming ${state.sessionId}`);
255
+ printAgentMessage(`Resuming ${state.sessionId}`);
166
256
  }
167
257
  return true;
168
258
  }
169
259
  if (command === "sessions") {
170
260
  const sessions = await listProjectSessions(process.cwd(), 20);
171
- if (sessions.length === 0) console.log("No project-local sessions found.");
261
+ if (sessions.length === 0) printAgentMessage("No project-local sessions found.");
172
262
  else {
173
- for (const session of sessions) {
174
- const goal = session.goal ? ` ${session.goal.slice(0, 80)}` : "";
175
- console.log(`${session.sessionId} ${session.provider}/${session.model} ${session.updatedAt}${goal}`);
176
- }
263
+ printAgentMessage(
264
+ sessions
265
+ .map((session) => {
266
+ const goal = session.goal ? ` ${session.goal.slice(0, 80)}` : "";
267
+ return `${session.sessionId} ${session.provider}/${session.model} ${session.updatedAt}${goal}`;
268
+ })
269
+ .join("\n")
270
+ );
177
271
  }
178
272
  return true;
179
273
  }
180
274
  if (command === "profile") {
181
275
  state.taskProfile = normalizeTaskProfile(value || "auto");
182
- console.log(`profile=${state.taskProfile}`);
276
+ printSystemLine(`profile=${state.taskProfile}`);
183
277
  return true;
184
278
  }
185
279
  if (command === "routing") {
186
280
  state.routingMode = value || "smart";
187
- console.log(`routing=${state.routingMode}`);
281
+ printSystemLine(`routing=${state.routingMode}`);
188
282
  return true;
189
283
  }
190
284
  if (command === "provider") {
191
285
  state.provider = value === "auto" ? "" : value;
192
- console.log(`provider=${state.provider || "auto"}`);
286
+ printSystemLine(`provider=${state.provider || "auto"}`);
193
287
  return true;
194
288
  }
195
289
  if (command === "model") {
196
290
  state.model = value === "auto" ? "" : value;
197
- console.log(`model=${state.model || "auto"}`);
291
+ printSystemLine(`model=${state.model || "auto"}`);
198
292
  return true;
199
293
  }
200
294
  if (command === "installs") {
201
295
  state.packageInstallPolicy = normalizePackageInstallPolicy(value || "prompt");
202
- console.log(`installs=${state.packageInstallPolicy}`);
296
+ printSystemLine(`installs=${state.packageInstallPolicy}`);
203
297
  return true;
204
298
  }
205
299
  if (command === "docker") {
206
300
  if (value === "on") {
207
301
  state.sandboxMode = "docker-workspace";
208
302
  state.packageInstallPolicy = "allow";
209
- console.log(`docker=on /workspace -> ${state.commandCwd || process.cwd()} installs=allow`);
303
+ printSystemLine(`docker=on /workspace -> ${state.commandCwd || process.cwd()} installs=allow`);
210
304
  } else if (value === "off") {
211
305
  state.sandboxMode = "host";
212
306
  state.packageInstallPolicy = "prompt";
213
- console.log("docker=off sandbox=host installs=prompt");
307
+ printSystemLine("docker=off sandbox=host installs=prompt");
214
308
  } else {
215
- console.log("Usage: /docker on OR /docker off");
309
+ printAgentMessage("Usage: /docker on OR /docker off");
216
310
  }
217
311
  return true;
218
312
  }
@@ -222,32 +316,32 @@ async function handleCommand(line, state, packageDir) {
222
316
  state.sandboxMode = "docker-workspace";
223
317
  state.packageInstallPolicy = "allow";
224
318
  state.maxSteps = Math.max(state.maxSteps, 30);
225
- console.log("latex=on profile=latex sandbox=docker-workspace installs=allow maxSteps=30");
319
+ printSystemLine("latex=on profile=latex sandbox=docker-workspace installs=allow maxSteps=30");
226
320
  } else if (value === "off") {
227
321
  state.taskProfile = "auto";
228
- console.log("latex=off profile=auto");
322
+ printSystemLine("latex=off profile=auto");
229
323
  } else {
230
- console.log("Usage: /latex on OR /latex off");
324
+ printAgentMessage("Usage: /latex on OR /latex off");
231
325
  }
232
326
  return true;
233
327
  }
234
328
  if (command === "cwd") {
235
329
  state.commandCwd = value || process.cwd();
236
- console.log(`cwd=${state.commandCwd}`);
330
+ printSystemLine(`cwd=${state.commandCwd}`);
237
331
  return true;
238
332
  }
239
333
  if (command === "init") {
240
334
  const result = await initProject(process.cwd());
241
- console.log(`initialized project=${result.projectRoot}`);
335
+ printAgentMessage(`initialized project=${result.projectRoot}`);
242
336
  return true;
243
337
  }
244
338
  if (command === "web") {
245
339
  const port = value || "3220";
246
- console.log(`Run in another terminal: aginti web --port ${port}`);
340
+ printAgentMessage(`Run in another terminal: aginti web --port ${port}`);
247
341
  return true;
248
342
  }
249
343
 
250
- console.log(`Unknown command: /${command}. Use /help.`);
344
+ printAgentMessage(`Unknown command: /${command}. Use /help.`);
251
345
  return true;
252
346
  }
253
347
 
@@ -279,8 +373,8 @@ async function runPrompt(prompt, state, packageDir) {
279
373
  state.status = "running";
280
374
  state.activeGoal = prompt.replace(/\s+/g, " ").slice(0, 120);
281
375
  state.lastEvent = "";
282
- console.log(`session=${state.sessionId}`);
283
- console.log(`status=running workingOn=${state.activeGoal}`);
376
+ printSystemLine(`session=${state.sessionId}`);
377
+ printSystemLine(`status=running workingOn=${state.activeGoal}`);
284
378
 
285
379
  const detachInterrupts = attachRunInterrupts(controller);
286
380
  let result;
@@ -288,6 +382,19 @@ async function runPrompt(prompt, state, packageDir) {
288
382
  result = await runAgent({
289
383
  ...config,
290
384
  abortSignal: controller.signal,
385
+ onConsole: (text, options = {}) => {
386
+ if (options.kind === "assistant") {
387
+ printAgentMessage(text);
388
+ } else if (options.kind === "plan") {
389
+ printWrapped(`${label("plan", ansi.systemBg)} `, text);
390
+ } else if (options.kind === "heading") {
391
+ printHeading(text);
392
+ } else if (options.error) {
393
+ console.error(`${label("error", ansi.systemBg)} ${stripMarkdown(text)}`);
394
+ } else {
395
+ printSystemLine(text);
396
+ }
397
+ },
291
398
  onEvent: (type, data = {}) => {
292
399
  if (type === "plan.created") {
293
400
  printStatusEvent(state, "planned");
@@ -316,7 +423,7 @@ async function runPrompt(prompt, state, packageDir) {
316
423
  state.sessionId = result.sessionId || state.sessionId;
317
424
  state.status = result.stopped ? "stopped" : "idle";
318
425
  state.activeGoal = "";
319
- console.log(`status=${state.status} session=${state.sessionId}`);
426
+ printSystemLine(`status=${state.status} session=${state.sessionId}`);
320
427
  if (result.stopped && result.reason === "user_interrupt") {
321
428
  await printResumeHint(state);
322
429
  }
@@ -326,16 +433,16 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
326
433
  const state = createState(args);
327
434
  const rl = readline.createInterface({ input, output, terminal: Boolean(input.isTTY && output.isTTY) });
328
435
 
329
- console.log(`AgInTiFlow ${packageVersion || ""}`.trim());
330
- console.log(`Project: ${process.cwd()}`);
331
- console.log("Interactive agent chat. Type /help for commands, /exit to quit.");
436
+ console.log(color(` AgInTiFlow ${packageVersion || ""} `, ansi.agentBg, ansi.bold).trimEnd());
437
+ printSystemLine(`Project: ${process.cwd()}`);
438
+ printAgentMessage("Interactive agent chat. Type /help for commands, /exit to quit.");
332
439
  printStatus(state);
333
440
 
334
441
  try {
335
442
  while (true) {
336
443
  let answer = "";
337
444
  try {
338
- answer = await rl.question("\naginti> ");
445
+ answer = await rl.question(userPrompt());
339
446
  } catch (error) {
340
447
  if (error?.code === "ERR_USE_AFTER_CLOSE") break;
341
448
  if (isAbortError(error)) {
@@ -359,7 +466,7 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
359
466
  await printResumeHint(state);
360
467
  break;
361
468
  }
362
- console.error(`error: ${error.message}`);
469
+ console.error(`${label("error", ansi.systemBg)} ${error.message}`);
363
470
  }
364
471
  }
365
472
  } finally {