pdfjs-reader-core 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/dist/index.cjs +114 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -20
- package/dist/index.d.ts +47 -20
- package/dist/index.js +114 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1278,6 +1278,7 @@ default. Clicking it clears every overlay and returns the camera to fit-page.
|
|
|
1278
1278
|
| `backgroundColor` | `string` | `'#ffffff'` | Surround colour visible around the PDF when the viewport is larger than the page fit. v0.4.1+ |
|
|
1279
1279
|
| `loadingComponent` | `ReactNode` | default spinner | Custom loading state shown while the PDF document/page is still fetching. v0.4.1+ |
|
|
1280
1280
|
| `onPageChange` | `(page: number) => void` | — | Called when the viewer's page changes from any source (agent API, sidebar, programmatic). Pair with the `pageNumber` prop for bidirectional sync. **Required** when agents call `goToPage`/`nextPage`/`previousPage`. v0.4.2+ |
|
|
1281
|
+
| `storyboardProvider` | `(input) => Promise<Storyboard \| null>` | — | Consumer-owned director — when provided, called per chunk INSTEAD of the built-in LLM director. Your backend owns the system prompt + bbox context and returns the storyboard JSON. v0.5.0+ |
|
|
1281
1282
|
| `className` | `string` | — | Passes through to the root container for custom theming |
|
|
1282
1283
|
|
|
1283
1284
|
### LlmConfig
|
|
@@ -1299,6 +1300,56 @@ interface LlmConfig {
|
|
|
1299
1300
|
multiple consumers and each owns its own inference endpoint. Pass the URL as
|
|
1300
1301
|
a prop at the call site, sourced from an env var or runtime config.
|
|
1301
1302
|
|
|
1303
|
+
### Alternative: `storyboardProvider` (v0.5.0+)
|
|
1304
|
+
|
|
1305
|
+
When your backend owns the system prompt and bbox context, use
|
|
1306
|
+
`storyboardProvider` instead of `llm`. The library will call your provider per
|
|
1307
|
+
chunk, validate its return value against `StoryboardSchema`, and execute the
|
|
1308
|
+
result.
|
|
1309
|
+
|
|
1310
|
+
```tsx
|
|
1311
|
+
<TutorModeContainer
|
|
1312
|
+
pageNumber={currentPage}
|
|
1313
|
+
bboxData={bboxData}
|
|
1314
|
+
narrationStore={storeRef.current}
|
|
1315
|
+
currentChunk={currentChunk}
|
|
1316
|
+
storyboardProvider={async ({ chunk, pageNumber, signal }) => {
|
|
1317
|
+
// Your director endpoint already has bbox server-side. Send just
|
|
1318
|
+
// the chunk + page number and get the storyboard back.
|
|
1319
|
+
const res = await fetch('/director', {
|
|
1320
|
+
method: 'POST',
|
|
1321
|
+
body: JSON.stringify({ chunk, pageNumber }),
|
|
1322
|
+
signal,
|
|
1323
|
+
});
|
|
1324
|
+
if (!res.ok) return null; // library skips this chunk gracefully
|
|
1325
|
+
return res.json(); // must match StoryboardSchema
|
|
1326
|
+
}}
|
|
1327
|
+
/>
|
|
1328
|
+
```
|
|
1329
|
+
|
|
1330
|
+
**Why use this instead of `llm`?**
|
|
1331
|
+
- You iterate on the system prompt without a library upgrade.
|
|
1332
|
+
- You choose the model (fine-tuned, OSS, hosted, local) without vendor lock.
|
|
1333
|
+
- You cache bbox server-side; the browser sends only the chunk + page number.
|
|
1334
|
+
- Works great with KV-cache / prefix caching on the director model.
|
|
1335
|
+
|
|
1336
|
+
**What the library still handles regardless of path:**
|
|
1337
|
+
- `StoryboardSchema` validation of the returned JSON
|
|
1338
|
+
- Range clamping of out-of-bounds numeric fields
|
|
1339
|
+
- `enforceOverlayPresence` auto-pulse if the storyboard is camera-only
|
|
1340
|
+
- Engine scheduling (per-step `setTimeout` at `at_ms`)
|
|
1341
|
+
- All overlay rendering (spotlight / underline / highlight / pulse / callout /
|
|
1342
|
+
ghost reference / box / label), plus viewport-space overlays and camera math
|
|
1343
|
+
- Debug events (`llm-request` / `llm-response` / `storyboard-execute`) so the
|
|
1344
|
+
DebugLog telemetry works identically to the built-in path
|
|
1345
|
+
|
|
1346
|
+
**Priority:** if both `storyboardProvider` and `llm` are set, the provider
|
|
1347
|
+
wins and `llm` is ignored.
|
|
1348
|
+
|
|
1349
|
+
**Return `null` to skip:** the provider may decide a given chunk shouldn't
|
|
1350
|
+
trigger visuals (e.g. filler words, acknowledgements). Returning `null`
|
|
1351
|
+
emits a `note` debug event and no storyboard fires.
|
|
1352
|
+
|
|
1302
1353
|
### The integration contract in one picture
|
|
1303
1354
|
|
|
1304
1355
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -13181,8 +13181,6 @@ var PAPER = "#faf6ec";
|
|
|
13181
13181
|
var ACCENT = "#b04a1a";
|
|
13182
13182
|
var ACCENT_SOFT = "rgba(176, 74, 26, 0.18)";
|
|
13183
13183
|
var ACCENT_GLOW = "rgba(176, 74, 26, 0.35)";
|
|
13184
|
-
var MARKER = "#e6b422";
|
|
13185
|
-
var MARKER_SOFT = "rgba(230, 180, 34, 0.38)";
|
|
13186
13184
|
var SERIF = "'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', 'EB Garamond', 'Hoefler Text', Georgia, serif";
|
|
13187
13185
|
var EASE_OUT_EXPO = [0.22, 1, 0.36, 1];
|
|
13188
13186
|
|
|
@@ -13470,17 +13468,17 @@ function AnimatedUnderline({ bbox, action }) {
|
|
|
13470
13468
|
var import_react56 = require("react");
|
|
13471
13469
|
var import_framer_motion4 = require("framer-motion");
|
|
13472
13470
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
13471
|
+
var WASH = "rgba(230, 180, 34, 0.22)";
|
|
13473
13472
|
function AnimatedHighlight({ bbox, action }) {
|
|
13474
13473
|
const [x1, y1, x2, y2] = bbox;
|
|
13475
13474
|
const h = Math.max(1, y2 - y1);
|
|
13476
13475
|
const bleed = Math.min(4, h * 0.12);
|
|
13477
13476
|
const yTop = y1 - bleed;
|
|
13478
13477
|
const yBot = y2 + bleed;
|
|
13479
|
-
const height = yBot - yTop;
|
|
13480
13478
|
const duration = action.draw_duration_ms / 1e3;
|
|
13481
13479
|
const filterId = (0, import_react56.useId)();
|
|
13482
|
-
const
|
|
13483
|
-
const
|
|
13480
|
+
const isDefaultColour = !action.color || action.color === "rgba(250, 204, 21, 0.35)" || action.color === "rgba(250,204,21,0.35)";
|
|
13481
|
+
const fill = isDefaultColour ? WASH : action.color;
|
|
13484
13482
|
const taper = Math.min(6, h * 0.2);
|
|
13485
13483
|
const pathD = `
|
|
13486
13484
|
M ${x1 - 2} ${yTop + taper}
|
|
@@ -13510,44 +13508,24 @@ function AnimatedHighlight({ bbox, action }) {
|
|
|
13510
13508
|
"feTurbulence",
|
|
13511
13509
|
{
|
|
13512
13510
|
type: "fractalNoise",
|
|
13513
|
-
baseFrequency: "1.
|
|
13511
|
+
baseFrequency: "1.8",
|
|
13514
13512
|
numOctaves: "1",
|
|
13515
13513
|
seed: 3,
|
|
13516
13514
|
result: "noise"
|
|
13517
13515
|
}
|
|
13518
13516
|
),
|
|
13519
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("feDisplacementMap", { in: "SourceGraphic", in2: "noise", scale: 1
|
|
13517
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("feDisplacementMap", { in: "SourceGraphic", in2: "noise", scale: 1 })
|
|
13520
13518
|
] }) }),
|
|
13521
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.
|
|
13522
|
-
import_framer_motion4.motion.
|
|
13519
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
13520
|
+
import_framer_motion4.motion.path,
|
|
13523
13521
|
{
|
|
13522
|
+
d: pathD,
|
|
13523
|
+
fill,
|
|
13524
13524
|
initial: { clipPath: `inset(0 100% 0 0)` },
|
|
13525
13525
|
animate: { clipPath: `inset(0 0% 0 0)` },
|
|
13526
13526
|
exit: { opacity: 0 },
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
13530
|
-
"path",
|
|
13531
|
-
{
|
|
13532
|
-
d: pathD,
|
|
13533
|
-
fill,
|
|
13534
|
-
opacity: 0.85,
|
|
13535
|
-
filter: `url(#${filterId})`
|
|
13536
|
-
}
|
|
13537
|
-
),
|
|
13538
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
13539
|
-
"rect",
|
|
13540
|
-
{
|
|
13541
|
-
x: x1 - 1,
|
|
13542
|
-
y: y1 - bleed * 0.4,
|
|
13543
|
-
width: x2 - x1 + 2,
|
|
13544
|
-
height: height - bleed * 0.8,
|
|
13545
|
-
fill: inner,
|
|
13546
|
-
opacity: 0.5,
|
|
13547
|
-
filter: `url(#${filterId})`
|
|
13548
|
-
}
|
|
13549
|
-
)
|
|
13550
|
-
]
|
|
13527
|
+
filter: `url(#${filterId})`,
|
|
13528
|
+
transition: { duration, ease: EASE_OUT_EXPO }
|
|
13551
13529
|
}
|
|
13552
13530
|
)
|
|
13553
13531
|
]
|
|
@@ -15110,7 +15088,12 @@ var StoryboardStepSchema = import_zod.z.object({
|
|
|
15110
15088
|
});
|
|
15111
15089
|
var StoryboardSchema = import_zod.z.object({
|
|
15112
15090
|
version: import_zod.z.literal(1),
|
|
15113
|
-
reasoning
|
|
15091
|
+
// `reasoning` was required in 0.4.x as a model-generated explanation used
|
|
15092
|
+
// by DebugLog. It carries no visual effect and costs 50–150 output tokens
|
|
15093
|
+
// per call, so from 0.5.1 it's optional (default empty). Consumers who
|
|
15094
|
+
// still send it (from cached prompts or older directors) keep working —
|
|
15095
|
+
// the field is still accepted, just not required.
|
|
15096
|
+
reasoning: import_zod.z.string().max(500).optional().default(""),
|
|
15114
15097
|
steps: import_zod.z.array(StoryboardStepSchema).min(1).max(4)
|
|
15115
15098
|
});
|
|
15116
15099
|
function storyboardJsonSchema(opts = {}) {
|
|
@@ -15225,7 +15208,10 @@ function storyboardJsonSchema(opts = {}) {
|
|
|
15225
15208
|
return {
|
|
15226
15209
|
type: "object",
|
|
15227
15210
|
additionalProperties: false,
|
|
15228
|
-
required
|
|
15211
|
+
// `reasoning` intentionally omitted from `required` — the field is still
|
|
15212
|
+
// accepted when present but the model doesn't need to generate it,
|
|
15213
|
+
// which saves 50–150 output tokens per call. See zod schema above.
|
|
15214
|
+
required: ["version", "steps"],
|
|
15229
15215
|
properties: {
|
|
15230
15216
|
version: { type: "integer", enum: [1] },
|
|
15231
15217
|
reasoning: { type: "string" },
|
|
@@ -15264,7 +15250,6 @@ Anchoring rules:
|
|
|
15264
15250
|
Output ONLY this JSON, nothing else:
|
|
15265
15251
|
{
|
|
15266
15252
|
"version": 1,
|
|
15267
|
-
"reasoning": "<which block(s) you picked, which intent you used, and why \u2014 name the block_id>",
|
|
15268
15253
|
"steps": [ { "at_ms": <int>, "duration_ms": <int>, "action": <action> }, ... ]
|
|
15269
15254
|
}
|
|
15270
15255
|
|
|
@@ -15301,7 +15286,6 @@ When narration fits one of these patterns, emit the corresponding storyboard sha
|
|
|
15301
15286
|
Shape: spotlight the term + underline it + drop a label tag. No camera move if the block is already on-screen.
|
|
15302
15287
|
{
|
|
15303
15288
|
"version": 1,
|
|
15304
|
-
"reasoning": "define recipe: spotlighting and underlining the term, labeling as 'definition'",
|
|
15305
15289
|
"steps": [
|
|
15306
15290
|
{ "at_ms":0, "duration_ms":700, "action": { "type":"spotlight", "target_block":"p1_para0", "dim_opacity":0.6, "feather_px":40, "shape":"rounded" } },
|
|
15307
15291
|
{ "at_ms":200, "duration_ms":800, "action": { "type":"underline", "target_block":"p1_para0", "color":"#FBBF24", "style":"sketch", "draw_duration_ms":700 } },
|
|
@@ -15313,7 +15297,6 @@ Shape: spotlight the term + underline it + drop a label tag. No camera move if t
|
|
|
15313
15297
|
Shape: gentle camera move + callout arrow from caption to figure + pulse the figure.
|
|
15314
15298
|
{
|
|
15315
15299
|
"version": 1,
|
|
15316
|
-
"reasoning": "point_out recipe: drawing attention from caption p1_cap1 to figure p1_fig0",
|
|
15317
15300
|
"steps": [
|
|
15318
15301
|
{ "at_ms":0, "duration_ms":600, "action": { "type":"camera", "target_block":"p1_fig0", "scale":1.3, "padding":80, "easing":"ease-out" } },
|
|
15319
15302
|
{ "at_ms":400, "duration_ms":900, "action": { "type":"callout", "from_block":"p1_cap1", "to_block":"p1_fig0", "label":"see here", "curve":"curved" } },
|
|
@@ -15325,7 +15308,6 @@ Shape: gentle camera move + callout arrow from caption to figure + pulse the fig
|
|
|
15325
15308
|
Shape: box A + box B + callout between them with a relational label.
|
|
15326
15309
|
{
|
|
15327
15310
|
"version": 1,
|
|
15328
|
-
"reasoning": "compare recipe: framing fibrous vs synovial joints",
|
|
15329
15311
|
"steps": [
|
|
15330
15312
|
{ "at_ms":0, "duration_ms":600, "action": { "type":"box", "target_block":"p1_list5", "color":"#3B82F6", "style":"solid" } },
|
|
15331
15313
|
{ "at_ms":300, "duration_ms":600, "action": { "type":"box", "target_block":"p1_list12", "color":"#F472B6", "style":"solid" } },
|
|
@@ -15337,7 +15319,6 @@ Shape: box A + box B + callout between them with a relational label.
|
|
|
15337
15319
|
Shape: highlight + pulse. Fast, punchy, no camera.
|
|
15338
15320
|
{
|
|
15339
15321
|
"version": 1,
|
|
15340
|
-
"reasoning": "emphasize recipe: highlighting key keyword and pulsing for stress",
|
|
15341
15322
|
"steps": [
|
|
15342
15323
|
{ "at_ms":0, "duration_ms":500, "action": { "type":"highlight", "target_block":"p1_list0", "color":"rgba(250,204,21,0.35)", "draw_duration_ms":450 } },
|
|
15343
15324
|
{ "at_ms":350, "duration_ms":800, "action": { "type":"pulse", "target_block":"p1_list0", "count":2, "intensity":"strong" } }
|
|
@@ -15644,9 +15625,10 @@ function enforceOverlayPresence(sb) {
|
|
|
15644
15625
|
if (!cameraStep || cameraStep.action.type !== "camera") return sb;
|
|
15645
15626
|
const target = cameraStep.action.target_block;
|
|
15646
15627
|
if (!target) return sb;
|
|
15628
|
+
const prefix = sb.reasoning ? `${sb.reasoning} ` : "";
|
|
15647
15629
|
return {
|
|
15648
15630
|
...sb,
|
|
15649
|
-
reasoning: `${
|
|
15631
|
+
reasoning: `${prefix}[auto-appended pulse: camera-only storyboards are forbidden]`,
|
|
15650
15632
|
steps: [
|
|
15651
15633
|
...sb.steps,
|
|
15652
15634
|
{
|
|
@@ -16038,6 +16020,7 @@ function TutorModeContainer({
|
|
|
16038
16020
|
backgroundColor = "#ffffff",
|
|
16039
16021
|
loadingComponent,
|
|
16040
16022
|
onPageChange,
|
|
16023
|
+
storyboardProvider,
|
|
16041
16024
|
className
|
|
16042
16025
|
}) {
|
|
16043
16026
|
const containerRef = (0, import_react58.useRef)(null);
|
|
@@ -16116,7 +16099,7 @@ function TutorModeContainer({
|
|
|
16116
16099
|
const debounceRef = (0, import_react58.useRef)(null);
|
|
16117
16100
|
const lastChunkRef = (0, import_react58.useRef)(null);
|
|
16118
16101
|
(0, import_react58.useEffect)(() => {
|
|
16119
|
-
if (!llm) return;
|
|
16102
|
+
if (!storyboardProvider && !llm) return;
|
|
16120
16103
|
if (!currentChunk || currentChunk === lastChunkRef.current) return;
|
|
16121
16104
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
16122
16105
|
debounceRef.current = setTimeout(async () => {
|
|
@@ -16137,6 +16120,75 @@ function TutorModeContainer({
|
|
|
16137
16120
|
});
|
|
16138
16121
|
abortRef.current?.abort();
|
|
16139
16122
|
abortRef.current = new AbortController();
|
|
16123
|
+
if (storyboardProvider) {
|
|
16124
|
+
narrationStore.getState().setLlmStatus("in-flight");
|
|
16125
|
+
narrationStore.getState().appendDebugEvent({
|
|
16126
|
+
kind: "llm-request",
|
|
16127
|
+
summary: `provider (page ${pageNumber}, ${page2.blocks.length} blocks)`,
|
|
16128
|
+
payload: {
|
|
16129
|
+
via: "storyboardProvider",
|
|
16130
|
+
pageNumber,
|
|
16131
|
+
blockCount: page2.blocks.length
|
|
16132
|
+
}
|
|
16133
|
+
});
|
|
16134
|
+
try {
|
|
16135
|
+
const raw = await storyboardProvider({
|
|
16136
|
+
chunk,
|
|
16137
|
+
pageNumber,
|
|
16138
|
+
page: page2,
|
|
16139
|
+
history: narrationStore.getState().chunkHistory,
|
|
16140
|
+
signal: abortRef.current.signal
|
|
16141
|
+
});
|
|
16142
|
+
if (!raw) {
|
|
16143
|
+
narrationStore.getState().setLlmStatus("idle");
|
|
16144
|
+
narrationStore.getState().appendDebugEvent({
|
|
16145
|
+
kind: "note",
|
|
16146
|
+
summary: "provider returned null \u2014 no storyboard for this chunk"
|
|
16147
|
+
});
|
|
16148
|
+
return;
|
|
16149
|
+
}
|
|
16150
|
+
const parsed = StoryboardSchema.safeParse(raw);
|
|
16151
|
+
if (!parsed.success) {
|
|
16152
|
+
narrationStore.getState().setLlmStatus(
|
|
16153
|
+
"failed",
|
|
16154
|
+
parsed.error.message
|
|
16155
|
+
);
|
|
16156
|
+
narrationStore.getState().appendDebugEvent({
|
|
16157
|
+
kind: "llm-error",
|
|
16158
|
+
summary: `provider storyboard rejected by schema: ${parsed.error.issues[0]?.message ?? "unknown"}`,
|
|
16159
|
+
payload: { raw, error: parsed.error.message }
|
|
16160
|
+
});
|
|
16161
|
+
return;
|
|
16162
|
+
}
|
|
16163
|
+
const storyboard = parsed.data;
|
|
16164
|
+
narrationStore.getState().setLlmStatus("idle");
|
|
16165
|
+
narrationStore.getState().appendDebugEvent({
|
|
16166
|
+
kind: "llm-response",
|
|
16167
|
+
summary: summariseStoryboard(storyboard),
|
|
16168
|
+
payload: { via: "storyboardProvider", storyboard }
|
|
16169
|
+
});
|
|
16170
|
+
engineRef.current?.execute(storyboard);
|
|
16171
|
+
narrationStore.getState().appendDebugEvent({
|
|
16172
|
+
kind: "storyboard-execute",
|
|
16173
|
+
summary: `engine executing ${storyboard.steps.length} steps`,
|
|
16174
|
+
payload: storyboard.steps.map((s) => ({
|
|
16175
|
+
at_ms: s.at_ms,
|
|
16176
|
+
type: s.action.type,
|
|
16177
|
+
target: "target_block" in s.action ? s.action.target_block : void 0
|
|
16178
|
+
}))
|
|
16179
|
+
});
|
|
16180
|
+
} catch (e) {
|
|
16181
|
+
if (e.name === "AbortError") return;
|
|
16182
|
+
narrationStore.getState().setLlmStatus("failed", e.message);
|
|
16183
|
+
narrationStore.getState().appendDebugEvent({
|
|
16184
|
+
kind: "llm-error",
|
|
16185
|
+
summary: `provider threw: ${e.message.slice(0, 80)}`,
|
|
16186
|
+
payload: e
|
|
16187
|
+
});
|
|
16188
|
+
}
|
|
16189
|
+
return;
|
|
16190
|
+
}
|
|
16191
|
+
if (!llm) return;
|
|
16140
16192
|
narrationStore.getState().setLlmStatus("in-flight");
|
|
16141
16193
|
narrationStore.getState().appendDebugEvent({
|
|
16142
16194
|
kind: "llm-request",
|
|
@@ -16158,7 +16210,7 @@ function TutorModeContainer({
|
|
|
16158
16210
|
narrationStore.getState().setLlmStatus("idle");
|
|
16159
16211
|
narrationStore.getState().appendDebugEvent({
|
|
16160
16212
|
kind: "llm-response",
|
|
16161
|
-
summary:
|
|
16213
|
+
summary: summariseStoryboard(result.storyboard),
|
|
16162
16214
|
payload: { raw: result.raw, storyboard: result.storyboard }
|
|
16163
16215
|
});
|
|
16164
16216
|
engineRef.current?.execute(result.storyboard);
|
|
@@ -16201,7 +16253,16 @@ function TutorModeContainer({
|
|
|
16201
16253
|
return () => {
|
|
16202
16254
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
16203
16255
|
};
|
|
16204
|
-
}, [
|
|
16256
|
+
}, [
|
|
16257
|
+
currentChunk,
|
|
16258
|
+
llm,
|
|
16259
|
+
storyboardProvider,
|
|
16260
|
+
index,
|
|
16261
|
+
pageNumber,
|
|
16262
|
+
narrationStore,
|
|
16263
|
+
embeddingProvider,
|
|
16264
|
+
llmTimeoutMs
|
|
16265
|
+
]);
|
|
16205
16266
|
(0, import_react58.useEffect)(() => {
|
|
16206
16267
|
if (!currentChunk) return;
|
|
16207
16268
|
const t = setTimeout(() => {
|
|
@@ -16391,6 +16452,15 @@ function TutorLoadingState({
|
|
|
16391
16452
|
}
|
|
16392
16453
|
);
|
|
16393
16454
|
}
|
|
16455
|
+
function summariseStoryboard(sb) {
|
|
16456
|
+
const stepCount = sb.steps.length;
|
|
16457
|
+
const trimmedReasoning = (sb.reasoning ?? "").trim();
|
|
16458
|
+
if (trimmedReasoning) {
|
|
16459
|
+
return `storyboard \u2713 ${stepCount} steps \u2014 ${trimmedReasoning.slice(0, 60)}`;
|
|
16460
|
+
}
|
|
16461
|
+
const kinds = sb.steps.map((s) => s.action.type).join(" \u2192 ");
|
|
16462
|
+
return `storyboard \u2713 ${stepCount} steps \u2014 ${kinds}`;
|
|
16463
|
+
}
|
|
16394
16464
|
|
|
16395
16465
|
// src/director/transformers-embedding.ts
|
|
16396
16466
|
var loaded = null;
|