# Report steps, tokens and human input

Agent Mission Control developer docs > Microsoft Agent Framework (Python)

> How AMC turns your markers into steps, cost and detail rows, how to rename a run or mark it completed with issues, and how a request_info pause becomes a human intervention.

**Before you start:** The marker helpers from Harden an agent or workflow for AMC.

This page is the agent-side view of what AMC reads from a Foundry-hosted run. The general run, step and cost model is in [the integration contract](https://www.agentmissioncontrol.ai/developers/integration-contract/).

## Steps

- Each informational `function_call` whose `call_id` equals its `name` becomes a step, keyed and labelled by that id. Use the executor id, such as `writer`.
- The marker's `added` frame marks the step running; its `done` frame completes it with the parsed `arguments`.
- A marker with `failure_reason` marks the step **failed**, even if the host frame did not.
- Steps are keyed by a stable id, so parallel branches are separate steps and a replayed frame updates the same step rather than adding one.
- A single agent has one step, named after the agent.
- Reserved names are never steps: `request_info` (human input), `run.renamed` (rename), `run.outcome` ([completed with issues](#completed-with-issues)) and `run.artifact`. A step with any of these names silently disappears from the run.

## Tokens and cost

AMC sums each step's tokens into the run total and prices each step by its `model`, with `cached_input_tokens` at the cached rate. When `model_usage` is present, AMC prices each model's row and sums them. A model AMC has no rate for, or a marker with no model, is priced at AMC's default rate. Model ids match without regard to case.

> **Important:** Tokens are the only cost signal from a hosted run. If `usage_details` is read with `getattr`, every step reports zero tokens and the run shows no cost.

## Detail rows with activity_log

`delivered` is the step's headline. `activity_log` adds what the agent did inside the step, which AMC shows as collapsible detail. It is optional: without it, AMC shows `delivered` as a single row. AMC replaces, not appends, the rows on each marker, so always send the full list.

```text
{ "time": "HH:MM:SS", "type": "thinking" | "tool" | "result",
  "tool": "<tool name or null>", "text": "<text>", "result": "<text or null>" }
```

- Map `text_reasoning` content to a `thinking` row.
- Collapse a `function_call` and its later `function_result` onto one `tool` row keyed by `call_id`, with the name, arguments and result.
- Add a trailing `result` row only when `delivered` is a short summary. If `delivered` is the full output, the row just duplicates it.
- Cap argument and thinking text at 2000 characters and result text at 4000.
- In a single agent, skip the agent's own marker (`call_id == AGENT_NAME`) when you build rows.
- Never let capture break a run. Wrap it so any error returns `None` and the marker falls back to `delivered` only.
- Gate it with an environment flag (`EMIT_STEP_ACTIVITY_LOG`), so turning it off is a configuration change, not a redeploy.

A workflow executor already holds a complete `AgentResponse`, so read rows straight from `response.messages`. A streaming single agent receives a tool call's arguments in fragments, so aggregate first with `AgentResponse.from_updates(updates).messages`.

```python
def _safe_activity(messages, final_text=None):
    if os.getenv("EMIT_STEP_ACTIVITY_LOG", "true").strip().lower() in {"false", "0", "no"}:
        return None
    try:
        return _activity_rows_from_messages(messages, final_text) or None
    except Exception:
        return None

# Workflow executor, success path:
await _emit_step_marker(ctx, "writer", delivered=response.text, ...,
                        activity_log=_safe_activity(response.messages))
```

## Rename the run

Once a run's identity is known, for example the topic it resolved, it can rename **this run only**. The registered default name never changes. Emit a reserved marker:

```python
RUN_RENAMED_MARKER = "run.renamed"   # reserved; spell it exactly


async def _emit_rename_marker(ctx, name: str) -> None:
    clean = (name or "").strip()
    if not clean:
        return                           # blank is a no-op and never clears the name
    await ctx.yield_output(Message(role="assistant", author_name=RUN_RENAMED_MARKER, contents=[
        Content.from_function_call(call_id=RUN_RENAMED_MARKER, name=RUN_RENAMED_MARKER,
                                   arguments={"name": clean}, informational_only=True)]))
```

- Or, when the rename coincides with a step, add `run_name` to that step marker's `arguments` instead of sending a second marker.
- A single agent emits the same `run.renamed` content alongside its token marker.
- Last non-empty name wins. A blank name is ignored. A rename after the run has ended is ignored. AMC keeps the name across reloads.

## Completed with issues

A run that finishes normally after a failure that matters, but isn't fatal, says so with the reserved `run.outcome` marker. AMC then records the run's outcome as `partial` and shows it as **Completed with issues**, with the reason. The status stays completed.

```python
RUN_OUTCOME_MARKER = "run.outcome"   # reserved; spell it exactly


async def _emit_outcome_marker(ctx, reason: str) -> None:
    clean = " ".join((reason or "").split())[:2000]
    if not clean:                        # a partial outcome must say what wasn't done
        return
    await ctx.yield_output(Message(role="assistant", author_name=RUN_OUTCOME_MARKER, contents=[
        Content.from_function_call(call_id=RUN_OUTCOME_MARKER, name=RUN_OUTCOME_MARKER,
                                   arguments={"outcome": "partial", "reason": clean},
                                   informational_only=True)]))
```

- The shape is exact: a `function_call` named `run.outcome`, `call_id` equal to `name`, `informational_only=True`, and `arguments` of `{"outcome": "partial", "reason": "..."}`.
- `outcome` must be `"partial"`. AMC ignores any other value. `reason` says what wasn't done, up to 2000 characters.
- In a workflow, emit it from the executor that decides the run is incomplete: it catches the exception, emits that step's `failure_reason` marker, doesn't re-raise, and calls `_emit_outcome_marker`. A single agent emits the same content alongside its token marker.
- Emit it any time before the response completes. The last one wins.
- Failed wins. If the run then ends `response.failed`, AMC ignores the marker.
- Only the marker counts. AMC never infers **Completed with issues** from a step that carries `failure_reason`; without the marker, that run is a clean success.

## Human input

When a workflow calls `ctx.request_info(...)`, the hosted agent surfaces the pending request as a **real** `function_call` named `request_info`. Its `call_id` is the request id. Then:

1. AMC adds a **Human input** step in the waiting state, shows the question, and puts the run into human intervention.
2. AMC reads the question from the `question` field of your `request_data` (it falls back to `prompt`). Give the dataclass a `question` field.
3. When someone answers, AMC sends a follow-up Responses call with the same `previous_response_id` and a `function_call_output` carrying the matching `call_id` and the answer text.
4. The host restores the paused workflow's checkpoint and your `@response_handler` receives the answer as the `response_type` you asked for (here `str`).
5. AMC records the step as completed with the answer and the run continues.

A paused turn also ends with `response.completed`. AMC keeps the run waiting until the answer resumes it, so you don't need to do anything special.

> **Important:** Without process-loss recovery, the resume checkpoint is local to the instance. Run a human-input workflow on a single replica, or turn on `resilient_background` with the checkpoint allow-list.

## Related

- [Harden an agent or workflow for AMC](https://www.agentmissioncontrol.ai/developers/af-amc-hardening/)
- [Orchestrations, human input and checkpoints](https://www.agentmissioncontrol.ai/developers/af-orchestration-and-checkpoints/)
- [Register and test in AMC](https://www.agentmissioncontrol.ai/developers/af-register-and-test/)

---
Source: https://www.agentmissioncontrol.ai/developers/af-report-to-amc/ · Last updated 2026-10-21 · Full index: https://www.agentmissioncontrol.ai/llms.txt
