All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Durable AI agents -- the Agentspan TypeScript SDK (
@conductor-oss/conductor-agent-sdk) is merged into this package as new subpath exports:@io-orkes/conductor-javascript/agents(core:Agent,AgentRuntime,tool, guardrails, handoffs, memory, schedules, streaming, HITL),/agents/testing, and framework wrappers/agents/vercel-ai,/agents/langgraph,/agents/langchain. The agent clients are also first-class citizens of the root export (AgentClient,WorkflowClient,Schedule,ScheduleInfo, schedule errors) — the root surface grows additively (minor). Docs at docs/agents/; 60+ examples at examples/agents/.- Migration for
@conductor-oss/conductor-agent-sdkusers: install@io-orkes/conductor-javascriptand rewrite import specifiers --@conductor-oss/conductor-agent-sdkbecomes@io-orkes/conductor-javascript/agents, and the wrapper subpaths gain the/agentsprefix (e.g..../vercel-aibecomes.../agents/vercel-ai). - New optional peer dependencies (all lazily resolved, install only what you use):
zod,zod-to-json-schema,ai,@langchain/core,@langchain/langgraph.dotenvbecomes a runtime dependency (the agent entry points load it at import time; the packagesideEffectsfield allowlistsdist/agents/**so bundlers keep that bootstrap).
- Migration for
- Agent clients in
sdk/clients, one client for both planes --AgentClientis an interface (the/agent/*control-plane surface);OrkesAgentClientis the implementation, obtained viaruntime.clientorOrkesClients.getAgentClient(). Both share a single underlyingConductorClient(and its one token mint) across control-plane and worker-plane calls -- no bespoke agent-layer auth/transport code exists. Naming note:getWorkflowClient()returns the general-purposeWorkflowExecutor; the agentWorkflowClient(OrkesClients.getAgentClient().workflows/getAgentWorkflowClient()) adds the agent-execution 404 fallback and token-usage rollup. AgentRuntime(configuration?, settings?)-- two independent, optional constructor arguments:configuration(connection/auth --OrkesApiConfigor a pre-builtConductorClient, same env chain as every other Conductor client:CONDUCTOR_*-> explicit config ->AGENTSPAN_*fallback ->http://localhost:8080default) andsettings(behavior-onlyAgentConfigOptions: worker polling/threads, streaming, liveness -- no connection fields).AgentConfigcarries only behavior now.- Verb contract --
serve(...agents, { blocking? })now deploys (registers the workflow def, same asdeploy) and serves in one call;{ blocking: false }returns once deploy + worker registration + polling have started instead of blocking until SIGINT/SIGTERM.deploy(...agents)gained a variadic form (DeploymentInfo[]) alongside the existing single-agentdeploy(agent, { schedules? })form.AgentHandle/ClientHandlegainedstop().wait()(both handle flavors) now rejects once a deadline passes (timeoutSeconds-derived, or 10 min default) with anAgentAPIErrornaming the last known status, instead of polling forever. RunSettings--RunOptions.runSettings(model,temperature,maxTokens,reasoningEffort,thinkingBudgetTokens) applies per-run LLM overrides torun/start/streamwithout mutating the agent's own config; unset fields keep the agent's values and overrides don't cascade to sub-agents.RunOptions.modelis sugar forrunSettings.model.- Credentials via
Task.runtimeMetadata, fail-closed -- the server resolves declared credentials at poll time and delivers them wire-only on the polled task'sruntimeMetadata; the SDK injects them into the worker'sprocess.envfor the call (mutate-invoke-restore) and never fetches or persists them separately. A tool whose declared credential wasn't delivered fails non-retryably naming the missing name -- there is no ambient-env fallback. Requires a server that persistsTaskDef.runtimeMetadataand deliversTask.runtimeMetadata(conductor-oss PR #1255 / agentspan server > 0.4.2); the CI matrix now runs the full agent e2e suite against bothagentspan-serverand the mainlineconductor-ossboot jar. - Liveness monitoring -- for a stateful (domain-routed) run, a new liveness monitor polls the execution's workflow every
livenessCheckIntervalSeconds(AgentConfigOptions.livenessEnabled, defaulttrue); aSCHEDULED/IN_PROGRESStask in that run's domain unpolled (pollCount === 0) pastlivenessStallSeconds(default 30s) rejects a blockingwait()with the newWorkerStallErrorinstead of hanging forever. Framework-spawned agents (no per-run domain) are unaffected. - Swarm hand-off contract -- the per-tool
{source}_transfer_to_{target}no-op worker now accepts an optionalmessagestring and echoes it back; the{agent}_check_transferworker addstransfer_message(the winning transfer call's message) and, when an LLM turn emits more than one transfer call,dropped_transfers(with a warning identifying the honored vs. dropped targets) so a fan-out intent is never silently collapsed to one transfer. SchedulerClientpause/resume works on both server families -- per-schedule pause/resume verbs differ by Conductor family (OSS/embedded map them PUT-only, Orkes GET-only).pauseSchedule/resumeSchedulenow issue PUT first and retry via GET only on HTTP 405 (stateless per call; the new optionalreasonon pause survives the fallback). Previously the GET-only calls failed against OSS/embedded servers. Admin bulk endpoints are unchanged.SchedulerClienttyped agent-schedule lifecycle -- absorbed from the deleted agentScheduleClient(below):save/get/listForAgent/pause/resume/delete/runNow/previewNext/reconcileoperating onSchedule/ScheduleInfowith${agent}-${name}wire-name prefixing and typed errors (ScheduleNotFound,ScheduleNameConflict,InvalidCronExpression). The constructor also acceptsPromiseLike<Client>for callers with async client construction.- Canonical metrics -- opt-in harmonized metric surface via
WORKER_CANONICAL_METRICS=true. See METRICS.md for the full catalog, configuration, and migration guide. - Bounded
urilabel onhttp_api_client_request_seconds: canonical mode uses path templates (e.g./workflow/{workflowId}) instead of fully-resolved paths, preventing metric cardinality explosion from dynamic IDs. TaskPausedevent type andPollerOptions.onPausedcallback: emitted when a poll cycle is skipped because the worker is paused. Canonical mode recordstask_paused_total; legacy mode does not (see Implementation Notes in METRICS.md).measurePayloadSizeoption inMetricsCollectorConfig: controls whetherworkflow_input_size_bytesis recorded viaJSON.stringifyon eachstartWorkflowcall. Defaults totruefor canonical,falsefor legacy.retryServerErrorsoption inOrkesApiConfig/RetryFetchOptionsandCONDUCTOR_RETRY_SERVER_ERRORSenv var: opt-in retry of HTTP 502/503/504 for idempotent methods (GET, HEAD, OPTIONS, PUT, DELETE). Defaultfalse; set totrueto enable.WorkflowStatusProbein harness: opt-in probe (viaHARNESS_PROBE_RATE_PER_SEC) that exercises UUID-bearing endpoints to validate template URI metrics.WORKER_LEGACY_METRICSis reserved for future use. Once canonical metrics become the default, settingWORKER_LEGACY_METRICS=truewill re-activate the legacy surface. It is not read by the current implementation.resolveOrkesConfig(used bycreateConductorClient, and so everyOrkesApiConfig-based client) gains anAGENTSPAN_*fallback tier for server URL and auth:CONDUCTOR_SERVER_URL-> explicit config ->AGENTSPAN_SERVER_URL-> defaulthttp://localhost:8080(previously an unset server URL threw; it now defaults instead). Auth follows the same shape:CONDUCTOR_AUTH_KEY/SECRET-> explicit config ->AGENTSPAN_AUTH_KEY/SECRET.createConductorClient()'s returned client gainsgetAuthenticationHeaders()(the sameX-Authorizationheader the standard call path attaches, for transports that can't go throughclient.request, e.g. SSE -- borrows the client's TTL-aware token, mints/caches nothing of its own) andstopBackgroundRefresh()(stops the client's background token-refresh interval; previously that handle was captured locally and dropped, leaking the interval for the life of the process).- Logger env chain:
DefaultLoggernow also readsAGENTSPAN_LOG_LEVELas a fallback whenCONDUCTOR_LOG_LEVELis unset.
- Legacy metrics emit unchanged when constructing
LegacyMetricsCollectordirectly (the pre-existing pattern). UsingcreateMetricsCollector()additionally enables automatic HTTP request timing via OpenAPI interceptors for both legacy and canonical modes; no other action required for existing deployments. MetricsCollector.tsrenamed toLegacyMetricsCollector.ts; the public symbol is preserved via re-export so existing imports keep working.http_api_client_requesttiming is now recorded automatically bywrapFetchWithRetrywhen a metrics collector is active (viacreateMetricsCollector()orsetHttpMetricsObserver), covering both successful responses and network-error fallback paths. A lightweight request interceptor captures OpenAPI path templates so the canonicalurilabel uses bounded-cardinality templates in all cases. Previously,recordApiRequestTimeexisted but was not wired into the HTTP pipeline -- details.- Added optional
durationMsfield toTaskUpdateFailureevent, recording the duration of the last update attempt. Declared optional so existing event listener implementations are unaffected.
- Agent
ScheduleClientandSchedulerFetcher(agents subpath; never released, no backward compatibility) -- schedules now ride the SDKSchedulerClient, re-exported from@io-orkes/conductor-javascript/agents. Method names and signatures are unchanged; migration is the import/type rename only (ScheduleClient->SchedulerClient). Theschedules.*namespace,runtime.schedulesClient(),deploy({ schedules })andAgentClient.schedule()are untouched.
- Legacy metric names remain the default during the transition period. Migration guidance is in METRICS.md.