Skip to content

Chapter 18 · Capstone 2: Slack On-Call Assistant (with Framework Comparison) ​

Chapter goals: Synthesize channels, durability, and subagents to build a Slack on-call assistant, and clarify the适用 boundary between Flue, Mastra, and pi-agent-core with a comparison table.

18.1 Capstone: Slack On-Call Assistant ​

Goal: someone @-mentions the bot in the on-call channel to report a故障 → the agent auto-classifies → for severe incidents, delegates to a subagent to draft an incident report → posts the result back to the channel.

typescript
// agents/oncall.ts — on-call assistant main agent
'use agent';
import { useModel, useSandbox, useSkill, useTool, useSubagent } from '@flue/runtime';
import { virtual } from '@flue/runtime/sandbox';
import incident from '../skills/incident/SKILL.md';
import { postSlackMessage, queryMetrics } from '../tools/ops.ts';

// Declare a subagent: the "expert" specialized in writing incident reports
useSubagent({
  name: 'report-writer',
  description: 'Draft a structured incident report (timeline/impact/review items) from故障 context',
  prompt: `You are an SRE report expert. Input is the incident tier and key metrics.
Output a Markdown report with three sections: [Timeline] [Impact] [Improvement Items].`,
});

export function OnCall() {
  useModel('anthropic/claude-sonnet-4-6');
  // This assistant only queries metrics and sends messages; virtual sandbox suffices (least privilege)
  useSandbox(virtual());
  useSkill(incident);
  useTool(queryMetrics);
  useTool(postSlackMessage);

  return `
Upon receiving an on-call channel message:
1. Classify per SKILL.md: P0 (全站不可用) / P1 (核心功能受损) / P2 (一般问题);
2. P2: give处理建议 directly and reply;
3. P0/P1: call query_metrics to pull the last 30 minutes of metrics as evidence;
4. Delegate to the report-writer subagent to generate the incident report;
5. Use post_slack_message to reply with the conclusion and report link.
`;
}
typescript
// src/channels/slack.ts — Slack channel接入
import { defineChannel } from '@flue/runtime';

export const slackChannel = defineChannel({
  name: 'oncall-slack',
  provider: 'slack', // Flue handles Slack signature verification
});
typescript
// src/main.ts — assembly: channel + durability + observability
import { createApp } from '@flue/runtime/node';
import { postgresAdapter } from '@flue/postgres';
import { observe } from '@flue/runtime';
import { Pool } from 'pg';
import { slackChannel } from './channels/slack.ts';

// Observability: error alerts + daily token cost (Chapter 13)
observe((event) => {
  if (event.type === 'error') console.error('[ALERT]', event);
});

createApp({
  database: postgresAdapter({ // Durability: on-call records survive crashes
    pool: new Pool({ connectionString: process.env.DATABASE_URL }),
  }),
})
  .channel(slackChannel, { secret: process.env.SLACK_SIGNING_SECRET! })
  .listen(3000);

This example ties together the main threads from Chapters 1–17: channel inbound → least-privilege sandbox → skill methodology → tool execution → subagent delegation → durable storage → observer monitoring.

18.2 Framework Comparison: Flue vs Mastra vs pi-agent-core ​

All three frameworks solve "building agents" in the TypeScript ecosystem, but their定位差异明显:

DimensionFlueMastrapi-agent-core
PositioningProgrammable Agent HarnessFull-stack AI应用框架Minimal Agent runtime
Core abstraction'use agent' function + harnessAgent / Workflow / Memory classesAgent class + event stream
Unique capabilitiesSandboxes, Channels, Durability contractWorkflow graph engine, Evals, StudioUnified multi-Provider LLM API, minimal心智负担
Execution environmentThree built-in sandboxes (virtual/local/remote container)Depends on host environment; no built-in sandbox conceptNo built-in sandbox (Pi官方 recommends containerization)
Inbound eventsChannels (verified HTTP ingress)Integrated into Next.js/Node app; received自行Implement自行
PersistenceDurability contract + Postgres adapterStorage layer + suspend/resumeSQLite session backend (community包)
Deployment shapesNode / Workers / GitHub Actions / GitLab / RenderNode service / Vercel / standalone serverEmbedded as a library in your process
Suitable forProduction agent teams needing "autonomous work"AI products with UI, heavy workflow orchestrationMinimal dependency, full runtime control
typescript
// Same task across three frameworks: weather tool call
// Flue —— declarative assembly, harness handles session/sandbox
'use agent';
import { useModel, useTool } from '@flue/runtime';
import getWeather from '../tools/weather.ts';
export function Weather() {
  useModel('anthropic/claude-sonnet-4-6');
  useTool(getWeather);
  return 'Fetch current weather for the user\'s location.';
}

// Mastra —— class-based, explicit tool definition
import { Agent } from '@mastra/core/agent';
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
const weatherTool = createTool({ /* ... */ });
export const weatherAgent = new Agent({
  id: 'weather',
  model: 'anthropic/claude-sonnet-4-6',
  tools: { weatherTool },
});

// pi-agent-core ——极简, function + event流
import { Agent } from 'pi-agent-core';
const agent = new Agent({ model: 'claude-sonnet-4-6' });
agent.on('tool_call', (tool) => { /* ... */ });

18.3 How to Choose ​

  • Need自主干活 with沙箱隔离 + 事件驱动 + Durability合约? → Flue;
  • Need带 UI 的 AI产品 with Workflow 图引擎 + Evals + Studio? → Mastra;
  • Need极简 + 完全掌控运行时 + 最小依赖? → pi-agent-core.

18.4 Chapter Summary ​

  • Capstone: Slack on-call assistant using channels + virtual sandbox + incident skill + query/post tools + report-writer subagent + Postgres durability;
  • Framework comparison: Flue (harness + sandboxes + channels + durability) vs Mastra (full-stack + workflows + evals + Studio) vs pi-agent-core (minimal + embedded);
  • Choose based on needs: autonomous production agents → Flue; UI products with heavy orchestration → Mastra; minimal embedded runtime → pi-agent-core.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. What sandbox is used for the on-call assistant and why?

2. What is the role of the report-writer subagent?

3. Why is Postgres used in this capstone?

4. When should you choose Flue over Mastra?

🛠️ Hands-On Exercises ​

  1. Build the full Slack on-call assistant: channel → agent → tools → subagent → Postgres durability; test with a simulated Slack webhook.
  2. Compare the code structure with a Mastra equivalent; note the differences in abstraction (function vs class).
  3. Deploy to a local Node server; send a simulated P0 incident via curl and verify the subagent report is generated and posted back.

Capstone 2 complete. Next: Capstone 3: Code Review Agent.