Skip to main content

Normalize native agent transcripts into a shared trajectory format.

Project description

trajectory

Normalize agent transcripts from different runtimes into one validated, model-ready record format.

Agent tools represent the same concepts—messages, reasoning, tool calls, and tool results—in incompatible native formats. trajectory provides one TypeScript API that turns those formats into deterministic, structured records for training, evaluation, analysis, and inference.

The caller supplies a transcript string and its source. The one exception is Deep Agents, whose sessions normalizeCheckpoint reads from its local LangGraph SQLite store by thread ID; see src/adapters/deepagents/.

Installation

The TypeScript package is published as @letta-ai/trajectory:

npm install @letta-ai/trajectory

The Python wrapper is published as agent-trajectory and imports as trajectory:

pip install agent-trajectory

Quick start

import { normalizeTranscript } from "@letta-ai/trajectory";

const { records, diagnostics } = normalizeTranscript({
  source: "codex",
  transcript: rawJsonl,
});

records contains the normalized trajectory. diagnostics is always present and is empty when the transcript required no recoverable cleanup.

{
  "records": [
    { "role": "meta", "source": "codex" },
    {
      "role": "user",
      "content": "Check the current directory.",
      "timestamp": "2026-07-10T12:00:00.000Z"
    },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_1",
          "name": "exec_command",
          "args": "{\"cmd\":\"pwd\"}"
        }
      ],
      "timestamp": "2026-07-10T12:00:01.000Z"
    },
    {
      "role": "tool",
      "tool_call_id": "call_1",
      "content": "/workspace",
      "timestamp": "2026-07-10T12:00:02.000Z"
    }
  ],
  "diagnostics": []
}

Supported sources

source Accepted input format Normalized meta.source
claude-code Native Claude Code JSONL claude-code
codex Native Codex rollout JSONL codex
copilot-cli Native GitHub Copilot CLI event JSONL copilot-cli
cursor Cursor role/message content-block JSONL capture cursor
droid Native Droid session JSONL droid
gemini-cli Native Gemini CLI whole-session JSON gemini-cli
hermes Session-store message-row array or a { "session": {...}, "messages": [...] } envelope hermes
letta-code Letta Code client transcript.jsonl letta-code
omp Native OMP (Oh My Pi) coding-agent session JSONL (pi-agent session format) omp
openclaw Native OpenClaw session JSONL (pi-agent session format) openclaw
opencode Native OpenCode { "info": ..., "messages": [...] } session JSON opencode
openhands JSON event array or an events-API { "items": [...] } envelope openhands
pi Native pi-coding-agent session JSONL pi
deepagents Deep Agents CLI LangGraph SQLite store plus threadId deepagents

Tool result records may include ok: boolean when the source exposes an authoritative structured outcome, such as Pi/OpenClaw isError, Claude Code is_error, Letta Code resultOk, OpenHands/Cursor is_error, OpenCode/Gemini terminal state, or Copilot CLI success. The field is omitted when the source does not expose a reliable status; result text is never interpreted as success or failure.

Each adapter lives in its own folder under src/adapters/ with a README documenting the exact input contract, decoding behavior, and what the adapter drops.

Listing local trajectories

listTrajectories() enumerates the sessions in a source's standard local store, newest first, with cursor pagination. It is a discovery layer beside normalization — normalizeTranscript() itself never touches the filesystem. Copilot CLI, Cursor, Gemini CLI, and OpenCode are export-only input contracts and intentionally return listing_unavailable; callers locate and read the exports themselves.

import { listTrajectories } from "@letta-ai/trajectory";

let cursor: string | undefined;
do {
  const page = await listTrajectories({ source: "claude-code", limit: 100, cursor });
  for (const item of page.items) {
    // item.id, item.path, item.updatedAt?, item.title?, item.sizeBytes?
  }
  cursor = page.nextCursor;
} while (cursor);

Normalized records

A trajectory is an ordered array containing:

  • One leading meta record identifying the source and available session metadata.
  • user and assistant prose records.
  • Optional reasoning records when the source exposes reasoning.
  • Assistant tool-call records with stable IDs and stringified JSON-object arguments.
  • tool records linked to earlier calls by tool_call_id.

Every conversational record has an ISO timestamp. The complete contract is available as both runtime validation and schema/trajectory-v1.schema.json.

The public function is:

normalizeTranscript(input: NormalizeInput): NormalizeResult

Adding a source

Each native format is implemented as a focused adapter that decodes source events into the shared internal message/tool contract. Common validation, linking, repair, timestamp handling, and bounds remain in the normalization core.

Use prompts/add-source.md with a coding agent to add a source from a local transcript corpus. The prompt covers privacy-safe corpus inspection, sanitized fixtures, compatibility checks, and the transcript-only API boundary.

Development

Requires Node.js 20+ and Bun for development:

bun install
bun run check

bun run check runs typechecking, the complete test suite, and the package build. It also regenerates the JavaScript runtime embedded in the Python wheel and fails if the committed bundle was stale. Run the Python parity suite with:

PYTHONPATH=python/src python3 -m unittest discover -s python/tests -v

See PARITY.md for compatibility checks performed against real transcript corpora and production source adapters. See SOURCE_VERSION_AUDIT.md for the privacy-safe source-version inventory, observed format families, and current decoder gaps.

License

Apache-2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_trajectory-0.2.4.tar.gz (38.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_trajectory-0.2.4-py3-none-any.whl (40.8 kB view details)

Uploaded Python 3

File details

Details for the file agent_trajectory-0.2.4.tar.gz.

File metadata

  • Download URL: agent_trajectory-0.2.4.tar.gz
  • Upload date:
  • Size: 38.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.20

File hashes

Hashes for agent_trajectory-0.2.4.tar.gz
Algorithm Hash digest
SHA256 b45dd630f94e311a700ed7d0cb92dc8a1b320ab211c53f0f1c710a00e2837cd6
MD5 1f073804c6cf45f198bcbc1d5dbc4ce9
BLAKE2b-256 60366c1e610dfcf9227527b95a443a63b6871742104a873dfa7fc248c9d7b4d6

See more details on using hashes here.

File details

Details for the file agent_trajectory-0.2.4-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_trajectory-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 1bf6d7cb56f795fddeb0c6d55f92f222fa302a219d9cd4e86cbe9bdc2fc05db7
MD5 3890b076b0cbf5e075645eb4fdf4d9a4
BLAKE2b-256 03b7455462fff73d70d46e9e67d9d26706bfe758166aec68e4fae26d8423549b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page