mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-18 03:30:48 +08:00
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
119 lines
2.6 KiB
Markdown
119 lines
2.6 KiB
Markdown
---
|
|
name: taskflow-inbox-triage
|
|
description: Example TaskFlow authoring pattern for inbox triage. Use when messages need different treatment based on intent, with some routes notifying immediately, some waiting on outside answers, and others rolling into a later summary.
|
|
metadata: { "openclaw": { "emoji": "📥" } }
|
|
---
|
|
|
|
# TaskFlow inbox triage
|
|
|
|
This is a concrete example of how to think about TaskFlow without turning the core runtime into a DSL.
|
|
|
|
## 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
|
|
|
|
## 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.
|
|
|
|
## Suggested `stateJson` shape
|
|
|
|
```json
|
|
{
|
|
"businessThreads": [],
|
|
"personalItems": [],
|
|
"eodSummary": []
|
|
}
|
|
```
|
|
|
|
Suggested `waitJson` when blocked on Slack:
|
|
|
|
```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,
|
|
});
|
|
```
|
|
|
|
## Related example
|
|
|
|
- `skills/taskflow/examples/inbox-triage.lobster`
|