compact-agent 1.22.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +11 -0
- package/dist/api.js +65 -15
- package/dist/api.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -1
- package/dist/key-rotation.d.ts +54 -0
- package/dist/key-rotation.js +117 -0
- package/dist/key-rotation.js.map +1 -0
- package/dist/swarm.d.ts +70 -0
- package/dist/swarm.js +119 -0
- package/dist/swarm.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -2,7 +2,18 @@ import OpenAI from 'openai';
|
|
|
2
2
|
import type { CrowcoderConfig, Message } from './types.js';
|
|
3
3
|
import type { Tool } from './tools/types.js';
|
|
4
4
|
export declare function getClient(config: CrowcoderConfig): OpenAI;
|
|
5
|
+
/**
|
|
6
|
+
* Same as getClient but explicitly reports the active key in use, so
|
|
7
|
+
* callers (streamChat) can attribute success/failure back to the
|
|
8
|
+
* specific key for rotation health-tracking.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getClientWithKey(config: CrowcoderConfig): {
|
|
11
|
+
client: OpenAI;
|
|
12
|
+
activeKey: string;
|
|
13
|
+
};
|
|
5
14
|
export declare function resetClient(): void;
|
|
15
|
+
/** Re-export so callers (index.ts /keys) can introspect pool status. */
|
|
16
|
+
export { reportFailure, reportSuccess, poolSize } from './key-rotation.js';
|
|
6
17
|
export declare function toolsToFunctions(tools: Tool[]): OpenAI.Chat.ChatCompletionTool[];
|
|
7
18
|
export declare function streamChat(config: CrowcoderConfig, messages: Message[], tools: Tool[], signal?: AbortSignal): AsyncGenerator<{
|
|
8
19
|
type: 'text' | 'thinking' | 'tool_call' | 'done';
|
package/dist/api.js
CHANGED
|
@@ -1,32 +1,63 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
2
|
import { withRetry } from './retry.js';
|
|
3
|
+
import { setPool, pickKey, reportFailure, reportSuccess, poolSize } from './key-rotation.js';
|
|
3
4
|
let client = null;
|
|
4
5
|
let lastConfigHash = '';
|
|
6
|
+
let lastClientKey = ''; // which key the current client was built with
|
|
5
7
|
function configHash(config) {
|
|
6
|
-
|
|
8
|
+
// The client cache key depends on the CURRENT pool key, not the config
|
|
9
|
+
// apiKey, so a rotation picks a fresh client without re-checking config.
|
|
10
|
+
const poolKeys = (config.apiKeys || []).join(',');
|
|
11
|
+
return `${config.baseURL}:${config.apiKey}:${poolKeys}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Sync the rotation pool with the latest config. Called from getClient
|
|
15
|
+
* on every request so /config or env-var changes flow through.
|
|
16
|
+
*/
|
|
17
|
+
function syncPool(config) {
|
|
18
|
+
setPool(config.apiKey, config.apiKeys || []);
|
|
7
19
|
}
|
|
8
20
|
export function getClient(config) {
|
|
21
|
+
syncPool(config);
|
|
22
|
+
// Pick the current key from the pool (round-robin, skipping cool keys).
|
|
23
|
+
// Falls back to config.apiKey when the pool is empty or all keys are
|
|
24
|
+
// cool — the original request will fail with a clear error in that
|
|
25
|
+
// case, which is the right behavior.
|
|
26
|
+
const activeKey = pickKey() || config.apiKey;
|
|
9
27
|
const hash = configHash(config);
|
|
10
|
-
if (!client || hash !== lastConfigHash) {
|
|
28
|
+
if (!client || hash !== lastConfigHash || activeKey !== lastClientKey) {
|
|
11
29
|
const isAnthropic = config.baseURL.includes('anthropic.com');
|
|
12
30
|
client = new OpenAI({
|
|
13
|
-
apiKey:
|
|
31
|
+
apiKey: activeKey || 'not-needed',
|
|
14
32
|
baseURL: config.baseURL,
|
|
15
33
|
...(isAnthropic ? {
|
|
16
34
|
defaultHeaders: {
|
|
17
|
-
'x-api-key':
|
|
35
|
+
'x-api-key': activeKey,
|
|
18
36
|
'anthropic-version': '2023-06-01',
|
|
19
37
|
},
|
|
20
38
|
} : {}),
|
|
21
39
|
});
|
|
22
40
|
lastConfigHash = hash;
|
|
41
|
+
lastClientKey = activeKey;
|
|
23
42
|
}
|
|
24
43
|
return client;
|
|
25
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Same as getClient but explicitly reports the active key in use, so
|
|
47
|
+
* callers (streamChat) can attribute success/failure back to the
|
|
48
|
+
* specific key for rotation health-tracking.
|
|
49
|
+
*/
|
|
50
|
+
export function getClientWithKey(config) {
|
|
51
|
+
const c = getClient(config);
|
|
52
|
+
return { client: c, activeKey: lastClientKey };
|
|
53
|
+
}
|
|
26
54
|
export function resetClient() {
|
|
27
55
|
client = null;
|
|
28
56
|
lastConfigHash = '';
|
|
57
|
+
lastClientKey = '';
|
|
29
58
|
}
|
|
59
|
+
/** Re-export so callers (index.ts /keys) can introspect pool status. */
|
|
60
|
+
export { reportFailure, reportSuccess, poolSize } from './key-rotation.js';
|
|
30
61
|
export function toolsToFunctions(tools) {
|
|
31
62
|
return tools.map((t) => ({
|
|
32
63
|
type: 'function',
|
|
@@ -38,21 +69,40 @@ export function toolsToFunctions(tools) {
|
|
|
38
69
|
}));
|
|
39
70
|
}
|
|
40
71
|
export async function* streamChat(config, messages, tools, signal) {
|
|
41
|
-
|
|
72
|
+
// Capture the active key so we can attribute success/failure to it
|
|
73
|
+
// for the rotation health tracker. Multi-key users (multiple OpenRouter
|
|
74
|
+
// accounts) get automatic round-robin when a key 429s or exhausts quota.
|
|
75
|
+
const { client: api, activeKey } = getClientWithKey(config);
|
|
42
76
|
const toolDefs = toolsToFunctions(tools);
|
|
43
77
|
// Bail early if the caller already cancelled before we even started
|
|
44
78
|
if (signal?.aborted)
|
|
45
79
|
throw new Error('Aborted before stream start');
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
80
|
+
let stream;
|
|
81
|
+
try {
|
|
82
|
+
stream = await withRetry(() => api.chat.completions.create({
|
|
83
|
+
model: config.model,
|
|
84
|
+
messages: messages,
|
|
85
|
+
tools: toolDefs.length > 0 ? toolDefs : undefined,
|
|
86
|
+
max_tokens: config.maxTokens,
|
|
87
|
+
temperature: config.temperature,
|
|
88
|
+
stream: true,
|
|
89
|
+
// OpenAI SDK supports cancellation via signal; pass it through
|
|
90
|
+
// so the underlying fetch can be aborted on Steer.
|
|
91
|
+
}, signal ? { signal } : undefined), { maxRetries: 3, baseDelay: 1000, maxDelay: 30000 });
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
// Hand the failure to the rotation pool so subsequent calls skip
|
|
95
|
+
// this key for the cool-down window. Re-throw so the outer error
|
|
96
|
+
// handling (auto-fallback model, error UI) still fires.
|
|
97
|
+
if (activeKey && poolSize() > 1)
|
|
98
|
+
reportFailure(activeKey, err);
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
// If we get this far, the request was at least accepted — record success.
|
|
102
|
+
// (We don't wait for completion; mid-stream errors are vanishingly rare
|
|
103
|
+
// for OpenAI-compatible APIs vs upfront 4xx/5xx).
|
|
104
|
+
if (activeKey && poolSize() > 1)
|
|
105
|
+
reportSuccess(activeKey);
|
|
56
106
|
let currentText = '';
|
|
57
107
|
const toolCallAccumulator = new Map();
|
|
58
108
|
for await (const chunk of stream) {
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -136,7 +136,7 @@ function validateConfig(config) {
|
|
|
136
136
|
config.permissionMode = 'ask';
|
|
137
137
|
}
|
|
138
138
|
// Warn on unexpected fields
|
|
139
|
-
const expectedFields = new Set(['apiKey', 'baseURL', 'model', 'fallbackModel', 'provider', 'maxTokens', 'temperature', 'permissionMode', 'alwaysAllowedTools', 'dryRun', 'theme', 'palette', 'showThinking', 'voice', 'memory', 'sandbox']);
|
|
139
|
+
const expectedFields = new Set(['apiKey', 'apiKeys', 'baseURL', 'model', 'fallbackModel', 'provider', 'maxTokens', 'temperature', 'permissionMode', 'alwaysAllowedTools', 'dryRun', 'theme', 'palette', 'showThinking', 'voice', 'memory', 'sandbox']);
|
|
140
140
|
for (const key in config) {
|
|
141
141
|
if (!expectedFields.has(key) && !_alreadyWarnedFields.has(key)) {
|
|
142
142
|
_alreadyWarnedFields.add(key);
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,10 @@ import * as mempalace from './mempalace/index.js';
|
|
|
61
61
|
import { runCurator } from './curator.js';
|
|
62
62
|
// Sandbox — OS-native isolation for bash tool (/sandbox)
|
|
63
63
|
import { status as sandboxStatus } from './sandbox.js';
|
|
64
|
+
// API key rotation pool (/keys)
|
|
65
|
+
import { listStatus as keyPoolStatus } from './key-rotation.js';
|
|
66
|
+
// Agentic swarm — fan-out concurrent agents on the same task (/swarm)
|
|
67
|
+
import { runSwarm, resolveAgents, formatSwarmResults } from './swarm.js';
|
|
64
68
|
// Voice / accessibility — built-in dictation (Whisper) + readout (ElevenLabs)
|
|
65
69
|
import { printVoiceStatus, isVoiceEnabled, getTtsConfig, getSttConfig, getAccessibilityConfig, speak, dictateOnce, } from './voice.js';
|
|
66
70
|
import { isFfmpegAvailable, audioCue, startRecording, probeMic, micProbeMessage } from './audio.js';
|
|
@@ -197,6 +201,7 @@ export function handleSlashCommand(input, config, messages, session, mode) {
|
|
|
197
201
|
console.log(d(' ') + c('/models') + d(' — list available models for provider'));
|
|
198
202
|
console.log(d(' ') + c('/fallback [model]') + d(' — set/show the model auto-retried on cryptic provider errors'));
|
|
199
203
|
console.log(d(' ') + c('/provider') + d(' — show provider info'));
|
|
204
|
+
console.log(d(' ') + c('/keys [add|rm]') + d(' — multi-key rotation pool (e.g. several OpenRouter accounts)'));
|
|
200
205
|
console.log(d(' ') + c('/route') + d(' — auto-route model based on next message'));
|
|
201
206
|
console.log(h('\n ── Modes ──'));
|
|
202
207
|
console.log(d(' ') + c('/mode [name]') + d(' — switch mode (dev/review/tdd/research/plan/debug/architect/hermes/design)'));
|
|
@@ -254,6 +259,7 @@ export function handleSlashCommand(input, config, messages, session, mode) {
|
|
|
254
259
|
// silent aliases for power users but are not listed here.
|
|
255
260
|
console.log(h('\n ── Orchestration ──'));
|
|
256
261
|
console.log(d(' ') + c('/orchestrate <task>') + d(' — decompose into parallel sub-agents'));
|
|
262
|
+
console.log(d(' ') + c('/swarm <agents> <task>') + d(' — true parallel fan-out: N agents on same task, results merged with attribution'));
|
|
257
263
|
console.log(d(' ') + c('/pr-loop') + d(' — autonomous PR review loop'));
|
|
258
264
|
console.log(d(' ') + c('/multi-plan <task>') + d(' — multi-agent planning'));
|
|
259
265
|
console.log(d(' ') + c('/multi-execute') + d(' — multi-agent execution'));
|
|
@@ -757,6 +763,30 @@ export function handleSlashCommand(input, config, messages, session, mode) {
|
|
|
757
763
|
mode.current = 'architect';
|
|
758
764
|
const orchPrompt = buildOrchestrationPrompt(args);
|
|
759
765
|
return { handled: false, injectPrompt: orchPrompt };
|
|
766
|
+
// ── Agentic swarm — true parallel fan-out (M3 swarm audit) ──
|
|
767
|
+
// Run N agents concurrently on the same task. Each agent gets its
|
|
768
|
+
// own ECC prompt + the task as user message; outputs are merged
|
|
769
|
+
// with attribution headers. No tools available to swarm agents —
|
|
770
|
+
// analysis only, no file edits.
|
|
771
|
+
//
|
|
772
|
+
// /swarm <agent1,agent2,...> <task>
|
|
773
|
+
//
|
|
774
|
+
// Each agent's request uses the key rotation pool from v1.23.0,
|
|
775
|
+
// so multi-account users get true parallel throughput.
|
|
776
|
+
case '/swarm': {
|
|
777
|
+
// Match: first whitespace-free token is the agents list, rest is task
|
|
778
|
+
const m = args.match(/^(\S+)\s+([\s\S]+)$/);
|
|
779
|
+
if (!m) {
|
|
780
|
+
console.log(chalk.yellow(' Usage: /swarm <agent1,agent2,...> <task>'));
|
|
781
|
+
console.log(chalk.dim(' Example: /swarm code-architect,silent-failure-hunter,type-design-analyzer audit the auth flow'));
|
|
782
|
+
console.log(chalk.dim(' Run /ecc-guide agents to see available agents.'));
|
|
783
|
+
return { handled: true };
|
|
784
|
+
}
|
|
785
|
+
const [, agentsList, task] = m;
|
|
786
|
+
// Use a sentinel + delimiter approach so the main REPL loop can
|
|
787
|
+
// pick up the async swarm dispatch (slash handlers are sync).
|
|
788
|
+
return { handled: false, injectPrompt: '__SWARM__' + agentsList + '|||' + task };
|
|
789
|
+
}
|
|
760
790
|
// ── Verification & Build ─────────────────────────
|
|
761
791
|
case '/verify': {
|
|
762
792
|
const prompt = buildVerifyPrompt(process.cwd(), args || undefined);
|
|
@@ -1555,6 +1585,77 @@ export function handleSlashCommand(input, config, messages, session, mode) {
|
|
|
1555
1585
|
console.log(chalk.dim(' Restart the REPL for the tool to appear in /tools.'));
|
|
1556
1586
|
return { handled: true };
|
|
1557
1587
|
}
|
|
1588
|
+
// ── API key pool (multi-account rotation) ────────────────
|
|
1589
|
+
// /keys show pool with health + stats
|
|
1590
|
+
// /keys add <key> append to the rotation pool
|
|
1591
|
+
// /keys remove <key> remove a specific key (or partial tail-match)
|
|
1592
|
+
// /keys clear empty the extras pool (keeps primary apiKey)
|
|
1593
|
+
case '/keys': {
|
|
1594
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
1595
|
+
const sub = (parts[0] || '').toLowerCase();
|
|
1596
|
+
if (!sub || sub === 'status' || sub === 'list') {
|
|
1597
|
+
const status = keyPoolStatus();
|
|
1598
|
+
if (status.length === 0) {
|
|
1599
|
+
console.log(chalk.dim(' Key pool is empty. /keys add <key> to start rotation.'));
|
|
1600
|
+
return { handled: true };
|
|
1601
|
+
}
|
|
1602
|
+
console.log(chalk.cyan(`\n API key pool (${status.length}):`));
|
|
1603
|
+
for (const k of status) {
|
|
1604
|
+
const health = k.healthy
|
|
1605
|
+
? chalk.green('✓ healthy')
|
|
1606
|
+
: chalk.yellow(`✗ cooling ${k.coolDownRemainingSec}s${k.lastReason ? ' (' + k.lastReason + ')' : ''}`);
|
|
1607
|
+
console.log(chalk.dim(` [${k.index}] ${k.tail} ${health} · ${k.successes} ok / ${k.failures} fail`));
|
|
1608
|
+
}
|
|
1609
|
+
console.log(chalk.dim('\n /keys add <key> add to pool'));
|
|
1610
|
+
console.log(chalk.dim(' /keys remove <tail> drop a key (last-4 char match)'));
|
|
1611
|
+
console.log(chalk.dim(' /keys clear empty the extras pool\n'));
|
|
1612
|
+
return { handled: true };
|
|
1613
|
+
}
|
|
1614
|
+
if (sub === 'add') {
|
|
1615
|
+
const newKey = parts.slice(1).join(' ').trim();
|
|
1616
|
+
if (!newKey) {
|
|
1617
|
+
console.log(chalk.yellow(' Usage: /keys add <api-key>'));
|
|
1618
|
+
return { handled: true };
|
|
1619
|
+
}
|
|
1620
|
+
const extras = (config.apiKeys || []).slice();
|
|
1621
|
+
if (extras.includes(newKey) || newKey === config.apiKey) {
|
|
1622
|
+
console.log(chalk.yellow(' Key already in the pool.'));
|
|
1623
|
+
return { handled: true };
|
|
1624
|
+
}
|
|
1625
|
+
extras.push(newKey);
|
|
1626
|
+
config.apiKeys = extras;
|
|
1627
|
+
saveConfig(config);
|
|
1628
|
+
resetClient();
|
|
1629
|
+
console.log(chalk.green(` Key added (…${newKey.slice(-4)}). Pool size: ${1 + extras.length}.`));
|
|
1630
|
+
return { handled: true };
|
|
1631
|
+
}
|
|
1632
|
+
if (sub === 'remove' || sub === 'rm') {
|
|
1633
|
+
const target = parts[1] || '';
|
|
1634
|
+
if (!target) {
|
|
1635
|
+
console.log(chalk.yellow(' Usage: /keys remove <tail-chars>'));
|
|
1636
|
+
return { handled: true };
|
|
1637
|
+
}
|
|
1638
|
+
const extras = (config.apiKeys || []).filter((k) => !k.endsWith(target) && k !== target);
|
|
1639
|
+
if (extras.length === (config.apiKeys || []).length) {
|
|
1640
|
+
console.log(chalk.yellow(` No key matched "${target}".`));
|
|
1641
|
+
return { handled: true };
|
|
1642
|
+
}
|
|
1643
|
+
config.apiKeys = extras;
|
|
1644
|
+
saveConfig(config);
|
|
1645
|
+
resetClient();
|
|
1646
|
+
console.log(chalk.green(` Key removed. Pool size: ${1 + extras.length}.`));
|
|
1647
|
+
return { handled: true };
|
|
1648
|
+
}
|
|
1649
|
+
if (sub === 'clear') {
|
|
1650
|
+
config.apiKeys = [];
|
|
1651
|
+
saveConfig(config);
|
|
1652
|
+
resetClient();
|
|
1653
|
+
console.log(chalk.green(' Extras pool cleared. Primary key remains.'));
|
|
1654
|
+
return { handled: true };
|
|
1655
|
+
}
|
|
1656
|
+
console.log(chalk.yellow(` Unknown /keys subcommand: ${sub}. Try: status, add, remove, clear`));
|
|
1657
|
+
return { handled: true };
|
|
1658
|
+
}
|
|
1558
1659
|
// ── Sandbox — OS-native isolation for bash tool ──────────
|
|
1559
1660
|
// /sandbox show backend + current level
|
|
1560
1661
|
// /sandbox off|standard|strict
|
|
@@ -2344,6 +2445,38 @@ async function main() {
|
|
|
2344
2445
|
console.log(theme.dim(' [dictate] ') + chalk.white(transcript));
|
|
2345
2446
|
messages.push({ role: 'user', content: transcript });
|
|
2346
2447
|
}
|
|
2448
|
+
else if (result.injectPrompt.startsWith('__SWARM__')) {
|
|
2449
|
+
// Swarm dispatch: __SWARM__<agentsCsv>|||<task>. Same sentinel
|
|
2450
|
+
// trick as /dictate so the slash handler stays sync; the async
|
|
2451
|
+
// fan-out happens here in the main REPL loop where we already
|
|
2452
|
+
// have await + the live config object.
|
|
2453
|
+
const payload = result.injectPrompt.slice('__SWARM__'.length);
|
|
2454
|
+
const sepIdx = payload.indexOf('|||');
|
|
2455
|
+
const agentsCsv = payload.slice(0, sepIdx);
|
|
2456
|
+
const task = payload.slice(sepIdx + 3);
|
|
2457
|
+
const slugs = agentsCsv.split(',').map((s) => s.trim()).filter(Boolean);
|
|
2458
|
+
try {
|
|
2459
|
+
const agents = resolveAgents(slugs);
|
|
2460
|
+
console.log(chalk.cyan(` Swarming ${agents.length} agent(s) in parallel: ${agents.map((a) => a.name).join(', ')}`));
|
|
2461
|
+
console.log(chalk.dim(` Task: ${task.length > 100 ? task.slice(0, 97) + '...' : task}`));
|
|
2462
|
+
const swarmStart = Date.now();
|
|
2463
|
+
const results = await runSwarm(agents, task, config);
|
|
2464
|
+
const output = formatSwarmResults(results);
|
|
2465
|
+
console.log(output);
|
|
2466
|
+
const elapsed = ((Date.now() - swarmStart) / 1000).toFixed(1);
|
|
2467
|
+
const ok = results.filter((r) => !r.error).length;
|
|
2468
|
+
console.log(chalk.dim(`\n swarm complete: ${ok}/${results.length} agent(s) succeeded in ${elapsed}s`));
|
|
2469
|
+
// Push the swarm as conversational context so follow-up
|
|
2470
|
+
// turns can reason about the consolidated output.
|
|
2471
|
+
messages.push({ role: 'user', content: `[/swarm ${agents.map((a) => a.name).join(',')}] ${task}` });
|
|
2472
|
+
messages.push({ role: 'assistant', content: output.slice(0, 8000) });
|
|
2473
|
+
}
|
|
2474
|
+
catch (e) {
|
|
2475
|
+
console.log(chalk.red(` Swarm failed: ${e instanceof Error ? e.message : e}`));
|
|
2476
|
+
}
|
|
2477
|
+
await autoSave(session, messages);
|
|
2478
|
+
continue;
|
|
2479
|
+
}
|
|
2347
2480
|
else {
|
|
2348
2481
|
messages.push({ role: 'user', content: result.injectPrompt });
|
|
2349
2482
|
}
|