@almyty/chat 0.1.3 → 0.1.4
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/dist/index.d.ts +2 -13
- package/dist/index.js +218 -138
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @almyty/chat — interactive
|
|
3
|
+
* @almyty/chat — interactive agent chat.
|
|
4
4
|
*
|
|
5
5
|
* npx @almyty/chat # pick from a menu
|
|
6
|
-
* npx @almyty/chat <agent> # start chatting
|
|
6
|
+
* npx @almyty/chat <agent> # start chatting
|
|
7
7
|
* npx @almyty/chat <agent> --resume <id> # resume a conversation
|
|
8
|
-
*
|
|
9
|
-
* Reads credentials from ~/.almyty/credentials.json (created by
|
|
10
|
-
* `npx @almyty/auth login`).
|
|
11
|
-
*
|
|
12
|
-
* Slash commands inside the REPL:
|
|
13
|
-
*
|
|
14
|
-
* /switch <agent> switch to a different agent
|
|
15
|
-
* /agents list agents in your organization
|
|
16
|
-
* /clear clear the screen
|
|
17
|
-
* /help show command list
|
|
18
|
-
* /quit, /exit leave the REPL
|
|
19
8
|
*/
|
|
20
9
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,133 +1,171 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @almyty/chat — interactive
|
|
3
|
+
* @almyty/chat — interactive agent chat.
|
|
4
4
|
*
|
|
5
5
|
* npx @almyty/chat # pick from a menu
|
|
6
|
-
* npx @almyty/chat <agent> # start chatting
|
|
6
|
+
* npx @almyty/chat <agent> # start chatting
|
|
7
7
|
* npx @almyty/chat <agent> --resume <id> # resume a conversation
|
|
8
|
-
*
|
|
9
|
-
* Reads credentials from ~/.almyty/credentials.json (created by
|
|
10
|
-
* `npx @almyty/auth login`).
|
|
11
|
-
*
|
|
12
|
-
* Slash commands inside the REPL:
|
|
13
|
-
*
|
|
14
|
-
* /switch <agent> switch to a different agent
|
|
15
|
-
* /agents list agents in your organization
|
|
16
|
-
* /clear clear the screen
|
|
17
|
-
* /help show command list
|
|
18
|
-
* /quit, /exit leave the REPL
|
|
19
8
|
*/
|
|
20
9
|
import { createInterface } from 'readline';
|
|
21
10
|
import { AlmytyClient, resolveCredentialsOrExit } from '@almyty/client';
|
|
22
|
-
const VERSION = '0.1.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
11
|
+
const VERSION = '0.1.3';
|
|
12
|
+
// ── ANSI helpers ────────────────────────────────────────────────
|
|
13
|
+
const DIM = '\x1b[2m';
|
|
14
|
+
const BOLD = '\x1b[1m';
|
|
15
|
+
const RESET = '\x1b[0m';
|
|
16
|
+
const VIOLET = '\x1b[38;5;141m';
|
|
17
|
+
const CYAN = '\x1b[36m';
|
|
18
|
+
const RED = '\x1b[31m';
|
|
19
|
+
const GRAY = '\x1b[90m';
|
|
20
|
+
const CLEAR_LINE = '\x1b[2K\r';
|
|
21
|
+
const isTTY = process.stdout.isTTY ?? false;
|
|
22
|
+
function dim(s) { return isTTY ? `${DIM}${s}${RESET}` : s; }
|
|
23
|
+
function bold(s) { return isTTY ? `${BOLD}${s}${RESET}` : s; }
|
|
24
|
+
function violet(s) { return isTTY ? `${VIOLET}${s}${RESET}` : s; }
|
|
25
|
+
function cyan(s) { return isTTY ? `${CYAN}${s}${RESET}` : s; }
|
|
26
|
+
function red(s) { return isTTY ? `${RED}${s}${RESET}` : s; }
|
|
27
|
+
function gray(s) { return isTTY ? `${GRAY}${s}${RESET}` : s; }
|
|
28
|
+
// ── Spinner ─────────────────────────────────────────────────────
|
|
29
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
30
|
+
class Spinner {
|
|
31
|
+
interval = null;
|
|
32
|
+
frame = 0;
|
|
33
|
+
start(label = 'Thinking') {
|
|
34
|
+
if (!isTTY)
|
|
35
|
+
return;
|
|
36
|
+
this.frame = 0;
|
|
37
|
+
this.interval = setInterval(() => {
|
|
38
|
+
const f = SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length];
|
|
39
|
+
process.stdout.write(`${CLEAR_LINE}${GRAY}${f} ${label}...${RESET}`);
|
|
40
|
+
this.frame++;
|
|
41
|
+
}, 80);
|
|
42
|
+
}
|
|
43
|
+
stop() {
|
|
44
|
+
if (this.interval) {
|
|
45
|
+
clearInterval(this.interval);
|
|
46
|
+
this.interval = null;
|
|
47
|
+
process.stdout.write(CLEAR_LINE);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
|
-
|
|
51
|
+
// ── Word wrapping ───────────────────────────────────────────────
|
|
52
|
+
function wordWrap(text, width) {
|
|
53
|
+
if (width <= 0)
|
|
54
|
+
return text;
|
|
55
|
+
const lines = [];
|
|
56
|
+
for (const paragraph of text.split('\n')) {
|
|
57
|
+
if (paragraph.length <= width) {
|
|
58
|
+
lines.push(paragraph);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
let line = '';
|
|
62
|
+
for (const word of paragraph.split(/\s+/)) {
|
|
63
|
+
if (line.length + word.length + 1 > width && line.length > 0) {
|
|
64
|
+
lines.push(line);
|
|
65
|
+
line = word;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
line = line ? `${line} ${word}` : word;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (line)
|
|
72
|
+
lines.push(line);
|
|
73
|
+
}
|
|
74
|
+
return lines.join('\n');
|
|
75
|
+
}
|
|
76
|
+
// ── Display ─────────────────────────────────────────────────────
|
|
77
|
+
function printBanner(agent) {
|
|
78
|
+
const cols = process.stdout.columns || 80;
|
|
79
|
+
const line = gray('─'.repeat(Math.min(cols, 60)));
|
|
45
80
|
console.log('');
|
|
46
|
-
console.log(
|
|
81
|
+
console.log(line);
|
|
82
|
+
console.log(` ${violet(bold(agent.name))} ${dim(agent.mode ?? '')}`);
|
|
47
83
|
if (agent.description)
|
|
48
|
-
console.log(`
|
|
49
|
-
console.log(
|
|
50
|
-
console.log(' Type
|
|
84
|
+
console.log(` ${dim(agent.description)}`);
|
|
85
|
+
console.log(line);
|
|
86
|
+
console.log(dim(' Type a message to chat. /help for commands, /quit to exit.'));
|
|
51
87
|
console.log('');
|
|
52
88
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return ` · llm_call (${step.tokens?.input ?? 0}↓ / ${step.tokens?.output ?? 0}↑)`;
|
|
61
|
-
case 'tool_call':
|
|
62
|
-
return ` · tool_call → ${step.input?.tool ?? '?'}`;
|
|
63
|
-
case 'sub_agent_call':
|
|
64
|
-
return ` · sub_agent_call → ${step.input?.agentId ?? '?'}`;
|
|
65
|
-
case 'error':
|
|
66
|
-
return ` ! error: ${step.error}`;
|
|
67
|
-
default:
|
|
68
|
-
return null;
|
|
89
|
+
function printResponse(text) {
|
|
90
|
+
const cols = process.stdout.columns || 80;
|
|
91
|
+
const maxWidth = Math.min(cols - 2, 78);
|
|
92
|
+
const wrapped = wordWrap(text.trim(), maxWidth);
|
|
93
|
+
console.log('');
|
|
94
|
+
for (const line of wrapped.split('\n')) {
|
|
95
|
+
console.log(` ${line}`);
|
|
69
96
|
}
|
|
97
|
+
console.log('');
|
|
98
|
+
}
|
|
99
|
+
function printToolCall(name) {
|
|
100
|
+
process.stdout.write(`${CLEAR_LINE}${gray(` > ${name}`)}\n`);
|
|
101
|
+
}
|
|
102
|
+
function printError(msg) {
|
|
103
|
+
console.log(`\n ${red('error')} ${msg}\n`);
|
|
70
104
|
}
|
|
105
|
+
// ── Agent picker ────────────────────────────────────────────────
|
|
71
106
|
async function pickAgent(client) {
|
|
72
107
|
const agents = await client.listAgents();
|
|
73
108
|
if (agents.length === 0) {
|
|
74
|
-
|
|
109
|
+
printError('No agents found. Create one at https://app.almyty.com/agents');
|
|
75
110
|
return null;
|
|
76
111
|
}
|
|
77
|
-
if (agents.length === 1)
|
|
112
|
+
if (agents.length === 1)
|
|
78
113
|
return agents[0];
|
|
79
|
-
}
|
|
80
114
|
console.log('');
|
|
81
|
-
console.log('
|
|
115
|
+
console.log(bold(' Select an agent:'));
|
|
116
|
+
console.log('');
|
|
82
117
|
agents.forEach((a, i) => {
|
|
83
|
-
const mode = a.mode ? ` [${a.mode}]` : '';
|
|
84
|
-
console.log(`
|
|
118
|
+
const mode = a.mode ? dim(` [${a.mode}]`) : '';
|
|
119
|
+
console.log(` ${cyan(`${i + 1}.`)} ${a.name}${mode}`);
|
|
85
120
|
});
|
|
86
121
|
console.log('');
|
|
87
122
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
88
123
|
const answer = await new Promise((resolve) => {
|
|
89
|
-
rl.question('
|
|
124
|
+
rl.question(` ${cyan('>')} `, (input) => {
|
|
90
125
|
rl.close();
|
|
91
126
|
resolve(input.trim());
|
|
92
127
|
});
|
|
93
128
|
});
|
|
94
129
|
const idx = parseInt(answer, 10) - 1;
|
|
95
130
|
if (Number.isNaN(idx) || idx < 0 || idx >= agents.length) {
|
|
96
|
-
|
|
131
|
+
printError('Invalid selection.');
|
|
97
132
|
return null;
|
|
98
133
|
}
|
|
99
134
|
return agents[idx];
|
|
100
135
|
}
|
|
136
|
+
// ── Slash commands ──────────────────────────────────────────────
|
|
101
137
|
async function handleSlashCommand(command, state) {
|
|
102
138
|
const [cmd, ...rest] = command.slice(1).trim().split(/\s+/);
|
|
103
139
|
switch (cmd) {
|
|
104
140
|
case 'quit':
|
|
105
141
|
case 'exit':
|
|
142
|
+
case 'q':
|
|
106
143
|
return { exit: true };
|
|
107
144
|
case 'help':
|
|
145
|
+
case 'h':
|
|
108
146
|
console.log('');
|
|
109
|
-
console.log('
|
|
110
|
-
console.log('
|
|
111
|
-
console.log('
|
|
112
|
-
console.log('
|
|
113
|
-
console.log(' /help this help');
|
|
147
|
+
console.log(` ${cyan('/switch')} ${dim('<agent>')} switch to a different agent`);
|
|
148
|
+
console.log(` ${cyan('/agents')} list available agents`);
|
|
149
|
+
console.log(` ${cyan('/clear')} clear the screen`);
|
|
150
|
+
console.log(` ${cyan('/quit')} exit`);
|
|
114
151
|
console.log('');
|
|
115
152
|
return {};
|
|
116
153
|
case 'clear':
|
|
154
|
+
case 'c':
|
|
117
155
|
process.stdout.write('\x1b[2J\x1b[H');
|
|
118
|
-
|
|
156
|
+
printBanner(state.agent);
|
|
119
157
|
return {};
|
|
120
158
|
case 'agents': {
|
|
121
159
|
const agents = await state.client.listAgents();
|
|
122
160
|
if (agents.length === 0) {
|
|
123
|
-
console.log(' (no agents
|
|
161
|
+
console.log(dim(' (no agents)'));
|
|
124
162
|
return {};
|
|
125
163
|
}
|
|
126
164
|
console.log('');
|
|
127
165
|
for (const a of agents) {
|
|
128
|
-
const marker = a.id === state.agent.id ? '
|
|
129
|
-
const mode = a.mode ? ` [${a.mode}]` : '';
|
|
130
|
-
console.log(` ${marker} ${a.name}${mode}
|
|
166
|
+
const marker = a.id === state.agent.id ? violet('>') : ' ';
|
|
167
|
+
const mode = a.mode ? dim(` [${a.mode}]`) : '';
|
|
168
|
+
console.log(` ${marker} ${a.name}${mode}`);
|
|
131
169
|
}
|
|
132
170
|
console.log('');
|
|
133
171
|
return {};
|
|
@@ -135,83 +173,106 @@ async function handleSlashCommand(command, state) {
|
|
|
135
173
|
case 'switch': {
|
|
136
174
|
const target = rest.join(' ').trim();
|
|
137
175
|
if (!target) {
|
|
138
|
-
console.log(' Usage: /switch <agent
|
|
176
|
+
console.log(dim(' Usage: /switch <agent>'));
|
|
139
177
|
return {};
|
|
140
178
|
}
|
|
141
179
|
const next = await state.client.findAgentByNameOrId(target);
|
|
142
180
|
if (!next) {
|
|
143
|
-
|
|
181
|
+
printError(`Agent "${target}" not found.`);
|
|
144
182
|
return {};
|
|
145
183
|
}
|
|
146
184
|
state.agent = next;
|
|
147
185
|
state.pendingRunId = null;
|
|
148
186
|
state.conversationId = null;
|
|
149
|
-
|
|
187
|
+
printBanner(state.agent);
|
|
150
188
|
return {};
|
|
151
189
|
}
|
|
152
190
|
default:
|
|
153
|
-
console.log(` Unknown command: /${cmd}
|
|
191
|
+
console.log(dim(` Unknown command: /${cmd}`));
|
|
154
192
|
return {};
|
|
155
193
|
}
|
|
156
194
|
}
|
|
195
|
+
// ── Turn handling ───────────────────────────────────────────────
|
|
157
196
|
async function handleAutonomousTurn(state, message) {
|
|
197
|
+
const spinner = new Spinner();
|
|
158
198
|
let runId;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const run = await state.client.startRun(state.agent.id, message, {
|
|
166
|
-
conversationId: state.conversationId ?? undefined,
|
|
167
|
-
});
|
|
168
|
-
runId = run.id;
|
|
169
|
-
if (run.conversationId) {
|
|
170
|
-
state.conversationId = run.conversationId;
|
|
199
|
+
try {
|
|
200
|
+
spinner.start();
|
|
201
|
+
if (state.pendingRunId) {
|
|
202
|
+
await state.client.sendRunInput(state.agent.id, state.pendingRunId, message);
|
|
203
|
+
runId = state.pendingRunId;
|
|
204
|
+
state.pendingRunId = null;
|
|
171
205
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (line)
|
|
180
|
-
console.log(line);
|
|
206
|
+
else {
|
|
207
|
+
const run = await state.client.startRun(state.agent.id, message, {
|
|
208
|
+
conversationId: state.conversationId ?? undefined,
|
|
209
|
+
});
|
|
210
|
+
runId = run.id;
|
|
211
|
+
if (run.conversationId) {
|
|
212
|
+
state.conversationId = run.conversationId;
|
|
181
213
|
}
|
|
182
|
-
printed = run.steps?.length ?? printed;
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
if (final.status === 'waiting_input') {
|
|
186
|
-
state.pendingRunId = runId;
|
|
187
|
-
console.log('');
|
|
188
|
-
console.log(' (agent is waiting for your input — answer below)');
|
|
189
|
-
console.log('');
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (final.status === 'completed') {
|
|
193
|
-
if (final.output != null) {
|
|
194
|
-
console.log('');
|
|
195
|
-
console.log(typeof final.output === 'string' ? ` ${final.output}` : JSON.stringify(final.output, null, 2));
|
|
196
214
|
}
|
|
197
|
-
|
|
215
|
+
// Poll for completion — show tool calls as they happen
|
|
216
|
+
const seenSteps = new Set();
|
|
217
|
+
const final = await state.client.pollRun(state.agent.id, runId, {
|
|
218
|
+
intervalMs: 800,
|
|
219
|
+
onStep: (run) => {
|
|
220
|
+
const steps = run.steps ?? [];
|
|
221
|
+
for (let i = 0; i < steps.length; i++) {
|
|
222
|
+
if (seenSteps.has(i))
|
|
223
|
+
continue;
|
|
224
|
+
seenSteps.add(i);
|
|
225
|
+
const step = steps[i];
|
|
226
|
+
if (step?.type === 'tool_call' && step?.input?.tool) {
|
|
227
|
+
spinner.stop();
|
|
228
|
+
printToolCall(step.input.tool);
|
|
229
|
+
spinner.start();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
spinner.stop();
|
|
235
|
+
if (final.status === 'waiting_input') {
|
|
236
|
+
state.pendingRunId = runId;
|
|
237
|
+
console.log(dim('\n (waiting for your input)\n'));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (final.status === 'completed' && final.output != null) {
|
|
241
|
+
const text = typeof final.output === 'string' ? final.output : JSON.stringify(final.output, null, 2);
|
|
242
|
+
printResponse(text);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (final.status === 'failed') {
|
|
246
|
+
printError(final.error || 'Run failed');
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (final.status === 'cancelled') {
|
|
250
|
+
console.log(dim('\n (cancelled)\n'));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
spinner.stop();
|
|
256
|
+
throw err;
|
|
198
257
|
}
|
|
199
|
-
console.log('');
|
|
200
|
-
console.log(` Run ${final.status}${final.error ? `: ${final.error}` : ''}`);
|
|
201
258
|
}
|
|
202
259
|
async function handleWorkflowTurn(state, message) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
260
|
+
const spinner = new Spinner();
|
|
261
|
+
try {
|
|
262
|
+
spinner.start();
|
|
263
|
+
const result = await state.client.invokeAgent(state.agent.id, { message });
|
|
264
|
+
spinner.stop();
|
|
265
|
+
const output = result?.output ?? result?.data?.output ?? result;
|
|
266
|
+
if (output == null) {
|
|
267
|
+
console.log(dim('\n (no output)\n'));
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const text = typeof output === 'string' ? output : JSON.stringify(output, null, 2);
|
|
271
|
+
printResponse(text);
|
|
212
272
|
}
|
|
213
|
-
|
|
214
|
-
|
|
273
|
+
catch (err) {
|
|
274
|
+
spinner.stop();
|
|
275
|
+
throw err;
|
|
215
276
|
}
|
|
216
277
|
}
|
|
217
278
|
async function handleUserTurn(state, message) {
|
|
@@ -220,16 +281,18 @@ async function handleUserTurn(state, message) {
|
|
|
220
281
|
}
|
|
221
282
|
return handleWorkflowTurn(state, message);
|
|
222
283
|
}
|
|
284
|
+
// ── Main loop ───────────────────────────────────────────────────
|
|
223
285
|
async function startChat(client, agent, resumeConversationId) {
|
|
224
286
|
const state = { client, agent, pendingRunId: null, conversationId: resumeConversationId ?? null };
|
|
225
287
|
if (resumeConversationId) {
|
|
226
|
-
console.log(` Resuming conversation ${resumeConversationId}`);
|
|
288
|
+
console.log(dim(` Resuming conversation ${resumeConversationId}`));
|
|
227
289
|
}
|
|
228
|
-
|
|
290
|
+
printBanner(state.agent);
|
|
291
|
+
const prompt = `${VIOLET}>${RESET} `;
|
|
229
292
|
const rl = createInterface({
|
|
230
293
|
input: process.stdin,
|
|
231
294
|
output: process.stdout,
|
|
232
|
-
prompt: '> ',
|
|
295
|
+
prompt: isTTY ? prompt : '> ',
|
|
233
296
|
});
|
|
234
297
|
rl.prompt();
|
|
235
298
|
rl.on('line', async (raw) => {
|
|
@@ -247,7 +310,7 @@ async function startChat(client, agent, resumeConversationId) {
|
|
|
247
310
|
}
|
|
248
311
|
}
|
|
249
312
|
catch (err) {
|
|
250
|
-
|
|
313
|
+
printError(err.message);
|
|
251
314
|
}
|
|
252
315
|
rl.prompt();
|
|
253
316
|
return;
|
|
@@ -256,17 +319,16 @@ async function startChat(client, agent, resumeConversationId) {
|
|
|
256
319
|
await handleUserTurn(state, line);
|
|
257
320
|
}
|
|
258
321
|
catch (err) {
|
|
259
|
-
|
|
322
|
+
printError(err.message);
|
|
260
323
|
}
|
|
261
|
-
console.log('');
|
|
262
324
|
rl.prompt();
|
|
263
325
|
});
|
|
264
326
|
rl.on('close', () => {
|
|
265
327
|
console.log('');
|
|
266
|
-
console.log('Chat ended.');
|
|
267
328
|
process.exit(0);
|
|
268
329
|
});
|
|
269
330
|
}
|
|
331
|
+
// ── Entry point ─────────────────────────────────────────────────
|
|
270
332
|
async function main() {
|
|
271
333
|
const argv = process.argv.slice(2);
|
|
272
334
|
if (argv.includes('--version') || argv.includes('-v')) {
|
|
@@ -274,18 +336,33 @@ async function main() {
|
|
|
274
336
|
return;
|
|
275
337
|
}
|
|
276
338
|
if (argv.includes('--help') || argv.includes('-h')) {
|
|
277
|
-
|
|
339
|
+
console.log(`
|
|
340
|
+
${bold('almyty chat')} ${dim(`v${VERSION}`)}
|
|
341
|
+
|
|
342
|
+
${bold('Usage:')}
|
|
343
|
+
npx @almyty/chat Pick an agent
|
|
344
|
+
npx @almyty/chat ${dim('<agent>')} Start chatting
|
|
345
|
+
npx @almyty/chat ${dim('<agent>')} --resume ${dim('<conv-id>')} Resume conversation
|
|
346
|
+
|
|
347
|
+
${bold('Commands:')}
|
|
348
|
+
/switch ${dim('<agent>')} switch agent
|
|
349
|
+
/agents list agents
|
|
350
|
+
/clear clear screen
|
|
351
|
+
/quit exit
|
|
352
|
+
|
|
353
|
+
${bold('Auth:')}
|
|
354
|
+
npx @almyty/auth login
|
|
355
|
+
`);
|
|
278
356
|
return;
|
|
279
357
|
}
|
|
280
358
|
const creds = resolveCredentialsOrExit();
|
|
281
359
|
const client = new AlmytyClient(creds.url, creds.token);
|
|
282
|
-
// Parse --resume <conversation-id>
|
|
283
360
|
let resumeConversationId;
|
|
284
361
|
const resumeIdx = argv.indexOf('--resume');
|
|
285
362
|
if (resumeIdx !== -1) {
|
|
286
363
|
const nextArg = argv[resumeIdx + 1];
|
|
287
364
|
if (!nextArg || nextArg.startsWith('-')) {
|
|
288
|
-
|
|
365
|
+
printError('Usage: --resume <conversation-id>');
|
|
289
366
|
process.exit(1);
|
|
290
367
|
}
|
|
291
368
|
resumeConversationId = nextArg;
|
|
@@ -293,9 +370,12 @@ async function main() {
|
|
|
293
370
|
let agent = null;
|
|
294
371
|
const ref = argv.find((a) => !a.startsWith('-') && a !== resumeConversationId);
|
|
295
372
|
if (ref) {
|
|
373
|
+
const spinner = new Spinner();
|
|
374
|
+
spinner.start('Connecting');
|
|
296
375
|
agent = await client.findAgentByNameOrId(ref);
|
|
376
|
+
spinner.stop();
|
|
297
377
|
if (!agent) {
|
|
298
|
-
|
|
378
|
+
printError(`Agent not found: ${ref}`);
|
|
299
379
|
process.exit(1);
|
|
300
380
|
}
|
|
301
381
|
}
|
|
@@ -307,6 +387,6 @@ async function main() {
|
|
|
307
387
|
await startChat(client, agent, resumeConversationId);
|
|
308
388
|
}
|
|
309
389
|
main().catch((err) => {
|
|
310
|
-
|
|
390
|
+
printError(err.message);
|
|
311
391
|
process.exit(1);
|
|
312
392
|
});
|