Skip to content

Commit d395e80

Browse files
xiaowuc1claude
andcommitted
Add fxtr plugin 0.1.0
The fxtr and behaviors skills, with copies of the docs.transluce.ai pages they link, prepared by `pnpm sync:plugin` from TransluceAI/fxtr3 at 8d820d77. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent fc4ade4 commit d395e80

33 files changed

Lines changed: 4950 additions & 1 deletion

‎.claude-plugin/marketplace.json‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@
1616
"name": "TransluceAI"
1717
},
1818
"tags": ["analysis", "ai", "mcp", "ingestion"]
19+
},
20+
{
21+
"name": "fxtr",
22+
"source": "./plugins/fxtr",
23+
"description": "Skills for writing, running, and viewing fxtr experiments, and for calling models from them with behaviors",
24+
"version": "0.1.0",
25+
"author": {
26+
"name": "TransluceAI"
27+
},
28+
"tags": ["experiments", "skills"]
1929
}
2030
]
2131
}

‎README.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@ A collection of plugins for Claude Code.
77
| Plugin | Description |
88
|--------|-------------|
99
| [docent](./plugins/docent) | Docent AI analysis tools |
10+
| [fxtr](./plugins/fxtr) | Skills for writing, running, and viewing fxtr experiments, and for calling models from them with behaviors |
1011

1112
The docent plugin includes two skills:
1213
- **analysis** - Analyzing agent behavior with Docent
1314
- **ingestion** - Structured workflow for ingesting agent run data into Docent
1415

16+
The fxtr plugin includes two skills, each with a copy of the documentation it links from
17+
[docs.transluce.ai](https://docs.transluce.ai):
18+
- **fxtr** - Setting up, writing, running, and viewing fxtr experiments
19+
- **behaviors** - Calling language models from fxtr experiments with the behaviors library
20+
1521
## Installation
1622

1723
Add this marketplace to Claude Code:
@@ -20,8 +26,9 @@ Add this marketplace to Claude Code:
2026
/plugin marketplace add TransluceAI/claude-code-plugins
2127
```
2228

23-
Then install the plugin:
29+
Then install a plugin:
2430

2531
```shell
2632
/plugin install docent@transluce-plugins
33+
/plugin install fxtr@transluce-plugins
2734
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "fxtr",
3+
"description": "Write, run, and view fxtr experiments",
4+
"author": {
5+
"name": "TransluceAI"
6+
},
7+
"version": "0.1.0"
8+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: behaviors
3+
description: Call language models from fxtr experiments with the behaviors Python library, covering one-shot requests and judge steps, multi-turn chat rollouts, scripted or custom user and tool policies, retries and failures, streaming, checkpoints, and storing conversations. Use whenever a fxtr experiment calls a model or holds a conversation, or when extending behaviors' model adapters or policies.
4+
---
5+
6+
# behaviors
7+
8+
behaviors is a Python library for calling language models from fxtr experiments: provider
9+
adapters, conversation sessions, context policies that play users and tools, retries and failure
10+
recording, and conversation records stored as fxtr entities. Use these pieces when they fit the
11+
experiment, rather than building another chat loop or transcript format.
12+
13+
The pages below are its documentation. Read the ones a task needs before writing code.
14+
15+
## Where to read
16+
17+
| Task | Read |
18+
| ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
19+
| Add behaviors to a project; hold a conversation, judge outputs, and summarize verdicts in fxtr steps; test without credentials | [Calling language models](references/guides/language-models.mdx) |
20+
| Pick a provider, an adapter, and an exact model ID | [Choosing models](references/guides/choosing-models.mdx) |
21+
| Script users, offer tools, or write a custom conversation flow | [Policies and tools](references/guides/policies-and-tools.mdx) |
22+
| Rollout statuses and `max_turns`, failures, retries, streaming | [Rollout outcomes and retries](references/guides/rollout-outcomes.mdx) |
23+
| Messages and content, stored records, transcripts, conversations in the viewer, checkpoints | [Conversation records and checkpoints](references/guides/conversation-records.mdx) |
24+
| Run Docent readings, or convert records for Docent | [Docent readings](references/guides/docent-readings.mdx) |
25+
| Choose a layer; imports, adapters, sampling settings, requests and responses | [API overview](references/reference/api.mdx) |
26+
| Steps, workflows, arrays, launching jobs, and the step cache | the adjacent [fxtr skill](../fxtr/SKILL.md) |
27+
28+
## Best practices
29+
30+
* **Judge with `gpt-6-luna` by default.** For an LLM judge, use `gpt-6-luna` through the
31+
`OpenAIResponsesAPI` adapter, unless the user asks for another model.
32+
* **Keep the model the user names.** Verify its exact ID from the provider's listing, as Choosing
33+
models shows, rather than substituting another. Without credentials to check, take candidate
34+
IDs from the provider's published catalog, and tell the user that account access has not been
35+
verified.
36+
* **Shape model experiments as the guide does**: one step per conversation, with every setting
37+
that affects the request in a configuration entity; fxtr replicas for repeated samples; and
38+
separate steps for judging and for aggregating verdicts.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"skill": "behaviors",
3+
"documentation": "https://docs.transluce.ai/behaviors",
4+
"packages": {
5+
"fxtr": "0.0.1a0",
6+
"behaviors": "0.0.1a0"
7+
},
8+
"revision": "8d820d77c1292b4792602cbbe5a9876693de3d99",
9+
"modified": false,
10+
"content_sha256": "1c5471096fa21b00e363ac7f69f33bb54d19ade3998658a937328b980645485b"
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# The behaviors documentation
2+
3+
The pages of https://docs.transluce.ai/behaviors, copied with this skill: `provenance.json`,
4+
beside its `SKILL.md`, says from which version. Each is listed with what it covers,
5+
in the order of the site's navigation.
6+
7+
## Get started
8+
9+
- [Introduction](index.mdx): Primitives for evaluating AI model behavior.
10+
11+
## Other pages
12+
13+
- [Choosing models](guides/choosing-models.mdx): Find the exact model IDs a provider offers your account, pick the adapter for its endpoint, and check a model before a sweep.
14+
- [Conversation records and checkpoints](guides/conversation-records.mdx): What a rollout records, how conversations are stored as fxtr entities and flattened into transcripts, and how to checkpoint a session.
15+
- [Docent readings](guides/docent-readings.mdx): Convert conversations to Docent's data models, and run a Docent reading against a transcript or agent run with a model you choose.
16+
- [Calling language models](guides/language-models.mdx): Use the behaviors library to hold conversations and judge outputs in fxtr steps.
17+
- [Policies and tools](guides/policies-and-tools.mdx): Decide what the model sees each turn: scripted users, tool policies, their combinations, and custom conversation flows.
18+
- [Rollout outcomes and retries](guides/rollout-outcomes.mdx): How a rollout ends, how model call failures are retried, recorded, or raised, and how to watch a rollout as it runs.
19+
- [API overview](reference/api.mdx): The layers of behaviors, where each is imported from, the provider adapters, and the request, response, and sampling types.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
title: "Choosing models"
3+
description: "Find the exact model IDs a provider offers your account, pick the adapter for its endpoint, and check a model before a sweep."
4+
---
5+
6+
behaviors takes a provider's model ID as given: it has no catalog of models, and it passes the
7+
string to the provider's endpoint without checking it against a list or translating it. Choose
8+
the provider and endpoint first, then get the exact model ID from that provider's listing API.
9+
Use the returned `id`, not a display name; the same model can have different IDs at different
10+
providers. When you've been asked for a particular model, keep it, and verify its ID rather than
11+
substituting another.
12+
13+
The examples below use `curl` and `jq`, with API keys already set in the named environment
14+
variables. They only list model metadata. Use the same credentials and endpoint as the
15+
experiment, since a listing shows what that account can use. An authentication or permission
16+
error does not mean that no models exist.
17+
18+
## OpenAI
19+
20+
[List models](https://developers.openai.com/api/reference/resources/models/methods/list)
21+
with `GET https://api.openai.com/v1/models`:
22+
23+
```bash
24+
curl --fail-with-body --silent --show-error https://api.openai.com/v1/models \
25+
-H "Authorization: Bearer $OPENAI_API_KEY" \
26+
-o /tmp/openai-models.json &&
27+
jq -r '.data[].id' /tmp/openai-models.json | sort
28+
```
29+
30+
Use a returned ID with `OpenAIResponsesAPI(model_id)` for models supporting the Responses API, or
31+
`OpenAICompatibleAPI(model_id)` for Chat Completions. The listing includes models for other
32+
tasks too; check a model's supported endpoints and features in the
33+
[model catalog](https://developers.openai.com/api/docs/models) before choosing an adapter.
34+
35+
## Anthropic
36+
37+
[List models](https://platform.claude.com/docs/en/api/models/list)
38+
with `GET https://api.anthropic.com/v1/models`:
39+
40+
```bash
41+
curl --fail-with-body --silent --show-error 'https://api.anthropic.com/v1/models?limit=1000' \
42+
-H "x-api-key: $ANTHROPIC_API_KEY" \
43+
-H 'anthropic-version: 2023-06-01' \
44+
-o /tmp/anthropic-models.json &&
45+
jq -r '.data[] | [.id, .display_name] | @tsv' /tmp/anthropic-models.json &&
46+
jq '{has_more, last_id}' /tmp/anthropic-models.json
47+
```
48+
49+
This is one page, even with `limit=1000`. While `has_more` is true, request the next page with
50+
`after_id` set to the returned `last_id`, and collect its models before advancing again.
51+
Pass a returned `id` to `AnthropicMessagesAPI(model_id)`; `display_name` is only for presentation.
52+
53+
## OpenRouter
54+
55+
OpenRouter serves models from multiple vendors through an OpenAI-compatible endpoint. Its
56+
[general catalog API](https://openrouter.ai/docs/api/api-reference/models/list-all-models-and-their-properties)
57+
is `GET https://openrouter.ai/api/v1/models`; the
58+
[account-filtered listing](https://openrouter.ai/docs/api/api-reference/models/list-models-filtered-by-user-provider-preferences-privacy-settings-and-guardrails)
59+
also applies your provider preferences, privacy settings, and guardrails:
60+
61+
```bash
62+
curl --fail-with-body --silent --show-error https://openrouter.ai/api/v1/models/user \
63+
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
64+
-o /tmp/openrouter-models.json &&
65+
jq -r '.data[] | [.id, .name] | @tsv' /tmp/openrouter-models.json
66+
```
67+
68+
For the general catalog, change `/models/user` to `/models`. The
69+
[model browser](https://openrouter.ai/models) is useful for interactive search. Inspect
70+
`architecture`, `context_length`, and `supported_parameters` in the JSON for candidate models.
71+
Use the full returned `id`, including its vendor prefix and any suffix, with:
72+
73+
```python
74+
import os
75+
76+
from behaviors.implementations.models.openai_compatible import OpenAICompatibleAPI
77+
78+
api = OpenAICompatibleAPI(
79+
model_id, # Exact id selected from the OpenRouter listing.
80+
base_url="https://openrouter.ai/api/v1",
81+
api_key=os.environ["OPENROUTER_API_KEY"],
82+
)
83+
```
84+
85+
The OpenAI SDK does not read `OPENROUTER_API_KEY` by itself, so pass it explicitly as above.
86+
Close the adapter with `await api.aclose()` when finished, as in the
87+
[conversation step](language-models.mdx#a-conversation-as-a-step).
88+
89+
## Search and validate a candidate
90+
91+
Search a saved response by ID or display name, changing the file and search text as needed:
92+
93+
```bash
94+
jq -r --arg query 'claude' '
95+
.data[]
96+
| select(([.id, (.name // .display_name // "")] | join(" ") | ascii_downcase)
97+
| contains($query | ascii_downcase))
98+
| .id
99+
' /tmp/openrouter-models.json
100+
```
101+
102+
For paginated responses, search every collected page. A catalog entry does not establish that
103+
the model supports every feature the experiment needs. Check its support for the endpoint,
104+
streaming, tools, and reasoning, then try the chosen adapter and sampling settings with a small
105+
request before launching a sweep. Without credentials, the providers' published catalogs and
106+
documentation give candidate IDs, but not whether your account can use them.
107+
108+
Keep the chosen provider, model ID, and request settings in the experiment's configuration
109+
inputs, so that each run records what was selected (see
110+
[A conversation as a step](language-models.mdx#a-conversation-as-a-step)).
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
title: "Conversation records and checkpoints"
3+
description: "What a rollout records, how conversations are stored as fxtr entities and flattened into transcripts, and how to checkpoint a session."
4+
---
5+
6+
A rollout returns a `ChatRollout`: its context turns, its model turns, how it ended, and the
7+
initialization its model session started from. This page covers what those records hold, how they
8+
are stored and shown, and how they differ from a session's checkpoint.
9+
10+
## Messages and content
11+
12+
Messages are `SystemMessage`, `UserMessage`, `AssistantMessage`, and `ToolMessage`, each holding a
13+
tuple of typed content blocks. An assistant's content may include text, tool calls, reasoning,
14+
redacted reasoning, or summarized reasoning, so don't assume every block has `.text`. For the
15+
answer's text alone, keep the `ContentText` blocks of the turn's `AssistantMessage`s, as the
16+
[judge step's](language-models.mdx#a-judge-step) `answer_text` does, and keep the
17+
structured rollout for later inspection.
18+
19+
A model turn made by an API-backed session records the provider's response in
20+
`ModelTurn.metadata["response"]`, as JSON, including its stop reason and usage. Metadata is defined
21+
by whatever produced the turn, so validate it before scoring with it.
22+
23+
## Storing records
24+
25+
`ChatRollout`, `Transcript`, `TranscriptGroup`, `AgentRun`, and the concrete session
26+
initializations, such as `SetSystemMessage`, are fxtr entities, with type IDs of the form
27+
`org.transluce.behaviors.<Class>.v1`. A step that returns a `ChatRollout` has it stored like any
28+
other entity (see [Entities and custom types](../../../fxtr/references/concepts/entities-and-custom-types.mdx)), and
29+
`await storage.store(entity)` and `await storage.load(ref)` work on them too. To load a bare ID,
30+
pass the concrete type, as in `as_type=ChatRollout`, not an abstract base such as
31+
`SessionInitialization`. A tree of transcripts and groups is stored as one entity, so there is no
32+
need to store each child separately.
33+
34+
fxtr checks stored records strictly: give fields their declared types (`temperature=0.0`, not
35+
`0`), and keep metadata to JSON values with string keys.
36+
37+
## Transcripts
38+
39+
`ChatRolloutTranscriptProjection`, from `behaviors.rollouts.chat`, flattens a rollout into a plain
40+
`Transcript`: `await ChatRolloutTranscriptProjection().to_transcript(rollout)` gives one message
41+
list, starting with the system message of a recorded `SetSystemMessage` initialization and
42+
followed by the turns in order, including a final context turn the model never answered.
43+
`to_agent_run` wraps that transcript in an `AgentRun`. The projection drops each turn's metadata,
44+
so judge from the native rollout when you need usage, stop reasons, or other metadata.
45+
46+
## Showing conversations in the viewer
47+
48+
The `fxtr-view-behaviors` package draws rollouts, transcripts, transcript groups, agent runs, and
49+
system-message initializations as conversations. To use it, spread its `behaviorsRenderers` into
50+
your project's bundle:
51+
52+
```ts views/src/bundle.ts
53+
import type { ViewBundle } from "fxtr-view";
54+
import { behaviorsRenderers } from "fxtr-view-behaviors";
55+
56+
const bundle: ViewBundle = {
57+
renderers: [...behaviorsRenderers],
58+
};
59+
60+
export default bundle;
61+
```
62+
63+
A new project's renderer package doesn't depend on it yet: add
64+
`"fxtr-view-behaviors": "link:./vendor/fxtr/packages/fxtr-view-behaviors"` to the dependencies in
65+
`views/package.json`, like the other fxtr packages, and run `pnpm install` in `views/` (see
66+
[The renderer package](../../../fxtr/references/reference/renderers.mdx#the-renderer-package)). The package also exports
67+
`ChatRolloutView`, for a rollout inside a view of your own, and `ComparedRollouts`.
68+
69+
## Checkpointing sessions
70+
71+
A serializable session can save its state and be restored from it. `await session.get_state()`
72+
returns a JSON object, and `await factory.restore_session(state)` starts a session in that state.
73+
The sessions of `chat_session_model_from_api` and of `ScriptedUserSimulator` support this, and the
74+
`serializable_context_policy_from_*` combinators build checkpointable policies when every component
75+
they combine is checkpointable. Generator-based policies can't be checkpointed, because a
76+
suspended generator can't be saved.
77+
78+
A checkpoint is not a stored record: it is a session's working state, apart from the transcript
79+
entities and from fxtr's step cache. fxtr doesn't resume a partly finished rollout from a
80+
checkpoint: a step that failed partway runs again from the start when its job resumes. Close the
81+
sessions you start yourself with `aclose()`.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: "Docent readings"
3+
description: "Convert conversations to Docent's data models, and run a Docent reading against a transcript or agent run with a model you choose."
4+
---
5+
6+
Docent is Transluce's platform for analyzing AI agent behavior, whose readings ask a language model
7+
questions about transcripts. behaviors can convert its conversation records to Docent's data
8+
models, and run a Docent reading locally:
9+
render a reading's prompt against a transcript or agent run, call a model through a `ModelAPI`
10+
you provide, and parse and validate the answer and its citations. Install the `docent` extra,
11+
`behaviors[docent]`, and import from `behaviors.implementations.docent`.
12+
13+
## Converting records
14+
15+
`to_docent_transcript(transcript)` and `to_docent_agent_run(agent_run)` turn behaviors'
16+
`Transcript` and `AgentRun` (see
17+
[Transcripts](conversation-records.mdx#transcripts)) into the Docent SDK's objects,
18+
and `to_docent_message(message)` converts one message.
19+
20+
## Running a reading
21+
22+
`DocentReadingStepConfig` describes one reading:
23+
24+
* `prompt_template_segments`: the segments of a Docent reading's prompt template, a tuple of
25+
strings and placeholder dictionaries, such as
26+
`{"param_name": "conversation", "param_type": "transcript", "is_list": False}`;
27+
* `output_schema`: the JSON Schema the answer must conform to;
28+
* `input_param_name`: the placeholder the transcript or agent run fills, which must be one of
29+
the segments' placeholders (`param_type` `"transcript"` for a `Transcript`, `"agent_run"` for an
30+
`AgentRun`);
31+
* `max_output_attempts`: how many times to sample the model when its answer doesn't parse or
32+
validate, 3 by default;
33+
* `default_parsed_response_on_failure`: what to return when those attempts run out; without it,
34+
the last validation error is raised.
35+
36+
Then construct `DocentReadingStep(config=config, model_api=api, sampling=sampling)` and call
37+
`await reader.read(transcript_or_agent_run)` with an input of the type the template declares.
38+
`retry=RetryConfig(...)` retries transport failures, as for any model call (see
39+
[Failures and retries](rollout-outcomes.mdx#failures-and-retries)), separately from
40+
the attempts at a valid answer.
41+
42+
`read` returns a `DocentReadingStepResult` with the `parsed_response`, the `reader_transcript` of
43+
the model call, and the `retry_error_transcripts` of attempts whose answers failed to validate. The
44+
fallback from `default_parsed_response_on_failure` has no reader transcript. A transport failure
45+
that outlasts its retries is returned as a `ModelCallFailure`. You own the model API you pass in:
46+
close it when the reading is done, as the
47+
[judge step](language-models.mdx#a-judge-step) closes its adapter.

0 commit comments

Comments
 (0)