From 330db43b5fc505c14b4d33d4c1dcd9dc0c9c667a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Sat, 23 May 2026 18:27:28 +0800 Subject: [PATCH 1/3] feat(builtin-agent): persist ReAct loop turns as session JSONL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each turn (assistant response / tool result) is appended to a JSONL file at ~/.uncaged/workflow/sessions/.jsonl during the loop. On completion, the JSONL is read back, each turn is stored as a CAS node, and the detail payload references them as a flat turns[] array in chronological order. The session file is then deleted. Benefits: - Real-time observability: tail -f the JSONL to watch loop progress - Crash recovery: partial JSONL survives process death - Zero write contention: one file per session - Detail stays a flat array for easy consumption by CLI/dashboard Changes: - New session.ts: initSessionDir, appendSessionTurn, readSessionTurns, removeSession - loop.ts: append JSONL each turn instead of accumulating in-memory - detail.ts: reads session JSONL → persists turns to CAS → stores detail - agent.ts: passes storageRoot/sessionId to loop, cleans up session on completion - types.ts: remove index from TurnPayload (order is implicit in JSONL/array) - schemas.ts: sync with type changes Ref: #433 --- packages/workflow-agent-builtin/src/agent.ts | 44 ++++++--- packages/workflow-agent-builtin/src/detail.ts | 90 +++---------------- packages/workflow-agent-builtin/src/index.ts | 6 +- packages/workflow-agent-builtin/src/loop.ts | 90 ++++++++++++------- .../workflow-agent-builtin/src/schemas.ts | 3 +- .../workflow-agent-builtin/src/session.ts | 59 ++++++++++++ packages/workflow-agent-builtin/src/types.ts | 1 - 7 files changed, 166 insertions(+), 127 deletions(-) create mode 100644 packages/workflow-agent-builtin/src/session.ts diff --git a/packages/workflow-agent-builtin/src/agent.ts b/packages/workflow-agent-builtin/src/agent.ts index 118fee7..cf43948 100644 --- a/packages/workflow-agent-builtin/src/agent.ts +++ b/packages/workflow-agent-builtin/src/agent.ts @@ -7,17 +7,26 @@ import { resolveModel, resolveStorageRoot, } from "@uncaged/workflow-agent-kit"; -import { generateUlid } from "@uncaged/workflow-util"; +import { createLogger, generateUlid } from "@uncaged/workflow-util"; 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 type { BuiltinSessionState } from "./types.js"; +import { initSessionDir, removeSession } from "./session.js"; -const sessions = new Map(); +const log = createLogger({ sink: { kind: "stderr" } }); -function getSession(sessionId: string): BuiltinSessionState { +type SessionRecord = { + sessionId: string; + model: string; + startedAtMs: number; + messages: ChatMessage[]; +}; + +const sessions = new Map(); + +function getSession(sessionId: string): SessionRecord { const session = sessions.get(sessionId); if (session === undefined) { throw new Error(`builtin session not found: ${sessionId}`); @@ -36,7 +45,7 @@ async function runBuiltinWithMessages( storageRoot: string, provider: ReturnType, messages: ChatMessage[], - session: BuiltinSessionState, + session: SessionRecord, store: Store, maxTurns: number, ): Promise { @@ -45,22 +54,31 @@ async function runBuiltinWithMessages( messages, toolCtx: buildToolContext(storageRoot), maxTurns, - existingTurns: session.turns, + storageRoot, + sessionId: session.sessionId, }); session.messages = loopResult.messages; - session.turns = loopResult.turns; - const { detailHash, output } = await storeBuiltinDetail( + if (loopResult.turnCount === 0) { + log("5RWTK9NB", "no turns produced, returning empty output"); + await removeSession(storageRoot, session.sessionId); + return { output: "", detailHash: "", sessionId: session.sessionId }; + } + + // Read jsonl → persist turns to CAS → store detail + const { detailHash } = await storeBuiltinDetail( store, + storageRoot, session.sessionId, session.model, session.startedAtMs, - session.turns, ); - const finalOutput = output !== "" ? output : loopResult.finalText; - return { output: finalOutput, detailHash, sessionId: session.sessionId }; + // Clean up session jsonl + await removeSession(storageRoot, session.sessionId); + + return { output: loopResult.finalText, detailHash, sessionId: session.sessionId }; } async function runBuiltin(ctx: AgentContext): Promise { @@ -69,14 +87,14 @@ async function runBuiltin(ctx: AgentContext): Promise { const provider = resolveModel(config, config.defaultModel); const sessionId = generateUlid(Date.now()); + await initSessionDir(storageRoot); const messages = buildBuiltinMessages(ctx); - const session: BuiltinSessionState = { + const session: SessionRecord = { sessionId, model: provider.model, startedAtMs: Date.now(), messages, - turns: [], }; sessions.set(sessionId, session); diff --git a/packages/workflow-agent-builtin/src/detail.ts b/packages/workflow-agent-builtin/src/detail.ts index ab49fbf..828fdcb 100644 --- a/packages/workflow-agent-builtin/src/detail.ts +++ b/packages/workflow-agent-builtin/src/detail.ts @@ -1,72 +1,15 @@ import { bootstrap, putSchema, type Store } from "@uncaged/json-cas"; import { BUILTIN_DETAIL_SCHEMA, BUILTIN_TURN_SCHEMA } from "./schemas.js"; -import type { - BuiltinDetailPayload, - BuiltinLoopTurn, - BuiltinToolCall, - BuiltinTurnPayload, - BuiltinTurnRole, -} from "./types.js"; - -function mapToolCalls(calls: NonNullable): BuiltinToolCall[] { - return calls.map((call) => ({ - name: call.name, - args: call.args, - })); -} - -function loopTurnToAssistantPayload(turn: BuiltinLoopTurn, index: number): BuiltinTurnPayload { - return { - index, - role: "assistant", - content: turn.assistantContent ?? "", - toolCalls: - turn.toolCalls !== null && turn.toolCalls.length > 0 ? mapToolCalls(turn.toolCalls) : null, - reasoning: null, - }; -} - -function loopTurnToToolPayloads(turn: BuiltinLoopTurn, startIndex: number): BuiltinTurnPayload[] { - if (turn.toolResults === null || turn.toolResults.length === 0) { - return []; - } - const payloads: BuiltinTurnPayload[] = []; - let index = startIndex; - for (const result of turn.toolResults) { - payloads.push({ - index, - role: "tool" as BuiltinTurnRole, - content: result.content, - toolCalls: null, - reasoning: null, - }); - index += 1; - } - return payloads; -} - -/** Last assistant message with non-empty text. */ -export function extractFinalAssistantText(turns: BuiltinLoopTurn[]): string { - for (let i = turns.length - 1; i >= 0; i--) { - const turn = turns[i]; - if (turn === undefined) { - continue; - } - const text = turn.assistantContent; - if (text !== null && text.trim() !== "") { - return text; - } - } - return ""; -} +import { readSessionTurns } from "./session.js"; +import type { BuiltinDetailPayload } from "./types.js"; type BuiltinSchemaHashes = { turn: string; detail: string; }; -async function registerBuiltinSchemas(store: Store): Promise { +export async function registerBuiltinSchemas(store: Store): Promise { await bootstrap(store); const [turn, detail] = await Promise.all([ putSchema(store, BUILTIN_TURN_SCHEMA), @@ -75,30 +18,22 @@ async function registerBuiltinSchemas(store: Store): Promise { +): Promise<{ detailHash: string; turnCount: number }> { const schemas = await registerBuiltinSchemas(store); + const turns = await readSessionTurns(storageRoot, sessionId); + const turnHashes: string[] = []; - let turnIndex = 0; - - for (const loopTurn of turns) { - const assistant = loopTurnToAssistantPayload(loopTurn, turnIndex); - const assistantHash = await store.put(schemas.turn, assistant); - turnHashes.push(assistantHash); - turnIndex += 1; - - const toolPayloads = loopTurnToToolPayloads(loopTurn, turnIndex); - for (const toolPayload of toolPayloads) { - const toolHash = await store.put(schemas.turn, toolPayload); - turnHashes.push(toolHash); - turnIndex += 1; - } + for (const turn of turns) { + const hash = await store.put(schemas.turn, turn); + turnHashes.push(hash); } const duration = Math.max(0, nowMs - startedAtMs); @@ -110,6 +45,5 @@ export async function storeBuiltinDetail( turns: turnHashes, }; const detailHash = await store.put(schemas.detail, detail); - const output = extractFinalAssistantText(turns); - return { detailHash, output }; + return { detailHash, turnCount: turnHashes.length }; } diff --git a/packages/workflow-agent-builtin/src/index.ts b/packages/workflow-agent-builtin/src/index.ts index f5ad799..2453c17 100644 --- a/packages/workflow-agent-builtin/src/index.ts +++ b/packages/workflow-agent-builtin/src/index.ts @@ -1,14 +1,16 @@ export { createBuiltinAgent } from "./agent.js"; -export { extractFinalAssistantText, storeBuiltinDetail } from "./detail.js"; +export { registerBuiltinSchemas, storeBuiltinDetail } from "./detail.js"; export type { ChatMessage, LlmAssistantResponse, LlmToolCall } from "./llm/index.js"; export { chatCompletionWithTools } from "./llm/index.js"; export { BUILTIN_CONTINUE_MAX_TURNS, BUILTIN_MAX_TURNS, runBuiltinLoop } from "./loop.js"; export { buildBuiltinMessages } from "./prompt.js"; +export { appendSessionTurn, initSessionDir, readSessionTurns, removeSession } from "./session.js"; export type { BuiltinTool, ToolContext } from "./tools/index.js"; export { executeBuiltinTool, getBuiltinTools } from "./tools/index.js"; export type { BuiltinDetailPayload, BuiltinLoopTurn, - BuiltinSessionState, + BuiltinToolCallRecord, + BuiltinToolResultRecord, BuiltinTurnPayload, } from "./types.js"; diff --git a/packages/workflow-agent-builtin/src/loop.ts b/packages/workflow-agent-builtin/src/loop.ts index 91b92de..d289c1c 100644 --- a/packages/workflow-agent-builtin/src/loop.ts +++ b/packages/workflow-agent-builtin/src/loop.ts @@ -2,13 +2,14 @@ import type { ResolvedLlmProvider } from "@uncaged/workflow-agent-kit"; import { createLogger } from "@uncaged/workflow-util"; import { type ChatMessage, chatCompletionWithTools, type LlmToolCall } from "./llm/index.js"; +import { appendSessionTurn } from "./session.js"; import { builtinToolsToOpenAi, executeBuiltinTool, getBuiltinTools, type ToolContext, } from "./tools/index.js"; -import type { BuiltinLoopTurn, BuiltinToolCallRecord, BuiltinToolResultRecord } from "./types.js"; +import type { BuiltinToolCall, BuiltinTurnPayload } from "./types.js"; const log = createLogger({ sink: { kind: "stderr" } }); @@ -20,31 +21,61 @@ export type RunBuiltinLoopOptions = { messages: ChatMessage[]; toolCtx: ToolContext; maxTurns: number; - existingTurns: BuiltinLoopTurn[]; + storageRoot: string; + sessionId: string; }; export type RunBuiltinLoopResult = { finalText: string; messages: ChatMessage[]; - turns: BuiltinLoopTurn[]; + turnCount: number; }; -function mapToolCalls(calls: LlmToolCall[]): BuiltinToolCallRecord[] { +function mapToolCallsForPayload(calls: LlmToolCall[]): BuiltinToolCall[] { return calls.map((call) => ({ - id: call.id, name: call.name, args: call.arguments, })); } +async function appendTurn( + storageRoot: string, + sessionId: string, + payload: BuiltinTurnPayload, +): Promise { + await appendSessionTurn(storageRoot, sessionId, payload); +} + +async function executeTurnTools( + calls: Array<{ id: string; name: string; arguments: string }>, + toolCtx: ToolContext, + messages: ChatMessage[], + storageRoot: string, + sessionId: string, +): Promise { + let turnCount = 0; + for (const call of calls) { + const result = await executeBuiltinTool(call.name, call.arguments, toolCtx); + messages.push({ role: "tool", tool_call_id: call.id, content: result }); + await appendTurn(storageRoot, sessionId, { + role: "tool", + content: result, + toolCalls: null, + reasoning: null, + }); + turnCount += 1; + } + return turnCount; +} + /** Agent run loop: LLM ↔ tools until no tool_calls or maxTurns. */ export async function runBuiltinLoop( options: RunBuiltinLoopOptions, ): Promise { const messages = [...options.messages]; - const turns = [...options.existingTurns]; const openAiTools = builtinToolsToOpenAi(getBuiltinTools()); let finalText = ""; + let turnCount = 0; for (let turn = 0; turn < options.maxTurns; turn++) { log("8K2M4N7P", `builtin loop turn ${turn + 1}/${options.maxTurns}`); @@ -59,36 +90,33 @@ export async function runBuiltinLoop( if (response.toolCalls === null || response.toolCalls.length === 0) { finalText = response.content ?? ""; - turns.push({ - assistantContent: response.content, + await appendTurn(options.storageRoot, options.sessionId, { + role: "assistant", + content: response.content ?? "", toolCalls: null, - toolResults: null, + reasoning: null, }); + turnCount += 1; break; } - const toolCallRecords = mapToolCalls(response.toolCalls); - const toolResults: BuiltinToolResultRecord[] = []; - - for (const call of response.toolCalls) { - const result = await executeBuiltinTool(call.name, call.arguments, options.toolCtx); - toolResults.push({ - toolCallId: call.id, - name: call.name, - content: result, - }); - messages.push({ - role: "tool", - tool_call_id: call.id, - content: result, - }); - } - - turns.push({ - assistantContent: response.content, - toolCalls: toolCallRecords, - toolResults, + // Assistant turn with tool calls + await appendTurn(options.storageRoot, options.sessionId, { + role: "assistant", + content: response.content ?? "", + toolCalls: mapToolCallsForPayload(response.toolCalls), + reasoning: null, }); + turnCount += 1; + + // Execute tools + turnCount += await executeTurnTools( + response.toolCalls, + options.toolCtx, + messages, + options.storageRoot, + options.sessionId, + ); } if (finalText === "" && messages.length > 0) { @@ -106,5 +134,5 @@ export async function runBuiltinLoop( } } - return { finalText, messages, turns }; + return { finalText, messages, turnCount }; } diff --git a/packages/workflow-agent-builtin/src/schemas.ts b/packages/workflow-agent-builtin/src/schemas.ts index 273d3df..c9e8077 100644 --- a/packages/workflow-agent-builtin/src/schemas.ts +++ b/packages/workflow-agent-builtin/src/schemas.ts @@ -13,9 +13,8 @@ const BUILTIN_TOOL_CALL_SCHEMA: JSONSchema = { export const BUILTIN_TURN_SCHEMA: JSONSchema = { title: "builtin-turn", type: "object", - required: ["index", "role", "content"], + required: ["role", "content"], properties: { - index: { type: "integer" }, role: { type: "string", enum: ["assistant", "tool"] }, content: { type: "string" }, toolCalls: { diff --git a/packages/workflow-agent-builtin/src/session.ts b/packages/workflow-agent-builtin/src/session.ts new file mode 100644 index 0000000..7f9c766 --- /dev/null +++ b/packages/workflow-agent-builtin/src/session.ts @@ -0,0 +1,59 @@ +import { appendFile, mkdir, readFile, rm } from "node:fs/promises"; +import { join } from "node:path"; + +import { createLogger } from "@uncaged/workflow-util"; + +import type { BuiltinTurnPayload } from "./types.js"; + +const log = createLogger({ sink: { kind: "stderr" } }); + +function sessionsDir(storageRoot: string): string { + return join(storageRoot, "sessions"); +} + +function sessionFile(storageRoot: string, sessionId: string): string { + return join(sessionsDir(storageRoot), `${sessionId}.jsonl`); +} + +/** Ensure sessions directory exists. */ +export async function initSessionDir(storageRoot: string): Promise { + await mkdir(sessionsDir(storageRoot), { recursive: true }); +} + +/** Append a turn to the session jsonl file. */ +export async function appendSessionTurn( + storageRoot: string, + sessionId: string, + turn: BuiltinTurnPayload, +): Promise { + const line = `${JSON.stringify(turn)}\n`; + await appendFile(sessionFile(storageRoot, sessionId), line, "utf-8"); + log("3XQVN8KR", `session ${sessionId} appended ${turn.role} turn`); +} + +/** Read all turns from session jsonl. Returns empty array if file does not exist. */ +export async function readSessionTurns( + storageRoot: string, + sessionId: string, +): Promise { + try { + const content = await readFile(sessionFile(storageRoot, sessionId), "utf-8"); + const lines = content + .trim() + .split("\n") + .filter((l) => l.length > 0); + return lines.map((l) => JSON.parse(l) as BuiltinTurnPayload); + } catch { + return []; + } +} + +/** Remove session jsonl file (called after detail is persisted to step CAS). */ +export async function removeSession(storageRoot: string, sessionId: string): Promise { + try { + await rm(sessionFile(storageRoot, sessionId)); + log("7FWDP2MJ", `session ${sessionId} removed`); + } catch { + // already gone — fine + } +} diff --git a/packages/workflow-agent-builtin/src/types.ts b/packages/workflow-agent-builtin/src/types.ts index 679d83c..f077279 100644 --- a/packages/workflow-agent-builtin/src/types.ts +++ b/packages/workflow-agent-builtin/src/types.ts @@ -34,7 +34,6 @@ export type BuiltinToolCall = { }; export type BuiltinTurnPayload = { - index: number; role: BuiltinTurnRole; content: string; toolCalls: BuiltinToolCall[] | null; From 1abc3b4cf4bea037f3c2bd8f7228da6622f850d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Sat, 23 May 2026 18:39:02 +0800 Subject: [PATCH 2/3] chore: fix all biome lint errors across monorepo - Fix import ordering (organizeImports) across multiple packages - Replace forEach with for...of loops (noForEach) - Replace non-null assertions with fallback values (noNonNullAssertion) - Add biome-ignore comments for justified noExplicitAny usages - Remove parameter properties, use explicit class properties (noParameterProperties) - Fix string concatenation to template literals (useTemplate) - Fix format issues (CSS, TypeScript) - Add tailwindDirectives CSS parser config in biome.json - Replace var with const (noVar) Result: 0 errors, 12 warnings (all cognitive complexity, acceptable) --- biome.json | 9 + .../cli-workflow/src/__tests__/log.test.ts | 6 +- .../__tests__/path.test.ts | 2 +- .../src/tools/run-command.ts | 3 +- .../__tests__/session-detail.test.ts | 11 +- .../src/claude-code.ts | 11 +- .../workflow-agent-hermes/src/acp-client.ts | 3 +- packages/workflow-agent-kit/src/index.ts | 2 +- .../workflow-agent-kit/src/session-cache.ts | 2 +- packages/workflow-dashboard/index.html | 4 +- packages/workflow-dashboard/server.ts | 3 - packages/workflow-dashboard/server/api.ts | 6 +- .../workflow-dashboard/server/workflow.ts | 12 +- .../src/components/ui/button.tsx | 14 +- .../src/components/ui/card.tsx | 41 ++--- .../src/components/ui/dialog.tsx | 81 ++++----- .../src/components/ui/input.tsx | 12 +- .../src/components/ui/label.tsx | 11 +- .../src/components/ui/separator.tsx | 18 +- .../src/components/ui/textarea.tsx | 10 +- .../workflow-dashboard/src/editor/context.tsx | 154 +++++++++++------- .../src/editor/edges/conditional.tsx | 64 +++++--- .../src/editor/edges/index.tsx | 2 +- .../workflow-dashboard/src/editor/flow.tsx | 40 ++--- .../src/editor/injection.ts | 29 ++-- .../src/editor/layout/index.ts | 26 +-- .../src/editor/model/add-node-view.ts | 31 ++-- .../src/editor/model/edges.ts | 33 ++-- .../src/editor/model/edit-node-view.ts | 19 ++- .../src/editor/model/handlers.ts | 53 +++--- .../src/editor/model/index.ts | 12 +- .../src/editor/model/inject.ts | 5 +- .../src/editor/model/nodes.ts | 41 ++--- .../src/editor/nodes/end.tsx | 14 +- .../src/editor/nodes/index.tsx | 6 +- .../src/editor/nodes/node-toolbar.tsx | 10 +- .../src/editor/nodes/nodes.style.tsx | 24 +-- .../src/editor/nodes/role.tsx | 111 +++++++++---- .../src/editor/nodes/start.tsx | 10 +- .../src/editor/panel/add-node.tsx | 22 ++- .../src/editor/panel/edit-node.tsx | 23 +-- .../src/editor/panel/index.tsx | 10 +- .../src/editor/panel/toolbar.tsx | 63 +++---- .../src/editor/trans/index.ts | 8 +- .../src/editor/trans/trans-in.ts | 66 ++++---- .../src/editor/trans/trans-out.ts | 25 +-- .../src/editor/trans/type.ts | 2 +- .../src/editor/trans/validate.ts | 64 ++++---- .../workflow-dashboard/src/editor/type.ts | 6 +- .../src/editor/utils/eventer.ts | 12 +- .../src/editor/utils/index.ts | 2 - .../src/editor/utils/use-click-out.tsx | 14 +- packages/workflow-dashboard/src/index.css | 4 +- packages/workflow-dashboard/src/lib/utils.ts | 6 +- .../workflow-dashboard/src/pages/detail.tsx | 34 ++-- .../workflow-dashboard/src/pages/editor.tsx | 2 +- .../workflow-dashboard/src/pages/home.tsx | 10 +- packages/workflow-dashboard/src/router.tsx | 2 +- packages/workflow-dashboard/vite-dev.ts | 2 +- .../__tests__/process-logger.test.ts | 2 +- packages/workflow-util/src/index.ts | 2 +- 61 files changed, 687 insertions(+), 639 deletions(-) diff --git a/biome.json b/biome.json index 357082f..d08b98a 100644 --- a/biome.json +++ b/biome.json @@ -17,6 +17,15 @@ "indentWidth": 2, "lineWidth": 100 }, + "css": { + "parser": { + "cssModules": true, + "tailwindDirectives": true + }, + "linter": { + "enabled": false + } + }, "javascript": { "formatter": { "quoteStyle": "double", diff --git a/packages/cli-workflow/src/__tests__/log.test.ts b/packages/cli-workflow/src/__tests__/log.test.ts index 75c839c..48dbbe5 100644 --- a/packages/cli-workflow/src/__tests__/log.test.ts +++ b/packages/cli-workflow/src/__tests__/log.test.ts @@ -62,9 +62,9 @@ const olderEntry = JSON.stringify({ async function writeLogFiles(): Promise { const logsDir = join(storageRoot, "logs"); - await writeFile(join(logsDir, "2026-05-20.jsonl"), [entry1, entry2, entry3].join("\n") + "\n"); - await writeFile(join(logsDir, "2026-05-19.jsonl"), oldEntry + "\n"); - await writeFile(join(logsDir, "2026-05-18.jsonl"), olderEntry + "\n"); + await writeFile(join(logsDir, "2026-05-20.jsonl"), `${[entry1, entry2, entry3].join("\n")}\n`); + await writeFile(join(logsDir, "2026-05-19.jsonl"), `${oldEntry}\n`); + await writeFile(join(logsDir, "2026-05-18.jsonl"), `${olderEntry}\n`); } describe("cmdLogList", () => { diff --git a/packages/workflow-agent-builtin/__tests__/path.test.ts b/packages/workflow-agent-builtin/__tests__/path.test.ts index 063475c..47ff143 100644 --- a/packages/workflow-agent-builtin/__tests__/path.test.ts +++ b/packages/workflow-agent-builtin/__tests__/path.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test"; -import { resolvePath } from "../src/tools/path.js"; import { resolve } from "node:path"; +import { resolvePath } from "../src/tools/path.js"; describe("resolvePath", () => { test("resolves relative paths against cwd", () => { diff --git a/packages/workflow-agent-builtin/src/tools/run-command.ts b/packages/workflow-agent-builtin/src/tools/run-command.ts index 2f34843..4cd041f 100644 --- a/packages/workflow-agent-builtin/src/tools/run-command.ts +++ b/packages/workflow-agent-builtin/src/tools/run-command.ts @@ -56,8 +56,7 @@ function runShell( export const runCommandTool: BuiltinTool = { name: "run_command", - description: - "Run a shell command. Output is truncated to 32KB.", + description: "Run a shell command. Output is truncated to 32KB.", parameters: { type: "object", required: ["command"], diff --git a/packages/workflow-agent-claude-code/__tests__/session-detail.test.ts b/packages/workflow-agent-claude-code/__tests__/session-detail.test.ts index 74af338..db67558 100644 --- a/packages/workflow-agent-claude-code/__tests__/session-detail.test.ts +++ b/packages/workflow-agent-claude-code/__tests__/session-detail.test.ts @@ -73,9 +73,7 @@ describe("parseClaudeCodeStreamOutput", () => { type: "user", message: { role: "user", - content: [ - { type: "tool_result", tool_use_id: "tool_1", content: "file1.ts\nfile2.ts" }, - ], + content: [{ type: "tool_result", tool_use_id: "tool_1", content: "file1.ts\nfile2.ts" }], }, session_id: "sess-123", }), @@ -167,7 +165,12 @@ describe("storeClaudeCodeDetail", () => { durationMs: 15000, model: "claude-sonnet-4.5", stopReason: "end_turn", - usage: { inputTokens: 100, outputTokens: 50, cacheReadInputTokens: 0, cacheCreationInputTokens: 0 }, + usage: { + inputTokens: 100, + outputTokens: 50, + cacheReadInputTokens: 0, + cacheCreationInputTokens: 0, + }, turns: [ { index: 0, role: "assistant", content: "hello", toolCalls: null }, { index: 1, role: "tool_result", content: "world", toolCalls: null }, diff --git a/packages/workflow-agent-claude-code/src/claude-code.ts b/packages/workflow-agent-claude-code/src/claude-code.ts index 8a34a60..c858bee 100644 --- a/packages/workflow-agent-claude-code/src/claude-code.ts +++ b/packages/workflow-agent-claude-code/src/claude-code.ts @@ -1,8 +1,5 @@ import { spawn } from "node:child_process"; import type { Store } from "@uncaged/json-cas"; - -import { createLogger } from "@uncaged/workflow-util"; - import { type AgentContext, type AgentRunResult, @@ -11,6 +8,7 @@ import { getCachedSessionId, setCachedSessionId, } from "@uncaged/workflow-agent-kit"; +import { createLogger } from "@uncaged/workflow-util"; import { parseClaudeCodeStreamOutput, storeClaudeCodeDetail } from "./session-detail.js"; @@ -146,7 +144,12 @@ async function runClaudeCode(ctx: AgentContext): Promise { } return result; } catch (err) { - log("5VKR8N3Q", "resume failed for session %s, falling back to fresh run: %s", cachedSessionId, err); + log( + "5VKR8N3Q", + "resume failed for session %s, falling back to fresh run: %s", + cachedSessionId, + err, + ); } } } diff --git a/packages/workflow-agent-hermes/src/acp-client.ts b/packages/workflow-agent-hermes/src/acp-client.ts index 400c7c6..beb6213 100644 --- a/packages/workflow-agent-hermes/src/acp-client.ts +++ b/packages/workflow-agent-hermes/src/acp-client.ts @@ -267,8 +267,7 @@ export class HermesAcpClient { case "tool_call": { const title = (update.title as string) ?? ""; const rawInput = update.rawInput; - const args = - rawInput !== undefined && rawInput !== null ? JSON.stringify(rawInput) : ""; + const args = rawInput !== undefined && rawInput !== null ? JSON.stringify(rawInput) : ""; const toolCallId = update.toolCallId as string; this.pendingTools.set(toolCallId, { name: title, args }); diff --git a/packages/workflow-agent-kit/src/index.ts b/packages/workflow-agent-kit/src/index.ts index 6d18e65..ffeaaa6 100644 --- a/packages/workflow-agent-kit/src/index.ts +++ b/packages/workflow-agent-kit/src/index.ts @@ -12,8 +12,8 @@ export { export type { FrontmatterFastPathResult } from "./frontmatter.js"; export { tryFrontmatterFastPath } from "./frontmatter.js"; export { createAgent } from "./run.js"; -export { getConfigPath, getEnvPath, loadWorkflowConfig, resolveStorageRoot } from "./storage.js"; export { getCachedSessionId, setCachedSessionId } from "./session-cache.js"; +export { getConfigPath, getEnvPath, loadWorkflowConfig, resolveStorageRoot } from "./storage.js"; export type { AgentContext, AgentContinueFn, diff --git a/packages/workflow-agent-kit/src/session-cache.ts b/packages/workflow-agent-kit/src/session-cache.ts index 238afc9..fd94de5 100644 --- a/packages/workflow-agent-kit/src/session-cache.ts +++ b/packages/workflow-agent-kit/src/session-cache.ts @@ -1,5 +1,5 @@ -import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; import { randomBytes } from "node:crypto"; +import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; import { dirname, join } from "node:path"; import type { ThreadId } from "@uncaged/workflow-protocol"; diff --git a/packages/workflow-dashboard/index.html b/packages/workflow-dashboard/index.html index 0948c36..e566099 100644 --- a/packages/workflow-dashboard/index.html +++ b/packages/workflow-dashboard/index.html @@ -6,8 +6,8 @@ Workflow UI