Skip to content

Stream a live pipeline

Show real-time progress as Kredence evaluates an ecosystem — useful for progress UIs, CLI tools, or server-sent event feeds.

Terminal progress display

ts
import { KredenceClient } from 'kredence';

const client = new KredenceClient();

const run = client.run(
  { kind: 'manual', urls: ['https://github.com/owner/repo'] },
  { maxProjects: 5 }
);

const stageStart: Record<string, number> = {};

run.on('ready', ({ serverVersion }) => {
  console.log(`\nConnected to Kredence v${serverVersion}\n`);
});

run.on('pipeline_start', ({ runId, ecosystem }) => {
  console.log(`Run ${runId} — evaluating ${ecosystem} ecosystem`);
});

run.on('stage_start', ({ stage }) => {
  stageStart[stage] = Date.now();
  process.stdout.write(`  [${stage.padEnd(12)}] running…`);
});

run.on('stage_done', ({ stage }) => {
  const elapsed = Date.now() - (stageStart[stage] ?? Date.now());
  process.stdout.write(` ${elapsed}ms\n`);
});

run.on('project_complete', (payload) => {
  const pct = Math.round(payload.confidenceScore * 100);
  const bar = '█'.repeat(Math.round(pct / 10)).padEnd(10, '░');
  console.log(`\n  ✓ ${payload.title}`);
  console.log(`    [${bar}] ${pct}%`);
  console.log(`    ${payload.verifiedClaims.length} verified · ${payload.flaggedClaims.length} flagged`);
});

run.on('pipeline_error', ({ stage, message }) => {
  console.error(`\n  ✗ Error at ${stage}: ${message}`);
});

const summary = await run.completed();
console.log(`\nDone — ${summary.projectsEvaluated} projects in ${summary.durationMs}ms`);

Server-Sent Events (Next.js)

Stream pipeline events to a browser over SSE from a Next.js Route Handler:

ts
// app/api/pipeline/route.ts
import { KredenceClient } from 'kredence';
import type { EcosystemInput } from 'kredence';

const client = new KredenceClient();

export async function POST(req: Request) {
  const input = (await req.json()) as EcosystemInput;

  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      const send = (data: unknown) => {
        controller.enqueue(
          encoder.encode(`data: ${JSON.stringify(data)}\n\n`)
        );
      };

      const run = client.run(input, { maxProjects: 5 });

      run.on('stage_start',       (e) => send({ type: 'stage_start',       ...e }));
      run.on('stage_done',        (e) => send({ type: 'stage_done',        ...e }));
      run.on('project_complete',  (p) => send({ type: 'project_complete', payload: p }));
      run.on('pipeline_error',    (e) => send({ type: 'pipeline_error',   ...e }));

      const summary = await run.completed().catch((err: Error) => {
        send({ type: 'error', message: err.message });
        return null;
      });

      if (summary) send({ type: 'pipeline_done', summary });
      controller.close();
    },
  });

  return new Response(stream, {
    headers: {
      'Content-Type':  'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection':    'keep-alive',
    },
  });
}

Client-side consumption:

ts
const source = new EventSource('/api/pipeline');

source.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type === 'project_complete') {
    console.log(msg.payload.title, msg.payload.confidenceScore);
  }

  if (msg.type === 'pipeline_done') {
    source.close();
  }
};

Async iterable pattern

ts
const run = client.run({ kind: 'octant', epochNumber: 7 });

const projects = [];

for await (const event of run) {
  if (event.type === 'project_complete') {
    projects.push(event.payload);
    console.log(`[${projects.length}] ${event.payload.title}`);
  }

  if (event.type === 'pipeline_done') {
    console.log(`Total: ${event.summary.projectsEvaluated} projects`);
    break;
  }
}

Filtering log events

The log event streams every structured agent log entry. Filter by level or phase for a noise-free view:

ts
run.on('log', ({ entry, agent }) => {
  // Only show warnings and errors
  if (entry.level === 'warn' || entry.level === 'error') {
    console.warn(`[${agent}] ${entry.action}`, entry.details);
  }
});

// Or only show tool calls
run.on('tool_call', ({ agent, tool, input }) => {
  console.log(`[${agent}] → ${tool}`, input);
});

run.on('tool_done', ({ agent, tool, durationMs }) => {
  console.log(`[${agent}] ← ${tool} (${durationMs}ms)`);
});

Released under the MIT License.