# Behaviors

The behavior decorators and base classes. For the conceptual model see [`concepts/behaviors`](https://docs.activegraph.ai/concepts/behaviors/index.md); for the activation rules and the determinism contract see [`concepts/patterns`](https://docs.activegraph.ai/concepts/patterns/index.md) and [`concepts/failure-model`](https://docs.activegraph.ai/concepts/failure-model/index.md).

## Decorators

Decorate a function as an event-driven behavior.

v0.7 additions (both keyword-only):

- `pattern=`: a Cypher subset pattern string. When set, the behavior fires only when the pattern matches the post-event graph state. Combined with `on=` both conditions must hold (CONTRACT v0.7 #11). Matches are exposed as `ctx.matches`.
- `activate_after=`: int event count or "N events". Delays invocation by N events; re-checks `where=` at fire time (CONTRACT v0.7 #13).

Decorate a function as an LLM-driven behavior.

The decorated function's signature is `(event, graph, ctx, llm_output) -> None`. The runtime assembles the prompt, calls the provider, parses the structured output, and only then invokes the handler with the parsed result. Failures flow as `behavior.failed` events with a `reason` from CONTRACT v0.6 #11 (`llm.parse_error`, `llm.schema_violation`, `llm.network_error`, `llm.rate_limited`, `budget.cost_exhausted`).

Keyword-only on purpose — `@llm_behavior` carries enough parameters that positional binding would be a footgun.

`model=` is optional (v1.0.2 #1). Omitted, the runtime resolves it to the configured provider's `default_model` at registration time — `"claude-sonnet-4-5"` for `AnthropicProvider`, `"gpt-4o-mini"` for `OpenAIProvider`. Passing an explicit model string still works byte-identically; the runtime additionally validates the name against the configured provider's `recognizes_model()` and raises :class:`InvalidRuntimeConfiguration` at registration time if the name belongs to a different shipped provider's family (e.g. `model="gpt-4o-mini"` on a runtime configured with `AnthropicProvider`). Names no shipped provider recognizes (custom or fine-tuned models) pass through silently.

`prompt_template=` is the only escape hatch from the runtime-assembled prompt. It is a `str.format`-style template that receives four placeholders:

- `{system}` — the system block: behavior name, frame goal and constraints, role description, and (when `output_schema=` is set) the schema with an example instance.
- `{view}` — the scoped graph view: objects, relations, and recent events, rendered as Markdown (format locked per CONTRACT v0.6 #13).
- `{event}` — the triggering event as id, type, actor, and pretty-printed JSON payload with volatile keys stripped.
- `{instruction}` — the one-sentence task derived from `creates=` and `output_schema=`.

The four placeholders carry the same runtime-assembled content whether or not a template is set; the template only re-arranges them. Omitting `prompt_template=` (the default) uses the runtime's canonical layout.

Decorate a function as a relation behavior — fires once per matching edge.

v0.7: also accepts `pattern=` and `activate_after=` per CONTRACT v0.7 #8 / #11 / #13.

## Base classes

Metadata plus the callable for an event-driven behavior.

A Behavior is data, not magic: `on` (event types), `where` (payload filter), `pattern` (Cypher-subset subscription), `activate_after` (event-count delay), and `view_spec` (what the runtime builds into `ctx.view`) describe *when* it fires; the 3-arg `fn` — invoked as `fn(event, graph, ctx)` — is *what* runs. Instances come from `@behavior` or a pack; the runtime introspects the metadata to match events, and nothing here executes on its own.

Bases: `Behavior`

A behavior whose body is an LLM call.

The runtime owns prompt assembly, cache lookup, the provider call, event emission, and structured-output parsing. The developer's `handler` is invoked only after the LLM has responded (or a cached response was found) and the output was successfully parsed.

CONTRACT v0.7: `tools=` declares a list of `Tool` objects (or strings naming globally-registered tools) the LLM can call during the turn loop. The runtime orchestrates the loop; the handler receives only the final structured output, never raw tool calls.

## `build_prompt(event, graph, *, frame=None, structured_output_mode='prompt')`

Assemble the prompt that would be sent for this event.

CONTRACT v0.6 #20 — public so a developer can inspect prompts without making an API call. Reproducible (pure over inputs); cheap (no I/O).

A behavior that fires once per matching relation edge.

Same metadata surface as :class:`Behavior` plus `relation_type`: when a triggering event touches a relation of that type, the 4-arg `fn` runs as `fn(relation, event, graph, ctx)` — once per (event, relation) pair. Deliberately not a subclass of `Behavior`; the runtime dispatches the two kinds separately.
