chat
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
chat-app/
├── main.tsx # Entry point
├── deno.json # Config
├── public/ # Static assets (logos, icons)
│
├── backend/ # Server-side code
│ ├── index.ts # App factory
│ ├── config.ts # Configuration
│ ├── utils.ts # File utilities
│ ├── providers/ # Chat providers (Groq, etc.)
│ │ ├── index.ts
│ │ ├── types.ts
│ │ └── groq.ts
│ └── routes/ # API routes
│ ├── static.ts # HTML, CSS, JS, assets
│ ├── chat.ts # /api/chat endpoints
│ ├── jobs.ts # /api/jobs endpoints
│ ├── providers.ts # /api/providers
│ └── system.ts # /health
│
└── frontend/ # Client-side code
├── index.html # App HTML
├── monaco-utils.js # Monaco editor utilities
├── styles/ # CSS/SCSS
│ ├── build.ts
│ ├── app.scss
│ ├── components/
│ └── design-system/
└── app/ # Alpine.js modules
├── index.js # Main app component
├── state.js
├── storage.js
├── folders.js
├── chats.js
├── messaging.js
├── models.js
├── settings.js
├── editing.js
├── dragdrop.js
└── jobs.js # NEW: Jobs API integration
The jobs module is now available in the Alpine.js app as this.jobs:
// Example: Create and stream a chat job
async createBackgroundChat() {
const job = await this.jobs.createAndStreamChatJob(
[{ role: "user", content: "Tell me a story" }],
{
model: "llama-3.3-70b-versatile",
handlers: {
onData: (data) => {
// Handle streaming chunks
console.log("Chunk:", data.content);
},
onJob: (job) => {
// Handle job status changes
console.log("Job status:", job.status);
if (job.status === 'completed') {
console.log("Final result:", job.result);
}
},
onError: (error) => {
console.error("Job error:", error);
}
}
}
);
}
// Example: List all jobs
async viewAllJobs() {
const jobs = await this.jobs.listJobs();
console.log("All jobs:", jobs);
}
// Example: Cancel a running job
async stopJob(jobId) {
await this.jobs.cancelJob(jobId);
}
// Create a job
const response = await fetch('/api/jobs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'chat',
input: {
messages: [{ role: "user", content: "Hello" }],
model: "llama-3.3-70b-versatile"
}
})
});
const { id, status } = await response.json();
// Subscribe to job updates (SSE)
const eventSource = new EventSource(\`/api/jobs/\${id}/stream\`);
eventSource.addEventListener('job', (event) => {
const job = JSON.parse(event.data);
console.log("Job update:", job.status);
});
eventSource.addEventListener('data', (event) => {
const chunk = JSON.parse(event.data);
console.log("Data chunk:", chunk.content);
});
// Get job result
const jobResponse = await fetch(\`/api/jobs/\${id}\`);
const job = await jobResponse.json();
console.log("Result:", job.result);
- Concurrent execution: Run multiple jobs simultaneously
- Real-time updates: Subscribe via SSE to watch job progress
- Cancellation: Cancel running jobs at any time
- Status tracking:
pending→running→completed/error/cancelled
- Immediate chat: Use
/api/chatfor direct streaming (existing functionality) - Background jobs: Use
/api/jobsfor concurrent work you can check on later
- Run multiple chat completions concurrently
- Check on job status without blocking
- Cancel long-running jobs
- Foundation for future agentic/MCP tasks
# Test job creation curl -X POST http://localhost:8001/api/jobs \ -H "Content-Type: application/json" \ -d '{"type":"chat","input":{"messages":[{"role":"user","content":"Hello"}]}}' # Test job status curl http://localhost:8001/api/jobs/JOBID # Test SSE streaming curl -N http://localhost:8001/api/jobs/JOBID/stream
