@makefinks/daemon 0.1.4 → 0.3.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/package.json +5 -4
- package/src/ai/daemon-ai.ts +30 -85
- package/src/ai/system-prompt.ts +134 -111
- package/src/ai/tool-approval-coordinator.ts +113 -0
- package/src/ai/tools/index.ts +12 -32
- package/src/ai/tools/subagents.ts +16 -30
- package/src/ai/tools/tool-registry.ts +203 -0
- package/src/app/App.tsx +23 -631
- package/src/app/components/AppOverlays.tsx +25 -1
- package/src/app/components/ConversationPane.tsx +5 -3
- package/src/components/HotkeysPane.tsx +3 -1
- package/src/components/TokenUsageDisplay.tsx +11 -11
- package/src/components/ToolsMenu.tsx +235 -0
- package/src/components/UrlMenu.tsx +182 -0
- package/src/hooks/daemon-event-handlers/interrupted-turn.ts +148 -0
- package/src/hooks/daemon-event-handlers.ts +11 -151
- package/src/hooks/use-app-context-builder.ts +4 -0
- package/src/hooks/use-app-controller.ts +546 -0
- package/src/hooks/use-app-menus.ts +12 -0
- package/src/hooks/use-app-preferences-bootstrap.ts +9 -0
- package/src/hooks/use-bootstrap-controller.ts +92 -0
- package/src/hooks/use-daemon-keyboard.ts +63 -57
- package/src/hooks/use-daemon-runtime-controller.ts +147 -0
- package/src/hooks/use-grounding-menu-controller.ts +51 -0
- package/src/hooks/use-overlay-controller.ts +84 -0
- package/src/hooks/use-session-controller.ts +79 -0
- package/src/hooks/use-url-menu-items.ts +19 -0
- package/src/state/app-context.tsx +4 -0
- package/src/state/daemon-state.ts +19 -8
- package/src/state/session-store.ts +4 -0
- package/src/types/index.ts +39 -0
- package/src/utils/derive-url-menu-items.ts +155 -0
- package/src/utils/formatters.ts +1 -7
- package/src/utils/preferences.ts +10 -0
|
@@ -24,6 +24,15 @@ import { REASONING_COLORS, STATE_COLORS } from "../types/theme";
|
|
|
24
24
|
import { REASONING_ANIMATION } from "../ui/constants";
|
|
25
25
|
import { debug } from "../utils/debug-logger";
|
|
26
26
|
import { hasVisibleText } from "../utils/formatters";
|
|
27
|
+
import {
|
|
28
|
+
INTERRUPTED_TOOL_RESULT,
|
|
29
|
+
buildInterruptedContentBlocks,
|
|
30
|
+
buildInterruptedModelMessages,
|
|
31
|
+
normalizeInterruptedToolBlockResult,
|
|
32
|
+
normalizeInterruptedToolResultOutput,
|
|
33
|
+
} from "./daemon-event-handlers/interrupted-turn";
|
|
34
|
+
|
|
35
|
+
export { buildInterruptedModelMessages };
|
|
27
36
|
|
|
28
37
|
function getToolCategory(toolName: string): ToolCategory | "fast" | undefined {
|
|
29
38
|
if (toolName === "subagent") return "subagent";
|
|
@@ -39,30 +48,6 @@ function getToolCategory(toolName: string): ToolCategory | "fast" | undefined {
|
|
|
39
48
|
return undefined;
|
|
40
49
|
}
|
|
41
50
|
|
|
42
|
-
const INTERRUPTED_TOOL_RESULT = "Tool execution interrupted by user";
|
|
43
|
-
|
|
44
|
-
function normalizeInterruptedToolBlockResult(result: unknown): unknown {
|
|
45
|
-
if (result !== undefined) return result;
|
|
46
|
-
return { success: false, error: INTERRUPTED_TOOL_RESULT };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function normalizeInterruptedToolResultOutput(result: unknown): ToolResultOutput {
|
|
50
|
-
if (result === undefined) {
|
|
51
|
-
return { type: "error-text", value: INTERRUPTED_TOOL_RESULT };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (typeof result === "string") {
|
|
55
|
-
return { type: "text", value: result };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
JSON.stringify(result);
|
|
60
|
-
return { type: "json", value: result as ToolResultOutput["value"] };
|
|
61
|
-
} catch {
|
|
62
|
-
return { type: "text", value: String(result) };
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
51
|
function clearAvatarToolEffects(avatar: DaemonAvatarRenderable | null): void {
|
|
67
52
|
if (!avatar) return;
|
|
68
53
|
avatar.triggerToolComplete();
|
|
@@ -71,133 +56,6 @@ function clearAvatarToolEffects(avatar: DaemonAvatarRenderable | null): void {
|
|
|
71
56
|
avatar.setTypingMode(false);
|
|
72
57
|
}
|
|
73
58
|
|
|
74
|
-
function buildInterruptedContentBlocks(contentBlocks: ContentBlock[]): ContentBlock[] {
|
|
75
|
-
return contentBlocks.map((block) => {
|
|
76
|
-
if (block.type !== "tool") return { ...block };
|
|
77
|
-
|
|
78
|
-
const call = { ...block.call };
|
|
79
|
-
if (call.status === "running") {
|
|
80
|
-
call.status = "failed";
|
|
81
|
-
call.error = INTERRUPTED_TOOL_RESULT;
|
|
82
|
-
}
|
|
83
|
-
if (call.subagentSteps) {
|
|
84
|
-
call.subagentSteps = call.subagentSteps.map((step) =>
|
|
85
|
-
step.status === "running" ? { ...step, status: "failed" } : step
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
...block,
|
|
91
|
-
call,
|
|
92
|
-
result: normalizeInterruptedToolBlockResult(block.result),
|
|
93
|
-
};
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function buildInterruptedModelMessages(contentBlocks: ContentBlock[]): ModelMessage[] {
|
|
98
|
-
const messages: ModelMessage[] = [];
|
|
99
|
-
|
|
100
|
-
type AssistantPart =
|
|
101
|
-
| { type: "text"; text: string }
|
|
102
|
-
| { type: "reasoning"; text: string }
|
|
103
|
-
| { type: "tool-call"; toolCallId: string; toolName: string; input: unknown };
|
|
104
|
-
|
|
105
|
-
type ToolResultPart = {
|
|
106
|
-
type: "tool-result";
|
|
107
|
-
toolCallId: string;
|
|
108
|
-
toolName: string;
|
|
109
|
-
output: ToolResultOutput;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
let assistantParts: AssistantPart[] = [];
|
|
113
|
-
let toolResults: ToolResultPart[] = [];
|
|
114
|
-
|
|
115
|
-
for (const block of contentBlocks) {
|
|
116
|
-
if (block.type === "reasoning" && block.content) {
|
|
117
|
-
// Tool results must be emitted before new assistant reasoning.
|
|
118
|
-
if (toolResults.length > 0) {
|
|
119
|
-
messages.push({
|
|
120
|
-
role: "tool",
|
|
121
|
-
content: [...toolResults],
|
|
122
|
-
} as unknown as ModelMessage);
|
|
123
|
-
toolResults = [];
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
assistantParts.push({ type: "reasoning", text: block.content });
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (block.type === "text" && block.content) {
|
|
131
|
-
// Tool results must be emitted before new assistant text.
|
|
132
|
-
if (toolResults.length > 0) {
|
|
133
|
-
messages.push({
|
|
134
|
-
role: "tool",
|
|
135
|
-
content: [...toolResults],
|
|
136
|
-
} as unknown as ModelMessage);
|
|
137
|
-
toolResults = [];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
assistantParts.push({ type: "text", text: block.content });
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (block.type === "tool") {
|
|
145
|
-
// Tool results must be emitted before a new tool call.
|
|
146
|
-
if (toolResults.length > 0) {
|
|
147
|
-
messages.push({
|
|
148
|
-
role: "tool",
|
|
149
|
-
content: [...toolResults],
|
|
150
|
-
} as unknown as ModelMessage);
|
|
151
|
-
toolResults = [];
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const toolCallId = block.call.toolCallId;
|
|
155
|
-
if (!toolCallId) {
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
assistantParts.push({
|
|
160
|
-
type: "tool-call",
|
|
161
|
-
toolCallId,
|
|
162
|
-
toolName: block.call.name,
|
|
163
|
-
input: block.call.input ?? {},
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// Tool calls must be emitted before their tool results.
|
|
167
|
-
if (assistantParts.length > 0) {
|
|
168
|
-
messages.push({
|
|
169
|
-
role: "assistant",
|
|
170
|
-
content: [...assistantParts],
|
|
171
|
-
} as unknown as ModelMessage);
|
|
172
|
-
assistantParts = [];
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
toolResults.push({
|
|
176
|
-
type: "tool-result",
|
|
177
|
-
toolCallId,
|
|
178
|
-
toolName: block.call.name,
|
|
179
|
-
output: normalizeInterruptedToolResultOutput(block.result),
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (assistantParts.length > 0) {
|
|
185
|
-
messages.push({
|
|
186
|
-
role: "assistant",
|
|
187
|
-
content: [...assistantParts],
|
|
188
|
-
} as unknown as ModelMessage);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (toolResults.length > 0) {
|
|
192
|
-
messages.push({
|
|
193
|
-
role: "tool",
|
|
194
|
-
content: [...toolResults],
|
|
195
|
-
} as unknown as ModelMessage);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return messages;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
59
|
function finalizePendingUserMessage(
|
|
202
60
|
prev: ConversationMessage[],
|
|
203
61
|
userText: string,
|
|
@@ -725,6 +583,8 @@ function mergeTokenUsage(prev: TokenUsage, usage: TokenUsage, isSubagent: boolea
|
|
|
725
583
|
subagentTotalTokens: prev.subagentTotalTokens,
|
|
726
584
|
subagentPromptTokens: prev.subagentPromptTokens,
|
|
727
585
|
subagentCompletionTokens: prev.subagentCompletionTokens,
|
|
586
|
+
latestTurnPromptTokens: usage.promptTokens,
|
|
587
|
+
latestTurnCompletionTokens: usage.completionTokens,
|
|
728
588
|
};
|
|
729
589
|
}
|
|
730
590
|
|
|
@@ -39,6 +39,10 @@ export interface UseAppContextBuilderParams {
|
|
|
39
39
|
setShowHotkeysPane: React.Dispatch<React.SetStateAction<boolean>>;
|
|
40
40
|
showGroundingMenu: boolean;
|
|
41
41
|
setShowGroundingMenu: React.Dispatch<React.SetStateAction<boolean>>;
|
|
42
|
+
showUrlMenu: boolean;
|
|
43
|
+
setShowUrlMenu: React.Dispatch<React.SetStateAction<boolean>>;
|
|
44
|
+
showToolsMenu: boolean;
|
|
45
|
+
setShowToolsMenu: React.Dispatch<React.SetStateAction<boolean>>;
|
|
42
46
|
};
|
|
43
47
|
|
|
44
48
|
device: {
|