compact-agent 1.21.0 → 1.23.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 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
- return `${config.baseURL}:${config.apiKey}`;
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: config.apiKey || 'not-needed',
31
+ apiKey: activeKey || 'not-needed',
14
32
  baseURL: config.baseURL,
15
33
  ...(isAnthropic ? {
16
34
  defaultHeaders: {
17
- 'x-api-key': config.apiKey,
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
- const api = getClient(config);
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
- const stream = await withRetry(() => api.chat.completions.create({
47
- model: config.model,
48
- messages: messages,
49
- tools: toolDefs.length > 0 ? toolDefs : undefined,
50
- max_tokens: config.maxTokens,
51
- temperature: config.temperature,
52
- stream: true,
53
- // OpenAI SDK supports cancellation via signal; pass it through
54
- // so the underlying fetch can be aborted on Steer.
55
- }, signal ? { signal } : undefined), { maxRetries: 3, baseDelay: 1000, maxDelay: 30000 });
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":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -26,6 +26,13 @@ const DEFAULT_CONFIG = {
26
26
  // Thinking / reasoning shown by default — gives users live "the model isn't
27
27
  // dead" feedback during long turns. Toggle off with /thinking.
28
28
  showThinking: true,
29
+ // Sandbox config. Default off: most workflows don't want the
30
+ // restrictions, and the execpolicy intent gate from 1.19.0 already
31
+ // catches the highest-risk commands. Users opt in via /sandbox standard
32
+ // or /sandbox strict.
33
+ sandbox: {
34
+ level: 'off',
35
+ },
29
36
  // MemPalace persistent memory. ON by default — it's a featured capability,
30
37
  // zero overhead until something is written, and the agent only uses the
31
38
  // tools when it sees a durable fact worth keeping. User can opt out during
@@ -129,7 +136,7 @@ function validateConfig(config) {
129
136
  config.permissionMode = 'ask';
130
137
  }
131
138
  // Warn on unexpected fields
132
- const expectedFields = new Set(['apiKey', 'baseURL', 'model', 'fallbackModel', 'provider', 'maxTokens', 'temperature', 'permissionMode', 'alwaysAllowedTools', 'dryRun', 'theme', 'palette', 'showThinking', 'voice', 'memory']);
139
+ const expectedFields = new Set(['apiKey', 'apiKeys', 'baseURL', 'model', 'fallbackModel', 'provider', 'maxTokens', 'temperature', 'permissionMode', 'alwaysAllowedTools', 'dryRun', 'theme', 'palette', 'showThinking', 'voice', 'memory', 'sandbox']);
133
140
  for (const key in config) {
134
141
  if (!expectedFields.has(key) && !_alreadyWarnedFields.has(key)) {
135
142
  _alreadyWarnedFields.add(key);
@@ -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
@@ -59,6 +59,10 @@ import { buildStitchPrompt, buildStitchToolsPrompt, saveStitchConfig, printStitc
59
59
  import * as mempalace from './mempalace/index.js';
60
60
  // Curator — periodic skill consolidation pass (/curate)
61
61
  import { runCurator } from './curator.js';
62
+ // Sandbox — OS-native isolation for bash tool (/sandbox)
63
+ import { status as sandboxStatus } from './sandbox.js';
64
+ // API key rotation pool (/keys)
65
+ import { listStatus as keyPoolStatus } from './key-rotation.js';
62
66
  // Voice / accessibility — built-in dictation (Whisper) + readout (ElevenLabs)
63
67
  import { printVoiceStatus, isVoiceEnabled, getTtsConfig, getSttConfig, getAccessibilityConfig, speak, dictateOnce, } from './voice.js';
64
68
  import { isFfmpegAvailable, audioCue, startRecording, probeMic, micProbeMessage } from './audio.js';
@@ -195,6 +199,7 @@ export function handleSlashCommand(input, config, messages, session, mode) {
195
199
  console.log(d(' ') + c('/models') + d(' — list available models for provider'));
196
200
  console.log(d(' ') + c('/fallback [model]') + d(' — set/show the model auto-retried on cryptic provider errors'));
197
201
  console.log(d(' ') + c('/provider') + d(' — show provider info'));
202
+ console.log(d(' ') + c('/keys [add|rm]') + d(' — multi-key rotation pool (e.g. several OpenRouter accounts)'));
198
203
  console.log(d(' ') + c('/route') + d(' — auto-route model based on next message'));
199
204
  console.log(h('\n ── Modes ──'));
200
205
  console.log(d(' ') + c('/mode [name]') + d(' — switch mode (dev/review/tdd/research/plan/debug/architect/hermes/design)'));
@@ -233,6 +238,7 @@ export function handleSlashCommand(input, config, messages, session, mode) {
233
238
  console.log(d(' ') + c('/rules') + d(' — show coding rules'));
234
239
  console.log(d(' ') + c('/perm <mode>') + d(' — set permission mode (ask/auto/yolo); no arg shows current + always-allow list'));
235
240
  console.log(d(' ') + c('/perm-reset') + d(' — clear the per-tool always-allow list'));
241
+ console.log(d(' ') + c('/sandbox [level]') + d(' — OS-native bash sandbox (off / standard / strict)'));
236
242
  console.log(d(' ') + c('/dry-run') + d(' — toggle dry-run mode'));
237
243
  console.log(d(' ') + c('/thinking') + d(' — toggle thinking/reasoning display'));
238
244
  console.log(d(' ') + c('/cd <path>') + d(' — change directory'));
@@ -1552,6 +1558,114 @@ export function handleSlashCommand(input, config, messages, session, mode) {
1552
1558
  console.log(chalk.dim(' Restart the REPL for the tool to appear in /tools.'));
1553
1559
  return { handled: true };
1554
1560
  }
1561
+ // ── API key pool (multi-account rotation) ────────────────
1562
+ // /keys show pool with health + stats
1563
+ // /keys add <key> append to the rotation pool
1564
+ // /keys remove <key> remove a specific key (or partial tail-match)
1565
+ // /keys clear empty the extras pool (keeps primary apiKey)
1566
+ case '/keys': {
1567
+ const parts = args.trim().split(/\s+/).filter(Boolean);
1568
+ const sub = (parts[0] || '').toLowerCase();
1569
+ if (!sub || sub === 'status' || sub === 'list') {
1570
+ const status = keyPoolStatus();
1571
+ if (status.length === 0) {
1572
+ console.log(chalk.dim(' Key pool is empty. /keys add <key> to start rotation.'));
1573
+ return { handled: true };
1574
+ }
1575
+ console.log(chalk.cyan(`\n API key pool (${status.length}):`));
1576
+ for (const k of status) {
1577
+ const health = k.healthy
1578
+ ? chalk.green('✓ healthy')
1579
+ : chalk.yellow(`✗ cooling ${k.coolDownRemainingSec}s${k.lastReason ? ' (' + k.lastReason + ')' : ''}`);
1580
+ console.log(chalk.dim(` [${k.index}] ${k.tail} ${health} · ${k.successes} ok / ${k.failures} fail`));
1581
+ }
1582
+ console.log(chalk.dim('\n /keys add <key> add to pool'));
1583
+ console.log(chalk.dim(' /keys remove <tail> drop a key (last-4 char match)'));
1584
+ console.log(chalk.dim(' /keys clear empty the extras pool\n'));
1585
+ return { handled: true };
1586
+ }
1587
+ if (sub === 'add') {
1588
+ const newKey = parts.slice(1).join(' ').trim();
1589
+ if (!newKey) {
1590
+ console.log(chalk.yellow(' Usage: /keys add <api-key>'));
1591
+ return { handled: true };
1592
+ }
1593
+ const extras = (config.apiKeys || []).slice();
1594
+ if (extras.includes(newKey) || newKey === config.apiKey) {
1595
+ console.log(chalk.yellow(' Key already in the pool.'));
1596
+ return { handled: true };
1597
+ }
1598
+ extras.push(newKey);
1599
+ config.apiKeys = extras;
1600
+ saveConfig(config);
1601
+ resetClient();
1602
+ console.log(chalk.green(` Key added (…${newKey.slice(-4)}). Pool size: ${1 + extras.length}.`));
1603
+ return { handled: true };
1604
+ }
1605
+ if (sub === 'remove' || sub === 'rm') {
1606
+ const target = parts[1] || '';
1607
+ if (!target) {
1608
+ console.log(chalk.yellow(' Usage: /keys remove <tail-chars>'));
1609
+ return { handled: true };
1610
+ }
1611
+ const extras = (config.apiKeys || []).filter((k) => !k.endsWith(target) && k !== target);
1612
+ if (extras.length === (config.apiKeys || []).length) {
1613
+ console.log(chalk.yellow(` No key matched "${target}".`));
1614
+ return { handled: true };
1615
+ }
1616
+ config.apiKeys = extras;
1617
+ saveConfig(config);
1618
+ resetClient();
1619
+ console.log(chalk.green(` Key removed. Pool size: ${1 + extras.length}.`));
1620
+ return { handled: true };
1621
+ }
1622
+ if (sub === 'clear') {
1623
+ config.apiKeys = [];
1624
+ saveConfig(config);
1625
+ resetClient();
1626
+ console.log(chalk.green(' Extras pool cleared. Primary key remains.'));
1627
+ return { handled: true };
1628
+ }
1629
+ console.log(chalk.yellow(` Unknown /keys subcommand: ${sub}. Try: status, add, remove, clear`));
1630
+ return { handled: true };
1631
+ }
1632
+ // ── Sandbox — OS-native isolation for bash tool ──────────
1633
+ // /sandbox show backend + current level
1634
+ // /sandbox off|standard|strict
1635
+ case '/sandbox': {
1636
+ const sub = args.trim().toLowerCase();
1637
+ const s = sandboxStatus();
1638
+ if (!sub || sub === 'status') {
1639
+ const current = config.sandbox?.level || 'off';
1640
+ console.log(chalk.cyan('\n Sandbox status'));
1641
+ console.log(chalk.dim(` platform: ${s.platform}`));
1642
+ console.log(chalk.dim(` backend: ${s.backend}${s.available ? ' ✓' : ' ✗ ' + (s.reason || 'unavailable')}`));
1643
+ console.log(chalk.dim(` level: ${current}${current === 'off' ? '' : (s.available ? ' (active)' : ' (config says ' + current + ' but backend unavailable → unsandboxed)')}`));
1644
+ console.log(chalk.dim('\n Levels:'));
1645
+ console.log(chalk.dim(' off — no wrap, behave as before'));
1646
+ console.log(chalk.dim(' standard — read everywhere, write to cwd + /tmp, full network'));
1647
+ console.log(chalk.dim(' strict — read/write cwd only, no network, no /tmp'));
1648
+ console.log(chalk.dim('\n Change with: /sandbox <level>\n'));
1649
+ return { handled: true };
1650
+ }
1651
+ if (sub === 'off' || sub === 'standard' || sub === 'strict') {
1652
+ config.sandbox = { ...(config.sandbox || {}), level: sub };
1653
+ saveConfig(config);
1654
+ if (sub === 'off') {
1655
+ console.log(chalk.green(` Sandbox: OFF — bash commands run unwrapped.`));
1656
+ }
1657
+ else if (s.available) {
1658
+ console.log(chalk.green(` Sandbox: ${sub} — bash commands wrap via ${s.backend}.`));
1659
+ }
1660
+ else {
1661
+ console.log(chalk.yellow(` Sandbox set to ${sub}, but ${s.backend} isn't available here (${s.reason}).`));
1662
+ console.log(chalk.dim(' Commands will still run, just unwrapped. Install the backend to actually sandbox.'));
1663
+ }
1664
+ return { handled: true };
1665
+ }
1666
+ console.log(chalk.yellow(` Unknown /sandbox level: ${sub}. Use: off, standard, strict.`));
1667
+ return { handled: true };
1668
+ }
1555
1669
  // ── Reset hooks (clear stale entries from old installs) ──
1556
1670
  // Wipes ~/.crowcoder/hooks.json, clears the in-memory quarantine, and
1557
1671
  // re-seeds the ECC default hooks against this install's bin path. Use