Files
David McKay 8cef043e92 feat(reskinnable-demo): accept spreadsheet attachments, and move to CopilotKit 1.71.0
Dropping an .xlsx into the composer did nothing: the accept filter silently
discarded it, and widening that filter alone would have killed the run, because
the pinned @ai-sdk/openai@3 converter accepts no document media type but
application/pdf and throws before a request is made.

Spreadsheets now work end to end:

- A dependency-free .xlsx / .csv reader (ZIP central directory + OOXML through
  DecompressionStream and DOMParser). It decodes date serials via styles.xml so
  a date does not render as 45231, and places cells by column reference so a
  gap does not shift every later value under the wrong header.
- The sheet is rendered to a column-aligned table document. Comparisons of
  table encodings put a markdown-style aligned table well ahead of CSV for
  model comprehension, and the same document is what a human sees.
- buildPdf paginates. It emitted a single page and drew overflow past the
  bottom margin, so anything after ~48 rows was silently absent from a
  perfectly valid PDF. Single-page output is byte-identical, so the existing
  golden assertions stand.
- A per-run bridge around the agent swaps the media type to application/pdf on
  the model leg only, and restores the original type and metadata on the way
  back. Both the composer chip and the transcript therefore read XLS with the
  real filename. The bridge keys on the exact payload, so a genuine PDF
  attachment is never mislabelled.
- onUploadFailed is wired. A rejected or unreadable file now says so instead of
  vanishing with no trace.

The demo workbook is committed as a generator rather than a binary blob, so the
fixture exercises the real reader: shared strings, date-styled serials, a
second sheet, deflate.

Also moves @copilotkit/* to 1.71.0 and @ag-ui/* to 0.0.59, and deletes the
@ag-ui canary overrides from both pnpm-workspace.yaml and package.json. Those
existed only because a released @ag-ui/core rejected SUBAGENT_* events and
killed banking's harness console; stable 0.0.59 ships SUBAGENT_STARTED,
SUBAGENT_FINISHED and SUBAGENT_ERROR, and 1.71.0 depends on exactly 0.0.59, so
the overrides would now hold the tree behind its own dependency.

Verified on the running demo, not just in tests: gen UI renders, the subagent
harness completes the offsite run (14 rows, 6 merchants, $2,377.15, 1m 4s),
memory recall returns seeded memories, and a spreadsheet answers with a table
built from the real file. Lint, typecheck, 2494 unit tests and build all pass.

Checked the reskin skill for staleness: buildPdf was documented as single-page
and two passages said onUploadFailed is wired by nobody. Both corrected here.
2026-09-10 10:03:57 -07:00

70 lines
2.3 KiB
JSON

{
"name": "reskinnable-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint .",
"test:e2e": "playwright test",
"test:e2e:ogui": "playwright test -c playwright.ogui.config.ts",
"test:self-learning": "playwright test e2e/memory-learning.spec.ts",
"test:unit": "vitest run",
"typecheck": "tsc --noEmit",
"mint-dev-license": "node scripts/mint-dev-license.mjs"
},
"dependencies": {
"@ag-ui/client": "0.0.59",
"@copilotkit/a2ui-renderer": "1.71.0",
"@copilotkit/core": "1.71.0",
"@copilotkit/react-core": "1.71.0",
"@copilotkit/runtime": "1.71.0",
"@copilotkit/shared": "1.71.0",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.2",
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.1",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-toast": "^1.2.2",
"@radix-ui/react-tooltip": "^1.1.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"hono": "^4.11.4",
"lucide-react": "^0.447.0",
"next": "^16.0.10",
"openai": "^4.96.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-resizable-panels": "^4.12.2",
"tailwind-merge": "^2.5.2",
"tw-animate-css": "^1.4.0",
"zod": "^3.25.76"
},
"devDependencies": {
"@copilotkit/aimock": "1.19.1",
"@playwright/test": "^1.59.1",
"@tailwindcss/postcss": "^4",
"@testing-library/react": "^16.1.0",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9",
"eslint-config-next": "^16.0.10",
"jsdom": "^25.0.1",
"tailwindcss": "^4",
"typescript": "^5",
"vitest": "^3.2.0"
},
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39"
}