# Building an Agent

This independently written synthesis uses public material and original Cedar Cycle examples. It is not the MEGA course body. All contracts, policies, traces, and pseudocode are illustrative, API-neutral, and untested against a live service.

## Learning goals

- Choose a framework by the behavior you need to inspect and control.
- Evaluate models on a representative multi-step job.
- Design narrow tools with explicit error and write semantics.
- Build context, memory, and workflow controls into one reviewable system.

Our target is now concrete: given an authorized support ticket, produce an evidence-linked draft for staff review. A successful run must investigate the right customer, use the right policy version, and save the draft without sending it. A polished paragraph alone does not satisfy this contract.

## Choose the smallest useful framework

A framework may manage model calls, tool adapters, message history, tracing, checkpoints, and interruptions. Before selecting one, sketch the system without product names. You need a model adapter, a tool registry, authorization, task state, a loop or workflow, and an artifact validator. Decide which component owns each concern.

Anthropic's [Building Effective Agents](https://www.anthropic.com/engineering/building-effective-agents) recommends simple starting points and warns that framework abstractions can hide prompts and responses. This is a practical selection test: can you see the model input, stop execution before a tool runs, and recover the task's actual state after an interruption?

For Cedar Cycle, a custom fixed workflow may be enough for the first release. A framework becomes more valuable when durable pauses, many adapters, or multiple agent roles become real requirements. Its convenience should be measured against the effort required to test and diagnose it. A library that makes the happy path short but hides failed operations may increase maintenance work.

Write a small acceptance checklist for any candidate. Can a denied tool call be recorded without running? Can a timeout be represented separately from a missing record? Can a paused draft resume without creating duplicates? These questions describe product behavior and remain useful when libraries change.

## Select models with task evidence

Angie Jones's [3 Prompts to Test for Agent Readiness](https://angiejones.tech/3-prompts-to-test-for-agent-readiness/) uses a sequence of tool use, follow-up modification, and reading to inspect whether a model can act and maintain continuity. Treat such a sequence as an initial capability check, then test the actual support job. A short probe is not a production guarantee.

Our model trial should include several runs of the same fixture set. Count correct tool selection, valid arguments, grounded drafts, unnecessary calls, and successful stopping. Record latency and cost per accepted draft. A cheaper model that needs frequent staff correction can cost more at the workflow level.

Keep the environment constant when comparing candidates. Use the same policy version, tool descriptions, fixtures, and limits. Otherwise an improved result might come from a better tool schema rather than the model. Model settings are part of the tested configuration; changing them creates a new candidate even if the model name stays the same.

Use model capability where interpretation is useful. Deterministic code can check a ticket identifier, enforce an allowed state transition, and reject missing evidence fields. Asking a model to enforce these rules repeatedly creates needless variability.

## Design tools from support decisions

Begin with the decisions the assistant must make. It needs to know what the customer reported, what the account service confirms, and what policy permits. That suggests separate ticket, account-summary, and policy tools. Return only the fields required for this job. A full customer export adds irrelevant personal information and makes reasoning harder.

Our original contract might look like this:

```text
read_account_summary(ticket_id)
  identity: bound by server from authenticated staff and ticket
  returns: account_status, settled_entries, pending_entries,
           observed_at, source_version
  errors: not_found | access_denied | temporarily_unavailable

save_draft(ticket_id, text, evidence_ids, idempotency_key)
  effect: creates or returns one staff-review draft
  returns: draft_id, revision, state="saved"
  errors: invalid_evidence | conflict | unavailable
```

The model never supplies a tenant override. The service checks that evidence references belong to the same case. The idempotency key identifies one intended draft operation, so retrying after a lost response does not create a second draft. A revision conflict asks the workflow to reread state rather than overwrite a staff member's edits.

Tool descriptions should make these semantics visible. Do not call a save tool “publish” if it only creates a draft. Do not expose a generic database writer when the intended operation is one constrained artifact.

## Context, memory, and workflow controls

Create a context builder with a stable order: task contract, current staff request, relevant evidence, current artifact state, and compact prior observations. Track where each included fact came from. The context builder should retrieve within the authenticated case before considering semantic relevance.

Store task progress independently of chat wording. A state such as `draft_saved` should have a draft receipt. A state such as `needs_policy` should retain the failed lookup and next useful action. This lets an interface show clear progress without interpreting the assistant's prose.

Define the allowable transitions. Our workflow moves from `created` to `evidence_ready`, then `draft_ready`, then `draft_saved`. Any stage can stop as `needs_input` or `failed`. Only a service response can advance the final save transition. This simple state machine makes the distinction between reasoning and execution visible.

Failure controls should match the operation. Retry a temporary read error within a deadline. Do not retry denied access with a different identity. Retry a save only with the same operation key and a way to check its outcome. A blanket “retry three times” policy ignores these differences.

## Worked example

Ticket C21 reports that a canceled plan still appears active. The first account read times out. The second returns `canceled`, effective tomorrow, observed today. Policy P9 explains that service continues through the paid period. The agent drafts a short explanation with the effective date and links both evidence records.

```text
created
  -> read ticket: C21 found
  -> read account: temporary timeout
  -> retry same authorized read: canceled, effective tomorrow
  -> read policy: P9 version 3
  -> draft_ready: cite account observation and P9
  -> save_draft(key="C21:request-52:draft")
  -> draft_saved: receipt D83 revision 1
```

Suppose the save response disappears after the service commits. A naive retry creates D84. Our contract reuses the key and receives D83. The final reply can truthfully report a saved draft once the receipt is recovered. Until then, it should say the save outcome is unresolved.

This example also shows why current state matters more than a remembered summary. Yesterday's conversation may say the plan was active. Today's account observation says it is canceled with a future effective date. The draft should use the current authoritative observation and explain the timing.

## Practice

Implement the workflow with local fixtures and a scripted model stub. Simulate a read timeout, an authorization failure, and a save that succeeds but loses its first response. Write the task-state record after each transition.

Acceptance criteria: access denial causes no alternate-identity retry; a lost save response produces one draft; the final state includes the draft receipt; stale conversation text never overrides the account fixture; the final artifact identifies its policy version.

A good answer keeps authorization outside model-generated arguments and treats saved state as a service fact. Its timeout trace has bounded retries. Its duplicate-save trace proves one stored draft by inspecting the stub store. A transcript that merely says “I avoided duplicates” is insufficient evidence.

## Check your understanding

1. What is a useful framework selection test? **Answer:** verify that you can inspect inputs, intercept tool execution, and recover actual task state.
2. Why compare cost per accepted draft? **Answer:** it includes failures and correction work that a per-call price hides.
3. What changes after an uncertain save? **Answer:** query or retry the same operation identity; do not create a new intended write.

## Sources

- [Angie Jones: 3 Prompts to Test for Agent Readiness](https://angiejones.tech/3-prompts-to-test-for-agent-readiness/) — initial multi-turn capability probes.
- [Anthropic: Building Effective Agents](https://www.anthropic.com/engineering/building-effective-agents) — simplicity and framework tradeoffs.
