Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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