mini-coder 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/bun.lock +13 -13
- package/package.json +3 -3
- package/src/agent.ts +299 -41
- package/src/cli.ts +11 -2
- package/src/headless.ts +185 -47
- package/src/index.ts +105 -12
- package/src/input.ts +1 -0
- package/src/prompt.ts +86 -78
- package/src/session.ts +56 -8
- package/src/submit.ts +53 -11
- package/src/tools.ts +401 -44
- package/src/ui/agent.ts +16 -2
- package/src/ui/commands.test.ts +72 -0
- package/src/ui/commands.ts +13 -0
- package/src/ui/conversation.test.ts +91 -0
- package/src/ui/conversation.ts +122 -3
- package/src/ui/help.test.ts +1 -0
- package/src/ui/help.ts +1 -0
- package/src/ui/input.test.ts +29 -1
- package/src/ui/input.ts +45 -51
- package/src/ui/render-performance.test.ts +1 -0
- package/src/ui/status.test.ts +1 -0
- package/src/ui.ts +85 -18
package/src/prompt.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* System prompt construction.
|
|
3
3
|
*
|
|
4
|
-
* Assembles the full system prompt from
|
|
4
|
+
* Assembles the full system prompt from the core prompt template plus
|
|
5
5
|
* dynamic context: AGENTS.md files, skill catalog, plugin suffixes,
|
|
6
|
-
* and
|
|
6
|
+
* and the current environment block.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
@@ -30,8 +30,14 @@ export interface AgentsMdFile {
|
|
|
30
30
|
interface BuildSystemPromptOpts {
|
|
31
31
|
/** Current working directory. */
|
|
32
32
|
cwd: string;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/** Active provider/model identifier. */
|
|
34
|
+
modelLabel: string;
|
|
35
|
+
/** Normalized host OS label (`linux`, `mac`, or `docker`). */
|
|
36
|
+
os: string;
|
|
37
|
+
/** Active shell name (for example `bash` or `zsh`). */
|
|
38
|
+
shell: string;
|
|
39
|
+
/** Whether the active model supports image input. */
|
|
40
|
+
supportsImages?: boolean;
|
|
35
41
|
/** Git repository state, or `null`/`undefined` if not in a repo. */
|
|
36
42
|
git?: GitState | null;
|
|
37
43
|
/** Discovered AGENTS.md files, ordered root-to-leaf. */
|
|
@@ -153,7 +159,7 @@ export function discoverAgentsMd(
|
|
|
153
159
|
// ---------------------------------------------------------------------------
|
|
154
160
|
|
|
155
161
|
/**
|
|
156
|
-
* Format a git state snapshot into a single-line string for the
|
|
162
|
+
* Format a git state snapshot into a single-line string for the environment block.
|
|
157
163
|
*
|
|
158
164
|
* Fields are omitted when their values are zero. The git line format:
|
|
159
165
|
* `Git: branch main | 3 staged, 1 modified, 2 untracked | +5 −2 vs origin/main`
|
|
@@ -185,67 +191,81 @@ export function formatGitLine(state: GitState): string {
|
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
// ---------------------------------------------------------------------------
|
|
188
|
-
//
|
|
194
|
+
// Core prompt template
|
|
189
195
|
// ---------------------------------------------------------------------------
|
|
190
196
|
|
|
191
|
-
|
|
197
|
+
function buildCorePrompt(opts: BuildSystemPromptOpts): string {
|
|
198
|
+
const lines = [
|
|
199
|
+
"You are mini-coder, the best software engineering assistant in the world.",
|
|
200
|
+
"",
|
|
201
|
+
"The current environment is:",
|
|
202
|
+
`- LLM in use: ${opts.modelLabel}`,
|
|
203
|
+
`- OS: ${opts.os}`,
|
|
204
|
+
`- Current working directory: ${opts.cwd}`,
|
|
205
|
+
];
|
|
192
206
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
# Tools
|
|
198
|
-
|
|
199
|
-
You have these core tools:
|
|
200
|
-
|
|
201
|
-
- \`shell\` — run commands in the user's shell. Use this to explore the codebase, read tests/verifiers/examples, inspect required outputs, and run targeted checks, builds, or git commands. Prefer \`rg\` over \`grep\` for speed.
|
|
202
|
-
- \`edit\` — make exact-text replacements in files. Provide the file path, the exact text to find, and the replacement text. The old text must match exactly one location in the file. To create a new file, use an empty old text and the full file content as new text. Use this to write the exact final file content the task requires.
|
|
203
|
-
|
|
204
|
-
You may also have additional tools provided by plugins. Use them when they match the task.
|
|
205
|
-
|
|
206
|
-
Workflow: **inspect with shell → mutate with edit → verify with shell**.
|
|
207
|
-
|
|
208
|
-
# Code quality
|
|
209
|
-
|
|
210
|
-
- Conform to the codebase's existing conventions: patterns, naming, formatting, language idioms.
|
|
211
|
-
- Write correct, clear, minimal code. Prefer the simplest solution that satisfies the task's checks exactly. Don't over-engineer, don't add abstractions for hypothetical futures.
|
|
212
|
-
- Reuse before creating. Search for existing helpers before writing new ones.
|
|
213
|
-
- Tight error handling: no broad try/catch, no silent failures, no swallowed errors.
|
|
214
|
-
- Keep type safety. Avoid \`any\` casts. Use proper types and guards.
|
|
215
|
-
- Only add comments where the logic isn't self-evident.
|
|
216
|
-
|
|
217
|
-
# Editing discipline
|
|
218
|
-
|
|
219
|
-
- Read enough context before editing. Batch logical changes together rather than making many small edits.
|
|
220
|
-
- Never revert changes you didn't make unless explicitly asked.
|
|
221
|
-
- Never use destructive git commands (reset --hard, checkout --, clean -fd) unless the user requests it.
|
|
222
|
-
- Default to ASCII. Only use non-ASCII characters when the file already uses them or there's clear justification.
|
|
223
|
-
|
|
224
|
-
# Exploring the codebase
|
|
225
|
-
|
|
226
|
-
- Think first: before any tool call, decide all files and information you need.
|
|
227
|
-
- Early in the task, look for acceptance criteria in tests, verifier scripts, eval scripts, examples, and expected-output files. Do not rely on the task text alone when machine-checkable criteria are available.
|
|
228
|
-
- Before relying on a binary, interpreter, or CLI helper you have not yet confirmed, probe availability with focused checks such as \`command -v <tool>\`, \`<tool> --version\`, or \`python3 -m pip --version\`, then adapt to what is actually installed.
|
|
229
|
-
- Batch reads: if you need multiple files, read them together in parallel rather than one at a time.
|
|
230
|
-
- Only make sequential calls when a later call genuinely depends on an earlier result.
|
|
207
|
+
if (opts.git) {
|
|
208
|
+
lines.push(`- ${formatGitLine(opts.git)}`);
|
|
209
|
+
}
|
|
231
210
|
|
|
232
|
-
|
|
211
|
+
lines.push(
|
|
212
|
+
`- Shell: ${opts.shell}. Use \`command -v <name>\` to check what is available to you; do not assume environment support.`,
|
|
213
|
+
"- Edit: Safe exact-text replacement in a single file.",
|
|
214
|
+
);
|
|
233
215
|
|
|
234
|
-
|
|
235
|
-
-
|
|
236
|
-
|
|
237
|
-
- When discussing multiple options, use numbered lists so the user can reply with a number without turning it into a questionnaire.
|
|
238
|
-
- If asked for a review, focus on bugs, risks, regressions, and missing tests. Findings first, ordered by severity.
|
|
216
|
+
if (opts.supportsImages) {
|
|
217
|
+
lines.push("- Read Image: Read an image from disk.");
|
|
218
|
+
}
|
|
239
219
|
|
|
240
|
-
|
|
220
|
+
lines.push(
|
|
221
|
+
"",
|
|
222
|
+
"## Core working style:",
|
|
223
|
+
"",
|
|
224
|
+
"- Be concise, direct, and useful.",
|
|
225
|
+
"- Use a casual, solution-oriented technical tone. Avoid fluff and performative apologies.",
|
|
226
|
+
"- When the user gives a clear command, do it without adding extra work they did not ask for.",
|
|
227
|
+
"- Prefer the minimal implementation that satisfies the request exactly.",
|
|
228
|
+
"- Use YAGNI. Avoid speculative abstractions, future-proofing, and unnecessary compatibility shims.",
|
|
229
|
+
"- Preserve working behavior where possible. Prefer targeted fixes over rewrites.",
|
|
230
|
+
"- Be thorough, use fresh eyes and internal analysis before taking action.",
|
|
231
|
+
"- Make informed decisions based on the available information and best practices.",
|
|
232
|
+
"- Always verify the result of your actions.",
|
|
233
|
+
"",
|
|
234
|
+
"### Using the shell tool:",
|
|
235
|
+
"",
|
|
236
|
+
"- Always execute shell commands in non-interactive mode.",
|
|
237
|
+
"- Use the appropriate commands and package managers for the specified operating system.",
|
|
238
|
+
"- Don't assume the environment supports all commands; check before using them.",
|
|
239
|
+
"- Avoid destructive commands that can discard changes or override edits.",
|
|
240
|
+
"",
|
|
241
|
+
"### Working with code:",
|
|
242
|
+
"",
|
|
243
|
+
"- Describe changes before implementing them",
|
|
244
|
+
"- Prefer boring dependable solutions over clever ones",
|
|
245
|
+
"- Avoid creating extra files, systems or documentation outside of what was asked.",
|
|
246
|
+
"- Check requirements, and plan your changes before editing code.",
|
|
247
|
+
"- Implement the necessary changes, following good practices and proper error handling.",
|
|
248
|
+
"- Always verify your changes using compilation, testing, and manual verification when possible.",
|
|
249
|
+
"- Do not leave helpers, tests, or any other form of temporary files; clean up after yourself and leave no trace.",
|
|
250
|
+
"- Ensure you match the requested output exactly. This applies to file names, directory structure, number of files, output formats, and all other details.",
|
|
251
|
+
'- "Polish" is not optional; it counts just as much as solving the task.',
|
|
252
|
+
"",
|
|
253
|
+
"### Task management",
|
|
254
|
+
"",
|
|
255
|
+
"- Use `todoWrite` proactively for multi-step or non-trivial tasks.",
|
|
256
|
+
"- Capture new requirements in the todo list as soon as you understand them.",
|
|
257
|
+
"- Use `todoRead` when you need to inspect the current list before updating it or when the user asks for the current plan/status.",
|
|
258
|
+
"- Keep the todo list up-to-date above all; mark tasks `in_progress` before starting them and `completed` as soon as verification succeeds.",
|
|
259
|
+
"- A todo item is only complete if the requested work is actually finished and verified to the degree the task requires.",
|
|
260
|
+
"- Use `cancelled` to remove tasks that are no longer relevant.",
|
|
261
|
+
"- Skip todo tools for single trivial tasks and purely conversational/informational requests.",
|
|
262
|
+
'- You have the option to delegate tasks to copies of yourself with `mc -p "subtask prompt"` in the shell.',
|
|
263
|
+
"- Delegate when you are orchestrating a large to-do/plan execution.",
|
|
264
|
+
"",
|
|
265
|
+
);
|
|
241
266
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
- Run the narrowest verifier or test as soon as there is a plausible first implementation or artifact. Do not delay the first verification run until the end.
|
|
245
|
-
- When verification is down to a small number of failures, stop broad exploration and focus only on the remaining failing assertions or exact contract gaps until the last detail passes.
|
|
246
|
-
- If you encounter an error, diagnose and fix it rather than reporting it and stopping.
|
|
247
|
-
- Before concluding, run the smallest targeted verification that checks the exact contract: required files exist, names and signatures match, outputs are in the required format, and no forbidden extra artifacts were left behind.
|
|
248
|
-
- Avoid excessive looping: if you're re-reading or re-editing the same files without progress, stop and ask the user.`;
|
|
267
|
+
return lines.join("\n");
|
|
268
|
+
}
|
|
249
269
|
|
|
250
270
|
// ---------------------------------------------------------------------------
|
|
251
271
|
// System prompt assembly
|
|
@@ -255,30 +275,27 @@ Workflow: **inspect with shell → mutate with edit → verify with shell**.
|
|
|
255
275
|
* Build the full system prompt.
|
|
256
276
|
*
|
|
257
277
|
* Assembly order:
|
|
258
|
-
* 1.
|
|
278
|
+
* 1. Core prompt template (including the current environment block)
|
|
259
279
|
* 2. AGENTS.md content (project-specific)
|
|
260
280
|
* 3. Skills catalog (XML)
|
|
261
281
|
* 4. Plugin suffixes
|
|
262
|
-
* 5. Session footer (date, CWD, git)
|
|
263
282
|
*
|
|
264
283
|
* @param opts - Prompt construction options.
|
|
265
284
|
* @returns The assembled system prompt string.
|
|
266
285
|
*/
|
|
267
286
|
export function buildSystemPrompt(opts: BuildSystemPromptOpts): string {
|
|
268
|
-
const sections: string[] = [
|
|
287
|
+
const sections: string[] = [buildCorePrompt(opts)];
|
|
269
288
|
|
|
270
289
|
// 2. AGENTS.md content
|
|
271
290
|
if (opts.agentsMd && opts.agentsMd.length > 0) {
|
|
272
|
-
const agentsSection = [
|
|
273
|
-
"\n# Project Context\n",
|
|
274
|
-
"Project-specific instructions and guidelines:\n",
|
|
275
|
-
];
|
|
291
|
+
const agentsSection = [];
|
|
276
292
|
for (const file of opts.agentsMd) {
|
|
277
|
-
agentsSection.push(`## ${file.path}
|
|
293
|
+
agentsSection.push(`## ${file.path}`);
|
|
294
|
+
agentsSection.push("");
|
|
278
295
|
agentsSection.push(file.content);
|
|
279
296
|
agentsSection.push("");
|
|
280
297
|
}
|
|
281
|
-
sections.push(agentsSection.join("\n"));
|
|
298
|
+
sections.push(agentsSection.join("\n").trimEnd());
|
|
282
299
|
}
|
|
283
300
|
|
|
284
301
|
// 3. Skills catalog
|
|
@@ -294,14 +311,5 @@ export function buildSystemPrompt(opts: BuildSystemPromptOpts): string {
|
|
|
294
311
|
}
|
|
295
312
|
}
|
|
296
313
|
|
|
297
|
-
|
|
298
|
-
const footer: string[] = [];
|
|
299
|
-
footer.push(`Current date: ${opts.date}`);
|
|
300
|
-
footer.push(`Current working directory: ${opts.cwd}`);
|
|
301
|
-
if (opts.git) {
|
|
302
|
-
footer.push(formatGitLine(opts.git));
|
|
303
|
-
}
|
|
304
|
-
sections.push(footer.join("\n"));
|
|
305
|
-
|
|
306
|
-
return sections.join("\n");
|
|
314
|
+
return sections.join("\n\n");
|
|
307
315
|
}
|
package/src/session.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
ToolResultMessage,
|
|
17
17
|
UserMessage,
|
|
18
18
|
} from "@mariozechner/pi-ai";
|
|
19
|
+
import type { TodoItem } from "./tools.ts";
|
|
19
20
|
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
21
22
|
// Types
|
|
@@ -94,8 +95,8 @@ interface AppendPromptHistoryOpts {
|
|
|
94
95
|
sessionId?: string;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
/** A persisted UI-only message shown in the conversation log. */
|
|
98
|
-
export interface
|
|
98
|
+
/** A persisted UI-only info message shown in the conversation log. */
|
|
99
|
+
export interface UiInfoMessage {
|
|
99
100
|
/** Identifies this as an internal UI message. */
|
|
100
101
|
role: "ui";
|
|
101
102
|
/** UI message category for rendering and future behavior. */
|
|
@@ -106,6 +107,21 @@ export interface UiMessage {
|
|
|
106
107
|
timestamp: number;
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
/** A persisted UI-only todo snapshot shown in the conversation log. */
|
|
111
|
+
export interface UiTodoMessage {
|
|
112
|
+
/** Identifies this as an internal UI message. */
|
|
113
|
+
role: "ui";
|
|
114
|
+
/** UI message category for rendering and future behavior. */
|
|
115
|
+
kind: "todo";
|
|
116
|
+
/** Todo snapshot rendered in the conversation pane. */
|
|
117
|
+
todos: TodoItem[];
|
|
118
|
+
/** Unix timestamp in milliseconds. */
|
|
119
|
+
timestamp: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** A persisted UI-only message shown in the conversation log. */
|
|
123
|
+
export type UiMessage = UiInfoMessage | UiTodoMessage;
|
|
124
|
+
|
|
109
125
|
/** Any message persisted in session history. */
|
|
110
126
|
export type PersistedMessage = Message | UiMessage;
|
|
111
127
|
|
|
@@ -491,10 +507,27 @@ function isUiMessageRecord(value: unknown): value is UiMessage {
|
|
|
491
507
|
return false;
|
|
492
508
|
}
|
|
493
509
|
|
|
510
|
+
const timestamp = readFiniteNumber(record, "timestamp");
|
|
511
|
+
if (timestamp === null) {
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (record.kind === "info") {
|
|
516
|
+
return typeof record.content === "string";
|
|
517
|
+
}
|
|
518
|
+
|
|
494
519
|
return (
|
|
495
|
-
record.kind === "
|
|
496
|
-
|
|
497
|
-
|
|
520
|
+
record.kind === "todo" &&
|
|
521
|
+
Array.isArray(record.todos) &&
|
|
522
|
+
record.todos.every(
|
|
523
|
+
(todo) =>
|
|
524
|
+
typeof todo === "object" &&
|
|
525
|
+
todo !== null &&
|
|
526
|
+
typeof (todo as { content?: unknown }).content === "string" &&
|
|
527
|
+
((todo as { status?: unknown }).status === "pending" ||
|
|
528
|
+
(todo as { status?: unknown }).status === "in_progress" ||
|
|
529
|
+
(todo as { status?: unknown }).status === "completed"),
|
|
530
|
+
)
|
|
498
531
|
);
|
|
499
532
|
}
|
|
500
533
|
|
|
@@ -593,12 +626,12 @@ export function truncateSessions(
|
|
|
593
626
|
// ---------------------------------------------------------------------------
|
|
594
627
|
|
|
595
628
|
/**
|
|
596
|
-
* Create a persisted UI message.
|
|
629
|
+
* Create a persisted UI info message.
|
|
597
630
|
*
|
|
598
631
|
* @param content - Display text shown in the conversation log.
|
|
599
|
-
* @returns A new {@link
|
|
632
|
+
* @returns A new {@link UiInfoMessage}.
|
|
600
633
|
*/
|
|
601
|
-
export function createUiMessage(content: string):
|
|
634
|
+
export function createUiMessage(content: string): UiInfoMessage {
|
|
602
635
|
return {
|
|
603
636
|
role: "ui",
|
|
604
637
|
kind: "info",
|
|
@@ -607,6 +640,21 @@ export function createUiMessage(content: string): UiMessage {
|
|
|
607
640
|
};
|
|
608
641
|
}
|
|
609
642
|
|
|
643
|
+
/**
|
|
644
|
+
* Create a persisted UI todo snapshot message.
|
|
645
|
+
*
|
|
646
|
+
* @param todos - Todo snapshot rendered in the conversation log.
|
|
647
|
+
* @returns A new {@link UiTodoMessage}.
|
|
648
|
+
*/
|
|
649
|
+
export function createUiTodoMessage(todos: readonly TodoItem[]): UiTodoMessage {
|
|
650
|
+
return {
|
|
651
|
+
role: "ui",
|
|
652
|
+
kind: "todo",
|
|
653
|
+
todos: todos.map((todo) => ({ ...todo })),
|
|
654
|
+
timestamp: Date.now(),
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
610
658
|
/**
|
|
611
659
|
* Check whether a persisted message is a UI-only message.
|
|
612
660
|
*
|
package/src/submit.ts
CHANGED
|
@@ -9,7 +9,6 @@ import type { UserMessage } from "@mariozechner/pi-ai";
|
|
|
9
9
|
import type { AgentEvent } from "./agent.ts";
|
|
10
10
|
import { runAgentLoop } from "./agent.ts";
|
|
11
11
|
import { getErrorMessage } from "./errors.ts";
|
|
12
|
-
import { getGitState } from "./git.ts";
|
|
13
12
|
import {
|
|
14
13
|
type AppState,
|
|
15
14
|
buildPrompt,
|
|
@@ -204,12 +203,63 @@ export function resolveRawInput(
|
|
|
204
203
|
}
|
|
205
204
|
}
|
|
206
205
|
|
|
206
|
+
function recordRawPromptHistory(
|
|
207
|
+
rawInput: string,
|
|
208
|
+
state: Pick<AppState, "db" | "cwd">,
|
|
209
|
+
sessionId: string,
|
|
210
|
+
): void {
|
|
211
|
+
appendPromptHistory(state.db, {
|
|
212
|
+
text: rawInput,
|
|
213
|
+
cwd: state.cwd,
|
|
214
|
+
sessionId,
|
|
215
|
+
});
|
|
216
|
+
truncatePromptHistory(state.db, MAX_PROMPT_HISTORY);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Queue resolved user content for the next model-request boundary of an active run.
|
|
221
|
+
*
|
|
222
|
+
* The raw prompt is recorded immediately in prompt history, but the model-visible
|
|
223
|
+
* `UserMessage` is only appended to session history when the agent loop consumes it.
|
|
224
|
+
*
|
|
225
|
+
* @param rawInput - Exact raw submitted prompt text.
|
|
226
|
+
* @param content - Resolved model-visible user content.
|
|
227
|
+
* @param state - Mutable application state.
|
|
228
|
+
*/
|
|
229
|
+
export function queueResolvedInput(
|
|
230
|
+
rawInput: string,
|
|
231
|
+
content: UserMessage["content"],
|
|
232
|
+
state: AppState,
|
|
233
|
+
): void {
|
|
234
|
+
if (!state.running) {
|
|
235
|
+
throw new Error("Cannot queue input while no turn is running.");
|
|
236
|
+
}
|
|
237
|
+
if (isEmptyUserContent(content)) {
|
|
238
|
+
throw new Error("Cannot queue empty input.");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const session = ensureSession(state);
|
|
242
|
+
recordRawPromptHistory(rawInput, state, session.id);
|
|
243
|
+
state.queuedUserMessages.push({
|
|
244
|
+
role: "user",
|
|
245
|
+
content,
|
|
246
|
+
timestamp: Date.now(),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
207
250
|
// ---------------------------------------------------------------------------
|
|
208
251
|
// Turn submission
|
|
209
252
|
// ---------------------------------------------------------------------------
|
|
210
253
|
|
|
211
254
|
function handleAgentEvent(event: AgentEvent, state: AppState): void {
|
|
212
255
|
switch (event.type) {
|
|
256
|
+
case "user_message":
|
|
257
|
+
state.messages.push(event.message);
|
|
258
|
+
state.contextTokens = addMessageToContextTokens(
|
|
259
|
+
state.contextTokens,
|
|
260
|
+
event.message,
|
|
261
|
+
);
|
|
262
|
+
break;
|
|
213
263
|
case "assistant_message":
|
|
214
264
|
state.messages.push(event.message);
|
|
215
265
|
state.stats = addMessageToStats(state.stats, event.message);
|
|
@@ -270,19 +320,13 @@ export async function submitResolvedInput(
|
|
|
270
320
|
}
|
|
271
321
|
|
|
272
322
|
const session = ensureSession(state);
|
|
273
|
-
|
|
274
|
-
text: rawInput,
|
|
275
|
-
cwd: state.cwd,
|
|
276
|
-
sessionId: session.id,
|
|
277
|
-
});
|
|
278
|
-
truncatePromptHistory(state.db, MAX_PROMPT_HISTORY);
|
|
323
|
+
recordRawPromptHistory(rawInput, state, session.id);
|
|
279
324
|
|
|
280
325
|
const userMessage = {
|
|
281
326
|
role: "user",
|
|
282
327
|
content,
|
|
283
328
|
timestamp: Date.now(),
|
|
284
329
|
} satisfies UserMessage;
|
|
285
|
-
const loadGitState = state.loadGitState ?? getGitState;
|
|
286
330
|
|
|
287
331
|
const turn = appendMessage(state.db, session.id, userMessage);
|
|
288
332
|
state.messages.push(userMessage);
|
|
@@ -292,8 +336,6 @@ export async function submitResolvedInput(
|
|
|
292
336
|
);
|
|
293
337
|
hooks?.onUserMessage?.(state);
|
|
294
338
|
|
|
295
|
-
state.git = await loadGitState(state.cwd);
|
|
296
|
-
|
|
297
339
|
const systemPrompt = buildPrompt(state);
|
|
298
340
|
const { tools, toolHandlers } = buildToolList(state);
|
|
299
341
|
const modelMessages = filterModelMessages(state.messages);
|
|
@@ -318,13 +360,13 @@ export async function submitResolvedInput(
|
|
|
318
360
|
apiKey: state.providers.get(state.model.provider),
|
|
319
361
|
effort: state.effort,
|
|
320
362
|
signal: state.abortController.signal,
|
|
363
|
+
takeQueuedUserMessage: () => state.queuedUserMessages.shift() ?? null,
|
|
321
364
|
onEvent: (event) => {
|
|
322
365
|
handleAgentEvent(event, state);
|
|
323
366
|
hooks?.onEvent?.(event, state);
|
|
324
367
|
},
|
|
325
368
|
});
|
|
326
369
|
stopReason = result.stopReason;
|
|
327
|
-
state.git = await loadGitState(state.cwd);
|
|
328
370
|
return result.stopReason;
|
|
329
371
|
} finally {
|
|
330
372
|
state.running = false;
|