Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0eeb4a8ed8 | |||
| a3fac708b6 | |||
| 52879c0028 | |||
| 9e4527bb89 | |||
| 5209cfa7ac |
@@ -141,7 +141,7 @@ function apiKeyEnvName(providerName: string): string {
|
||||
* Discover uwf-* agent binaries in PATH.
|
||||
* Returns sorted list of binary names (e.g., ["uwf-hermes", "uwf-claude-code"]).
|
||||
*/
|
||||
async function discoverAgents(): Promise<string[]> {
|
||||
async function _discoverAgents(): Promise<string[]> {
|
||||
try {
|
||||
// Use which -a to find all uwf-* binaries in PATH
|
||||
const proc = Bun.spawn(["which", "-a", "uwf-hermes", "uwf-claude-code", "uwf-cursor"], {
|
||||
@@ -186,12 +186,15 @@ async function discoverAgents(): Promise<string[]> {
|
||||
}
|
||||
|
||||
// Parse which output - each line is a path to a binary
|
||||
const paths = text.trim().split("\n").filter((line) => line.length > 0);
|
||||
const paths = text
|
||||
.trim()
|
||||
.split("\n")
|
||||
.filter((line) => line.length > 0);
|
||||
const agents = new Set<string>();
|
||||
|
||||
for (const path of paths) {
|
||||
const basename = path.split("/").pop();
|
||||
if (basename && basename.startsWith("uwf-") && basename !== "uwf") {
|
||||
if (basename?.startsWith("uwf-") && basename !== "uwf") {
|
||||
agents.add(basename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +539,7 @@ function collectOrderedSteps(
|
||||
}
|
||||
|
||||
function formatYaml(value: unknown): string {
|
||||
return stringify(value).trimEnd();
|
||||
return stringify(value, { aliasDuplicateObjects: false }).trimEnd();
|
||||
}
|
||||
|
||||
function formatCompactStep(index: number, item: OrderedStepItem, outputYaml: string): string {
|
||||
|
||||
@@ -7,6 +7,6 @@ export function formatOutput(data: unknown, format: OutputFormat): string {
|
||||
case "json":
|
||||
return JSON.stringify(data);
|
||||
case "yaml":
|
||||
return stringify(data).trimEnd();
|
||||
return stringify(data, { aliasDuplicateObjects: false }).trimEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,28 @@ import { storeBuiltinDetail } from "./detail.js";
|
||||
import type { ChatMessage } from "./llm/index.js";
|
||||
import { BUILTIN_CONTINUE_MAX_TURNS, BUILTIN_MAX_TURNS, runBuiltinLoop } from "./loop.js";
|
||||
import { buildBuiltinMessages } from "./prompt.js";
|
||||
import { initSessionDir, removeSession } from "./session.js";
|
||||
import { initSessionDir } from "./session.js";
|
||||
|
||||
const log = createLogger({ sink: { kind: "stderr" } });
|
||||
|
||||
const FRONTMATTER_FENCE = "---";
|
||||
|
||||
/**
|
||||
* Strip any text before the first `---` fence.
|
||||
* LLMs sometimes emit preamble text before the frontmatter block.
|
||||
*/
|
||||
function stripPreamble(text: string): string {
|
||||
if (text.startsWith(FRONTMATTER_FENCE)) {
|
||||
return text;
|
||||
}
|
||||
const idx = text.indexOf(`\n${FRONTMATTER_FENCE}\n`);
|
||||
if (idx !== -1) {
|
||||
log("6GWRP3QX", `stripped ${idx + 1} chars of preamble before frontmatter`);
|
||||
return text.slice(idx + 1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
type SessionRecord = {
|
||||
sessionId: string;
|
||||
model: string;
|
||||
@@ -62,7 +80,6 @@ async function runBuiltinWithMessages(
|
||||
|
||||
if (loopResult.turnCount === 0) {
|
||||
log("5RWTK9NB", "no turns produced, returning empty output");
|
||||
await removeSession(storageRoot, session.sessionId);
|
||||
return { output: "", detailHash: "", sessionId: session.sessionId };
|
||||
}
|
||||
|
||||
@@ -75,10 +92,7 @@ async function runBuiltinWithMessages(
|
||||
session.startedAtMs,
|
||||
);
|
||||
|
||||
// Clean up session jsonl
|
||||
await removeSession(storageRoot, session.sessionId);
|
||||
|
||||
return { output: loopResult.finalText, detailHash, sessionId: session.sessionId };
|
||||
return { output: stripPreamble(loopResult.finalText), detailHash, sessionId: session.sessionId };
|
||||
}
|
||||
|
||||
async function runBuiltin(ctx: AgentContext): Promise<AgentRunResult> {
|
||||
|
||||
@@ -59,6 +59,18 @@ export function buildBuiltinMessages(ctx: AgentContext): ChatMessage[] {
|
||||
}
|
||||
systemParts.push(rolePrompt);
|
||||
|
||||
systemParts.push(
|
||||
"",
|
||||
"## Workflow",
|
||||
"",
|
||||
"You have tools available (read_file, write_file, run_command). " +
|
||||
"Use them to complete your task — read files, run commands, make changes as needed. " +
|
||||
"When you are done, output your final response with the YAML frontmatter block as specified above. " +
|
||||
"Do NOT output the frontmatter until you have completed all necessary work. " +
|
||||
"CRITICAL: Your final output MUST start with the `---` fence on the very first line — " +
|
||||
"no preamble text, no explanation before it. The parser requires `---` at position 0.",
|
||||
);
|
||||
|
||||
const messages: ChatMessage[] = [{ role: "system", content: systemParts.join("\n") }];
|
||||
|
||||
const roleVisitIndices: number[] = [];
|
||||
|
||||
Reference in New Issue
Block a user