@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.
- package/SUPPLEMENTAL_TERMS.md +40 -0
- package/dist/commands/create.d.ts +12 -0
- package/dist/commands/create.js +865 -0
- package/dist/config.d.ts +4 -4
- package/dist/index.js +5308 -20409
- package/package.json +15 -6
- package/dist/__tests__/api.test.d.ts +0 -1
- package/dist/__tests__/api.test.js +0 -257
- package/dist/__tests__/cli.test.d.ts +0 -1
- package/dist/__tests__/cli.test.js +0 -153
- package/dist/__tests__/commands/config.test.d.ts +0 -1
- package/dist/__tests__/commands/config.test.js +0 -154
- package/dist/__tests__/commands/init.test.d.ts +0 -1
- package/dist/__tests__/commands/init.test.js +0 -186
- package/dist/__tests__/commands/pull.test.d.ts +0 -1
- package/dist/__tests__/commands/pull.test.js +0 -54
- package/dist/__tests__/commands/push-spinner.test.d.ts +0 -1
- package/dist/__tests__/commands/push-spinner.test.js +0 -127
- package/dist/__tests__/commands/push.test.d.ts +0 -1
- package/dist/__tests__/commands/push.test.js +0 -265
- package/dist/__tests__/config-validation.test.d.ts +0 -1
- package/dist/__tests__/config-validation.test.js +0 -98
- package/dist/__tests__/package.test.d.ts +0 -1
- package/dist/__tests__/package.test.js +0 -82
- package/dist/__tests__/utils/json-comparator.test.d.ts +0 -1
- package/dist/__tests__/utils/json-comparator.test.js +0 -174
- package/dist/__tests__/utils/ts-loader.test.d.ts +0 -1
- package/dist/__tests__/utils/ts-loader.test.js +0 -232
- package/dist/api.d.ts +0 -23
- package/dist/api.js +0 -140
- package/dist/commands/chat-enhanced.d.ts +0 -7
- package/dist/commands/chat-enhanced.js +0 -396
- package/dist/commands/chat.d.ts +0 -5
- package/dist/commands/chat.js +0 -125
- package/dist/commands/config.d.ts +0 -6
- package/dist/commands/config.js +0 -128
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.js +0 -171
- package/dist/commands/list-graphs.d.ts +0 -6
- package/dist/commands/list-graphs.js +0 -131
- package/dist/commands/pull.d.ts +0 -15
- package/dist/commands/pull.js +0 -305
- package/dist/commands/pull.llm-generate.d.ts +0 -10
- package/dist/commands/pull.llm-generate.js +0 -184
- package/dist/commands/push.d.ts +0 -6
- package/dist/commands/push.js +0 -268
- package/dist/exports.d.ts +0 -2
- package/dist/exports.js +0 -2
- package/dist/index.js.map +0 -7
- package/dist/types/config.d.ts +0 -9
- package/dist/types/config.js +0 -3
- package/dist/types/graph.d.ts +0 -10
- package/dist/types/graph.js +0 -1
- package/dist/utils/json-comparator.d.ts +0 -60
- package/dist/utils/json-comparator.js +0 -222
- package/dist/utils/mcp-runner.d.ts +0 -6
- package/dist/utils/mcp-runner.js +0 -147
- package/dist/utils/ts-loader.d.ts +0 -5
- 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,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
|
-
}
|
package/dist/commands/chat.d.ts
DELETED
package/dist/commands/chat.js
DELETED
|
@@ -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>;
|