klaus-agent 0.3.1 → 0.4.1
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 +36 -2
- package/README.zh-CN.md +35 -1
- package/dist/approval/approval.d.ts +8 -3
- package/dist/approval/approval.js +23 -23
- package/dist/approval/approval.js.map +1 -1
- package/dist/approval/types.d.ts +1 -0
- package/dist/background/task-manager.d.ts +2 -0
- package/dist/background/task-manager.js +14 -0
- package/dist/background/task-manager.js.map +1 -1
- package/dist/compaction/compaction.d.ts +0 -1
- package/dist/compaction/compaction.js +21 -35
- package/dist/compaction/compaction.js.map +1 -1
- package/dist/compaction/summarizer.js +2 -7
- package/dist/compaction/summarizer.js.map +1 -1
- package/dist/core/agent-loop.d.ts +2 -1
- package/dist/core/agent-loop.js +14 -9
- package/dist/core/agent-loop.js.map +1 -1
- package/dist/core/agent.d.ts +7 -0
- package/dist/core/agent.js +35 -10
- package/dist/core/agent.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/injection/history-normalizer.js +20 -10
- package/dist/injection/history-normalizer.js.map +1 -1
- package/dist/llm/types.d.ts +2 -0
- package/dist/multi-agent/task-executor.d.ts +2 -1
- package/dist/multi-agent/types.d.ts +3 -0
- package/dist/planning/planning-manager.d.ts +2 -0
- package/dist/planning/planning-manager.js +6 -0
- package/dist/planning/planning-manager.js.map +1 -1
- package/dist/providers/anthropic.js +14 -6
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/openai-codex.js +5 -8
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/openai.js +3 -2
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/shared.d.ts +2 -2
- package/dist/providers/shared.js +11 -6
- package/dist/providers/shared.js.map +1 -1
- package/dist/session/session-manager.d.ts +1 -0
- package/dist/session/session-manager.js +11 -1
- package/dist/session/session-manager.js.map +1 -1
- package/dist/task-graph/result-injection.d.ts +8 -0
- package/dist/task-graph/result-injection.js +26 -0
- package/dist/task-graph/result-injection.js.map +1 -0
- package/dist/task-graph/task-graph.d.ts +41 -0
- package/dist/task-graph/task-graph.js +266 -0
- package/dist/task-graph/task-graph.js.map +1 -0
- package/dist/task-graph/tools.d.ts +3 -0
- package/dist/task-graph/tools.js +106 -0
- package/dist/task-graph/tools.js.map +1 -0
- package/dist/task-graph/types.d.ts +44 -0
- package/dist/task-graph/types.js +9 -0
- package/dist/task-graph/types.js.map +1 -0
- package/dist/tools/executor.d.ts +3 -2
- package/dist/tools/mcp-adapter.js +22 -5
- package/dist/tools/mcp-adapter.js.map +1 -1
- package/dist/utils/id.js +2 -6
- package/dist/utils/id.js.map +1 -1
- package/dist/wire/wire.d.ts +2 -1
- package/package.json +1 -1
- package/src/approval/approval.ts +29 -23
- package/src/approval/types.ts +1 -0
- package/src/background/task-manager.ts +17 -0
- package/src/compaction/compaction.ts +23 -36
- package/src/compaction/summarizer.ts +2 -7
- package/src/core/agent-loop.ts +17 -10
- package/src/core/agent.ts +41 -9
- package/src/index.ts +15 -0
- package/src/injection/history-normalizer.ts +22 -12
- package/src/llm/types.ts +2 -0
- package/src/multi-agent/task-executor.ts +1 -1
- package/src/multi-agent/types.ts +3 -0
- package/src/planning/planning-manager.ts +8 -0
- package/src/providers/anthropic.ts +70 -57
- package/src/providers/google.ts +1 -1
- package/src/providers/openai-codex.ts +7 -2
- package/src/providers/openai.ts +8 -3
- package/src/providers/shared.ts +11 -6
- package/src/session/session-manager.ts +15 -4
- package/src/task-graph/result-injection.ts +29 -0
- package/src/task-graph/task-graph.ts +298 -0
- package/src/task-graph/tools.ts +109 -0
- package/src/task-graph/types.ts +52 -0
- package/src/tools/executor.ts +2 -2
- package/src/tools/mcp-adapter.ts +23 -7
- package/src/utils/id.ts +3 -6
- package/src/wire/wire.ts +1 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Task graph tools — CRUD + dependency management + background execution
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
import { TASK_GRAPH_TOOL_NAMES } from "./types.js";
|
|
4
|
+
export function createTaskGraphTools(graph) {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
name: TASK_GRAPH_TOOL_NAMES.create,
|
|
8
|
+
label: "Create Task",
|
|
9
|
+
description: "Create a new task in the task graph. Tasks start as pending. " +
|
|
10
|
+
"Use task_depend to set up dependency ordering.",
|
|
11
|
+
parameters: Type.Object({
|
|
12
|
+
subject: Type.String({ description: "Short title for the task." }),
|
|
13
|
+
description: Type.Optional(Type.String({ description: "Detailed description." })),
|
|
14
|
+
}),
|
|
15
|
+
async execute(_id, params) {
|
|
16
|
+
const task = graph.create(params.subject, params.description);
|
|
17
|
+
return text(`Created task ${task.id}: ${task.subject}\n\n${graph.render()}`);
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: TASK_GRAPH_TOOL_NAMES.depend,
|
|
22
|
+
label: "Add Task Dependency",
|
|
23
|
+
description: "Add a dependency: task_id cannot start until blocked_by_id completes. " +
|
|
24
|
+
"Rejects if this would create a cycle.",
|
|
25
|
+
parameters: Type.Object({
|
|
26
|
+
task_id: Type.String({ description: "Task that is blocked." }),
|
|
27
|
+
blocked_by_id: Type.String({ description: "Task that must complete first." }),
|
|
28
|
+
}),
|
|
29
|
+
async execute(_id, params) {
|
|
30
|
+
graph.addDependency(params.task_id, params.blocked_by_id);
|
|
31
|
+
return text(`Dependency added: ${params.task_id} blocked by ${params.blocked_by_id}\n\n${graph.render()}`);
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: TASK_GRAPH_TOOL_NAMES.update,
|
|
36
|
+
label: "Update Task",
|
|
37
|
+
description: "Update a task's status, owner, or result. " +
|
|
38
|
+
"Setting status to 'completed' auto-unblocks dependent tasks. " +
|
|
39
|
+
"Cannot start a task that has unfinished blockers.",
|
|
40
|
+
parameters: Type.Object({
|
|
41
|
+
task_id: Type.String({ description: "Task ID." }),
|
|
42
|
+
status: Type.Optional(Type.Union([Type.Literal("pending"), Type.Literal("in_progress"), Type.Literal("completed"), Type.Literal("failed")], { description: "New status." })),
|
|
43
|
+
owner: Type.Optional(Type.String({ description: "Assign to an agent or user." })),
|
|
44
|
+
result: Type.Optional(Type.String({ description: "Result summary." })),
|
|
45
|
+
}),
|
|
46
|
+
async execute(_id, params) {
|
|
47
|
+
const task = graph.update(params.task_id, {
|
|
48
|
+
status: params.status,
|
|
49
|
+
owner: params.owner,
|
|
50
|
+
result: params.result,
|
|
51
|
+
});
|
|
52
|
+
return text(`Updated task ${task.id}\n\n${graph.render()}`);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: TASK_GRAPH_TOOL_NAMES.list,
|
|
57
|
+
label: "List Tasks",
|
|
58
|
+
description: "List all tasks with their status, dependencies, and progress.",
|
|
59
|
+
parameters: Type.Object({
|
|
60
|
+
filter: Type.Optional(Type.Union([Type.Literal("all"), Type.Literal("ready"), Type.Literal("blocked"), Type.Literal("in_progress"), Type.Literal("completed")], { description: "Filter tasks by category. Default: all." })),
|
|
61
|
+
}),
|
|
62
|
+
async execute(_id, params) {
|
|
63
|
+
let tasks;
|
|
64
|
+
switch (params.filter) {
|
|
65
|
+
case "ready":
|
|
66
|
+
tasks = graph.listReady();
|
|
67
|
+
break;
|
|
68
|
+
case "blocked":
|
|
69
|
+
tasks = graph.listBlocked();
|
|
70
|
+
break;
|
|
71
|
+
case "in_progress":
|
|
72
|
+
tasks = graph.listAll().filter((t) => t.status === "in_progress");
|
|
73
|
+
break;
|
|
74
|
+
case "completed":
|
|
75
|
+
tasks = graph.listAll().filter((t) => t.status === "completed");
|
|
76
|
+
break;
|
|
77
|
+
default: tasks = graph.listAll();
|
|
78
|
+
}
|
|
79
|
+
if (tasks.length === 0)
|
|
80
|
+
return text(`No tasks matching filter: ${params.filter ?? "all"}`);
|
|
81
|
+
if (!params.filter || params.filter === "all")
|
|
82
|
+
return text(graph.render());
|
|
83
|
+
const lines = tasks.map((t) => `${t.id}: ${t.subject} [${t.status}]`);
|
|
84
|
+
return text(`${params.filter}: ${tasks.length} task(s)\n${lines.join("\n")}`);
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: TASK_GRAPH_TOOL_NAMES.get,
|
|
89
|
+
label: "Get Task",
|
|
90
|
+
description: "Get detailed information about a specific task.",
|
|
91
|
+
parameters: Type.Object({
|
|
92
|
+
task_id: Type.String({ description: "Task ID." }),
|
|
93
|
+
}),
|
|
94
|
+
async execute(_id, params) {
|
|
95
|
+
const task = graph.get(params.task_id);
|
|
96
|
+
if (!task)
|
|
97
|
+
return text(`Task not found: ${params.task_id}`);
|
|
98
|
+
return text(JSON.stringify(task, null, 2));
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
function text(t) {
|
|
104
|
+
return { content: [{ type: "text", text: t }] };
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/task-graph/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const TASK_GRAPH_TOOL_NAMES: {
|
|
2
|
+
readonly create: "task_create";
|
|
3
|
+
readonly depend: "task_depend";
|
|
4
|
+
readonly update: "task_update";
|
|
5
|
+
readonly list: "task_list";
|
|
6
|
+
readonly get: "task_get";
|
|
7
|
+
};
|
|
8
|
+
export type TaskStatus = "pending" | "in_progress" | "completed" | "failed";
|
|
9
|
+
export interface TaskNode {
|
|
10
|
+
id: string;
|
|
11
|
+
subject: string;
|
|
12
|
+
description: string;
|
|
13
|
+
status: TaskStatus;
|
|
14
|
+
/** IDs of tasks that must complete before this one can start. */
|
|
15
|
+
blockedBy: string[];
|
|
16
|
+
/** IDs of tasks that this task blocks (reverse edges, maintained automatically). */
|
|
17
|
+
blocks: string[];
|
|
18
|
+
/** Agent or user assigned to this task. */
|
|
19
|
+
owner: string;
|
|
20
|
+
/** Result summary after completion/failure. */
|
|
21
|
+
result?: string;
|
|
22
|
+
/** Background execution handle ID, if running in background. */
|
|
23
|
+
backgroundId?: string;
|
|
24
|
+
createdAt: number;
|
|
25
|
+
updatedAt: number;
|
|
26
|
+
}
|
|
27
|
+
export interface TaskGraphConfig {
|
|
28
|
+
/** Directory for persisting task graph to disk. If omitted, in-memory only. */
|
|
29
|
+
persistDir?: string;
|
|
30
|
+
/** Maximum number of tasks. Default: 100. */
|
|
31
|
+
maxTasks?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Auto-inject completed background task results before each LLM call.
|
|
34
|
+
* Default: true.
|
|
35
|
+
*/
|
|
36
|
+
autoInjectResults?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface CompletedTaskResult {
|
|
39
|
+
taskId: string;
|
|
40
|
+
subject: string;
|
|
41
|
+
result: string;
|
|
42
|
+
status: "completed" | "failed";
|
|
43
|
+
unblockedTasks: string[];
|
|
44
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Task graph types — dependency-aware task DAG with background execution
|
|
2
|
+
export const TASK_GRAPH_TOOL_NAMES = {
|
|
3
|
+
create: "task_create",
|
|
4
|
+
depend: "task_depend",
|
|
5
|
+
update: "task_update",
|
|
6
|
+
list: "task_list",
|
|
7
|
+
get: "task_get",
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/task-graph/types.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,aAAa;IACrB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,UAAU;CACP,CAAC"}
|
package/dist/tools/executor.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolResult, BeforeToolCallContext, BeforeToolCallResult, AfterToolCallContext, AfterToolCallResult } from "./types.js";
|
|
2
2
|
import type { ToolCallBlock } from "../llm/types.js";
|
|
3
3
|
import type { Approval } from "../approval/types.js";
|
|
4
|
-
|
|
4
|
+
interface ToolExecutorConfig {
|
|
5
5
|
tools: AgentTool[];
|
|
6
6
|
mode: "sequential" | "parallel";
|
|
7
7
|
approval: Approval;
|
|
@@ -11,7 +11,7 @@ export interface ToolExecutorConfig {
|
|
|
11
11
|
afterToolCall?: (ctx: AfterToolCallContext) => Promise<AfterToolCallResult | void>;
|
|
12
12
|
onEvent: (event: ToolExecutorEvent) => void;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
type ToolExecutorEvent = {
|
|
15
15
|
type: "tool_execution_start";
|
|
16
16
|
toolCallId: string;
|
|
17
17
|
toolName: string;
|
|
@@ -35,3 +35,4 @@ export interface ToolCallResult {
|
|
|
35
35
|
isError: boolean;
|
|
36
36
|
}
|
|
37
37
|
export declare function executeToolCalls(toolCalls: ToolCallBlock[], config: ToolExecutorConfig): Promise<ToolCallResult[]>;
|
|
38
|
+
export {};
|
|
@@ -88,15 +88,32 @@ export class MCPAdapter {
|
|
|
88
88
|
async execute(toolCallId, params, context) {
|
|
89
89
|
// Approval is handled by the executor via approvalAction field
|
|
90
90
|
// No need to request approval here
|
|
91
|
-
// Call with timeout
|
|
91
|
+
// Call with timeout and abort signal support
|
|
92
92
|
const callPromise = client.callTool(def.name, params);
|
|
93
93
|
let result;
|
|
94
|
+
let timer;
|
|
95
|
+
let abortHandler;
|
|
96
|
+
const racers = [callPromise];
|
|
94
97
|
if (timeout) {
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
racers.push(new Promise((_, reject) => {
|
|
99
|
+
timer = setTimeout(() => reject(new Error(`MCP tool ${def.name} timed out after ${timeout}ms`)), timeout);
|
|
100
|
+
}));
|
|
97
101
|
}
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
if (context.signal.aborted)
|
|
103
|
+
throw new Error("Aborted");
|
|
104
|
+
racers.push(new Promise((_, reject) => {
|
|
105
|
+
abortHandler = () => reject(new Error("Aborted"));
|
|
106
|
+
context.signal.addEventListener("abort", abortHandler, { once: true });
|
|
107
|
+
}));
|
|
108
|
+
try {
|
|
109
|
+
result = await Promise.race(racers);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
if (timer !== undefined)
|
|
113
|
+
clearTimeout(timer);
|
|
114
|
+
if (abortHandler) {
|
|
115
|
+
context.signal.removeEventListener("abort", abortHandler);
|
|
116
|
+
}
|
|
100
117
|
}
|
|
101
118
|
// Convert MCP result to AgentToolResult
|
|
102
119
|
const content = result.content
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-adapter.js","sourceRoot":"","sources":["../../src/tools/mcp-adapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"mcp-adapter.js","sourceRoot":"","sources":["../../src/tools/mcp-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/id.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
1
2
|
export function generateId() {
|
|
2
|
-
|
|
3
|
-
let id = "";
|
|
4
|
-
for (let i = 0; i < 12; i++) {
|
|
5
|
-
id += chars[Math.floor(Math.random() * chars.length)];
|
|
6
|
-
}
|
|
7
|
-
return id;
|
|
3
|
+
return randomBytes(9).toString("base64url").slice(0, 12);
|
|
8
4
|
}
|
|
9
5
|
//# sourceMappingURL=id.js.map
|
package/dist/utils/id.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,UAAU,UAAU;IACxB,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3D,CAAC"}
|
package/dist/wire/wire.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WireMessage, WireSubscriber, WireSubscription } from "./types.js";
|
|
2
|
-
|
|
2
|
+
interface WireOptions {
|
|
3
3
|
/** Max messages to buffer for replay to late subscribers. 0 = no buffering. */
|
|
4
4
|
bufferSize?: number;
|
|
5
5
|
}
|
|
@@ -18,3 +18,4 @@ export declare class Wire {
|
|
|
18
18
|
getBuffer(): readonly WireMessage[];
|
|
19
19
|
dispose(): void;
|
|
20
20
|
}
|
|
21
|
+
export {};
|
package/package.json
CHANGED
package/src/approval/approval.ts
CHANGED
|
@@ -8,21 +8,27 @@ interface PendingRequest {
|
|
|
8
8
|
resolve: (approved: boolean) => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
interface SharedApprovalState {
|
|
12
|
+
yolo: boolean;
|
|
13
|
+
autoApproveActions: Set<string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
export class ApprovalImpl implements Approval {
|
|
12
|
-
private
|
|
13
|
-
private _autoApproveActions: Set<string>;
|
|
17
|
+
private _shared: SharedApprovalState;
|
|
14
18
|
private _pending = new Map<string, PendingRequest>();
|
|
15
19
|
private _queue: ApprovalRequest[] = [];
|
|
16
20
|
private _waiters: ((req: ApprovalRequest) => void)[] = [];
|
|
17
21
|
|
|
18
|
-
constructor(config?: ApprovalConfig) {
|
|
19
|
-
this.
|
|
20
|
-
|
|
22
|
+
constructor(config?: ApprovalConfig, sharedState?: SharedApprovalState) {
|
|
23
|
+
this._shared = sharedState ?? {
|
|
24
|
+
yolo: config?.yolo ?? false,
|
|
25
|
+
autoApproveActions: new Set(config?.autoApproveActions ?? []),
|
|
26
|
+
};
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
async request(sender: string, action: string, description: string, toolCallId: string): Promise<boolean> {
|
|
24
|
-
if (this.
|
|
25
|
-
if (this.
|
|
30
|
+
if (this._shared.yolo) return true;
|
|
31
|
+
if (this._shared.autoApproveActions.has(action)) return true;
|
|
26
32
|
|
|
27
33
|
const req: ApprovalRequest = {
|
|
28
34
|
id: generateId(),
|
|
@@ -72,7 +78,7 @@ export class ApprovalImpl implements Approval {
|
|
|
72
78
|
this._pending.delete(requestId);
|
|
73
79
|
|
|
74
80
|
if (response === "approve_for_session") {
|
|
75
|
-
this.
|
|
81
|
+
this._shared.autoApproveActions.add(pending.request.action);
|
|
76
82
|
pending.resolve(true);
|
|
77
83
|
} else {
|
|
78
84
|
pending.resolve(response === "approve");
|
|
@@ -80,29 +86,29 @@ export class ApprovalImpl implements Approval {
|
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
setYolo(yolo: boolean): void {
|
|
83
|
-
this.
|
|
89
|
+
this._shared.yolo = yolo;
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
isYolo(): boolean {
|
|
87
|
-
return this.
|
|
93
|
+
return this._shared.yolo;
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
get autoApproveActions(): Set<string> {
|
|
91
|
-
return this.
|
|
97
|
+
return this._shared.autoApproveActions;
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
share(): Approval {
|
|
95
|
-
// Shared state (yolo, autoApproveActions), independent queue
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
// Shared state (yolo, autoApproveActions) via same reference, independent queue
|
|
102
|
+
return new ApprovalImpl(undefined, this._shared);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
dispose(): void {
|
|
106
|
+
this.cancelPendingWaiters();
|
|
107
|
+
// Reject all pending approval requests so blocked tools don't hang forever
|
|
108
|
+
for (const [id, pending] of this._pending) {
|
|
109
|
+
pending.resolve(false);
|
|
110
|
+
}
|
|
111
|
+
this._pending.clear();
|
|
112
|
+
this._queue = [];
|
|
107
113
|
}
|
|
108
114
|
}
|
package/src/approval/types.ts
CHANGED
|
@@ -82,6 +82,23 @@ export class BackgroundTaskManager {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/** Remove completed/failed tasks older than `maxAgeMs` (default: 5 minutes). */
|
|
86
|
+
prune(maxAgeMs = 5 * 60 * 1000): number {
|
|
87
|
+
const now = Date.now();
|
|
88
|
+
let removed = 0;
|
|
89
|
+
for (const [id, task] of this._tasks) {
|
|
90
|
+
if (
|
|
91
|
+
(task.status === "completed" || task.status === "failed") &&
|
|
92
|
+
task.completedAt &&
|
|
93
|
+
now - task.completedAt > maxAgeMs
|
|
94
|
+
) {
|
|
95
|
+
this._tasks.delete(id);
|
|
96
|
+
removed++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return removed;
|
|
100
|
+
}
|
|
101
|
+
|
|
85
102
|
dispose(): void {
|
|
86
103
|
this.abortAll();
|
|
87
104
|
this._tasks.clear();
|
|
@@ -75,6 +75,14 @@ export function findCutPoint(
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// If all messages fit within keepRecentTokens, nothing can be discarded.
|
|
79
|
+
// Return firstKeptIndex: 0 so callers know there's nothing to cut —
|
|
80
|
+
// this prevents infinite compaction loops when context exceeds max but
|
|
81
|
+
// all messages fall within the keep window.
|
|
82
|
+
if (cutIndex >= messages.length) {
|
|
83
|
+
return { firstKeptIndex: 0, isSplitTurn: false };
|
|
84
|
+
}
|
|
85
|
+
|
|
78
86
|
// Ensure we don't cut at a tool_result (must follow its tool_call)
|
|
79
87
|
while (cutIndex < messages.length) {
|
|
80
88
|
const msg = messages[cutIndex];
|
|
@@ -85,8 +93,8 @@ export function findCutPoint(
|
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
95
|
|
|
88
|
-
//
|
|
89
|
-
if (cutIndex <= 1) {
|
|
96
|
+
// After adjusting for tool_results, check if we've pushed past all messages
|
|
97
|
+
if (cutIndex >= messages.length || cutIndex <= 1) {
|
|
90
98
|
return { firstKeptIndex: 0, isSplitTurn: false };
|
|
91
99
|
}
|
|
92
100
|
|
|
@@ -108,25 +116,24 @@ export function microCompact(messages: Message[], keepRecent: number): Message[]
|
|
|
108
116
|
|
|
109
117
|
if (toolResultIndices.length <= keepRecent) return messages;
|
|
110
118
|
|
|
119
|
+
// Build toolCallId → toolName map in one pass
|
|
120
|
+
const toolCallNames = new Map<string, string>();
|
|
121
|
+
for (const msg of messages) {
|
|
122
|
+
if (msg.role === "assistant") {
|
|
123
|
+
for (const b of msg.content) {
|
|
124
|
+
if (b.type === "tool_call") {
|
|
125
|
+
toolCallNames.set(b.id, b.name);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
const toReplace = toolResultIndices.slice(0, -keepRecent);
|
|
112
132
|
const result = [...messages];
|
|
113
133
|
|
|
114
134
|
for (const idx of toReplace) {
|
|
115
135
|
const msg = result[idx] as ToolResultMessage;
|
|
116
|
-
|
|
117
|
-
let toolName = "tool";
|
|
118
|
-
for (let j = idx - 1; j >= 0; j--) {
|
|
119
|
-
const prev = result[j];
|
|
120
|
-
if (prev.role === "assistant") {
|
|
121
|
-
const call = prev.content.find(
|
|
122
|
-
(b): b is ToolCallBlock => b.type === "tool_call" && b.id === msg.toolCallId,
|
|
123
|
-
);
|
|
124
|
-
if (call) {
|
|
125
|
-
toolName = call.name;
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
136
|
+
const toolName = toolCallNames.get(msg.toolCallId) ?? "tool";
|
|
130
137
|
|
|
131
138
|
result[idx] = {
|
|
132
139
|
role: "tool_result",
|
|
@@ -139,23 +146,3 @@ export function microCompact(messages: Message[], keepRecent: number): Message[]
|
|
|
139
146
|
return result;
|
|
140
147
|
}
|
|
141
148
|
|
|
142
|
-
export function messagesToText(messages: AgentMessage[]): string {
|
|
143
|
-
const parts: string[] = [];
|
|
144
|
-
for (const msg of messages) {
|
|
145
|
-
if (!msg || typeof msg !== "object" || !("role" in msg)) continue;
|
|
146
|
-
const m = msg as Message;
|
|
147
|
-
|
|
148
|
-
if (m.role === "user") {
|
|
149
|
-
const text = typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => (b as { text: string }).text).join("\n");
|
|
150
|
-
parts.push(`User: ${text}`);
|
|
151
|
-
} else if (m.role === "assistant") {
|
|
152
|
-
const text = m.content.filter((b) => b.type === "text").map((b) => (b as { text: string }).text).join("\n");
|
|
153
|
-
const toolCalls = m.content.filter((b) => b.type === "tool_call").map((b) => (b as { name: string }).name);
|
|
154
|
-
parts.push(`Assistant: ${text}${toolCalls.length ? ` [tools: ${toolCalls.join(", ")}]` : ""}`);
|
|
155
|
-
} else if (m.role === "tool_result") {
|
|
156
|
-
const text = typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => (b as { text: string }).text).join("\n");
|
|
157
|
-
parts.push(`Tool result: ${text.slice(0, 500)}`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return parts.join("\n");
|
|
161
|
-
}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import type { LLMProvider, LLMRequestOptions, AssistantMessage } from "../llm/types.js";
|
|
4
4
|
import type { AgentMessage } from "../types.js";
|
|
5
5
|
import type { CompactionSummarizer, CompactionInput } from "./types.js";
|
|
6
|
-
import { messagesToText } from "./compaction.js";
|
|
7
6
|
|
|
8
7
|
const SUMMARIZE_PROMPT = `You are a conversation summarizer. Summarize the following conversation history concisely, preserving:
|
|
9
8
|
- Key decisions and outcomes
|
|
@@ -42,13 +41,9 @@ export class LLMSummarizer implements CompactionSummarizer {
|
|
|
42
41
|
|
|
43
42
|
let result = "";
|
|
44
43
|
for await (const event of this.provider.stream(options)) {
|
|
45
|
-
if (event.type === "
|
|
46
|
-
result += event.text;
|
|
47
|
-
} else if (event.type === "done") {
|
|
44
|
+
if (event.type === "done") {
|
|
48
45
|
const textBlocks = event.message.content.filter((b) => b.type === "text");
|
|
49
|
-
|
|
50
|
-
result = textBlocks.map((b) => (b as { text: string }).text).join("");
|
|
51
|
-
}
|
|
46
|
+
result = textBlocks.map((b) => (b as { text: string }).text).join("");
|
|
52
47
|
}
|
|
53
48
|
}
|
|
54
49
|
|
package/src/core/agent-loop.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { estimateTokens, shouldCompact, findCutPoint, microCompact } from "../co
|
|
|
29
29
|
import { normalizeHistory } from "../injection/history-normalizer.js";
|
|
30
30
|
import { calculateCost } from "../providers/shared.js";
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
interface AgentLoopConfig {
|
|
33
33
|
provider: LLMProvider;
|
|
34
34
|
modelId: string;
|
|
35
35
|
systemPrompt: string;
|
|
@@ -91,7 +91,7 @@ function toolResultsToMessages(results: ToolCallResult[]): ToolResultMessage[] {
|
|
|
91
91
|
role: "tool_result" as const,
|
|
92
92
|
toolCallId: r.toolCallId,
|
|
93
93
|
content: r.result.content,
|
|
94
|
-
isError: r.isError
|
|
94
|
+
isError: r.isError,
|
|
95
95
|
}));
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -185,14 +185,10 @@ export async function runAgentLoop(
|
|
|
185
185
|
}
|
|
186
186
|
allMessages.push(...toKeep);
|
|
187
187
|
|
|
188
|
-
// Persist compaction to session
|
|
189
|
-
//
|
|
190
|
-
// kept messages after it so buildSessionContext picks them up
|
|
188
|
+
// Persist compaction boundary marker to session.
|
|
189
|
+
// Kept messages are already in the session tree — only append the compaction entry.
|
|
191
190
|
if (sessionManager) {
|
|
192
191
|
await sessionManager.appendCompaction(summary, sessionManager.getLeafId() ?? "", tokens);
|
|
193
|
-
for (const msg of toKeep) {
|
|
194
|
-
await sessionManager.appendMessage(msg);
|
|
195
|
-
}
|
|
196
192
|
}
|
|
197
193
|
|
|
198
194
|
onEvent({ type: "compaction_end", summary });
|
|
@@ -257,7 +253,7 @@ export async function runAgentLoop(
|
|
|
257
253
|
|
|
258
254
|
// --- Phase-aware tool filtering ---
|
|
259
255
|
let visibleTools = allTools;
|
|
260
|
-
if (config.planningManager?.phase === "planning" && config.planningManager.
|
|
256
|
+
if (config.planningManager?.phase === "planning" && config.planningManager.hasConfiguredReadOnlyTools) {
|
|
261
257
|
visibleTools = allTools.filter((t) => config.planningManager!.allowedInPlanning.has(t.name));
|
|
262
258
|
}
|
|
263
259
|
|
|
@@ -442,9 +438,20 @@ export async function runAgentLoop(
|
|
|
442
438
|
}
|
|
443
439
|
}
|
|
444
440
|
} catch (err) {
|
|
445
|
-
|
|
441
|
+
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
442
|
+
if (!isAbort) {
|
|
446
443
|
onEvent({ type: "error", error: err instanceof Error ? err : new Error(String(err)) });
|
|
447
444
|
}
|
|
445
|
+
|
|
446
|
+
onEvent({ type: "agent_end", messages: allMessages });
|
|
447
|
+
await extensionRunner?.emitSimple("agent_end", { messages: allMessages });
|
|
448
|
+
|
|
449
|
+
// Re-throw non-abort errors so the caller (Agent._runLoop) can set error state.
|
|
450
|
+
// AbortError is intentional (user called agent.abort()), not an error condition.
|
|
451
|
+
if (!isAbort) {
|
|
452
|
+
throw err;
|
|
453
|
+
}
|
|
454
|
+
return allMessages;
|
|
448
455
|
}
|
|
449
456
|
|
|
450
457
|
onEvent({ type: "agent_end", messages: allMessages });
|