Skip to content
GitHub
EN VI

Workspace & AgentRouter

@moon-wave/workspace provides two utilities:

  • AgentRouter β€” serve multiple agents from one Worker with a clean REST API
  • FileSystem β€” R2-backed file storage for agents that need to read/write files

Install

Terminal window
npm install @moon-wave/workspace

AgentRouter

Route HTTP requests to different agents based on a name in the URL path. Useful when you have several agents that share the same Worker but serve different purposes.

Basic usage

src/index.ts
import { Agent } from '@moon-wave/core';
import { AgentRouter } from '@moon-wave/workspace';
export interface Env {
GROQ_API_KEY: string;
}
const supportAgent = new Agent({
name: 'support',
model: { provider: 'groq', model: 'llama-3.3-70b-versatile' },
systemPrompt: 'You are a helpful customer support agent.',
memory: 'none',
});
const codingAgent = new Agent({
name: 'coding',
model: { provider: 'groq', model: 'llama-3.3-70b-versatile' },
systemPrompt: 'You are a senior software engineer. Help with code reviews and debugging.',
memory: 'none',
});
const router = new AgentRouter();
router.register('support', supportAgent, 'Customer support');
router.register('coding', codingAgent, 'Software engineering help');
export default {
async fetch(request: Request, env: Env): Promise<Response> {
return router.handle(request, env as unknown as Record<string, unknown>);
},
};

Routes

MethodPathDescription
GET/agentsList all registered agents
GET/agents/:nameGet info about one agent
POST/agents/:nameRun an agent

List agents

Terminal window
curl https://your-worker.workers.dev/agents
[
{ "name": "support", "description": "Customer support" },
{ "name": "coding", "description": "Software engineering help" }
]

Run an agent

Terminal window
curl -X POST https://your-worker.workers.dev/agents/support \
-H "Content-Type: application/json" \
-d '{ "input": "How do I reset my password?" }'
{
"output": "To reset your password, go to the login page and click...",
"iterations": 1,
"toolCalls": []
}

Pass sessionId to preserve conversation history across requests (requires memory configured):

Terminal window
curl -X POST .../agents/support \
-H "Content-Type: application/json" \
-d '{ "input": "follow up question", "sessionId": "user-123" }'

Combine with dashboard

AgentRouter and @moon-wave/dashboard work well together:

import { AgentRouter } from '@moon-wave/workspace';
import { createDashboard } from '@moon-wave/dashboard';
const router = new AgentRouter();
router.register('support', supportAgent, 'Customer support');
router.register('coding', codingAgent, 'Engineering help');
const dashboard = createDashboard({
agents: { support: supportAgent, coding: codingAgent },
});
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
if (url.pathname.startsWith('/dashboard')) {
return dashboard.handle(request, env as unknown as Record<string, unknown>);
}
return router.handle(request, env as unknown as Record<string, unknown>);
},
};

This gives you:

  • GET /agents β€” list all agents
  • POST /agents/:name β€” call an agent
  • GET /dashboard β€” interactive playground UI

API reference

new AgentRouter()

Create a new router instance.

router.register(name, agent, description?)

Register an agent under a URL slug.

ParameterTypeDescription
namestringURL-safe slug (e.g. "support")
agentAgentAgent instance
descriptionstring (optional)Shown in GET /agents

router.handle(request, env)

Handle an incoming Request. Returns a Response. Mount in your Worker’s fetch handler.


FileSystem

R2-backed file storage. Useful for agents that need to persist or read files (documents, knowledge bases, generated outputs).

Setup

Add an R2 binding to your wrangler.toml:

[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-workspace"

Add it to your Env type:

export interface Env {
BUCKET: R2Bucket;
}

Usage

import { FileSystem } from '@moon-wave/workspace';
const fs = new FileSystem(env.BUCKET, 'workspace-id');
// Write a file
await fs.write('notes.txt', 'hello world', 'text/plain');
// Read it back
const text = await fs.readText('notes.txt');
// List files
const files = await fs.list();
// Search across all text files
const results = await fs.grep('hello');
// β†’ [{ path: 'notes.txt', line: 'hello world', lineNumber: 1 }]
// Delete
await fs.delete('notes.txt');

API reference

const fs = new FileSystem(r2: R2Bucket, workspaceId: string)
fs.write(path, content, contentType?) β†’ Promise<FileEntry>
fs.read(path) β†’ Promise<ArrayBuffer | null>
fs.readText(path) β†’ Promise<string | null>
fs.list(prefix?) β†’ Promise<FileEntry[]>
fs.grep(query, filePrefix?) β†’ Promise<SearchResult[]>
fs.delete(path) β†’ Promise<void>