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:
@@ -106,6 +106,9 @@ interface LoopContext {
|
||||
/** Fires when abortJob kills the run; abortSignal is passed into every
|
||||
* model call so the spend stops mid-call, not at the next loop check. */
|
||||
abortSignal: AbortSignal;
|
||||
/** The job's chat (debug: raw provider-event recording under
|
||||
* LH_PROVIDER_EVENTS=1 — forwarded into every subagent run). */
|
||||
chatId?: string;
|
||||
/** Fold one model call's usage into the job record (progress write). */
|
||||
onUsage: (step: UsageStepLike) => void;
|
||||
}
|
||||
@@ -127,6 +130,7 @@ export function createJobRunner(deps: JobRunnerDeps): JobRunner {
|
||||
const usageTotals = new Map<string, JobUsage>();
|
||||
|
||||
function makeLoopContext(jobId: string, engine: PiEngine): LoopContext {
|
||||
const chatId = jobStore.getJob(jobId)?.chatId;
|
||||
// Provider-qualified stamp: the engine's actual model — the only
|
||||
// thing that ran (BYOK: no config-pin fallback stamps exist).
|
||||
const model = `${engine.model.provider}:${engine.model.id}`;
|
||||
@@ -137,6 +141,7 @@ export function createJobRunner(deps: JobRunnerDeps): JobRunner {
|
||||
registerJobAbort(jobId, controller);
|
||||
return {
|
||||
abortSignal: controller.signal,
|
||||
chatId,
|
||||
onUsage: (step) => {
|
||||
const next = accumulateJobUsage(usageTotals.get(jobId), model, step);
|
||||
usageTotals.set(jobId, next);
|
||||
@@ -355,6 +360,7 @@ export function createJobRunner(deps: JobRunnerDeps): JobRunner {
|
||||
engine: model,
|
||||
search: deps.searchProvider,
|
||||
abortSignal: loop.abortSignal,
|
||||
chatId: loop.chatId,
|
||||
// Money channel: each agent step is one model call — fold its
|
||||
// usage into the record as it completes (progress write).
|
||||
onUsage: (usage) => loop.onUsage(piUsageToStep(usage)),
|
||||
@@ -403,6 +409,7 @@ export function createJobRunner(deps: JobRunnerDeps): JobRunner {
|
||||
{
|
||||
engine: model,
|
||||
abortSignal: loop.abortSignal,
|
||||
chatId: loop.chatId,
|
||||
onUsage: (usage) => loop.onUsage(piUsageToStep(usage)),
|
||||
onActivity: (line) => jobStore.updateJob(jobId, { activity: line }),
|
||||
},
|
||||
@@ -438,6 +445,7 @@ export function createJobRunner(deps: JobRunnerDeps): JobRunner {
|
||||
{
|
||||
engine: model,
|
||||
abortSignal: loop.abortSignal,
|
||||
chatId: loop.chatId,
|
||||
onUsage: (usage) => loop.onUsage(piUsageToStep(usage)),
|
||||
onActivity: (line) => jobStore.updateJob(jobId, { activity: line }),
|
||||
},
|
||||
@@ -476,6 +484,7 @@ export function createJobRunner(deps: JobRunnerDeps): JobRunner {
|
||||
{
|
||||
engine: model,
|
||||
abortSignal: loop.abortSignal,
|
||||
chatId: loop.chatId,
|
||||
onUsage: (usage) => loop.onUsage(piUsageToStep(usage)),
|
||||
onActivity: (line) => jobStore.updateJob(jobId, { activity: line }),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user