@calliopelabs/cli 2.3.0 → 2.5.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/README.md +17 -0
- package/dist/agents/agent-config-loader.js +1 -1
- package/dist/agents/agent-config-presets.js +13 -13
- package/dist/agents/agent-config-presets.js.map +1 -1
- package/dist/agents/agent-config-types.d.ts +1 -1
- package/dist/agents/agent-config-types.d.ts.map +1 -1
- package/dist/agents/dynamic-tools.d.ts.map +1 -1
- package/dist/agents/dynamic-tools.js +39 -10
- package/dist/agents/dynamic-tools.js.map +1 -1
- package/dist/agents/sdk-backend.js +1 -1
- package/dist/agents/sdk-backend.js.map +1 -1
- package/dist/api-server.d.ts +9 -0
- package/dist/api-server.d.ts.map +1 -1
- package/dist/api-server.js +74 -3
- package/dist/api-server.js.map +1 -1
- package/dist/auto-checkpoint.d.ts.map +1 -1
- package/dist/auto-checkpoint.js +50 -17
- package/dist/auto-checkpoint.js.map +1 -1
- package/dist/auto-compressor.d.ts.map +1 -1
- package/dist/auto-compressor.js +9 -5
- package/dist/auto-compressor.js.map +1 -1
- package/dist/bin.d.ts +8 -0
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +59 -4
- package/dist/bin.js.map +1 -1
- package/dist/branching.d.ts.map +1 -1
- package/dist/branching.js +14 -1
- package/dist/branching.js.map +1 -1
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +13 -1
- package/dist/checkpoint.js.map +1 -1
- package/dist/cli/agent.d.ts.map +1 -1
- package/dist/cli/agent.js +19 -3
- package/dist/cli/agent.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +99 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +32 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/types.js +1 -1
- package/dist/cli/types.js.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +42 -4
- package/dist/diff.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +30 -3
- package/dist/errors.js.map +1 -1
- package/dist/headless.d.ts.map +1 -1
- package/dist/headless.js +56 -2
- package/dist/headless.js.map +1 -1
- package/dist/hooks.d.ts +8 -2
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +97 -11
- package/dist/hooks.js.map +1 -1
- package/dist/idle-eviction.d.ts.map +1 -1
- package/dist/idle-eviction.js +8 -1
- package/dist/idle-eviction.js.map +1 -1
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +32 -10
- package/dist/markdown.js.map +1 -1
- package/dist/mcp.d.ts +35 -5
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +186 -12
- package/dist/mcp.js.map +1 -1
- package/dist/model-detection.d.ts +14 -1
- package/dist/model-detection.d.ts.map +1 -1
- package/dist/model-detection.js +307 -114
- package/dist/model-detection.js.map +1 -1
- package/dist/model-router.js +7 -7
- package/dist/model-router.js.map +1 -1
- package/dist/parallel-tools.d.ts +9 -1
- package/dist/parallel-tools.d.ts.map +1 -1
- package/dist/parallel-tools.js +6 -5
- package/dist/parallel-tools.js.map +1 -1
- package/dist/plugins.d.ts +37 -0
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +87 -0
- package/dist/plugins.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +36 -2
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/bedrock.d.ts.map +1 -1
- package/dist/providers/bedrock.js +81 -17
- package/dist/providers/bedrock.js.map +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +19 -10
- package/dist/providers/types.js.map +1 -1
- package/dist/risk.d.ts.map +1 -1
- package/dist/risk.js +15 -5
- package/dist/risk.js.map +1 -1
- package/dist/sandbox-native.d.ts +1 -0
- package/dist/sandbox-native.d.ts.map +1 -1
- package/dist/sandbox-native.js +37 -5
- package/dist/sandbox-native.js.map +1 -1
- package/dist/scope.d.ts +10 -0
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js +75 -15
- package/dist/scope.js.map +1 -1
- package/dist/scuttlebot/client.d.ts +83 -0
- package/dist/scuttlebot/client.d.ts.map +1 -0
- package/dist/scuttlebot/client.js +350 -0
- package/dist/scuttlebot/client.js.map +1 -0
- package/dist/scuttlebot/config.d.ts +28 -0
- package/dist/scuttlebot/config.d.ts.map +1 -0
- package/dist/scuttlebot/config.js +91 -0
- package/dist/scuttlebot/config.js.map +1 -0
- package/dist/scuttlebot/http-client.d.ts +63 -0
- package/dist/scuttlebot/http-client.d.ts.map +1 -0
- package/dist/scuttlebot/http-client.js +124 -0
- package/dist/scuttlebot/http-client.js.map +1 -0
- package/dist/scuttlebot/index.d.ts +13 -0
- package/dist/scuttlebot/index.d.ts.map +1 -0
- package/dist/scuttlebot/index.js +10 -0
- package/dist/scuttlebot/index.js.map +1 -0
- package/dist/scuttlebot/irc-client.d.ts +124 -0
- package/dist/scuttlebot/irc-client.d.ts.map +1 -0
- package/dist/scuttlebot/irc-client.js +599 -0
- package/dist/scuttlebot/irc-client.js.map +1 -0
- package/dist/skills.d.ts +19 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +98 -10
- package/dist/skills.js.map +1 -1
- package/dist/smart-router.js +4 -4
- package/dist/smart-router.js.map +1 -1
- package/dist/storage.d.ts +0 -4
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +81 -5
- package/dist/storage.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +232 -38
- package/dist/tools.js.map +1 -1
- package/dist/trust.d.ts +16 -3
- package/dist/trust.d.ts.map +1 -1
- package/dist/trust.js +23 -4
- package/dist/trust.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -4
- package/dist/types.js.map +1 -1
- package/dist/ui/agent.d.ts +1 -1
- package/dist/ui/agent.d.ts.map +1 -1
- package/dist/ui/agent.js +35 -44
- package/dist/ui/agent.js.map +1 -1
- package/dist/ui/chat-input.d.ts +3 -1
- package/dist/ui/chat-input.d.ts.map +1 -1
- package/dist/ui/chat-input.js +82 -17
- package/dist/ui/chat-input.js.map +1 -1
- package/dist/ui/commands.d.ts +2 -0
- package/dist/ui/commands.d.ts.map +1 -1
- package/dist/ui/commands.js +318 -10
- package/dist/ui/commands.js.map +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +236 -46
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-utils.d.ts +20 -0
- package/dist/ui/input-utils.d.ts.map +1 -0
- package/dist/ui/input-utils.js +35 -0
- package/dist/ui/input-utils.js.map +1 -0
- package/dist/ui/messages.d.ts +6 -2
- package/dist/ui/messages.d.ts.map +1 -1
- package/dist/ui/messages.js +42 -11
- package/dist/ui/messages.js.map +1 -1
- package/dist/ui/modals.d.ts +21 -1
- package/dist/ui/modals.d.ts.map +1 -1
- package/dist/ui/modals.js +67 -5
- package/dist/ui/modals.js.map +1 -1
- package/dist/ui/status-bar.d.ts +4 -1
- package/dist/ui/status-bar.d.ts.map +1 -1
- package/dist/ui/status-bar.js +12 -1
- package/dist/ui/status-bar.js.map +1 -1
- package/dist/ui/types.d.ts +3 -0
- package/dist/ui/types.d.ts.map +1 -1
- package/package.json +4 -7
- package/dist/completion.d.ts +0 -75
- package/dist/completion.d.ts.map +0 -1
- package/dist/completion.js +0 -234
- package/dist/completion.js.map +0 -1
- package/dist/keyboard.d.ts +0 -57
- package/dist/keyboard.d.ts.map +0 -1
- package/dist/keyboard.js +0 -265
- package/dist/keyboard.js.map +0 -1
package/dist/ui/commands.js
CHANGED
|
@@ -21,6 +21,7 @@ import { getAgentStatusReport, swarmManager, councilManager, COUNCIL_TEMPLATES,
|
|
|
21
21
|
import { smartRoute, getDefaultSmartRoutingConfig, detectTaskType } from '../smart-router.js';
|
|
22
22
|
import { getCurrentSkin, getCurrentPalette, applySkin, applyPalette, listSkins, listPalettes } from '../hud/api.js';
|
|
23
23
|
import { getCurrentCompanion, applyCompanion, listCompanions, getMoodText } from '../companions.js';
|
|
24
|
+
import { scuttlebotClient } from '../scuttlebot/index.js';
|
|
24
25
|
import { createJob, runJob, cancelJob, getJob, formatJob, formatJobsList, clearFinishedJobs } from '../background-jobs.js';
|
|
25
26
|
import { listRecordings, loadRecording, formatRecording, deleteRecording } from '../terminal-recording.js';
|
|
26
27
|
import { startApiServer, stopApiServer, isApiServerRunning } from '../api-server.js';
|
|
@@ -113,7 +114,7 @@ export async function handleCommand(cmd, ctx) {
|
|
|
113
114
|
/persona [name] - Switch personality
|
|
114
115
|
/route [on|off] - Auto model routing (/autoroute)
|
|
115
116
|
/smart [on|off|cost|test] - Cross-provider smart routing
|
|
116
|
-
/breaker [status|
|
|
117
|
+
/breaker [status|adjust] - Circuit breaker control (/cb)
|
|
117
118
|
|
|
118
119
|
--- Conversation ---
|
|
119
120
|
/edit - Edit and resend last message
|
|
@@ -194,9 +195,17 @@ Modes: Plan | Hybrid | Work | Auto-route: ${ctx.autoRoute ? 'ON' : 'OFF'}${ctx.a
|
|
|
194
195
|
case '/providers':
|
|
195
196
|
case '/p':
|
|
196
197
|
if (parts[1]) {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
const requested = parts[1].toLowerCase();
|
|
199
|
+
const available = getAvailableProviders();
|
|
200
|
+
if (!available.includes(requested)) {
|
|
201
|
+
ctx.addMessage('error', `Provider "${requested}" is not configured. Run /provider (no args) for an interactive picker with setup.`);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
ctx.setProvider(requested);
|
|
205
|
+
ctx.addMessage('system', `Provider: ${selectProvider(requested)}`);
|
|
206
|
+
}
|
|
207
|
+
else if (ctx.openProviderPicker) {
|
|
208
|
+
ctx.openProviderPicker();
|
|
200
209
|
}
|
|
201
210
|
else {
|
|
202
211
|
ctx.addMessage('system', `Provider: ${ctx.actualProvider} | Available: ${getAvailableProviders().join(', ')}`);
|
|
@@ -226,7 +235,7 @@ Modes: Plan | Hybrid | Work | Auto-route: ${ctx.autoRoute ? 'ON' : 'OFF'}${ctx.a
|
|
|
226
235
|
else {
|
|
227
236
|
ctx.addMessage('system', `Fetching models for ${ctx.actualProvider}...`);
|
|
228
237
|
try {
|
|
229
|
-
const models = await getAvailableModels(ctx.actualProvider);
|
|
238
|
+
const models = await getAvailableModels(ctx.actualProvider, { throwOnError: true });
|
|
230
239
|
if (models.length > 0) {
|
|
231
240
|
ctx.setAvailableModels(models);
|
|
232
241
|
ctx.setModalMode('model');
|
|
@@ -243,7 +252,7 @@ Modes: Plan | Hybrid | Work | Auto-route: ${ctx.autoRoute ? 'ON' : 'OFF'}${ctx.a
|
|
|
243
252
|
case '/models':
|
|
244
253
|
ctx.addMessage('system', `Fetching models for ${ctx.actualProvider}...`);
|
|
245
254
|
try {
|
|
246
|
-
const models = await getAvailableModels(ctx.actualProvider);
|
|
255
|
+
const models = await getAvailableModels(ctx.actualProvider, { throwOnError: true });
|
|
247
256
|
if (models.length > 0) {
|
|
248
257
|
ctx.setAvailableModels(models);
|
|
249
258
|
ctx.setModalMode('model');
|
|
@@ -410,7 +419,91 @@ Modes: Plan | Hybrid | Work | Auto-route: ${ctx.autoRoute ? 'ON' : 'OFF'}${ctx.a
|
|
|
410
419
|
case '/status':
|
|
411
420
|
case '/s': {
|
|
412
421
|
const imgInfo = getTerminalImageInfo();
|
|
413
|
-
|
|
422
|
+
let statusMsg = `${ctx.actualProvider}:${ctx.actualModel} | ${ctx.stats.messageCount} msgs | ${ctx.stats.inputTokens + ctx.stats.outputTokens} tokens | terminal: ${getImageModeLabel(imgInfo.mode)}${imgInfo.truecolor ? ' (truecolor)' : ''} ${imgInfo.width}cols`;
|
|
423
|
+
// Add scuttlebot status if enabled
|
|
424
|
+
if (scuttlebotClient.isEnabled()) {
|
|
425
|
+
const sbStatus = scuttlebotClient.getStatus();
|
|
426
|
+
statusMsg += `\nScuttlebot: enabled (${sbStatus.nick}) | irc:${sbStatus.config?.ircAddr} | #${sbStatus.config?.channel}`;
|
|
427
|
+
}
|
|
428
|
+
ctx.addMessage('system', statusMsg);
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
case '/scuttlebot': {
|
|
432
|
+
const subCmd = parts[1];
|
|
433
|
+
const sbStatus = scuttlebotClient.getStatus();
|
|
434
|
+
// /scuttlebot enable - enable mid-session
|
|
435
|
+
if (subCmd === 'enable') {
|
|
436
|
+
if (sbStatus.enabled) {
|
|
437
|
+
ctx.addMessage('system', 'Scuttlebot is already enabled.');
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
// Initialize scuttlebot — config is loaded from ~/.config/scuttlebot-relay.env,
|
|
441
|
+
// process.env, and .scuttlebot.yaml inside initialize()
|
|
442
|
+
const sessionId = ctx.sessionRef.current?.id || 'default';
|
|
443
|
+
const cwd = getActiveProjectDir(ctx);
|
|
444
|
+
scuttlebotClient.initialize(sessionId, cwd).then(async (enabled) => {
|
|
445
|
+
if (enabled) {
|
|
446
|
+
const status = scuttlebotClient.getStatus();
|
|
447
|
+
let msg = '✓ Scuttlebot enabled!\n';
|
|
448
|
+
msg += ` Nick: ${status.nick}\n`;
|
|
449
|
+
msg += ` IRC: ${status.config?.ircAddr}\n`;
|
|
450
|
+
msg += ` Channel: #${status.config?.channel}`;
|
|
451
|
+
if (status.config?.channels && status.config.channels.length > 1) {
|
|
452
|
+
msg += `\n Channels: ${status.config.channels.map((c) => '#' + c).join(', ')}`;
|
|
453
|
+
}
|
|
454
|
+
ctx.addMessage('system', msg);
|
|
455
|
+
// Post online status and start routing IRC instructions
|
|
456
|
+
await scuttlebotClient.postOnline();
|
|
457
|
+
ctx.startScuttlebotPolling();
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
ctx.addMessage('system', 'Failed to enable scuttlebot');
|
|
461
|
+
}
|
|
462
|
+
}).catch((err) => {
|
|
463
|
+
ctx.addMessage('system', `Failed to enable scuttlebot: ${err instanceof Error ? err.message : String(err)}`);
|
|
464
|
+
});
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
// /scuttlebot disable - disable mid-session
|
|
468
|
+
if (subCmd === 'disable') {
|
|
469
|
+
if (!sbStatus.enabled) {
|
|
470
|
+
ctx.addMessage('system', 'Scuttlebot is not enabled.');
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
scuttlebotClient.postOffline().then(() => {
|
|
474
|
+
return scuttlebotClient.disconnect();
|
|
475
|
+
}).then(() => {
|
|
476
|
+
ctx.addMessage('system', 'Scuttlebot disabled');
|
|
477
|
+
}).catch((err) => {
|
|
478
|
+
ctx.addMessage('system', `Error disabling scuttlebot: ${err instanceof Error ? err.message : String(err)}`);
|
|
479
|
+
});
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
// Show status
|
|
483
|
+
if (!sbStatus.enabled) {
|
|
484
|
+
ctx.addMessage('system', 'Scuttlebot not enabled.\n\nRun: /scuttlebot enable\n\nConfig is loaded automatically from ~/.config/scuttlebot-relay.env\nChannel is read from .scuttlebot.yaml');
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
let statusText = 'Scuttlebot Status\n────────────────────────────────────────\n';
|
|
488
|
+
statusText += `Enabled: yes\n`;
|
|
489
|
+
statusText += `Nick: ${sbStatus.nick}\n`;
|
|
490
|
+
statusText += `IRC: ${sbStatus.config?.ircAddr}\n`;
|
|
491
|
+
statusText += `Channel: #${sbStatus.config?.channel}\n`;
|
|
492
|
+
statusText += `Connected: ${sbStatus.connected ? 'yes' : 'no'}`;
|
|
493
|
+
if (sbStatus.config?.channels && sbStatus.config.channels.length > 1) {
|
|
494
|
+
statusText += `\nChannels: ${sbStatus.config.channels.map((c) => '#' + c).join(', ')}`;
|
|
495
|
+
}
|
|
496
|
+
statusText += '\n\nCommands:\n /scuttlebot <message> Post a message\n /scuttlebot disable Disable integration';
|
|
497
|
+
ctx.addMessage('system', statusText);
|
|
498
|
+
// Allow manual message posting
|
|
499
|
+
if (subCmd && subCmd !== 'enable' && subCmd !== 'disable') {
|
|
500
|
+
const message = parts.slice(1).join(' ');
|
|
501
|
+
scuttlebotClient.postMessage(message).then(() => {
|
|
502
|
+
ctx.addMessage('system', 'Message posted to scuttlebot.');
|
|
503
|
+
}).catch((err) => {
|
|
504
|
+
ctx.addMessage('system', `Failed to post message: ${err instanceof Error ? err.message : String(err)}`);
|
|
505
|
+
});
|
|
506
|
+
}
|
|
414
507
|
break;
|
|
415
508
|
}
|
|
416
509
|
case '/config':
|
|
@@ -2646,19 +2739,234 @@ Example: /loop "Build a REST API" --max-iterations 50 --completion-promise "DONE
|
|
|
2646
2739
|
}
|
|
2647
2740
|
else if (subCmd === 'off') {
|
|
2648
2741
|
config.set('circuitBreakersEnabled', false);
|
|
2649
|
-
|
|
2742
|
+
// Also disable the current circuit breaker instance if it exists
|
|
2743
|
+
if (ctx.circuitBreaker) {
|
|
2744
|
+
ctx.circuitBreaker = undefined;
|
|
2745
|
+
ctx.setBreakerHealth?.('ok');
|
|
2746
|
+
}
|
|
2747
|
+
ctx.addMessage('system', '\u2713 Circuit breakers disabled');
|
|
2650
2748
|
}
|
|
2651
2749
|
else if (subCmd === 'on') {
|
|
2652
2750
|
config.set('circuitBreakersEnabled', true);
|
|
2653
2751
|
ctx.addMessage('system', '\u2713 Circuit breakers enabled');
|
|
2654
2752
|
}
|
|
2753
|
+
else if (subCmd === 'adjust') {
|
|
2754
|
+
const breakerTypeString = parts[2];
|
|
2755
|
+
const param = parts[3];
|
|
2756
|
+
const rawValue = parts[4];
|
|
2757
|
+
// Handle special 'list' command to show detailed parameter info
|
|
2758
|
+
if (breakerTypeString === 'list') {
|
|
2759
|
+
ctx.addMessage('system', `Circuit Breaker Configuration Reference:
|
|
2760
|
+
|
|
2761
|
+
📊 REPEATED-FAILURE (Consecutive Errors)
|
|
2762
|
+
• maxConsecutiveErrors: Number of consecutive errors before tripping (default: 3)
|
|
2763
|
+
Example: /breaker adjust repeated-failure maxConsecutiveErrors 5
|
|
2764
|
+
|
|
2765
|
+
💰 COST-RUNAWAY (Spending Control)
|
|
2766
|
+
• maxSessionCost: Maximum total cost per session in USD (default: $5.0)
|
|
2767
|
+
• maxCostPerMinute: Maximum spending rate per minute in USD (default: $1.0)
|
|
2768
|
+
• windowSizeMs: Sliding window size for rate calculation in milliseconds (default: 60000)
|
|
2769
|
+
Examples:
|
|
2770
|
+
/breaker adjust cost-runaway maxSessionCost 10.0
|
|
2771
|
+
/breaker adjust cost-runaway maxCostPerMinute 2.0
|
|
2772
|
+
|
|
2773
|
+
🔄 INFINITE-LOOP (Repetitive Behavior)
|
|
2774
|
+
• maxIdenticalInWindow: Max identical tool calls in window before tripping (default: 3)
|
|
2775
|
+
• windowSize: Number of recent tool calls to analyze (default: 6)
|
|
2776
|
+
• detectOscillation: Detect A-B-A-B oscillation patterns (default: true)
|
|
2777
|
+
Examples:
|
|
2778
|
+
/breaker adjust infinite-loop maxIdenticalInWindow 5
|
|
2779
|
+
/breaker adjust infinite-loop detectOscillation false
|
|
2780
|
+
|
|
2781
|
+
🔥 TOKEN-BURN (Token Usage Limits)
|
|
2782
|
+
• maxTokensPerIteration: Max tokens per single iteration (default: 200,000)
|
|
2783
|
+
• maxTotalTokens: Max total tokens per session (default: 5,000,000)
|
|
2784
|
+
Examples:
|
|
2785
|
+
/breaker adjust token-burn maxTokensPerIteration 100000
|
|
2786
|
+
/breaker adjust token-burn maxTotalTokens 1000000
|
|
2787
|
+
|
|
2788
|
+
⏸️ STALL (Progress Detection)
|
|
2789
|
+
• maxIdleIterations: Max iterations with no tool calls/content (default: 5)
|
|
2790
|
+
Example: /breaker adjust stall maxIdleIterations 3
|
|
2791
|
+
|
|
2792
|
+
⏰ WALL-CLOCK (Time Limits)
|
|
2793
|
+
• maxSessionDurationMs: Max session duration in milliseconds (0 = unlimited, default: 0)
|
|
2794
|
+
• maxIterationDurationMs: Max single iteration duration in milliseconds (default: 600000 = 10 min)
|
|
2795
|
+
Examples:
|
|
2796
|
+
/breaker adjust wall-clock maxSessionDurationMs 3600000 # 1 hour
|
|
2797
|
+
/breaker adjust wall-clock maxIterationDurationMs 300000 # 5 minutes
|
|
2798
|
+
|
|
2799
|
+
Quick Commands:
|
|
2800
|
+
/breaker adjust <type> - Show current settings for that type
|
|
2801
|
+
/breaker adjust - Show types overview
|
|
2802
|
+
/breaker status - Show current breaker states`);
|
|
2803
|
+
break;
|
|
2804
|
+
}
|
|
2805
|
+
// Show basic types overview if no type specified
|
|
2806
|
+
if (!breakerTypeString) {
|
|
2807
|
+
ctx.addMessage('system', `Circuit Breaker Types Available for Configuration:
|
|
2808
|
+
|
|
2809
|
+
repeated-failure - Consecutive errors before tripping
|
|
2810
|
+
cost-runaway - Spending rate and total cost limits
|
|
2811
|
+
infinite-loop - Identical tool calls and oscillation detection
|
|
2812
|
+
token-burn - Token usage per iteration and total limits
|
|
2813
|
+
stall - Idle iterations without progress
|
|
2814
|
+
wall-clock - Time-based session and iteration limits
|
|
2815
|
+
|
|
2816
|
+
Usage: /breaker adjust <type> [param] [value]
|
|
2817
|
+
/breaker adjust list - Show detailed parameter reference
|
|
2818
|
+
|
|
2819
|
+
Examples:
|
|
2820
|
+
/breaker adjust repeated-failure - Show current settings
|
|
2821
|
+
/breaker adjust cost-runaway maxSessionCost 10.0
|
|
2822
|
+
/breaker adjust infinite-loop detectOscillation true`);
|
|
2823
|
+
break;
|
|
2824
|
+
}
|
|
2825
|
+
// Cast to BreakerType and validate
|
|
2826
|
+
const breakerType = breakerTypeString;
|
|
2827
|
+
const validTypes = ['repeated-failure', 'cost-runaway', 'infinite-loop', 'token-burn', 'stall', 'wall-clock'];
|
|
2828
|
+
if (!validTypes.includes(breakerType)) {
|
|
2829
|
+
ctx.addMessage('error', `Invalid breaker type "${breakerType}". Valid types: ${validTypes.join(', ')}`);
|
|
2830
|
+
break;
|
|
2831
|
+
}
|
|
2832
|
+
const currentConfig = ctx.circuitBreaker.getConfig();
|
|
2833
|
+
const breakerConfig = currentConfig.breakers[breakerType];
|
|
2834
|
+
// Show current configuration if no param specified
|
|
2835
|
+
if (!param) {
|
|
2836
|
+
let configDisplay = `${breakerType} Circuit Breaker Settings:\n`;
|
|
2837
|
+
switch (breakerType) {
|
|
2838
|
+
case 'repeated-failure':
|
|
2839
|
+
configDisplay += ` maxConsecutiveErrors: ${breakerConfig.maxConsecutiveErrors} errors\n\nUsage: /breaker adjust repeated-failure <param> <value>\n /breaker adjust repeated-failure maxConsecutiveErrors <number>`;
|
|
2840
|
+
break;
|
|
2841
|
+
case 'cost-runaway':
|
|
2842
|
+
configDisplay += ` maxSessionCost: ${breakerConfig.maxSessionCost} per session\n maxCostPerMinute: ${breakerConfig.maxCostPerMinute} per minute\n windowSizeMs: ${breakerConfig.windowSizeMs}ms\n\nUsage: /breaker adjust cost-runaway <param> <value>\n /breaker adjust cost-runaway maxSessionCost <dollars>\n /breaker adjust cost-runaway maxCostPerMinute <dollars>\n /breaker adjust cost-runaway windowSizeMs <milliseconds>`;
|
|
2843
|
+
break;
|
|
2844
|
+
case 'infinite-loop':
|
|
2845
|
+
configDisplay += ` maxIdenticalInWindow: ${breakerConfig.maxIdenticalInWindow} calls\n windowSize: ${breakerConfig.windowSize} recent calls\n detectOscillation: ${breakerConfig.detectOscillation}\n\nUsage: /breaker adjust infinite-loop <param> <value>\n /breaker adjust infinite-loop maxIdenticalInWindow <number>\n /breaker adjust infinite-loop windowSize <number>\n /breaker adjust infinite-loop detectOscillation <true|false>`;
|
|
2846
|
+
break;
|
|
2847
|
+
case 'token-burn':
|
|
2848
|
+
configDisplay += ` maxTokensPerIteration: ${breakerConfig.maxTokensPerIteration.toLocaleString()} tokens\n maxTotalTokens: ${breakerConfig.maxTotalTokens.toLocaleString()} tokens\n\nUsage: /breaker adjust token-burn <param> <value>\n /breaker adjust token-burn maxTokensPerIteration <number>\n /breaker adjust token-burn maxTotalTokens <number>`;
|
|
2849
|
+
break;
|
|
2850
|
+
case 'stall':
|
|
2851
|
+
configDisplay += ` maxIdleIterations: ${breakerConfig.maxIdleIterations} iterations\n\nUsage: /breaker adjust stall <param> <value>\n /breaker adjust stall maxIdleIterations <number>`;
|
|
2852
|
+
break;
|
|
2853
|
+
case 'wall-clock':
|
|
2854
|
+
const sessionDuration = breakerConfig.maxSessionDurationMs;
|
|
2855
|
+
const iterationDuration = breakerConfig.maxIterationDurationMs;
|
|
2856
|
+
configDisplay += ` maxSessionDurationMs: ${sessionDuration === 0 ? 'unlimited' : sessionDuration + 'ms'}\n maxIterationDurationMs: ${iterationDuration}ms (${Math.round(iterationDuration / 60000)} minutes)\n\nUsage: /breaker adjust wall-clock <param> <value>\n /breaker adjust wall-clock maxSessionDurationMs <milliseconds>\n /breaker adjust wall-clock maxIterationDurationMs <milliseconds>`;
|
|
2857
|
+
break;
|
|
2858
|
+
}
|
|
2859
|
+
ctx.addMessage('system', configDisplay);
|
|
2860
|
+
break;
|
|
2861
|
+
}
|
|
2862
|
+
// Parse and validate the value
|
|
2863
|
+
let parsedValue;
|
|
2864
|
+
// Handle boolean parameters
|
|
2865
|
+
if (param === 'detectOscillation') {
|
|
2866
|
+
if (rawValue === 'true')
|
|
2867
|
+
parsedValue = true;
|
|
2868
|
+
else if (rawValue === 'false')
|
|
2869
|
+
parsedValue = false;
|
|
2870
|
+
else {
|
|
2871
|
+
ctx.addMessage('error', 'detectOscillation must be "true" or "false"');
|
|
2872
|
+
break;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
else {
|
|
2876
|
+
// Handle numeric parameters
|
|
2877
|
+
parsedValue = parseFloat(rawValue);
|
|
2878
|
+
if (isNaN(parsedValue) || parsedValue < 0) {
|
|
2879
|
+
ctx.addMessage('error', 'Value must be a non-negative number');
|
|
2880
|
+
break;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
// Validate parameter names for each breaker type
|
|
2884
|
+
const paramValidations = {
|
|
2885
|
+
'repeated-failure': {
|
|
2886
|
+
params: ['maxConsecutiveErrors'],
|
|
2887
|
+
validate: (param, value) => value <= 0 ? 'maxConsecutiveErrors must be > 0' : null
|
|
2888
|
+
},
|
|
2889
|
+
'cost-runaway': {
|
|
2890
|
+
params: ['maxSessionCost', 'maxCostPerMinute', 'windowSizeMs'],
|
|
2891
|
+
validate: (param, value) => value <= 0 ? `${param} must be > 0` : null
|
|
2892
|
+
},
|
|
2893
|
+
'infinite-loop': {
|
|
2894
|
+
params: ['maxIdenticalInWindow', 'windowSize', 'detectOscillation'],
|
|
2895
|
+
validate: (param, value) => {
|
|
2896
|
+
if (param === 'detectOscillation')
|
|
2897
|
+
return null; // boolean is already validated above
|
|
2898
|
+
return value <= 0 ? `${param} must be > 0` : null;
|
|
2899
|
+
}
|
|
2900
|
+
},
|
|
2901
|
+
'token-burn': {
|
|
2902
|
+
params: ['maxTokensPerIteration', 'maxTotalTokens'],
|
|
2903
|
+
validate: (param, value) => value <= 0 ? `${param} must be > 0` : null
|
|
2904
|
+
},
|
|
2905
|
+
'stall': {
|
|
2906
|
+
params: ['maxIdleIterations'],
|
|
2907
|
+
validate: (param, value) => value <= 0 ? 'maxIdleIterations must be > 0' : null
|
|
2908
|
+
},
|
|
2909
|
+
'wall-clock': {
|
|
2910
|
+
params: ['maxSessionDurationMs', 'maxIterationDurationMs'],
|
|
2911
|
+
validate: (param, value) => {
|
|
2912
|
+
if (param === 'maxSessionDurationMs' && value === 0)
|
|
2913
|
+
return null; // 0 = unlimited is valid
|
|
2914
|
+
return value < 0 ? `${param} cannot be negative` : null;
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
};
|
|
2918
|
+
const validation = paramValidations[breakerType];
|
|
2919
|
+
if (!validation.params.includes(param)) {
|
|
2920
|
+
ctx.addMessage('error', `Invalid parameter "${param}" for ${breakerType}. Valid parameters: ${validation.params.join(', ')}`);
|
|
2921
|
+
break;
|
|
2922
|
+
}
|
|
2923
|
+
// Run custom validation if provided
|
|
2924
|
+
if (validation.validate) {
|
|
2925
|
+
const error = validation.validate(param, parsedValue);
|
|
2926
|
+
if (error) {
|
|
2927
|
+
ctx.addMessage('error', error);
|
|
2928
|
+
break;
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
// Update the configuration
|
|
2932
|
+
const oldValue = breakerConfig[param];
|
|
2933
|
+
ctx.circuitBreaker.adjust(breakerType, { [param]: parsedValue });
|
|
2934
|
+
// Format the success message based on parameter type
|
|
2935
|
+
let formattedOld, formattedNew;
|
|
2936
|
+
if (param === 'detectOscillation') {
|
|
2937
|
+
formattedOld = String(oldValue);
|
|
2938
|
+
formattedNew = String(parsedValue);
|
|
2939
|
+
}
|
|
2940
|
+
else if (param.includes('Cost')) {
|
|
2941
|
+
formattedOld = `${oldValue}`;
|
|
2942
|
+
formattedNew = `${parsedValue}`;
|
|
2943
|
+
}
|
|
2944
|
+
else if (param.includes('Ms')) {
|
|
2945
|
+
formattedOld = oldValue === 0 ? 'unlimited' : `${oldValue}ms`;
|
|
2946
|
+
formattedNew = parsedValue === 0 ? 'unlimited' : `${parsedValue}ms`;
|
|
2947
|
+
}
|
|
2948
|
+
else if (param.includes('Tokens')) {
|
|
2949
|
+
formattedOld = oldValue.toLocaleString();
|
|
2950
|
+
formattedNew = parsedValue.toLocaleString();
|
|
2951
|
+
}
|
|
2952
|
+
else {
|
|
2953
|
+
formattedOld = String(oldValue);
|
|
2954
|
+
formattedNew = String(parsedValue);
|
|
2955
|
+
}
|
|
2956
|
+
ctx.addMessage('system', `✅ ${breakerType} ${param}: ${formattedOld} → ${formattedNew}`);
|
|
2957
|
+
}
|
|
2655
2958
|
else {
|
|
2656
|
-
ctx.addMessage('system', `Usage: /breaker [status|resume|reset|on|off]
|
|
2959
|
+
ctx.addMessage('system', `Usage: /breaker [status|resume|reset|adjust|on|off]
|
|
2657
2960
|
/breaker resume [type] - Resume tripped breaker (half-open)
|
|
2658
2961
|
/breaker reset [type] - Reset breaker to closed
|
|
2962
|
+
/breaker adjust [type] [param] [value] - Configure breaker thresholds
|
|
2659
2963
|
/breaker on|off - Enable/disable circuit breakers
|
|
2660
2964
|
|
|
2661
|
-
Breaker types: repeated-failure, cost-runaway, infinite-loop, token-burn, stall
|
|
2965
|
+
Breaker types: repeated-failure, cost-runaway, infinite-loop, token-burn, stall, wall-clock
|
|
2966
|
+
|
|
2967
|
+
Quick help:
|
|
2968
|
+
/breaker adjust - Show types overview
|
|
2969
|
+
/breaker adjust list - Show detailed parameter reference`);
|
|
2662
2970
|
}
|
|
2663
2971
|
break;
|
|
2664
2972
|
}
|