openfox 0.2.4 → 1.0.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/dist/agent-defaults/builder.agent.md +3 -7
- package/dist/agent-defaults/code-reviewer.agent.md +1 -2
- package/dist/agent-defaults/explorer.agent.md +22 -0
- package/dist/agent-defaults/planner.agent.md +2 -9
- package/dist/agent-defaults/verifier.agent.md +4 -5
- package/dist/ask-3RK5YJZE.js +19 -0
- package/dist/auto-compaction-WRS52ERL.js +23 -0
- package/dist/{branch.api-WDHKZJS6.js → branch.api-XADFZZAA.js} +2 -2
- package/dist/chat-handler-226J7XYE.js +201 -0
- package/dist/chunk-22CTURMH.js +128 -0
- package/dist/chunk-2KSCZSXQ.js +680 -0
- package/dist/{chunk-4Z2OZ6NX.js → chunk-3EHGGBWE.js} +29 -2
- package/dist/{chunk-GZ7ZVJIW.js → chunk-3UQACISJ.js} +159 -49
- package/dist/{chunk-AF7XS4OI.js → chunk-5YQAXUKO.js} +4 -1
- package/dist/{chunk-MTX5Y3V3.js → chunk-7IOZFJBW.js} +2 -2
- package/dist/{chunk-FUUYYDVG.js → chunk-ARKA56ZM.js} +2842 -4508
- package/dist/chunk-BU2ZYOEA.js +1067 -0
- package/dist/{chunk-O4W4555H.js → chunk-HGMG5F72.js} +1353 -1134
- package/dist/chunk-M2C5GEQR.js +137 -0
- package/dist/chunk-OWDPT3M6.js +314 -0
- package/dist/{chunk-U62ZECSQ.js → chunk-PNBH3RAX.js} +2 -2
- package/dist/chunk-QDEKU5RL.js +75 -0
- package/dist/chunk-QYP5HQV4.js +438 -0
- package/dist/chunk-S4QKTRGJ.js +343 -0
- package/dist/{chunk-ARFK3RZW.js → chunk-TPT6HP4H.js} +1 -1
- package/dist/chunk-TVQOONDR.js +75 -0
- package/dist/{chunk-5ZUU23XF.js → chunk-U6BUT37A.js} +286 -33
- package/dist/{chunk-S5NRIWEU.js → chunk-VUQPJFMQ.js} +12 -12
- package/dist/{chunk-26NRL3HX.js → chunk-XFXOSPYH.js} +3 -2
- package/dist/{chunk-N2XYX4ZA.js → chunk-XKFPU2FA.js} +13 -2
- package/dist/cli/dev.js +4 -3
- package/dist/cli/index.js +4 -3
- package/dist/{config-GIXXE4VK.js → config-GIFCEJDU.js} +11 -6
- package/dist/events-G6CKHDNZ.js +114 -0
- package/dist/folding-O52L65VN.js +37 -0
- package/dist/{init-2EJ5AC7Z.js → init-MKTUIGZU.js} +46 -13
- package/dist/orchestrator-4CBESUGB.js +39 -0
- package/dist/package.json +9 -2
- package/dist/{paths-4BPXWB2W.js → paths-MM76AWYB.js} +2 -2
- package/dist/processor-LAKHPIG3.js +236 -0
- package/dist/{project-creator-CWPKRIKI.js → project-creator-KAQXMZCT.js} +9 -8
- package/dist/projects-GSMMEVSO.js +19 -0
- package/dist/{protocol-BFFz3WM0.d.ts → protocol-BZ6OIASP.d.ts} +71 -50
- package/dist/protocol-WQENDK72.js +88 -0
- package/dist/{provider-QEVVNYOX.js → provider-4KTWU6IV.js} +41 -9
- package/dist/runtime-config-2XJJIMSC.js +9 -0
- package/dist/{serve-RYEBLJVN.js → serve-5NHW3X5B.js} +50 -18
- package/dist/server/index.d.ts +81 -27
- package/dist/server/index.js +19 -11
- package/dist/{settings-D5O3TMLD.js → settings-NCLN4JDZ.js} +4 -4
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js +1 -1
- package/dist/tools-WOZVXNEQ.js +48 -0
- package/dist/vision-fallback-63VPBSEN.js +22 -0
- package/dist/web/assets/{index-DHmZmhnR.css → index-BsaaC0X0.css} +32 -1
- package/dist/web/assets/index-CvO7QkGh.js +141 -0
- package/dist/web/index.html +2 -2
- package/dist/web/sounds/typing.mp3 +0 -0
- package/dist/workflow-defaults/default.workflow.json +1 -1
- package/package.json +9 -2
- package/dist/agent-defaults/debugger.agent.md +0 -21
- package/dist/agent-defaults/test-generator.agent.md +0 -22
- package/dist/chunk-L4XDA3V7.js +0 -218
- package/dist/tools-QMIIDJTV.js +0 -48
- package/dist/web/assets/index-CAD7Iv_d.js +0 -122
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-PNBH3RAX.js";
|
|
4
|
+
|
|
5
|
+
// src/server/llm/vision-fallback.ts
|
|
6
|
+
var DEFAULT_CONFIG = {
|
|
7
|
+
enabled: false,
|
|
8
|
+
url: "http://localhost:11434",
|
|
9
|
+
model: "qwen3-vl:2b",
|
|
10
|
+
timeout: 12e4
|
|
11
|
+
};
|
|
12
|
+
var config = { ...DEFAULT_CONFIG };
|
|
13
|
+
var configLoaded = false;
|
|
14
|
+
var descriptionCache = /* @__PURE__ */ new Map();
|
|
15
|
+
function clearDescriptionCache() {
|
|
16
|
+
descriptionCache.clear();
|
|
17
|
+
}
|
|
18
|
+
function setVisionFallbackConfig(newConfig) {
|
|
19
|
+
config = { ...config, ...newConfig };
|
|
20
|
+
configLoaded = true;
|
|
21
|
+
logger.debug("Vision fallback config updated", { config });
|
|
22
|
+
}
|
|
23
|
+
function getVisionFallbackConfig() {
|
|
24
|
+
return { ...config };
|
|
25
|
+
}
|
|
26
|
+
function isVisionFallbackEnabled() {
|
|
27
|
+
return config.enabled;
|
|
28
|
+
}
|
|
29
|
+
async function ensureVisionFallbackConfigLoaded() {
|
|
30
|
+
if (configLoaded) return;
|
|
31
|
+
try {
|
|
32
|
+
const { loadGlobalConfig, getVisionFallback } = await import("./config-GIFCEJDU.js");
|
|
33
|
+
const { getRuntimeConfig } = await import("./runtime-config-2XJJIMSC.js");
|
|
34
|
+
const runtimeConfig = getRuntimeConfig();
|
|
35
|
+
const mode = runtimeConfig.mode ?? "production";
|
|
36
|
+
const globalConfig = await loadGlobalConfig(mode);
|
|
37
|
+
const fallback = getVisionFallback(globalConfig);
|
|
38
|
+
config = {
|
|
39
|
+
enabled: fallback.enabled ?? false,
|
|
40
|
+
url: fallback.url ?? "http://localhost:11434",
|
|
41
|
+
model: fallback.model ?? "qwen3-vl:2b",
|
|
42
|
+
timeout: (fallback.timeout ?? 120) * 1e3
|
|
43
|
+
};
|
|
44
|
+
configLoaded = true;
|
|
45
|
+
logger.debug("Vision fallback config loaded from global config", { config });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.warn("Failed to load vision fallback config from global config", { error: error instanceof Error ? error.message : String(error) });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var IMAGE_PROMPT = `Describe this image in detail. Focus on:
|
|
51
|
+
- What the image shows (UI, diagram, photo, etc.)
|
|
52
|
+
- Any text visible in the image
|
|
53
|
+
- Layout and visual structure
|
|
54
|
+
- Key elements and their relationships
|
|
55
|
+
|
|
56
|
+
Provide a concise but comprehensive description.`;
|
|
57
|
+
async function describeImage(base64Data, options) {
|
|
58
|
+
await ensureVisionFallbackConfigLoaded();
|
|
59
|
+
if (!config.enabled) {
|
|
60
|
+
return "[Image - vision fallback not enabled]";
|
|
61
|
+
}
|
|
62
|
+
const cacheKey = `${base64Data.slice(0, 100)}:${options?.context ?? ""}`;
|
|
63
|
+
const cached = descriptionCache.get(cacheKey);
|
|
64
|
+
if (cached) {
|
|
65
|
+
logger.debug("Using cached image description");
|
|
66
|
+
return cached;
|
|
67
|
+
}
|
|
68
|
+
const timeout = options?.timeout ?? config.timeout;
|
|
69
|
+
try {
|
|
70
|
+
const url = `${config.url}/api/chat`;
|
|
71
|
+
const requestBody = {
|
|
72
|
+
model: config.model,
|
|
73
|
+
messages: [
|
|
74
|
+
{
|
|
75
|
+
role: "user",
|
|
76
|
+
content: options?.context ? `${IMAGE_PROMPT}
|
|
77
|
+
|
|
78
|
+
Context: ${options.context}` : IMAGE_PROMPT,
|
|
79
|
+
images: [base64Data]
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
stream: false,
|
|
83
|
+
think: false
|
|
84
|
+
};
|
|
85
|
+
const controller = new AbortController();
|
|
86
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
87
|
+
const response = await fetch(url, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "application/json"
|
|
91
|
+
},
|
|
92
|
+
body: JSON.stringify(requestBody),
|
|
93
|
+
signal: controller.signal
|
|
94
|
+
});
|
|
95
|
+
clearTimeout(timeoutId);
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
98
|
+
logger.error("Vision fallback API error", { status: response.status, error: errorText });
|
|
99
|
+
return `[Image description failed: HTTP ${response.status}]`;
|
|
100
|
+
}
|
|
101
|
+
const data = await response.json();
|
|
102
|
+
const description = data.message?.content?.trim();
|
|
103
|
+
if (!description) {
|
|
104
|
+
logger.warn("Vision fallback returned empty description");
|
|
105
|
+
return "[Image - could not describe]";
|
|
106
|
+
}
|
|
107
|
+
descriptionCache.set(cacheKey, description);
|
|
108
|
+
logger.debug("Cached image description", { cacheKey: cacheKey.slice(0, 20) });
|
|
109
|
+
return description;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
112
|
+
logger.error("Vision fallback error", { error: message });
|
|
113
|
+
if (message.includes("abort")) {
|
|
114
|
+
return "[Image description timed out]";
|
|
115
|
+
}
|
|
116
|
+
return `[Image description failed: ${message}]`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function describeImageFromDataUrl(dataUrl, options) {
|
|
120
|
+
const base64Match = dataUrl.match(/^data:image\/[^;]+;base64,(.+)$/);
|
|
121
|
+
if (!base64Match || !base64Match[1]) {
|
|
122
|
+
return "[Invalid image data URL]";
|
|
123
|
+
}
|
|
124
|
+
return describeImage(base64Match[1], options);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
descriptionCache,
|
|
129
|
+
clearDescriptionCache,
|
|
130
|
+
setVisionFallbackConfig,
|
|
131
|
+
getVisionFallbackConfig,
|
|
132
|
+
isVisionFallbackEnabled,
|
|
133
|
+
ensureVisionFallbackConfigLoaded,
|
|
134
|
+
describeImage,
|
|
135
|
+
describeImageFromDataUrl
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=chunk-M2C5GEQR.js.map
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BUILDER_KICKOFF_PROMPT,
|
|
3
|
+
PathAccessDeniedError,
|
|
4
|
+
TurnMetrics,
|
|
5
|
+
VERIFIER_KICKOFF_PROMPT,
|
|
6
|
+
assembleAgentRequest,
|
|
7
|
+
buildAgentReminder,
|
|
8
|
+
createChatDoneEvent,
|
|
9
|
+
createMessageStartEvent,
|
|
10
|
+
executeSubAgent,
|
|
11
|
+
findAgentById,
|
|
12
|
+
getSubAgents,
|
|
13
|
+
getToolRegistryForAgent,
|
|
14
|
+
loadAllAgentsDefault,
|
|
15
|
+
runTopLevelAgentLoop
|
|
16
|
+
} from "./chunk-ARKA56ZM.js";
|
|
17
|
+
import {
|
|
18
|
+
getCurrentContextWindowId,
|
|
19
|
+
getEventStore
|
|
20
|
+
} from "./chunk-BU2ZYOEA.js";
|
|
21
|
+
import {
|
|
22
|
+
buildSnapshotFromSessionState
|
|
23
|
+
} from "./chunk-2KSCZSXQ.js";
|
|
24
|
+
import {
|
|
25
|
+
createChatMessageMessage
|
|
26
|
+
} from "./chunk-S4QKTRGJ.js";
|
|
27
|
+
import {
|
|
28
|
+
logger
|
|
29
|
+
} from "./chunk-PNBH3RAX.js";
|
|
30
|
+
|
|
31
|
+
// src/server/sub-agents/verifier-helpers.ts
|
|
32
|
+
var MAX_CONSECUTIVE_VERIFIER_NUDGES = 10;
|
|
33
|
+
var VERIFIER_STALL_REASON = "Verifier stopped repeatedly before terminalizing verification after repeated nudges.";
|
|
34
|
+
function getCriteriaAwaitingVerification(criteria) {
|
|
35
|
+
return criteria.filter((criterion) => criterion.status.type === "completed");
|
|
36
|
+
}
|
|
37
|
+
function buildVerifierNudgeContent(criteria) {
|
|
38
|
+
const ids = criteria.map((criterion) => criterion.id).join(", ");
|
|
39
|
+
return `You stopped before finalizing verification. ${criteria.length} criteria still need a terminal verification result. Use criterion with action "pass" or "fail" for each remaining criterion: ${ids}.`;
|
|
40
|
+
}
|
|
41
|
+
function buildVerifierRestartContent(criteria) {
|
|
42
|
+
const ids = criteria.map((criterion) => criterion.id).join(", ");
|
|
43
|
+
return `${VERIFIER_STALL_REASON} Leaving remaining criteria unchanged so verification can restart in a fresh window: ${ids}.`;
|
|
44
|
+
}
|
|
45
|
+
function createVerifierNudgeConfig() {
|
|
46
|
+
return {
|
|
47
|
+
maxConsecutiveNudges: MAX_CONSECUTIVE_VERIFIER_NUDGES,
|
|
48
|
+
getCriteriaAwaiting: getCriteriaAwaitingVerification,
|
|
49
|
+
buildNudgeContent: buildVerifierNudgeContent,
|
|
50
|
+
buildRestartContent: buildVerifierRestartContent
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/server/chat/orchestrator.ts
|
|
55
|
+
function getCurrentWindowMessageOptions(sessionId) {
|
|
56
|
+
const contextWindowId = getCurrentContextWindowId(sessionId);
|
|
57
|
+
return contextWindowId ? { contextWindowId } : void 0;
|
|
58
|
+
}
|
|
59
|
+
function resolveStatsIdentity(options) {
|
|
60
|
+
const model = options.llmClient.getModel();
|
|
61
|
+
if (options.statsIdentity) {
|
|
62
|
+
return {
|
|
63
|
+
...options.statsIdentity,
|
|
64
|
+
model
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
providerId: `provider:${model}`,
|
|
69
|
+
providerName: "Unknown Provider",
|
|
70
|
+
backend: "unknown",
|
|
71
|
+
model
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function runChatTurn(options) {
|
|
75
|
+
const { sessionManager, sessionId } = options;
|
|
76
|
+
const eventStore = getEventStore();
|
|
77
|
+
const statsIdentity = resolveStatsIdentity(options);
|
|
78
|
+
const session = sessionManager.requireSession(sessionId);
|
|
79
|
+
const mode = session.mode;
|
|
80
|
+
logger.debug("Starting chat turn", { sessionId, mode });
|
|
81
|
+
const turnMetrics = new TurnMetrics();
|
|
82
|
+
try {
|
|
83
|
+
if (mode === "builder") {
|
|
84
|
+
await runBuilderTurn(options, turnMetrics);
|
|
85
|
+
} else {
|
|
86
|
+
await runGenericAgentTurn(options, turnMetrics, mode);
|
|
87
|
+
}
|
|
88
|
+
const snapshot = buildSnapshot(sessionManager, sessionId, turnMetrics.buildStats(statsIdentity, mode));
|
|
89
|
+
const snapshotEvent = eventStore.append(sessionId, { type: "turn.snapshot", data: snapshot });
|
|
90
|
+
const deletedCount = eventStore.cleanupOldEvents(sessionId);
|
|
91
|
+
if (deletedCount > 0) {
|
|
92
|
+
logger.debug("Cleaned up old events after snapshot", { sessionId, deletedCount, snapshotSeq: snapshotEvent.seq });
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error instanceof PathAccessDeniedError) {
|
|
96
|
+
const errorMsgId2 = crypto.randomUUID();
|
|
97
|
+
const reasonText = error.reason === "sensitive_file" ? "sensitive files that may contain secrets" : error.reason === "both" ? "files outside the project and sensitive files" : "files outside the project directory";
|
|
98
|
+
eventStore.append(sessionId, {
|
|
99
|
+
type: "chat.error",
|
|
100
|
+
data: {
|
|
101
|
+
error: `User denied access to ${reasonText}.`,
|
|
102
|
+
recoverable: false
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
eventStore.append(sessionId, createMessageStartEvent(errorMsgId2, "user", `Access denied: ${error.paths.join(", ")}. If you need this file, explain why and ask the user for permission.`, {
|
|
106
|
+
...getCurrentWindowMessageOptions(sessionId) ?? {},
|
|
107
|
+
isSystemGenerated: true,
|
|
108
|
+
messageKind: "correction"
|
|
109
|
+
}));
|
|
110
|
+
eventStore.append(sessionId, createChatDoneEvent(errorMsgId2, "error"));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (error instanceof Error && error.message === "Aborted") {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
logger.error("Chat turn error", { sessionId, mode, error });
|
|
117
|
+
const errorMsgId = crypto.randomUUID();
|
|
118
|
+
eventStore.append(sessionId, {
|
|
119
|
+
type: "chat.error",
|
|
120
|
+
data: {
|
|
121
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
122
|
+
recoverable: false
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
eventStore.append(sessionId, createMessageStartEvent(errorMsgId, "user", `Error: ${error instanceof Error ? error.message : "Unknown error"}`, {
|
|
126
|
+
...getCurrentWindowMessageOptions(sessionId) ?? {},
|
|
127
|
+
isSystemGenerated: true,
|
|
128
|
+
messageKind: "correction"
|
|
129
|
+
}));
|
|
130
|
+
eventStore.append(sessionId, createChatDoneEvent(errorMsgId, "error"));
|
|
131
|
+
} finally {
|
|
132
|
+
eventStore.append(sessionId, { type: "running.changed", data: { isRunning: false } });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function injectModeReminderIfNeeded(sessionManager, sessionId, agentId, allAgents, onMessage) {
|
|
136
|
+
const eventStore = getEventStore();
|
|
137
|
+
const session = sessionManager.requireSession(sessionId);
|
|
138
|
+
const lastModeReminder = session.executionState?.lastModeWithReminder;
|
|
139
|
+
if (lastModeReminder === agentId) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const agentDef = findAgentById(agentId, allAgents);
|
|
143
|
+
if (!agentDef) return;
|
|
144
|
+
const reminderContent = buildAgentReminder(agentDef);
|
|
145
|
+
const reminderMsgId = crypto.randomUUID();
|
|
146
|
+
const currentWindowMessageOptions = getCurrentContextWindowId(sessionId) ? { contextWindowId: getCurrentContextWindowId(sessionId) } : void 0;
|
|
147
|
+
eventStore.append(sessionId, {
|
|
148
|
+
type: "message.start",
|
|
149
|
+
data: {
|
|
150
|
+
messageId: reminderMsgId,
|
|
151
|
+
role: "user",
|
|
152
|
+
content: reminderContent,
|
|
153
|
+
...currentWindowMessageOptions ?? {},
|
|
154
|
+
isSystemGenerated: true,
|
|
155
|
+
messageKind: "auto-prompt",
|
|
156
|
+
metadata: {
|
|
157
|
+
type: "agent",
|
|
158
|
+
name: agentDef.metadata.name ?? agentDef.metadata.id,
|
|
159
|
+
color: agentDef.metadata.color ?? "#6b7280"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
eventStore.append(sessionId, {
|
|
164
|
+
type: "message.done",
|
|
165
|
+
data: { messageId: reminderMsgId }
|
|
166
|
+
});
|
|
167
|
+
if (onMessage) {
|
|
168
|
+
onMessage(createChatMessageMessage({
|
|
169
|
+
id: reminderMsgId,
|
|
170
|
+
role: "user",
|
|
171
|
+
content: reminderContent,
|
|
172
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
173
|
+
isSystemGenerated: true,
|
|
174
|
+
messageKind: "auto-prompt",
|
|
175
|
+
metadata: {
|
|
176
|
+
type: "agent",
|
|
177
|
+
name: agentDef.metadata.name ?? agentDef.metadata.id,
|
|
178
|
+
color: agentDef.metadata.color ?? "#6b7280"
|
|
179
|
+
}
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
sessionManager.updateExecutionState(sessionId, {
|
|
183
|
+
lastModeWithReminder: agentId
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
async function runGenericAgentTurn(options, turnMetrics, agentId) {
|
|
187
|
+
const statsIdentity = resolveStatsIdentity(options);
|
|
188
|
+
const allAgents = await loadAllAgentsDefault();
|
|
189
|
+
injectModeReminderIfNeeded(options.sessionManager, options.sessionId, agentId, allAgents, options.onMessage);
|
|
190
|
+
const agentDef = findAgentById(agentId, allAgents) ?? findAgentById("planner", allAgents);
|
|
191
|
+
const subAgentDefs = getSubAgents(allAgents);
|
|
192
|
+
await runTopLevelAgentLoop({
|
|
193
|
+
mode: agentId,
|
|
194
|
+
sessionManager: options.sessionManager,
|
|
195
|
+
sessionId: options.sessionId,
|
|
196
|
+
llmClient: options.llmClient,
|
|
197
|
+
statsIdentity,
|
|
198
|
+
signal: options.signal,
|
|
199
|
+
onMessage: options.onMessage,
|
|
200
|
+
assembleRequest: (input) => assembleAgentRequest({ ...input, agentDef, subAgentDefs }),
|
|
201
|
+
getToolRegistry: () => getToolRegistryForAgent(agentDef)
|
|
202
|
+
}, turnMetrics);
|
|
203
|
+
}
|
|
204
|
+
function filterToolRegistryForStepDone(baseRegistry, _injectStepDone) {
|
|
205
|
+
return baseRegistry;
|
|
206
|
+
}
|
|
207
|
+
async function runBuilderTurn(options, turnMetrics) {
|
|
208
|
+
const { sessionManager, sessionId } = options;
|
|
209
|
+
const statsIdentity = resolveStatsIdentity(options);
|
|
210
|
+
const eventStore = getEventStore();
|
|
211
|
+
const allAgents = await loadAllAgentsDefault();
|
|
212
|
+
injectModeReminderIfNeeded(options.sessionManager, options.sessionId, "builder", allAgents, options.onMessage);
|
|
213
|
+
const builderDef = findAgentById("builder", allAgents);
|
|
214
|
+
const subAgentDefs = getSubAgents(allAgents);
|
|
215
|
+
let stepDoneCalled = false;
|
|
216
|
+
return {
|
|
217
|
+
...await runTopLevelAgentLoop({
|
|
218
|
+
mode: "builder",
|
|
219
|
+
sessionManager,
|
|
220
|
+
sessionId,
|
|
221
|
+
llmClient: options.llmClient,
|
|
222
|
+
statsIdentity,
|
|
223
|
+
signal: options.signal,
|
|
224
|
+
onMessage: options.onMessage,
|
|
225
|
+
assembleRequest: (input) => assembleAgentRequest({ ...input, agentDef: builderDef, subAgentDefs }),
|
|
226
|
+
getToolRegistry: () => {
|
|
227
|
+
const baseRegistry = getToolRegistryForAgent(builderDef);
|
|
228
|
+
return filterToolRegistryForStepDone(baseRegistry, options.injectStepDone === true);
|
|
229
|
+
},
|
|
230
|
+
onToolExecuted: (toolCall, toolResult) => {
|
|
231
|
+
if (toolCall.name === "step_done" && toolResult.success) {
|
|
232
|
+
stepDoneCalled = true;
|
|
233
|
+
}
|
|
234
|
+
if (toolResult.success && ["write_file", "edit_file"].includes(toolCall.name)) {
|
|
235
|
+
const path = toolCall.arguments["path"];
|
|
236
|
+
sessionManager.addModifiedFile(sessionId, path);
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
injectKickoff: () => {
|
|
240
|
+
if (options.injectBuilderKickoff !== true) return;
|
|
241
|
+
const session = sessionManager.requireSession(sessionId);
|
|
242
|
+
const events = eventStore.getEvents(sessionId);
|
|
243
|
+
const hasBuilderKickoff = events.some((e) => {
|
|
244
|
+
if (e.type !== "message.start") return false;
|
|
245
|
+
const data = e.data;
|
|
246
|
+
return data.messageKind === "auto-prompt" && data.content?.includes("fulfil the");
|
|
247
|
+
});
|
|
248
|
+
if (!hasBuilderKickoff) {
|
|
249
|
+
const kickoffMsgId = crypto.randomUUID();
|
|
250
|
+
const kickoffContent = BUILDER_KICKOFF_PROMPT(session.criteria.length);
|
|
251
|
+
eventStore.append(sessionId, createMessageStartEvent(kickoffMsgId, "user", kickoffContent, {
|
|
252
|
+
...getCurrentWindowMessageOptions(sessionId) ?? {},
|
|
253
|
+
isSystemGenerated: true,
|
|
254
|
+
messageKind: "auto-prompt",
|
|
255
|
+
metadata: { type: "agent", name: "Builder", color: "#22c55e" }
|
|
256
|
+
}));
|
|
257
|
+
eventStore.append(sessionId, { type: "message.done", data: { messageId: kickoffMsgId } });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}, turnMetrics),
|
|
261
|
+
stepDoneCalled
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
async function runVerifierTurn(options, turnMetrics) {
|
|
265
|
+
const { sessionManager, sessionId, llmClient, signal, onMessage } = options;
|
|
266
|
+
const statsIdentity = resolveStatsIdentity(options);
|
|
267
|
+
const session = sessionManager.requireSession(sessionId);
|
|
268
|
+
const toVerify = session.criteria.filter((c) => c.status.type === "completed");
|
|
269
|
+
if (toVerify.length === 0) {
|
|
270
|
+
logger.debug("Nothing to verify", { sessionId });
|
|
271
|
+
return { allPassed: true, failed: [] };
|
|
272
|
+
}
|
|
273
|
+
const allAgents = await loadAllAgentsDefault();
|
|
274
|
+
const verifierDef = findAgentById("verifier", allAgents);
|
|
275
|
+
const toolRegistry = getToolRegistryForAgent(verifierDef);
|
|
276
|
+
const result = await executeSubAgent({
|
|
277
|
+
subAgentType: "verifier",
|
|
278
|
+
prompt: VERIFIER_KICKOFF_PROMPT,
|
|
279
|
+
sessionManager,
|
|
280
|
+
sessionId,
|
|
281
|
+
llmClient,
|
|
282
|
+
toolRegistry,
|
|
283
|
+
turnMetrics,
|
|
284
|
+
statsIdentity,
|
|
285
|
+
signal,
|
|
286
|
+
onMessage,
|
|
287
|
+
nudgeConfig: createVerifierNudgeConfig()
|
|
288
|
+
});
|
|
289
|
+
return {
|
|
290
|
+
allPassed: result.allPassed ?? true,
|
|
291
|
+
failed: result.failed ?? [],
|
|
292
|
+
content: result.content
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function buildSnapshot(sessionManager, sessionId, lastStats) {
|
|
296
|
+
const eventStore = getEventStore();
|
|
297
|
+
const session = sessionManager.requireSession(sessionId);
|
|
298
|
+
const events = eventStore.getEvents(sessionId);
|
|
299
|
+
const latestSeq = eventStore.getLatestSeq(sessionId) ?? 0;
|
|
300
|
+
return buildSnapshotFromSessionState({
|
|
301
|
+
session,
|
|
302
|
+
events,
|
|
303
|
+
latestSeq
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export {
|
|
308
|
+
createVerifierNudgeConfig,
|
|
309
|
+
runChatTurn,
|
|
310
|
+
filterToolRegistryForStepDone,
|
|
311
|
+
runBuilderTurn,
|
|
312
|
+
runVerifierTurn
|
|
313
|
+
};
|
|
314
|
+
//# sourceMappingURL=chunk-OWDPT3M6.js.map
|
|
@@ -8,7 +8,7 @@ var LEVELS = {
|
|
|
8
8
|
var currentLevel = "info";
|
|
9
9
|
function setLogLevel(level, mode) {
|
|
10
10
|
if (mode && !level) {
|
|
11
|
-
currentLevel = mode === "development" ? "debug" : "warn";
|
|
11
|
+
currentLevel = mode === "development" ? "debug" : mode === "test" ? "error" : "warn";
|
|
12
12
|
} else {
|
|
13
13
|
currentLevel = level ?? "info";
|
|
14
14
|
}
|
|
@@ -51,4 +51,4 @@ export {
|
|
|
51
51
|
setLogLevel,
|
|
52
52
|
logger
|
|
53
53
|
};
|
|
54
|
-
//# sourceMappingURL=chunk-
|
|
54
|
+
//# sourceMappingURL=chunk-PNBH3RAX.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-PNBH3RAX.js";
|
|
4
|
+
|
|
5
|
+
// src/server/session/name-generator.ts
|
|
6
|
+
var SESSION_NAME_PROMPT = `Generate a concise, descriptive session name (max 50 characters) based on the user's message.
|
|
7
|
+
Return ONLY the name, nothing else.
|
|
8
|
+
|
|
9
|
+
Example inputs and outputs:
|
|
10
|
+
- "How do I set up React?" \u2192 "React setup"
|
|
11
|
+
- "Fix the authentication bug" \u2192 "Fix authentication bug"
|
|
12
|
+
- "Add unit tests for the API" \u2192 "Add API unit tests"
|
|
13
|
+
|
|
14
|
+
User message: {message}`;
|
|
15
|
+
async function generateSessionName(options) {
|
|
16
|
+
const { userMessage, llmClient, signal } = options;
|
|
17
|
+
try {
|
|
18
|
+
logger.debug("Generating session name", { messagePreview: userMessage.slice(0, 50) });
|
|
19
|
+
const prompt = SESSION_NAME_PROMPT.replace("{message}", userMessage);
|
|
20
|
+
const messages = [
|
|
21
|
+
{
|
|
22
|
+
role: "user",
|
|
23
|
+
content: prompt
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
const timeoutSignal = AbortSignal.timeout(6e4);
|
|
27
|
+
const composedSignal = signal ? AbortSignal.any([timeoutSignal, signal]) : timeoutSignal;
|
|
28
|
+
const response = await llmClient.complete({
|
|
29
|
+
messages,
|
|
30
|
+
tools: [],
|
|
31
|
+
signal: composedSignal,
|
|
32
|
+
disableThinking: true
|
|
33
|
+
});
|
|
34
|
+
let name = response.content.trim();
|
|
35
|
+
if (name.length > 50) {
|
|
36
|
+
name = name.substring(0, 47) + "...";
|
|
37
|
+
}
|
|
38
|
+
if (!name || name.length < 3) {
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
error: "Generated name is too short or empty"
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
logger.debug("Session name generated successfully", { name });
|
|
45
|
+
return {
|
|
46
|
+
success: true,
|
|
47
|
+
name
|
|
48
|
+
};
|
|
49
|
+
} catch (error) {
|
|
50
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error generating session name";
|
|
51
|
+
logger.debug("Session name generation error", { error: errorMessage });
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
error: errorMessage
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function needsNameGeneration(sessionTitle, messageCount) {
|
|
59
|
+
if (messageCount > 1) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (!sessionTitle || sessionTitle.trim() === "") {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if (/^Session \d+$/.test(sessionTitle)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
generateSessionName,
|
|
73
|
+
needsNameGeneration
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=chunk-QDEKU5RL.js.map
|