diff --git a/apps/cli/src/application/entities/run-events.ts b/apps/cli/src/application/entities/run-events.ts index 47f27ce9..670b93e3 100644 --- a/apps/cli/src/application/entities/run-events.ts +++ b/apps/cli/src/application/entities/run-events.ts @@ -10,8 +10,7 @@ const BaseRunEvent = z.object({ export const RunStartEvent = BaseRunEvent.extend({ type: z.literal("start"), runId: z.string(), - agentId: z.string(), - agent: Agent, + agent: z.string(), interactive: z.boolean(), }); diff --git a/apps/cli/src/application/lib/agent.ts b/apps/cli/src/application/lib/agent.ts index 4881e2b4..1a612370 100644 --- a/apps/cli/src/application/lib/agent.ts +++ b/apps/cli/src/application/lib/agent.ts @@ -223,16 +223,17 @@ export async function* streamAgent(opts: { runId?: string; input?: string; interactive?: boolean; -}) { +}): AsyncGenerator, void, unknown> { const messages: z.infer = []; // load existing and assemble state if required - if (opts.runId) { - console.error("loading run", opts.runId); + let runId = opts.runId; + if (runId) { + console.error("loading run", runId); let stream: fs.ReadStream | null = null; let rl: Interface | null = null; try { - const logFile = path.join(WorkDir, "runs", `${opts.runId}.jsonl`); + const logFile = path.join(WorkDir, "runs", `${runId}.jsonl`); stream = fs.createReadStream(logFile, { encoding: "utf8" }); rl = createInterface({ input: stream, crlfDelay: Infinity }); for await (const line of rl) { @@ -253,8 +254,8 @@ export async function* streamAgent(opts: { } // create runId if not present - if (!opts.runId) { - opts.runId = runIdGenerator.next(); + if (!runId) { + runId = runIdGenerator.next(); } // load agent data @@ -280,11 +281,21 @@ export async function* streamAgent(opts: { } // set up - const logger = new RunLogger(opts.runId); + const logger = new RunLogger(runId); const ly = new LogAndYield(logger); const provider = getProvider(agent.provider); const model = provider(agent.model || ModelConfig.defaults.model); + // emit start event if first time run + if (!opts.runId) { + yield* ly.logAndYield({ + type: "start", + runId, + agent: opts.agent, + interactive: opts.interactive ?? false, + }); + } + // get first input if needed let rl: Interface | null = null; if (opts.interactive) { diff --git a/apps/cli/src/application/lib/stream-renderer.ts b/apps/cli/src/application/lib/stream-renderer.ts index 7ac3279d..cfd7ab1a 100644 --- a/apps/cli/src/application/lib/stream-renderer.ts +++ b/apps/cli/src/application/lib/stream-renderer.ts @@ -27,7 +27,7 @@ export class StreamRenderer { render(event: z.infer) { switch (event.type) { case "start": { - this.onStart(event.agentId, event.runId, event.interactive); + this.onStart(event.agent, event.runId, event.interactive); break; } case "step-start": { @@ -94,19 +94,19 @@ export class StreamRenderer { } } - private onStart(workflowId: string, runId: string, interactive: boolean) { + private onStart(agent: string, runId: string, interactive: boolean) { this.write("\n"); - this.write(this.bold(`▶ Workflow ${workflowId} (run ${runId})`)); + this.write(this.bold(`▶ Agent ${agent} (run ${runId})`)); if (!interactive) this.write(this.dim(" (--no-interactive)")); this.write("\n"); } private onEnd() { - this.write(this.bold("\n■ Workflow complete\n")); + this.write(this.bold("\n■ complete\n")); } private onError(error: string) { - this.write(this.red(`\n✖ Workflow error: ${error}\n`)); + this.write(this.red(`\n✖ error: ${error}\n`)); } private onStepStart() {