@bubblebrain-ai/bubble 0.0.8 → 0.0.9
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/agent/categories.d.ts +34 -0
- package/dist/agent/categories.js +98 -0
- package/dist/agent/profiles.d.ts +4 -0
- package/dist/agent/profiles.js +2 -3
- package/dist/agent/subagent-control.d.ts +5 -0
- package/dist/agent/subagent-control.js +4 -0
- package/dist/agent/subagent-lifecycle-reminder.d.ts +3 -0
- package/dist/agent/subagent-lifecycle-reminder.js +102 -0
- package/dist/agent/subagent-route-format.d.ts +8 -0
- package/dist/agent/subagent-route-format.js +18 -0
- package/dist/agent/subtask-policy.d.ts +0 -1
- package/dist/agent/subtask-policy.js +0 -4
- package/dist/agent.d.ts +12 -0
- package/dist/agent.js +152 -13
- package/dist/config.d.ts +23 -3
- package/dist/config.js +59 -6
- package/dist/context/budget.d.ts +3 -3
- package/dist/context/budget.js +29 -15
- package/dist/context/compact.d.ts +23 -0
- package/dist/context/compact.js +129 -0
- package/dist/context/llm-compactor.d.ts +19 -0
- package/dist/context/llm-compactor.js +200 -0
- package/dist/context/projector.js +28 -12
- package/dist/context/token-estimator.d.ts +14 -0
- package/dist/context/token-estimator.js +106 -0
- package/dist/context/tool-output-truncate.d.ts +8 -0
- package/dist/context/tool-output-truncate.js +59 -0
- package/dist/context/usage.js +9 -9
- package/dist/main.js +43 -6
- package/dist/model-catalog.d.ts +9 -0
- package/dist/model-catalog.js +16 -0
- package/dist/orchestrator/default-hooks.js +18 -0
- package/dist/provider-openai-codex.d.ts +13 -2
- package/dist/provider-openai-codex.js +81 -32
- package/dist/provider-registry.js +20 -4
- package/dist/slash-commands/commands.js +24 -0
- package/dist/slash-commands/types.d.ts +7 -0
- package/dist/tools/agent-lifecycle.js +22 -4
- package/dist/tools/edit.js +2 -2
- package/dist/tools/glob.js +2 -1
- package/dist/tools/grep.js +2 -2
- package/dist/tools/lsp.js +2 -2
- package/dist/tools/path-utils.d.ts +2 -0
- package/dist/tools/path-utils.js +16 -0
- package/dist/tools/read.js +117 -5
- package/dist/tools/write.js +3 -2
- package/dist/tui-ink/app.d.ts +11 -2
- package/dist/tui-ink/app.js +191 -78
- package/dist/tui-ink/approval/approval-dialog.js +4 -1
- package/dist/tui-ink/approval/diff-view.js +2 -1
- package/dist/tui-ink/approval/select.js +2 -1
- package/dist/tui-ink/code-highlight.d.ts +2 -0
- package/dist/tui-ink/code-highlight.js +30 -2
- package/dist/tui-ink/detect-theme.d.ts +19 -0
- package/dist/tui-ink/detect-theme.js +123 -0
- package/dist/tui-ink/footer.js +4 -3
- package/dist/tui-ink/input-box.js +83 -26
- package/dist/tui-ink/input-history.d.ts +16 -0
- package/dist/tui-ink/input-history.js +81 -0
- package/dist/tui-ink/markdown.js +30 -20
- package/dist/tui-ink/message-list.js +112 -16
- package/dist/tui-ink/model-picker.js +6 -1
- package/dist/tui-ink/plan-confirm.js +2 -1
- package/dist/tui-ink/question-dialog.js +2 -1
- package/dist/tui-ink/run.d.ts +5 -1
- package/dist/tui-ink/run.js +30 -2
- package/dist/tui-ink/theme.d.ts +64 -35
- package/dist/tui-ink/theme.js +81 -8
- package/dist/tui-ink/todos.js +5 -3
- package/dist/tui-ink/trace-groups.d.ts +3 -1
- package/dist/tui-ink/trace-groups.js +93 -14
- package/dist/tui-ink/welcome.js +23 -4
- package/dist/types.d.ts +6 -0
- package/package.json +2 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ThinkingLevel } from "../types.js";
|
|
2
|
+
export interface AgentCategoryConfig {
|
|
3
|
+
model?: string;
|
|
4
|
+
thinkingLevel?: ThinkingLevel;
|
|
5
|
+
maxConcurrent?: number;
|
|
6
|
+
}
|
|
7
|
+
export type AgentCategoriesConfig = Record<string, AgentCategoryConfig>;
|
|
8
|
+
export interface ModelRoute {
|
|
9
|
+
providerId: string;
|
|
10
|
+
model: string;
|
|
11
|
+
thinkingLevel: ThinkingLevel;
|
|
12
|
+
}
|
|
13
|
+
export interface ResolvedSubagentRoute extends ModelRoute {
|
|
14
|
+
category?: string;
|
|
15
|
+
inherited: boolean;
|
|
16
|
+
}
|
|
17
|
+
export type CategoryResolution = {
|
|
18
|
+
route: ResolvedSubagentRoute;
|
|
19
|
+
} | {
|
|
20
|
+
error: string;
|
|
21
|
+
};
|
|
22
|
+
export interface ResolvedModelSelection {
|
|
23
|
+
providerId: string;
|
|
24
|
+
model: string | "inherit";
|
|
25
|
+
}
|
|
26
|
+
export declare function builtinAgentCategories(): AgentCategoriesConfig;
|
|
27
|
+
export declare function mergeAgentCategories(userCategories?: AgentCategoriesConfig): AgentCategoriesConfig;
|
|
28
|
+
export declare function sanitizeAgentCategories(value: unknown): AgentCategoriesConfig;
|
|
29
|
+
export declare function resolveSubagentRoute(category: string | undefined, parent: ModelRoute, categories?: AgentCategoriesConfig): CategoryResolution;
|
|
30
|
+
export declare function resolveModelRoute(model: string | undefined, parentProviderId: string): ResolvedModelSelection;
|
|
31
|
+
export declare function resolveSameProviderModelRoute(model: string | undefined, parentProviderId: string): {
|
|
32
|
+
model: string | "inherit";
|
|
33
|
+
};
|
|
34
|
+
export declare function normalizeCategoryName(value: unknown): string | undefined;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const THINKING_LEVELS = new Set([
|
|
2
|
+
"off",
|
|
3
|
+
"minimal",
|
|
4
|
+
"low",
|
|
5
|
+
"medium",
|
|
6
|
+
"high",
|
|
7
|
+
"xhigh",
|
|
8
|
+
"max",
|
|
9
|
+
]);
|
|
10
|
+
const BUILTIN_CATEGORIES = {
|
|
11
|
+
quick: { model: "inherit", thinkingLevel: "low", maxConcurrent: 3 },
|
|
12
|
+
deep: { model: "inherit", thinkingLevel: "high", maxConcurrent: 2 },
|
|
13
|
+
explore: { model: "inherit", thinkingLevel: "low", maxConcurrent: 3 },
|
|
14
|
+
review: { model: "inherit", thinkingLevel: "high", maxConcurrent: 2 },
|
|
15
|
+
frontend: { model: "inherit", thinkingLevel: "high", maxConcurrent: 1 },
|
|
16
|
+
writing: { model: "inherit", thinkingLevel: "medium", maxConcurrent: 2 },
|
|
17
|
+
};
|
|
18
|
+
export function builtinAgentCategories() {
|
|
19
|
+
return cloneCategories(BUILTIN_CATEGORIES);
|
|
20
|
+
}
|
|
21
|
+
export function mergeAgentCategories(userCategories) {
|
|
22
|
+
const merged = builtinAgentCategories();
|
|
23
|
+
for (const [name, config] of Object.entries(sanitizeAgentCategories(userCategories))) {
|
|
24
|
+
merged[name] = {
|
|
25
|
+
...(merged[name] ?? {}),
|
|
26
|
+
...config,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return merged;
|
|
30
|
+
}
|
|
31
|
+
export function sanitizeAgentCategories(value) {
|
|
32
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
33
|
+
return {};
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const [name, raw] of Object.entries(value)) {
|
|
36
|
+
const normalizedName = normalizeCategoryName(name);
|
|
37
|
+
if (!normalizedName || !raw || typeof raw !== "object" || Array.isArray(raw))
|
|
38
|
+
continue;
|
|
39
|
+
const record = raw;
|
|
40
|
+
const config = {};
|
|
41
|
+
if (typeof record.model === "string" && record.model.trim()) {
|
|
42
|
+
config.model = record.model.trim();
|
|
43
|
+
}
|
|
44
|
+
if (isThinkingLevel(record.thinkingLevel)) {
|
|
45
|
+
config.thinkingLevel = record.thinkingLevel;
|
|
46
|
+
}
|
|
47
|
+
if (typeof record.maxConcurrent === "number" && Number.isFinite(record.maxConcurrent)) {
|
|
48
|
+
config.maxConcurrent = Math.max(1, Math.floor(record.maxConcurrent));
|
|
49
|
+
}
|
|
50
|
+
out[normalizedName] = config;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
export function resolveSubagentRoute(category, parent, categories) {
|
|
55
|
+
const normalizedCategory = normalizeCategoryName(category);
|
|
56
|
+
if (!normalizedCategory) {
|
|
57
|
+
return { route: { ...parent, inherited: true } };
|
|
58
|
+
}
|
|
59
|
+
const merged = mergeAgentCategories(categories);
|
|
60
|
+
const config = merged[normalizedCategory];
|
|
61
|
+
if (!config) {
|
|
62
|
+
return { error: `Unknown subagent category "${normalizedCategory}".` };
|
|
63
|
+
}
|
|
64
|
+
const modelSelection = parseModelSelection(config.model, parent.providerId);
|
|
65
|
+
return {
|
|
66
|
+
route: {
|
|
67
|
+
category: normalizedCategory,
|
|
68
|
+
providerId: modelSelection.providerId,
|
|
69
|
+
model: modelSelection.model === "inherit" ? parent.model : modelSelection.model,
|
|
70
|
+
thinkingLevel: config.thinkingLevel ?? parent.thinkingLevel,
|
|
71
|
+
inherited: modelSelection.model === "inherit" && config.thinkingLevel === undefined,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function resolveModelRoute(model, parentProviderId) {
|
|
76
|
+
return parseModelSelection(model, parentProviderId);
|
|
77
|
+
}
|
|
78
|
+
export function resolveSameProviderModelRoute(model, parentProviderId) {
|
|
79
|
+
return { model: parseModelSelection(model, parentProviderId).model };
|
|
80
|
+
}
|
|
81
|
+
export function normalizeCategoryName(value) {
|
|
82
|
+
return typeof value === "string" && value.trim() ? value.trim().toLowerCase() : undefined;
|
|
83
|
+
}
|
|
84
|
+
function parseModelSelection(model, parentProviderId) {
|
|
85
|
+
if (!model || model === "inherit")
|
|
86
|
+
return { providerId: parentProviderId, model: "inherit" };
|
|
87
|
+
if (model.includes(":")) {
|
|
88
|
+
const [providerId, ...rest] = model.split(":");
|
|
89
|
+
return { providerId: providerId || parentProviderId, model: rest.join(":") };
|
|
90
|
+
}
|
|
91
|
+
return { providerId: parentProviderId, model };
|
|
92
|
+
}
|
|
93
|
+
function isThinkingLevel(value) {
|
|
94
|
+
return typeof value === "string" && THINKING_LEVELS.has(value);
|
|
95
|
+
}
|
|
96
|
+
function cloneCategories(categories) {
|
|
97
|
+
return Object.fromEntries(Object.entries(categories).map(([name, config]) => [name, { ...config }]));
|
|
98
|
+
}
|
package/dist/agent/profiles.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ToolRegistryEntry, TokenUsage } from "../types.js";
|
|
2
|
+
import type { ResolvedSubagentRoute } from "./categories.js";
|
|
2
3
|
import { type SubtaskType } from "./subtask-policy.js";
|
|
3
4
|
export type AgentProfileSource = "user" | "project" | "builtin";
|
|
4
5
|
export type AgentProfileMode = "readonly" | "write_patch" | "write_worktree";
|
|
@@ -16,6 +17,7 @@ export interface AgentProfile {
|
|
|
16
17
|
filePath?: string;
|
|
17
18
|
mode: AgentProfileMode;
|
|
18
19
|
model?: string | "inherit";
|
|
20
|
+
category?: string;
|
|
19
21
|
tools: AgentProfileTools;
|
|
20
22
|
maxTurns?: number;
|
|
21
23
|
approval: AgentProfileApproval;
|
|
@@ -29,6 +31,8 @@ export interface SubagentRunResult {
|
|
|
29
31
|
nickname?: string;
|
|
30
32
|
status: "completed" | "failed" | "blocked" | "cancelled";
|
|
31
33
|
profileSource: AgentProfileSource;
|
|
34
|
+
category?: string;
|
|
35
|
+
route?: ResolvedSubagentRoute;
|
|
32
36
|
task: string;
|
|
33
37
|
summary: string;
|
|
34
38
|
toolNotes: string[];
|
package/dist/agent/profiles.js
CHANGED
|
@@ -85,7 +85,6 @@ export function builtinAgentProfiles() {
|
|
|
85
85
|
include: [...policy.allowedTools],
|
|
86
86
|
exclude: [],
|
|
87
87
|
},
|
|
88
|
-
maxTurns: policy.maxTurns,
|
|
89
88
|
approval: "fail",
|
|
90
89
|
nicknameCandidates: DEFAULT_NICKNAME_CANDIDATES,
|
|
91
90
|
prompt: policy.reminder,
|
|
@@ -103,7 +102,6 @@ export function builtinAgentProfiles() {
|
|
|
103
102
|
include,
|
|
104
103
|
exclude: [],
|
|
105
104
|
},
|
|
106
|
-
maxTurns: 8,
|
|
107
105
|
approval: "fail",
|
|
108
106
|
nicknameCandidates: DEFAULT_NICKNAME_CANDIDATES,
|
|
109
107
|
prompt,
|
|
@@ -119,7 +117,7 @@ export function builtinAgentProfiles() {
|
|
|
119
117
|
"Answer the specific question by inspecting the repository directly. Prefer precise file paths and line-level evidence.",
|
|
120
118
|
"Keep the answer compact and avoid broad refactors or implementation plans unless asked.",
|
|
121
119
|
].join("\n"), ["read", "glob", "grep", "lsp", "memory_search", "memory_read_summary", "skill", "todo_write"]),
|
|
122
|
-
roleProfile("worker", "
|
|
120
|
+
roleProfile("worker", "Implementation-planning worker subagent", [
|
|
123
121
|
"You are a worker subagent. In this Phase 1 runtime you are read-only, so you must not modify files.",
|
|
124
122
|
"Analyze the assigned implementation slice, identify exact files to change, and return a concrete patch plan or findings.",
|
|
125
123
|
"If write-capable worker mode is needed, say so explicitly.",
|
|
@@ -298,6 +296,7 @@ function parseAgentProfileFile(raw, source, filePath) {
|
|
|
298
296
|
filePath,
|
|
299
297
|
mode: modeValue(frontmatter.mode),
|
|
300
298
|
model: stringValue(frontmatter.model) || "inherit",
|
|
299
|
+
category: stringValue(frontmatter.category),
|
|
301
300
|
tools: toolsValue(frontmatter.tools),
|
|
302
301
|
maxTurns: numberValue(frontmatter.maxTurns),
|
|
303
302
|
approval: approvalValue(frontmatter.approval),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentProfile, AgentProfileSource, SubagentRunResult } from "./profiles.js";
|
|
2
|
+
import type { ResolvedSubagentRoute } from "./categories.js";
|
|
2
3
|
import type { AgentEvent, ContentPart, Message, ToolUpdate } from "../types.js";
|
|
3
4
|
export type SubagentThreadStatus = "queued" | "running" | "completed" | "failed" | "blocked" | "cancelled" | "closed";
|
|
4
5
|
export interface SubagentThreadSnapshot {
|
|
@@ -7,6 +8,8 @@ export interface SubagentThreadSnapshot {
|
|
|
7
8
|
nickname: string;
|
|
8
9
|
agentName: string;
|
|
9
10
|
profileSource: AgentProfileSource;
|
|
11
|
+
category?: string;
|
|
12
|
+
route?: ResolvedSubagentRoute;
|
|
10
13
|
status: SubagentThreadStatus;
|
|
11
14
|
task: string;
|
|
12
15
|
summary: string;
|
|
@@ -21,6 +24,8 @@ export interface SubagentThreadRecord {
|
|
|
21
24
|
runId: string;
|
|
22
25
|
nickname: string;
|
|
23
26
|
profile: AgentProfile;
|
|
27
|
+
category?: string;
|
|
28
|
+
route?: ResolvedSubagentRoute;
|
|
24
29
|
parentToolCallId: string;
|
|
25
30
|
parentToolName: string;
|
|
26
31
|
status: SubagentThreadStatus;
|
|
@@ -5,6 +5,8 @@ export function snapshotSubagentThread(record) {
|
|
|
5
5
|
nickname: record.nickname,
|
|
6
6
|
agentName: record.profile.name,
|
|
7
7
|
profileSource: record.profile.source,
|
|
8
|
+
category: record.category,
|
|
9
|
+
route: record.route,
|
|
8
10
|
status: record.status,
|
|
9
11
|
task: record.task,
|
|
10
12
|
summary: record.summary,
|
|
@@ -29,6 +31,8 @@ export function subagentResultFromThread(record) {
|
|
|
29
31
|
nickname: record.nickname,
|
|
30
32
|
status,
|
|
31
33
|
profileSource: record.profile.source,
|
|
34
|
+
category: record.category,
|
|
35
|
+
route: record.route,
|
|
32
36
|
task: record.task,
|
|
33
37
|
summary: record.summary,
|
|
34
38
|
toolNotes: [...record.toolNotes],
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const STATUS_ORDER = ["queued", "running", "completed", "blocked", "failed", "cancelled", "closed"];
|
|
2
|
+
export function buildSubagentLifecycleReminder(snapshots, toolResults) {
|
|
3
|
+
const subagents = collectUniqueSubagents(snapshots, toolResults);
|
|
4
|
+
if (subagents.length === 0)
|
|
5
|
+
return undefined;
|
|
6
|
+
const counts = statusCounts(subagents);
|
|
7
|
+
const lines = [
|
|
8
|
+
"Subagent lifecycle truth:",
|
|
9
|
+
`- Unique subagents currently tracked: ${subagents.length}.`,
|
|
10
|
+
`- Status counts: ${formatStatusCounts(counts)}.`,
|
|
11
|
+
"- Agents:",
|
|
12
|
+
...subagents.map(formatSubagentLine),
|
|
13
|
+
"- Count unique agent_id values only; do not count repeated spawn_agent/wait_agent tool calls or repeated UI Subagents blocks as additional subagents.",
|
|
14
|
+
"- Do not describe a subagent as running or still working if its status above is completed, failed, blocked, cancelled, or closed.",
|
|
15
|
+
"- After spawn_agent, call wait_agent before user-facing progress narration unless you are doing concrete non-overlapping local work.",
|
|
16
|
+
"- When writing a synthesis, use the exact unique subagent count and statuses above.",
|
|
17
|
+
];
|
|
18
|
+
return lines.join("\n");
|
|
19
|
+
}
|
|
20
|
+
function collectUniqueSubagents(snapshots, toolResults) {
|
|
21
|
+
const byId = new Map();
|
|
22
|
+
for (const result of toolResults) {
|
|
23
|
+
for (const subagent of subagentsFromMetadata(result.metadata)) {
|
|
24
|
+
byId.set(subagent.agentId, {
|
|
25
|
+
...byId.get(subagent.agentId),
|
|
26
|
+
...subagent,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const snapshot of snapshots) {
|
|
31
|
+
byId.set(snapshot.agentId, {
|
|
32
|
+
...byId.get(snapshot.agentId),
|
|
33
|
+
agentId: snapshot.agentId,
|
|
34
|
+
nickname: snapshot.nickname,
|
|
35
|
+
agentName: snapshot.agentName,
|
|
36
|
+
category: snapshot.category,
|
|
37
|
+
status: snapshot.status,
|
|
38
|
+
summary: snapshot.summary,
|
|
39
|
+
error: snapshot.error,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return [...byId.values()].sort((a, b) => a.agentId.localeCompare(b.agentId));
|
|
43
|
+
}
|
|
44
|
+
function subagentsFromMetadata(metadata) {
|
|
45
|
+
const raw = metadata?.subagents;
|
|
46
|
+
if (!Array.isArray(raw))
|
|
47
|
+
return [];
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const item of raw) {
|
|
50
|
+
if (!item || typeof item !== "object")
|
|
51
|
+
continue;
|
|
52
|
+
const record = item;
|
|
53
|
+
const agentId = stringField(record.subAgentId) ?? stringField(record.agentId);
|
|
54
|
+
if (!agentId)
|
|
55
|
+
continue;
|
|
56
|
+
out.push({
|
|
57
|
+
agentId,
|
|
58
|
+
nickname: stringField(record.nickname),
|
|
59
|
+
agentName: stringField(record.agentName),
|
|
60
|
+
category: stringField(record.category),
|
|
61
|
+
status: stringField(record.status),
|
|
62
|
+
summary: stringField(record.summary),
|
|
63
|
+
error: stringField(record.error),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function statusCounts(subagents) {
|
|
69
|
+
const counts = new Map();
|
|
70
|
+
for (const subagent of subagents) {
|
|
71
|
+
const status = subagent.status || "unknown";
|
|
72
|
+
counts.set(status, (counts.get(status) ?? 0) + 1);
|
|
73
|
+
}
|
|
74
|
+
return counts;
|
|
75
|
+
}
|
|
76
|
+
function formatStatusCounts(counts) {
|
|
77
|
+
const known = STATUS_ORDER
|
|
78
|
+
.filter((status) => counts.has(status))
|
|
79
|
+
.map((status) => `${status}=${counts.get(status)}`);
|
|
80
|
+
const extra = [...counts.keys()]
|
|
81
|
+
.filter((status) => !STATUS_ORDER.includes(status))
|
|
82
|
+
.sort()
|
|
83
|
+
.map((status) => `${status}=${counts.get(status)}`);
|
|
84
|
+
return [...known, ...extra].join(", ") || "none";
|
|
85
|
+
}
|
|
86
|
+
function formatSubagentLine(subagent) {
|
|
87
|
+
const label = subagent.nickname || subagent.agentName || subagent.agentId;
|
|
88
|
+
const role = [subagent.agentName, subagent.category ? `/${subagent.category}` : ""].join("") || "default";
|
|
89
|
+
const status = subagent.status || "unknown";
|
|
90
|
+
const note = subagent.error || subagent.summary;
|
|
91
|
+
const suffix = note ? `; note=${truncateForReminder(oneLine(note))}` : "";
|
|
92
|
+
return ` - ${label} (${role}) agent_id=${subagent.agentId} status=${status}${suffix}`;
|
|
93
|
+
}
|
|
94
|
+
function stringField(value) {
|
|
95
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
96
|
+
}
|
|
97
|
+
function oneLine(value) {
|
|
98
|
+
return value.replace(/\s+/g, " ").trim();
|
|
99
|
+
}
|
|
100
|
+
function truncateForReminder(value, max = 180) {
|
|
101
|
+
return value.length <= max ? value : `${value.slice(0, max - 3)}...`;
|
|
102
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function formatSubagentRoute(route, options = {}) {
|
|
2
|
+
if (!route || typeof route !== "object")
|
|
3
|
+
return undefined;
|
|
4
|
+
const providerId = stringField(route.providerId);
|
|
5
|
+
const model = stringField(route.model);
|
|
6
|
+
if (!providerId && !model)
|
|
7
|
+
return undefined;
|
|
8
|
+
const modelLabel = providerId && model
|
|
9
|
+
? `${providerId}:${model}`
|
|
10
|
+
: providerId || model;
|
|
11
|
+
if (!options.includeThinking)
|
|
12
|
+
return modelLabel;
|
|
13
|
+
const thinkingLevel = stringField(route.thinkingLevel);
|
|
14
|
+
return thinkingLevel ? `${modelLabel} (thinking: ${thinkingLevel})` : modelLabel;
|
|
15
|
+
}
|
|
16
|
+
function stringField(value) {
|
|
17
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
18
|
+
}
|
|
@@ -9,7 +9,6 @@ const POLICY_MAP = {
|
|
|
9
9
|
"- Return a concise summary of what you found and where.",
|
|
10
10
|
].join("\n"),
|
|
11
11
|
resultStatus: "success",
|
|
12
|
-
maxTurns: 6,
|
|
13
12
|
taskBudget: { total: 180_000 },
|
|
14
13
|
},
|
|
15
14
|
security_investigation: {
|
|
@@ -22,7 +21,6 @@ const POLICY_MAP = {
|
|
|
22
21
|
"- Do not loop on broad keyword search; summarize evidence and uncertainty.",
|
|
23
22
|
].join("\n"),
|
|
24
23
|
resultStatus: "success",
|
|
25
|
-
maxTurns: 8,
|
|
26
24
|
taskBudget: { total: 220_000 },
|
|
27
25
|
},
|
|
28
26
|
evidence_correlation: {
|
|
@@ -35,7 +33,6 @@ const POLICY_MAP = {
|
|
|
35
33
|
"- Produce a reasoning-focused summary that states what the evidence supports.",
|
|
36
34
|
].join("\n"),
|
|
37
35
|
resultStatus: "success",
|
|
38
|
-
maxTurns: 4,
|
|
39
36
|
taskBudget: { total: 120_000 },
|
|
40
37
|
},
|
|
41
38
|
general_readonly: {
|
|
@@ -47,7 +44,6 @@ const POLICY_MAP = {
|
|
|
47
44
|
"- Keep the scope tightly bounded and summarize findings concisely.",
|
|
48
45
|
].join("\n"),
|
|
49
46
|
resultStatus: "success",
|
|
50
|
-
maxTurns: 6,
|
|
51
47
|
taskBudget: { total: 180_000 },
|
|
52
48
|
},
|
|
53
49
|
};
|
package/dist/agent.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { type ContextUsageSnapshot } from "./context/usage.js";
|
|
6
6
|
import type { AgentEvent, ContentPart, PermissionMode, Message, Provider, ThinkingLevel, Todo, ToolResult, ToolRegistryEntry, ToolUpdate } from "./types.js";
|
|
7
7
|
import { type TurnHooks } from "./orchestrator/hooks.js";
|
|
8
|
+
import { type AgentCategoriesConfig, type ResolvedSubagentRoute } from "./agent/categories.js";
|
|
8
9
|
import { BudgetLedger } from "./agent/budget-ledger.js";
|
|
9
10
|
import { type AgentProfile, type SubagentRunResult } from "./agent/profiles.js";
|
|
10
11
|
import { type SubagentThreadSnapshot } from "./agent/subagent-control.js";
|
|
@@ -42,6 +43,8 @@ export interface AgentOptions {
|
|
|
42
43
|
skills?: SkillSummary[];
|
|
43
44
|
memoryPrompt?: string;
|
|
44
45
|
fileStateTracker?: FileStateTracker;
|
|
46
|
+
agentCategories?: AgentCategoriesConfig;
|
|
47
|
+
providerFactory?: (route: ResolvedSubagentRoute) => Provider | Promise<Provider>;
|
|
45
48
|
}
|
|
46
49
|
export declare class Agent {
|
|
47
50
|
messages: Message[];
|
|
@@ -69,6 +72,8 @@ export declare class Agent {
|
|
|
69
72
|
private skillSummaries;
|
|
70
73
|
private memoryPrompt?;
|
|
71
74
|
private fileStateTracker?;
|
|
75
|
+
private agentCategories;
|
|
76
|
+
private providerFactory?;
|
|
72
77
|
private subagentThreads;
|
|
73
78
|
private pendingSubagentUpdates;
|
|
74
79
|
private lastInputTokens;
|
|
@@ -115,6 +120,7 @@ export declare class Agent {
|
|
|
115
120
|
}): AsyncIterable<AgentEvent>;
|
|
116
121
|
private recoverFromOverflow;
|
|
117
122
|
compactResidentHistory(): void;
|
|
123
|
+
private maybeCompactWithLLM;
|
|
118
124
|
runSubtask(input: string | ContentPart[], cwd: string, options?: {
|
|
119
125
|
subtaskType?: string;
|
|
120
126
|
description?: string;
|
|
@@ -124,6 +130,8 @@ export declare class Agent {
|
|
|
124
130
|
runId: string;
|
|
125
131
|
subAgentId: string;
|
|
126
132
|
parentToolCallId: string;
|
|
133
|
+
category?: string;
|
|
134
|
+
route?: ResolvedSubagentRoute;
|
|
127
135
|
approval?: "fail" | "disabled";
|
|
128
136
|
emitUpdate?: (update: ToolUpdate) => void;
|
|
129
137
|
description?: string;
|
|
@@ -134,6 +142,8 @@ export declare class Agent {
|
|
|
134
142
|
spawnSubAgent(input: string | ContentPart[], cwd: string, options: {
|
|
135
143
|
profile: AgentProfile;
|
|
136
144
|
parentToolCallId: string;
|
|
145
|
+
category?: string;
|
|
146
|
+
route?: ResolvedSubagentRoute;
|
|
137
147
|
approval?: "fail" | "disabled";
|
|
138
148
|
description?: string;
|
|
139
149
|
abortSignal?: AbortSignal;
|
|
@@ -150,10 +160,12 @@ export declare class Agent {
|
|
|
150
160
|
}): Promise<SubagentThreadSnapshot>;
|
|
151
161
|
closeSubAgent(agentId: string): Promise<SubagentThreadSnapshot>;
|
|
152
162
|
listSubAgents(): SubagentThreadSnapshot[];
|
|
163
|
+
private resolveRouteForSubagent;
|
|
153
164
|
private createSubagentThreadRecord;
|
|
154
165
|
private runSubagentThread;
|
|
155
166
|
private runSubagentFinalSummaryTurn;
|
|
156
167
|
private createSubAgentInstance;
|
|
168
|
+
private resolveProviderForRoute;
|
|
157
169
|
private forkMessagesForSubagent;
|
|
158
170
|
private buildSubagentUpdate;
|
|
159
171
|
private queueSubagentUpdate;
|