Skip to content

refactor(sdk): unify WorkflowTrajectory on agent-trajectories SDK#732

Merged
khaliqgant merged 3 commits intomainfrom
fix/sdk-unify-trajectory-writer
Apr 13, 2026
Merged

refactor(sdk): unify WorkflowTrajectory on agent-trajectories SDK#732
khaliqgant merged 3 commits intomainfrom
fix/sdk-unify-trajectory-writer

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

@khaliqgant khaliqgant commented Apr 13, 2026

Summary

Collapses packages/sdk/src/workflows/trajectory.ts from 779 → 314 lines (-465) by deleting the hand-rolled trajectory writer and delegating persistence to the canonical agent-trajectories SDK. All workflow semantics (public API, event shapes, chapter titles, non-blocking boundary) are preserved.

Why

The SDK shipped a parallel implementation of the same on-disk trajectory format — its own type shadows, its own mkdir / writeFile / rename plumbing, its own chapter bookkeeping, its own ID generation. That meant two places to fix bugs, two places to evolve the schema, and inevitable drift against the reader/writer in agent-trajectories. Downstream tooling (viewer, reconcile, compaction) can now trust a single source of truth for trajectory persistence.

Changes

packages/sdk/src/workflows/trajectory.ts (779 → 314 lines)

Deleted:

  • Local Chapter / TrajectoryAgent / TrajectoryEvent type shadows
  • Hand-rolled flush() / moveToCompleted() filesystem I/O
  • Manual chapter open/close state tracking
  • Custom trajectory ID generation

Kept:

  • Public WorkflowTrajectory API (no caller changes)
  • Workflow event shapes and chapter title semantics
  • classifyFailure / diagnosisFor / synthesis helpers (workflow-specific)
  • guard() try/catch boundary — the non-blocking invariant (persistence failures must never break the workflow)

Added:

  • agent-trajectories as a runtime dependency in packages/sdk/package.json
  • Adapter now drives createTrajectory / completeTrajectory + FileStorage directly

packages/sdk/src/__tests__/workflow-trajectory.test.ts — updated for the new persistence path; 31/31 passing.

Design

Chosen approach is the hybrid (B-leaning) plan from workflows/unify-sdk-trajectory-writer/DESIGN.md — take Proposal B's semantic conservatism (keep public API, event strings, non-blocking boundary) but take Proposal A's deletion targets (type shadows, hand-rolled I/O).

Verification

All 5 gates green (verify-80-to-100):

  1. structural: trajectory.ts imports agent-trajectories
  2. quantitative: 314 ≤ 400 line budget ✓
  3. build: tsc -p tsconfig.build.json
  4. unit: 31/31 vitest tests passing ✓
  5. 80→100 round-trip: trajectory created, flushed, moved to completed/, re-read via FileStorage — id, title, status, chapter count, and agent count all match ✓

Companion PRs

Test plan

  • CI passes on fix/sdk-unify-trajectory-writer
  • pnpm --filter @agent-relay/sdk build succeeds
  • pnpm --filter @agent-relay/sdk test — 31/31 workflow-trajectory tests pass
  • Manual spot-check: run a workflow end-to-end, confirm trajectory written under .trajectories/ and moved to completed/ with the expected shape
  • Verify fix(storage): tolerate legacy trajectory shapes + harden reconcile trajectories#22 is merged (or queued) before rollout

🤖 Generated with Claude Code


Open with Devin

Collapse the hand-rolled trajectory writer in packages/sdk/src/workflows/
trajectory.ts onto the agent-trajectories SDK. The SDK writer was a parallel
implementation of the same on-disk format, with its own types, filesystem I/O,
and chapter bookkeeping — a steady source of drift against the canonical
reader/writer in agent-trajectories.

Why:
- Two implementations of the same trajectory schema means two places to fix
  bugs, two places to evolve the schema, and inevitable skew over time.
- The SDK duplicated type shadows, mkdir/writeFile/rename plumbing, and
  chapter open/close state that agent-trajectories already owns.
- One source of truth for trajectory persistence lets downstream tooling
  (viewer, reconcile, compaction) trust a single format.

What changed (trajectory.ts: 779 → 314 lines, -465):
- Deleted: local Chapter/TrajectoryAgent/TrajectoryEvent type shadows,
  hand-rolled flush()/moveToCompleted() filesystem I/O, manual chapter state
  tracking, and ID generation.
- Kept: public WorkflowTrajectory API, workflow event shapes, chapter title
  semantics, failure classification / diagnosis / synthesis helpers, and the
  non-blocking guard() boundary (all workflow semantics are preserved).
- Added: agent-trajectories as a runtime dependency; the adapter now drives
  TrajectoryBuilder / core functions + FileStorage directly.
- Tests: workflow-trajectory.test.ts updated for the new persistence path;
  31/31 passing.

Chosen approach is the hybrid (B-leaning) plan from
workflows/unify-sdk-trajectory-writer/DESIGN.md — keep Proposal B's semantic
conservatism (public API, event strings, non-blocking boundary) but take
Proposal A's deletion targets (type shadows, hand-rolled I/O).

Verification — all 5 gates green:
  1. structural: imports agent-trajectories ✓
  2. quantitative: 314 ≤ 400 line budget ✓
  3. build: tsc -p tsconfig.build.json ✓
  4. unit: 31/31 vitest tests passing ✓
  5. 80→100 round-trip: trajectory created, flushed, moved to completed,
     re-read via FileStorage — id/title/status/chapters/agents all match ✓

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

khaliqgant and others added 2 commits April 13, 2026 14:42
The unification in 95eafc4 relied on looser types from
agent-trajectories (role as open string, expanded TrajectoryEventType,
relaxed id regex). Those types only existed locally on fix/reconcile-stale-index
when the worker implemented the PR, so CI (which installs from npm)
hit 5 TS errors against the published 0.5.3.

agent-trajectories@0.5.4 is now published with those looser types
(AgentWorkforce/trajectories#22). Bumping:
  - packages/sdk/package.json: ^0.5.3 -> ^0.5.4
  - root package.json (devDependencies): ^0.4.1 -> ^0.5.4
  - package-lock.json regenerated via `npm install --package-lock-only`

Verified locally:
  - `npm run build` in packages/sdk: clean tsc -p tsconfig.build.json
  - `npx vitest run src/__tests__/workflow-trajectory.test.ts`: 31 passed

This should turn CI green on PR #732.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous bump in 5411666 placed agent-trajectories@^0.5.4 in the
root devDependencies, which tripped scripts/audit-bundled-deps.mjs in
CI:

  ❌ MISSING DEPENDENCIES
    "agent-trajectories": "^0.5.4",
      // used by: sdk

@agent-relay/sdk is a bundled sub-package inside the root agent-relay
tarball. When a user runs `npm install -g agent-relay`, only the root
`dependencies` (not `devDependencies`) are installed as runtime deps.
Since the SDK now imports agent-trajectories at runtime (the unified
WorkflowTrajectory wraps TrajectoryClient from agent-trajectories/sdk),
it must be a runtime dep of the root, not a dev dep.

Move agent-trajectories from devDependencies to dependencies and
regenerate the lock file.

Local audit now passes:
  ✅ All bundled package dependencies are properly hoisted.
  Bundled packages: 9
  External dependencies found: 15
  Hoisted to root: 15
  Missing from root: 0

Build + unit tests still green (31/31 in workflow-trajectory.test.ts).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 11 additional findings in Devin Review.

Open in Devin Review

Comment on lines +173 to +174
const dataDir = process.env.TRAJECTORIES_DATA_DIR ?? join(cwd, '.trajectories');
this.storageBaseDir = process.env.TRAJECTORIES_DATA_DIR ? dirname(dataDir) : cwd;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 TRAJECTORIES_DATA_DIR contract silently broken when path doesn't end with .trajectories

The old code used TRAJECTORIES_DATA_DIR directly as the parent directory for active/ and completed/ subdirectories (e.g., TRAJECTORIES_DATA_DIR=/custom/path → writes to /custom/path/active/). The new code applies dirname() to it and passes the result to FileStorage, which internally re-appends .trajectories. This means the env var now implicitly requires the path to end with .trajectories — otherwise data is silently written to the wrong location.

For example, if TRAJECTORIES_DATA_DIR=/data/my-trajectories, old behavior wrote to /data/my-trajectories/active/, but new behavior writes to /data/.trajectories/active/. The test at packages/sdk/src/__tests__/workflow-trajectory.test.ts:174 only covers the happy path where the env var ends with .trajectories, so the regression isn't caught.

Prompt for agents
In the constructor of WorkflowTrajectory (trajectory.ts), the computation of storageBaseDir assumes that TRAJECTORIES_DATA_DIR always ends with .trajectories so that dirname() strips it and FileStorage re-adds it. The old code used TRAJECTORIES_DATA_DIR directly as the data directory (writing active/ and completed/ under it). The new code breaks this contract when TRAJECTORIES_DATA_DIR doesn't follow the .trajectories naming convention.

Consider either:
1. Documenting the requirement that TRAJECTORIES_DATA_DIR must end with .trajectories, OR
2. Accepting a separate TRAJECTORIES_BASE_DIR env var that points to the parent of .trajectories, OR
3. Checking at runtime whether the last path component is .trajectories and handling both cases.

Relevant code: packages/sdk/src/workflows/trajectory.ts constructor, lines 173-174.
Relevant test: packages/sdk/src/__tests__/workflow-trajectory.test.ts lines 173-181.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@khaliqgant khaliqgant merged commit 9449830 into main Apr 13, 2026
39 checks passed
@khaliqgant khaliqgant deleted the fix/sdk-unify-trajectory-writer branch April 13, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant