@denizokcu/haze 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +100 -34
- package/dist/cli/commands/chat.d.ts +3 -1
- package/dist/cli/commands/chat.js +500 -56
- package/dist/cli/commands/commands.d.ts +5 -0
- package/dist/cli/commands/commands.js +114 -29
- package/dist/cli/commands/formatters.js +32 -2
- package/dist/cli/commands/streaming.d.ts +6 -1
- package/dist/cli/commands/streaming.js +316 -98
- package/dist/cli/index.js +5 -2
- package/dist/config/inputHistory.js +8 -0
- package/dist/config/providers.d.ts +26 -0
- package/dist/config/providers.js +88 -0
- package/dist/config/settings.d.ts +9 -2
- package/dist/core/agent/compaction.d.ts +13 -0
- package/dist/core/agent/compaction.js +34 -0
- package/dist/core/agent/errors.d.ts +3 -0
- package/dist/core/agent/errors.js +13 -0
- package/dist/core/agent/events.d.ts +58 -0
- package/dist/core/agent/events.js +3 -0
- package/dist/core/goal/completionPolicy.d.ts +28 -0
- package/dist/core/goal/completionPolicy.js +84 -0
- package/dist/core/goal/requestClassifier.d.ts +6 -0
- package/dist/core/goal/requestClassifier.js +31 -0
- package/dist/core/goal/sessionGoal.d.ts +30 -0
- package/dist/core/goal/sessionGoal.js +88 -0
- package/dist/core/session/sessionStore.d.ts +37 -0
- package/dist/core/session/sessionStore.js +59 -0
- package/dist/core/subagent/subagentRunner.d.ts +33 -0
- package/dist/core/subagent/subagentRunner.js +140 -0
- package/dist/llm/client.d.ts +1 -1
- package/dist/llm/client.js +6 -6
- package/dist/llm/hazeTools.d.ts +86 -0
- package/dist/llm/hazeTools.js +313 -93
- package/dist/llm/initPrompt.js +6 -4
- package/dist/llm/systemPrompt.js +11 -7
- package/dist/skills/builder/SkillBuilder.d.ts +6 -0
- package/dist/skills/builder/SkillBuilder.js +146 -24
- package/dist/ui/components/ErrorView.d.ts +2 -1
- package/dist/ui/components/Header.d.ts +2 -1
- package/dist/ui/components/Header.js +1 -11
- package/dist/ui/components/MarkdownText.d.ts +2 -1
- package/dist/ui/components/TextInput.d.ts +7 -3
- package/dist/ui/components/TextInput.js +112 -27
- package/dist/ui/theme.d.ts +3 -0
- package/dist/ui/theme.js +4 -1
- package/package.json +8 -8
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { HAZE_DIR } from '../../config/paths.js';
|
|
5
|
+
const DEFAULT_SESSIONS_DIR = path.join(HAZE_DIR, 'sessions');
|
|
6
|
+
function cwdHash(cwd = process.cwd()) {
|
|
7
|
+
return crypto.createHash('sha256').update(path.resolve(cwd)).digest('hex').slice(0, 16);
|
|
8
|
+
}
|
|
9
|
+
function sessionDir(cwd = process.cwd(), sessionsDir = DEFAULT_SESSIONS_DIR) {
|
|
10
|
+
return path.join(sessionsDir, cwdHash(cwd));
|
|
11
|
+
}
|
|
12
|
+
function sessionFile(id, cwd = process.cwd(), sessionsDir = DEFAULT_SESSIONS_DIR) {
|
|
13
|
+
return path.join(sessionDir(cwd, sessionsDir), `${id}.jsonl`);
|
|
14
|
+
}
|
|
15
|
+
function newSessionId(now = new Date()) {
|
|
16
|
+
return now.toISOString().replace(/[:.]/g, '-');
|
|
17
|
+
}
|
|
18
|
+
export async function createSession(options = {}) {
|
|
19
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
20
|
+
const id = newSessionId();
|
|
21
|
+
const file = sessionFile(id, cwd, options.sessionsDir);
|
|
22
|
+
await fs.ensureDir(path.dirname(file));
|
|
23
|
+
await appendSessionEntry({ id, file, cwd }, { type: 'header', id, cwd, createdAt: new Date().toISOString(), hazeVersion: options.hazeVersion });
|
|
24
|
+
return { id, file, cwd };
|
|
25
|
+
}
|
|
26
|
+
export async function latestSession(cwd = process.cwd(), sessionsDir = DEFAULT_SESSIONS_DIR) {
|
|
27
|
+
const dir = sessionDir(cwd, sessionsDir);
|
|
28
|
+
const files = (await fs.readdir(dir).catch(() => []))
|
|
29
|
+
.filter(file => file.endsWith('.jsonl'))
|
|
30
|
+
.sort();
|
|
31
|
+
const latest = files.at(-1);
|
|
32
|
+
if (!latest)
|
|
33
|
+
return undefined;
|
|
34
|
+
const id = path.basename(latest, '.jsonl');
|
|
35
|
+
return { id, file: path.join(dir, latest), cwd: path.resolve(cwd) };
|
|
36
|
+
}
|
|
37
|
+
export async function appendSessionEntry(session, entry) {
|
|
38
|
+
await fs.ensureDir(path.dirname(session.file));
|
|
39
|
+
await fs.appendFile(session.file, `${JSON.stringify(entry)}\n`, 'utf8');
|
|
40
|
+
}
|
|
41
|
+
export async function readSessionEntries(session) {
|
|
42
|
+
const raw = await fs.readFile(session.file, 'utf8');
|
|
43
|
+
return raw.split('\n').filter(Boolean).flatMap(line => {
|
|
44
|
+
try {
|
|
45
|
+
return [JSON.parse(line)];
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export async function restoreConversation(session) {
|
|
53
|
+
const entries = await readSessionEntries(session);
|
|
54
|
+
const snapshots = entries.filter((entry) => entry.type === 'conversation_snapshot');
|
|
55
|
+
return snapshots.at(-1)?.messages ?? [];
|
|
56
|
+
}
|
|
57
|
+
export function formatSession(session) {
|
|
58
|
+
return `${session.id} · ${session.file}`;
|
|
59
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { streamText } from 'ai';
|
|
2
|
+
import type { ContextFile } from '../../config/contextFiles.js';
|
|
3
|
+
export interface SubagentResult {
|
|
4
|
+
status: 'ok' | 'error' | 'timeout' | 'cancelled';
|
|
5
|
+
summary: string;
|
|
6
|
+
toolCalls: Array<{
|
|
7
|
+
name: string;
|
|
8
|
+
summary: string;
|
|
9
|
+
durationMs: number;
|
|
10
|
+
}>;
|
|
11
|
+
toolCallCount: number;
|
|
12
|
+
tokens: {
|
|
13
|
+
in: number;
|
|
14
|
+
out: number;
|
|
15
|
+
};
|
|
16
|
+
durationMs: number;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function runSubagent(task: string, options: {
|
|
20
|
+
model: Parameters<typeof streamText>[0]['model'];
|
|
21
|
+
contextFiles: ContextFile[];
|
|
22
|
+
allowedTools?: readonly string[];
|
|
23
|
+
maxSteps?: number;
|
|
24
|
+
abortSignal?: AbortSignal;
|
|
25
|
+
}): Promise<SubagentResult>;
|
|
26
|
+
export declare function createSubagentTool(options: {
|
|
27
|
+
model: Parameters<typeof streamText>[0]['model'];
|
|
28
|
+
contextFiles: ContextFile[];
|
|
29
|
+
}): import("ai").Tool<{
|
|
30
|
+
task: string;
|
|
31
|
+
tools?: ("editFile" | "replaceLines" | "writeFile" | "listFiles" | "readFile" | "grep" | "bash")[] | undefined;
|
|
32
|
+
maxSteps?: number | undefined;
|
|
33
|
+
}, SubagentResult>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { streamText, stepCountIs, tool } from 'ai';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { buildSystemPrompt } from '../../llm/systemPrompt.js';
|
|
4
|
+
import { hazeTools } from '../../llm/hazeTools.js';
|
|
5
|
+
const SUBAGENT_SYSTEM_PROMPT = `You are a focused subagent. Complete the assigned task using all tools available to you, then return a clear summary.
|
|
6
|
+
|
|
7
|
+
Rules:
|
|
8
|
+
- Use whatever tools you need. You have full access to file tools and bash.
|
|
9
|
+
- If the task requires creating or modifying files, do it directly — do not ask for permission.
|
|
10
|
+
- If a tool fails, read the file again and retry with the correct content.
|
|
11
|
+
- After completing the task, summarize what you did, what files you created or changed, and any important findings.
|
|
12
|
+
- If you cannot complete the task, explain exactly what blocked you and what you tried.
|
|
13
|
+
- Your summary is all the parent agent will see. Be specific: include file paths, function names, and concrete results.`;
|
|
14
|
+
const ALL_TOOLS = ['listFiles', 'readFile', 'grep', 'bash', 'editFile', 'replaceLines', 'writeFile'];
|
|
15
|
+
const STEP_LIMIT = 25;
|
|
16
|
+
const MAX_SUMMARY = 4000;
|
|
17
|
+
const TOOL_ONLY_LIMIT = 12;
|
|
18
|
+
function toolSummary(output) {
|
|
19
|
+
if (typeof output !== 'object' || output == null)
|
|
20
|
+
return 'completed';
|
|
21
|
+
const o = output;
|
|
22
|
+
if (typeof o.totalMatches === 'number')
|
|
23
|
+
return o.totalMatches === 0 ? 'no matches' : `${o.totalMatches} matches`;
|
|
24
|
+
if (typeof o.code === 'number')
|
|
25
|
+
return `exit ${o.code}`;
|
|
26
|
+
if (o.ok === true)
|
|
27
|
+
return 'completed';
|
|
28
|
+
if (o.ok === false && typeof o.error === 'string')
|
|
29
|
+
return `failed: ${o.error.slice(0, 120)}`;
|
|
30
|
+
return 'completed';
|
|
31
|
+
}
|
|
32
|
+
function toolOnlyStepCount(steps) {
|
|
33
|
+
let count = 0;
|
|
34
|
+
for (const step of [...steps].reverse()) {
|
|
35
|
+
if (step.toolCalls.length === 0 || step.text.trim().length > 0)
|
|
36
|
+
break;
|
|
37
|
+
count += 1;
|
|
38
|
+
}
|
|
39
|
+
return count;
|
|
40
|
+
}
|
|
41
|
+
export async function runSubagent(task, options) {
|
|
42
|
+
const start = performance.now();
|
|
43
|
+
const toolNames = (options.allowedTools ?? ALL_TOOLS).filter(t => ALL_TOOLS.includes(t));
|
|
44
|
+
const maxSteps = Math.min(options.maxSteps ?? STEP_LIMIT, STEP_LIMIT);
|
|
45
|
+
const scopedTools = {};
|
|
46
|
+
for (const name of toolNames) {
|
|
47
|
+
const key = name;
|
|
48
|
+
if (key in hazeTools)
|
|
49
|
+
scopedTools[name] = hazeTools[key];
|
|
50
|
+
}
|
|
51
|
+
const toolCallLog = [];
|
|
52
|
+
let tokensIn = 0;
|
|
53
|
+
let tokensOut = 0;
|
|
54
|
+
let lastStep = 0;
|
|
55
|
+
let totalToolCalls = 0;
|
|
56
|
+
try {
|
|
57
|
+
const result = streamText({
|
|
58
|
+
model: options.model,
|
|
59
|
+
temperature: 0,
|
|
60
|
+
maxOutputTokens: 4096,
|
|
61
|
+
system: `${SUBAGENT_SYSTEM_PROMPT}\n\n${buildSystemPrompt(options.contextFiles)}`,
|
|
62
|
+
messages: [{ role: 'user', content: task }],
|
|
63
|
+
tools: scopedTools,
|
|
64
|
+
stopWhen: stepCountIs(maxSteps),
|
|
65
|
+
abortSignal: options.abortSignal,
|
|
66
|
+
experimental_context: { inFlightToolCalls: new Map() },
|
|
67
|
+
prepareStep({ steps }) {
|
|
68
|
+
const calls = steps.flatMap(step => step.toolCalls);
|
|
69
|
+
const consecutiveToolOnly = toolOnlyStepCount(steps);
|
|
70
|
+
if (consecutiveToolOnly >= TOOL_ONLY_LIMIT || calls.length >= maxSteps * 2) {
|
|
71
|
+
return {
|
|
72
|
+
toolChoice: 'none',
|
|
73
|
+
messages: [
|
|
74
|
+
{ role: 'user', content: 'You have done enough tool work. Summarize what you found or did right now.' },
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
},
|
|
80
|
+
onStepFinish({ stepNumber }) {
|
|
81
|
+
lastStep = stepNumber;
|
|
82
|
+
},
|
|
83
|
+
onFinish(event) {
|
|
84
|
+
if (event.usage) {
|
|
85
|
+
tokensIn = event.usage.inputTokens ?? 0;
|
|
86
|
+
tokensOut = event.usage.outputTokens ?? 0;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
experimental_onToolCallFinish(event) {
|
|
90
|
+
if (!event.toolCall)
|
|
91
|
+
return;
|
|
92
|
+
totalToolCalls += 1;
|
|
93
|
+
toolCallLog.push({
|
|
94
|
+
name: event.toolCall.toolName,
|
|
95
|
+
summary: toolSummary(event.output),
|
|
96
|
+
durationMs: event.durationMs,
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
let text = '';
|
|
101
|
+
for await (const delta of result.textStream) {
|
|
102
|
+
text += delta;
|
|
103
|
+
}
|
|
104
|
+
await result.response;
|
|
105
|
+
const summary = (text.trim() || 'Subagent completed without text output.').slice(0, MAX_SUMMARY);
|
|
106
|
+
const durationMs = performance.now() - start;
|
|
107
|
+
const status = options.abortSignal?.aborted ? 'cancelled'
|
|
108
|
+
: lastStep >= maxSteps ? 'timeout'
|
|
109
|
+
: 'ok';
|
|
110
|
+
return { status, summary, toolCalls: toolCallLog, toolCallCount: totalToolCalls, tokens: { in: tokensIn, out: tokensOut }, durationMs };
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
return {
|
|
114
|
+
status: options.abortSignal?.aborted ? 'cancelled' : 'error',
|
|
115
|
+
summary: error instanceof Error ? error.message : String(error),
|
|
116
|
+
toolCalls: toolCallLog,
|
|
117
|
+
toolCallCount: totalToolCalls,
|
|
118
|
+
tokens: { in: tokensIn, out: tokensOut },
|
|
119
|
+
durationMs: performance.now() - start,
|
|
120
|
+
error: error instanceof Error ? error.message : String(error),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export function createSubagentTool(options) {
|
|
125
|
+
return tool({
|
|
126
|
+
description: 'Spawn subagents to run independent tasks in parallel. ONLY use when a request clearly decomposes into 2+ independent subtasks that can run concurrently — spawn all of them in one step. Do NOT use for single tasks, sequential work, or anything that benefits from conversation context; do those directly instead. Subagents have no conversation history and return a summary.',
|
|
127
|
+
inputSchema: z.object({
|
|
128
|
+
task: z.string().min(1).describe('Clear, specific task for the subagent to complete.'),
|
|
129
|
+
tools: z.array(z.enum(['listFiles', 'readFile', 'grep', 'bash', 'editFile', 'replaceLines', 'writeFile'])).optional().describe('Tools the subagent can use. Defaults to all tools. Restrict to a subset only when the subagent should be read-only.'),
|
|
130
|
+
maxSteps: z.number().int().positive().max(50).optional().describe('Maximum tool-call rounds. Default 25.'),
|
|
131
|
+
}),
|
|
132
|
+
execute: async ({ task, tools, maxSteps }, context) => runSubagent(task, {
|
|
133
|
+
model: options.model,
|
|
134
|
+
contextFiles: options.contextFiles,
|
|
135
|
+
allowedTools: tools,
|
|
136
|
+
maxSteps,
|
|
137
|
+
abortSignal: context.abortSignal,
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
}
|
package/dist/llm/client.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function model(): Promise<import("@ai-sdk/provider").LanguageModelV3
|
|
1
|
+
export declare function model(): Promise<import("@ai-sdk/provider").LanguageModelV3>;
|
package/dist/llm/client.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
2
2
|
import { readSettings } from '../config/settings.js';
|
|
3
|
+
import { activeModel } from '../config/providers.js';
|
|
3
4
|
export async function model() {
|
|
4
5
|
const settings = await readSettings();
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return createOpenAI({ apiKey, baseURL })(name);
|
|
6
|
+
const selection = activeModel(settings);
|
|
7
|
+
const baseURL = process.env.OPENAI_BASE_URL ?? selection.provider.url;
|
|
8
|
+
const apiKey = process.env.OPENAI_API_KEY ?? selection.provider.key ?? settings.apiKey ?? 'not-needed';
|
|
9
|
+
const name = process.env.HAZE_MODEL ?? selection.model;
|
|
10
|
+
return createOpenAI({ apiKey, baseURL }).chat(name);
|
|
11
11
|
}
|
package/dist/llm/hazeTools.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
type ToolDiffLine = {
|
|
2
|
+
type: 'add' | 'remove' | 'context';
|
|
3
|
+
oldLine?: number;
|
|
4
|
+
newLine?: number;
|
|
5
|
+
text: string;
|
|
6
|
+
};
|
|
1
7
|
export declare const hazeTools: {
|
|
2
8
|
listFiles: import("ai").Tool<{
|
|
3
9
|
path: string;
|
|
@@ -6,6 +12,13 @@ export declare const hazeTools: {
|
|
|
6
12
|
includeIgnored: boolean;
|
|
7
13
|
cursor?: string | undefined;
|
|
8
14
|
}, {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
toolName: string;
|
|
17
|
+
path: string | undefined;
|
|
18
|
+
error: string;
|
|
19
|
+
recoverable: boolean;
|
|
20
|
+
suggestedNextStep: string;
|
|
21
|
+
} | {
|
|
9
22
|
ok: true;
|
|
10
23
|
duplicateSkipped: true;
|
|
11
24
|
toolName: string;
|
|
@@ -30,6 +43,13 @@ export declare const hazeTools: {
|
|
|
30
43
|
offset?: number | undefined;
|
|
31
44
|
limit?: number | undefined;
|
|
32
45
|
}, {
|
|
46
|
+
ok: boolean;
|
|
47
|
+
toolName: string;
|
|
48
|
+
path: string | undefined;
|
|
49
|
+
error: string;
|
|
50
|
+
recoverable: boolean;
|
|
51
|
+
suggestedNextStep: string;
|
|
52
|
+
} | {
|
|
33
53
|
ok: true;
|
|
34
54
|
duplicateSkipped: true;
|
|
35
55
|
toolName: string;
|
|
@@ -53,6 +73,39 @@ export declare const hazeTools: {
|
|
|
53
73
|
totalLines: number;
|
|
54
74
|
lineNumberedText: string;
|
|
55
75
|
}>;
|
|
76
|
+
grep: import("ai").Tool<{
|
|
77
|
+
pattern: string;
|
|
78
|
+
path: string;
|
|
79
|
+
contextLines: number;
|
|
80
|
+
maxMatches: number;
|
|
81
|
+
caseInsensitive: boolean;
|
|
82
|
+
glob?: string | undefined;
|
|
83
|
+
}, {
|
|
84
|
+
ok: boolean;
|
|
85
|
+
toolName: string;
|
|
86
|
+
path: string | undefined;
|
|
87
|
+
error: string;
|
|
88
|
+
recoverable: boolean;
|
|
89
|
+
suggestedNextStep: string;
|
|
90
|
+
} | {
|
|
91
|
+
ok: true;
|
|
92
|
+
duplicateSkipped: true;
|
|
93
|
+
toolName: string;
|
|
94
|
+
reason: string;
|
|
95
|
+
} | {
|
|
96
|
+
pattern: string;
|
|
97
|
+
path: string;
|
|
98
|
+
glob: string | null;
|
|
99
|
+
caseInsensitive: boolean;
|
|
100
|
+
matches: {
|
|
101
|
+
file: string;
|
|
102
|
+
line: number;
|
|
103
|
+
content: string;
|
|
104
|
+
isContext: boolean;
|
|
105
|
+
}[];
|
|
106
|
+
totalMatches: number;
|
|
107
|
+
truncated: boolean;
|
|
108
|
+
}>;
|
|
56
109
|
replaceLines: import("ai").Tool<{
|
|
57
110
|
path: string;
|
|
58
111
|
startLine: number;
|
|
@@ -60,6 +113,13 @@ export declare const hazeTools: {
|
|
|
60
113
|
content: string;
|
|
61
114
|
allowIgnored: boolean;
|
|
62
115
|
}, {
|
|
116
|
+
ok: boolean;
|
|
117
|
+
toolName: string;
|
|
118
|
+
path: string | undefined;
|
|
119
|
+
error: string;
|
|
120
|
+
recoverable: boolean;
|
|
121
|
+
suggestedNextStep: string;
|
|
122
|
+
} | {
|
|
63
123
|
ok: true;
|
|
64
124
|
duplicateSkipped: true;
|
|
65
125
|
toolName: string;
|
|
@@ -69,8 +129,14 @@ export declare const hazeTools: {
|
|
|
69
129
|
path: string;
|
|
70
130
|
startLine: number;
|
|
71
131
|
endLine: number;
|
|
132
|
+
requestedEndLine: number;
|
|
133
|
+
endLineClamped: boolean;
|
|
72
134
|
replacementLines: number;
|
|
73
135
|
appended: boolean;
|
|
136
|
+
addedLines: number;
|
|
137
|
+
removedLines: number;
|
|
138
|
+
diffLineCount: number;
|
|
139
|
+
diff: ToolDiffLine[] | undefined;
|
|
74
140
|
}>;
|
|
75
141
|
writeFile: import("ai").Tool<{
|
|
76
142
|
path: string;
|
|
@@ -78,6 +144,13 @@ export declare const hazeTools: {
|
|
|
78
144
|
overwriteExisting: boolean;
|
|
79
145
|
allowIgnored: boolean;
|
|
80
146
|
}, {
|
|
147
|
+
ok: boolean;
|
|
148
|
+
toolName: string;
|
|
149
|
+
path: string | undefined;
|
|
150
|
+
error: string;
|
|
151
|
+
recoverable: boolean;
|
|
152
|
+
suggestedNextStep: string;
|
|
153
|
+
} | {
|
|
81
154
|
ok: true;
|
|
82
155
|
duplicateSkipped: true;
|
|
83
156
|
toolName: string;
|
|
@@ -96,6 +169,13 @@ export declare const hazeTools: {
|
|
|
96
169
|
}[];
|
|
97
170
|
allowIgnored: boolean;
|
|
98
171
|
}, {
|
|
172
|
+
ok: boolean;
|
|
173
|
+
toolName: string;
|
|
174
|
+
path: string | undefined;
|
|
175
|
+
error: string;
|
|
176
|
+
recoverable: boolean;
|
|
177
|
+
suggestedNextStep: string;
|
|
178
|
+
} | {
|
|
99
179
|
ok: true;
|
|
100
180
|
duplicateSkipped: true;
|
|
101
181
|
toolName: string;
|
|
@@ -104,6 +184,11 @@ export declare const hazeTools: {
|
|
|
104
184
|
ok: boolean;
|
|
105
185
|
path: string;
|
|
106
186
|
edits: number;
|
|
187
|
+
approximateMatches: number;
|
|
188
|
+
addedLines: number;
|
|
189
|
+
removedLines: number;
|
|
190
|
+
diffLineCount: number;
|
|
191
|
+
diff: ToolDiffLine[] | undefined;
|
|
107
192
|
}>;
|
|
108
193
|
bash: import("ai").Tool<{
|
|
109
194
|
command: string;
|
|
@@ -112,3 +197,4 @@ export declare const hazeTools: {
|
|
|
112
197
|
}, unknown>;
|
|
113
198
|
};
|
|
114
199
|
export type HazeTools = typeof hazeTools;
|
|
200
|
+
export {};
|