Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
77aa2bd
feat: add embedding search, document upload, and RAG agent template
ariskemper Mar 3, 2026
ba03b92
feat: chat UI phase 3 — sidebar, model selector, code blocks, step in…
ariskemper Mar 3, 2026
94f7630
feat: chat UI tabs, quick actions, model avatars, and RAG search fix
ariskemper Mar 5, 2026
f7084df
feat: compound Message component, full Chat migration, legacy removal…
kojiwakayama Mar 5, 2026
e3b5176
fix: resolve review issues — exports, security, race conditions, form…
kojiwakayama Mar 5, 2026
459bfdb
docs: add missing sub-components and context providers to chat reference
kojiwakayama Mar 5, 2026
8e664b8
fix: SSE line buffer, stale refs, concurrent guard, BM25 div-by-zero
kojiwakayama Mar 5, 2026
88f0414
chore: remove dead code
kojiwakayama Mar 5, 2026
7e824ca
fix: batch A quick wins — correctness, security, React quality, template
kojiwakayama Mar 5, 2026
b4ae6b9
fix: complete barrel exports across ai/index.ts, public.ts, chat/inde…
kojiwakayama Mar 5, 2026
8423c3c
fix: accessibility — ARIA listbox, tab pattern, SSR hydration
kojiwakayama Mar 5, 2026
182ef7b
docs: fix chat-ui examples, update RAG template, expand chat API refe…
kojiwakayama Mar 5, 2026
5e7aa45
test: add SSE line-buffer and vector store tests, fix step-part asser…
kojiwakayama Mar 5, 2026
a1646c3
refactor: rename Documents → Uploads across embedding, UI, templates,…
kojiwakayama Mar 5, 2026
b2f96c2
fix: make LOG_LEVEL_MAP deeply immutable to resolve CodeQL alert
kojiwakayama Mar 5, 2026
a189f03
fix: remove unused onNewThread prop from ChatSidebar
kojiwakayama Mar 5, 2026
1b9ff44
refactor: adopt Studio design tokens across all chat UI components
kojiwakayama Mar 5, 2026
f3ac1e3
refactor: align chat UI components with Studio design patterns
kojiwakayama Mar 5, 2026
e0cb917
fix: address PR review feedback — security, DX, and correctness
kojiwakayama Mar 5, 2026
3c4736d
style: fix formatting (deno fmt)
kojiwakayama Mar 5, 2026
57793e6
fix: update templates test for pre-bundled state and sync FRAMEWORK_S…
kojiwakayama Mar 5, 2026
342fd69
fix: address PR #477 review regressions
kojiwakayama Mar 5, 2026
b7c7ff2
test: add coverage for useChat state, upload-store, and loader alias …
kojiwakayama Mar 5, 2026
1281d45
refactor: auto-extract framework Tailwind candidates at build time
kojiwakayama Mar 5, 2026
e229555
style: chat UI polish — tabs in header, icon circles, button cursor, …
kojiwakayama Mar 5, 2026
b4da8fb
fix: center tabs horizontally with balanced flexbox spacer
kojiwakayama Mar 5, 2026
7b6b3a9
style: fix formatting (deno fmt)
kojiwakayama Mar 5, 2026
1901976
chore: unify build/distribution task pipeline
kojiwakayama Mar 5, 2026
162dd55
chore: bump version to 0.1.48
kojiwakayama Mar 5, 2026
3ee173e
fix: add missing import map entries, reduce binary from 902MB to 172MB
kojiwakayama Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,7 @@ jobs:
with:
deno-version: lts

- run: deno run -A scripts/build/generate-templates-manifest.ts
- run: deno run -A scripts/build/prepare-framework-sources.ts
- run: deno run -A scripts/build/prebundle-bridge.ts
- run: deno task build:prepare

- name: Compile binary
shell: bash
Expand Down
39 changes: 33 additions & 6 deletions DISTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,35 +126,53 @@ This creates binaries in `dist/`:
### Build Individual Platform

```bash
# Required prep step (manifests, prebundles, framework sources)
deno task build:prepare

# macOS ARM (M1/M2/M3)
deno compile --allow-all \
--include src/platform/polyfills \
--include src/proxy/main.ts \
--include dist/framework-src \
--target aarch64-apple-darwin \
--output dist/veryfront-macos-arm64 \
src/cli/main.ts
cli/main.ts

# macOS Intel
deno compile --allow-all \
--include src/platform/polyfills \
--include src/proxy/main.ts \
--include dist/framework-src \
--target x86_64-apple-darwin \
--output dist/veryfront-macos-x64 \
src/cli/main.ts
cli/main.ts

# Linux x64
deno compile --allow-all \
--include src/platform/polyfills \
--include src/proxy/main.ts \
--include dist/framework-src \
--target x86_64-unknown-linux-gnu \
--output dist/veryfront-linux-x64 \
src/cli/main.ts
cli/main.ts

# Linux ARM64
deno compile --allow-all \
--include src/platform/polyfills \
--include src/proxy/main.ts \
--include dist/framework-src \
--target aarch64-unknown-linux-gnu \
--output dist/veryfront-linux-arm64 \
src/cli/main.ts
cli/main.ts

# Windows x64
deno compile --allow-all \
--include src/platform/polyfills \
--include src/proxy/main.ts \
--include dist/framework-src \
--target x86_64-pc-windows-msvc \
--output dist/veryfront-windows-x64.exe \
src/cli/main.ts
cli/main.ts
```

### Test Binaries
Expand Down Expand Up @@ -186,6 +204,9 @@ deno task release 0.1.0
### 2. Build All Binaries

```bash
# One-shot local distribution verification (binary + npm package)
deno task verify:dist

# Build for all platforms
node scripts/build/build-all.js

Expand Down Expand Up @@ -509,12 +530,18 @@ jobs:
with:
deno-version: v2.x

- name: Prepare build artifacts
run: deno task build:prepare

- name: Build binary
run: |
deno compile --allow-all \
--include src/platform/polyfills \
--include src/proxy/main.ts \
--include dist/framework-src \
--target ${{ matrix.target }} \
--output dist/${{ matrix.output }} \
src/cli/main.ts
cli/main.ts

- name: Generate checksum
run: |
Expand Down
2 changes: 1 addition & 1 deletion cli/app/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function createApp(config: AppConfig): App {

state = setTemplates([
{ id: "ai-agent", name: "AI Chatbot", description: "Agent + chat UI + streaming" },
{ id: "chat-with-your-docs", name: "Chat with Docs", description: "RAG with source citations" },
{ id: "ai-rag-agent", name: "AI RAG Agent", description: "RAG with source citations" },
{
id: "multi-agent-system",
name: "Multi-Agent",
Expand Down
2 changes: 1 addition & 1 deletion cli/commands/init/catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe("catalog", () => {
assertEquals(ids, [
"minimal",
"ai-agent",
"chat-with-your-docs",
"ai-rag-agent",
"agentic-workflow",
"multi-agent-system",
"coding-agent",
Expand Down
4 changes: 2 additions & 2 deletions cli/commands/init/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export const TEMPLATES: readonly TemplateOption[] = [
{ id: "minimal", label: "Minimal", description: "Blank canvas, no extras" },
{ id: "ai-agent", label: "AI Agent", description: "Agent + chat UI + streaming" },
{
id: "chat-with-your-docs",
label: "Chat with Your Docs",
id: "ai-rag-agent",
label: "AI RAG Agent",
description: "RAG with source citations",
},
{
Expand Down
4 changes: 2 additions & 2 deletions cli/commands/init/command-help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const initHelp: CommandHelp = {
{
flag: "-t, --template <name>",
description:
"Project template (minimal | ai-agent | chat-with-your-docs | agentic-workflow | multi-agent-system | coding-agent | saas-starter)",
"Project template (minimal | ai-agent | ai-rag-agent | agentic-workflow | multi-agent-system | coding-agent | saas-starter)",
},
{
flag: "--integrations <list>",
Expand Down Expand Up @@ -39,7 +39,7 @@ export const initHelp: CommandHelp = {
"veryfront init # Interactive wizard",
"veryfront init my-app",
"veryfront init my-app --template ai-agent",
"veryfront init my-rag --template chat-with-your-docs",
"veryfront init my-rag --template ai-rag-agent",
"veryfront init my-pipeline --template agentic-workflow",
"veryfront init my-app --deploy # Create and deploy",
"veryfront init --config project.json # From config file",
Expand Down
9 changes: 9 additions & 0 deletions cli/commands/init/config-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ export async function createPackageJson(
): Promise<void> {
const fs = createFileSystem();

// Read any existing package.json (e.g. from template) to merge dependencies
let templateDeps: Record<string, string> = {};
const pkgPath = join(projectDir, "package.json");
if (await fs.exists(pkgPath)) {
const existing = JSON.parse(await fs.readTextFile(pkgPath));
templateDeps = existing.dependencies ?? {};
}

const dirName = projectDir.split(/[/\\]/).pop();
const packageJson = {
name: projectName ?? dirName ?? "veryfront-project",
Expand All @@ -25,6 +33,7 @@ export async function createPackageJson(
onlyBuiltDependencies: ["esbuild", "veryfront"],
},
dependencies: {
...templateDeps,
react: `^${DEFAULT_INIT_REACT_VERSION}`,
"react-dom": `^${DEFAULT_INIT_REACT_VERSION}`,
veryfront: `^${VERSION}`,
Expand Down
2 changes: 1 addition & 1 deletion cli/commands/init/init-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe("InitCommand Types", () => {
describe("InitTemplate", () => {
const templates: InitTemplate[] = [
"ai-agent",
"chat-with-your-docs",
"ai-rag-agent",
"multi-agent-system",
"agentic-workflow",
"coding-agent",
Expand Down
4 changes: 2 additions & 2 deletions cli/commands/init/init.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,11 @@ describe("init command integration", () => {
assertEquals(statResult.isDirectory, true);
});

it("should use chat-with-your-docs template when specified", async () => {
it("should use ai-rag-agent template when specified", async () => {
const result = await runInitCommand([
projectName,
"-t",
"chat-with-your-docs",
"ai-rag-agent",
"--skip-install",
]);

Expand Down
2 changes: 1 addition & 1 deletion cli/commands/init/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { FeatureName, IntegrationName } from "../../templates/types.ts";

export type InitTemplate =
| "ai-agent"
| "chat-with-your-docs"
| "ai-rag-agent"
| "multi-agent-system"
| "agentic-workflow"
| "coding-agent"
Expand Down
2 changes: 1 addition & 1 deletion cli/commands/new/fast-scaffold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function dedupeFilesByPath(files: TemplateFile[]): TemplateFile[] {
function createVeryfrontConfig(slug: string, template: InitTemplate): TemplateFile {
const usesAppRouter = [
"ai-agent",
"chat-with-your-docs",
"ai-rag-agent",
"multi-agent-system",
"agentic-workflow",
"coding-agent",
Expand Down
2 changes: 1 addition & 1 deletion cli/help/tips.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe("cli/help/tips", () => {
for (
const template of [
"ai-agent",
"chat-with-your-docs",
"ai-rag-agent",
"multi-agent-system",
"agentic-workflow",
"coding-agent",
Expand Down
2 changes: 1 addition & 1 deletion cli/help/tips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function getBuildTips(): string {
export function getInitTemplates(): string {
return `${yellow("Available Templates:")}\n` +
` • ${green("ai-agent")} - AI chatbot with tools and streaming\n` +
` • ${green("chat-with-your-docs")} - Chat with your docs (RAG + citations)\n` +
` • ${green("ai-rag-agent")} - RAG agent with source citations\n` +
` • ${green("multi-agent-system")} - Agents that delegate to each other\n` +
` • ${green("agentic-workflow")} - AI pipeline with approvals\n` +
` • ${green("coding-agent")} - AI code assistant with file tools\n` +
Expand Down
2 changes: 1 addition & 1 deletion cli/mcp/remote-file-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ const remoteCreateProjectInput = z.object({
"Project slug (lowercase letters, numbers, hyphens only). A random suffix is appended if the slug is already taken.",
),
templateSlug: z.string().optional().describe(
"Template project slug to fork from (e.g., 'blank', 'ai-agent', 'chat-with-your-docs')",
"Template project slug to fork from (e.g., 'blank', 'ai-agent', 'ai-rag-agent')",
),
is_public: z.boolean().optional().describe("Whether the project is public (default: false)"),
});
Expand Down
6 changes: 3 additions & 3 deletions cli/mcp/tools/catalog-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const EXAMPLES: ExampleInfo[] = [
{
name: "data-analyst",
description: "RAG-powered data analyst with Sheets and Snowflake",
template: "chat-with-your-docs",
template: "ai-rag-agent",
integrations: ["sheets", "snowflake", "notion"],
features: ["Document search", "Chart generation", "Reports"],
difficulty: "advanced",
Expand Down Expand Up @@ -89,7 +89,7 @@ const TEMPLATES: TemplateInfo[] = [
recommended: true,
},
{
name: "chat-with-your-docs",
name: "ai-rag-agent",
description: "Chat with your docs using retrieval-augmented generation",
features: ["Document search", "Source citations", "File-based knowledge"],
},
Expand Down Expand Up @@ -407,7 +407,7 @@ const createProjectInput = z.object({
template: z
.enum([
"ai-agent",
"chat-with-your-docs",
"ai-rag-agent",
"multi-agent-system",
"agentic-workflow",
"coding-agent",
Expand Down
123 changes: 123 additions & 0 deletions cli/templates/files/ai-rag-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# AI RAG Agent

A chatbot that answers questions from your own documents using Retrieval-Augmented Generation (RAG).

## What's included

- Q&A agent with source citation
- Embedding-based semantic search (OpenAI text-embedding-3-small)
- Document upload supporting PDF, DOCX, CSV, TXT, and Markdown
- JSON-based vector store — no external database required
- Sample content in `/content` directory auto-indexed on first search

## Getting started

1. Set your OpenAI API key:

```bash
export OPENAI_API_KEY=sk-...
```

2. Start the dev server:

```bash
npx veryfront dev
```

3. Open the app and upload a document or ask a question — the sample docs in `content/` are indexed automatically.

## Architecture

RAG grounds LLM responses in your documents through three pipelines — **Ingestion**, **Query**, and **RAG** — orchestrated around a shared vector store.

```mermaid
flowchart LR
ChatUI_L["Chat UI"]

subgraph IngestionFlow["Ingestion Pipeline"]
D["Documents"] --> EXT["Extraction"] --> DC["Chunking"] --> DE["Document\nEmbedding"] --> ING["Storage"]
end

subgraph QueryFlow["Query Pipeline"]
Q["Query"] --> QE["Query\nEmbedding"] --> SS["Similarity\nSearch"]
end

subgraph RAGFlow["RAG Pipeline"]
BF["beforeStream\nHook"] --> RET["Retrieval"] --> AUG["Augmentation"] --> AG["Agent"] --> GEN["Generation"]
end

EMB(("Embedding\nModel"))
GEN_LLM(("Generative\nModel"))
VS[("Vector\nStore")]
ChatUI_R["Chat UI"]

ChatUI_L --> D
ChatUI_L --> Q

QE -.- EMB
DE -.- EMB

SS --> VS
ING --> VS

Q --> BF
VS --> RET
AG -.- GEN_LLM
GEN -.- GEN_LLM
GEN --> ChatUI_R
```

### Pipelines

**Ingestion** — Documents are parsed into plain text (PDF via `pdf-parse`, DOCX via ZIP/XML, text formats directly), split into overlapping chunks (~1000 chars, 200 char overlap), and stored with their embeddings in `data/index.json`. Embeddings are generated lazily on first search to keep uploads fast.

**Query** — The user's query is embedded into the same vector space as the documents, then compared against all stored chunks using cosine similarity to find the top-*k* most relevant results.

**RAG** — The `beforeStream` hook in the chat route intercepts each message before it reaches the agent. It searches the document store for relevant chunks, assembles them into context, and prepends them as a system message. The agent then generates a cited response streamed back to the user.

## Structure

```
store.ts Upload store config (embedding model, storage path)
agents/rag.ts Q&A agent with citation instructions
content/
getting-started.md Sample document
architecture.md Sample document
app/
api/chat/route.ts Chat API endpoint
api/uploads/route.ts Upload (POST) and list (GET) uploads
api/uploads/[id]/route.ts Delete upload
page.tsx Chat UI with document upload panel
layout.tsx Root layout with header
```

## Framework usage

| What | Framework | Template code |
|------|-----------|---------------|
| Chat UI + streaming | `Chat`, `useChat` | `page.tsx` |
| Upload management | `useUploads` hook | `page.tsx` |
| Source display | `showSources` prop on `Chat` | `page.tsx` |
| Upload API routes | `createUploadHandler` | 1-line per route file |
| Chat API route | `createChatHandler` | 1 line in `route.ts` |
| Agent definition | `agent()` | Config object in `agents/rag.ts` |
| RAG retrieval | `beforeStream` hook | Context injection in `api/chat/route.ts` |
| Vector store | `uploadStore()` | Config in `store.ts` |

## Adding documents

- Drop files into `content/` — they're indexed automatically on first search
- Or use the upload panel in the UI for PDF, DOCX, CSV, TXT, and MD files

## npm packages

This template uses `pdf-parse` for PDF text extraction. Any npm package you install in your project works in API routes — the framework automatically detects your `package.json` dependencies and handles bundling.

## Production notes

This is a starter template — not a production-ready setup. For production, consider:

- **Vector store** — Replace the JSON store with pgvector, Pinecone, or Qdrant for datasets beyond ~10k chunks
- **DOCX parser** — The built-in extractor handles basic documents; use the `mammoth` package for complex formatting
- **Reranking** — Add a cross-encoder reranker (e.g. Cohere Rerank) after retrieval to improve precision
- **Hybrid search** — Combine dense vectors with BM25 keyword matching for better recall
10 changes: 10 additions & 0 deletions cli/templates/files/ai-rag-agent/agents/rag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { agent } from "veryfront/agent";

export default agent({
id: "rag",
model: "local/qwen3-1.7b",
system:
`You answer questions using the provided documents. ` +
`Always cite your sources by referencing the document title. ` +
`If the search results don't contain a clear answer, say so honestly.`,
});
Loading
Loading