kagent-ts 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/LICENSE +21 -0
- package/README.md +395 -0
- package/dist/compression/interface.d.ts +26 -0
- package/dist/compression/interface.d.ts.map +1 -0
- package/dist/compression/interface.js +3 -0
- package/dist/compression/interface.js.map +1 -0
- package/dist/compression/sliding-window.d.ts +21 -0
- package/dist/compression/sliding-window.d.ts.map +1 -0
- package/dist/compression/sliding-window.js +55 -0
- package/dist/compression/sliding-window.js.map +1 -0
- package/dist/compression/types.d.ts +12 -0
- package/dist/compression/types.d.ts.map +1 -0
- package/dist/compression/types.js +3 -0
- package/dist/compression/types.js.map +1 -0
- package/dist/context/context-manager.d.ts +76 -0
- package/dist/context/context-manager.d.ts.map +1 -0
- package/dist/context/context-manager.js +132 -0
- package/dist/context/context-manager.js.map +1 -0
- package/dist/context/types.d.ts +35 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +3 -0
- package/dist/context/types.js.map +1 -0
- package/dist/core/agent.d.ts +288 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +398 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/hooks.d.ts +34 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +3 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/plan-solve-agent.d.ts +114 -0
- package/dist/core/plan-solve-agent.d.ts.map +1 -0
- package/dist/core/plan-solve-agent.js +450 -0
- package/dist/core/plan-solve-agent.js.map +1 -0
- package/dist/core/react-agent.d.ts +52 -0
- package/dist/core/react-agent.d.ts.map +1 -0
- package/dist/core/react-agent.js +266 -0
- package/dist/core/react-agent.js.map +1 -0
- package/dist/core/response-schema.d.ts +91 -0
- package/dist/core/response-schema.d.ts.map +1 -0
- package/dist/core/response-schema.js +292 -0
- package/dist/core/response-schema.js.map +1 -0
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/interface.d.ts +87 -0
- package/dist/llm/interface.d.ts.map +1 -0
- package/dist/llm/interface.js +3 -0
- package/dist/llm/interface.js.map +1 -0
- package/dist/llm/openai-provider.d.ts +92 -0
- package/dist/llm/openai-provider.d.ts.map +1 -0
- package/dist/llm/openai-provider.js +262 -0
- package/dist/llm/openai-provider.js.map +1 -0
- package/dist/messages/message.d.ts +50 -0
- package/dist/messages/message.d.ts.map +1 -0
- package/dist/messages/message.js +87 -0
- package/dist/messages/message.js.map +1 -0
- package/dist/messages/types.d.ts +31 -0
- package/dist/messages/types.d.ts.map +1 -0
- package/dist/messages/types.js +14 -0
- package/dist/messages/types.js.map +1 -0
- package/dist/preferences/preference-manager.d.ts +88 -0
- package/dist/preferences/preference-manager.d.ts.map +1 -0
- package/dist/preferences/preference-manager.js +196 -0
- package/dist/preferences/preference-manager.js.map +1 -0
- package/dist/preferences/types.d.ts +27 -0
- package/dist/preferences/types.d.ts.map +1 -0
- package/dist/preferences/types.js +3 -0
- package/dist/preferences/types.js.map +1 -0
- package/dist/session/session-manager.d.ts +56 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +156 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/session-types.d.ts +51 -0
- package/dist/session/session-types.d.ts.map +1 -0
- package/dist/session/session-types.js +3 -0
- package/dist/session/session-types.js.map +1 -0
- package/dist/skills/file-skill-loader.d.ts +88 -0
- package/dist/skills/file-skill-loader.d.ts.map +1 -0
- package/dist/skills/file-skill-loader.js +365 -0
- package/dist/skills/file-skill-loader.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +10 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skill-manager.d.ts +133 -0
- package/dist/skills/skill-manager.d.ts.map +1 -0
- package/dist/skills/skill-manager.js +310 -0
- package/dist/skills/skill-manager.js.map +1 -0
- package/dist/skills/types.d.ts +42 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +3 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/builtin/edit-file.d.ts +12 -0
- package/dist/tools/builtin/edit-file.d.ts.map +1 -0
- package/dist/tools/builtin/edit-file.js +123 -0
- package/dist/tools/builtin/edit-file.js.map +1 -0
- package/dist/tools/builtin/glob-search.d.ts +11 -0
- package/dist/tools/builtin/glob-search.d.ts.map +1 -0
- package/dist/tools/builtin/glob-search.js +264 -0
- package/dist/tools/builtin/glob-search.js.map +1 -0
- package/dist/tools/builtin/grep-search.d.ts +14 -0
- package/dist/tools/builtin/grep-search.d.ts.map +1 -0
- package/dist/tools/builtin/grep-search.js +264 -0
- package/dist/tools/builtin/grep-search.js.map +1 -0
- package/dist/tools/builtin/index.d.ts +21 -0
- package/dist/tools/builtin/index.d.ts.map +1 -0
- package/dist/tools/builtin/index.js +53 -0
- package/dist/tools/builtin/index.js.map +1 -0
- package/dist/tools/builtin/read-file.d.ts +11 -0
- package/dist/tools/builtin/read-file.d.ts.map +1 -0
- package/dist/tools/builtin/read-file.js +122 -0
- package/dist/tools/builtin/read-file.js.map +1 -0
- package/dist/tools/builtin/write-file.d.ts +10 -0
- package/dist/tools/builtin/write-file.d.ts.map +1 -0
- package/dist/tools/builtin/write-file.js +89 -0
- package/dist/tools/builtin/write-file.js.map +1 -0
- package/dist/tools/circuit-breaker.d.ts +77 -0
- package/dist/tools/circuit-breaker.d.ts.map +1 -0
- package/dist/tools/circuit-breaker.js +102 -0
- package/dist/tools/circuit-breaker.js.map +1 -0
- package/dist/tools/error-tracker.d.ts +116 -0
- package/dist/tools/error-tracker.d.ts.map +1 -0
- package/dist/tools/error-tracker.js +484 -0
- package/dist/tools/error-tracker.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +87 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +188 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/types.d.ts +95 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +14 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/token-counter.d.ts +31 -0
- package/dist/utils/token-counter.d.ts.map +1 -0
- package/dist/utils/token-counter.js +105 -0
- package/dist/utils/token-counter.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReActAgent = void 0;
|
|
4
|
+
const agent_1 = require("./agent");
|
|
5
|
+
const message_1 = require("../messages/message");
|
|
6
|
+
const response_schema_1 = require("./response-schema");
|
|
7
|
+
const openai_provider_1 = require("../llm/openai-provider");
|
|
8
|
+
const response_schema_2 = require("./response-schema");
|
|
9
|
+
/**
|
|
10
|
+
* Default system prompt for ReAct-style reasoning with structured JSON output.
|
|
11
|
+
*
|
|
12
|
+
* The LLM is instructed to respond with JSON so the agent can reliably
|
|
13
|
+
* parse thoughts and final answers — no free-text format ambiguity.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_REACT_SYSTEM_PROMPT = `You are a helpful AI assistant powered by a ReAct (Reasoning + Acting) loop.
|
|
16
|
+
You have access to a set of tools you can use to answer the user's question.
|
|
17
|
+
|
|
18
|
+
Follow this process:
|
|
19
|
+
1. Think step by step about what the user needs.
|
|
20
|
+
2. Decide whether to use a tool or give the final answer.
|
|
21
|
+
3. If using a tool, call it with the correct parameters.
|
|
22
|
+
4. Observe the result and decide the next step.
|
|
23
|
+
5. Repeat until you have the complete answer.
|
|
24
|
+
|
|
25
|
+
If no tools are needed, respond with the final answer directly.
|
|
26
|
+
Always think step by step before acting.
|
|
27
|
+
|
|
28
|
+
=== Tool Error Recovery ===
|
|
29
|
+
When a tool returns an error:
|
|
30
|
+
1. READ the error message carefully — understand WHY it failed.
|
|
31
|
+
2. ANALYZE whether the parameters were correct. Common issues:
|
|
32
|
+
- Wrong file path (check spelling, use absolute paths)
|
|
33
|
+
- Missing or incorrect arguments
|
|
34
|
+
- The tool may need different input formats
|
|
35
|
+
3. RETRY with corrected parameters if you can fix the issue.
|
|
36
|
+
4. If the same tool fails repeatedly, try a COMPLETELY DIFFERENT approach.
|
|
37
|
+
5. If a tool is disabled after too many failures, DO NOT try to use it again.
|
|
38
|
+
Find another way to accomplish the task.${response_schema_1.STRUCTURED_OUTPUT_INSTRUCTIONS}`;
|
|
39
|
+
/**
|
|
40
|
+
* ReAct Agent implementing a structured Thought → Action → Observation → Final Answer loop.
|
|
41
|
+
*
|
|
42
|
+
* The agent uses structured JSON output from the LLM:
|
|
43
|
+
* - Intermediate steps: {"thought": "..."}
|
|
44
|
+
* - Final answer: {"thought": "...", "answer": "..."}
|
|
45
|
+
* - Tool calls via native function calling (OpenAI tool_calls)
|
|
46
|
+
*
|
|
47
|
+
* Session persistence:
|
|
48
|
+
* When `enableCheckpointing` is set, the agent auto-saves checkpoints after
|
|
49
|
+
* each LLM+tools cycle. On network error, an `interrupted` checkpoint is
|
|
50
|
+
* saved so the user can resume later via `agent.resume(sessionId, input)`.
|
|
51
|
+
*/
|
|
52
|
+
class ReActAgent extends agent_1.Agent {
|
|
53
|
+
maxIterations;
|
|
54
|
+
enableSkillAutoDetect;
|
|
55
|
+
constructor(config) {
|
|
56
|
+
// Set default ReAct system prompt if none provided
|
|
57
|
+
const mergedConfig = {
|
|
58
|
+
...config,
|
|
59
|
+
systemPrompt: config.systemPrompt ?? DEFAULT_REACT_SYSTEM_PROMPT,
|
|
60
|
+
};
|
|
61
|
+
super(mergedConfig);
|
|
62
|
+
this.maxIterations = config.maxIterations ?? 10;
|
|
63
|
+
this.enableSkillAutoDetect = config.enableSkillAutoDetect ?? true;
|
|
64
|
+
// If skills are registered, rebuild the system prompt so the
|
|
65
|
+
// available-skills hint is included in the initial prompt.
|
|
66
|
+
if (this.skillManager.activeCount > 0) {
|
|
67
|
+
this.rebuildSystemPrompt();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async run(input) {
|
|
71
|
+
// ── Progressive disclosure ─────────────────────────────────────────
|
|
72
|
+
if (this.enableSkillAutoDetect && this.skillManager.activeCount >= 0) {
|
|
73
|
+
const activated = this.skillManager.detectAndActivate(input);
|
|
74
|
+
if (activated.length > 0) {
|
|
75
|
+
this.rebuildSystemPrompt();
|
|
76
|
+
console.log(`[Skills] Auto-activated: ${activated.join(", ")}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ── Create user message ──────────────────────────────────────────
|
|
80
|
+
const userMessage = message_1.Message.user(input);
|
|
81
|
+
this.contextManager.addMessage(userMessage.toDict());
|
|
82
|
+
// Save initial checkpoint (captures user input before any LLM call)
|
|
83
|
+
if (this.checkpointingEnabled) {
|
|
84
|
+
this.saveCheckpoint("active");
|
|
85
|
+
}
|
|
86
|
+
// Track consecutive unproductive iterations (no tool calls, no answer)
|
|
87
|
+
let consecutiveEmptyIterations = 0;
|
|
88
|
+
const EMPTY_ITERATION_LIMIT = 5;
|
|
89
|
+
// ── ReAct loop ────────────────────────────────────────────────────
|
|
90
|
+
for (let iteration = 0; iteration < this.maxIterations; iteration++) {
|
|
91
|
+
// Check if user cancelled (SIGINT)
|
|
92
|
+
if (this.isCancelled) {
|
|
93
|
+
this.sessionManager?.deleteSession(this.sessionManager.getSessionId());
|
|
94
|
+
return "Execution cancelled by user. Session discarded.";
|
|
95
|
+
}
|
|
96
|
+
// Check and compress if needed
|
|
97
|
+
this.checkAndCompress();
|
|
98
|
+
// Prepare messages for the LLM
|
|
99
|
+
const contextMessages = this.contextManager.getContextMessages();
|
|
100
|
+
// Call the LLM with all registered tools — with network error handling
|
|
101
|
+
this.hooks.onLLMStart?.();
|
|
102
|
+
let response;
|
|
103
|
+
try {
|
|
104
|
+
response = await this.llm.chat(contextMessages, this.toolRegistry.getTools());
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
if (err instanceof openai_provider_1.LLMNetworkError) {
|
|
108
|
+
this.hooks.onLLMError?.(err);
|
|
109
|
+
return this.handleNetworkError(err, iteration + 1);
|
|
110
|
+
}
|
|
111
|
+
throw err; // Unknown error — propagate
|
|
112
|
+
}
|
|
113
|
+
this.hooks.onLLMEnd?.(response);
|
|
114
|
+
// Parse the response content as structured JSON
|
|
115
|
+
const parsed = (0, response_schema_1.parseReActResponse)(response.content);
|
|
116
|
+
const rawContent = response.content;
|
|
117
|
+
// Create assistant message from the response
|
|
118
|
+
const assistantMessage = message_1.Message.assistant(rawContent, response.tool_calls);
|
|
119
|
+
// Store in context
|
|
120
|
+
this.contextManager.addMessage(assistantMessage.toDict());
|
|
121
|
+
// Check if LLM wants to call tools
|
|
122
|
+
if (response.tool_calls && response.tool_calls.length > 0) {
|
|
123
|
+
consecutiveEmptyIterations = 0;
|
|
124
|
+
// Log the reasoning thought and capture as error analysis
|
|
125
|
+
if (parsed.thought) {
|
|
126
|
+
console.log(`[Thought] ${parsed.thought}`);
|
|
127
|
+
this.hooks.onThought?.(parsed.thought);
|
|
128
|
+
this.captureAnalysisFromThought(parsed.thought);
|
|
129
|
+
}
|
|
130
|
+
for (const toolCall of response.tool_calls) {
|
|
131
|
+
let args;
|
|
132
|
+
try {
|
|
133
|
+
args = JSON.parse(toolCall.function.arguments);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
args = {};
|
|
137
|
+
}
|
|
138
|
+
this.hooks.onToolStart?.(toolCall.function.name, args);
|
|
139
|
+
// Execute via ToolRegistry — includes circuit breaker protection
|
|
140
|
+
let result;
|
|
141
|
+
try {
|
|
142
|
+
result = await this.toolRegistry.execute(toolCall.function.name, args);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
146
|
+
result = `Error executing tool "${toolCall.function.name}": ${message}`;
|
|
147
|
+
}
|
|
148
|
+
// Determine success vs error and fire appropriate hook
|
|
149
|
+
if (result.startsWith("Error")) {
|
|
150
|
+
this.hooks.onToolError?.(toolCall.function.name, result);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
this.hooks.onToolEnd?.(toolCall.function.name, result);
|
|
154
|
+
}
|
|
155
|
+
// Track this result for error analysis if it indicates a failure
|
|
156
|
+
this.trackToolErrorForAnalysis(toolCall.function.name, result);
|
|
157
|
+
// Create tool result message
|
|
158
|
+
const toolMessage = message_1.Message.tool(result, toolCall.id, toolCall.function.name);
|
|
159
|
+
this.contextManager.addMessage(toolMessage.toDict());
|
|
160
|
+
}
|
|
161
|
+
// Save checkpoint after complete tool execution round
|
|
162
|
+
if (this.checkpointingEnabled) {
|
|
163
|
+
this.saveCheckpoint("active");
|
|
164
|
+
}
|
|
165
|
+
// Continue the loop for the next Thought
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
// No tool calls — extract the final answer from the JSON
|
|
169
|
+
if ("answer" in parsed && parsed.answer) {
|
|
170
|
+
this.hooks.onFinish?.(parsed.answer);
|
|
171
|
+
// Save final checkpoint as completed
|
|
172
|
+
if (this.checkpointingEnabled) {
|
|
173
|
+
this.saveCheckpoint("completed");
|
|
174
|
+
}
|
|
175
|
+
return parsed.answer;
|
|
176
|
+
}
|
|
177
|
+
// JSON has "thought" but no "answer" — continue the loop
|
|
178
|
+
// (the agent is still reasoning)
|
|
179
|
+
if (parsed.thought) {
|
|
180
|
+
consecutiveEmptyIterations++;
|
|
181
|
+
console.log(`[Thought] ${parsed.thought}`);
|
|
182
|
+
this.hooks.onThought?.(parsed.thought);
|
|
183
|
+
this.captureAnalysisFromThought(parsed.thought);
|
|
184
|
+
// If stuck in unproductive thought-only loop, inject format reminder
|
|
185
|
+
if (consecutiveEmptyIterations >= 3) {
|
|
186
|
+
console.log(`[ReAct] ${consecutiveEmptyIterations} consecutive thought-only iterations — ` +
|
|
187
|
+
`injecting format reminder.`);
|
|
188
|
+
const reminderMsg = message_1.Message.assistant(response_schema_2.STRUCTURED_OUTPUT_REMINDER);
|
|
189
|
+
this.contextManager.addMessage(reminderMsg.toDict());
|
|
190
|
+
}
|
|
191
|
+
// If exceeded limit, bail out
|
|
192
|
+
if (consecutiveEmptyIterations >= EMPTY_ITERATION_LIMIT) {
|
|
193
|
+
const stuckMsg = "I apologize, but I'm having difficulty making progress on your request. " +
|
|
194
|
+
"Please try rephrasing or breaking it down into smaller, more specific steps.";
|
|
195
|
+
const stuckAssistantMessage = message_1.Message.assistant(stuckMsg);
|
|
196
|
+
this.contextManager.addMessage(stuckAssistantMessage.toDict());
|
|
197
|
+
this.hooks.onFinish?.(stuckMsg);
|
|
198
|
+
return stuckMsg;
|
|
199
|
+
}
|
|
200
|
+
// Save checkpoint after a thought-only iteration
|
|
201
|
+
if (this.checkpointingEnabled) {
|
|
202
|
+
this.saveCheckpoint("active");
|
|
203
|
+
}
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
// Empty response (no thought, no answer, no tool calls)
|
|
207
|
+
consecutiveEmptyIterations++;
|
|
208
|
+
if (consecutiveEmptyIterations >= EMPTY_ITERATION_LIMIT) {
|
|
209
|
+
const stuckMsg = "I apologize, but I'm having difficulty making progress on your request. " +
|
|
210
|
+
"Please try rephrasing or breaking it down into smaller, more specific steps.";
|
|
211
|
+
const stuckAssistantMessage = message_1.Message.assistant(stuckMsg);
|
|
212
|
+
this.contextManager.addMessage(stuckAssistantMessage.toDict());
|
|
213
|
+
this.hooks.onFinish?.(stuckMsg);
|
|
214
|
+
return stuckMsg;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// ── Max iterations reached without final answer ───────────────────
|
|
218
|
+
const timeoutMsg = `I apologize, but I was unable to complete the task within ${this.maxIterations} iterations. ` +
|
|
219
|
+
`Please try breaking your request into smaller steps.`;
|
|
220
|
+
const timeoutAssistantMessage = message_1.Message.assistant(timeoutMsg);
|
|
221
|
+
this.contextManager.addMessage(timeoutAssistantMessage.toDict());
|
|
222
|
+
this.hooks.onFinish?.(timeoutMsg);
|
|
223
|
+
return timeoutMsg;
|
|
224
|
+
}
|
|
225
|
+
// ─── Resume ──────────────────────────────────────────────────────────
|
|
226
|
+
/**
|
|
227
|
+
* Resume a previously interrupted session.
|
|
228
|
+
*
|
|
229
|
+
* Loads the saved session state (messages, system prompt) so the agent
|
|
230
|
+
* can continue from where it left off. The `input` is treated as a new
|
|
231
|
+
* user message appended to the restored conversation.
|
|
232
|
+
*
|
|
233
|
+
* @param sessionId The session ID to resume.
|
|
234
|
+
* @param input New user input to continue the conversation.
|
|
235
|
+
* @returns The agent's final response.
|
|
236
|
+
*/
|
|
237
|
+
async resume(sessionId, input) {
|
|
238
|
+
this.loadAndRestoreSession(sessionId);
|
|
239
|
+
return this.run(input);
|
|
240
|
+
}
|
|
241
|
+
// ─── Private Helpers ─────────────────────────────────────────────────
|
|
242
|
+
/**
|
|
243
|
+
* Handle an LLMNetworkError: save an interrupted checkpoint if
|
|
244
|
+
* checkpointing is enabled, and return a user-facing message with
|
|
245
|
+
* resume instructions.
|
|
246
|
+
*/
|
|
247
|
+
handleNetworkError(err, iteration) {
|
|
248
|
+
if (this.checkpointingEnabled) {
|
|
249
|
+
this.saveCheckpoint("interrupted");
|
|
250
|
+
}
|
|
251
|
+
const sid = this.sessionManager?.getSessionId() ?? "unknown";
|
|
252
|
+
console.error(`\n[Network Error] ${err.cause}: ${err.message}`);
|
|
253
|
+
if (this.checkpointingEnabled && this.sessionManager) {
|
|
254
|
+
return (`[Network Error] ${err.message}\n\n` +
|
|
255
|
+
`Your session "${sid}" has been saved (iteration ${iteration}).\n` +
|
|
256
|
+
`After your network is restored, resume with:\n` +
|
|
257
|
+
` agent.resume("${sid}", "continue with my previous request")\n\n` +
|
|
258
|
+
`Or start a new session by calling agent.run() again with a fresh input.`);
|
|
259
|
+
}
|
|
260
|
+
// Checkpointing not enabled — just report the error
|
|
261
|
+
return (`[Network Error] ${err.message}\n\n` +
|
|
262
|
+
`Please check your network connection and try again.`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
exports.ReActAgent = ReActAgent;
|
|
266
|
+
//# sourceMappingURL=react-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-agent.js","sourceRoot":"","sources":["../../src/core/react-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured JSON response schema for LLM outputs.
|
|
3
|
+
*
|
|
4
|
+
* Instead of parsing free-text ReAct format (Thought/Action/Action Input),
|
|
5
|
+
* the LLM is instructed to respond with a JSON object that the agent
|
|
6
|
+
* can reliably parse. This eliminates ambiguity in the agent loop.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Intermediate reasoning step (no final answer yet).
|
|
10
|
+
*/
|
|
11
|
+
export interface ReActReasoning {
|
|
12
|
+
/** Step-by-step reasoning about what to do next. */
|
|
13
|
+
thought: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Final answer from the agent.
|
|
17
|
+
*/
|
|
18
|
+
export interface ReActFinalAnswer {
|
|
19
|
+
/** Final reasoning before answering. */
|
|
20
|
+
thought: string;
|
|
21
|
+
/** The complete answer for the user. */
|
|
22
|
+
answer: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Union of all possible ReAct response shapes.
|
|
26
|
+
*/
|
|
27
|
+
export type ReActResponse = ReActReasoning | ReActFinalAnswer;
|
|
28
|
+
/**
|
|
29
|
+
* Parse a raw LLM content string into a structured ReActResponse.
|
|
30
|
+
*
|
|
31
|
+
* Handles:
|
|
32
|
+
* - Raw JSON: {"thought": "...", "answer": "..."}
|
|
33
|
+
* - Code blocks: ```json\n{"thought": "..."}\n```
|
|
34
|
+
* - Extra text: Let me think... {"thought": "..."}
|
|
35
|
+
*
|
|
36
|
+
* Falls back to wrapping the raw text as a thought when JSON parsing fails.
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseReActResponse(raw: string): ReActResponse;
|
|
39
|
+
/**
|
|
40
|
+
* Instructions injected into the system prompt to teach the LLM
|
|
41
|
+
* the JSON response format.
|
|
42
|
+
*/
|
|
43
|
+
export declare const STRUCTURED_OUTPUT_INSTRUCTIONS = "\n=== Response Format ===\nYou MUST respond with a valid JSON object in the \"content\" field of your message.\nDo NOT wrap the JSON in markdown code blocks.\n\nWhen you have the FINAL ANSWER for the user:\n{\"thought\": \"...step-by-step reasoning...\", \"answer\": \"...complete answer for the user...\"}\n\nWhen you are REASONING (intermediate step, before or after using tools):\n{\"thought\": \"...step-by-step reasoning...\"}\n\nRules:\n- \"thought\" is REQUIRED in every response \u2014 it contains your step-by-step reasoning.\n- \"answer\" is ONLY included in your final response, when you have the complete answer.\n- The JSON must be valid and parseable \u2014 no trailing commas, no comments.\n- If you need to use a tool, put your reasoning in \"thought\" as JSON, and send the tool call via the function calling mechanism.";
|
|
44
|
+
/**
|
|
45
|
+
* Compact one-line reminder appended to each assistant message
|
|
46
|
+
* to reinforce the JSON format.
|
|
47
|
+
*/
|
|
48
|
+
export declare const STRUCTURED_OUTPUT_REMINDER = "\n\nRemember: Respond with a JSON object: {\"thought\": \"...\", \"answer\": \"...\"} (answer only for final response).";
|
|
49
|
+
/**
|
|
50
|
+
* Response from the Plan-and-Solve agent.
|
|
51
|
+
*
|
|
52
|
+
* Different phases produce different shapes:
|
|
53
|
+
* - Planning: { thought, plan: string[] }
|
|
54
|
+
* - Executing: { thought } (may also include tool_calls)
|
|
55
|
+
* - Revising: { thought, revised_plan: string[] }
|
|
56
|
+
* - Final: { thought, answer }
|
|
57
|
+
*/
|
|
58
|
+
export interface PlanSolveResponse {
|
|
59
|
+
/** Step-by-step reasoning (required in every response). */
|
|
60
|
+
thought: string;
|
|
61
|
+
/** Initial plan — numbered steps covering the full task. */
|
|
62
|
+
plan?: string[];
|
|
63
|
+
/** Replacement plan — overrides remaining steps. */
|
|
64
|
+
revised_plan?: string[];
|
|
65
|
+
/** Final answer for the user. */
|
|
66
|
+
answer?: string;
|
|
67
|
+
/**
|
|
68
|
+
* 1-based index of the step the LLM is currently working on.
|
|
69
|
+
* Used for plan progress tracking and display.
|
|
70
|
+
* Steps before this are marked as completed.
|
|
71
|
+
*/
|
|
72
|
+
currentStep?: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Parse a raw LLM content string into a PlanSolveResponse.
|
|
76
|
+
*
|
|
77
|
+
* Reuses the same multi-strategy JSON extraction as parseReActResponse
|
|
78
|
+
* but handles the Plan-and-Solve shapes (plan/revised_plan arrays).
|
|
79
|
+
*/
|
|
80
|
+
export declare function parsePlanSolveResponse(raw: string): PlanSolveResponse;
|
|
81
|
+
/**
|
|
82
|
+
* System prompt instructions for the Plan-and-Solve paradigm.
|
|
83
|
+
*
|
|
84
|
+
* The LLM is instructed to separate planning from execution:
|
|
85
|
+
* 1. Phase 1 — PLAN: Analyze and create a detailed numbered plan.
|
|
86
|
+
* 2. Phase 2 — RESOLVE: Work through each step, using tools.
|
|
87
|
+
* Revise remaining steps if new information emerges.
|
|
88
|
+
* 3. Final: When all steps are complete, provide the full answer.
|
|
89
|
+
*/
|
|
90
|
+
export declare const PLAN_SOLVE_INSTRUCTIONS = "\n=== Plan-and-Resolve Paradigm ===\nYou follow a structured two-phase approach to solve tasks:\n\nPhase 1 \u2014 PLAN: Analyze the user's request and create a detailed, step-by-step plan covering all the work needed. Each step must be concrete and actionable.\n\nPhase 2 \u2014 RESOLVE: Execute each step of the plan. Use tools as needed.\n- After each step, you may REVISE remaining steps if the plan needs updating.\n- A revision replaces all remaining steps \u2014 do NOT re-list already completed steps.\n\n=== Response Format ===\nYou MUST respond with a valid JSON object in the \"content\" field.\n\nCreating the INITIAL PLAN:\n{\"thought\": \"...analysis...\", \"plan\": [\"Step 1: description\", \"Step 2: description\", \"...\"]}\n\nExecuting steps (use \"currentStep\" to indicate your progress):\n{\"thought\": \"...reasoning...\", \"currentStep\": 2}\n\nREVISING the plan (replaces REMAINING steps only):\n{\"thought\": \"...reasoning about why the plan needs to change...\", \"revised_plan\": [\"Updated Step A: ...\", \"Updated Step B: ...\", \"...\"]}\n\nFinal answer:\n{\"thought\": \"...summary...\", \"answer\": \"...complete answer for the user...\"}\n\nRules:\n- \"thought\" is REQUIRED in every response.\n- \"plan\" is ONLY for the initial plan creation (first response after user input).\n- \"revised_plan\" replaces REMAINING steps \u2014 do NOT re-list already done steps.\n- \"currentStep\" is the 1-based index of the step you are about to execute next.\n- \"answer\" is ONLY for the final response, when ALL steps are complete.\n- The JSON must be valid and parseable \u2014 no trailing commas, no comments.\n\n=== When to Replan \u2014 output \"revised_plan\" when: ===\n1. REPEATED TOOL FAILURES: A tool fails 2+ consecutive times on the same step.\n \u2192 The current approach isn't working \u2014 try a completely different method.\n\n2. CONTRADICTED ASSUMPTIONS: A tool result reveals information that disproves\n a key assumption your plan was based on.\n \u2192 Adjust remaining steps to account for the new reality.\n\n3. EXECUTION DRIFT: The actual state of things differs from what the plan\n expected at this point.\n \u2192 Realign the remaining steps with what has actually happened.\n\n4. STUCK ON A STEP: You cannot make progress on the current step after\n multiple attempts with different approaches.\n \u2192 Skip or reorder steps \u2014 try a different angle to reach the goal.\n\nIMPORTANT: Replanning is a normal part of problem-solving. If in doubt,\noutput a \"revised_plan\" rather than retrying the same failing approach.";
|
|
91
|
+
//# sourceMappingURL=response-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-schema.d.ts","sourceRoot":"","sources":["../../src/core/response-schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAI9D;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAwB7D;AAmID;;;GAGG;AACH,eAAO,MAAM,8BAA8B,y0BAesF,CAAC;AAElI;;;GAGG;AACH,eAAO,MAAM,0BAA0B,4HACoF,CAAC;AAI5H;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAwCrE;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,oiFAkDoC,CAAC"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Structured JSON response schema for LLM outputs.
|
|
4
|
+
*
|
|
5
|
+
* Instead of parsing free-text ReAct format (Thought/Action/Action Input),
|
|
6
|
+
* the LLM is instructed to respond with a JSON object that the agent
|
|
7
|
+
* can reliably parse. This eliminates ambiguity in the agent loop.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.PLAN_SOLVE_INSTRUCTIONS = exports.STRUCTURED_OUTPUT_REMINDER = exports.STRUCTURED_OUTPUT_INSTRUCTIONS = void 0;
|
|
11
|
+
exports.parseReActResponse = parseReActResponse;
|
|
12
|
+
exports.parsePlanSolveResponse = parsePlanSolveResponse;
|
|
13
|
+
// ─── Response Parser ────────────────────────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* Parse a raw LLM content string into a structured ReActResponse.
|
|
16
|
+
*
|
|
17
|
+
* Handles:
|
|
18
|
+
* - Raw JSON: {"thought": "...", "answer": "..."}
|
|
19
|
+
* - Code blocks: ```json\n{"thought": "..."}\n```
|
|
20
|
+
* - Extra text: Let me think... {"thought": "..."}
|
|
21
|
+
*
|
|
22
|
+
* Falls back to wrapping the raw text as a thought when JSON parsing fails.
|
|
23
|
+
*/
|
|
24
|
+
function parseReActResponse(raw) {
|
|
25
|
+
const json = extractJSON(raw);
|
|
26
|
+
if (json) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(json);
|
|
29
|
+
// Must be an object with at least "thought"
|
|
30
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
31
|
+
const thought = String(parsed.thought ?? "");
|
|
32
|
+
if ("answer" in parsed && parsed.answer !== undefined && parsed.answer !== null) {
|
|
33
|
+
return { thought, answer: String(parsed.answer) };
|
|
34
|
+
}
|
|
35
|
+
return { thought };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// JSON parse failed — fall through to fallback
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Fallback: treat the entire raw string as the thought
|
|
43
|
+
return { thought: raw };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Try to extract a JSON object from a string that may contain
|
|
47
|
+
* markdown, extra text, malformed newlines, or other noise.
|
|
48
|
+
*
|
|
49
|
+
* Strategy in order:
|
|
50
|
+
* 1. Direct parse of the trimmed text.
|
|
51
|
+
* 2. Extract from ```json ... ``` markdown block.
|
|
52
|
+
* 3. Find balanced { ... } via depth counting, then try to parse.
|
|
53
|
+
* 4. Clean up common issues (unescaped newlines) and retry steps 1-3.
|
|
54
|
+
*
|
|
55
|
+
* Returns the JSON string if found, or null.
|
|
56
|
+
*/
|
|
57
|
+
function extractJSON(text) {
|
|
58
|
+
if (!text)
|
|
59
|
+
return null;
|
|
60
|
+
// Try with progressively more aggressive cleanup
|
|
61
|
+
const variants = [
|
|
62
|
+
text.trim(),
|
|
63
|
+
cleanupJSON(text.trim()),
|
|
64
|
+
text.trim().replace(/\n/g, " ").replace(/\r/g, ""),
|
|
65
|
+
];
|
|
66
|
+
// De-duplicate variants
|
|
67
|
+
const seen = new Set();
|
|
68
|
+
const uniqueVariants = variants.filter((v) => {
|
|
69
|
+
if (seen.has(v))
|
|
70
|
+
return false;
|
|
71
|
+
seen.add(v);
|
|
72
|
+
return true;
|
|
73
|
+
});
|
|
74
|
+
for (const variant of uniqueVariants) {
|
|
75
|
+
const result = tryExtractJSON(variant);
|
|
76
|
+
if (result)
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Try all extraction strategies on a single variant of the text.
|
|
83
|
+
*/
|
|
84
|
+
function tryExtractJSON(text) {
|
|
85
|
+
// 1. Try the entire string as JSON
|
|
86
|
+
if (isValidJSON(text))
|
|
87
|
+
return text;
|
|
88
|
+
// 2. Try extracting from markdown code blocks: ```json ... ```
|
|
89
|
+
const blockMatch = text.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/);
|
|
90
|
+
if (blockMatch && isValidJSON(blockMatch[1]))
|
|
91
|
+
return blockMatch[1];
|
|
92
|
+
// 3. Try finding the first { ... } with balanced braces
|
|
93
|
+
const braceStart = text.indexOf("{");
|
|
94
|
+
if (braceStart >= 0) {
|
|
95
|
+
const fromBrace = text.slice(braceStart);
|
|
96
|
+
const result = extractBalancedBraces(fromBrace);
|
|
97
|
+
if (result)
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Find balanced { ... } and validate as JSON.
|
|
104
|
+
* Handles strings with escaped quotes to avoid false brace matching.
|
|
105
|
+
*/
|
|
106
|
+
function extractBalancedBraces(text) {
|
|
107
|
+
let depth = 0;
|
|
108
|
+
let inString = false;
|
|
109
|
+
let escapeNext = false;
|
|
110
|
+
for (let i = 0; i < text.length; i++) {
|
|
111
|
+
const ch = text[i];
|
|
112
|
+
if (inString) {
|
|
113
|
+
if (escapeNext) {
|
|
114
|
+
escapeNext = false;
|
|
115
|
+
}
|
|
116
|
+
else if (ch === "\\") {
|
|
117
|
+
escapeNext = true;
|
|
118
|
+
}
|
|
119
|
+
else if (ch === '"') {
|
|
120
|
+
inString = false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
if (ch === '"') {
|
|
125
|
+
inString = true;
|
|
126
|
+
escapeNext = false;
|
|
127
|
+
}
|
|
128
|
+
else if (ch === "{") {
|
|
129
|
+
depth++;
|
|
130
|
+
}
|
|
131
|
+
else if (ch === "}") {
|
|
132
|
+
depth--;
|
|
133
|
+
if (depth === 0) {
|
|
134
|
+
const candidate = text.slice(0, i + 1);
|
|
135
|
+
if (isValidJSON(candidate))
|
|
136
|
+
return candidate;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Clean up common JSON formatting issues from LLM output.
|
|
146
|
+
*/
|
|
147
|
+
function cleanupJSON(text) {
|
|
148
|
+
let result = text;
|
|
149
|
+
// Replace actual newlines inside JSON strings with \n escape
|
|
150
|
+
// (only between "..." regions)
|
|
151
|
+
result = result.replace(/\r\n/g, "\n").replace(/\r/g, "");
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Quick check if a string is valid JSON.
|
|
156
|
+
*/
|
|
157
|
+
function isValidJSON(text) {
|
|
158
|
+
try {
|
|
159
|
+
JSON.parse(text);
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ─── System Prompt Templates ────────────────────────────────────────────
|
|
167
|
+
/**
|
|
168
|
+
* Instructions injected into the system prompt to teach the LLM
|
|
169
|
+
* the JSON response format.
|
|
170
|
+
*/
|
|
171
|
+
exports.STRUCTURED_OUTPUT_INSTRUCTIONS = `
|
|
172
|
+
=== Response Format ===
|
|
173
|
+
You MUST respond with a valid JSON object in the "content" field of your message.
|
|
174
|
+
Do NOT wrap the JSON in markdown code blocks.
|
|
175
|
+
|
|
176
|
+
When you have the FINAL ANSWER for the user:
|
|
177
|
+
{"thought": "...step-by-step reasoning...", "answer": "...complete answer for the user..."}
|
|
178
|
+
|
|
179
|
+
When you are REASONING (intermediate step, before or after using tools):
|
|
180
|
+
{"thought": "...step-by-step reasoning..."}
|
|
181
|
+
|
|
182
|
+
Rules:
|
|
183
|
+
- "thought" is REQUIRED in every response — it contains your step-by-step reasoning.
|
|
184
|
+
- "answer" is ONLY included in your final response, when you have the complete answer.
|
|
185
|
+
- The JSON must be valid and parseable — no trailing commas, no comments.
|
|
186
|
+
- If you need to use a tool, put your reasoning in "thought" as JSON, and send the tool call via the function calling mechanism.`;
|
|
187
|
+
/**
|
|
188
|
+
* Compact one-line reminder appended to each assistant message
|
|
189
|
+
* to reinforce the JSON format.
|
|
190
|
+
*/
|
|
191
|
+
exports.STRUCTURED_OUTPUT_REMINDER = "\n\nRemember: Respond with a JSON object: {\"thought\": \"...\", \"answer\": \"...\"} (answer only for final response).";
|
|
192
|
+
/**
|
|
193
|
+
* Parse a raw LLM content string into a PlanSolveResponse.
|
|
194
|
+
*
|
|
195
|
+
* Reuses the same multi-strategy JSON extraction as parseReActResponse
|
|
196
|
+
* but handles the Plan-and-Solve shapes (plan/revised_plan arrays).
|
|
197
|
+
*/
|
|
198
|
+
function parsePlanSolveResponse(raw) {
|
|
199
|
+
const json = extractJSON(raw);
|
|
200
|
+
if (json) {
|
|
201
|
+
try {
|
|
202
|
+
const parsed = JSON.parse(json);
|
|
203
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
204
|
+
const thought = String(parsed.thought ?? "");
|
|
205
|
+
const result = { thought };
|
|
206
|
+
// plan — array of strings
|
|
207
|
+
if (parsed.plan && Array.isArray(parsed.plan)) {
|
|
208
|
+
result.plan = parsed.plan.map(String);
|
|
209
|
+
}
|
|
210
|
+
// revised_plan — array of strings
|
|
211
|
+
if (parsed.revised_plan && Array.isArray(parsed.revised_plan)) {
|
|
212
|
+
result.revised_plan = parsed.revised_plan.map(String);
|
|
213
|
+
}
|
|
214
|
+
// answer — final response
|
|
215
|
+
if (parsed.answer !== undefined && parsed.answer !== null) {
|
|
216
|
+
result.answer = String(parsed.answer);
|
|
217
|
+
}
|
|
218
|
+
// currentStep — step progress indicator (1-based)
|
|
219
|
+
if (typeof parsed.currentStep === "number" && parsed.currentStep >= 1) {
|
|
220
|
+
result.currentStep = Math.floor(parsed.currentStep);
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// JSON parse failed — fall through to fallback
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Fallback: treat the entire raw string as thought
|
|
230
|
+
return { thought: raw };
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* System prompt instructions for the Plan-and-Solve paradigm.
|
|
234
|
+
*
|
|
235
|
+
* The LLM is instructed to separate planning from execution:
|
|
236
|
+
* 1. Phase 1 — PLAN: Analyze and create a detailed numbered plan.
|
|
237
|
+
* 2. Phase 2 — RESOLVE: Work through each step, using tools.
|
|
238
|
+
* Revise remaining steps if new information emerges.
|
|
239
|
+
* 3. Final: When all steps are complete, provide the full answer.
|
|
240
|
+
*/
|
|
241
|
+
exports.PLAN_SOLVE_INSTRUCTIONS = `
|
|
242
|
+
=== Plan-and-Resolve Paradigm ===
|
|
243
|
+
You follow a structured two-phase approach to solve tasks:
|
|
244
|
+
|
|
245
|
+
Phase 1 — PLAN: Analyze the user's request and create a detailed, step-by-step plan covering all the work needed. Each step must be concrete and actionable.
|
|
246
|
+
|
|
247
|
+
Phase 2 — RESOLVE: Execute each step of the plan. Use tools as needed.
|
|
248
|
+
- After each step, you may REVISE remaining steps if the plan needs updating.
|
|
249
|
+
- A revision replaces all remaining steps — do NOT re-list already completed steps.
|
|
250
|
+
|
|
251
|
+
=== Response Format ===
|
|
252
|
+
You MUST respond with a valid JSON object in the "content" field.
|
|
253
|
+
|
|
254
|
+
Creating the INITIAL PLAN:
|
|
255
|
+
{"thought": "...analysis...", "plan": ["Step 1: description", "Step 2: description", "..."]}
|
|
256
|
+
|
|
257
|
+
Executing steps (use "currentStep" to indicate your progress):
|
|
258
|
+
{"thought": "...reasoning...", "currentStep": 2}
|
|
259
|
+
|
|
260
|
+
REVISING the plan (replaces REMAINING steps only):
|
|
261
|
+
{"thought": "...reasoning about why the plan needs to change...", "revised_plan": ["Updated Step A: ...", "Updated Step B: ...", "..."]}
|
|
262
|
+
|
|
263
|
+
Final answer:
|
|
264
|
+
{"thought": "...summary...", "answer": "...complete answer for the user..."}
|
|
265
|
+
|
|
266
|
+
Rules:
|
|
267
|
+
- "thought" is REQUIRED in every response.
|
|
268
|
+
- "plan" is ONLY for the initial plan creation (first response after user input).
|
|
269
|
+
- "revised_plan" replaces REMAINING steps — do NOT re-list already done steps.
|
|
270
|
+
- "currentStep" is the 1-based index of the step you are about to execute next.
|
|
271
|
+
- "answer" is ONLY for the final response, when ALL steps are complete.
|
|
272
|
+
- The JSON must be valid and parseable — no trailing commas, no comments.
|
|
273
|
+
|
|
274
|
+
=== When to Replan — output "revised_plan" when: ===
|
|
275
|
+
1. REPEATED TOOL FAILURES: A tool fails 2+ consecutive times on the same step.
|
|
276
|
+
→ The current approach isn't working — try a completely different method.
|
|
277
|
+
|
|
278
|
+
2. CONTRADICTED ASSUMPTIONS: A tool result reveals information that disproves
|
|
279
|
+
a key assumption your plan was based on.
|
|
280
|
+
→ Adjust remaining steps to account for the new reality.
|
|
281
|
+
|
|
282
|
+
3. EXECUTION DRIFT: The actual state of things differs from what the plan
|
|
283
|
+
expected at this point.
|
|
284
|
+
→ Realign the remaining steps with what has actually happened.
|
|
285
|
+
|
|
286
|
+
4. STUCK ON A STEP: You cannot make progress on the current step after
|
|
287
|
+
multiple attempts with different approaches.
|
|
288
|
+
→ Skip or reorder steps — try a different angle to reach the goal.
|
|
289
|
+
|
|
290
|
+
IMPORTANT: Replanning is a normal part of problem-solving. If in doubt,
|
|
291
|
+
output a "revised_plan" rather than retrying the same failing approach.`;
|
|
292
|
+
//# sourceMappingURL=response-schema.js.map
|