provider-events: raw provider stream recorder (LH_PROVIDER_EVENTS=1)
pi-ai 1.0's onProviderStreamEvent, at the layer our incident class lives (GLM arg truncation, DeepSeek id resets) — env-gated (owner choice: no app surface, off by default; raw events carry full prompts), one JSONL per chat under data/debug/provider-events/ with a 20MB cap and a run-start marker for record correlation. Wired at every agent construction: teacher/prober turns (AgentBuildOptions. chatId), jobs via LoopContext (researcher, demo-builder through runSubagent; visual-maker + pdf-reader through their streamOnce), and the extraction pipeline (extractor + auditor keyed by source id). practice deliberately unwired (sunk-cost module).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Agent, type AgentEvent, type AgentMessage, type AgentTool } from "@earendil-works/pi-agent-core";
|
||||
import type { AssistantMessage, ToolResultMessage, Usage } from "@earendil-works/pi-ai";
|
||||
import { piEngineFor, type PiEngine } from "../models.ts";
|
||||
import { providerEventObserver } from "../provider-events.ts";
|
||||
import type { ModelRole } from "../../../config.ts";
|
||||
|
||||
/**
|
||||
@@ -37,6 +38,10 @@ export interface SubagentRunOptions {
|
||||
onAssistantMessage?: (message: AssistantMessage, step: number) => void;
|
||||
/** Extra stop rule (extractor: stop after a clean submit). */
|
||||
shouldStop?: (message: AssistantMessage, toolResults: ToolResultMessage[]) => boolean;
|
||||
/** Debug: when set AND LH_PROVIDER_EVENTS=1, raw provider stream
|
||||
* events append to data/debug/provider-events/<chatId>.jsonl (context
|
||||
* "job:<role>"). Absent or env-off → no observer. */
|
||||
chatId?: string;
|
||||
}
|
||||
|
||||
export interface SubagentRunResult {
|
||||
@@ -56,6 +61,8 @@ export function subagentEngine(role: ModelRole, override?: PiEngine): PiEngine {
|
||||
export async function runSubagent(tools: AgentTool<any, any>[], opts: SubagentRunOptions): Promise<SubagentRunResult> {
|
||||
const engine = subagentEngine(opts.role, opts.engine);
|
||||
let turns = 0;
|
||||
// Debug recorder (owner, 2026-10-04): raw provider events per job run.
|
||||
const providerEvents = opts.chatId ? providerEventObserver(opts.chatId, `job:${opts.role}`) : undefined;
|
||||
const agent = new Agent({
|
||||
initialState: {
|
||||
systemPrompt: opts.systemPrompt,
|
||||
@@ -65,6 +72,7 @@ export async function runSubagent(tools: AgentTool<any, any>[], opts: SubagentRu
|
||||
messages: opts.messages ?? [],
|
||||
},
|
||||
streamFn: engine.streamFn,
|
||||
...(providerEvents ? { onProviderStreamEvent: providerEvents } : {}),
|
||||
// 0.87.1: shouldStopAfterTurn → finishTurn (same call point; "end"
|
||||
// exits before the steering poll, exactly the old boolean-true).
|
||||
finishTurn: (turn) => {
|
||||
|
||||
Reference in New Issue
Block a user