snow-flow 4.0.3 → 4.1.1
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/README.md +15 -40
- package/dist/cli.js +0 -81
- package/dist/dynamic-version.js +1 -1
- package/dist/index.js +3 -1
- package/dist/intelligence/performance-recommendations-engine.js +1 -0
- package/dist/mcp/servicenow-local-development-mcp.d.ts +0 -3
- package/dist/mcp/servicenow-local-development-mcp.js +7 -204
- package/dist/memory/snow-flow-memory-patterns.d.ts +29 -30
- package/dist/memory/snow-flow-memory-patterns.js +26 -37
- package/dist/snow-flow-system.js +1 -0
- package/dist/testing/integration-test-suite.js +1 -0
- package/dist/utils/artifact-local-sync.js +0 -17
- package/dist/utils/artifact-sync/artifact-registry.js +10 -10
- package/dist/utils/smart-field-fetcher.js +4 -6
- package/package.json +2 -2
- package/dist/agent/interactive.d.ts +0 -11
- package/dist/agent/interactive.js +0 -190
- package/dist/agent/session.d.ts +0 -12
- package/dist/agent/session.js +0 -106
- package/dist/cli/auth.d.ts +0 -3
- package/dist/cli/auth.js +0 -59
- package/dist/cli/session.d.ts +0 -3
- package/dist/cli/session.js +0 -46
- package/dist/llm/keys.d.ts +0 -5
- package/dist/llm/keys.js +0 -29
- package/dist/llm/providers.d.ts +0 -11
- package/dist/llm/providers.js +0 -77
- package/dist/mcp/bridge.d.ts +0 -10
- package/dist/mcp/bridge.js +0 -31
- package/dist/mcp/shared/mcp-types.d.ts +0 -37
- package/dist/mcp/shared/mcp-types.js +0 -7
- package/dist/memory/hierarchical-memory-system.d.ts +0 -32
- package/dist/memory/hierarchical-memory-system.js +0 -60
- package/dist/memory/memory-system.d.ts +0 -25
- package/dist/memory/memory-system.js +0 -36
- package/dist/session/store.d.ts +0 -47
- package/dist/session/store.js +0 -74
- package/dist/utils/chunking-manager.d.ts +0 -39
- package/dist/utils/chunking-manager.js +0 -142
|
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.IntegrationTestSuite = void 0;
|
|
11
11
|
const logger_js_1 = require("../utils/logger.js");
|
|
12
12
|
const servicenow_client_js_1 = require("../utils/servicenow-client.js");
|
|
13
|
+
const memory_system_js_1 = require("../memory/memory-system.js");
|
|
13
14
|
class IntegrationTestSuite {
|
|
14
15
|
constructor() {
|
|
15
16
|
// Flow-related systems removed in v1.4.0
|
|
@@ -47,7 +47,6 @@ const fs = __importStar(require("fs"));
|
|
|
47
47
|
const path = __importStar(require("path"));
|
|
48
48
|
const smart_field_fetcher_js_1 = require("./smart-field-fetcher.js");
|
|
49
49
|
const mcp_timeout_config_js_1 = require("./mcp-timeout-config.js");
|
|
50
|
-
const chunking_manager_js_1 = require("./chunking-manager.js");
|
|
51
50
|
const artifact_registry_1 = require("./artifact-sync/artifact-registry");
|
|
52
51
|
class ArtifactLocalSync {
|
|
53
52
|
constructor(client, customBaseDir) {
|
|
@@ -286,22 +285,6 @@ class ArtifactLocalSync {
|
|
|
286
285
|
}
|
|
287
286
|
// Map back to ServiceNow field
|
|
288
287
|
if (file.field && file.field !== 'documentation' && file.field !== 'metadata') {
|
|
289
|
-
// Check if field needs chunking (large server scripts)
|
|
290
|
-
if (chunking_manager_js_1.ChunkingManager.needsChunking(processedContent)) {
|
|
291
|
-
console.log(` ⚠️ Large field detected: ${file.field} (${processedContent.length} chars)`);
|
|
292
|
-
// Attempt chunked update
|
|
293
|
-
const chunkResult = await chunking_manager_js_1.ChunkingManager.attemptChunkedUpdate(this.client, config.tableName, sys_id, file.field, processedContent);
|
|
294
|
-
if (!chunkResult.success) {
|
|
295
|
-
// Add to validation results as a manual instruction
|
|
296
|
-
validationResults.push({
|
|
297
|
-
valid: false,
|
|
298
|
-
errors: [],
|
|
299
|
-
warnings: [`Large ${file.field} requires manual update`],
|
|
300
|
-
hints: [chunkResult.message]
|
|
301
|
-
});
|
|
302
|
-
continue; // Skip adding to updates
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
288
|
updates[file.field] = processedContent;
|
|
306
289
|
console.log(` 📝 Changed: ${file.filename} (${file.field})`);
|
|
307
290
|
// Validate ES5 if required
|
|
@@ -33,7 +33,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
33
33
|
fileExtension: 'html',
|
|
34
34
|
description: 'HTML template with Angular bindings',
|
|
35
35
|
wrapperHeader: '<!-- ServiceNow Widget Template: {name} -->\n<!-- Angular bindings: {{data.x}}, ng-click="method()" -->\n\n',
|
|
36
|
-
maxTokens:
|
|
36
|
+
maxTokens: 20000,
|
|
37
37
|
isRequired: true
|
|
38
38
|
},
|
|
39
39
|
{
|
|
@@ -43,7 +43,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
43
43
|
description: 'Server-side script (ES5 ONLY)',
|
|
44
44
|
wrapperHeader: '/**\n * Server Script for Widget: {name}\n * ES5 ONLY - No arrow functions, const/let, template literals\n * Available: data, input, options, gs, $sp\n */\n\n(function() {\n',
|
|
45
45
|
wrapperFooter: '\n})();',
|
|
46
|
-
maxTokens:
|
|
46
|
+
maxTokens: 20000,
|
|
47
47
|
isRequired: false,
|
|
48
48
|
validateES5: true
|
|
49
49
|
},
|
|
@@ -54,7 +54,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
54
54
|
description: 'Client-side AngularJS controller',
|
|
55
55
|
wrapperHeader: '/**\n * Client Controller for Widget: {name}\n * AngularJS 1.x\n * Available: c (this), c.data, c.server, $scope\n */\n\nfunction(',
|
|
56
56
|
wrapperFooter: ')',
|
|
57
|
-
maxTokens:
|
|
57
|
+
maxTokens: 20000,
|
|
58
58
|
isRequired: false
|
|
59
59
|
},
|
|
60
60
|
{
|
|
@@ -63,7 +63,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
63
63
|
fileExtension: 'css',
|
|
64
64
|
description: 'Widget-specific CSS styles',
|
|
65
65
|
wrapperHeader: '/* Styles for Widget: {name} */\n/* Prefix classes to avoid conflicts */\n\n',
|
|
66
|
-
maxTokens:
|
|
66
|
+
maxTokens: 20000,
|
|
67
67
|
isRequired: false
|
|
68
68
|
},
|
|
69
69
|
{
|
|
@@ -243,7 +243,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
243
243
|
description: 'Business rule script',
|
|
244
244
|
wrapperHeader: '/**\n * Business Rule: {name}\n * Table: {collection}\n * When: {when}\n * Order: {order}\n * Available: current, previous, gs, g_scratchpad\n */\n\n(function executeRule(current, previous /*null when async*/) {\n',
|
|
245
245
|
wrapperFooter: '\n})(current, previous);',
|
|
246
|
-
maxTokens:
|
|
246
|
+
maxTokens: 20000,
|
|
247
247
|
isRequired: true,
|
|
248
248
|
validateES5: true
|
|
249
249
|
},
|
|
@@ -281,7 +281,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
281
281
|
localFileName: '{name}.client',
|
|
282
282
|
fileExtension: 'js',
|
|
283
283
|
description: 'Client-side JavaScript',
|
|
284
|
-
maxTokens:
|
|
284
|
+
maxTokens: 20000,
|
|
285
285
|
isRequired: false
|
|
286
286
|
},
|
|
287
287
|
{
|
|
@@ -289,7 +289,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
289
289
|
localFileName: '{name}.server',
|
|
290
290
|
fileExtension: 'js',
|
|
291
291
|
description: 'Server-side processing script (ES5)',
|
|
292
|
-
maxTokens:
|
|
292
|
+
maxTokens: 20000,
|
|
293
293
|
isRequired: false,
|
|
294
294
|
validateES5: true
|
|
295
295
|
}
|
|
@@ -310,7 +310,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
310
310
|
fileExtension: 'js',
|
|
311
311
|
description: 'Client-side form script',
|
|
312
312
|
wrapperHeader: '/**\n * Client Script: {name}\n * Table: {table}\n * Type: {type}\n * Available: g_form, g_user, g_list\n */\n\n',
|
|
313
|
-
maxTokens:
|
|
313
|
+
maxTokens: 20000,
|
|
314
314
|
isRequired: true
|
|
315
315
|
}
|
|
316
316
|
]
|
|
@@ -375,7 +375,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
375
375
|
localFileName: '{name}',
|
|
376
376
|
fileExtension: 'js',
|
|
377
377
|
description: 'Transform map script',
|
|
378
|
-
maxTokens:
|
|
378
|
+
maxTokens: 20000,
|
|
379
379
|
isRequired: false,
|
|
380
380
|
validateES5: true
|
|
381
381
|
}
|
|
@@ -396,7 +396,7 @@ exports.ARTIFACT_REGISTRY = {
|
|
|
396
396
|
fileExtension: 'js',
|
|
397
397
|
description: 'Scheduled job script (ES5)',
|
|
398
398
|
wrapperHeader: '/**\n * Scheduled Job: {name}\n * Run as: {run_as}\n * Time zone: {time_zone}\n */\n\n',
|
|
399
|
-
maxTokens:
|
|
399
|
+
maxTokens: 20000,
|
|
400
400
|
isRequired: true,
|
|
401
401
|
validateES5: true
|
|
402
402
|
}
|
|
@@ -130,8 +130,8 @@ class SmartFieldFetcher {
|
|
|
130
130
|
description: group.description,
|
|
131
131
|
fields: group.fields
|
|
132
132
|
};
|
|
133
|
-
//
|
|
134
|
-
Object.assign(results, response);
|
|
133
|
+
// Add to flat structure for easy access
|
|
134
|
+
Object.assign(results, response.result[0]);
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
catch (error) {
|
|
@@ -232,9 +232,8 @@ class SmartFieldFetcher {
|
|
|
232
232
|
// Try using getRecord instead of searchRecords with short timeout
|
|
233
233
|
const directResponse = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.getRecord('sp_widget', sys_id), 5000, // 5 second timeout for direct fetch
|
|
234
234
|
`Direct widget fetch ${sys_id}`);
|
|
235
|
-
if (directResponse) {
|
|
236
|
-
|
|
237
|
-
const directData = directResponse;
|
|
235
|
+
if (directResponse && directResponse.success && directResponse.data && directResponse.data.result) {
|
|
236
|
+
const directData = directResponse.data.result;
|
|
238
237
|
// Merge any new data we got
|
|
239
238
|
Object.assign(results, directData);
|
|
240
239
|
console.log(`📊 Direct API retrieved:`);
|
|
@@ -293,7 +292,6 @@ class SmartFieldFetcher {
|
|
|
293
292
|
console.log(` 📄 Fetching field: ${field}`);
|
|
294
293
|
const response = await this.client.getRecord(table, sys_id);
|
|
295
294
|
if (response) {
|
|
296
|
-
// FIX: getRecord returns direct object
|
|
297
295
|
result.data[field] = response[field];
|
|
298
296
|
result._field_status[field] = 'success';
|
|
299
297
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.1.1",
|
|
4
|
+
"description": "ENTERPRISE SCALE - v4.1.0 removes ALL artificial limits! Built on stable v3.6.25 with enterprise-grade support for massive widgets (5MB+ scripts), 200k token fields, and 100k record queries.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { SnowFlowConfig } from '../config/llm-config-loader';
|
|
2
|
-
import type { ProviderOptions } from '../llm/providers';
|
|
3
|
-
export interface InteractiveOptions extends ProviderOptions {
|
|
4
|
-
system?: string;
|
|
5
|
-
mcp: SnowFlowConfig['mcp'];
|
|
6
|
-
maxSteps?: number;
|
|
7
|
-
showReasoning?: boolean;
|
|
8
|
-
resumeId?: string;
|
|
9
|
-
}
|
|
10
|
-
export declare function runInteractive(opts: InteractiveOptions): Promise<void>;
|
|
11
|
-
//# sourceMappingURL=interactive.d.ts.map
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.runInteractive = runInteractive;
|
|
7
|
-
const bridge_1 = require("../mcp/bridge");
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const boxen_1 = __importDefault(require("boxen"));
|
|
10
|
-
const node_readline_1 = __importDefault(require("node:readline"));
|
|
11
|
-
const store_js_1 = require("../session/store.js");
|
|
12
|
-
const ora_1 = __importDefault(require("ora"));
|
|
13
|
-
async function runInteractive(opts) {
|
|
14
|
-
const { provider, model, baseURL, apiKeyEnv, system, mcp, maxSteps = 40, showReasoning = true, resumeId } = opts;
|
|
15
|
-
// Resolve model
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
17
|
-
const prov = require('../llm/providers.js');
|
|
18
|
-
const llm = prov.getModel({ provider, model, baseURL, apiKeyEnv });
|
|
19
|
-
const sessionId = resumeId || (0, store_js_1.createSessionId)();
|
|
20
|
-
(0, store_js_1.startSession)({
|
|
21
|
-
id: sessionId,
|
|
22
|
-
startedAt: new Date().toISOString(),
|
|
23
|
-
objective: '(interactive)',
|
|
24
|
-
provider: { id: String(provider), model: String(model), baseURL },
|
|
25
|
-
mcp: { cmd: mcp.cmd, args: mcp.args },
|
|
26
|
-
});
|
|
27
|
-
process.stdout.write(chalk_1.default.bold(`\nSnow-Flow Interactive (${provider}:${model})`) + "\n");
|
|
28
|
-
process.stdout.write(chalk_1.default.gray('Tips: ESC ESC = vorige assistant-antwoord | /quit om te stoppen') + "\n\n");
|
|
29
|
-
// Load tools once with spinner
|
|
30
|
-
const spinner = (0, ora_1.default)('MCP-tools laden...').start();
|
|
31
|
-
const { tools, close } = await (0, bridge_1.loadMCPTools)(mcp).finally(() => spinner.stop());
|
|
32
|
-
const messages = [];
|
|
33
|
-
if (system)
|
|
34
|
-
messages.push({ role: 'system', content: system });
|
|
35
|
-
// Preload previous messages if resuming
|
|
36
|
-
if (resumeId) {
|
|
37
|
-
try {
|
|
38
|
-
const { readSession } = require('../session/store.js');
|
|
39
|
-
const rec = readSession(resumeId);
|
|
40
|
-
if (rec?.messages?.length) {
|
|
41
|
-
const recent = rec.messages.filter((m) => m.role === 'user' || m.role === 'assistant').slice(-20);
|
|
42
|
-
for (const m of recent)
|
|
43
|
-
messages.push({ role: m.role, content: m.content });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch { }
|
|
47
|
-
}
|
|
48
|
-
// Key handling for ESC ESC
|
|
49
|
-
node_readline_1.default.emitKeypressEvents(process.stdin);
|
|
50
|
-
if (process.stdin.isTTY)
|
|
51
|
-
process.stdin.setRawMode(true);
|
|
52
|
-
let lastEsc = 0;
|
|
53
|
-
let lastAssistant = null;
|
|
54
|
-
let showTools = true;
|
|
55
|
-
const onKeypress = (_str, key) => {
|
|
56
|
-
if (!key)
|
|
57
|
-
return;
|
|
58
|
-
if (key.name === 'escape') {
|
|
59
|
-
const now = Date.now();
|
|
60
|
-
if (now - lastEsc < 500) {
|
|
61
|
-
// double ESC
|
|
62
|
-
if (lastAssistant) {
|
|
63
|
-
const box = (0, boxen_1.default)(lastAssistant.slice(0, 1200) + (lastAssistant.length > 1200 ? '…' : ''), { padding: 1, borderColor: 'yellow', title: 'Vorige assistant', titleAlignment: 'center' });
|
|
64
|
-
process.stdout.write('\n' + box + '\n');
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
process.stdout.write(chalk_1.default.gray('\nGeen vorige assistant-respons beschikbaar.') + '\n');
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
lastEsc = now;
|
|
71
|
-
}
|
|
72
|
-
if (key.name === 't') {
|
|
73
|
-
showTools = !showTools;
|
|
74
|
-
process.stdout.write('\n' + (showTools ? chalk_1.default.gray('Tool events: ON') : chalk_1.default.gray('Tool events: OFF')) + '\n');
|
|
75
|
-
}
|
|
76
|
-
if (key.name === 'h') {
|
|
77
|
-
const last = messages.slice(-6);
|
|
78
|
-
const text = last.map(m => `${m.role}> ${m.content}`).join('\n');
|
|
79
|
-
const panel = (0, boxen_1.default)(text, { padding: 1, borderColor: 'blue', title: 'History (tail)', titleAlignment: 'center' });
|
|
80
|
-
process.stdout.write('\n' + panel + '\n');
|
|
81
|
-
}
|
|
82
|
-
if (key.name === 's') {
|
|
83
|
-
const fs = require('fs');
|
|
84
|
-
const out = (lastAssistant || '').toString();
|
|
85
|
-
const outPath = `${process.env.HOME || ''}/.snow-flow/sessions/${sessionId}.txt`;
|
|
86
|
-
try {
|
|
87
|
-
fs.writeFileSync(outPath, out, 'utf8');
|
|
88
|
-
}
|
|
89
|
-
catch { }
|
|
90
|
-
process.stdout.write(chalk_1.default.gray(`Saved assistant output to ${outPath}`) + '\n');
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
process.stdin.on('keypress', onKeypress);
|
|
94
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
95
|
-
const { streamText } = require('ai');
|
|
96
|
-
const rl = node_readline_1.default.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
|
97
|
-
const ask = (q) => new Promise(resolve => rl.question(q, resolve));
|
|
98
|
-
try {
|
|
99
|
-
const onSignal = async () => {
|
|
100
|
-
try {
|
|
101
|
-
await close();
|
|
102
|
-
}
|
|
103
|
-
catch { }
|
|
104
|
-
(0, store_js_1.endSession)(sessionId);
|
|
105
|
-
process.stdout.write('\n' + chalk_1.default.gray('Session ended.') + '\n');
|
|
106
|
-
process.exit(0);
|
|
107
|
-
};
|
|
108
|
-
process.on('SIGINT', onSignal);
|
|
109
|
-
process.on('SIGTERM', onSignal);
|
|
110
|
-
// loop
|
|
111
|
-
while (true) {
|
|
112
|
-
const input = await ask(chalk_1.default.cyan('You: '));
|
|
113
|
-
if (!input)
|
|
114
|
-
continue;
|
|
115
|
-
if (input.trim() === '/quit')
|
|
116
|
-
break;
|
|
117
|
-
const long = input.length > 1200;
|
|
118
|
-
if (long) {
|
|
119
|
-
const preview = input.slice(0, 1200) + '…';
|
|
120
|
-
const box = (0, boxen_1.default)(preview, { padding: 1, borderColor: 'green', title: 'Preview (truncated)', titleAlignment: 'center' });
|
|
121
|
-
process.stdout.write('\n' + box + '\n');
|
|
122
|
-
const confirm = await ask(chalk_1.default.gray('Doorgaan met verzenden? [y/N] '));
|
|
123
|
-
if (!/^y(es)?$/i.test(confirm.trim()))
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
messages.push({ role: 'user', content: input });
|
|
127
|
-
(0, store_js_1.appendMessage)(sessionId, { role: 'user', content: input, timestamp: new Date().toISOString() });
|
|
128
|
-
const result = await streamText({
|
|
129
|
-
model: llm,
|
|
130
|
-
system,
|
|
131
|
-
messages,
|
|
132
|
-
tools,
|
|
133
|
-
maxSteps,
|
|
134
|
-
});
|
|
135
|
-
let buffer = '';
|
|
136
|
-
let inReasoning = false;
|
|
137
|
-
const write = (s) => {
|
|
138
|
-
buffer += s;
|
|
139
|
-
const out = inReasoning && showReasoning ? chalk_1.default.yellow.dim(s) : s;
|
|
140
|
-
process.stdout.write(out);
|
|
141
|
-
};
|
|
142
|
-
if (result.toolCallStream && typeof result.toolCallStream[Symbol.asyncIterator] === 'function') {
|
|
143
|
-
(async () => {
|
|
144
|
-
for await (const ev of result.toolCallStream) {
|
|
145
|
-
const name = ev?.toolName || ev?.name || 'tool';
|
|
146
|
-
const args = ev?.args ? JSON.stringify(ev.args).slice(0, 180) : '';
|
|
147
|
-
if (showTools)
|
|
148
|
-
process.stdout.write('\n' + chalk_1.default.cyan(`🔧 Tool → ${name} ${args}`) + '\n');
|
|
149
|
-
(0, store_js_1.appendToolEvent)(sessionId, { name, argsPreview: args });
|
|
150
|
-
}
|
|
151
|
-
})().catch(() => { });
|
|
152
|
-
}
|
|
153
|
-
if (result.toolResultStream && typeof result.toolResultStream[Symbol.asyncIterator] === 'function') {
|
|
154
|
-
(async () => {
|
|
155
|
-
for await (const ev of result.toolResultStream) {
|
|
156
|
-
const name = ev?.toolName || ev?.name || 'tool';
|
|
157
|
-
const out = ev?.result ? JSON.stringify(ev.result).slice(0, 180) : '';
|
|
158
|
-
if (showTools)
|
|
159
|
-
process.stdout.write(chalk_1.default.magenta(`📦 Result ← ${name} ${out}`) + '\n');
|
|
160
|
-
(0, store_js_1.appendToolEvent)(sessionId, { name, resultPreview: out });
|
|
161
|
-
}
|
|
162
|
-
})().catch(() => { });
|
|
163
|
-
}
|
|
164
|
-
process.stdout.write(chalk_1.default.green('\nAssistant: '));
|
|
165
|
-
for await (const chunk of result.textStream) {
|
|
166
|
-
const s = String(chunk);
|
|
167
|
-
if (showReasoning) {
|
|
168
|
-
if (s.includes('```reasoning') || s.toLowerCase().includes('<thinking>') || /\[\s*reasoning\s*\]/i.test(s))
|
|
169
|
-
inReasoning = true;
|
|
170
|
-
if (s.includes('```') || s.toLowerCase().includes('</thinking>'))
|
|
171
|
-
inReasoning = false;
|
|
172
|
-
}
|
|
173
|
-
write(s);
|
|
174
|
-
}
|
|
175
|
-
process.stdout.write('\n');
|
|
176
|
-
lastAssistant = buffer;
|
|
177
|
-
messages.push({ role: 'assistant', content: buffer });
|
|
178
|
-
(0, store_js_1.appendMessage)(sessionId, { role: 'assistant', content: buffer, timestamp: new Date().toISOString() });
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
finally {
|
|
182
|
-
rl.close();
|
|
183
|
-
process.stdin.off('keypress', onKeypress);
|
|
184
|
-
if (process.stdin.isTTY)
|
|
185
|
-
process.stdin.setRawMode(false);
|
|
186
|
-
await close();
|
|
187
|
-
(0, store_js_1.endSession)(sessionId);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
//# sourceMappingURL=interactive.js.map
|
package/dist/agent/session.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { SnowFlowConfig } from '../config/llm-config-loader';
|
|
2
|
-
import type { ProviderOptions } from '../llm/providers';
|
|
3
|
-
export interface AgentRunOptions extends ProviderOptions {
|
|
4
|
-
system?: string;
|
|
5
|
-
user: string;
|
|
6
|
-
mcp: SnowFlowConfig['mcp'];
|
|
7
|
-
maxSteps?: number;
|
|
8
|
-
showReasoning?: boolean;
|
|
9
|
-
saveOutputPath?: string;
|
|
10
|
-
}
|
|
11
|
-
export declare function runAgent(opts: AgentRunOptions): Promise<void>;
|
|
12
|
-
//# sourceMappingURL=session.d.ts.map
|
package/dist/agent/session.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Agent session placeholder to keep build green.
|
|
3
|
-
// Will be replaced with streaming + tool-calling using the AI SDK.
|
|
4
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
-
};
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.runAgent = runAgent;
|
|
9
|
-
const bridge_1 = require("../mcp/bridge");
|
|
10
|
-
const boxen_1 = __importDefault(require("boxen"));
|
|
11
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
const store_js_1 = require("../session/store.js");
|
|
13
|
-
async function runAgent(opts) {
|
|
14
|
-
const { mcp, system, user, maxSteps = 40, provider, model, baseURL, apiKeyEnv, showReasoning = true, saveOutputPath } = opts;
|
|
15
|
-
// Resolve model via provider registry
|
|
16
|
-
let llm;
|
|
17
|
-
try {
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19
|
-
const prov = require('../llm/providers.js');
|
|
20
|
-
llm = prov.getModel({ provider, model, baseURL, apiKeyEnv });
|
|
21
|
-
}
|
|
22
|
-
catch (e) {
|
|
23
|
-
console.error('❌ LLM provider init error:', e instanceof Error ? e.message : String(e));
|
|
24
|
-
throw e;
|
|
25
|
-
}
|
|
26
|
-
// Load MCP tools (if AI SDK MCP client is available)
|
|
27
|
-
const { tools, close } = await (0, bridge_1.loadMCPTools)(mcp);
|
|
28
|
-
// Stream using AI SDK
|
|
29
|
-
try {
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
31
|
-
const { streamText } = require('ai');
|
|
32
|
-
const sessionId = (0, store_js_1.createSessionId)();
|
|
33
|
-
(0, store_js_1.startSession)({
|
|
34
|
-
id: sessionId,
|
|
35
|
-
startedAt: new Date().toISOString(),
|
|
36
|
-
objective: user,
|
|
37
|
-
provider: { id: String(provider), model: String(model), baseURL },
|
|
38
|
-
mcp: { cmd: mcp.cmd, args: mcp.args },
|
|
39
|
-
});
|
|
40
|
-
(0, store_js_1.appendMessage)(sessionId, { role: 'user', content: user, timestamp: new Date().toISOString() });
|
|
41
|
-
const result = await streamText({
|
|
42
|
-
model: llm,
|
|
43
|
-
system: system ?? 'You are Snow-Flow, a ServiceNow engineering agent. Be precise. Use tools when helpful.',
|
|
44
|
-
messages: [{ role: 'user', content: user }],
|
|
45
|
-
tools,
|
|
46
|
-
maxSteps,
|
|
47
|
-
});
|
|
48
|
-
let buffer = '';
|
|
49
|
-
let inReasoning = false;
|
|
50
|
-
const writeChunk = (s) => {
|
|
51
|
-
buffer += s;
|
|
52
|
-
const colored = inReasoning && showReasoning ? chalk_1.default.yellow.dim(s) : s;
|
|
53
|
-
process.stdout.write(colored);
|
|
54
|
-
};
|
|
55
|
-
// Optional: stream tool call events if provided by SDK
|
|
56
|
-
if (result.toolCallStream && typeof result.toolCallStream[Symbol.asyncIterator] === 'function') {
|
|
57
|
-
(async () => {
|
|
58
|
-
for await (const ev of result.toolCallStream) {
|
|
59
|
-
const name = ev?.toolName || ev?.name || 'tool';
|
|
60
|
-
const args = ev?.args ? JSON.stringify(ev.args).slice(0, 200) : '';
|
|
61
|
-
process.stdout.write('\n' + chalk_1.default.cyan(`🔧 Tool → ${name} ${args}`) + '\n');
|
|
62
|
-
(0, store_js_1.appendToolEvent)(sessionId, { name, argsPreview: args });
|
|
63
|
-
}
|
|
64
|
-
})().catch(() => { });
|
|
65
|
-
}
|
|
66
|
-
if (result.toolResultStream && typeof result.toolResultStream[Symbol.asyncIterator] === 'function') {
|
|
67
|
-
(async () => {
|
|
68
|
-
for await (const ev of result.toolResultStream) {
|
|
69
|
-
const name = ev?.toolName || ev?.name || 'tool';
|
|
70
|
-
const out = ev?.result ? JSON.stringify(ev.result).slice(0, 200) : '';
|
|
71
|
-
process.stdout.write(chalk_1.default.magenta(`📦 Result ← ${name} ${out}`) + '\n');
|
|
72
|
-
(0, store_js_1.appendToolEvent)(sessionId, { name, resultPreview: out });
|
|
73
|
-
}
|
|
74
|
-
})().catch(() => { });
|
|
75
|
-
}
|
|
76
|
-
for await (const chunk of result.textStream) {
|
|
77
|
-
const str = String(chunk);
|
|
78
|
-
// Heuristic: detect reasoning blocks (```reasoning, <thinking>, [reasoning])
|
|
79
|
-
if (showReasoning) {
|
|
80
|
-
if (str.includes('```reasoning') || str.toLowerCase().includes('<thinking>') || /\[\s*reasoning\s*\]/i.test(str))
|
|
81
|
-
inReasoning = true;
|
|
82
|
-
if (str.includes('```') || str.toLowerCase().includes('</thinking>'))
|
|
83
|
-
inReasoning = false;
|
|
84
|
-
}
|
|
85
|
-
writeChunk(str);
|
|
86
|
-
}
|
|
87
|
-
// Render a boxed summary if output is long
|
|
88
|
-
if (buffer.length > 4000) {
|
|
89
|
-
const preview = buffer.slice(0, 1200) + '…';
|
|
90
|
-
const box = (0, boxen_1.default)(preview, { padding: 1, borderColor: 'green', title: 'Preview (truncated)', titleAlignment: 'center' });
|
|
91
|
-
process.stdout.write('\n' + box + '\n');
|
|
92
|
-
process.stdout.write(chalk_1.default.gray(`Full length: ${buffer.length} chars`) + '\n');
|
|
93
|
-
}
|
|
94
|
-
if (saveOutputPath) {
|
|
95
|
-
const fs = require('fs');
|
|
96
|
-
fs.writeFileSync(saveOutputPath, buffer, 'utf8');
|
|
97
|
-
process.stdout.write(chalk_1.default.gray(`Saved full output to ${saveOutputPath}`) + '\n');
|
|
98
|
-
}
|
|
99
|
-
(0, store_js_1.appendMessage)(sessionId, { role: 'assistant', content: buffer, timestamp: new Date().toISOString() });
|
|
100
|
-
(0, store_js_1.endSession)(sessionId);
|
|
101
|
-
}
|
|
102
|
-
finally {
|
|
103
|
-
await close();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
//# sourceMappingURL=session.js.map
|
package/dist/cli/auth.d.ts
DELETED
package/dist/cli/auth.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.registerAuthCommands = registerAuthCommands;
|
|
7
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const keys_js_1 = require("../llm/keys.js");
|
|
10
|
-
function registerAuthCommands(program) {
|
|
11
|
-
const auth = program.command('auth').description('Manage provider API credentials for Snow-Flow');
|
|
12
|
-
auth
|
|
13
|
-
.command('login')
|
|
14
|
-
.description('Interactive login to store API keys for a provider')
|
|
15
|
-
.option('--provider <provider>', 'Provider id (openai|google|openrouter|openai-compatible|ollama)')
|
|
16
|
-
.action(async (opts) => {
|
|
17
|
-
const p = opts.provider || (await inquirer_1.default.prompt([{ name: 'provider', message: 'Provider', type: 'list', choices: ['openai', 'google', 'openrouter', 'openai-compatible', 'ollama'] }])).provider;
|
|
18
|
-
const existing = (0, keys_js_1.getApiKey)(p);
|
|
19
|
-
const { apiKey } = await inquirer_1.default.prompt([{ name: 'apiKey', message: `API key for ${p}${existing ? ' (leave blank to keep existing)' : ''}`, type: 'password', mask: '*' }]);
|
|
20
|
-
if (!apiKey && existing) {
|
|
21
|
-
console.log(chalk_1.default.yellow('Keeping existing key.'));
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (!apiKey) {
|
|
25
|
-
console.error(chalk_1.default.red('No key entered. Aborting.'));
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
(0, keys_js_1.setApiKey)(p, apiKey);
|
|
29
|
-
console.log(chalk_1.default.green(`Saved API key for ${p}.`));
|
|
30
|
-
});
|
|
31
|
-
auth
|
|
32
|
-
.command('set-key')
|
|
33
|
-
.description('Set API key non-interactively')
|
|
34
|
-
.requiredOption('--provider <provider>', 'Provider id')
|
|
35
|
-
.requiredOption('--api-key <key>', 'API key value')
|
|
36
|
-
.action((opts) => {
|
|
37
|
-
(0, keys_js_1.setApiKey)(opts.provider, opts.apiKey);
|
|
38
|
-
console.log(chalk_1.default.green(`Saved API key for ${opts.provider}.`));
|
|
39
|
-
});
|
|
40
|
-
auth
|
|
41
|
-
.command('show')
|
|
42
|
-
.description('Show configured providers (keys partially masked)')
|
|
43
|
-
.action(() => {
|
|
44
|
-
const entries = (0, keys_js_1.listKeys)();
|
|
45
|
-
for (const [p, v] of Object.entries(entries)) {
|
|
46
|
-
const mask = v ? `${v.substring(0, 4)}…${v.substring(v.length - 4)}` : '—';
|
|
47
|
-
console.log(`${p.padEnd(18)} ${mask}`);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
auth
|
|
51
|
-
.command('clear')
|
|
52
|
-
.description('Clear a stored API key')
|
|
53
|
-
.requiredOption('--provider <provider>', 'Provider id')
|
|
54
|
-
.action((opts) => {
|
|
55
|
-
(0, keys_js_1.clearApiKey)(opts.provider);
|
|
56
|
-
console.log(chalk_1.default.yellow(`Cleared API key for ${opts.provider}.`));
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
//# sourceMappingURL=auth.js.map
|
package/dist/cli/session.d.ts
DELETED
package/dist/cli/session.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.registerSessionCommands = registerSessionCommands;
|
|
7
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
-
const store_js_1 = require("../session/store.js");
|
|
9
|
-
function registerSessionCommands(program) {
|
|
10
|
-
const sess = program.command('session').description('Manage and inspect Snow-Flow sessions');
|
|
11
|
-
sess
|
|
12
|
-
.command('list')
|
|
13
|
-
.description('List recent sessions')
|
|
14
|
-
.action(() => {
|
|
15
|
-
const rows = (0, store_js_1.listSessions)().slice(0, 30);
|
|
16
|
-
if (!rows.length)
|
|
17
|
-
return console.log('No sessions yet.');
|
|
18
|
-
for (const r of rows) {
|
|
19
|
-
console.log(`${chalk_1.default.gray(r.startedAt)} ${chalk_1.default.cyan(r.id)} ${r.objective}`);
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
sess
|
|
23
|
-
.command('show <id>')
|
|
24
|
-
.description('Show session details')
|
|
25
|
-
.action((id) => {
|
|
26
|
-
const rec = (0, store_js_1.readSession)(id);
|
|
27
|
-
if (!rec)
|
|
28
|
-
return console.error(chalk_1.default.red('Session not found.'));
|
|
29
|
-
console.log(chalk_1.default.cyan(`Session ${rec.id}`));
|
|
30
|
-
console.log(`${chalk_1.default.gray(rec.startedAt)} → ${chalk_1.default.gray(rec.endedAt ?? '…')}`);
|
|
31
|
-
console.log('Objective:', rec.objective);
|
|
32
|
-
console.log('Provider:', `${rec.provider.id} ${rec.provider.model}`);
|
|
33
|
-
console.log('MCP:', `${rec.mcp.cmd} ${(rec.mcp.args || []).join(' ')}`);
|
|
34
|
-
console.log('\nMessages:');
|
|
35
|
-
for (const m of rec.messages) {
|
|
36
|
-
console.log(`- ${chalk_1.default.yellow(m.role)} ${chalk_1.default.gray(m.timestamp)}\n ${m.content.slice(0, 400)}${m.content.length > 400 ? '…' : ''}`);
|
|
37
|
-
}
|
|
38
|
-
if (rec.toolEvents?.length) {
|
|
39
|
-
console.log('\nTool events:');
|
|
40
|
-
for (const ev of rec.toolEvents) {
|
|
41
|
-
console.log(` 🔧 ${ev.name} ${chalk_1.default.gray(ev.when)} ${ev.argsPreview ? ('args:' + ev.argsPreview) : ''} ${ev.resultPreview ? ('res:' + ev.resultPreview) : ''}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=session.js.map
|
package/dist/llm/keys.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare function setApiKey(provider: string, value: string): void;
|
|
2
|
-
export declare function getApiKey(provider: string): string | undefined;
|
|
3
|
-
export declare function clearApiKey(provider: string): void;
|
|
4
|
-
export declare function listKeys(): Record<string, string | undefined>;
|
|
5
|
-
//# sourceMappingURL=keys.d.ts.map
|
package/dist/llm/keys.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.setApiKey = setApiKey;
|
|
7
|
-
exports.getApiKey = getApiKey;
|
|
8
|
-
exports.clearApiKey = clearApiKey;
|
|
9
|
-
exports.listKeys = listKeys;
|
|
10
|
-
const conf_1 = __importDefault(require("conf"));
|
|
11
|
-
// Avoid generic type for broader compatibility with shimmed types
|
|
12
|
-
const store = new conf_1.default({ projectName: 'snow-flow' });
|
|
13
|
-
function setApiKey(provider, value) {
|
|
14
|
-
store.set(`keys.${provider}`, value);
|
|
15
|
-
}
|
|
16
|
-
function getApiKey(provider) {
|
|
17
|
-
return store.get(`keys.${provider}`);
|
|
18
|
-
}
|
|
19
|
-
function clearApiKey(provider) {
|
|
20
|
-
store.delete(`keys.${provider}`);
|
|
21
|
-
}
|
|
22
|
-
function listKeys() {
|
|
23
|
-
const providers = ['openai', 'google', 'openrouter', 'openai-compatible', 'ollama'];
|
|
24
|
-
const out = {};
|
|
25
|
-
for (const p of providers)
|
|
26
|
-
out[p] = getApiKey(p);
|
|
27
|
-
return out;
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=keys.js.map
|