Skip to content

Repository files navigation

LYTA

Cloudflare Workers Durable Objects Workers AI Frontend Status

LYTA workspace preview

Edge-native AI workspace for technical work.
Persistent workspaces · Reusable file memory · Retrieval with citations · Streaming chat · Output board

Live Demo · Architecture Notes

Overview

LYTA is a portfolio-grade AI workspace built on Cloudflare Workers, Durable Objects, and Workers AI. It is designed to demonstrate more than a prompt box: it models user state, file memory, retrieval, streaming, and output capture as a real product system.

The current product experience is intentionally minimal. The interface focuses on a quiet workspace rail, readable chat, reusable files, cited answers, and a document-style output board.

What LYTA Does

  • Starts immediately in guest mode with temporary server-backed workspace state.
  • Supports account workspaces for persisted chats, files, profile data, and preferences.
  • Ingests PDFs, DOCX, TXT, Markdown, CSV, JSON, HTML, XML, and images.
  • Stores uploaded documents in a reusable file library instead of treating every upload as a one-off attachment.
  • Retrieves relevant file snippets and returns source citations in chat and on the output board.
  • Streams assistant responses over Server-Sent Events.
  • Provides Instant, Deep, and Creative response modes.
  • Generates short chat titles and follow-up prompts.
  • Lets users pin strong assistant responses to a board for copy or Markdown export.

Why This Is Technically Interesting

Most AI demos are stateless chat screens. LYTA is structured around explicit ownership boundaries:

  • Worker Router resolves guest/account identity, validates requests, coordinates retrieval, and forwards normalized chat work.
  • AuthDirectory Durable Object owns account records, password hashes, auth sessions, and token validation.
  • Workspace Durable Object owns profile data, preferences, chat index, file metadata, document chunks, embeddings, and library search.
  • Conversation Durable Object owns per-chat memory, ordered writes, summarization, title generation, follow-ups, and streaming persistence.
  • Workers AI provides both chat generation and embedding generation.

The streaming path is hardened for demo reliability. /chat/stream establishes a valid SSE response before the model call runs, and model/retrieval failures degrade into clean LYTA errors instead of leaking Cloudflare 1101 HTML into the UI. Chat responses also include X-Lyta-Request-Id for log correlation, while logs avoid prompts, file text, emails, tokens, and full user data.

Demo Walkthrough

  1. Open the live demo.
  2. Start as a guest and ask a technical question.
  3. Upload a document and ask LYTA to summarize risks, decisions, or next steps.
  4. Reuse the uploaded file from the library in another chat.
  5. Compare Instant, Deep, and Creative response modes.
  6. Pin a response to the output board and copy or download it.
  7. Sign in to move from temporary guest state to a saved account workspace.

Prefer not to type your own material? fixtures/demo-architecture-change.md is a short, clearly-fictional sample change proposal you can upload in step 3 instead — safe public material for demoing retrieval and citations.

Architecture

LYTA architecture diagram

flowchart TD
    UI[Browser UI<br/>Chat, Files, Board, Settings] --> Router[Cloudflare Worker Router]
    Router --> Auth[AuthDirectory DO<br/>Accounts + Sessions]
    Router --> Workspace[Workspace DO<br/>Profile, Preferences, Chat Index, File Library]
    Router --> Conversation[Conversation DO<br/>Per-Chat Memory + Streaming]
    Router --> Embeddings[Workers AI Embeddings]
    Conversation --> ChatModel[Workers AI Chat Model]
    Embeddings --> Workspace
    Workspace --> Router
    Conversation --> Workspace
Loading
sequenceDiagram
    participant User
    participant UI as Browser UI
    participant Router as Worker Router
    participant Workspace as Workspace DO
    participant Chat as Conversation DO
    participant AI as Workers AI

    User->>UI: Send message and optional files
    UI->>Router: POST /chat/stream
    Router->>Workspace: Import/search reusable library
    Router->>Chat: Forward message, context, citations, request id
    Chat-->>UI: Open SSE response
    Chat->>AI: Run streaming chat model
    AI-->>Chat: Token stream
    Chat-->>UI: SSE chunks, metadata, citations
    Chat->>Workspace: Touch/rename session
Loading

Core Building Blocks

Layer Responsibility
pages/ Vanilla HTML/CSS/JS workspace UI, uploads, auth modal, streaming chat, board
src/router.ts Principal resolution, route validation, guest/account routing, library retrieval orchestration
AuthDirectory Account records, password hashing, session tokens
Workspace Profile, preferences, chat index, reusable file library, vector search
Conversation Per-chat state, summaries, titles, follow-ups, SSE streaming, persistence
services/ai.ts / services/embeddings.ts Workers AI model and embedding calls with normalized failures

More detail lives in ARCHITECTURE.md.

Feature Inventory

Implemented

  • Guest and account workspace modes
  • Email/password account registration and login
  • Persistent chat sessions for account workspaces
  • Temporary guest sessions with isolated server-backed state
  • File upload and browser-side document text extraction
  • Reusable workspace file library
  • Embedding-backed file retrieval with citations
  • SSE streaming chat responses
  • Response modes: Instant, Deep, Creative
  • Chat title generation, summarization, and follow-up prompts
  • Minimal output board with copy and Markdown download
  • Request-id based chat error correlation
  • Graceful degradation for AI/retrieval failures

Known Tradeoffs

  • Guest state is temporary and scoped to the guest cookie.
  • Auth is email/password based, not OAuth or magic link.
  • Retrieval uses Durable Object state rather than a dedicated external vector database.
  • Browser-side extraction keeps the architecture compact but does not replace server-side OCR.
  • The output board is a focused Markdown capture pane, not a full artifact runtime.

Project Structure

assets/
  architecture.svg         Source for the README architecture visual
  architecture.png         Rendered README architecture visual
  demo.svg                 Source for the README product preview
  demo.png                 Rendered README product preview

scripts/
  render_asset.swift       Renders SVG assets to PNG on macOS

pages/
  index.html               Main UI shell
  styles.css               Minimal workspace visual system
  app-core.js              Generated browser utility bundle
  app-attachments.js       Browser-side attachment preparation
  app.js                   Client logic for auth, chat, uploads, board, settings

pages-src/
  app-core.ts              TypeScript source for app-core.js

src/
  index.ts                 Worker entry point
  router.ts                Request orchestration and workspace routing
  auth/crypto.ts           Password and token helpers
  chat/messages.ts         Prompt shaping and message normalization
  durable/
    authDirectory.ts       Account and session storage
    workspace.ts           Workspace state, file library, preferences
    conversation.ts        Chat memory, streaming, follow-ups, summaries
  library/chunks.ts        Document chunking and citation formatting
  services/
    ai.ts                  Workers AI chat calls
    embeddings.ts          Embedding generation
    retriever.ts           Small built-in knowledge retriever
  utils/
    serverErrors.ts        Sanitized server error logging helpers

Stack

  • Cloudflare Workers
  • Cloudflare Durable Objects
  • Cloudflare Workers AI
  • TypeScript
  • Vanilla HTML, CSS, and browser JavaScript
  • PDF.js
  • Mammoth
  • Server-Sent Events

Local Development

Requirements

  • Node.js 18+
  • Wrangler CLI
  • macOS only for the optional SVG-to-PNG asset renderer

Install

npm install

Build Client Assets

npm run build:client

Run Locally

wrangler dev --remote

Open:

http://localhost:8787

Render README Assets

swift scripts/render_asset.swift assets/demo.svg assets/demo.png 1600 960
swift scripts/render_asset.swift assets/architecture.svg assets/architecture.png 1600 900

Verification

npm run format:check
npm run build:client
./node_modules/.bin/tsc --noEmit
./node_modules/.bin/tsc -p tsconfig.client.json --noEmit
node --check pages/app-core.js
node --check pages/app.js
node --check pages/app-attachments.js
git diff --check

Or run everything at once with npm run check — it's the exact gate CI and the deploy workflow both run.

Testing

npm run test:unit          # pure-function tests, no Durable Object involved
npm run test:integration   # drive a Durable Object's fetch() against faked storage
npm run test:eval          # scripted-model evaluation suite (eval/dataset.json)
npm run test:smoke         # register -> upload -> chat -> stream through the real router

npm test runs unit, integration, and smoke (the eval suite runs as part of test:integration's glob and separately via test:eval for CI visibility — see below). Coverage areas called out in issue #9:

Area Test file
Auth/session isolation tests/integration/abuse-controls.test.ts
Rate limits tests/integration/abuse-controls.test.ts
Streaming persistence tests/integration/streaming-persistence.test.ts
Prompt boundaries tests/unit/retrieval-boundary.test.ts
File lifecycle tests/integration/workspace-artifacts.test.ts
Citation identity tests/unit/retrieval-boundary.test.ts, tests/integration/project-context.test.ts
History retention tests/integration/conversation-history.test.ts, tests/integration/workspace-artifacts.test.ts
Log redaction tests/unit/log-redaction.test.ts
Full request pipeline tests/smoke/smoke.test.ts

Model Configuration and Evaluation

src/config/modelProfiles.ts is the single source of truth for per-mode model selection: model id, version label, timeout, retry budget, fallback model, and documented latency/cost/quality targets for Instant and Deep (Deep Review). src/services/ai.ts's callWithPolicy() wraps every Workers AI call with that timeout/retry/fallback policy and records the outcome as non-sensitive telemetry (model, version, retry count, fallback used, timed out) — never prompt or response content.

eval/dataset.json is a versioned evaluation baseline (citation accuracy, insufficient-evidence compliance, cross-mode sanity checks) that CI runs on every PR as a pipeline-correctness regression gate. See eval/README.md for what that suite does and doesn't prove, and the model-promotion policy: no model or prompt change is called "stronger" until it beats the documented baseline against this suite, run against a real model.

CI/CD

GitHub Actions runs formatting, the client build, unit tests, integration tests, the evaluation suite, the smoke test, TypeScript checks, browser bundle syntax checks, a generated-client consistency check, a production dependency audit, a model/prompt configuration change report, and a Worker deployment bundle validation as separate steps for every pull request and merge to main (npm run check runs the same gates locally in one command).

Production deployment is deliberately manual through the Deploy production workflow. Protect the repository's production environment with required reviewers, then add these environment secrets:

  • CLOUDFLARE_API_TOKEN — scoped to deploy this Worker and write to its R2 bucket.
  • CLOUDFLARE_ACCOUNT_ID — the Cloudflare account that owns LYTA.

The workflow never prints either value. It installs from package-lock.json, reruns the complete quality gate, and only then calls Wrangler to deploy. Before dispatching it, walk through RELEASE_CHECKLIST.md for the things CI can't verify automatically — deployed-header verification, migration review, an AI-evaluation comparison, and a manual accessibility smoke test.

Project Context and Provenance

LYTA stores workspace source payloads in private R2 objects and treats chunks, findings, decisions, and user-approved summaries as provider-independent context. A model request receives only retrieval-selected evidence, never a full workspace dump. Each selection creates an ID-only context manifest with a policy version; it contains no source text or query.

Authenticated workspace APIs support inspection and management:

  • GET /context lists context metadata; add ?includeContent=true to inspect saved findings, decisions, and summaries.
  • POST /context/records creates or updates a finding, decision, or approved summary with source/chunk provenance.
  • POST /context/records/delete deletes a saved context record.
  • GET /context/manifests lists non-sensitive selection audit records.

Deleting a source also removes derived context records linked to that source and returns the affected-record count. Historical ID-only manifests remain as audit evidence; deleted source text is not retrievable.

Roadmap Ideas

  • OCR for scanned PDFs and image-heavy documents
  • Web research mode with explicit external citations
  • Shareable board outputs or published artifact pages
  • OAuth or magic-link authentication
  • Retrieval quality metrics and latency dashboards
  • Richer artifact generation beyond Markdown export

Repo Quality Goals

LYTA is structured to be readable by reviewers:

  • clear product story and live demo path
  • explicit state ownership boundaries
  • architecture diagrams that match implementation
  • minimal frontend without framework overhead
  • failure handling that preserves product polish during AI or retrieval issues

About

Stateful edge-based AI system with deterministic execution under concurrency. Built using Cloudflare Workers, Durable Objects, and SSE streaming.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages