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 +11 -0
- package/dist/api.js +65 -15
- package/dist/api.js.map +1 -1
- package/dist/config.js +8 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +114 -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/sandbox.d.ts +37 -0
- package/dist/sandbox.js +192 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/tools/bash.js +27 -1
- package/dist/tools/bash.js.map +1 -1
- package/dist/types.d.ts +6 -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
|
@@ -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);
|
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
|
@@ -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
|