@inkeep/agents-cli 0.1.4 → 0.1.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.
Files changed (59) hide show
  1. package/SUPPLEMENTAL_TERMS.md +40 -0
  2. package/dist/commands/create.d.ts +12 -0
  3. package/dist/commands/create.js +865 -0
  4. package/dist/config.d.ts +4 -4
  5. package/dist/index.js +5308 -20409
  6. package/package.json +15 -6
  7. package/dist/__tests__/api.test.d.ts +0 -1
  8. package/dist/__tests__/api.test.js +0 -257
  9. package/dist/__tests__/cli.test.d.ts +0 -1
  10. package/dist/__tests__/cli.test.js +0 -153
  11. package/dist/__tests__/commands/config.test.d.ts +0 -1
  12. package/dist/__tests__/commands/config.test.js +0 -154
  13. package/dist/__tests__/commands/init.test.d.ts +0 -1
  14. package/dist/__tests__/commands/init.test.js +0 -186
  15. package/dist/__tests__/commands/pull.test.d.ts +0 -1
  16. package/dist/__tests__/commands/pull.test.js +0 -54
  17. package/dist/__tests__/commands/push-spinner.test.d.ts +0 -1
  18. package/dist/__tests__/commands/push-spinner.test.js +0 -127
  19. package/dist/__tests__/commands/push.test.d.ts +0 -1
  20. package/dist/__tests__/commands/push.test.js +0 -265
  21. package/dist/__tests__/config-validation.test.d.ts +0 -1
  22. package/dist/__tests__/config-validation.test.js +0 -98
  23. package/dist/__tests__/package.test.d.ts +0 -1
  24. package/dist/__tests__/package.test.js +0 -82
  25. package/dist/__tests__/utils/json-comparator.test.d.ts +0 -1
  26. package/dist/__tests__/utils/json-comparator.test.js +0 -174
  27. package/dist/__tests__/utils/ts-loader.test.d.ts +0 -1
  28. package/dist/__tests__/utils/ts-loader.test.js +0 -232
  29. package/dist/api.d.ts +0 -23
  30. package/dist/api.js +0 -140
  31. package/dist/commands/chat-enhanced.d.ts +0 -7
  32. package/dist/commands/chat-enhanced.js +0 -396
  33. package/dist/commands/chat.d.ts +0 -5
  34. package/dist/commands/chat.js +0 -125
  35. package/dist/commands/config.d.ts +0 -6
  36. package/dist/commands/config.js +0 -128
  37. package/dist/commands/init.d.ts +0 -5
  38. package/dist/commands/init.js +0 -171
  39. package/dist/commands/list-graphs.d.ts +0 -6
  40. package/dist/commands/list-graphs.js +0 -131
  41. package/dist/commands/pull.d.ts +0 -15
  42. package/dist/commands/pull.js +0 -305
  43. package/dist/commands/pull.llm-generate.d.ts +0 -10
  44. package/dist/commands/pull.llm-generate.js +0 -184
  45. package/dist/commands/push.d.ts +0 -6
  46. package/dist/commands/push.js +0 -268
  47. package/dist/exports.d.ts +0 -2
  48. package/dist/exports.js +0 -2
  49. package/dist/index.js.map +0 -7
  50. package/dist/types/config.d.ts +0 -9
  51. package/dist/types/config.js +0 -3
  52. package/dist/types/graph.d.ts +0 -10
  53. package/dist/types/graph.js +0 -1
  54. package/dist/utils/json-comparator.d.ts +0 -60
  55. package/dist/utils/json-comparator.js +0 -222
  56. package/dist/utils/mcp-runner.d.ts +0 -6
  57. package/dist/utils/mcp-runner.js +0 -147
  58. package/dist/utils/ts-loader.d.ts +0 -5
  59. package/dist/utils/ts-loader.js +0 -145
package/dist/api.js DELETED
@@ -1,140 +0,0 @@
1
- import { getManagementApiUrl, getExecutionApiUrl, getProjectId, getTenantId } from './config.js';
2
- class BaseApiClient {
3
- apiUrl;
4
- tenantId;
5
- projectId;
6
- constructor(apiUrl, tenantId, projectId) {
7
- this.apiUrl = apiUrl;
8
- this.tenantId = tenantId;
9
- this.projectId = projectId;
10
- }
11
- checkTenantId() {
12
- if (!this.tenantId) {
13
- throw new Error('No tenant ID configured. Please run: inkeep init');
14
- }
15
- return this.tenantId;
16
- }
17
- getTenantId() {
18
- return this.tenantId;
19
- }
20
- getProjectId() {
21
- return this.projectId;
22
- }
23
- getApiUrl() {
24
- return this.apiUrl;
25
- }
26
- }
27
- export class ManagementApiClient extends BaseApiClient {
28
- constructor(apiUrl, tenantId, projectId) {
29
- super(apiUrl, tenantId, projectId);
30
- }
31
- static async create(apiUrl, configPath, tenantIdOverride, projectIdOverride) {
32
- const resolvedApiUrl = await getManagementApiUrl(apiUrl, configPath);
33
- const tenantId = tenantIdOverride || (await getTenantId(configPath));
34
- const projectId = projectIdOverride || (await getProjectId(configPath));
35
- return new ManagementApiClient(resolvedApiUrl, tenantId, projectId);
36
- }
37
- async listGraphs() {
38
- const tenantId = this.checkTenantId();
39
- const projectId = this.getProjectId();
40
- const response = await fetch(`${this.apiUrl}/tenants/${tenantId}/crud/projects/${projectId}/agent-graphs`, {
41
- method: 'GET',
42
- headers: {
43
- 'Content-Type': 'application/json',
44
- ...(process.env.INKEEP_AGENTS_MANAGE_API_SECRET && {
45
- Authorization: `Bearer ${process.env.INKEEP_AGENTS_MANAGE_API_SECRET}`,
46
- }),
47
- },
48
- });
49
- if (!response.ok) {
50
- throw new Error(`Failed to list graphs: ${response.statusText}`);
51
- }
52
- const data = await response.json();
53
- return data.data || [];
54
- }
55
- async getGraph(graphId) {
56
- // Since there's no dedicated GET endpoint for graphs,
57
- // we check if the graph exists in the CRUD endpoint
58
- const graphs = await this.listGraphs();
59
- const graph = graphs.find((g) => g.id === graphId);
60
- // If found in CRUD, return it as a valid graph
61
- // The graph is usable for chat even without a dedicated GET endpoint
62
- return graph || null;
63
- }
64
- async pushGraph(graphDefinition) {
65
- const tenantId = this.checkTenantId();
66
- const projectId = this.getProjectId();
67
- // Ensure the graph has the correct tenant ID
68
- graphDefinition.tenantId = tenantId;
69
- const graphId = graphDefinition.id;
70
- if (!graphId) {
71
- throw new Error('Graph must have an id property');
72
- }
73
- // Try to update first using PUT, if it doesn't exist, it will create it
74
- const response = await fetch(`${this.apiUrl}/tenants/${tenantId}/crud/projects/${projectId}/graph/${graphId}`, {
75
- method: 'PUT',
76
- headers: {
77
- 'Content-Type': 'application/json',
78
- ...(process.env.INKEEP_AGENTS_MANAGE_API_SECRET && {
79
- Authorization: `Bearer ${process.env.INKEEP_AGENTS_MANAGE_API_SECRET}`,
80
- }),
81
- },
82
- body: JSON.stringify(graphDefinition),
83
- });
84
- if (!response.ok) {
85
- const errorText = await response.text();
86
- throw new Error(`Failed to push graph: ${response.statusText}\n${errorText}`);
87
- }
88
- const data = await response.json();
89
- return data.data;
90
- }
91
- }
92
- export class ExecutionApiClient extends BaseApiClient {
93
- constructor(apiUrl, tenantId, projectId) {
94
- super(apiUrl, tenantId, projectId);
95
- }
96
- static async create(apiUrl, configPath, tenantIdOverride, projectIdOverride) {
97
- const resolvedApiUrl = await getExecutionApiUrl(apiUrl, configPath);
98
- const tenantId = tenantIdOverride || (await getTenantId(configPath));
99
- const projectId = projectIdOverride || (await getProjectId(configPath));
100
- return new ExecutionApiClient(resolvedApiUrl, tenantId, projectId);
101
- }
102
- async chatCompletion(graphId, messages, conversationId) {
103
- const response = await fetch(`${this.apiUrl}/v1/chat/completions`, {
104
- method: 'POST',
105
- headers: {
106
- 'Content-Type': 'application/json',
107
- Accept: 'text/event-stream',
108
- ...(process.env.INKEEP_AGENTS_RUN_BYPASS_SECRET && {
109
- Authorization: `Bearer ${process.env.INKEEP_AGENTS_RUN_BYPASS_SECRET}`,
110
- }),
111
- 'x-inkeep-tenant-id': this.tenantId || 'test-tenant-id',
112
- 'x-inkeep-project-id': this.projectId,
113
- 'x-inkeep-graph-id': graphId,
114
- },
115
- body: JSON.stringify({
116
- model: 'gpt-4o-mini', // Required but will be overridden by graph config
117
- messages,
118
- conversationId,
119
- stream: true,
120
- }),
121
- });
122
- if (!response.ok) {
123
- const errorText = await response.text();
124
- throw new Error(`Chat request failed: ${response.statusText}\n${errorText}`);
125
- }
126
- // Check if response is streaming
127
- const contentType = response.headers.get('content-type');
128
- if (contentType?.includes('text/event-stream')) {
129
- if (!response.body) {
130
- throw new Error('No response body for streaming request');
131
- }
132
- return response.body;
133
- }
134
- else {
135
- // Non-streaming response
136
- const data = await response.json();
137
- return data.choices?.[0]?.message?.content || data.result || '';
138
- }
139
- }
140
- }
@@ -1,7 +0,0 @@
1
- export interface ChatOptions {
2
- tenantId?: string;
3
- managementApiUrl?: string;
4
- executionApiUrl?: string;
5
- configFilePath?: string;
6
- }
7
- export declare function chatCommandEnhanced(graphIdInput?: string, options?: ChatOptions): Promise<void>;
@@ -1,396 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { existsSync } from 'node:fs';
3
- import { dirname, extname, resolve } from 'node:path';
4
- import * as readline from 'node:readline';
5
- import { fileURLToPath } from 'node:url';
6
- import chalk from 'chalk';
7
- import inquirer from 'inquirer';
8
- import ora from 'ora';
9
- import { ManagementApiClient, ExecutionApiClient } from '../api.js';
10
- import { validateConfiguration } from '../config.js';
11
- export async function chatCommandEnhanced(graphIdInput, options) {
12
- // Check if we need to re-run with tsx for TypeScript config files
13
- if (!process.env.TSX_RUNNING) {
14
- // Helper function to find config file
15
- function findConfigFile(startPath = process.cwd()) {
16
- let currentPath = resolve(startPath);
17
- const root = '/';
18
- const configNames = ['inkeep.config.ts', 'inkeep.config.js', '.inkeeprc.ts', '.inkeeprc.js'];
19
- while (currentPath !== root) {
20
- // Check for config files at this level
21
- for (const configName of configNames) {
22
- const configPath = resolve(currentPath, configName);
23
- if (existsSync(configPath)) {
24
- return configPath;
25
- }
26
- }
27
- const parentPath = dirname(currentPath);
28
- if (parentPath === currentPath) {
29
- break; // Reached filesystem root
30
- }
31
- currentPath = parentPath;
32
- }
33
- return null;
34
- }
35
- // Determine if we have a TypeScript config that needs tsx
36
- let configPath = null;
37
- if (options?.configFilePath) {
38
- // User specified a config path
39
- configPath = resolve(process.cwd(), options.configFilePath);
40
- if (!existsSync(configPath)) {
41
- // Config file doesn't exist, let the normal flow handle the error
42
- configPath = null;
43
- }
44
- }
45
- else {
46
- // Search for config file
47
- configPath = findConfigFile();
48
- }
49
- // If we found a TypeScript config file, re-run with tsx
50
- if (configPath && extname(configPath) === '.ts') {
51
- // Re-run this command with tsx
52
- const __filename = fileURLToPath(import.meta.url);
53
- const __dirname = dirname(__filename);
54
- const cliPath = resolve(__dirname, '../index.js');
55
- const args = [cliPath, 'chat'];
56
- if (graphIdInput)
57
- args.push(graphIdInput);
58
- if (options?.tenantId)
59
- args.push('--tenant-id', options.tenantId);
60
- if (options?.managementApiUrl)
61
- args.push('--management-api-url', options.managementApiUrl);
62
- if (options?.executionApiUrl)
63
- args.push('--execution-api-url', options.executionApiUrl);
64
- if (options?.configFilePath)
65
- args.push('--config-file-path', options.configFilePath);
66
- const child = spawn('npx', ['tsx', ...args], {
67
- cwd: process.cwd(),
68
- stdio: 'inherit',
69
- env: { ...process.env, TSX_RUNNING: '1' },
70
- });
71
- child.on('error', (error) => {
72
- console.error(chalk.red('Failed to load TypeScript configuration:'), error.message);
73
- process.exit(1);
74
- });
75
- child.on('exit', (code) => {
76
- process.exit(code || 0);
77
- });
78
- return;
79
- }
80
- }
81
- // Validate configuration
82
- let config;
83
- try {
84
- config = await validateConfiguration(options?.tenantId, options?.managementApiUrl, options?.executionApiUrl, options?.configFilePath);
85
- }
86
- catch (error) {
87
- console.error(chalk.red(error.message));
88
- process.exit(1);
89
- }
90
- // Log configuration sources for debugging
91
- console.log(chalk.gray('Using configuration:'));
92
- console.log(chalk.gray(` • Tenant ID: ${config.sources.tenantId}`));
93
- console.log(chalk.gray(` • Management API: ${config.sources.managementApiUrl}`));
94
- console.log(chalk.gray(` • Execution API: ${config.sources.executionApiUrl}`));
95
- console.log();
96
- const managementApi = await ManagementApiClient.create(config.managementApiUrl, options?.configFilePath, config.tenantId);
97
- const executionApi = await ExecutionApiClient.create(config.executionApiUrl, options?.configFilePath, config.tenantId);
98
- let graphId = graphIdInput;
99
- // If no graph ID provided, show autocomplete selection
100
- if (!graphId) {
101
- const spinner = ora('Fetching available graphs...').start();
102
- try {
103
- const graphs = await managementApi.listGraphs();
104
- spinner.stop();
105
- if (graphs.length === 0) {
106
- console.error(chalk.red('No graphs available. Push a graph first with: inkeep push <graph-path>'));
107
- process.exit(1);
108
- }
109
- // Create searchable source for autocomplete
110
- const graphChoices = graphs.map((g) => ({
111
- name: `${chalk.cyan(g.id)} - ${g.name || 'Unnamed Graph'}`,
112
- value: g.id,
113
- short: g.id,
114
- searchText: `${g.id} ${g.name || ''}`.toLowerCase(),
115
- }));
116
- // Use list prompt for interactive selection
117
- const answer = await inquirer.prompt([
118
- {
119
- type: 'list',
120
- name: 'graphId',
121
- message: 'Select a graph to chat with:',
122
- choices: graphChoices,
123
- pageSize: 10,
124
- },
125
- ]);
126
- graphId = answer.graphId;
127
- }
128
- catch (error) {
129
- spinner.fail('Failed to fetch graphs');
130
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
131
- process.exit(1);
132
- }
133
- }
134
- // Check if graph exists
135
- const spinner = ora('Connecting to graph...').start();
136
- try {
137
- const graph = await managementApi.getGraph(graphId);
138
- if (!graph) {
139
- spinner.fail(`Graph "${graphId}" not found`);
140
- // Show available graphs
141
- const graphs = await managementApi.listGraphs();
142
- if (graphs.length > 0) {
143
- console.log(chalk.yellow('\nAvailable graphs:'));
144
- graphs.forEach((g) => {
145
- console.log(chalk.gray(` • ${g.id} - ${g.name || 'Unnamed'}`));
146
- });
147
- console.log(chalk.gray('\nRun "inkeep chat" without arguments for interactive selection'));
148
- }
149
- else {
150
- console.log(chalk.yellow('\nNo graphs found. Please create and push a graph first.'));
151
- console.log(chalk.gray('Example: inkeep push ./my-graph.js'));
152
- }
153
- process.exit(1);
154
- }
155
- spinner.succeed(`Connected to graph: ${chalk.green(graph.name || graphId)}`);
156
- // Display graph details
157
- if (graph.description) {
158
- console.log(chalk.gray(`Description: ${graph.description}`));
159
- }
160
- if (graph.defaultAgentId || graph.default_agent_id) {
161
- console.log(chalk.gray(`Default Agent: ${graph.defaultAgentId || graph.default_agent_id}`));
162
- }
163
- }
164
- catch (error) {
165
- spinner.fail('Failed to connect to graph');
166
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
167
- process.exit(1);
168
- }
169
- // Create readline interface for chat
170
- const rl = readline.createInterface({
171
- input: process.stdin,
172
- output: process.stdout,
173
- prompt: chalk.cyan('You> '),
174
- });
175
- // Generate a conversation ID for this session
176
- const conversationId = `cli-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
177
- const messages = [];
178
- let debugMode = false;
179
- console.log(chalk.gray('\nšŸ’¬ Chat session started. Type "exit" or press Ctrl+C to quit.'));
180
- console.log(chalk.gray('Commands: help, clear, history, reset, debug\n'));
181
- // Function to handle streaming response
182
- async function handleStreamingResponse(stream, showDebug = false) {
183
- const decoder = new TextDecoder();
184
- const reader = stream.getReader();
185
- let buffer = '';
186
- let responseContent = '';
187
- const debugOperations = [];
188
- let hasStartedResponse = false;
189
- try {
190
- while (true) {
191
- const { done, value } = await reader.read();
192
- if (done)
193
- break;
194
- buffer += decoder.decode(value, { stream: true });
195
- const lines = buffer.split('\n');
196
- buffer = lines.pop() || '';
197
- for (const line of lines) {
198
- if (line.startsWith('data: ')) {
199
- const data = line.slice(6);
200
- if (data === '[DONE]')
201
- continue;
202
- try {
203
- const parsed = JSON.parse(data);
204
- // Handle OpenAI-style streaming chunks
205
- const content = parsed.choices?.[0]?.delta?.content;
206
- if (content) {
207
- // Process content character by character to extract JSON objects
208
- let currentPos = 0;
209
- while (currentPos < content.length) {
210
- // Check if we're at the start of a JSON data operation
211
- if (content.substring(currentPos).startsWith('{"type":"data-operation"')) {
212
- // Find the matching closing brace
213
- let braceCount = 0;
214
- let jsonEnd = currentPos;
215
- for (let i = currentPos; i < content.length; i++) {
216
- if (content[i] === '{')
217
- braceCount++;
218
- if (content[i] === '}') {
219
- braceCount--;
220
- if (braceCount === 0) {
221
- jsonEnd = i + 1;
222
- break;
223
- }
224
- }
225
- }
226
- // Extract and parse the JSON object
227
- const jsonStr = content.substring(currentPos, jsonEnd);
228
- try {
229
- const dataOp = JSON.parse(jsonStr);
230
- debugOperations.push(dataOp);
231
- // Show debug info if enabled
232
- if (showDebug && dataOp.type === 'data-operation') {
233
- const opType = dataOp.data?.type || 'unknown';
234
- const ctx = dataOp.data?.ctx || {};
235
- // Format context based on operation type
236
- let ctxDisplay = '';
237
- if (opType === 'agent_thinking' || opType === 'iteration_start') {
238
- ctxDisplay = ctx.agent || JSON.stringify(ctx);
239
- }
240
- else if (opType === 'task_creation') {
241
- ctxDisplay = `agent: ${ctx.agent}`;
242
- }
243
- else {
244
- ctxDisplay = JSON.stringify(ctx);
245
- }
246
- // Add newline before completion operations that come after text
247
- if (opType === 'completion' && hasStartedResponse) {
248
- console.log(''); // Add newline before completion
249
- }
250
- console.log(chalk.gray(` [${opType}] ${ctxDisplay}`));
251
- }
252
- currentPos = jsonEnd;
253
- }
254
- catch {
255
- // Failed to parse, treat as regular content
256
- if (!hasStartedResponse) {
257
- process.stdout.write(chalk.green('Assistant> '));
258
- hasStartedResponse = true;
259
- }
260
- process.stdout.write(content[currentPos]);
261
- responseContent += content[currentPos];
262
- currentPos++;
263
- }
264
- }
265
- else {
266
- // Regular text content
267
- if (!hasStartedResponse) {
268
- process.stdout.write(chalk.green('Assistant> '));
269
- hasStartedResponse = true;
270
- }
271
- process.stdout.write(content[currentPos]);
272
- responseContent += content[currentPos];
273
- currentPos++;
274
- }
275
- }
276
- }
277
- }
278
- catch {
279
- // Ignore parse errors
280
- }
281
- }
282
- }
283
- }
284
- }
285
- finally {
286
- reader.releaseLock();
287
- }
288
- // Add final newline if we had content
289
- if (hasStartedResponse) {
290
- console.log('\n');
291
- }
292
- else {
293
- console.log(chalk.green('Assistant> ') + chalk.gray('(no response)') + '\n');
294
- }
295
- return responseContent;
296
- }
297
- // Handle user input
298
- rl.on('line', async (input) => {
299
- const trimmedInput = input.trim();
300
- const command = trimmedInput.toLowerCase().replace(/^\//, '');
301
- if (command === 'exit') {
302
- console.log(chalk.gray('Goodbye! šŸ‘‹'));
303
- rl.close();
304
- process.exit(0);
305
- }
306
- if (command === 'clear') {
307
- console.clear();
308
- console.log(chalk.gray('Screen cleared. Conversation context preserved.\n'));
309
- rl.prompt();
310
- return;
311
- }
312
- if (command === 'help') {
313
- console.log(chalk.cyan('\nšŸ“š Available commands:'));
314
- console.log(chalk.gray(' • exit - End the chat session'));
315
- console.log(chalk.gray(' • clear - Clear the screen (preserves context)'));
316
- console.log(chalk.gray(' • history - Show conversation history'));
317
- console.log(chalk.gray(' • reset - Reset conversation context'));
318
- console.log(chalk.gray(' • debug - Toggle debug mode (show/hide data operations)'));
319
- console.log(chalk.gray(' • help - Show this help message'));
320
- console.log(chalk.gray('\n Commands can be prefixed with / (e.g., /help)\n'));
321
- rl.prompt();
322
- return;
323
- }
324
- if (command === 'debug') {
325
- debugMode = !debugMode;
326
- console.log(chalk.yellow(`\nšŸ”§ Debug mode: ${debugMode ? 'ON' : 'OFF'}`));
327
- if (debugMode) {
328
- console.log(chalk.gray('Data operations will be shown during responses.\n'));
329
- }
330
- else {
331
- console.log(chalk.gray('Data operations are hidden.\n'));
332
- }
333
- rl.prompt();
334
- return;
335
- }
336
- if (command === 'history') {
337
- console.log(chalk.cyan('\nšŸ“œ Conversation History:'));
338
- if (messages.length === 0) {
339
- console.log(chalk.gray(' (No messages yet)\n'));
340
- }
341
- else {
342
- messages.forEach((msg, idx) => {
343
- const role = msg.role === 'user' ? chalk.blue('You') : chalk.green('Assistant');
344
- const preview = msg.content.substring(0, 100);
345
- const suffix = msg.content.length > 100 ? '...' : '';
346
- console.log(` ${idx + 1}. ${role}: ${preview}${suffix}`);
347
- });
348
- console.log();
349
- }
350
- rl.prompt();
351
- return;
352
- }
353
- if (command === 'reset') {
354
- messages.length = 0;
355
- console.log(chalk.yellow('āš ļø Conversation context has been reset.\n'));
356
- rl.prompt();
357
- return;
358
- }
359
- if (!trimmedInput) {
360
- rl.prompt();
361
- return;
362
- }
363
- // Add user message to history
364
- messages.push({ role: 'user', content: trimmedInput });
365
- try {
366
- // Send message to API using execution API
367
- const response = await executionApi.chatCompletion(graphId, messages, conversationId);
368
- let assistantResponse;
369
- if (typeof response === 'string') {
370
- // Non-streaming response
371
- console.log(chalk.green('Assistant>'), response);
372
- assistantResponse = response;
373
- }
374
- else {
375
- // Streaming response
376
- assistantResponse = await handleStreamingResponse(response, debugMode);
377
- }
378
- // Add assistant response to history
379
- messages.push({ role: 'assistant', content: assistantResponse });
380
- }
381
- catch (error) {
382
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
383
- }
384
- rl.prompt();
385
- });
386
- rl.on('close', () => {
387
- console.log(chalk.gray('\nšŸ“Š Session Summary:'));
388
- console.log(chalk.gray(` • Graph: ${graphId}`));
389
- console.log(chalk.gray(` • Messages: ${messages.length}`));
390
- console.log(chalk.gray(` • Duration: ${new Date().toLocaleTimeString()}`));
391
- console.log(chalk.gray('\nChat session ended.'));
392
- process.exit(0);
393
- });
394
- // Initial prompt
395
- rl.prompt();
396
- }
@@ -1,5 +0,0 @@
1
- export interface ChatOptions {
2
- url?: string;
3
- config?: string;
4
- }
5
- export declare function chatCommand(graphId: string, options: ChatOptions): Promise<void>;
@@ -1,125 +0,0 @@
1
- import * as readline from 'node:readline';
2
- import chalk from 'chalk';
3
- import ora from 'ora';
4
- import { ManagementApiClient, ExecutionApiClient } from '../api.js';
5
- export async function chatCommand(graphId, options) {
6
- const managementApi = await ManagementApiClient.create(options.url, options.config);
7
- const executionApi = await ExecutionApiClient.create(options.url, options.config);
8
- // Check if graph exists using management API
9
- const spinner = ora('Connecting to graph...').start();
10
- try {
11
- const graph = await managementApi.getGraph(graphId);
12
- if (!graph) {
13
- spinner.fail(`Graph "${graphId}" not found`);
14
- process.exit(1);
15
- }
16
- spinner.succeed(`Connected to graph: ${graph.name || graphId}`);
17
- }
18
- catch (error) {
19
- spinner.fail('Failed to connect to graph');
20
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
21
- process.exit(1);
22
- }
23
- // Create readline interface
24
- const rl = readline.createInterface({
25
- input: process.stdin,
26
- output: process.stdout,
27
- prompt: chalk.cyan('You> '),
28
- });
29
- // Generate a conversation ID for this session
30
- const conversationId = `cli-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
31
- const messages = [];
32
- console.log(chalk.gray('\nšŸ’¬ Chat session started. Type "exit" or press Ctrl+C to quit.\n'));
33
- // Function to handle streaming response
34
- async function handleStreamingResponse(stream) {
35
- const decoder = new TextDecoder();
36
- const reader = stream.getReader();
37
- let buffer = '';
38
- let responseContent = '';
39
- process.stdout.write(chalk.green('Assistant> '));
40
- try {
41
- while (true) {
42
- const { done, value } = await reader.read();
43
- if (done)
44
- break;
45
- buffer += decoder.decode(value, { stream: true });
46
- const lines = buffer.split('\n');
47
- buffer = lines.pop() || '';
48
- for (const line of lines) {
49
- if (line.startsWith('data: ')) {
50
- const data = line.slice(6);
51
- if (data === '[DONE]')
52
- continue;
53
- try {
54
- const parsed = JSON.parse(data);
55
- const content = parsed.choices?.[0]?.delta?.content;
56
- if (content) {
57
- // Debug logging
58
- if (process.env.DEBUG) {
59
- console.error('Content received:', content);
60
- }
61
- // Filter out data operation JSON messages
62
- if (!content.startsWith('{"type":"data-operation"')) {
63
- process.stdout.write(content);
64
- responseContent += content;
65
- }
66
- }
67
- }
68
- catch (err) {
69
- // Log parse errors for debugging
70
- if (process.env.DEBUG) {
71
- console.error('Parse error:', err, 'Data:', data);
72
- }
73
- }
74
- }
75
- }
76
- }
77
- }
78
- finally {
79
- reader.releaseLock();
80
- }
81
- console.log('\n');
82
- return responseContent;
83
- }
84
- // Set up tab completion for graph IDs
85
- rl.on('line', async (input) => {
86
- const trimmedInput = input.trim();
87
- if (trimmedInput.toLowerCase() === 'exit') {
88
- console.log(chalk.gray('Goodbye! šŸ‘‹'));
89
- rl.close();
90
- process.exit(0);
91
- }
92
- if (!trimmedInput) {
93
- rl.prompt();
94
- return;
95
- }
96
- // Add user message to history
97
- messages.push({ role: 'user', content: trimmedInput });
98
- try {
99
- // Send message to API using execution API
100
- const response = await executionApi.chatCompletion(graphId, messages, conversationId);
101
- let assistantResponse;
102
- if (typeof response === 'string') {
103
- // Non-streaming response
104
- console.log(chalk.green('Assistant>'), response);
105
- assistantResponse = response;
106
- }
107
- else {
108
- // Streaming response
109
- assistantResponse = await handleStreamingResponse(response);
110
- }
111
- // Add assistant response to history
112
- messages.push({ role: 'assistant', content: assistantResponse });
113
- }
114
- catch (error) {
115
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
116
- }
117
- rl.prompt();
118
- });
119
- rl.on('close', () => {
120
- console.log(chalk.gray('\nChat session ended.'));
121
- process.exit(0);
122
- });
123
- // Initial prompt
124
- rl.prompt();
125
- }
@@ -1,6 +0,0 @@
1
- export interface ConfigOptions {
2
- configFilePath?: string;
3
- }
4
- export declare function configGetCommand(key?: string, options?: ConfigOptions): Promise<void>;
5
- export declare function configSetCommand(key: string, value: string, options?: ConfigOptions): Promise<void>;
6
- export declare function configListCommand(options?: ConfigOptions): Promise<void>;