TaskFlow は何をしますか?
TaskFlowは、ジョブが1つのプロンプトや1つのデタッチされた実行を超えて存続する必要がある場合に使用しますが、それでも1つのオーナーセッション、1つのリターンコンテキスト、および作業を検査または再開するための1つの場所を維持したい場合に最適です。
いつ使用するか
- 1人のオーナーによるマルチステップのバックグラウンドワーク
- デタッチされたACPまたはサブエージェントタスクを待機する作業
- オーナーに1つの明確な更新を発行する必要がある可能性のあるジョブ
- ステップ間で小さな永続化された状態を必要とするジョブ
- 再起動やリビジョンの競合をクリーンに乗り越える必要があるプラグインまたはツールワーク
TaskFlowが所有するもの
- フローID
- オーナーセッションとリクエスタオリジン
currentStep、stateJson、waitJson- リンクされた子タスクとその親フローID
- 終了、失敗、キャンセル、待機中、ブロック中の状態
- 競合を起こさないミューテーションのためのリビジョントラッキング
分岐やビジネスロジックは所有しません。それらはLobster、acpx、または呼び出し元のコードに任せてください。
現在のランタイム形状
正規のプラグイン/ランタイムエントリポイント:
api.runtime.tasks.flowapi.runtime.taskFlowはエイリアスとして引き続き存在しますが、api.runtime.tasks.flowが正規の形状です
バインディング:
api.runtime.tasks.flow.fromToolContext(ctx): すでに信頼できるsessionKeyを持つツールコンテキストがある場合api.runtime.tasks.flow.bindSession({ sessionKey, requesterOrigin }): バインディングレイヤーがすでにセッションと配信コンテキストを解決している場合
管理フローのライフサイクル:
createManaged(...)runTask(...)setWaiting(...): 人または外部システムを待機する場合resume(...): 作業を続行できる場合finish(...)またはfail(...)requestCancel(...)またはcancel(...): ジョブ全体を停止する必要がある場合
設計上の制約
- コードがオーケストレーションを所有している場合は、管理 TaskFlow を使用してください。
- ミラーリングフローは、デタッチされたACP/サブエージェント作業のためにコアランタイムによって作成されます。このスキルは主に管理フローに関するものです。
stateJsonを永続化された状態バッグとして扱ってください。個別のsetFlowOutputやappendFlowOutputAPI はありません。- 作成後のすべてのミューテーションメソッドはリビジョンチェックされます。各ミューテーションが成功した後、最新の
flow.revisionを引き継いでください。 runTask(...)は子タスクをフローにリンクします。親のオーケストレーションが必要な場合、手動でデタッチされたタスクを作成する代わりにこれを使用してください。
形状の例
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 classify = taskFlow.runTask({
flowId: created.flowId,
runtime: "acp",
childSessionKey: "agent:main:subagent:classifier",
runId: "inbox-classify-1",
task: "Classify inbox messages",
status: "running",
startedAt: Date.now(),
lastEventAt: Date.now(),
});
if (!classify.created) {
throw new Error(classify.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: "finalize",
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,
});
条件分岐はランタイムの上に置く
状態とタスクのリンクにはフローランタイムを使用します。決定はオーサリングレイヤーに残してください:
business-> Slackに投稿して待機personal-> 今すぐオーナーに通知later-> 1日の終わりのサマリーバケットに追加
運用パターン
- 再開に必要な最小限の状態のみを保存します。
- 人間が読める待機理由は
blockedSummaryに、構造化された待機メタデータはwaitJsonに格納します。 - オーケストレーターが子作業のコンパクトな健全性ビューを必要とする場合は、
getTaskSummary(flowId)を使用します。 - 呼び出し元がフローのスケジューリングを直ちに停止させたい場合は、
requestCancel(...)を使用します。 - アクティブなリンクされた子タスクもキャンセルしたい場合は、
cancel(...)を使用します。
例
skills/taskflow/examples/inbox-triage.lobsterを参照skills/taskflow/examples/pr-intake.lobsterを参照- 具体的なルーティングパターンについては
skills/taskflow-inbox-triage/SKILL.mdを参照