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.5.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.5-py3-none-any.whl (40.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: agent_trajectory-0.2.5.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.5.tar.gz
Algorithm Hash digest
SHA256 6c6683bc22eb5183e68f3314c169ff6d16fe2920a81f6c6243f33ef42ea2b4e5
MD5 b8eb2732d89c381f908620579509f58c
BLAKE2b-256 d497b52fceabc99ee92e22c408d419e3fe326eb9493b81ad5b022a56989879a3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for agent_trajectory-0.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 cf8ff35be2cec4ae6955e158d8e51ddf6267c83c919c69149d0e392d74e5d485
MD5 f8c8a42c33d57ea9b0658d1f3fea1f53
BLAKE2b-256 2356c003097f3606a2847f11c35394af8cf5039e29902064c15811dd621f53f8

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