---
title: 工作流程執行
url: https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs
description: 追蹤代理的工作流程執行：其狀態與事件、工作何時完成、執行開啟期間的請求、預算以及限制。
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

「**Workflow**」（工作流程）是代理撰寫的程式，用來執行多個代理並合併它們傳回的結果。「**Workflow run**」（工作流程執行）是一個工作流程的一次執行。**[Dynamic workflows](https://platform.claude.com/docs/zh-TW/managed-agents/multiagent-orchestration#dynamic-workflows)**（動態工作流程）是讓代理能夠撰寫工作流程並啟動執行的功能。您可以透過代理 `multiagent` (csharp, go: `Multiagent`) 區塊中的 `workflows` (csharp, go: `Workflows`) 設定來開啟或關閉它。

伺服器會在背景執行工作流程。其代理在「[session threads](https://platform.claude.com/docs/zh-TW/managed-agents/session-threads)」（工作階段執行緒）中工作，這些執行緒由伺服器依工作流程的需要建立。您可以在工作階段的「[event stream](https://platform.claude.com/docs/zh-TW/managed-agents/events-and-streaming)」（事件串流）上追蹤執行。若要停止執行，請要求代理停止它（請參閱[在有開啟的執行時中斷工作階段](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)）。

## 動態工作流程的運作方式

工作階段所執行的代理會針對您描述的工作撰寫每個工作流程。工作流程是一個程式：它會執行其他代理、收集每個代理傳回的內容，並合併結果。如此一來，代理就能承擔對單一對話而言過於龐大的任務，例如審閱數百份文件。在執行期間，代理可以繼續工作或結束其回合，也可以查看執行的狀況。

<Frame>
  ![「Workflow run」（工作流程執行）的層次：執行本身、其兩個「phases」（階段），以及每個階段中的「agent threads」（代理執行緒）。結果會從一個階段傳遞到下一個階段。](https://platform.claude.com/docs/zh-TW/images/workflow-anatomy.svg)
</Frame>

此圖顯示一個範例。代理撰寫的每個工作流程都有自己的階段與代理。一個執行包含以下層次：

* **工作流程執行：** 伺服器會在背景執行工作流程，作為一個工作流程執行。一個工作階段可以同時開啟多個執行。
* **階段：** 工作流程可以將其工作劃分為「phases」（階段）。階段是執行中一個具名的環節，例如「Read the contracts」。您可以透過階段事件追蹤執行的進度。
* **代理執行緒：** 在一個階段中，程式會執行代理。每個代理在自己的[工作階段執行緒](https://platform.claude.com/docs/zh-TW/managed-agents/session-threads)中，依據程式撰寫的提示工作。執行中的代理可以是「inline agent」（內嵌代理），由程式自行定義；也可以是「predefined agent」（預先定義代理），由您列在 [`workflows` (csharp, go: `Workflows`) 的 `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) 清單](https://platform.claude.com/docs/zh-TW/managed-agents/multiagent-orchestration#predefined-and-inline-agents)中。關於每個執行緒顯示的內容，請參閱[執行的執行緒](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#a-runs-threads)。

程式可以執行以下操作：

* **同時執行多個代理：** 程式可以同時執行許多代理，這稱為「fanning out」（扇出）。在圖中，三個代理在第一個階段閱讀合約。
* **將結果從一個代理傳遞給另一個代理：** 每個代理都會將其結果傳回給程式。程式可以將該結果傳遞給另一個代理。在圖中，第二個階段的代理會使用前三個代理傳回的內容進行工作。執行中的代理也會在工作階段的沙箱中處理相同的檔案。
* **自行採取下一步：** 代理的結果會傳給程式，而不是傳給工作階段所執行的代理。程式會決定接下來執行哪些代理，並撰寫它們的提示。
* **重複與選擇：** 在一個階段內，程式可以重複工作，並根據代理傳回的內容選擇下一步。例如，它可以讓草稿持續修訂，直到審閱通過或用完設定的輪數為止。在圖中，程式可以在第二個階段內重複某個步驟。
* **處理失敗的代理：** 當其中一個代理失敗時，伺服器通常會在新的執行緒上再執行該代理一次，同時執行中的其他代理繼續工作。如果再次失敗，程式可以處理該失敗，或讓它結束執行。如果程式處理了失敗，執行仍可能以 `completed` 結束，因此請告訴工作階段所執行的代理回報哪些部分失敗了。

執行結束時，工作階段所執行的代理會獲得一個回合來閱讀執行所做的事。接著它可以回答您，或啟動另一個執行。[執行事件](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#run-events)列出了該回合延後到來或不會到來的情況。

您可以引導執行如何完成工作，例如如何拆分工作，以及代理失敗時該怎麼做。請參閱[告訴代理何時使用執行](https://platform.claude.com/docs/zh-TW/managed-agents/multiagent-orchestration#tell-the-agent-when-to-use-a-run)。

執行開始前沒有核准步驟：代理會在撰寫工作流程的同一回合中啟動執行。若要先審閱計畫，請告訴代理描述該執行並等待您的同意。執行開始時，`workflow_run.created` 會顯示其名稱、描述和階段。如果啟動了您未核准的執行，請要求代理停止它（請參閱[在有開啟的執行時中斷工作階段](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)）。

## 執行如何在各狀態之間轉換

<Frame>
  ![工作流程執行的狀態：「running」（執行中）、「idle」（閒置）與「ended」（已結束），以及使執行從一個狀態轉換到另一個狀態的原因。](https://platform.claude.com/docs/zh-TW/images/workflow-run-states.svg)
</Frame>

執行以「running」（執行中）或「idle」（閒置）狀態開始。例如，達到預算會暫停執行中的執行，使其變為閒置；接著提高或移除預算會使其再次執行，除非它也因中斷而暫停。當工作流程完成、代理停止它、它失敗、其存續時間已過，或工作階段被封存時，執行中的執行就會結束。閒置的執行也可能結束，例如當代理停止它或工作階段被封存時。

執行從其 `workflow_run.created` 事件到其 `workflow_run.status_ended` 事件之間都處於**開啟**狀態，無論它是執行中還是閒置。執行在暫停期間（例如達到工作階段的預算時）處於閒置狀態。執行有[存續時間](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#limits)，代理可以在啟動執行時設定它。執行等待您的用戶端所花費的時間會計入該存續時間。暫停不會停止執行存續時間的流逝，因此持續暫停的執行可能會以 `timeout_error` 結束。以下事件會回報執行的開始、其階段以及其結束。在預算處暫停也會傳送一個事件。中斷後的暫停可能不會傳送任何事件。每個 `workflow_run.*` 事件都包含 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`)，只有在未建立任何執行的 `workflow_run.error` 上，它才會是 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`)。

## 執行事件

執行事件會出現在工作階段的事件串流（即主要執行緒的串流）上，列出工作階段的事件時也會傳回它們。執行事件不會觸發 [webhooks](https://platform.claude.com/docs/zh-TW/managed-agents/webhooks)。來自執行之執行緒的狀態事件也會出現在同一個串流上。每個事件都會在 `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) 中指明其執行緒，而執行的執行緒就是其 `session.thread_created` 事件帶有該執行之 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) 的那些執行緒。

| 事件                                                      | 何時出現                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | 該怎麼做                                                                                                                                                                                                                                                                                                                     |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `workflow_run.created`                                  | 代理啟動了一次執行。包含 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`)（`wrun_…`）、執行的 `name` (csharp, go: `Name`) 和 `description` (csharp, go: `Description`)，以及 `phases` (csharp, go: `Phases`)，即工作流程宣告的階段，每個階段都有 `id` (csharp, go: `ID`)、`name` (csharp, go: `Name`) 和 `description` (csharp, go: `Description`)。當工作流程未提供描述時，`description` (csharp, go: `Description`) 為 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`)。`phases` (csharp, go: `Phases`) 一定存在，且可以為空。執行和階段的 `name` (csharp, go: `Name`) 和 `description` (csharp, go: `Description`) 是模型撰寫的文字，因此可能重複您請求中的字詞。執行的 `name` (csharp, go: `Name`) 也可能是伺服器指派的名稱。 | 將該執行追蹤為開啟狀態。顯示其 `name` (csharp, go: `Name`)，以及相對於 `phases` (csharp, go: `Phases`) 的進度。                                                                                                                                                                                                                                   |
| `workflow_run.status_running`                           | 當執行開始執行時（可能在 `created` 之後一段時間），以及每次在預算處暫停後恢復時。中斷後的恢復可能不會傳送此事件。以閒置狀態開始的執行可能會先收到 `workflow_run.status_idle`。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | 將執行顯示為執行中。                                                                                                                                                                                                                                                                                                               |
| `workflow_run.status_idle`                              | 執行已暫停，例如在達到工作階段的預算時。此事件不會說明原因。中斷後的暫停可能不會傳送此事件。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | 若要繼續，請參閱[成本與預算](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#cost-and-budgets)或[在有開啟的執行時中斷工作階段](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)。                                                                                          |
| `workflow_run.phase_started`、`workflow_run.phase_ended` | 工作流程進入或離開了一個階段，或執行的結束關閉了一個仍開啟的階段。結束事件不會說明該階段的工作是否已完成。兩者都包含 `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`)。結束事件還有 `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`)，即它所關閉之開始事件的 `id` (csharp, go: `ID`)。兩者都沒有階段的名稱：請在 `workflow_run.created` 的 `phases` (csharp, go: `Phases`) 中依 `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`) 查詢。                                                                                                                                                             | 更新進度。階段會依 `phases` (csharp, go: `Phases`) 的順序一次執行一個，每個最多一次，但 API 不保證這一點。請依 `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`) 將階段的結束與其開始配對。請處理多個開啟的階段、不在 `phases` (csharp, go: `Phases`) 中的階段，以及列出但從未開始的階段，即使在已完成的執行中也是如此。每個開始的階段也都會在執行的 `workflow_run.status_ended` 之前結束。 |
| `workflow_run.status_ended`                             | 執行已結束。一定是該執行的 `workflow_run.*` 事件中的最後一個。包含 `result` (csharp, go: `Result`)。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | 讀取 `result` (csharp, go: `Result`)（見下一個表格）。接著代理會獲得一個回合來閱讀執行如何結束。在達到預算時，或主要執行緒等待您的用戶端時，該回合會延後到來。中斷後，該回合可能不會到來：請傳送 `user.message`，或自行讀取 `result` (csharp, go: `Result`)。封存或終止後，該回合不會到來。                                                                                                                                    |
| `workflow_run.error`                                    | 伺服器回報執行的錯誤，或它拒絕的啟動。以 `error` 結束的執行會在其 `workflow_run.status_ended` 之前收到此事件，帶有相同的錯誤。包含 `error` (csharp, go: `Error`)：一個 `type` (csharp, go: `Type`) 和一個可安全記錄的 `message` (csharp, go: `Message`)。未建立任何執行時，`workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) 為 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`)。                                                                                                                                                                                                                                                                                                      | 記錄它，且不要將其視為執行的結束。如果 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) 為 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`)，表示沒有啟動任何執行。否則請持續追蹤該執行，直到其 `workflow_run.status_ended`。                                                                       |

| `result`                        | 意義                                                                                                                                                                                   |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `{"type": "completed"}`         | 工作流程已執行完畢。結果不會說明工作是否通過。即使其執行緒上的工作失敗，或某個執行緒無法建立，執行仍可能以 `completed` 結束。若要找出失敗的工作，請閱讀每個[執行的執行緒](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#a-runs-threads)的事件。 |
| `{"type": "stopped"}`           | 代理停止了執行，或工作階段已被封存。此事件不會說明是哪一種。請勿將這些視為唯一的原因。                                                                                                                                          |
| `error` 搭配 `timeout_error`      | 執行已達到其[存續時間](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#limits)，代理可以設定它。                                                                                    |
| `error` 搭配 `program_error`      | 工作流程失敗。其程式碼失敗，或違反了工作流程的規則（限制除外）。或者執行的某個執行緒失敗或無法建立，而工作流程讓此情況結束了執行。                                                                                                                    |
| `error` 搭配 `thread_limit_error` | 執行超過了其[工作流程啟動之代理數量的限制](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#limits)。                                                                                  |
| `error` 搭配 `unknown_error`      | 伺服器無法繼續執行，或執行超過了伺服器對工作流程的其他限制之一。                                                                                                                                                     |

錯誤結果看起來像 `{"type": "error", "error": {"type": "timeout_error", "message": "..."}}`，其中 `message` 可安全記錄。請將無法辨識的 `result.type` 視為以其他方式結束的執行，並將無法辨識的 `error.type` 視為錯誤。當工作階段所依賴的某項事物失敗時，例如模型、MCP 伺服器、憑證或帳單，失敗之執行緒的串流會收到 `session.error`。這本身不會結束執行。但如果它導致執行的某個執行緒失敗，而工作流程讓此情況結束執行，執行就會以 `program_error` 結束。

例如，您詢問[合約審查代理](https://platform.claude.com/docs/zh-TW/managed-agents/multiagent-orchestration#turn-on-dynamic-workflows) 300 份合約中有哪些包含控制權變更條款，代理便啟動了一個執行：

1. `workflow_run.created` 將執行命名為「Find change-of-control clauses」，並在 `phases` (csharp, go: `Phases`) 中列出階段「Read the contracts」和「Reconcile the findings」。接著是 `workflow_run.status_running`。
2. 階段事件標示每個階段，而執行建立的每個執行緒都會傳送帶有該執行之 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) 的 `session.thread_created`。
3. `workflow_run.status_ended` 帶著 `result: {"type": "completed"}` 出現。
4. 代理回答「300 份合約中有 41 份包含此條款」，接著 `session.status_idle` 帶著 `end_turn` 出現。

執行的第一個事件會列出其階段：

```json
{
  "type": "workflow_run.created",
  "id": "sevt_01abc...",
  "workflow_run_id": "wrun_01J8XkN5uT3vHpLqRfWdY2",
  "name": "Find change-of-control clauses",
  "description": "Reads each contract and lists those that have the clause.",
  "phases": [
    {
      "id": "wrph_01Kd3a1f3",
      "name": "Read the contracts",
      "description": "Reads each contract for the clause."
    },
    { "id": "wrph_01Kd3b7c9", "name": "Reconcile the findings", "description": null }
  ],
  "processed_at": "2026-10-09T14:01:45Z"
}
```

每個階段事件都會以 `workflow_run_phase_id` 指明其階段。那是 `phases` 中的一個 `id`，但 API 不保證這一點：

```json
{
  "type": "workflow_run.phase_started",
  "id": "sevt_01def...",
  "workflow_run_id": "wrun_01J8XkN5uT3vHpLqRfWdY2",
  "workflow_run_phase_id": "wrph_01Kd3a1f3",
  "processed_at": "2026-10-09T14:01:46Z"
}
```

執行的最後一個事件會回報它如何結束：

```json
{
  "type": "workflow_run.status_ended",
  "id": "sevt_01ghi...",
  "workflow_run_id": "wrun_01J8XkN5uT3vHpLqRfWdY2",
  "result": { "type": "completed" },
  "processed_at": "2026-10-09T14:09:12Z"
}
```

## 執行的執行緒

執行中的每個代理都在自己的[工作階段執行緒](https://platform.claude.com/docs/zh-TW/managed-agents/session-threads)中工作，該執行緒由伺服器依工作流程需要而建立。您可以像處理任何子執行緒一樣列出、讀取和串流執行的執行緒，並從主要串流回應它們的工具呼叫。若要停止它們，請要求代理停止該執行（請參閱[在有開啟的執行時中斷工作階段](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)）。

* **分組：** 執行的執行緒帶有該執行的 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`)，宣告它的 `session.thread_created` 事件也是如此。其他執行緒以及宣告它們的 `session.thread_created` 事件，其 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) 設為 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`)。
* **代理：** `agent` (csharp, go: `Agent`) 顯示該執行緒所執行的代理。對於您在 `multiagent` (csharp, go: `Multiagent`) 中 [`workflows` (csharp, go: `Workflows`) 的 `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) 清單](https://platform.claude.com/docs/zh-TW/managed-agents/multiagent-orchestration#turn-on-dynamic-workflows)中列出的代理，`agent` (csharp, go: `Agent`) 帶有該代理的 `id` (csharp, go: `ID`) 和 `version` (csharp, go: `Version`)，與您列出之子代理的執行緒相同。對於工作流程定義的代理（內嵌代理），`agent` (csharp, go: `Agent`) 的 `type` 為 `inline`，且沒有 `id` (csharp, go: `ID`) 或 `version` (csharp, go: `Version`)。它帶有工作流程撰寫的系統提示，而非工作階段代理的系統提示。它也帶有工作流程給予的名稱和描述。如果工作流程未提供名稱，伺服器會指派一個。它使用工作階段代理（即工作階段所執行的代理）的模型。它的工具、MCP 伺服器和技能是工作階段代理的子集。它會取得全部，但 API 不保證這一點。它的工具會保留其權限政策。
* **執行緒共用的內容：** 執行的執行緒在工作階段的沙箱中工作，因此每個執行緒都處理相同的檔案。這包括工作階段所掛載之記憶體儲存區的檔案。工作流程定義的代理會以工作階段為其 MCP 伺服器解析的憑證來使用這些伺服器。每個執行緒都有自己的對話歷史記錄。
* **事件：** 執行之執行緒的 `session.thread_created`、`session.thread_status_running`、`session.thread_status_idle` 與 `session.thread_status_terminated` 事件也會出現在主要串流上（請參閱[執行事件](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#run-events)）。其訊息事件則保留在它自己的串流上。其執行緒 webhooks 的傳送方式與任何子執行緒相同。關於執行緒自身串流所記錄的內容，請參閱[工作階段執行緒事件](https://platform.claude.com/docs/zh-TW/managed-agents/session-threads#session-thread-events)。
* **階段：** 沒有任何事件或欄位說明執行緒在哪個階段中工作，而同一次執行的執行緒可能有相同的 `agent_name`。請透過階段事件追蹤執行的進度，並以 `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) 區分其執行緒。
* **封存：** 伺服器最遲會在執行結束時封存每個執行緒。一旦執行緒傳回其結果或執行不再需要它，伺服器可能會更早封存它。如果此時執行緒仍在執行中或正在等待您的用戶端，伺服器會先停止它。已封存的執行緒會保留在執行緒清單中，狀態為 `terminated`。您不需要自行封存執行的執行緒。
* **工具：** 執行可能會為同一項工作建立多個執行緒，因此請確保您的代理所呼叫的工具可以安全地被呼叫兩次。

<Tip>
  您可以向代理索取它為您的請求所撰寫的工作流程。請等到執行結束且工作階段為 `idle`。接著傳送一則 `user.message`，要求代理逐字印出它用來啟動執行的工作流程，且不要啟動另一個執行。

  ```text wrap
  Print the workflow that you started the run with, word for word, in one code block. Do not start another run.
  ```
</Tip>

## 得知工作何時完成

當執行正在執行時，預期工作階段會保持 `running`，即使其執行緒都沒有在工作也是如此。當沒有執行緒在工作且有執行緒正在等待您的用戶端時，它會以 `requires_action` 變為 `idle`。閒置本身並不代表工作已完成。當以下兩者皆成立時，工作才算完成：

1. 您看到建立的每個執行都已有其 `workflow_run.status_ended`。
2. 在那之後，出現一個 `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) 為 `end_turn` 的 `session.status_idle`，且它不是由您自己的請求（例如中斷）所造成。中斷之後，只計算在您下一則 `user.message` 或 `user.define_outcome` 之後出現的閒置。

* **已暫停的執行：** 已暫停的執行不會讓工作階段保持 `running`，因此工作階段可能在執行仍開啟時變為閒置。例如在達到預算時，工作階段會以 `budget_reached` 變為閒置。在執行結束之前，工作都尚未完成。
* **另一個執行：** 代理在閱讀結果時可以啟動新的執行，因此請再次檢查。
* **成果：** 如果您[定義了成果](https://platform.claude.com/docs/zh-TW/managed-agents/define-outcomes)，在執行開啟期間（無論是執行中還是閒置）都不會開始評估。代理閱讀執行結果的那個回合可以開始評估。
* **`retries_exhausted`：** 代理的回合因錯誤而失敗：重試次數已用盡，或該錯誤無法重試，例如帳單失敗。出現此閒置時，執行可能仍在執行中。如果某個執行已結束而代理尚未閱讀其結果，伺服器會在沒有您輸入的情況下開始新的回合。工作階段會再次變為 `running`，因此請等待下一次閒置。如果工作階段保持閒置，請閱讀在它之前出現的 `session.error` 並修正原因。接著傳送 `user.message`，或自行讀取每個執行的 `result` (csharp, go: `Result`)。

## 追蹤執行

此範例會從您的訊息到代理的回答追蹤一個工作階段。它會開啟串流並傳送訊息。接著它會執行以下操作：

* **追蹤每個執行**，從其 `workflow_run.created` 到其 `workflow_run.status_ended`，並在每個階段開始時將其印出。
* **回應自訂工具呼叫**，在每個 `agent.custom_tool_use` 出現時回應，因為執行的執行緒可能在工作階段保持 `running` 時等待您的用戶端。如果您代理的工具會[要求確認](https://platform.claude.com/docs/zh-TW/managed-agents/events-and-streaming#tool-confirmation)，請新增一個分支，回應每個 `evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`) 為 `ask` 的 `agent.tool_use` 或 `agent.mcp_tool_use`。此範例沒有這樣的分支，因為允許每個呼叫的分支會將 `always_ask` 變成一律允許。
* **停止**，當[工作完成](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#know-when-the-work-is-done)時：沒有開啟的執行，且工作階段以 `end_turn` 變為閒置。如果工作階段終止，它也會停止。在以 `requires_action` 以外的任何其他停止原因（例如 `budget_reached`、`retries_exhausted` 或 `refusal`）閒置時，它會印出原因並停止，因此請在您自己的程式碼中處理這些情況。即使伺服器即將自行開始新的回合，它在遇到 `retries_exhausted` 時也會停止。遇到 `requires_action` 時，以及在有執行開啟時遇到 `end_turn` 時，它會繼續等待。

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    此工作流程需要的邏輯超出單一 shell 指令所能處理的範圍。請使用 [Claude SDK](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/overview) 來執行。
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    此工作流程需要的邏輯超出單一 shell 指令所能處理的範圍。請使用 [Claude SDK](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/overview) 來執行。
  </CodeGroupItem>

  ```python Python
  open_runs: dict[str, str] = {}  # workflow_run_id -> run name
  phase_names: dict[tuple[str, str], str] = {}  # (run ID, phase ID) -> phase name

  # 先開啟串流，再傳送使用者訊息
  with client.beta.sessions.events.stream(session_id) as stream:
      client.beta.sessions.events.send(
          session_id,
          events=[
              {
                  "type": "user.message",
                  "content": [
                      {
                          "type": "text",
                          "text": "Which contracts in /contracts have a change-of-control clause?",
                      },
                  ],
              },
          ],
      )

      for event in stream:
          match event.type:
              case "workflow_run.created":
                  open_runs[event.workflow_run_id] = event.name
                  for phase in event.phases:
                      phase_names[event.workflow_run_id, phase.id] = phase.name
                  print(f"Run started: {event.name}")
              case "workflow_run.phase_started":
                  phase_id = event.workflow_run_phase_id
                  key = (event.workflow_run_id, phase_id)
                  print(f"  Phase: {phase_names.get(key, phase_id)}")
              case "workflow_run.status_ended":
                  name = open_runs.pop(event.workflow_run_id, event.workflow_run_id)
                  print(f"Run ended: {name} ({event.result.type})")
              case "agent.custom_tool_use":
                  # 事件抵達時再回應。run 的執行緒可能會等待您的
                  # 用戶端，而工作階段仍保持執行中。
                  result = call_tool(event.name, event.input)
                  try:
                      client.beta.sessions.events.send(
                          session_id,
                          events=[
                              {
                                  "type": "user.custom_tool_result",
                                  "custom_tool_use_id": event.id,
                                  "content": [{"type": "text", "text": result}],
                              },
                          ],
                      )
                  except anthropic.BadRequestError as error:
                      # 若結果太晚送達（在伺服器封存該呼叫的執行緒之後），
                      # 伺服器會拒絕該結果。請繼續追蹤該 run。
                      print(f"  Answer to {event.name} refused: {error.message}")
              case "session.status_idle":
                  # 當所有 run 皆已結束且代理已完成其回合時即完成
                  if not open_runs and event.stop_reason.type == "end_turn":
                      break
                  # 帶有 requires_action 的 idle 會等待您的用戶端，因此請繼續讀取。
                  # 若為其他停止原因，請印出該原因並停止。
                  if event.stop_reason.type not in ("end_turn", "requires_action"):
                      print(f"Session idle: {event.stop_reason.type}")
                      break
              case "session.status_terminated":
                  break
  ```

  ```typescript TypeScript
  const openRuns = new Map<string, string>(); // workflow_run_id -> run name
  const phaseNames = new Map<string, string>(); // "run ID:phase ID" -> phase name

  // 先開啟串流，再傳送使用者訊息
  const stream = await client.beta.sessions.events.stream(sessionId);
  await client.beta.sessions.events.send(sessionId, {
    events: [
      {
        type: "user.message",
        content: [
          {
            type: "text",
            text: "Which contracts in /contracts have a change-of-control clause?"
          }
        ]
      }
    ]
  });

  events: for await (const event of stream) {
    switch (event.type) {
      case "workflow_run.created":
        openRuns.set(event.workflow_run_id, event.name);
        for (const phase of event.phases) {
          phaseNames.set(`${event.workflow_run_id}:${phase.id}`, phase.name);
        }
        console.log(`Run started: ${event.name}`);
        break;
      case "workflow_run.phase_started": {
        const phaseId = event.workflow_run_phase_id;
        const phaseName = phaseNames.get(`${event.workflow_run_id}:${phaseId}`);
        console.log(`  Phase: ${phaseName ?? phaseId}`);
        break;
      }
      case "workflow_run.status_ended": {
        const name = openRuns.get(event.workflow_run_id) ?? event.workflow_run_id;
        openRuns.delete(event.workflow_run_id);
        console.log(`Run ended: ${name} (${event.result.type})`);
        break;
      }
      case "agent.custom_tool_use": {
        // 事件抵達時再回應。run 的執行緒可能會等待您的
        // 用戶端，而工作階段仍保持執行中。
        const result = await callTool(event.name, event.input);
        try {
          await client.beta.sessions.events.send(sessionId, {
            events: [
              {
                type: "user.custom_tool_result",
                custom_tool_use_id: event.id,
                content: [{ type: "text", text: result }]
              }
            ]
          });
        } catch (error) {
          // 若結果太晚送達（在伺服器封存該呼叫的執行緒之後），
          // 伺服器會拒絕該結果。請繼續追蹤該 run。
          if (!(error instanceof Anthropic.BadRequestError)) {
            throw error;
          }
          console.log(`  Answer to ${event.name} refused: ${error.message}`);
        }
        break;
      }
      case "session.status_idle": {
        // 當所有 run 皆已結束且代理程式已完成其回合時即完成
        const reason = event.stop_reason.type;
        if (openRuns.size === 0 && reason === "end_turn") {
          break events;
        }
        // 帶有 requires_action 的 idle 正在等待您的用戶端，因此請繼續讀取。
        // 若為其他停止原因，請將其印出並停止。
        if (reason !== "end_turn" && reason !== "requires_action") {
          console.log(`Session idle: ${reason}`);
          break events;
        }
        break;
      }
      case "session.status_terminated":
        break events;
    }
  }
  ```

  ```csharp C#
  var openRuns = new Dictionary<string, string>(); // workflow_run_id -> run name
  var phaseNames = new Dictionary<(string, string), string>(); // (run ID, phase ID) -> phase name

  // 先開啟串流，再傳送使用者訊息。raw-response 呼叫
  // 會立即開啟串流。一般呼叫則會等到第一次讀取時才開啟。
  using var stream = await client.Beta.Sessions.Events.WithRawResponse.StreamStreaming(sessionId);
  await client.Beta.Sessions.Events.Send(sessionId, new()
  {
      Events =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Type = BetaManagedAgentsTextBlockType.Text,
                      Text = "Which contracts in /contracts have a change-of-control clause?",
                  },
              ],
          },
      ],
  });

  await foreach (var streamEvent in stream.Enumerate())
  {
      if (streamEvent.Value is BetaManagedAgentsWorkflowRunCreatedEvent created)
      {
          openRuns[created.WorkflowRunID] = created.Name;
          foreach (var listed in created.Phases)
          {
              phaseNames[(created.WorkflowRunID, listed.ID)] = listed.Name;
          }
          Console.WriteLine($"Run started: {created.Name}");
      }
      else if (streamEvent.Value is BetaManagedAgentsWorkflowRunPhaseStartedEvent phase)
      {
          var phaseId = phase.WorkflowRunPhaseID;
          var key = (phase.WorkflowRunID, phaseId);
          Console.WriteLine($"  Phase: {phaseNames.GetValueOrDefault(key, phaseId)}");
      }
      else if (streamEvent.Value is BetaManagedAgentsWorkflowRunStatusEndedEvent ended)
      {
          var name = openRuns.GetValueOrDefault(ended.WorkflowRunID, ended.WorkflowRunID);
          openRuns.Remove(ended.WorkflowRunID);
          var outcome = ended.Result.Value switch
          {
              BetaManagedAgentsWorkflowRunResultCompleted => "completed",
              BetaManagedAgentsWorkflowRunResultStopped => "stopped",
              BetaManagedAgentsWorkflowRunResultError => "error",
              _ => "ended",
          };
          Console.WriteLine($"Run ended: {name} ({outcome})");
      }
      else if (streamEvent.Value is BetaManagedAgentsAgentCustomToolUseEvent toolUse)
      {
          // 事件抵達時再回應。run 的執行緒可能會等待您的
          // 用戶端，而工作階段仍保持執行中。
          var result = await CallTool(toolUse.Name, toolUse.Input);
          try
          {
              await client.Beta.Sessions.Events.Send(sessionId, new()
              {
                  Events =
                  [
                      new BetaManagedAgentsUserCustomToolResultEventParams
                      {
                          Type = BetaManagedAgentsUserCustomToolResultEventParamsType.UserCustomToolResult,
                          CustomToolUseID = toolUse.ID,
                          Content =
                          [
                              new BetaManagedAgentsTextBlock
                              {
                                  Type = BetaManagedAgentsTextBlockType.Text,
                                  Text = result,
                              },
                          ],
                      },
                  ],
              });
          }
          catch (AnthropicBadRequestException error)
          {
              // 若結果來得太晚（伺服器已封存該呼叫的執行緒之後），
              // 伺服器會拒絕該結果。請繼續追蹤該 run。
              Console.WriteLine($"  Answer to {toolUse.Name} refused: {error.Message}");
          }
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusIdleEvent idle)
      {
          // 當所有 run 皆已結束且代理程式已完成其回合時即完成
          var finished = idle.StopReason?.Value is BetaManagedAgentsSessionEndTurn;
          if (openRuns.Count == 0 && finished)
          {
              break;
          }
          // 帶有 requires_action 的 idle 會等待您的用戶端，因此請繼續讀取。
          // 若為其他停止原因，則印出該原因並停止。
          if (!finished && idle.StopReason?.Value is not BetaManagedAgentsSessionRequiresAction)
          {
              var reason = idle.StopReason?.Json.GetProperty("type").GetString();
              Console.WriteLine($"Session idle: {reason}");
              break;
          }
      }
      else if (streamEvent.Value is BetaManagedAgentsSessionStatusTerminatedEvent)
      {
          break;
      }
  }
  ```

  ```go Go
  	openRuns := map[string]string{}      // workflow_run_id -> run name
  	phaseNames := map[[2]string]string{} // {run ID, phase ID} -> phase name

  	// 先開啟串流，再傳送使用者訊息
  	stream := client.Beta.Sessions.Events.StreamEvents(ctx, sessionID, anthropic.BetaSessionEventStreamParams{})
  	defer stream.Close()

  	if _, err := client.Beta.Sessions.Events.Send(ctx, sessionID, anthropic.BetaSessionEventSendParams{
  		Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  						Text: "Which contracts in /contracts have a change-of-control clause?",
  					},
  				}},
  			},
  		}},
  	}); err != nil {
  		panic(err)
  	}

  events:
  	for stream.Next() {
  		switch event := stream.Current().AsAny().(type) {
  		case anthropic.BetaManagedAgentsWorkflowRunCreatedEvent:
  			openRuns[event.WorkflowRunID] = event.Name
  			for _, phase := range event.Phases {
  				phaseNames[[2]string{event.WorkflowRunID, phase.ID}] = phase.Name
  			}
  			fmt.Printf("Run started: %s\n", event.Name)
  		case anthropic.BetaManagedAgentsWorkflowRunPhaseStartedEvent:
  			phaseName, ok := phaseNames[[2]string{event.WorkflowRunID, event.WorkflowRunPhaseID}]
  			if !ok {
  				phaseName = event.WorkflowRunPhaseID
  			}
  			fmt.Printf("  Phase: %s\n", phaseName)
  		case anthropic.BetaManagedAgentsWorkflowRunStatusEndedEvent:
  			name, ok := openRuns[event.WorkflowRunID]
  			if !ok {
  				name = event.WorkflowRunID
  			}
  			delete(openRuns, event.WorkflowRunID)
  			fmt.Printf("Run ended: %s (%s)\n", name, event.Result.Type)
  		case anthropic.BetaManagedAgentsAgentCustomToolUseEvent:
  			// 事件抵達時再回應。run 的執行緒可能會等待您的
  			// 用戶端，而工作階段仍保持執行中。
  			result := callTool(event.Name, event.Input)
  			if _, err := client.Beta.Sessions.Events.Send(ctx, sessionID, anthropic.BetaSessionEventSendParams{
  				Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  					OfUserCustomToolResult: &anthropic.BetaManagedAgentsUserCustomToolResultEventParams{
  						Type:            anthropic.BetaManagedAgentsUserCustomToolResultEventParamsTypeUserCustomToolResult,
  						CustomToolUseID: event.ID,
  						Content: []anthropic.BetaManagedAgentsUserCustomToolResultEventParamsContentUnion{{
  							OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  								Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  								Text: result,
  							},
  						}},
  					},
  				}},
  			}); err != nil {
  				// 若結果太晚送達（在伺服器封存該呼叫的執行緒之後），
  				// 伺服器會拒絕該結果。請繼續追蹤該 run。
  				var apiErr *anthropic.Error
  				if !errors.As(err, &apiErr) || apiErr.StatusCode != http.StatusBadRequest {
  					panic(err)
  				}
  				fmt.Printf("  Answer to %s refused: %v\n", event.Name, err)
  			}
  		case anthropic.BetaManagedAgentsSessionStatusIdleEvent:
  			// 當所有 run 皆已結束且代理已完成其回合時即完成
  			switch event.StopReason.AsAny().(type) {
  			case anthropic.BetaManagedAgentsSessionEndTurn:
  				if len(openRuns) == 0 {
  					break events
  				}
  			// 帶有 requires_action 的 idle 會等待您的用戶端，因此請繼續讀取。
  			// 若為其他停止原因，則印出該原因並停止。
  			case anthropic.BetaManagedAgentsSessionRequiresAction:
  			default:
  				fmt.Printf("Session idle: %s\n", event.StopReason.Type)
  				break events
  			}
  		case anthropic.BetaManagedAgentsSessionStatusTerminatedEvent:
  			break events
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  ```

  ```java Java
  var openRuns = new HashMap<String, String>(); // workflow_run_id -> run name
  var phaseNames = new HashMap<String, String>(); // "run ID:phase ID" -> phase name

  // 先開啟串流，再傳送使用者訊息
  try (var stream = client.beta().sessions().events().streamStreaming(sessionId)) {
      client.beta().sessions().events().send(
          sessionId,
          EventSendParams.builder()
              .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
                  .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
                  .addTextContent("Which contracts in /contracts have a change-of-control clause?")
                  .build())
              .build()
      );

      Iterable<BetaManagedAgentsStreamSessionEvents> events = stream.stream()::iterator;
      events:
      for (var event : events) {
          switch (event.type().value()) {
              case WORKFLOW_RUN_CREATED -> {
                  var created = event.asWorkflowRunCreated();
                  openRuns.put(created.workflowRunId(), created.name());
                  created.phases().forEach(phase ->
                      phaseNames.put(created.workflowRunId() + ":" + phase.id(), phase.name()));
                  IO.println("Run started: " + created.name());
              }
              case WORKFLOW_RUN_PHASE_STARTED -> {
                  var started = event.asWorkflowRunPhaseStarted();
                  var phaseId = started.workflowRunPhaseId();
                  var key = started.workflowRunId() + ":" + phaseId;
                  IO.println("  Phase: " + phaseNames.getOrDefault(key, phaseId));
              }
              case WORKFLOW_RUN_STATUS_ENDED -> {
                  var ended = event.asWorkflowRunStatusEnded();
                  var name = openRuns.getOrDefault(ended.workflowRunId(), ended.workflowRunId());
                  openRuns.remove(ended.workflowRunId());
                  var result = ended.result();
                  var outcome = result.isCompleted() ? "completed"
                      : result.isStopped() ? "stopped"
                      : result.isError() ? "error"
                      : "ended";
                  IO.println("Run ended: " + name + " (" + outcome + ")");
              }
              case AGENT_CUSTOM_TOOL_USE -> {
                  // 事件抵達時再回應。run 的執行緒可能會等待您的
                  // 用戶端，而工作階段仍保持執行中。
                  var toolUse = event.asAgentCustomToolUse();
                  var result = callTool(toolUse.name(), toolUse.input());
                  try {
                      client.beta().sessions().events().send(
                          sessionId,
                          EventSendParams.builder()
                              .addEvent(BetaManagedAgentsUserCustomToolResultEventParams.builder()
                                  .type(BetaManagedAgentsUserCustomToolResultEventParams.Type.USER_CUSTOM_TOOL_RESULT)
                                  .customToolUseId(toolUse.id())
                                  .addTextContent(result)
                                  .build())
                              .build());
                  } catch (BadRequestException e) {
                      // 若結果太晚送達（在伺服器封存該呼叫的執行緒之後），
                      // 伺服器會拒絕該結果。請繼續追蹤該 run。
                      IO.println("  Answer to " + toolUse.name() + " refused: " + e.getMessage());
                  }
              }
              case SESSION_STATUS_IDLE -> {
                  // 當所有 run 皆已結束且代理已完成其回合時即完成
                  var stopReason = event.asSessionStatusIdle().stopReason();
                  if (openRuns.isEmpty() && stopReason.isEndTurn()) {
                      break events;
                  }
                  // 帶有 requires_action 的 idle 會等待您的用戶端，因此請繼續讀取。
                  // 若為其他停止原因，則印出該原因並停止。
                  if (!stopReason.isEndTurn() && !stopReason.isRequiresAction()) {
                      IO.println("Session idle: " + stopReason.type().asString());
                      break events;
                  }
              }
              case SESSION_STATUS_TERMINATED -> {
                  break events;
              }
              default -> {}
          }
      }
  }
  ```

  ```php PHP
  $openRuns = []; // workflow_run_id => run name
  $phaseNames = []; // run ID => [phase ID => phase name]

  // 先開啟串流，再傳送使用者訊息
  $stream = $client->beta->sessions->events->streamStream($sessionId);
  $client->beta->sessions->events->send(
      $sessionId,
      events: [
          [
              'type' => 'user.message',
              'content' => [
                  ['type' => 'text', 'text' => 'Which contracts in /contracts have a change-of-control clause?'],
              ],
          ],
      ],
  );

  foreach ($stream as $event) {
      switch (true) {
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsWorkflowRunCreatedEvent:
              $openRuns[$event->workflowRunID] = $event->name;
              foreach ($event->phases as $phase) {
                  $phaseNames[$event->workflowRunID][$phase->id] = $phase->name;
              }
              echo "Run started: {$event->name}", PHP_EOL;
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsWorkflowRunPhaseStartedEvent:
              $phaseId = $event->workflowRunPhaseID;
              echo '  Phase: ', $phaseNames[$event->workflowRunID][$phaseId] ?? $phaseId, PHP_EOL;
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsWorkflowRunStatusEndedEvent:
              $name = $openRuns[$event->workflowRunID] ?? $event->workflowRunID;
              unset($openRuns[$event->workflowRunID]);
              echo "Run ended: {$name} ({$event->result->type})", PHP_EOL;
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsAgentCustomToolUseEvent:
              // 事件抵達時再回應。run 的執行緒可能會等待您的
              // 用戶端，而工作階段仍保持執行中。
              $result = callTool($event->name, $event->input);
              try {
                  $client->beta->sessions->events->send(
                      $sessionId,
                      events: [
                          [
                              'type' => 'user.custom_tool_result',
                              'custom_tool_use_id' => $event->id,
                              'content' => [['type' => 'text', 'text' => $result]],
                          ],
                      ],
                  );
              } catch (\Anthropic\Core\Exceptions\BadRequestException $error) {
                  // 若結果太晚送達（在伺服器封存該呼叫的執行緒之後），
                  // 伺服器會拒絕該結果。請繼續追蹤該 run。
                  echo "  Answer to {$event->name} refused: {$error->getMessage()}", PHP_EOL;
              }
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent:
              // 當所有 run 皆已結束且代理已完成其回合時即完成
              $finished = $event->stopReason->type === 'end_turn';
              if (!$openRuns && $finished) {
                  break 2;
              }
              // 帶有 requires_action 的 idle 會等待您的用戶端，因此請繼續讀取。
              // 若為其他停止原因，則印出該原因並停止。
              if (!$finished && $event->stopReason->type !== 'requires_action') {
                  echo "Session idle: {$event->stopReason->type}", PHP_EOL;
                  break 2;
              }
              break;
          case $event instanceof \Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusTerminatedEvent:
              break 2;
      }
  }
  $stream->close();
  ```

  ```ruby Ruby
  open_runs = {} # workflow_run_id => run name
  phase_names = {} # [run ID, phase ID] => phase name

  # 先開啟串流，再傳送使用者訊息
  stream = client.beta.sessions.events.stream_events(session_id)

  client.beta.sessions.events.send_(
    session_id,
    events: [{
      type: "user.message",
      content: [{type: "text", text: "Which contracts in /contracts have a change-of-control clause?"}]
    }]
  )

  stream.each do |event|
    case event
    when Anthropic::Beta::Sessions::BetaManagedAgentsWorkflowRunCreatedEvent
      open_runs[event.workflow_run_id] = event.name
      event.phases.each { |phase| phase_names[[event.workflow_run_id, phase.id]] = phase.name }
      puts "Run started: #{event.name}"
    when Anthropic::Beta::Sessions::BetaManagedAgentsWorkflowRunPhaseStartedEvent
      phase_id = event.workflow_run_phase_id
      puts "  Phase: #{phase_names.fetch([event.workflow_run_id, phase_id], phase_id)}"
    when Anthropic::Beta::Sessions::BetaManagedAgentsWorkflowRunStatusEndedEvent
      name = open_runs.delete(event.workflow_run_id) || event.workflow_run_id
      puts "Run ended: #{name} (#{event.result.type})"
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentCustomToolUseEvent
      # 事件抵達時再回應。run 的執行緒可能會等待您的
      # 用戶端，而工作階段仍保持執行中。
      result = call_tool.call(event.name, event.input)
      begin
        client.beta.sessions.events.send_(
          session_id,
          events: [{
            type: "user.custom_tool_result",
            custom_tool_use_id: event.id,
            content: [{type: "text", text: result}]
          }]
        )
      rescue Anthropic::Errors::BadRequestError => error
        # 若結果太晚送達（在伺服器封存該呼叫的執行緒之後），伺服器會拒絕它
        # 。請繼續追蹤該 run。
        puts "  Answer to #{event.name} refused: #{error.message}"
      end
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      reason = event.stop_reason.type.to_sym
      # 當所有 run 皆已結束且代理程式已完成其回合時即完成
      break if open_runs.empty? && reason == :end_turn
      # 帶有 requires_action 的 idle 會等待您的用戶端，因此請繼續讀取。
      # 若為其他停止原因，請將其印出並停止。
      unless %i[end_turn requires_action].include?(reason)
        puts "Session idle: #{reason}"
        break
      end
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusTerminatedEvent
      break
    end
  end
  ```
</CodeGroup>

## 在有開啟的執行時中斷工作階段

傳送不帶 `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`)，或帶有主要執行緒 ID 的 [`user.interrupt`](https://platform.claude.com/docs/zh-TW/managed-agents/events-and-streaming#interrupt-the-agent)。它會停止代理的回合。它不會結束任何執行。工作階段的執行可能會暫停或繼續執行，而它們的事件可能不會顯示是哪一種。已暫停之執行的存續時間會持續流逝，因此執行可能在暫停期間以 `timeout_error` 結束。

* **等待中的工具呼叫：** 中斷後，執行之執行緒的工具呼叫可能仍在等待您的用戶端。請回應每一個。若要取消要求確認的呼叫，請拒絕它。若要取消自訂工具呼叫，請傳送一個結果，將 `is_error` (java, php: `isError`; csharp, go: `IsError`) 設為 `true`，並在 `content` (csharp, go: `Content`) 中附上說明原因的文字。當工作階段以 `requires_action` 處於 `idle` 時，`user.message` 會傳回 400，因此請先回應這些呼叫。
* **若要停止執行：** 傳送一則 `user.message`，要求代理停止其執行。已停止的執行會以 `result` `{"type": "stopped"}` 結束。當工作階段以 `budget_reached` 處於 `idle` 時，在您提高或移除預算之前，`user.message` 會傳回 400。提高或移除預算也會恢復因預算而暫停的執行，除非這些執行也因中斷而暫停。
* **若要繼續：** 傳送一則 `user.message`，要求代理繼續其執行。中斷後，執行可能會等待這則訊息。如果工作階段以 `budget_reached` 處於 `idle`，請先提高或移除預算。
* **執行結果：** 在中斷後結束的執行仍會傳送 `workflow_run.status_ended`。

## 執行開啟期間

| 請求                                    | 執行開啟期間                                                                                                                                                            | 該怎麼做                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 封存或刪除工作階段                             | 在執行開啟期間可能會傳回 400，無論工作階段的狀態為何。錯誤的 `error.details.error_code` 可能是 `"workflow_run_open"`。也可能會成功。                                                                     | 要求代理停止其執行，或等到每個執行都結束。已暫停的執行只有在其存續時間已過時才會自行結束。接著在工作階段為 `idle` 時傳送請求。成功的封存會以 `{"type": "stopped"}` 結束每個開啟的執行。封存後，執行的 `workflow_run.status_ended`，以及仍處於開啟狀態之階段的 `workflow_run.phase_ended`，都不會出現在串流上。請列出工作階段的事件來讀取它們。成功刪除後，不會有任何 `workflow_run` 事件回報工作階段之執行的結束。                                                                                                                                                                                                                          |
| 封存執行的某個執行緒                            | 在執行開啟期間（無論執行中或閒置），會傳回 400 並帶有 `error.details.error_code: "workflow_run_open"`，除非伺服器已封存該執行緒。                                                                       | 無需任何操作。伺服器會封存執行的執行緒。                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| 更新工作階段的 `agent` (csharp, go: `Agent`) | 在任何執行開啟期間（即使是已暫停的執行），會傳回 400 並帶有 `error.details.error_code: "workflow_run_open"`。更新底層代理仍會被接受，而工作階段會保留自己的副本。同時傳送其他欄位（例如 `budget` (csharp, go: `Budget`)）的請求會被整個拒絕。 | 等到每個執行都有其 `workflow_run.status_ended`，或要求代理停止其執行。                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| 回應來自執行之執行緒的工具呼叫或工具確認                  | 允許。它會出現在主要串流上，其 `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) 會指明該執行緒。                                     | 在事件出現時立即回應，將事件的 `id` (csharp, go: `ID`) 作為 `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) 或 `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`) 傳入。不要等待 `session.status_idle`：在執行的其他執行緒工作時，工作階段可能保持 `running`。一旦伺服器封存了該執行緒，針對其呼叫的工具結果將不會有任何作用，且可能傳回 400。當工具結果傳回 400 時，請在執行緒清單中找到該呼叫的執行緒。如果其狀態為 `terminated`，表示結果來得太晚，請將其捨棄。請將每個工具結果以各自獨立的請求傳送，因為當伺服器拒絕請求中的某個事件時，會拒絕整個請求。來得太晚的工具確認會傳回 200，但這並不代表工具已執行。 |

### 重新連線後重建執行狀態

請從工作階段的事件重建每個執行的狀態。串流不會重播您錯過的內容：新的連線只會傳送在其開啟之後發出的事件。因此，請使用 `types` (curl: `types[]`; cli: `--type`; csharp, go: `Types`) 篩選條件列出事件，每種事件類型一個項目，如[列出過去的事件](https://platform.claude.com/docs/zh-TW/managed-agents/events-and-streaming#list-past-events)中所述。將每個回應的 `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) 作為 `page` (cli: `--page`; csharp, go: `Page`) 傳入，直到 `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) 為 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) 或不存在為止。`workflow_run.created`、`workflow_run.status_running`、`workflow_run.status_idle` 和 `workflow_run.status_ended` 提供每個執行的狀態，但在中斷後暫停的執行可能仍顯示為執行中。`workflow_run.phase_started` 和 `workflow_run.phase_ended` 可重建進度。尚未有任何狀態事件的執行表示尚未開始執行。沒有任何端點會列出執行。

## 成本與預算

執行的模型請求會計入[工作階段的預算](https://platform.claude.com/docs/zh-TW/managed-agents/budgets)。執行本身沒有價格。其代理使用的 token 會像工作階段的其他 token 一樣，依各模型的費率計費。關於工作階段的所有費用，請參閱 [Claude Managed Agents 定價](https://platform.claude.com/docs/zh-TW/about-claude/pricing#claude-managed-agents-pricing)。

* **單一執行的用量：** 列出工作階段的執行緒，並將具有該執行之 `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) 的執行緒在 `usage` (csharp, go: `Usage`) 中的 token 數量加總。清單包含已封存的執行緒（其狀態為 `terminated`），因此已完成之執行的執行緒也會被計入。將每個回應的 `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) 作為 `page` (cli: `--page`; csharp, go: `Page`) 傳入，直到 `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) 為 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) 或不存在為止，並略過沒有 `usage` (csharp, go: `Usage`) 的執行緒。如果您改為加總執行緒的 `list_cost` (java, php: `listCost`; csharp, go: `ListCost`)，總計將不包含工作階段執行時間，且每個數值會分別四捨五入。
* **達到預算時：** 每個開啟的執行都會暫停，工作階段會回報 `idle` 並附帶 `budget_reached`，若同時有工具呼叫在等待，則回報 `requires_action`。每個執行緒會完成其已開始的模型請求，因此執行可能會因每個工作中的執行緒多出一個請求而超出預算。提高或移除預算會恢復因預算而暫停的執行，除非這些執行也因中斷而暫停。如果工作階段的用量包含沒有定價的模型，則只有移除預算才會恢復；請參閱[沒有定價的模型](https://platform.claude.com/docs/zh-TW/managed-agents/budgets#models-without-a-list-price)。已暫停之執行的存續時間會持續流逝，因此執行可能在暫停期間以 `timeout_error` 結束。

## 限制

| 限制                  | 值                    | 達到限制時                                                                                                            |
| ------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------- |
| 單一執行中同時工作的執行緒       | 64                   | 執行在有執行緒完成之前不會再建立新的執行緒。API 不保證此數字。                                                                                |
| 工作流程在執行整個生命週期中啟動的代理 | 1,000                | 當工作流程要求更多時，伺服器不會再啟動另一個代理，且執行會以 `thread_limit_error` 結束。伺服器可能會在新的執行緒上重新執行失敗的代理，因此執行可能會有超過 1,000 個執行緒。             |
| 執行存續時間              | 預設為 24 小時，或代理設定的存續時間 | 執行會以 `timeout_error` 結束。沒有任何事件會說明代理設定了多長的存續時間。                                                                   |
| 工作階段中同時開啟的執行        | 預設為 10               | 伺服器會拒絕啟動另一個執行。代理的工具呼叫會收到錯誤，而您會收到一個 `error.type` 為 `max_workflow_runs_error` 的 `workflow_run.error`。閒置的執行也會計入此限制。 |

伺服器會將執行或階段的 `name` (csharp, go: `Name`) 縮短為 64 個字元，並將其 `description` (csharp, go: `Description`) 縮短為 256 個字元。伺服器對工作流程還有其他未在此列出的限制和規則。您看到的結果取決於伺服器何時發現問題：

| 發生的情況                         | 您看到的內容                                                 |
| ----------------------------- | ------------------------------------------------------ |
| 代理啟動執行時，工作流程已超過其他限制之一         | 啟動會被拒絕。您會收到 `workflow_run.error`，且不會有執行。               |
| 執行稍後超過其他限制之一                  | 您會收到 `workflow_run.error`，接著執行可能會以 `unknown_error` 結束。 |
| 伺服器在啟動後發現工作流程違反了工作流程的規則（限制除外） | 您會收到 `workflow_run.error`，接著執行可能會以 `program_error` 結束。 |

工作階段在其生命週期中可以啟動任意數量的執行。

* **啟動執行：** 只有工作階段主要執行緒上的代理可以啟動執行。在執行的執行緒中工作的代理無法啟動自己的執行，因此執行不會巢狀。
* **結束執行：** 您傳送的任何事件都無法結束執行；封存工作階段則可以。
* **執行的執行緒：** 您無法[依其 ID 停止](https://platform.claude.com/docs/zh-TW/managed-agents/session-threads#interrupt-a-session-thread)其中一個執行緒，也無法在其執行開啟時封存它。
* **執行緒限制：** 執行的執行緒不受工作階段的[子執行緒限制](https://platform.claude.com/docs/zh-TW/managed-agents/session-threads#primary-thread-and-session-threads)約束。
* **可見性：** 您看不到工作流程的程式碼，但可以向代理索取工作流程，如[執行的執行緒](https://platform.claude.com/docs/zh-TW/managed-agents/workflow-runs#a-runs-threads)中的提示所述。您也看不到代理為啟動和管理執行所進行的工具呼叫，或每個執行緒傳回給工作流程的結果。

### 速率限制

執行的工作會計入您組織既有的「rate limits」（速率限制）。

| 項目                         | 計入                                                                                                      | 該怎麼做                                                                                                       |
| -------------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| 您的用戶端擷取或列出工作階段、其執行緒及其事件的請求 | [Managed Agents 端點](https://platform.claude.com/docs/zh-TW/managed-agents/reference#rate-limits)的讀取限制   | 在工作階段的事件串流上追蹤執行，而不是輪詢。                                                                                     |
| 來自執行之執行緒的模型請求              | 您針對每個執行緒所使用之模型的 [Messages API 速率限制](https://platform.claude.com/docs/zh-TW/api/rate-limits)，與您的其他流量一起計算 | 在這些限制中為執行保留空間，或[申請更高的限制](https://platform.claude.com/docs/zh-TW/api/rate-limits#requesting-higher-limits)。 |

當來自執行之某個執行緒的模型請求受到速率限制，或模型過載時，該執行緒自身的串流可能會收到類型為 `model_rate_limited_error` 或 `model_overloaded_error` 的 `session.error`：

* 如果其 `retry_status.type` 為 `retrying`，表示伺服器正在重試該請求，且執行緒仍在工作。
* 如果為 `exhausted`，表示執行緒已失敗。如果工作流程讓該失敗結束執行，執行會以 `program_error` 結束，而它不會指明原因。請閱讀失敗之執行緒的事件來找出原因。

伺服器也會限制您組織所有工作階段每分鐘的工作量。達到此限制的執行緒會停止，並在其自身的串流上收到一個訊息中指明速率限制的 `session.error`。請等待一分鐘後再要求代理繼續。
