@zhijiewang/openharness 2.1.0 → 2.3.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 +4 -4
- package/dist/DeferredTool.js +3 -1
- package/dist/Tool.d.ts +1 -1
- package/dist/agents/roles.js +58 -62
- package/dist/commands/cybergotchi.d.ts +1 -1
- package/dist/commands/cybergotchi.js +30 -30
- package/dist/commands/index.js +288 -132
- package/dist/components/App.d.ts +1 -1
- package/dist/components/App.js +6 -6
- package/dist/components/CompanionFooter.d.ts +1 -1
- package/dist/components/CompanionFooter.js +6 -8
- package/dist/components/CybergotchiBubble.js +5 -5
- package/dist/components/CybergotchiPanel.d.ts +1 -1
- package/dist/components/CybergotchiPanel.js +7 -7
- package/dist/components/CybergotchiPanelConnected.js +2 -2
- package/dist/components/CybergotchiSetup.js +26 -24
- package/dist/components/CybergotchiSprite.d.ts +1 -1
- package/dist/components/CybergotchiSprite.js +8 -12
- package/dist/components/DiffView.d.ts +1 -1
- package/dist/components/DiffView.js +10 -10
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/ErrorBoundary.js +1 -1
- package/dist/components/InitWizard.js +65 -33
- package/dist/components/Markdown.js +2 -4
- package/dist/components/Messages.js +4 -4
- package/dist/components/PermissionPrompt.d.ts +1 -1
- package/dist/components/PermissionPrompt.js +15 -17
- package/dist/components/REPL.d.ts +1 -1
- package/dist/components/REPL.js +74 -49
- package/dist/components/Spinner.js +2 -2
- package/dist/components/TextInput.js +35 -29
- package/dist/components/ToolCallDisplay.js +3 -5
- package/dist/cybergotchi/bones.d.ts +1 -1
- package/dist/cybergotchi/bones.js +8 -8
- package/dist/cybergotchi/config.d.ts +2 -2
- package/dist/cybergotchi/config.js +13 -13
- package/dist/cybergotchi/events.d.ts +5 -5
- package/dist/cybergotchi/events.js +7 -7
- package/dist/cybergotchi/needs.d.ts +2 -2
- package/dist/cybergotchi/needs.js +7 -9
- package/dist/cybergotchi/personality.d.ts +2 -2
- package/dist/cybergotchi/personality.js +2 -2
- package/dist/cybergotchi/species.d.ts +1 -1
- package/dist/cybergotchi/species.js +145 -217
- package/dist/cybergotchi/speech.d.ts +2 -2
- package/dist/cybergotchi/speech.js +43 -43
- package/dist/cybergotchi/types.d.ts +4 -4
- package/dist/cybergotchi/types.js +26 -26
- package/dist/cybergotchi/useCybergotchi.d.ts +1 -1
- package/dist/cybergotchi/useCybergotchi.js +29 -25
- package/dist/git/index.js +11 -9
- package/dist/harness/checkpoints.js +29 -21
- package/dist/harness/config.d.ts +3 -3
- package/dist/harness/config.js +15 -9
- package/dist/harness/context-warning.d.ts +1 -1
- package/dist/harness/context-warning.js +1 -1
- package/dist/harness/cost.js +1 -1
- package/dist/harness/credentials.js +13 -13
- package/dist/harness/hooks.js +7 -5
- package/dist/harness/keybindings.js +20 -18
- package/dist/harness/marketplace.d.ts +3 -3
- package/dist/harness/marketplace.js +55 -42
- package/dist/harness/memory.d.ts +23 -5
- package/dist/harness/memory.js +142 -41
- package/dist/harness/onboarding.js +30 -10
- package/dist/harness/plugins.d.ts +9 -1
- package/dist/harness/plugins.js +54 -30
- package/dist/harness/rules.js +12 -7
- package/dist/harness/sandbox.js +15 -15
- package/dist/harness/session-db.d.ts +55 -0
- package/dist/harness/session-db.js +165 -0
- package/dist/harness/session.d.ts +1 -1
- package/dist/harness/session.js +34 -15
- package/dist/harness/store.d.ts +3 -3
- package/dist/harness/store.js +6 -4
- package/dist/harness/submit-handler.d.ts +4 -4
- package/dist/harness/submit-handler.js +25 -23
- package/dist/harness/telemetry.d.ts +1 -1
- package/dist/harness/telemetry.js +23 -19
- package/dist/harness/traces.d.ts +2 -2
- package/dist/harness/traces.js +39 -33
- package/dist/harness/verification.d.ts +1 -1
- package/dist/harness/verification.js +50 -44
- package/dist/lsp/client.js +44 -40
- package/dist/main.js +114 -59
- package/dist/mcp/DeferredMcpTool.d.ts +4 -4
- package/dist/mcp/DeferredMcpTool.js +9 -5
- package/dist/mcp/McpTool.d.ts +4 -4
- package/dist/mcp/McpTool.js +8 -4
- package/dist/mcp/client.d.ts +2 -2
- package/dist/mcp/client.js +21 -21
- package/dist/mcp/loader.d.ts +1 -1
- package/dist/mcp/loader.js +17 -12
- package/dist/mcp/registry.d.ts +3 -3
- package/dist/mcp/registry.js +97 -97
- package/dist/mcp/schema.d.ts +1 -1
- package/dist/mcp/schema.js +16 -16
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +21 -21
- package/dist/mcp/types.d.ts +3 -3
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +10 -9
- package/dist/providers/base.d.ts +1 -1
- package/dist/providers/index.js +10 -3
- package/dist/providers/llamacpp.d.ts +2 -2
- package/dist/providers/llamacpp.js +1 -3
- package/dist/providers/ollama.d.ts +2 -2
- package/dist/providers/ollama.js +3 -4
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openai.js +3 -5
- package/dist/providers/openrouter.d.ts +2 -2
- package/dist/providers/router.d.ts +1 -1
- package/dist/providers/router.js +7 -7
- package/dist/query/compress.d.ts +2 -2
- package/dist/query/compress.js +22 -21
- package/dist/query/context-manager.d.ts +1 -1
- package/dist/query/context-manager.js +5 -5
- package/dist/query/errors.js +1 -1
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +42 -24
- package/dist/query/tools.js +15 -12
- package/dist/query/types.d.ts +3 -1
- package/dist/query.d.ts +1 -1
- package/dist/query.js +1 -1
- package/dist/remote/auth.d.ts +2 -2
- package/dist/remote/auth.js +8 -8
- package/dist/remote/server.d.ts +3 -3
- package/dist/remote/server.js +60 -60
- package/dist/renderer/cells.js +9 -9
- package/dist/renderer/colors.js +24 -6
- package/dist/renderer/diff.d.ts +2 -2
- package/dist/renderer/diff.js +27 -19
- package/dist/renderer/differ.d.ts +1 -1
- package/dist/renderer/differ.js +9 -9
- package/dist/renderer/image.js +19 -19
- package/dist/renderer/index.d.ts +6 -6
- package/dist/renderer/index.js +163 -93
- package/dist/renderer/input.js +66 -48
- package/dist/renderer/layout.d.ts +6 -6
- package/dist/renderer/layout.js +163 -124
- package/dist/renderer/markdown.d.ts +2 -2
- package/dist/renderer/markdown.js +173 -54
- package/dist/renderer/session-browser.d.ts +2 -2
- package/dist/renderer/session-browser.js +19 -21
- package/dist/repl.d.ts +5 -5
- package/dist/repl.js +311 -198
- package/dist/sdk/index.d.ts +5 -5
- package/dist/sdk/index.js +32 -26
- package/dist/services/AgentDispatcher.d.ts +3 -3
- package/dist/services/AgentDispatcher.js +33 -29
- package/dist/services/CronExecutor.d.ts +4 -4
- package/dist/services/CronExecutor.js +12 -8
- package/dist/services/EvaluatorLoop.d.ts +3 -3
- package/dist/services/EvaluatorLoop.js +29 -21
- package/dist/services/MetaHarness.d.ts +1 -1
- package/dist/services/MetaHarness.js +34 -32
- package/dist/services/PipelineExecutor.d.ts +1 -1
- package/dist/services/PipelineExecutor.js +23 -25
- package/dist/services/SkillExtractor.d.ts +43 -0
- package/dist/services/SkillExtractor.js +163 -0
- package/dist/services/StreamingToolExecutor.d.ts +2 -2
- package/dist/services/StreamingToolExecutor.js +11 -7
- package/dist/services/a2a.d.ts +8 -8
- package/dist/services/a2a.js +44 -34
- package/dist/services/agent-messaging.d.ts +33 -15
- package/dist/services/agent-messaging.js +65 -13
- package/dist/services/cron.js +16 -16
- package/dist/tools/AgentTool/index.d.ts +5 -2
- package/dist/tools/AgentTool/index.js +25 -39
- package/dist/tools/AskUserTool/index.js +1 -1
- package/dist/tools/BashTool/index.d.ts +2 -2
- package/dist/tools/BashTool/index.js +18 -10
- package/dist/tools/CronTool/index.js +30 -12
- package/dist/tools/DiagnosticsTool/index.js +28 -22
- package/dist/tools/EnterPlanModeTool/index.js +93 -14
- package/dist/tools/EnterWorktreeTool/index.js +7 -3
- package/dist/tools/ExitPlanModeTool/index.d.ts +22 -1
- package/dist/tools/ExitPlanModeTool/index.js +20 -5
- package/dist/tools/ExitWorktreeTool/index.js +11 -4
- package/dist/tools/FileEditTool/index.js +3 -5
- package/dist/tools/FileReadTool/index.js +16 -10
- package/dist/tools/FileWriteTool/index.js +2 -2
- package/dist/tools/GlobTool/index.js +5 -9
- package/dist/tools/GrepTool/index.d.ts +2 -2
- package/dist/tools/GrepTool/index.js +14 -9
- package/dist/tools/ImageReadTool/index.js +2 -2
- package/dist/tools/KillProcessTool/index.js +11 -7
- package/dist/tools/LSTool/index.js +3 -3
- package/dist/tools/MemoryTool/index.d.ts +5 -5
- package/dist/tools/MemoryTool/index.js +28 -14
- package/dist/tools/MonitorTool/index.js +24 -19
- package/dist/tools/MultiEditTool/index.js +9 -5
- package/dist/tools/NotebookEditTool/index.js +3 -3
- package/dist/tools/ParallelAgentTool/index.d.ts +4 -4
- package/dist/tools/ParallelAgentTool/index.js +12 -6
- package/dist/tools/PipelineTool/index.js +3 -3
- package/dist/tools/PowerShellTool/index.js +10 -6
- package/dist/tools/RemoteTriggerTool/index.js +8 -4
- package/dist/tools/ScheduleWakeupTool/index.d.ts +42 -0
- package/dist/tools/ScheduleWakeupTool/index.js +115 -0
- package/dist/tools/SendMessageTool/index.js +25 -7
- package/dist/tools/SessionSearchTool/index.d.ts +15 -0
- package/dist/tools/SessionSearchTool/index.js +36 -0
- package/dist/tools/SkillTool/index.d.ts +3 -0
- package/dist/tools/SkillTool/index.js +39 -9
- package/dist/tools/TaskCreateTool/index.d.ts +2 -2
- package/dist/tools/TaskCreateTool/index.js +2 -2
- package/dist/tools/TaskGetTool/index.js +2 -2
- package/dist/tools/TaskListTool/index.js +3 -5
- package/dist/tools/TaskOutputTool/index.js +2 -2
- package/dist/tools/TaskStopTool/index.js +3 -3
- package/dist/tools/TaskUpdateTool/index.d.ts +4 -4
- package/dist/tools/TaskUpdateTool/index.js +2 -2
- package/dist/tools/ToolSearchTool/index.js +9 -6
- package/dist/tools/WebFetchTool/index.js +1 -1
- package/dist/tools/WebSearchTool/index.js +2 -6
- package/dist/tools.js +31 -30
- package/dist/types/permissions.js +15 -9
- package/dist/utils/bash-safety.d.ts +1 -1
- package/dist/utils/bash-safety.js +64 -54
- package/dist/utils/diff-algorithm.d.ts +3 -3
- package/dist/utils/diff-algorithm.js +7 -7
- package/dist/utils/fs.js +3 -3
- package/dist/utils/safe-env.js +1 -1
- package/dist/utils/theme-data.d.ts +1 -1
- package/dist/utils/theme-data.js +1 -1
- package/dist/utils/theme.d.ts +1 -1
- package/dist/utils/theme.js +1 -1
- package/dist/utils/tool-summary.d.ts +1 -1
- package/dist/utils/tool-summary.js +27 -9
- package/package.json +10 -3
package/dist/sdk/index.d.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* const result = await agent.run('Fix the failing tests');
|
|
14
14
|
* console.log(result.text);
|
|
15
15
|
*/
|
|
16
|
-
import type { StreamEvent } from
|
|
17
|
-
import type { PermissionMode } from
|
|
16
|
+
import type { StreamEvent } from "../types/events.js";
|
|
17
|
+
import type { PermissionMode } from "../types/permissions.js";
|
|
18
18
|
export type AgentConfig = {
|
|
19
19
|
/** Provider name: 'anthropic', 'openai', 'ollama', 'openrouter', etc. */
|
|
20
20
|
provider: string;
|
|
@@ -25,7 +25,7 @@ export type AgentConfig = {
|
|
|
25
25
|
/** Custom base URL */
|
|
26
26
|
baseUrl?: string;
|
|
27
27
|
/** Tools to include: 'all', 'read-only', or array of tool names */
|
|
28
|
-
tools?:
|
|
28
|
+
tools?: "all" | "read-only" | string[];
|
|
29
29
|
/** Permission mode (default: 'trust') */
|
|
30
30
|
permissionMode?: PermissionMode;
|
|
31
31
|
/** Custom system prompt */
|
|
@@ -71,6 +71,6 @@ export declare class Agent {
|
|
|
71
71
|
}
|
|
72
72
|
/** Create a new agent instance */
|
|
73
73
|
export declare function createAgent(config: AgentConfig): Agent;
|
|
74
|
-
export type { StreamEvent } from
|
|
75
|
-
export type { PermissionMode } from
|
|
74
|
+
export type { StreamEvent } from "../types/events.js";
|
|
75
|
+
export type { PermissionMode } from "../types/permissions.js";
|
|
76
76
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/sdk/index.js
CHANGED
|
@@ -21,7 +21,7 @@ export class Agent {
|
|
|
21
21
|
initPromise = null;
|
|
22
22
|
constructor(config) {
|
|
23
23
|
this.config = {
|
|
24
|
-
permissionMode:
|
|
24
|
+
permissionMode: "trust",
|
|
25
25
|
maxTurns: 20,
|
|
26
26
|
...config,
|
|
27
27
|
};
|
|
@@ -31,8 +31,8 @@ export class Agent {
|
|
|
31
31
|
return (this.initPromise ??= this._doInit());
|
|
32
32
|
}
|
|
33
33
|
async _doInit() {
|
|
34
|
-
const { createProvider } = await import(
|
|
35
|
-
const { getAllTools } = await import(
|
|
34
|
+
const { createProvider } = await import("../providers/index.js");
|
|
35
|
+
const { getAllTools } = await import("../tools.js");
|
|
36
36
|
const overrides = {};
|
|
37
37
|
if (this.config.apiKey)
|
|
38
38
|
overrides.apiKey = this.config.apiKey;
|
|
@@ -42,36 +42,38 @@ export class Agent {
|
|
|
42
42
|
this.provider = provider;
|
|
43
43
|
// Filter tools
|
|
44
44
|
let tools = getAllTools();
|
|
45
|
-
if (this.config.tools ===
|
|
46
|
-
const readOnlyNames = new Set([
|
|
47
|
-
tools = tools.filter(t => readOnlyNames.has(t.name));
|
|
45
|
+
if (this.config.tools === "read-only") {
|
|
46
|
+
const readOnlyNames = new Set(["Read", "Glob", "Grep", "LS", "ImageRead", "WebSearch", "WebFetch"]);
|
|
47
|
+
tools = tools.filter((t) => readOnlyNames.has(t.name));
|
|
48
48
|
}
|
|
49
49
|
else if (Array.isArray(this.config.tools)) {
|
|
50
|
-
const allowed = new Set(this.config.tools.map(n => n.toLowerCase()));
|
|
51
|
-
tools = tools.filter(t => allowed.has(t.name.toLowerCase()));
|
|
50
|
+
const allowed = new Set(this.config.tools.map((n) => n.toLowerCase()));
|
|
51
|
+
tools = tools.filter((t) => allowed.has(t.name.toLowerCase()));
|
|
52
52
|
}
|
|
53
53
|
this.tools = tools;
|
|
54
54
|
}
|
|
55
55
|
/** Run a single prompt and return the result */
|
|
56
56
|
async run(prompt) {
|
|
57
57
|
await this.init();
|
|
58
|
-
const { query } = await import(
|
|
58
|
+
const { query } = await import("../query.js");
|
|
59
59
|
const originalCwd = process.cwd();
|
|
60
60
|
if (this.config.cwd) {
|
|
61
61
|
try {
|
|
62
62
|
process.chdir(this.config.cwd);
|
|
63
63
|
}
|
|
64
|
-
catch {
|
|
64
|
+
catch {
|
|
65
|
+
/* ignore */
|
|
66
|
+
}
|
|
65
67
|
}
|
|
66
68
|
const config = {
|
|
67
69
|
provider: this.provider,
|
|
68
70
|
tools: this.tools,
|
|
69
|
-
systemPrompt: this.config.systemPrompt ??
|
|
71
|
+
systemPrompt: this.config.systemPrompt ?? "You are a helpful coding agent.",
|
|
70
72
|
permissionMode: this.config.permissionMode,
|
|
71
73
|
model: this.config.model,
|
|
72
74
|
maxTurns: this.config.maxTurns,
|
|
73
75
|
};
|
|
74
|
-
let text =
|
|
76
|
+
let text = "";
|
|
75
77
|
const toolCalls = [];
|
|
76
78
|
let cost = 0;
|
|
77
79
|
let inputTokens = 0;
|
|
@@ -80,22 +82,22 @@ export class Agent {
|
|
|
80
82
|
try {
|
|
81
83
|
for await (const event of query(prompt, config)) {
|
|
82
84
|
switch (event.type) {
|
|
83
|
-
case
|
|
85
|
+
case "text_delta":
|
|
84
86
|
text += event.content;
|
|
85
87
|
break;
|
|
86
|
-
case
|
|
88
|
+
case "tool_call_end":
|
|
87
89
|
toolCalls.push({
|
|
88
|
-
toolName: event.
|
|
89
|
-
output: event.output
|
|
90
|
-
isError: event.isError
|
|
90
|
+
toolName: event.callId,
|
|
91
|
+
output: event.output,
|
|
92
|
+
isError: event.isError,
|
|
91
93
|
});
|
|
92
94
|
break;
|
|
93
|
-
case
|
|
94
|
-
cost += event.cost
|
|
95
|
-
inputTokens += event.inputTokens
|
|
96
|
-
outputTokens += event.outputTokens
|
|
95
|
+
case "cost_update":
|
|
96
|
+
cost += event.cost;
|
|
97
|
+
inputTokens += event.inputTokens;
|
|
98
|
+
outputTokens += event.outputTokens;
|
|
97
99
|
break;
|
|
98
|
-
case
|
|
100
|
+
case "turn_complete":
|
|
99
101
|
turns++;
|
|
100
102
|
break;
|
|
101
103
|
}
|
|
@@ -106,7 +108,9 @@ export class Agent {
|
|
|
106
108
|
try {
|
|
107
109
|
process.chdir(originalCwd);
|
|
108
110
|
}
|
|
109
|
-
catch {
|
|
111
|
+
catch {
|
|
112
|
+
/* ignore */
|
|
113
|
+
}
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
116
|
return { text, toolCalls, cost, inputTokens, outputTokens, turns };
|
|
@@ -114,17 +118,19 @@ export class Agent {
|
|
|
114
118
|
/** Stream events from a prompt */
|
|
115
119
|
async *stream(prompt) {
|
|
116
120
|
await this.init();
|
|
117
|
-
const { query } = await import(
|
|
121
|
+
const { query } = await import("../query.js");
|
|
118
122
|
if (this.config.cwd) {
|
|
119
123
|
try {
|
|
120
124
|
process.chdir(this.config.cwd);
|
|
121
125
|
}
|
|
122
|
-
catch {
|
|
126
|
+
catch {
|
|
127
|
+
/* ignore */
|
|
128
|
+
}
|
|
123
129
|
}
|
|
124
130
|
const config = {
|
|
125
131
|
provider: this.provider,
|
|
126
132
|
tools: this.tools,
|
|
127
|
-
systemPrompt: this.config.systemPrompt ??
|
|
133
|
+
systemPrompt: this.config.systemPrompt ?? "You are a helpful coding agent.",
|
|
128
134
|
permissionMode: this.config.permissionMode,
|
|
129
135
|
model: this.config.model,
|
|
130
136
|
maxTurns: this.config.maxTurns,
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* dispatches independent tasks to parallel worktrees, collects results,
|
|
6
6
|
* and triggers dependent tasks when their blockers complete.
|
|
7
7
|
*/
|
|
8
|
-
import type { Provider } from
|
|
9
|
-
import type { Tools } from
|
|
10
|
-
import type { PermissionMode } from
|
|
8
|
+
import type { Provider } from "../providers/base.js";
|
|
9
|
+
import type { Tools } from "../Tool.js";
|
|
10
|
+
import type { PermissionMode } from "../types/permissions.js";
|
|
11
11
|
export type AgentTask = {
|
|
12
12
|
id: string;
|
|
13
13
|
prompt: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* dispatches independent tasks to parallel worktrees, collects results,
|
|
6
6
|
* and triggers dependent tasks when their blockers complete.
|
|
7
7
|
*/
|
|
8
|
-
import { createWorktree,
|
|
8
|
+
import { createWorktree, isGitRepo, removeWorktree } from "../git/index.js";
|
|
9
9
|
export class AgentDispatcher {
|
|
10
10
|
provider;
|
|
11
11
|
tools;
|
|
@@ -29,7 +29,7 @@ export class AgentDispatcher {
|
|
|
29
29
|
this.maxConcurrency = maxConcurrency;
|
|
30
30
|
}
|
|
31
31
|
addTask(task) {
|
|
32
|
-
this.tasks.set(task.id, { ...task, status:
|
|
32
|
+
this.tasks.set(task.id, { ...task, status: "pending" });
|
|
33
33
|
}
|
|
34
34
|
addTasks(tasks) {
|
|
35
35
|
for (const t of tasks)
|
|
@@ -42,8 +42,8 @@ export class AgentDispatcher {
|
|
|
42
42
|
if (this.abortSignal?.aborted)
|
|
43
43
|
break;
|
|
44
44
|
// Find tasks ready to run (all blockers completed)
|
|
45
|
-
const ready = [...this.tasks.values()].filter(t => t.status ===
|
|
46
|
-
const running = [...this.tasks.values()].filter(t => t.status ===
|
|
45
|
+
const ready = [...this.tasks.values()].filter((t) => t.status === "pending" && this.isReady(t));
|
|
46
|
+
const running = [...this.tasks.values()].filter((t) => t.status === "running");
|
|
47
47
|
// All done?
|
|
48
48
|
if (ready.length === 0 && running.length === 0)
|
|
49
49
|
break;
|
|
@@ -52,11 +52,11 @@ export class AgentDispatcher {
|
|
|
52
52
|
if (toStart.length === 0 && running.length === 0) {
|
|
53
53
|
// Deadlock — blocked tasks with no way to unblock
|
|
54
54
|
for (const t of this.tasks.values()) {
|
|
55
|
-
if (t.status ===
|
|
56
|
-
t.status =
|
|
55
|
+
if (t.status === "pending") {
|
|
56
|
+
t.status = "failed";
|
|
57
57
|
const result = {
|
|
58
58
|
id: t.id,
|
|
59
|
-
output:
|
|
59
|
+
output: "Deadlock: blocked dependencies never completed.",
|
|
60
60
|
isError: true,
|
|
61
61
|
durationMs: 0,
|
|
62
62
|
};
|
|
@@ -67,10 +67,10 @@ export class AgentDispatcher {
|
|
|
67
67
|
break;
|
|
68
68
|
}
|
|
69
69
|
// Run tasks in parallel
|
|
70
|
-
const promises = toStart.map(t => {
|
|
71
|
-
t.status =
|
|
72
|
-
return this.runTask(t).then(result => {
|
|
73
|
-
t.status =
|
|
70
|
+
const promises = toStart.map((t) => {
|
|
71
|
+
t.status = "running";
|
|
72
|
+
return this.runTask(t).then((result) => {
|
|
73
|
+
t.status = "completed";
|
|
74
74
|
t.result = result;
|
|
75
75
|
this.results.set(t.id, result);
|
|
76
76
|
results.push(result);
|
|
@@ -85,11 +85,11 @@ export class AgentDispatcher {
|
|
|
85
85
|
else {
|
|
86
86
|
// Running tasks exist but we can't start more — wait for all running
|
|
87
87
|
const runningPromises = [...this.tasks.values()]
|
|
88
|
-
.filter(t => t.status ===
|
|
89
|
-
.map(
|
|
88
|
+
.filter((t) => t.status === "running" && t.result)
|
|
89
|
+
.map((_t) => Promise.resolve());
|
|
90
90
|
if (runningPromises.length === 0) {
|
|
91
91
|
// Need to poll — running tasks haven't resolved yet
|
|
92
|
-
await new Promise(r => setTimeout(r, 100));
|
|
92
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -98,9 +98,9 @@ export class AgentDispatcher {
|
|
|
98
98
|
isReady(task) {
|
|
99
99
|
if (!task.blockedBy || task.blockedBy.length === 0)
|
|
100
100
|
return true;
|
|
101
|
-
return task.blockedBy.every(id => {
|
|
101
|
+
return task.blockedBy.every((id) => {
|
|
102
102
|
const blocker = this.tasks.get(id);
|
|
103
|
-
return blocker && (blocker.status ===
|
|
103
|
+
return blocker && (blocker.status === "completed" || blocker.status === "failed");
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
async runTask(task) {
|
|
@@ -112,13 +112,13 @@ export class AgentDispatcher {
|
|
|
112
112
|
worktreePath = createWorktree(cwd);
|
|
113
113
|
}
|
|
114
114
|
try {
|
|
115
|
-
const { query } = await import(
|
|
115
|
+
const { query } = await import("../query.js");
|
|
116
116
|
// Filter tools if task specifies allowed tools
|
|
117
117
|
let taskTools = this.tools;
|
|
118
118
|
if (task.allowedTools && task.allowedTools.length > 0) {
|
|
119
|
-
const allowSet = new Set(task.allowedTools.map(n => n.toLowerCase()));
|
|
120
|
-
allowSet.add(
|
|
121
|
-
const filtered = this.tools.filter(t => allowSet.has(t.name.toLowerCase()));
|
|
119
|
+
const allowSet = new Set(task.allowedTools.map((n) => n.toLowerCase()));
|
|
120
|
+
allowSet.add("askuser");
|
|
121
|
+
const filtered = this.tools.filter((t) => allowSet.has(t.name.toLowerCase()));
|
|
122
122
|
if (filtered.length > 0)
|
|
123
123
|
taskTools = filtered;
|
|
124
124
|
}
|
|
@@ -135,12 +135,12 @@ export class AgentDispatcher {
|
|
|
135
135
|
let promptWithContext = task.prompt;
|
|
136
136
|
if (task.blockedBy && task.blockedBy.length > 0) {
|
|
137
137
|
const blockerContext = task.blockedBy
|
|
138
|
-
.map(id => {
|
|
138
|
+
.map((id) => {
|
|
139
139
|
const r = this.results.get(id);
|
|
140
|
-
return r ? `## Result from task "${id}":\n${r.output.slice(0, 1000)}` :
|
|
140
|
+
return r ? `## Result from task "${id}":\n${r.output.slice(0, 1000)}` : "";
|
|
141
141
|
})
|
|
142
142
|
.filter(Boolean)
|
|
143
|
-
.join(
|
|
143
|
+
.join("\n\n");
|
|
144
144
|
if (blockerContext) {
|
|
145
145
|
promptWithContext = `${blockerContext}\n\n---\n\n${task.prompt}`;
|
|
146
146
|
}
|
|
@@ -150,14 +150,16 @@ export class AgentDispatcher {
|
|
|
150
150
|
try {
|
|
151
151
|
process.chdir(worktreePath);
|
|
152
152
|
}
|
|
153
|
-
catch {
|
|
153
|
+
catch {
|
|
154
|
+
/* ignore */
|
|
155
|
+
}
|
|
154
156
|
}
|
|
155
|
-
let output =
|
|
157
|
+
let output = "";
|
|
156
158
|
try {
|
|
157
159
|
for await (const event of query(promptWithContext, config)) {
|
|
158
|
-
if (event.type ===
|
|
160
|
+
if (event.type === "text_delta")
|
|
159
161
|
output += event.content;
|
|
160
|
-
if (event.type ===
|
|
162
|
+
if (event.type === "error") {
|
|
161
163
|
return { id: task.id, output: `Error: ${event.message}`, isError: true, durationMs: Date.now() - start };
|
|
162
164
|
}
|
|
163
165
|
}
|
|
@@ -167,10 +169,12 @@ export class AgentDispatcher {
|
|
|
167
169
|
try {
|
|
168
170
|
process.chdir(originalCwd);
|
|
169
171
|
}
|
|
170
|
-
catch {
|
|
172
|
+
catch {
|
|
173
|
+
/* ignore */
|
|
174
|
+
}
|
|
171
175
|
}
|
|
172
176
|
}
|
|
173
|
-
return { id: task.id, output: output ||
|
|
177
|
+
return { id: task.id, output: output || "(no output)", isError: false, durationMs: Date.now() - start };
|
|
174
178
|
}
|
|
175
179
|
catch (err) {
|
|
176
180
|
return {
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* Execution is non-blocking and failure-isolated — one failing cron
|
|
9
9
|
* does not affect others or the main REPL session.
|
|
10
10
|
*/
|
|
11
|
-
import type { Provider } from
|
|
12
|
-
import type { Tools } from
|
|
13
|
-
import type { PermissionMode } from
|
|
14
|
-
import { type CronResult } from
|
|
11
|
+
import type { Provider } from "../providers/base.js";
|
|
12
|
+
import type { Tools } from "../Tool.js";
|
|
13
|
+
import type { PermissionMode } from "../types/permissions.js";
|
|
14
|
+
import { type CronResult } from "./cron.js";
|
|
15
15
|
export declare class CronExecutor {
|
|
16
16
|
private provider;
|
|
17
17
|
private tools;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Execution is non-blocking and failure-isolated — one failing cron
|
|
9
9
|
* does not affect others or the main REPL session.
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { getDueCrons, listCrons, saveCronResult, updateCron } from "./cron.js";
|
|
12
12
|
const CHECK_INTERVAL_MS = 60_000; // Check every 60 seconds
|
|
13
13
|
const MAX_CRON_TURNS = 10; // Limit sub-query turns for cron tasks
|
|
14
14
|
export class CronExecutor {
|
|
@@ -35,12 +35,16 @@ export class CronExecutor {
|
|
|
35
35
|
// Run first tick after a short delay (don't block startup)
|
|
36
36
|
setTimeout(() => {
|
|
37
37
|
if (!this._stopped)
|
|
38
|
-
this.tick().catch(() => {
|
|
38
|
+
this.tick().catch(() => {
|
|
39
|
+
/* fire-and-forget: cron tick errors are non-fatal */
|
|
40
|
+
});
|
|
39
41
|
}, 5_000);
|
|
40
42
|
// Then check every 60 seconds
|
|
41
43
|
this.intervalId = setInterval(() => {
|
|
42
44
|
if (!this._stopped)
|
|
43
|
-
this.tick().catch(() => {
|
|
45
|
+
this.tick().catch(() => {
|
|
46
|
+
/* fire-and-forget: cron tick errors are non-fatal */
|
|
47
|
+
});
|
|
44
48
|
}, CHECK_INTERVAL_MS);
|
|
45
49
|
}
|
|
46
50
|
/** Stop the scheduler */
|
|
@@ -69,7 +73,7 @@ export class CronExecutor {
|
|
|
69
73
|
const result = {
|
|
70
74
|
cronId: cron.id,
|
|
71
75
|
timestamp: Date.now(),
|
|
72
|
-
output:
|
|
76
|
+
output: "",
|
|
73
77
|
error: err instanceof Error ? err.message : String(err),
|
|
74
78
|
};
|
|
75
79
|
saveCronResult(result);
|
|
@@ -83,7 +87,7 @@ export class CronExecutor {
|
|
|
83
87
|
this.running.add(cron.id);
|
|
84
88
|
const timestamp = Date.now();
|
|
85
89
|
try {
|
|
86
|
-
const { query } = await import(
|
|
90
|
+
const { query } = await import("../query.js");
|
|
87
91
|
const config = {
|
|
88
92
|
provider: this.provider,
|
|
89
93
|
tools: this.tools,
|
|
@@ -92,11 +96,11 @@ export class CronExecutor {
|
|
|
92
96
|
model: this.model,
|
|
93
97
|
maxTurns: MAX_CRON_TURNS,
|
|
94
98
|
};
|
|
95
|
-
let output =
|
|
99
|
+
let output = "";
|
|
96
100
|
for await (const event of query(cron.prompt, config)) {
|
|
97
|
-
if (event.type ===
|
|
101
|
+
if (event.type === "text_delta")
|
|
98
102
|
output += event.content;
|
|
99
|
-
if (event.type ===
|
|
103
|
+
if (event.type === "error") {
|
|
100
104
|
const result = { cronId: cron.id, timestamp, output, error: event.message };
|
|
101
105
|
saveCronResult(result);
|
|
102
106
|
// Still update lastRun on error to prevent rapid retry loops
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* 3. If below threshold, Generator refines based on feedback
|
|
13
13
|
* 4. Repeat until pass or max iterations reached
|
|
14
14
|
*/
|
|
15
|
-
import type { Provider } from
|
|
16
|
-
import type { Tools } from
|
|
17
|
-
import type { PermissionMode } from
|
|
15
|
+
import type { Provider } from "../providers/base.js";
|
|
16
|
+
import type { Tools } from "../Tool.js";
|
|
17
|
+
import type { PermissionMode } from "../types/permissions.js";
|
|
18
18
|
export type EvaluationCriterion = {
|
|
19
19
|
name: string;
|
|
20
20
|
weight: number;
|
|
@@ -15,10 +15,18 @@
|
|
|
15
15
|
// ── Default Rubric ──
|
|
16
16
|
export const DEFAULT_RUBRIC = {
|
|
17
17
|
criteria: [
|
|
18
|
-
{
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
{
|
|
19
|
+
name: "correctness",
|
|
20
|
+
weight: 0.4,
|
|
21
|
+
description: "Does the output correctly address the task? Are there logical errors?",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "completeness",
|
|
25
|
+
weight: 0.3,
|
|
26
|
+
description: "Is the solution complete? Any missing edge cases or requirements?",
|
|
27
|
+
},
|
|
28
|
+
{ name: "quality", weight: 0.2, description: "Is the code clean, well-structured, and following best practices?" },
|
|
29
|
+
{ name: "safety", weight: 0.1, description: "Are there security issues, unsafe patterns, or potential bugs?" },
|
|
22
30
|
],
|
|
23
31
|
passThreshold: 0.7,
|
|
24
32
|
};
|
|
@@ -45,14 +53,14 @@ export class EvaluatorLoop {
|
|
|
45
53
|
*/
|
|
46
54
|
async run(task) {
|
|
47
55
|
const refinements = [];
|
|
48
|
-
let currentOutput =
|
|
56
|
+
let currentOutput = "";
|
|
49
57
|
let scores = [];
|
|
50
58
|
let weightedScore = 0;
|
|
51
59
|
for (let iteration = 1; iteration <= this.maxIterations; iteration++) {
|
|
52
60
|
// ── Generate ──
|
|
53
61
|
const generatorPrompt = iteration === 1
|
|
54
62
|
? task
|
|
55
|
-
: `${task}\n\n[Evaluator feedback from iteration ${iteration - 1}]:\n${scores.map(s => `${s.criterion}: ${s.score}/1.0 — ${s.feedback}`).join(
|
|
63
|
+
: `${task}\n\n[Evaluator feedback from iteration ${iteration - 1}]:\n${scores.map((s) => `${s.criterion}: ${s.score}/1.0 — ${s.feedback}`).join("\n")}\n\nPlease refine your output based on this feedback.`;
|
|
56
64
|
currentOutput = await this.generate(generatorPrompt);
|
|
57
65
|
// ── Evaluate ──
|
|
58
66
|
scores = await this.evaluate(task, currentOutput);
|
|
@@ -80,7 +88,7 @@ export class EvaluatorLoop {
|
|
|
80
88
|
};
|
|
81
89
|
}
|
|
82
90
|
async generate(prompt) {
|
|
83
|
-
const { query } = await import(
|
|
91
|
+
const { query } = await import("../query.js");
|
|
84
92
|
const config = {
|
|
85
93
|
provider: this.provider,
|
|
86
94
|
tools: this.tools,
|
|
@@ -89,9 +97,9 @@ export class EvaluatorLoop {
|
|
|
89
97
|
model: this.model,
|
|
90
98
|
maxTurns: 15,
|
|
91
99
|
};
|
|
92
|
-
let output =
|
|
100
|
+
let output = "";
|
|
93
101
|
for await (const event of query(prompt, config)) {
|
|
94
|
-
if (event.type ===
|
|
102
|
+
if (event.type === "text_delta")
|
|
95
103
|
output += event.content;
|
|
96
104
|
}
|
|
97
105
|
return output;
|
|
@@ -105,16 +113,16 @@ Output to evaluate:
|
|
|
105
113
|
${output.slice(0, 3000)}
|
|
106
114
|
|
|
107
115
|
Criteria:
|
|
108
|
-
${this.rubric.criteria.map(c => `- ${c.name} (weight: ${c.weight}): ${c.description}`).join(
|
|
116
|
+
${this.rubric.criteria.map((c) => `- ${c.name} (weight: ${c.weight}): ${c.description}`).join("\n")}
|
|
109
117
|
|
|
110
118
|
Respond ONLY with a JSON array: [{"criterion": "name", "score": 0.8, "feedback": "brief explanation"}, ...]`;
|
|
111
|
-
const response = await this.provider.complete([{ role:
|
|
119
|
+
const response = await this.provider.complete([{ role: "user", content: evaluationPrompt, uuid: `eval-${Date.now()}`, timestamp: Date.now() }], "You are a strict code evaluator. Respond ONLY with valid JSON. Be critical and specific.", undefined, this.model);
|
|
112
120
|
try {
|
|
113
121
|
const jsonMatch = response.content.match(/\[[\s\S]*\]/);
|
|
114
122
|
if (!jsonMatch)
|
|
115
123
|
return this.defaultScores();
|
|
116
124
|
const parsed = JSON.parse(jsonMatch[0]);
|
|
117
|
-
return parsed.filter(s => s.criterion && typeof s.score ===
|
|
125
|
+
return parsed.filter((s) => s.criterion && typeof s.score === "number");
|
|
118
126
|
}
|
|
119
127
|
catch {
|
|
120
128
|
return this.defaultScores();
|
|
@@ -123,35 +131,35 @@ Respond ONLY with a JSON array: [{"criterion": "name", "score": 0.8, "feedback":
|
|
|
123
131
|
calculateWeightedScore(scores) {
|
|
124
132
|
let total = 0;
|
|
125
133
|
for (const criterion of this.rubric.criteria) {
|
|
126
|
-
const score = scores.find(s => s.criterion === criterion.name);
|
|
134
|
+
const score = scores.find((s) => s.criterion === criterion.name);
|
|
127
135
|
total += (score?.score ?? 0.5) * criterion.weight;
|
|
128
136
|
}
|
|
129
137
|
return total;
|
|
130
138
|
}
|
|
131
139
|
defaultScores() {
|
|
132
|
-
return this.rubric.criteria.map(c => ({
|
|
140
|
+
return this.rubric.criteria.map((c) => ({
|
|
133
141
|
criterion: c.name,
|
|
134
142
|
score: 0.5,
|
|
135
|
-
feedback:
|
|
143
|
+
feedback: "Could not evaluate (parsing error)",
|
|
136
144
|
}));
|
|
137
145
|
}
|
|
138
146
|
}
|
|
139
147
|
/** Format evaluator results for display */
|
|
140
148
|
export function formatEvaluatorResult(result) {
|
|
141
149
|
const lines = [];
|
|
142
|
-
lines.push(`Evaluator: ${result.passed ?
|
|
150
|
+
lines.push(`Evaluator: ${result.passed ? "PASSED" : "NEEDS IMPROVEMENT"} (${result.weightedScore.toFixed(2)}/${1.0})`);
|
|
143
151
|
lines.push(`Iterations: ${result.iterations}`);
|
|
144
|
-
lines.push(
|
|
152
|
+
lines.push("");
|
|
145
153
|
for (const s of result.scores) {
|
|
146
|
-
const bar =
|
|
154
|
+
const bar = "█".repeat(Math.round(s.score * 10)) + "░".repeat(10 - Math.round(s.score * 10));
|
|
147
155
|
lines.push(` ${s.criterion.padEnd(15)} ${bar} ${s.score.toFixed(1)} — ${s.feedback}`);
|
|
148
156
|
}
|
|
149
157
|
if (result.refinements.length > 0) {
|
|
150
|
-
lines.push(
|
|
151
|
-
lines.push(
|
|
158
|
+
lines.push("");
|
|
159
|
+
lines.push("Refinements:");
|
|
152
160
|
for (const r of result.refinements)
|
|
153
161
|
lines.push(` ${r}`);
|
|
154
162
|
}
|
|
155
|
-
return lines.join(
|
|
163
|
+
return lines.join("\n");
|
|
156
164
|
}
|
|
157
165
|
//# sourceMappingURL=EvaluatorLoop.js.map
|