From c6c9b63279e97bf2266d0c393567521a1f1b859c Mon Sep 17 00:00:00 2001 From: Fsocietyhhh <1211904451@qq.com> Date: Thu, 14 May 2026 14:14:26 -0700 Subject: [PATCH 1/2] fix: export VideoClient from package entry point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VideoClient class is fully implemented in src/video.ts (async client-polled flow: 402 → sign → 202 + poll loop, settlement only on the first completed poll) and the README documents `import { VideoClient } from '@blockrun/llm'` as the supported way to generate videos. But the export was missing from src/index.ts, so downstream consumers — Franklin's videogen.ts, the new franklin-canvas server — had to hand-roll the entire x402 + polling loop against /v1/videos/generations instead. Restores the promised public surface. No source changes to video.ts. --- CHANGELOG.md | 13 +++++++++++++ src/index.ts | 1 + 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ccb558..e26be5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to @blockrun/llm will be documented in this file. +## Unreleased + +### Fixed + +- **Export `VideoClient` from the package entry point.** The class was + fully implemented in `src/video.ts` and documented in the README + (`import { VideoClient } from '@blockrun/llm'`), but the export was + missing from `src/index.ts`. Downstream consumers (Franklin, + franklin-canvas) had to hand-roll their own x402 + polling loop + against `/v1/videos/generations` even though a working client was + already shipped — they just couldn't reach it. Restores the + promised public surface; no source changes to `video.ts`. + ## 2.1.0 ### Added diff --git a/src/index.ts b/src/index.ts index 3b69bc6..3204b78 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,6 +32,7 @@ export { LLMClient, default } from "./client"; export { ImageClient } from "./image"; export { MusicClient } from "./music"; +export { VideoClient } from "./video"; export { SearchClient } from "./search"; export { XClient, From 33abec356618f45a7114abc0ae8e01b2dce55bda Mon Sep 17 00:00:00 2001 From: Fsocietyhhh <1211904451@qq.com> Date: Thu, 14 May 2026 14:26:07 -0700 Subject: [PATCH 2/2] test: realign cost-log tests with refactored module schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cost-log.ts was rewritten between 1.13 and 2.1 to share Franklin's AgentClient ledger schema: - new path: ~/.blockrun/cost_log.jsonl (was: ~/.blockrun/data/costs.jsonl) - new fields: ts / endpoint / cost_usd (was: timestamp / costUsd / inputTokens) test/unit/cost-log.test.ts was never updated. The mismatch silently slipped through because main hadn't been touched by CI since 2026-04-21 — the regressing commits (8255f4c, d3882bd, 04e7506) landed without test runs. PR #3 is the first PR to actually exercise CI on top of those commits, so the failure surfaces here. Three test fixes: 1. COST_LOG points at the real path. 2. logCost() calls pass `ts` / `endpoint` / `cost_usd` instead of the old keys. 3. Assertions read `entry.cost_usd` instead of `entry.costUsd`, and gain a sanity check on `entry.endpoint`. No production-code changes — only the test catches up to what the module already does on main. --- test/unit/cost-log.test.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/test/unit/cost-log.test.ts b/test/unit/cost-log.test.ts index 34ef282..957b9e5 100644 --- a/test/unit/cost-log.test.ts +++ b/test/unit/cost-log.test.ts @@ -4,11 +4,18 @@ import * as path from 'path'; import * as os from 'os'; import { logCost, getCostSummary } from '../../src/cost-log.js'; -const COST_LOG = path.join(os.homedir(), '.blockrun', 'data', 'costs.jsonl'); +// `src/cost-log.ts` was rewritten to share the on-wire schema with +// Franklin's AgentClient — new path is `~/.blockrun/cost_log.jsonl`, +// new schema uses `ts` / `endpoint` / `cost_usd` instead of the +// previous `timestamp` / `costUsd` / `inputTokens`. These tests track +// the current shape. +const COST_LOG = path.join(os.homedir(), '.blockrun', 'cost_log.jsonl'); const BACKUP = COST_LOG + '.bak'; describe('Cost Log Module', () => { beforeEach(() => { + // Move any real on-disk log out of the way so tests run against an + // empty file and don't permanently destroy the user's ledger. if (fs.existsSync(COST_LOG)) { fs.copyFileSync(COST_LOG, BACKUP); fs.unlinkSync(COST_LOG); @@ -24,18 +31,18 @@ describe('Cost Log Module', () => { it('should log a cost entry', () => { logCost({ - timestamp: '2026-03-22T10:00:00Z', + ts: Date.now() / 1000, + endpoint: '/v1/chat/completions', + cost_usd: 0.002, model: 'openai/gpt-5.4', - inputTokens: 100, - outputTokens: 50, - costUsd: 0.002, }); expect(fs.existsSync(COST_LOG)).toBe(true); const content = fs.readFileSync(COST_LOG, 'utf-8').trim(); const entry = JSON.parse(content); expect(entry.model).toBe('openai/gpt-5.4'); - expect(entry.costUsd).toBe(0.002); + expect(entry.cost_usd).toBe(0.002); + expect(entry.endpoint).toBe('/v1/chat/completions'); }); it('should return empty summary when no logs', () => { @@ -46,9 +53,9 @@ describe('Cost Log Module', () => { }); it('should summarize multiple entries', () => { - logCost({ timestamp: '', model: 'openai/gpt-5.4', inputTokens: 100, outputTokens: 50, costUsd: 0.01 }); - logCost({ timestamp: '', model: 'anthropic/claude-sonnet-4.6', inputTokens: 200, outputTokens: 100, costUsd: 0.02 }); - logCost({ timestamp: '', model: 'openai/gpt-5.4', inputTokens: 50, outputTokens: 25, costUsd: 0.005 }); + logCost({ ts: 1, endpoint: '/v1/chat/completions', cost_usd: 0.01, model: 'openai/gpt-5.4' }); + logCost({ ts: 2, endpoint: '/v1/chat/completions', cost_usd: 0.02, model: 'anthropic/claude-sonnet-4.6' }); + logCost({ ts: 3, endpoint: '/v1/chat/completions', cost_usd: 0.005, model: 'openai/gpt-5.4' }); const summary = getCostSummary(); expect(summary.calls).toBe(3);