@bubblebrain-ai/bubble 0.0.28 → 0.0.29
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 +21 -0
- package/dist/agent/categories.d.ts +2 -0
- package/dist/agent/categories.js +4 -0
- package/dist/agent/child-runner.d.ts +5 -1
- package/dist/agent/child-runner.js +35 -2
- package/dist/agent/profiles.js +3 -0
- package/dist/agent/structured-output.d.ts +37 -0
- package/dist/agent/structured-output.js +193 -0
- package/dist/agent/subagent-control.d.ts +3 -0
- package/dist/agent/subagent-scheduler.d.ts +10 -0
- package/dist/agent/subagent-scheduler.js +31 -0
- package/dist/agent/workflow/control.d.ts +37 -0
- package/dist/agent/workflow/control.js +20 -0
- package/dist/agent/workflow/errors.d.ts +16 -0
- package/dist/agent/workflow/errors.js +24 -0
- package/dist/agent/workflow/runtime.d.ts +75 -0
- package/dist/agent/workflow/runtime.js +237 -0
- package/dist/agent.d.ts +105 -0
- package/dist/agent.js +425 -17
- package/dist/context/compact-llm.d.ts +10 -1
- package/dist/context/compact-llm.js +13 -5
- package/dist/context/compact.d.ts +30 -0
- package/dist/context/compact.js +34 -17
- package/dist/network/provider-transport.d.ts +9 -0
- package/dist/network/provider-transport.js +19 -1
- package/dist/provider.d.ts +14 -0
- package/dist/provider.js +24 -0
- package/dist/session.d.ts +16 -0
- package/dist/session.js +33 -1
- package/dist/slash-commands/commands.js +47 -1
- package/dist/slash-commands/types.d.ts +16 -1
- package/dist/tools/agent-lifecycle.d.ts +6 -0
- package/dist/tools/agent-lifecycle.js +285 -0
- package/dist/tools/child-tools.d.ts +10 -0
- package/dist/tools/child-tools.js +12 -0
- package/dist/tools/read.d.ts +1 -1
- package/dist/tools/read.js +9 -0
- package/dist/tui/image-display.d.ts +6 -0
- package/dist/tui/image-display.js +26 -1
- package/dist/tui-ink/app.js +84 -6
- package/dist/tui-ink/compaction-progress.d.ts +19 -0
- package/dist/tui-ink/compaction-progress.js +74 -0
- package/dist/tui-ink/input-box.d.ts +7 -1
- package/dist/tui-ink/input-box.js +48 -15
- package/dist/tui-ink/markdown.d.ts +18 -0
- package/dist/tui-ink/markdown.js +172 -16
- package/dist/tui-ink/message-list.js +38 -94
- package/dist/tui-ink/run.js +5 -0
- package/dist/tui-ink/subagent-inspector.d.ts +17 -0
- package/dist/tui-ink/subagent-inspector.js +189 -0
- package/dist/tui-ink/subagent-view.d.ts +47 -0
- package/dist/tui-ink/subagent-view.js +163 -0
- package/dist/tui-ink/terminal-env.d.ts +15 -0
- package/dist/tui-ink/terminal-env.js +22 -0
- package/dist/tui-ink/use-terminal-size.js +33 -6
- package/dist/tui-ink/width.d.ts +18 -0
- package/dist/tui-ink/width.js +130 -0
- package/dist/types.d.ts +35 -0
- package/package.json +2 -1
package/dist/context/compact.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function planSessionCompaction(entries, options = {}) {
|
|
2
2
|
const keepRecentTurns = options.keepRecentTurns ?? 2;
|
|
3
|
-
const maxSummaryItems = options.maxSummaryItems ?? 4;
|
|
4
3
|
const metadataEntries = entries.filter((entry) => entry.type === "metadata");
|
|
5
4
|
const nonMetadataEntries = entries.filter((entry) => entry.type !== "metadata");
|
|
6
5
|
const latestSummaryIndex = findLatestSummaryIndex(nonMetadataEntries);
|
|
@@ -10,34 +9,52 @@ export function compactSessionEntries(entries, options = {}) {
|
|
|
10
9
|
.map((entry, index) => (entry.type === "user_message" ? index : -1))
|
|
11
10
|
.filter((index) => index >= 0);
|
|
12
11
|
if (turnStartIndexes.length <= keepRecentTurns) {
|
|
13
|
-
return {
|
|
12
|
+
return { compactable: false };
|
|
14
13
|
}
|
|
15
14
|
const keepStartIndex = turnStartIndexes[Math.max(0, turnStartIndexes.length - keepRecentTurns)];
|
|
16
15
|
if (keepStartIndex <= 0) {
|
|
17
|
-
return {
|
|
18
|
-
}
|
|
19
|
-
const oldEntries = activeEntries.slice(0, keepStartIndex);
|
|
20
|
-
const keptEntries = activeEntries.slice(keepStartIndex);
|
|
21
|
-
const summary = buildCompactionSummary(oldEntries, maxSummaryItems);
|
|
22
|
-
if (!summary) {
|
|
23
|
-
return { compacted: false };
|
|
16
|
+
return { compactable: false };
|
|
24
17
|
}
|
|
18
|
+
return {
|
|
19
|
+
compactable: true,
|
|
20
|
+
metadataEntries,
|
|
21
|
+
oldEntries: activeEntries.slice(0, keepStartIndex),
|
|
22
|
+
keptEntries: activeEntries.slice(keepStartIndex),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Assemble the post-compaction entry list from a plan and a (possibly
|
|
27
|
+
* LLM-generated) summary string. The summary entry is keyed off the full
|
|
28
|
+
* original `entries` so its id never collides with a prior summary.
|
|
29
|
+
*/
|
|
30
|
+
export function buildCompactedEntries(entries, plan, summary) {
|
|
25
31
|
const summaryEntry = {
|
|
26
32
|
id: nextSummaryId(entries),
|
|
27
33
|
type: "summary",
|
|
28
34
|
summary,
|
|
29
35
|
timestamp: Date.now(),
|
|
30
36
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
return [...plan.metadataEntries, summaryEntry, ...plan.keptEntries];
|
|
38
|
+
}
|
|
39
|
+
/** Flatten a plan's old entries into messages for an external summarizer. */
|
|
40
|
+
export function planOldMessages(plan) {
|
|
41
|
+
return entriesToMessages(plan.oldEntries);
|
|
42
|
+
}
|
|
43
|
+
export function compactSessionEntries(entries, options = {}) {
|
|
44
|
+
const maxSummaryItems = options.maxSummaryItems ?? 4;
|
|
45
|
+
const plan = planSessionCompaction(entries, options);
|
|
46
|
+
if (!plan.compactable) {
|
|
47
|
+
return { compacted: false };
|
|
48
|
+
}
|
|
49
|
+
const summary = buildCompactionSummary(plan.oldEntries, maxSummaryItems);
|
|
50
|
+
if (!summary) {
|
|
51
|
+
return { compacted: false };
|
|
52
|
+
}
|
|
36
53
|
return {
|
|
37
54
|
compacted: true,
|
|
38
55
|
summary,
|
|
39
|
-
entries:
|
|
40
|
-
droppedEntries: oldEntries.length,
|
|
56
|
+
entries: buildCompactedEntries(entries, plan, summary),
|
|
57
|
+
droppedEntries: plan.oldEntries.length,
|
|
41
58
|
};
|
|
42
59
|
}
|
|
43
60
|
export function compactMessages(messages, options = {}) {
|
|
@@ -28,5 +28,14 @@ export declare function normalizeProviderNetworkError(error: unknown, options: {
|
|
|
28
28
|
env?: NodeJS.ProcessEnv;
|
|
29
29
|
}): Error;
|
|
30
30
|
export declare function isProviderTransportError(error: unknown): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Request/response timeouts surface as prose rather than errno tokens — e.g.
|
|
33
|
+
* Bun fetch throws a DOMException named "TimeoutError" with message
|
|
34
|
+
* "The operation timed out.", and openai-node raises APIConnectionTimeoutError.
|
|
35
|
+
* These are kept OUT of isProviderNetworkErrorText on purpose: that predicate
|
|
36
|
+
* drives normalizeProviderNetworkError's proxy/TLS/CA advice, and a plain
|
|
37
|
+
* timeout must not be rewrapped into a misleading "check your proxy" message.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isProviderTimeoutErrorText(text: string): boolean;
|
|
31
40
|
export declare function shouldEnableFetchVerbose(env?: NodeJS.ProcessEnv, providerVerboseEnvVar?: string): boolean;
|
|
32
41
|
export {};
|
|
@@ -99,7 +99,25 @@ export function normalizeProviderNetworkError(error, options) {
|
|
|
99
99
|
return new Error(message, { cause: error });
|
|
100
100
|
}
|
|
101
101
|
export function isProviderTransportError(error) {
|
|
102
|
-
|
|
102
|
+
const text = errorMessageChain(error).join("\n");
|
|
103
|
+
return isProviderNetworkErrorText(text) || isProviderTimeoutErrorText(text);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Request/response timeouts surface as prose rather than errno tokens — e.g.
|
|
107
|
+
* Bun fetch throws a DOMException named "TimeoutError" with message
|
|
108
|
+
* "The operation timed out.", and openai-node raises APIConnectionTimeoutError.
|
|
109
|
+
* These are kept OUT of isProviderNetworkErrorText on purpose: that predicate
|
|
110
|
+
* drives normalizeProviderNetworkError's proxy/TLS/CA advice, and a plain
|
|
111
|
+
* timeout must not be rewrapped into a misleading "check your proxy" message.
|
|
112
|
+
*/
|
|
113
|
+
export function isProviderTimeoutErrorText(text) {
|
|
114
|
+
return [
|
|
115
|
+
/operation timed out/i,
|
|
116
|
+
/request timed out/i,
|
|
117
|
+
/\bTimeoutError\b/i,
|
|
118
|
+
/\bAPIConnectionTimeoutError\b/i,
|
|
119
|
+
/\bESOCKETTIMEDOUT\b/i,
|
|
120
|
+
].some((pattern) => pattern.test(text));
|
|
103
121
|
}
|
|
104
122
|
export function shouldEnableFetchVerbose(env = process.env, providerVerboseEnvVar) {
|
|
105
123
|
const providerValue = providerVerboseEnvVar ? env[providerVerboseEnvVar] : undefined;
|
package/dist/provider.d.ts
CHANGED
|
@@ -54,4 +54,18 @@ export declare function translateOpenAIFullResponse(response: any): AsyncIterabl
|
|
|
54
54
|
* in index order to keep multi-call turns deterministic.
|
|
55
55
|
*/
|
|
56
56
|
export declare function translateOpenAIStream(stream: AsyncIterable<any>, options?: TranslateOpenAIStreamOptions): AsyncIterable<StreamChunk>;
|
|
57
|
+
/** Largest value Node's 32-bit timers accept; ~24.8 days. */
|
|
58
|
+
export declare const MAX_TIMER_MS = 2147483647;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the provider request timeout (ms) from the operator override.
|
|
61
|
+
*
|
|
62
|
+
* Default is effectively NO TIMEOUT — safe for streaming APIs where the model
|
|
63
|
+
* sends chunks continuously. But Node's timers are 32-bit: a duration above
|
|
64
|
+
* 2**31-1 ms overflows, which makes Node print a TimeoutOverflowWarning to
|
|
65
|
+
* stderr (corrupting the Ink TUI) AND silently clamp the timeout to 1ms,
|
|
66
|
+
* aborting the request almost immediately. So we use the largest SAFE timer
|
|
67
|
+
* value as the "no timeout" sentinel — never Number.MAX_SAFE_INTEGER — and
|
|
68
|
+
* clamp any operator-supplied value into range too.
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveRequestTimeoutMs(raw: string | undefined): number;
|
|
57
71
|
export {};
|
package/dist/provider.js
CHANGED
|
@@ -94,6 +94,7 @@ export function createProviderInstance(options) {
|
|
|
94
94
|
const client = new OpenAI({
|
|
95
95
|
apiKey: options.apiKey,
|
|
96
96
|
baseURL: options.baseURL,
|
|
97
|
+
timeout: resolveRequestTimeoutMs(process.env.BUBBLE_PROVIDER_REQUEST_TIMEOUT_MS),
|
|
97
98
|
});
|
|
98
99
|
const fallbackModel = "gpt-4o";
|
|
99
100
|
async function* streamChat(messages, chatOptions) {
|
|
@@ -704,6 +705,29 @@ function mergeToolArgumentDelta(current, incoming, mode) {
|
|
|
704
705
|
debugToolArgs({ stage: "merge", branch: mode === "delta" ? "delta-append" : "snapshot-fallback-concat", current, incoming, args: current + incoming, delta: incoming });
|
|
705
706
|
return { args: current + incoming, delta: incoming };
|
|
706
707
|
}
|
|
708
|
+
function parsePositiveInt(raw) {
|
|
709
|
+
if (!raw?.trim())
|
|
710
|
+
return undefined;
|
|
711
|
+
const value = Number(raw);
|
|
712
|
+
return Number.isInteger(value) && value > 0 ? value : undefined;
|
|
713
|
+
}
|
|
714
|
+
/** Largest value Node's 32-bit timers accept; ~24.8 days. */
|
|
715
|
+
export const MAX_TIMER_MS = 2_147_483_647; // 2**31 - 1
|
|
716
|
+
/**
|
|
717
|
+
* Resolve the provider request timeout (ms) from the operator override.
|
|
718
|
+
*
|
|
719
|
+
* Default is effectively NO TIMEOUT — safe for streaming APIs where the model
|
|
720
|
+
* sends chunks continuously. But Node's timers are 32-bit: a duration above
|
|
721
|
+
* 2**31-1 ms overflows, which makes Node print a TimeoutOverflowWarning to
|
|
722
|
+
* stderr (corrupting the Ink TUI) AND silently clamp the timeout to 1ms,
|
|
723
|
+
* aborting the request almost immediately. So we use the largest SAFE timer
|
|
724
|
+
* value as the "no timeout" sentinel — never Number.MAX_SAFE_INTEGER — and
|
|
725
|
+
* clamp any operator-supplied value into range too.
|
|
726
|
+
*/
|
|
727
|
+
export function resolveRequestTimeoutMs(raw) {
|
|
728
|
+
const requested = parsePositiveInt(raw);
|
|
729
|
+
return Math.min(requested ?? MAX_TIMER_MS, MAX_TIMER_MS);
|
|
730
|
+
}
|
|
707
731
|
function mergeStreamingText(current, incoming, mode) {
|
|
708
732
|
if (!current)
|
|
709
733
|
return { args: incoming, delta: incoming };
|
package/dist/session.d.ts
CHANGED
|
@@ -57,6 +57,22 @@ export declare class SessionManager {
|
|
|
57
57
|
appendTodosSnapshot(todos: Todo[]): void;
|
|
58
58
|
getTodos(): Todo[];
|
|
59
59
|
compact(options?: CompactOptions): CompactResult;
|
|
60
|
+
/**
|
|
61
|
+
* Inspect whether the session is large enough to compact and, if so, return
|
|
62
|
+
* the older messages an external summarizer should condense. Returns null
|
|
63
|
+
* when there isn't enough history past the last summary to bother — the
|
|
64
|
+
* caller should then report "already compact enough" without calling a model.
|
|
65
|
+
*/
|
|
66
|
+
getCompactionPlan(options?: CompactOptions): {
|
|
67
|
+
oldMessages: Message[];
|
|
68
|
+
} | null;
|
|
69
|
+
/**
|
|
70
|
+
* Apply a precomputed (typically LLM-generated) summary as the compaction
|
|
71
|
+
* checkpoint, rewriting the log to [metadata, summary, kept turns]. Mirrors
|
|
72
|
+
* `compact()` but skips the built-in heuristic summarizer. Returns
|
|
73
|
+
* `{ compacted: false }` if the session is no longer compactable.
|
|
74
|
+
*/
|
|
75
|
+
applyLLMCompaction(summary: string, options?: CompactOptions): CompactResult;
|
|
60
76
|
getMessages(): Message[];
|
|
61
77
|
/**
|
|
62
78
|
* Pre-edit file snapshot store for this session, used by /rewind.
|
package/dist/session.js
CHANGED
|
@@ -6,7 +6,7 @@ import { mkdirSync, appendFileSync, existsSync, readFileSync, readdirSync, statS
|
|
|
6
6
|
import { basename, dirname, join } from "node:path";
|
|
7
7
|
import { getBubbleHome } from "./bubble-home.js";
|
|
8
8
|
import { CheckpointStore } from "./checkpoints.js";
|
|
9
|
-
import { compactSessionEntries } from "./context/compact.js";
|
|
9
|
+
import { buildCompactedEntries, compactSessionEntries, planOldMessages, planSessionCompaction, } from "./context/compact.js";
|
|
10
10
|
import { SessionLog } from "./session-log.js";
|
|
11
11
|
import { normalizeSingleLine, truncateVisual } from "./text-display.js";
|
|
12
12
|
import { deterministicTitleFromUserContent } from "./session-title.js";
|
|
@@ -162,6 +162,38 @@ export class SessionManager {
|
|
|
162
162
|
}
|
|
163
163
|
return result;
|
|
164
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Inspect whether the session is large enough to compact and, if so, return
|
|
167
|
+
* the older messages an external summarizer should condense. Returns null
|
|
168
|
+
* when there isn't enough history past the last summary to bother — the
|
|
169
|
+
* caller should then report "already compact enough" without calling a model.
|
|
170
|
+
*/
|
|
171
|
+
getCompactionPlan(options) {
|
|
172
|
+
const plan = planSessionCompaction(this.log.list(), options);
|
|
173
|
+
if (!plan.compactable)
|
|
174
|
+
return null;
|
|
175
|
+
return { oldMessages: planOldMessages(plan) };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Apply a precomputed (typically LLM-generated) summary as the compaction
|
|
179
|
+
* checkpoint, rewriting the log to [metadata, summary, kept turns]. Mirrors
|
|
180
|
+
* `compact()` but skips the built-in heuristic summarizer. Returns
|
|
181
|
+
* `{ compacted: false }` if the session is no longer compactable.
|
|
182
|
+
*/
|
|
183
|
+
applyLLMCompaction(summary, options) {
|
|
184
|
+
const entries = this.log.list();
|
|
185
|
+
const plan = planSessionCompaction(entries, options);
|
|
186
|
+
if (!plan.compactable)
|
|
187
|
+
return { compacted: false };
|
|
188
|
+
const nextEntries = buildCompactedEntries(entries, plan, summary);
|
|
189
|
+
this.rewrite(nextEntries);
|
|
190
|
+
return {
|
|
191
|
+
compacted: true,
|
|
192
|
+
summary,
|
|
193
|
+
entries: nextEntries,
|
|
194
|
+
droppedEntries: plan.oldEntries.length,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
165
197
|
getMessages() {
|
|
166
198
|
return this.log.toMessages();
|
|
167
199
|
}
|
|
@@ -306,6 +306,13 @@ const builtinSlashCommandEntries = [
|
|
|
306
306
|
ctx.openPicker("skill");
|
|
307
307
|
},
|
|
308
308
|
},
|
|
309
|
+
{
|
|
310
|
+
name: "agents",
|
|
311
|
+
description: "Inspect spawned subagents and their working traces (also Ctrl+G)",
|
|
312
|
+
async handler(_args, ctx) {
|
|
313
|
+
ctx.openPicker("agents");
|
|
314
|
+
},
|
|
315
|
+
},
|
|
309
316
|
{
|
|
310
317
|
name: "help",
|
|
311
318
|
description: "Show available slash commands",
|
|
@@ -978,7 +985,46 @@ const builtinSlashCommandEntries = [
|
|
|
978
985
|
if (preHook?.decision === "deny") {
|
|
979
986
|
return preHook.reason ?? `Compaction blocked by hook ${preHook.sourceHookId ?? "<unknown>"}.`;
|
|
980
987
|
}
|
|
981
|
-
|
|
988
|
+
// Plan first so we can report "already compact" without spending a model
|
|
989
|
+
// call, and so the LLM summarizer gets the exact set of evicted messages.
|
|
990
|
+
const plan = ctx.sessionManager.getCompactionPlan();
|
|
991
|
+
if (!plan) {
|
|
992
|
+
await ctx.hookController?.runEvent({
|
|
993
|
+
eventName: "PostCompact",
|
|
994
|
+
cwd: ctx.cwd,
|
|
995
|
+
sessionId: ctx.sessionManager.getSessionFile(),
|
|
996
|
+
agentRole: "driver",
|
|
997
|
+
target: "manual",
|
|
998
|
+
payload: { kind: "manual", compacted: false },
|
|
999
|
+
});
|
|
1000
|
+
return "Session is already compact enough.";
|
|
1001
|
+
}
|
|
1002
|
+
// Stream an LLM summary for high fidelity, reporting progress to the TUI.
|
|
1003
|
+
// On any failure (or empty output) fall back to the instant heuristic
|
|
1004
|
+
// compaction so /compact always makes progress.
|
|
1005
|
+
let result;
|
|
1006
|
+
try {
|
|
1007
|
+
ctx.compactionProgress?.({ phase: "collecting", streamedChars: 0 });
|
|
1008
|
+
let summary = "";
|
|
1009
|
+
try {
|
|
1010
|
+
summary = await ctx.agent.summarizeForCompaction(plan.oldMessages, (full) => {
|
|
1011
|
+
ctx.compactionProgress?.({ phase: "summarizing", streamedChars: full.length });
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
catch {
|
|
1015
|
+
summary = "";
|
|
1016
|
+
}
|
|
1017
|
+
if (summary) {
|
|
1018
|
+
ctx.compactionProgress?.({ phase: "applying", streamedChars: summary.length });
|
|
1019
|
+
result = ctx.sessionManager.applyLLMCompaction(summary);
|
|
1020
|
+
}
|
|
1021
|
+
else {
|
|
1022
|
+
result = ctx.sessionManager.compact();
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
finally {
|
|
1026
|
+
ctx.compactionProgress?.(null);
|
|
1027
|
+
}
|
|
982
1028
|
if (!result.compacted) {
|
|
983
1029
|
await ctx.hookController?.runEvent({
|
|
984
1030
|
eventName: "PostCompact",
|
|
@@ -11,6 +11,16 @@ import type { MemoryScope } from "../memory/index.js";
|
|
|
11
11
|
import type { ThemeMode } from "../config.js";
|
|
12
12
|
import type { ExternalHookController } from "../hooks/controller.js";
|
|
13
13
|
export type SidebarMode = "auto" | "expanded" | "collapsed";
|
|
14
|
+
/**
|
|
15
|
+
* Live progress for a manual `/compact` run, pushed to the TUI so it can render
|
|
16
|
+
* a progress bar. `phase` advances collecting → summarizing → applying;
|
|
17
|
+
* `streamedChars` is the running length of the streamed summary (drives the
|
|
18
|
+
* bar's fill within the summarizing phase). Hosts without a UI omit the sink.
|
|
19
|
+
*/
|
|
20
|
+
export interface CompactionProgress {
|
|
21
|
+
phase: "collecting" | "summarizing" | "applying";
|
|
22
|
+
streamedChars: number;
|
|
23
|
+
}
|
|
14
24
|
export interface SidebarCommandState {
|
|
15
25
|
mode: SidebarMode;
|
|
16
26
|
visible: boolean;
|
|
@@ -24,7 +34,7 @@ export interface SlashCommandContext {
|
|
|
24
34
|
exit: () => void;
|
|
25
35
|
sessionManager?: SessionManager;
|
|
26
36
|
createProvider: (providerId: string, apiKey: string, baseURL: string) => Provider;
|
|
27
|
-
openPicker: (mode: "model" | "key" | "provider" | "provider-add" | "login" | "logout" | "skill" | "feishu-setup", providerId?: string) => void;
|
|
37
|
+
openPicker: (mode: "model" | "key" | "provider" | "provider-add" | "login" | "logout" | "skill" | "feishu-setup" | "agents", providerId?: string) => void;
|
|
28
38
|
registry: ProviderRegistry;
|
|
29
39
|
skillRegistry: SkillRegistry;
|
|
30
40
|
bashAllowlist?: BashAllowlist;
|
|
@@ -56,6 +66,11 @@ export interface SlashCommandContext {
|
|
|
56
66
|
fillComposer?: (text: string) => void;
|
|
57
67
|
/** Open the interactive usage stats panel. */
|
|
58
68
|
openStats?: () => void;
|
|
69
|
+
/**
|
|
70
|
+
* Push live compaction progress to the running TUI. Pass a progress object
|
|
71
|
+
* while compacting and `null` to clear the indicator. Absent in non-TUI hosts.
|
|
72
|
+
*/
|
|
73
|
+
compactionProgress?: (progress: CompactionProgress | null) => void;
|
|
59
74
|
}
|
|
60
75
|
/**
|
|
61
76
|
* Return types for a slash command handler:
|
|
@@ -28,5 +28,11 @@ export declare function createListAgentsTool(): ToolRegistryEntry;
|
|
|
28
28
|
export declare const AGENT_TEAM_MIN_ITEMS = 2;
|
|
29
29
|
export declare const AGENT_TEAM_MAX_ITEMS = 32;
|
|
30
30
|
export declare function createAgentTeamTool(options?: AgentLifecycleToolOptions, sharedTrust?: ProjectProfileTrust): ToolRegistryEntry;
|
|
31
|
+
/** Specs bound for one agent_batch call (design v2 §1.3). */
|
|
32
|
+
export declare const AGENT_BATCH_MIN_SPECS = 2;
|
|
33
|
+
export declare const AGENT_BATCH_MAX_SPECS = 32;
|
|
34
|
+
export declare function createAgentBatchTool(options?: AgentLifecycleToolOptions, sharedTrust?: ProjectProfileTrust): ToolRegistryEntry;
|
|
35
|
+
export declare function createRunWorkflowTool(options?: AgentLifecycleToolOptions): ToolRegistryEntry;
|
|
36
|
+
export declare function createWaitWorkflowTool(): ToolRegistryEntry;
|
|
31
37
|
export declare function createAgentLifecycleTools(options?: AgentLifecycleToolOptions): ToolRegistryEntry[];
|
|
32
38
|
export {};
|