@inkeep/agents-cli 0.1.5 → 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 +5306 -20407
- 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/commands/pull.js
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { dirname, extname, join, resolve } from 'node:path';
|
|
4
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
import ora from 'ora';
|
|
7
|
-
import { validateConfiguration } from '../config.js';
|
|
8
|
-
import { compareJsonObjects, getDifferenceSummary } from '../utils/json-comparator.js';
|
|
9
|
-
import { generateTypeScriptFileWithLLM } from './pull.llm-generate.js';
|
|
10
|
-
/**
|
|
11
|
-
* Convert a TypeScript graph file to its JSON representation
|
|
12
|
-
* Uses the exact same approach as the push command
|
|
13
|
-
*/
|
|
14
|
-
export async function convertTypeScriptToJson(graphPath) {
|
|
15
|
-
// Resolve the absolute path
|
|
16
|
-
const absolutePath = resolve(process.cwd(), graphPath);
|
|
17
|
-
// Check if file exists
|
|
18
|
-
if (!existsSync(absolutePath)) {
|
|
19
|
-
throw new Error(`File not found: ${absolutePath}`);
|
|
20
|
-
}
|
|
21
|
-
// Check if this is a TypeScript file
|
|
22
|
-
const ext = extname(absolutePath);
|
|
23
|
-
if (ext === '.ts') {
|
|
24
|
-
// For TypeScript files, we need to use tsx to run this entire command
|
|
25
|
-
// Check if we're already running under tsx
|
|
26
|
-
if (!process.env.TSX_RUNNING) {
|
|
27
|
-
// Re-run this function with tsx - just like push does
|
|
28
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
29
|
-
const __dirname = dirname(__filename);
|
|
30
|
-
const pullPath = resolve(__dirname, '../commands/pull.js');
|
|
31
|
-
return new Promise((resolve, reject) => {
|
|
32
|
-
const child = spawn('npx', ['tsx', pullPath, 'convert', graphPath], {
|
|
33
|
-
cwd: process.cwd(),
|
|
34
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
35
|
-
env: {
|
|
36
|
-
...process.env,
|
|
37
|
-
TSX_RUNNING: '1',
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
let stdout = '';
|
|
41
|
-
let stderr = '';
|
|
42
|
-
child.stdout.on('data', (data) => {
|
|
43
|
-
stdout += data.toString();
|
|
44
|
-
});
|
|
45
|
-
child.stderr.on('data', (data) => {
|
|
46
|
-
stderr += data.toString();
|
|
47
|
-
});
|
|
48
|
-
child.on('error', (error) => {
|
|
49
|
-
reject(new Error(`Failed to load TypeScript file: ${error.message}`));
|
|
50
|
-
});
|
|
51
|
-
child.on('exit', (code) => {
|
|
52
|
-
if (code === 0) {
|
|
53
|
-
try {
|
|
54
|
-
// Look for JSON markers in stdout
|
|
55
|
-
const jsonStartMarker = '===JSON_START===';
|
|
56
|
-
const jsonEndMarker = '===JSON_END===';
|
|
57
|
-
const startIndex = stdout.indexOf(jsonStartMarker);
|
|
58
|
-
const endIndex = stdout.indexOf(jsonEndMarker);
|
|
59
|
-
if (startIndex === -1 || endIndex === -1) {
|
|
60
|
-
reject(new Error('JSON markers not found in output'));
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const jsonString = stdout
|
|
64
|
-
.substring(startIndex + jsonStartMarker.length, endIndex)
|
|
65
|
-
.trim();
|
|
66
|
-
const result = JSON.parse(jsonString);
|
|
67
|
-
resolve(result);
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
reject(new Error(`Failed to parse conversion result: ${error}`));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
reject(new Error(`Conversion failed: ${stderr}`));
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// Now we can import the module (either JS directly, or TS via tsx)
|
|
81
|
-
const fileUrl = pathToFileURL(absolutePath).href;
|
|
82
|
-
const module = await import(fileUrl);
|
|
83
|
-
// Validate that exactly one graph is exported
|
|
84
|
-
const exports = Object.keys(module);
|
|
85
|
-
const graphExports = exports.filter((key) => {
|
|
86
|
-
const value = module[key];
|
|
87
|
-
// Check for AgentGraph-like objects (has required methods)
|
|
88
|
-
return (value &&
|
|
89
|
-
typeof value === 'object' &&
|
|
90
|
-
typeof value.init === 'function' &&
|
|
91
|
-
typeof value.getId === 'function' &&
|
|
92
|
-
typeof value.getName === 'function' &&
|
|
93
|
-
typeof value.getAgents === 'function');
|
|
94
|
-
});
|
|
95
|
-
if (graphExports.length === 0) {
|
|
96
|
-
throw new Error('No AgentGraph exported from configuration file');
|
|
97
|
-
}
|
|
98
|
-
if (graphExports.length > 1) {
|
|
99
|
-
throw new Error(`Multiple AgentGraphs exported from configuration file. Found: ${graphExports.join(', ')}`);
|
|
100
|
-
}
|
|
101
|
-
// Get the graph instance
|
|
102
|
-
const graphKey = graphExports[0];
|
|
103
|
-
const graph = module[graphKey];
|
|
104
|
-
// Get the full graph definition using the same method as push
|
|
105
|
-
return await graph.toFullGraphDefinition();
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* CLI entry point for the converter (used when running with tsx)
|
|
109
|
-
*/
|
|
110
|
-
async function cliConvert(graphPath) {
|
|
111
|
-
try {
|
|
112
|
-
// Suppress ALL console output except our JSON
|
|
113
|
-
const originalConsoleLog = console.log;
|
|
114
|
-
const originalConsoleError = console.error;
|
|
115
|
-
const originalConsoleWarn = console.warn;
|
|
116
|
-
const originalConsoleInfo = console.info;
|
|
117
|
-
// Suppress all console output
|
|
118
|
-
console.log = () => { };
|
|
119
|
-
console.error = () => { };
|
|
120
|
-
console.warn = () => { };
|
|
121
|
-
console.info = () => { };
|
|
122
|
-
const result = await convertTypeScriptToJson(graphPath);
|
|
123
|
-
// Restore console functions
|
|
124
|
-
console.log = originalConsoleLog;
|
|
125
|
-
console.error = originalConsoleError;
|
|
126
|
-
console.warn = originalConsoleWarn;
|
|
127
|
-
console.info = originalConsoleInfo;
|
|
128
|
-
// Output a clear marker before JSON so parent process knows where to start parsing
|
|
129
|
-
console.log('===JSON_START===');
|
|
130
|
-
console.log(JSON.stringify(result, null, 2));
|
|
131
|
-
console.log('===JSON_END===');
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
console.error('Error:', error.message);
|
|
135
|
-
process.exit(1);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
export async function pullCommand(graphId, options) {
|
|
139
|
-
const spinner = ora('Loading configuration...').start();
|
|
140
|
-
try {
|
|
141
|
-
// Validate configuration
|
|
142
|
-
let config;
|
|
143
|
-
try {
|
|
144
|
-
config = await validateConfiguration(options.tenantId, options.apiUrl, options.configFilePath);
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
spinner.fail('Configuration validation failed');
|
|
148
|
-
console.error(chalk.red(error.message));
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
// Get output directory from options or config
|
|
152
|
-
const outputDirectory = options.outputPath || config.outputDirectory || './agent-configurations';
|
|
153
|
-
// Create output directory if it doesn't exist
|
|
154
|
-
const absoluteOutputPath = resolve(process.cwd(), outputDirectory);
|
|
155
|
-
if (!existsSync(absoluteOutputPath)) {
|
|
156
|
-
mkdirSync(absoluteOutputPath, { recursive: true });
|
|
157
|
-
}
|
|
158
|
-
spinner.text = 'Fetching graph from API...';
|
|
159
|
-
// Fetch graph from API
|
|
160
|
-
const response = await fetch(`${config.managementApiUrl}/tenants/${config.tenantId}/crud/projects/${config.projectId}/graph/${graphId}`, {
|
|
161
|
-
method: 'GET',
|
|
162
|
-
headers: {
|
|
163
|
-
'Content-Type': 'application/json',
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
if (!response.ok) {
|
|
167
|
-
if (response.status === 404) {
|
|
168
|
-
spinner.fail(`Graph with ID "${graphId}" not found`);
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
171
|
-
spinner.fail(`Failed to fetch graph: ${response.statusText}`);
|
|
172
|
-
process.exit(1);
|
|
173
|
-
}
|
|
174
|
-
const responseData = await response.json();
|
|
175
|
-
const graphData = responseData.data;
|
|
176
|
-
if (options.json) {
|
|
177
|
-
// Output JSON file
|
|
178
|
-
spinner.text = 'Writing JSON file...';
|
|
179
|
-
const jsonFilePath = join(absoluteOutputPath, `${graphId}.json`);
|
|
180
|
-
writeFileSync(jsonFilePath, JSON.stringify(graphData, null, 2), 'utf-8');
|
|
181
|
-
spinner.succeed(`Graph "${graphData.name}" pulled successfully`);
|
|
182
|
-
console.log(chalk.green(`✅ JSON file created: ${jsonFilePath}`));
|
|
183
|
-
// Display next steps for JSON
|
|
184
|
-
console.log(chalk.cyan('\n✨ Next steps:'));
|
|
185
|
-
console.log(chalk.gray(` • View the file: ${jsonFilePath}`));
|
|
186
|
-
console.log(chalk.gray(` • Use the data in your application`));
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
// Generate TypeScript file using LLM
|
|
190
|
-
spinner.text = 'Generating TypeScript file with LLM...';
|
|
191
|
-
const outputFilePath = join(absoluteOutputPath, `${graphId}.graph.ts`);
|
|
192
|
-
if (!config.modelSettings) {
|
|
193
|
-
spinner.fail('Model Settings is required for TypeScript generation');
|
|
194
|
-
console.error(chalk.red('Error: No modelSettings found in configuration.'));
|
|
195
|
-
console.error(chalk.yellow('Please add modelSettings to your inkeep.config.ts file.'));
|
|
196
|
-
console.error(chalk.gray('Example:'));
|
|
197
|
-
console.error(chalk.gray(' modelSettings: {'));
|
|
198
|
-
console.error(chalk.gray(' model: "anthropic/claude-3-5-sonnet-20241022",'));
|
|
199
|
-
console.error(chalk.gray(' providerOptions: { anthropic: {} }'));
|
|
200
|
-
console.error(chalk.gray(' }'));
|
|
201
|
-
process.exit(1);
|
|
202
|
-
}
|
|
203
|
-
// Generate TypeScript file with validation and retry logic
|
|
204
|
-
const maxRetries = options.maxRetries || 3;
|
|
205
|
-
let attempt = 1;
|
|
206
|
-
let validationPassed = false;
|
|
207
|
-
let previousDifferences = [];
|
|
208
|
-
while (attempt <= maxRetries && !validationPassed) {
|
|
209
|
-
if (attempt > 1) {
|
|
210
|
-
spinner.text = `Regenerating TypeScript file (attempt ${attempt}/${maxRetries})...`;
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
spinner.text = 'Generating TypeScript file with LLM...';
|
|
214
|
-
}
|
|
215
|
-
await generateTypeScriptFileWithLLM(graphData, graphId, outputFilePath, config.modelSettings, {
|
|
216
|
-
attempt,
|
|
217
|
-
maxRetries,
|
|
218
|
-
previousDifferences: attempt > 1 ? previousDifferences : undefined,
|
|
219
|
-
});
|
|
220
|
-
// Always validate the generated TypeScript file
|
|
221
|
-
spinner.text = 'Validating generated TypeScript file...';
|
|
222
|
-
try {
|
|
223
|
-
// Convert the generated TypeScript back to JSON
|
|
224
|
-
const convertedResult = await convertTypeScriptToJson(outputFilePath);
|
|
225
|
-
// Compare with the original graph data
|
|
226
|
-
const comparison = compareJsonObjects(graphData, convertedResult, {
|
|
227
|
-
ignoreArrayOrder: true,
|
|
228
|
-
ignoreCase: false,
|
|
229
|
-
ignoreWhitespace: false,
|
|
230
|
-
showDetails: true,
|
|
231
|
-
});
|
|
232
|
-
if (comparison.isEqual) {
|
|
233
|
-
validationPassed = true;
|
|
234
|
-
spinner.succeed('TypeScript file validation passed');
|
|
235
|
-
console.log(chalk.green('✅ Generated TypeScript file matches original graph data'));
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
// Collect differences for next retry
|
|
239
|
-
previousDifferences = comparison.differences.map((diff) => `${diff.path}: ${diff.description}`);
|
|
240
|
-
if (attempt < maxRetries) {
|
|
241
|
-
spinner.warn(`Validation failed (attempt ${attempt}/${maxRetries}), retrying...`);
|
|
242
|
-
console.log(chalk.yellow('⚠️ Generated TypeScript file has differences from original graph data:'));
|
|
243
|
-
console.log(chalk.gray(getDifferenceSummary(comparison)));
|
|
244
|
-
console.log(chalk.gray('\n🔄 Retrying with improved prompt...'));
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
// Final attempt failed
|
|
248
|
-
spinner.fail('TypeScript file validation failed after all retries');
|
|
249
|
-
console.log(chalk.red('❌ Generated TypeScript file has differences from original:'));
|
|
250
|
-
console.log(chalk.gray(getDifferenceSummary(comparison)));
|
|
251
|
-
console.log(chalk.yellow('\n💡 You may need to manually edit the generated file or check the LLM configuration.'));
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
catch (validationError) {
|
|
256
|
-
// Collect validation error for next retry
|
|
257
|
-
previousDifferences = [`Validation error: ${validationError.message}`];
|
|
258
|
-
if (attempt < maxRetries) {
|
|
259
|
-
spinner.warn(`Validation failed (attempt ${attempt}/${maxRetries}), retrying...`);
|
|
260
|
-
console.log(chalk.yellow('⚠️ Could not validate generated TypeScript file against original graph data:'));
|
|
261
|
-
console.log(chalk.gray(validationError.message));
|
|
262
|
-
console.log(chalk.gray('This might be due to the generated file having syntax errors or missing dependencies.'));
|
|
263
|
-
console.log(chalk.gray('\n🔄 Retrying with improved prompt...'));
|
|
264
|
-
}
|
|
265
|
-
else {
|
|
266
|
-
// Final attempt failed
|
|
267
|
-
spinner.fail('TypeScript file validation failed after all retries');
|
|
268
|
-
console.log(chalk.red('❌ Could not validate generated TypeScript file against original graph data:'));
|
|
269
|
-
console.log(chalk.gray(validationError.message));
|
|
270
|
-
console.log(chalk.gray('This might be due to the generated file having syntax errors or missing dependencies.'));
|
|
271
|
-
console.log(chalk.yellow('\n💡 You may need to manually edit the generated file or check the LLM configuration.'));
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
attempt++;
|
|
275
|
-
}
|
|
276
|
-
spinner.succeed(`Graph "${graphData.name}" pulled successfully`);
|
|
277
|
-
console.log(chalk.green(`✅ TypeScript file created: ${outputFilePath}`));
|
|
278
|
-
// Display next steps
|
|
279
|
-
console.log(chalk.cyan('\n✨ Next steps:'));
|
|
280
|
-
console.log(chalk.gray(` • Edit the file: ${outputFilePath}`));
|
|
281
|
-
console.log(chalk.gray(` • Test locally: inkeep push ${outputFilePath}`));
|
|
282
|
-
console.log(chalk.gray(` • Version control: git add ${outputFilePath}`));
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
catch (error) {
|
|
286
|
-
spinner.fail('Failed to pull graph');
|
|
287
|
-
console.error(chalk.red('Error:'), error.message);
|
|
288
|
-
if (error.stack && process.env.DEBUG) {
|
|
289
|
-
console.error(chalk.gray(error.stack));
|
|
290
|
-
}
|
|
291
|
-
process.exit(1);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
// CLI entry point for conversion
|
|
295
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
296
|
-
const command = process.argv[2];
|
|
297
|
-
const graphPath = process.argv[3];
|
|
298
|
-
if (command === 'convert' && graphPath) {
|
|
299
|
-
cliConvert(graphPath);
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
console.error('Usage: tsx pull.js convert <graph-path>');
|
|
303
|
-
process.exit(1);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ModelSettings } from '@inkeep/agents-core';
|
|
2
|
-
import type { FullGraphDefinition } from '../types/graph.js';
|
|
3
|
-
/**
|
|
4
|
-
* Generate TypeScript code using LLM to intelligently merge graph data
|
|
5
|
-
*/
|
|
6
|
-
export declare function generateTypeScriptFileWithLLM(graphData: FullGraphDefinition, graphId: string, outputFilePath: string, modelSettings: ModelSettings, retryContext?: {
|
|
7
|
-
attempt: number;
|
|
8
|
-
maxRetries: number;
|
|
9
|
-
previousDifferences?: string[];
|
|
10
|
-
}): Promise<void>;
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { anthropic, createAnthropic } from '@ai-sdk/anthropic';
|
|
2
|
-
import { createOpenAI, openai } from '@ai-sdk/openai';
|
|
3
|
-
import { generateText } from 'ai';
|
|
4
|
-
/**
|
|
5
|
-
* Create a language model instance from configuration
|
|
6
|
-
* Similar to ModelFactory but simplified for CLI use
|
|
7
|
-
*/
|
|
8
|
-
function createModel(config) {
|
|
9
|
-
// Extract from base model settings or use defaults
|
|
10
|
-
const modelString = config.model || 'anthropic/claude-4-sonnet-20250514';
|
|
11
|
-
const providerOptions = config.providerOptions;
|
|
12
|
-
const { provider, modelName } = parseModelString(modelString);
|
|
13
|
-
switch (provider) {
|
|
14
|
-
case 'anthropic':
|
|
15
|
-
if (providerOptions) {
|
|
16
|
-
const provider = createAnthropic(providerOptions);
|
|
17
|
-
return provider(modelName);
|
|
18
|
-
}
|
|
19
|
-
return anthropic(modelName);
|
|
20
|
-
case 'openai':
|
|
21
|
-
if (providerOptions) {
|
|
22
|
-
const provider = createOpenAI(providerOptions);
|
|
23
|
-
return provider(modelName);
|
|
24
|
-
}
|
|
25
|
-
return openai(modelName);
|
|
26
|
-
default:
|
|
27
|
-
throw new Error(`Unsupported provider: ${provider}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Parse model string to extract provider and model name
|
|
32
|
-
*/
|
|
33
|
-
function parseModelString(modelString) {
|
|
34
|
-
if (modelString.includes('/')) {
|
|
35
|
-
const [provider, ...modelParts] = modelString.split('/');
|
|
36
|
-
return {
|
|
37
|
-
provider: provider.toLowerCase(),
|
|
38
|
-
modelName: modelParts.join('/'),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
// Default to anthropic if no provider specified
|
|
42
|
-
return {
|
|
43
|
-
provider: 'anthropic',
|
|
44
|
-
modelName: modelString,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Generate TypeScript code using LLM to intelligently merge graph data
|
|
49
|
-
*/
|
|
50
|
-
export async function generateTypeScriptFileWithLLM(graphData, graphId, outputFilePath, modelSettings, retryContext) {
|
|
51
|
-
const fs = await import('fs');
|
|
52
|
-
// Read existing file content if it exists
|
|
53
|
-
let existingContent = '';
|
|
54
|
-
let fileExists = false;
|
|
55
|
-
try {
|
|
56
|
-
existingContent = fs.readFileSync(outputFilePath, 'utf-8');
|
|
57
|
-
fileExists = true;
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
// File doesn't exist, we'll create a new one
|
|
61
|
-
fileExists = false;
|
|
62
|
-
}
|
|
63
|
-
// Create the model instance
|
|
64
|
-
const model = createModel(modelSettings);
|
|
65
|
-
// Prepare the prompt
|
|
66
|
-
const prompt = createPrompt(graphData, graphId, existingContent, fileExists, retryContext);
|
|
67
|
-
try {
|
|
68
|
-
// Generate the updated code using the LLM
|
|
69
|
-
const { text } = await generateText({
|
|
70
|
-
model,
|
|
71
|
-
prompt,
|
|
72
|
-
temperature: 0.1, // Low temperature for consistent code generation
|
|
73
|
-
maxOutputTokens: 16000, // Increased to handle large TypeScript files
|
|
74
|
-
});
|
|
75
|
-
// Write the generated code to the file
|
|
76
|
-
fs.writeFileSync(outputFilePath, text, 'utf-8');
|
|
77
|
-
console.log(`✅ Successfully generated TypeScript file: ${outputFilePath}`);
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
console.error('❌ Error generating TypeScript file with LLM:', error);
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Create a comprehensive prompt for the LLM to generate/update TypeScript code
|
|
86
|
-
*/
|
|
87
|
-
function createPrompt(graphData, graphId, existingContent, fileExists, retryContext) {
|
|
88
|
-
const graphDataJson = JSON.stringify(graphData, null, 2);
|
|
89
|
-
// Add retry context to the prompt if this is a retry
|
|
90
|
-
const retryInstructions = retryContext && retryContext.attempt > 1
|
|
91
|
-
? `
|
|
92
|
-
RETRY CONTEXT:
|
|
93
|
-
This is attempt ${retryContext.attempt} of ${retryContext.maxRetries}. Previous attempts had validation issues.
|
|
94
|
-
|
|
95
|
-
${retryContext.previousDifferences && retryContext.previousDifferences.length > 0
|
|
96
|
-
? `
|
|
97
|
-
PREVIOUS VALIDATION ISSUES:
|
|
98
|
-
${retryContext.previousDifferences.map((diff, index) => `${index + 1}. ${diff}`).join('\n')}
|
|
99
|
-
|
|
100
|
-
IMPORTANT: Pay special attention to these specific issues and ensure they are resolved in this attempt.
|
|
101
|
-
`
|
|
102
|
-
: ''}
|
|
103
|
-
|
|
104
|
-
CRITICAL: This is a retry attempt. You must be extremely careful to match the exact structure and values from the graph data. Double-check all IDs, names, and configurations.
|
|
105
|
-
`
|
|
106
|
-
: '';
|
|
107
|
-
if (!fileExists) {
|
|
108
|
-
// Create new file
|
|
109
|
-
return `You are an expert TypeScript developer. Generate a complete TypeScript file for an Inkeep agent graph configuration.${retryInstructions}
|
|
110
|
-
|
|
111
|
-
GRAPH DATA (JSON):
|
|
112
|
-
${graphDataJson}
|
|
113
|
-
|
|
114
|
-
GRAPH ID: ${graphId}
|
|
115
|
-
|
|
116
|
-
REQUIREMENTS:
|
|
117
|
-
1. Create a complete TypeScript file that exports an agentGraph configuration
|
|
118
|
-
2. Use the exact structure and patterns shown in the graph data
|
|
119
|
-
3. For agents, use the \`agent()\` function with proper configuration
|
|
120
|
-
4. For MCP tools, use the \`mcpTool()\` function with proper configuration
|
|
121
|
-
5. For context configs, use the \`contextConfig()\` function
|
|
122
|
-
6. For credential references, use the \`credentialReference()\` function
|
|
123
|
-
7. Use proper TypeScript syntax with correct imports
|
|
124
|
-
8. Handle multi-line strings with template literals (backticks) when needed
|
|
125
|
-
9. Preserve the exact structure and relationships from the graph data
|
|
126
|
-
10. Use descriptive variable names based on IDs (e.g., \`qaAgent\`, \`factsTool\`)
|
|
127
|
-
11. Include helpful comments for complex configurations
|
|
128
|
-
12. Preserve all configuration details exactly as provided in the graph data
|
|
129
|
-
|
|
130
|
-
IMPORTANT:
|
|
131
|
-
- If tools array contains numeric indices, use the actual tool IDs instead
|
|
132
|
-
- Preserve all configuration details exactly as provided
|
|
133
|
-
- Use proper TypeScript formatting and indentation
|
|
134
|
-
- Include all necessary imports at the top
|
|
135
|
-
- Add comments for complex objects like GraphQL queries or multi-line instructions
|
|
136
|
-
- Keep the same structure and organization as typical Inkeep graph files
|
|
137
|
-
|
|
138
|
-
CRITICAL: Generate ONLY the raw TypeScript code. Do NOT wrap it in markdown code blocks (no triple backticks with typescript). Do NOT include any explanations, comments, or markdown formatting. Return only the pure TypeScript code that can be written directly to a .ts file.`;
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
// Update existing file
|
|
142
|
-
return `You are an expert TypeScript developer. You must make MINIMAL changes to an existing TypeScript file. Your job is to update ONLY the specific values that have changed, while preserving EVERYTHING else exactly as it is.${retryInstructions}
|
|
143
|
-
|
|
144
|
-
EXISTING FILE CONTENT:
|
|
145
|
-
\`\`\`typescript
|
|
146
|
-
${existingContent}
|
|
147
|
-
\`\`\`
|
|
148
|
-
|
|
149
|
-
NEW GRAPH DATA (JSON):
|
|
150
|
-
${graphDataJson}
|
|
151
|
-
|
|
152
|
-
GRAPH ID: ${graphId}
|
|
153
|
-
|
|
154
|
-
CRITICAL RULES - FOLLOW THESE EXACTLY:
|
|
155
|
-
1. PRESERVE ALL EXISTING CONTENT - Do not delete, rewrite, or restructure anything
|
|
156
|
-
2. ONLY change property values that are actually different between the existing file and new graph data
|
|
157
|
-
3. KEEP ALL COMMENTS - Do not remove any comments unless they are factually incorrect
|
|
158
|
-
4. KEEP ALL FORMATTING - Preserve exact spacing, indentation, line breaks, and code style
|
|
159
|
-
5. KEEP ALL IMPORTS - Do not change import statements
|
|
160
|
-
6. KEEP ALL VARIABLE NAMES - Use the exact same variable names as in the existing file
|
|
161
|
-
7. KEEP ALL STRUCTURE - Do not reorganize code blocks or change the order of definitions
|
|
162
|
-
|
|
163
|
-
WHAT TO CHANGE:
|
|
164
|
-
- Only update property values (like id, name, description, instructions, etc.) that are different
|
|
165
|
-
- If a property value is the same, leave it exactly as it is
|
|
166
|
-
- If a new agent/tool/config is added in the graph data, add it following the existing patterns
|
|
167
|
-
- If an agent/tool/config is removed from the graph data, remove it from the file
|
|
168
|
-
|
|
169
|
-
WHAT NOT TO CHANGE:
|
|
170
|
-
- Do not rewrite entire functions or objects
|
|
171
|
-
- Do not change the structure or organization
|
|
172
|
-
- Do not remove or modify comments
|
|
173
|
-
- Do not change formatting or style
|
|
174
|
-
- Do not reorganize code blocks
|
|
175
|
-
- Do not change variable names or function names
|
|
176
|
-
|
|
177
|
-
EXAMPLES OF MINIMAL CHANGES:
|
|
178
|
-
- If only the description changed: update only that one line
|
|
179
|
-
- If only a tool was added: add only the new tool definition
|
|
180
|
-
- If only a property value changed: update only that specific property
|
|
181
|
-
|
|
182
|
-
CRITICAL: Return ONLY the raw TypeScript code. Do NOT wrap it in markdown code blocks (no triple backticks with typescript). Do NOT include any explanations, comments, or markdown formatting. Return only the pure TypeScript code that can be written directly to a .ts file.`;
|
|
183
|
-
}
|
|
184
|
-
}
|