feat(HAI-082): display tool call details in AgentLogViewer

- Extend AgentLogEntry type with optional detail field for tool metadata
- Thread tool args through engine executor callbacks to populate detail
- Render tool detail (name, args) in AgentLogViewer component
- Add unit tests for store, executor, and AgentLogViewer changes
This commit is contained in:
Dustin Byrne
2026-03-26 00:59:11 -04:00
parent 93a79a5bfa
commit 2baa119969
10 changed files with 150 additions and 7 deletions

View File

@@ -472,6 +472,30 @@ describe("TaskStore", () => {
expect(events[0].taskId).toBe(task.id);
});
it("appendAgentLog writes detail when provided", async () => {
const task = await createTestTask();
await store.appendAgentLog(task.id, "Bash", "tool", "ls -la");
await store.appendAgentLog(task.id, "Read", "tool", "packages/core/src/types.ts");
await store.appendAgentLog(task.id, "some text", "text");
const logs = await store.getAgentLogs(task.id);
expect(logs).toHaveLength(3);
expect(logs[0].detail).toBe("ls -la");
expect(logs[1].detail).toBe("packages/core/src/types.ts");
expect(logs[2].detail).toBeUndefined();
});
it("appendAgentLog omits detail field when not provided", async () => {
const task = await createTestTask();
await store.appendAgentLog(task.id, "Bash", "tool");
const logs = await store.getAgentLogs(task.id);
expect(logs).toHaveLength(1);
expect(logs[0]).not.toHaveProperty("detail");
});
it("handles multiple appends correctly (JSONL format)", async () => {
const task = await createTestTask();
for (let i = 0; i < 5; i++) {

View File

@@ -849,13 +849,15 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
* @param taskId - The task ID (e.g. "HAI-001")
* @param text - The text content (delta for "text", tool name for "tool")
* @param type - Whether this is a "text" delta or a "tool" invocation marker
* @param detail - Optional human-readable summary of tool args (e.g. file path, command)
*/
async appendAgentLog(taskId: string, text: string, type: "text" | "tool"): Promise<void> {
async appendAgentLog(taskId: string, text: string, type: "text" | "tool", detail?: string): Promise<void> {
const entry: AgentLogEntry = {
timestamp: new Date().toISOString(),
taskId,
text,
type,
...(detail !== undefined && { detail }),
};
const dir = this.taskDir(taskId);
const logPath = join(dir, "agent.log");

View File

@@ -24,6 +24,8 @@ export interface AgentLogEntry {
text: string;
/** Whether this is a text delta or a tool invocation marker */
type: "text" | "tool";
/** For tool entries: human-readable summary of tool args (e.g. file path, command) */
detail?: string;
}
export interface TaskAttachment {