Merge the Agentspan agent SDK into conductor-javascript#131
Open
kowser-orkes wants to merge 13 commits into
Open
Merge the Agentspan agent SDK into conductor-javascript#131kowser-orkes wants to merge 13 commits into
kowser-orkes wants to merge 13 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests.
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
kowser-orkes
pushed a commit
that referenced
this pull request
Jul 9, 2026
actions/setup-python's `cache: pip` hard-fails when the repo has no requirements.txt or pyproject.toml to hash for the cache key — true for this repo, where Python exists only to run mcp-testkit. Carried over from the Python SDK's agent-e2e workflow, where a pyproject.toml exists. First observed on PR #131: the job died in "Set up Python" before any test ran, and the silently-empty guard correctly reported 0/0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
df8aa64 to
d43dea6
Compare
…orts Merge the Agentspan TypeScript SDK source (@conductor-oss/conductor-agent-sdk 0.3.0, agentspan@f8704fa3) into this package as src/agents/, published only via subpath exports: ./agents, ./agents/testing, ./agents/vercel-ai, ./agents/langgraph, ./agents/langchain. The root export surface is byte-identical to before (verified via compiler API), so the one name collision (Action) never materializes. Changes beyond the verbatim copy: - agent-client.ts / worker.ts: import from ../sdk and ../open-api instead of the package name (the only coupling to the workflow layer) - tool.ts: rename the createRequire binding to peerRequire (top-level `require` is reserved in this repo's CJS module flavor) - lint conformance to this repo's strict+stylistic ruleset (~41 fixes: no-op arrows, guard-throws replacing non-null assertions, Reflect.deleteProperty, for-of); no-explicit-any and no-unsafe-function-type stay at upstream's own "warn" contract via a scoped eslint override - tsup.config.ts replaces the inline package.json block: 6 entries, esm+cjs+dts; optional peers external; verify:dist gate loads every exports subpath in both formats - package.json: dotenv to dependencies (import-time side effect in config.ts), 5 optional peerDependencies, sideEffects allowlists dist/agents/**, tsx/zod/zod-to-json-schema devDeps - tsconfig: lib es2022 -> es2023 (stream.ts uses Array.findLast; superset, Node >= 18 supports it), package-name paths for in-repo resolution Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
38 of upstream's 41 unit/cli-bin suites move to src/agents/__tests__/, where
the existing test:unit glob and per-PR CI matrix pick them up with zero
workflow changes. Test-count parity with upstream vitest is exact:
761 = 860 - 99 in the three deferred files. Deferred:
- kitchen-sink-structural.test.ts (imports examples/kitchen-sink; lands with
the examples in the next commit)
- validation/{algorithmic,event-audit}.test.ts (they test the validation/
LLM-judge harness, whose migration is explicitly deferred)
Port mechanics: vitest imports -> @jest/globals, vi.* -> jest.*,
toBeTypeOf/toHaveBeenCalledOnce -> jest equivalents, vi.stubGlobal -> local
helpers/stub-global.ts (upstream never unstubs; per-file isolation contains
it), relative ../../src paths -> colocated paths, skills fixtures colocated
under __tests__/fixtures/. The two jest.mock("child_process") factories
hoist correctly under ts-jest (verified green).
cli-bin/ lands at repo root (the Go CLI walk-up probe expects <dir>/cli-bin)
with imports retargeted to src/agents/. deploy.ts gets a type-only fix for
its workflowName read (upstream never typechecked cli-bin; runtime shape
unchanged).
jest.config.mjs: package-name mappers to in-repo sources plus the standard
ESM .js-suffix strip for relative imports. eslint: upstream's warn contract
extended to cli-bin; stylistic-only relaxations scoped to the migrated tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
221 example files (top-level + quickstart + adk/langgraph/openai/vercel-ai framework subdirs) land at examples/agents/, the 6 agent docs at docs/agents/ (sidestepping the README and api-reference path collisions). All imports and install instructions rewritten from @conductor-oss/conductor-agent-sdk to @io-orkes/conductor-javascript (/agents subpaths), including the runtime error-message strings in src/agents wrappers — zero old-name references remain outside git history. Run story: top-level/quickstart examples resolve the package name straight to src/agents via examples/agents/tsconfig.json paths (npx tsx, no install); framework subdirs install their own deps (scripts/install-example-deps.sh, nonexistent langchain/ entry dropped) and gain an explicit file:../../.. SDK dep; langgraph/ also gains the @langchain deps it silently inherited from upstream's deleted examples workspace manifest. Also lands the deferred kitchen-sink-structural.test.ts (66 tests; unit suite now 1500 green) and a type-only fix upstream never caught because examples were never typechecked: schedules-api.ts runNow's first overload makes opts optional, matching the documented 1-arg default usage. Root tsconfig excludes examples/agents (framework subdir deps are not installed at the root); eslint gains a scoped override for the four rules the didactic files break en masse — upstream ignored examples/ in lint entirely. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All 25 upstream e2e suites move to e2e/ (with fixtures/, _configs/, and the
loose harness scripts under e2e/tools/), run by jest.e2e.config.mjs:
testMatch e2e/**, 60s default timeout, maxWorkers 3 (upstream's maxForks 3),
jest-junit to results/junit-e2e.xml. New script: npm run test:agent-e2e
(--forceExit, matching the repo's other jest scripts — agent polling keeps
handles open after LLM suites). Deliberately invisible to
test/test:unit/test:integration globs — per-PR CI cost is unchanged
(verified: unit run still 74 suites).
Beyond the mechanical vitest-to-jest pass, six vitest-isms needed real
porting (verified by loading all 25 suites under jest — 196 tests enumerate
clean — and by running suites 1/2/9 against a live release-JAR server):
- expect(actual, message) two-arg form (265 sites, jest 30 rejects it) ->
expectMsg helper in e2e/helpers.ts that prepends the diagnostic message
to matcher failures
- describe(name, { timeout }, fn) options object (19 files) -> file-level
jest.setTimeout
- it.skipIf(cond) (19 sites) -> itSkipIf helper
- it.fails -> it.failing (suite 7)
- it(name, { retry: 2 }, fn) (4 sites) -> file-level jest.retryTimes(2)
(jest has no per-test retry; both files are LLM-variability suites)
- top-level await gates (suites 11/21/23; illegal in CJS) -> synchronous
require for the langgraph availability probe, and fail-hard beforeAll
health/scheduler gates (matches the TS-e2e fail-hard philosophy; the CI
workflow health-gates the server before tests run)
Live-server proof (local V1): suites 1/2/9 against agentspan-server 0.4.0 —
11 tests pass; the only failures are server-side OpenAI 401s from the
missing local LLM key (the CI run with repo secrets is the full proof).
Unused-var noise (port artifacts + upstream) fixed with _-prefixes and
import trims; the stylistic eslint relaxations for migrated tests extend to
e2e/**. jest-junit output dirs (reports/, results/) are now gitignored.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port of the Python SDK's implemented agent-e2e workflow. Kept verbatim: pull_request + workflow_dispatch triggers, per-ref concurrency with cancel-in-progress, pinned AGENTSPAN_VERSION 0.4.0 (server JAR from the GitHub release, cached by version; linux CLI binary), temurin 21, hard 90s health gate that dumps server.log on failure, executed>0 junit guard (defense-in-depth here — the TS suites fail hard when the server is down), junit + HTML + server.log artifacts at 14-day retention, 45-min timeout, job-level OPENAI_API_KEY/ANTHROPIC_API_KEY secrets (must be added to this repo's settings before the first live run). JS deltas: Node 22 + npm ci + npm run build + npm run test:agent-e2e as the test step; Python setup retained only for mcp-testkit; HTML report via npx tsx e2e/generate-report.ts; no CONDUCTOR_MP_START_METHOD (Python multiprocessing concern, no JS analog). Rehearsed locally: actionlint clean; health gate passed against the booted 0.4.0 JAR; guard correctly fails an all-skipped junit (0/196) and the report generator renders the real junit output. The test:agent-e2e script pins jest-junit's output to results/junit-e2e.xml via env vars — the package.json jest-junit block (reports/jest-junit.xml) outranks reporter options, and env vars outrank the block. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README: new Durable AI Agents section (subpath quickstart mirroring examples/agents/quickstart/01-basic-agent.ts, wrapper/testing subpaths, docs + examples pointers) and a Documentation-table row. AGENTS.md: src/agents feature area — repo layout additions (src/agents, e2e/, cli-bin/, examples/agents, docs/agents), the subpath-only export rule (root re-export ban and the OpenAPI Action collision that motivates it), colocated-test and e2e conventions, example run story, AGENTSPAN_* config surface, and the agent-e2e command. CHANGELOG: additive-minor entry with a migration note for @conductor-oss/conductor-agent-sdk users (specifier rewrite, /agents-prefixed wrapper subpaths, optional peers, dotenv/sideEffects behavior). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
actions/setup-python's `cache: pip` hard-fails when the repo has no requirements.txt or pyproject.toml to hash for the cache key — true for this repo, where Python exists only to run mcp-testkit. Carried over from the Python SDK's agent-e2e workflow, where a pyproject.toml exists. First observed on PR #131: the job died in "Set up Python" before any test ran, and the silently-empty guard correctly reported 0/0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Stage-4 lint pass blanket-prefixed suite 10's diag and codeOutputs locals as unused, but most scopes still reference the bare names inside expectMsg messages and output assertions — ReferenceError at runtime. ts-jest is transpile-only, so it surfaced only in the first secrets- enabled CI run (6 failures, the run's only red). Only genuinely-unused declarations keep the underscore (upstream parity; upstream never linted e2e). Verified live: suite 10 vs local server JAR 0.4.0 with real keys — 8 passed, 1 skipped (Jupyter, needs kernel). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4141a1e to
6c75d48
Compare
… agent lifecycle surface Per-schedule pause/resume verbs differ by server family: OSS/embedded Conductor maps them PUT-only, Orkes Conductor GET-only. SchedulerClient now issues PUT first and retries via GET only on HTTP 405, stateless per call, with the pause reason re-applied on the fallback URL (mirrors the Python SDK's OrkesSchedulerClient). Implemented in the hand-written wrapper via raw non-throwing client calls — the generated transport is untouched and regeneration stays safe. SchedulerClient also absorbs the typed agent-schedule lifecycle surface (save/get/listForAgent/pause/resume/delete/runNow/previewNext/reconcile) operating on Schedule/ScheduleInfo with wire-name prefixing and typed errors via _translate. The models/mapping/errors relocate verbatim from src/agents/schedule.ts to src/sdk/clients/agent/schedule.ts (Python parity: conductor/client/ai/schedule.py); the agents module re-exports them. Ctor widened to Client | PromiseLike<Client> so callers with async client construction keep synchronous accessors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e SchedulerClient
BREAKING CHANGE (agent layer, no backward compatibility): the raw-fetch
ScheduleClient class and SchedulerFetcher interface are gone from the
./agents surface. SchedulerClient — which absorbed the same typed
lifecycle methods (save/get/listForAgent/pause/resume/delete/runNow/
previewNext/reconcile) in the previous commit — is re-exported from
./agents in their place; every method call site keeps its name and
signature. The scheduling e2e suite needed exactly two lines (import +
one type annotation); the schedules.* module facade, runtime
schedulesClient(), deploy({schedules}) reconciliation and
AgentClient.schedule() are unchanged.
AgentClient.schedules now hands its memoized Conductor-client promise to
SchedulerClient (single transport; the SchedulerFetcher raw-fetch path is
deleted, _rawRequestUntyped remains for /agent/* control-plane calls).
An absence test pins the deletion, mirroring the Python SDK's
test_agent_schedule_client_is_gone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…posed via OrkesClients
Moves the agent control-plane client and the agent-flavored workflow
client from src/agents/ to src/sdk/clients/agent/ (names kept — nothing
on the root surface collides: Conductor's workflow client is
WorkflowExecutor). OrkesClients gains getAgentClient() and
getAgentWorkflowClient(); AgentClient's constructor accepts an optional
pre-built client ((AgentConfigOptions & {client?}) | AgentConfig) which
pre-seeds the memoized promise, so the factory path reuses one Conductor
client across workflow + schedule surfaces. The /agent/* raw transport
and JWT mint path are unchanged; decodeJwtExp stays exported.
Cycle guard: the moved files import createConductorClient and the agent
domain modules via deep paths, never the sdk barrel; madge reports no
new cycles (the AgentClient↔WorkflowClient type-only edge predates the
move). The ./agents subpath re-exports everything from the new homes —
its surface is unchanged. The enriched ConductorClient type is not
re-exported at root (the deprecated bare alias keeps that name).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CHANGELOG (Unreleased): OrkesClients agent getters, PUT-first/405→GET pause-resume verb handling, absorbed typed schedule lifecycle, and the ScheduleClient/SchedulerFetcher removal with its one-line migration. Agent docs re-point the schedule surface at SchedulerClient and note the WorkflowExecutor vs agent WorkflowClient distinction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Folds the Agentspan TypeScript SDK (
@conductor-oss/conductor-agent-sdk0.3.0, upstreamf8704fa3) into this package as a durable AI-agent layer, exposed only via newsubpath exports — one install, one package:
./agentsAgent,AgentRuntime,tool, guardrails, handoffs, multi-agent strategies (223 names)./agents/testing./agents/vercel-ai,./agents/langgraph,./agents/langchainThe root export surface is byte-identical to
main(309 names) — existing users areunaffected. Agent-layer deps (
zod,ai,@langchain/*) are optional peers; installingthe package without them keeps working.
What's included
src/agents/— agent runtime, verbatim from upstream except recorded deltas(import seam to
../sdk/../open-api, lint conformance, package rebrand)examples/agents/(100+ runnable examples) +docs/agents/agent-e2eCI workflow: boots the released Agentspan server JAR (0.4.0) +mcp-testkit per PR and runs the e2e suites against real LLMs
(needs
OPENAI_API_KEY/ANTHROPIC_API_KEYrepo secrets)verify:distgate that loads everysubpath in both formats
Notable decisions
AGENTSPAN_SERVER_URLishttp://localhost:8080/api— aligned with the mergedPython SDK (upstream Agentspan defaulted to
6767).AGENTSPAN_*env vars kept as-is;CONDUCTOR_*aliases are a possible follow-up.@conductor-oss/conductor-agent-sdk: change the import to@io-orkes/conductor-javascript/agents— API unchanged.