taskflow-inbox-triage

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TaskFlow inbox triage

TaskFlow 收件箱分类

This is a concrete example of how to think about TaskFlow without turning the core runtime into a DSL.
这是一个无需将核心运行时转换为DSL即可设计TaskFlow的具体示例。

Goal

目标

Triage inbox items with one owner flow:
  • business → post to Slack and wait for reply
  • personal → notify the owner now
  • everything else → keep for end-of-day summary
通过一个所有者流程对收件箱项目进行分类:
  • 商务类 → 发布至Slack并等待回复
  • 个人类 → 立即通知所有者
  • 其他所有类 → 保留至当日结束时汇总

Pattern

模式

  1. Create one flow for the inbox batch.
  2. Run one detached task to classify new items.
  3. Persist the routing state in
    stateJson
    .
  4. Move to
    waiting
    only when an outside reply is required.
  5. Resume the flow when classification or human input completes.
  6. Finish when the batch has been routed.
  1. 为收件箱批次创建一个流程。
  2. 运行一个独立任务对新项目进行分类。
  3. 将路由状态持久化到
    stateJson
    中。
  4. 仅当需要外部回复时切换至
    waiting
    状态。
  5. 当分类或人工输入完成后恢复流程。
  6. 当批次完成路由后结束流程。

Suggested
stateJson
shape

建议的
stateJson
结构

json
{
  "businessThreads": [],
  "personalItems": [],
  "eodSummary": []
}
Suggested
waitJson
when blocked on Slack:
json
{
  "kind": "reply",
  "channel": "slack",
  "threadKey": "slack:thread-1"
}
json
{
  "businessThreads": [],
  "personalItems": [],
  "eodSummary": []
}
当在Slack上被阻塞时建议的
waitJson
结构:
json
{
  "kind": "reply",
  "channel": "slack",
  "threadKey": "slack:thread-1"
}

Minimal runtime calls

最小化运行时调用

ts
const taskFlow = api.runtime.tasks.flow.fromToolContext(ctx);

const created = taskFlow.createManaged({
  controllerId: "my-plugin/inbox-triage",
  goal: "triage inbox",
  currentStep: "classify",
  stateJson: {
    businessThreads: [],
    personalItems: [],
    eodSummary: [],
  },
});

const child = taskFlow.runTask({
  flowId: created.flowId,
  runtime: "acp",
  childSessionKey: "agent:main:subagent:classifier",
  task: "Classify inbox messages",
  status: "running",
  startedAt: Date.now(),
  lastEventAt: Date.now(),
});

if (!child.created) {
  throw new Error(child.reason);
}

const waiting = taskFlow.setWaiting({
  flowId: created.flowId,
  expectedRevision: created.revision,
  currentStep: "await_business_reply",
  stateJson: {
    businessThreads: ["slack:thread-1"],
    personalItems: [],
    eodSummary: [],
  },
  waitJson: {
    kind: "reply",
    channel: "slack",
    threadKey: "slack:thread-1",
  },
});

if (!waiting.applied) {
  throw new Error(waiting.code);
}

const resumed = taskFlow.resume({
  flowId: waiting.flow.flowId,
  expectedRevision: waiting.flow.revision,
  status: "running",
  currentStep: "route_items",
  stateJson: waiting.flow.stateJson,
});

if (!resumed.applied) {
  throw new Error(resumed.code);
}

taskFlow.finish({
  flowId: resumed.flow.flowId,
  expectedRevision: resumed.flow.revision,
  stateJson: resumed.flow.stateJson,
});
ts
const taskFlow = api.runtime.tasks.flow.fromToolContext(ctx);

const created = taskFlow.createManaged({
  controllerId: "my-plugin/inbox-triage",
  goal: "triage inbox",
  currentStep: "classify",
  stateJson: {
    businessThreads: [],
    personalItems: [],
    eodSummary: [],
  },
});

const child = taskFlow.runTask({
  flowId: created.flowId,
  runtime: "acp",
  childSessionKey: "agent:main:subagent:classifier",
  task: "Classify inbox messages",
  status: "running",
  startedAt: Date.now(),
  lastEventAt: Date.now(),
});

if (!child.created) {
  throw new Error(child.reason);
}

const waiting = taskFlow.setWaiting({
  flowId: created.flowId,
  expectedRevision: created.revision,
  currentStep: "await_business_reply",
  stateJson: {
    businessThreads: ["slack:thread-1"],
    personalItems: [],
    eodSummary: [],
  },
  waitJson: {
    kind: "reply",
    channel: "slack",
    threadKey: "slack:thread-1",
  },
});

if (!waiting.applied) {
  throw new Error(waiting.code);
}

const resumed = taskFlow.resume({
  flowId: waiting.flow.flowId,
  expectedRevision: waiting.flow.revision,
  status: "running",
  currentStep: "route_items",
  stateJson: waiting.flow.stateJson,
});

if (!resumed.applied) {
  throw new Error(resumed.code);
}

taskFlow.finish({
  flowId: resumed.flow.flowId,
  expectedRevision: resumed.flow.revision,
  stateJson: resumed.flow.stateJson,
});

Related example

相关示例

  • skills/taskflow/examples/inbox-triage.lobster
  • skills/taskflow/examples/inbox-triage.lobster