diff --git a/.changeset/claude-rate-limit-handling.md b/.changeset/claude-rate-limit-handling.md deleted file mode 100644 index 8656345..0000000 --- a/.changeset/claude-rate-limit-handling.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -"a2a-claude": minor -"@a2a-wrapper/core": minor ---- - -Handle Claude rate limit events instead of failing the turn generically. - -Rate-limit signals were previously unrecognised: `rate_limit_event`, -`system/api_retry`, and assistant `rate_limit` errors all fell through to a -debug log, and the turn surfaced as `failed` with `"Error during execution."` - -A rejection now ends the turn immediately with an `input-required` status naming -the limit type and reset time, plus structured metadata (`reason`, -`rateLimitType`, `resetsAt`, `resetsAtIso`, `utilization`, and `errorCode` / -`canPurchaseCredits` when the SDK reports them). The task stays non-terminal, so -the client continues the same conversation on the same task once the limit -resets. Configurable via `rateLimit.taskState` for clients that require a -terminal state. - -This does not shorten the SDK's own retry behaviour: a `system/api_retry` is -deliberately treated as a warning that does not end the turn, so the SDK's -internal retries still run to exhaustion inside the same `timeouts.prompt` -window. The turn ends only once the SDK gives up and emits an assistant -`rate_limit` error. Those retries are at least visible now, as `rate_limit` -sideband events with `action: "retrying"` carrying the SDK's `attempt`, -`maxRetries`, and `delayMs`. - -A rejection whose overage window is still open is treated as a warning rather -than a rejection, since the request may proceed on overage credits; if it does -not, the assistant `rate_limit` error still ends the turn. Limit details are -never fabricated — a limit type or reset time is inherited by a later signal -only from a snapshot that reported pressure, utilization is never inherited, and -a reset time that is not in the future is dropped. - -Adds a `rate_limit` sideband event type to `@a2a-wrapper/core`, gated by -`features.emitRateLimitEvents`. diff --git a/.changeset/hold-task-for-background-work.md b/.changeset/hold-task-for-background-work.md deleted file mode 100644 index 2380bb3..0000000 --- a/.changeset/hold-task-for-background-work.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -"a2a-claude": minor -"@a2a-wrapper/core": minor ---- - -Hold the A2A Task open while Claude has background work in flight. - -A Task used to reach a terminal state as soon as Claude's first turn ended — -even when that turn had just started a background process and said it was -waiting on the result. A2A gives an agent no way to open a new turn against a -terminal Task, so the follow-up report had nowhere to land. - -The Task now stays in `working` for as long as Claude reports background work -running, and completes only once a turn ends with nothing left. Each turn -publishes its own `response` artifact and a non-final `working` status update -whose `metadata.backgroundTasks` lists what is still in flight. Chains of any -length work this way, as rounds of one Task rather than several Tasks. - -Controlled by `features.holdTaskForBackgroundWork` (default `true`; set -`false` for the old complete-at-first-result behavior) and -`features.emitBackgroundTaskEvents` (default `true`), which publishes a new -`background_tasks` sideband event — added to `@a2a-wrapper/core` — each time -the live set changes. - -Bumps `@anthropic-ai/claude-agent-sdk` from `0.3.202` to `0.3.245`. The -feature needs at least `0.3.235`, the first version to emit -`background_tasks_changed`. - -Three changes apply even with `holdTaskForBackgroundWork` off: - -- Queries now use streaming input rather than a string prompt. A string prompt - makes the SDK close the CLI subprocess's stdin on the first result, which - ends the process before a second round is possible. This is not switchable. -- `agent_started` / `agent_finished` are emitted once per A2A Task rather than - once per SDK turn. -- A success result with empty text no longer publishes an empty `response` - artifact. - -See the a2a-claude README for caveats, including how `claude.maxTurns` and -`timeouts.prompt` now span a held-open Task's rounds. diff --git a/.changeset/prompt-timeout-disable.md b/.changeset/prompt-timeout-disable.md deleted file mode 100644 index ad6009a..0000000 --- a/.changeset/prompt-timeout-disable.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"a2a-claude": minor ---- - -Allow `timeouts.prompt` to be disabled by setting it to `0` (or any value `<= 0`). Previously every turn was bounded at ten minutes by default with no way to opt out, which cut off legitimately long-running turns. - -Negative values were also a footgun: `setTimeout` coerces a negative delay to the next tick, so `prompt: -1` — the intuitive spelling for "no timeout" — aborted the turn immediately instead of disabling the bound. The timer is now armed only for positive values, matching the "set to `0` to disable" convention already used for `healthCheck`. diff --git a/.changeset/rate-limit-fail-task.md b/.changeset/rate-limit-fail-task.md deleted file mode 100644 index e00a2bc..0000000 --- a/.changeset/rate-limit-fail-task.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -"a2a-claude": minor ---- - -**Breaking:** a rate limit now always fails the task. The `rateLimit.taskState` -config option is removed. - -It previously defaulted to `input-required`, on the reasoning that leaving the -task open let the client continue the same conversation. That reasoning does not -hold: - -- **The interrupted turn cannot resume.** `ctx.task` only suppresses the initial - `Task` record; the prompt sent is always the new user message, and there is no - replay or continue-previous-turn logic. A follow-up on the open task is just a - new prompt appended to the conversation — exactly what a new task would send. -- **Continuity never depended on the task state.** It comes from the - `contextId` → Claude session mapping in `SessionManager`, which is indifferent - to how a task ended. A new task on the same `contextId` resumes the identical - Claude session. -- **`input-required` means the agent lacks information.** A rate limit lacks - quota; nothing the client sends unblocks it, only elapsed time. Clients with - generic `input-required` handling would prompt a human for input nobody wants. -- Publishing a non-terminal state alongside `final: true` was also internally - inconsistent. - -The status message now always points at the `contextId` rather than the closed -task, and still carries the structured metadata (`reason`, `rateLimitType`, -`resetsAt`, `resetsAtIso`, `utilization`) that an orchestrator needs to schedule -its own retry. `features.emitRateLimitEvents` is unchanged. - -Migration: remove any `rateLimit` block from your config. If your orchestrator -alerts on failed tasks, key the suppression on `metadata.reason === "rate_limit"`. diff --git a/.changeset/session-ttl-disabled-by-default.md b/.changeset/session-ttl-disabled-by-default.md deleted file mode 100644 index 86fb9b5..0000000 --- a/.changeset/session-ttl-disabled-by-default.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -"a2a-claude": minor ---- - -**Breaking:** session expiry is now disabled by default (`session.ttl` defaults -to `0`), and the background cleanup sweep with it (`session.cleanupInterval` -also defaults to `0`). Set `"session.ttl": 3600000` and -`"session.cleanupInterval": 300000` to restore the previous behaviour. - -Previously sessions expired one hour after their **first** message regardless of -activity, which silently dropped the `contextId` → Claude session mapping and -made a conversation lose all of its context with no error and only an -`info`-level log line. Evicting the record reclaimed no disk either — the wrapper -never deletes SDK session files, so eviction orphaned the transcript rather than -removing it. - -`session.ttl <= 0` now disables expiry in both eviction paths. A positive `ttl` -behaves as before. - -`cleanupInterval` is only ever consulted when `ttl > 0` — with expiry off there -is nothing to sweep — so leaving it at `300000` alongside `ttl: 0` was dead -configuration that read as if it did something. It now defaults to `0` to match, -and both example configs drop it entirely. If you set `ttl` on its own you get -expiry via the lazy check in `getOrCreate`, but a context that is never used -again holds its record until the process exits; set `cleanupInterval` too if you -want that reclaimed. Both disabled states are now logged at startup, so neither -can be lost silently. - -Known consequence: if a Claude session's on-disk transcript is removed while the -server is running, the stored `contextId` → `sessionId` mapping is now pinned for -the life of the process instead of being evicted within the hour, so turns on -that context keep failing to resume until the server restarts. Previously the -one-hour expiry masked this by self-healing. diff --git a/a2a-antigravity/CHANGELOG.md b/a2a-antigravity/CHANGELOG.md index beda35c..fcbe36d 100644 --- a/a2a-antigravity/CHANGELOG.md +++ b/a2a-antigravity/CHANGELOG.md @@ -1,5 +1,13 @@ # a2a-antigravity +## 0.2.1 + +### Patch Changes + +- Updated dependencies [f3c7062] +- Updated dependencies [41e2d82] + - @a2a-wrapper/core@2.1.0 + ## 0.2.0 ### Minor Changes diff --git a/a2a-antigravity/package.json b/a2a-antigravity/package.json index f6242d1..923c4b7 100644 --- a/a2a-antigravity/package.json +++ b/a2a-antigravity/package.json @@ -1,6 +1,6 @@ { "name": "a2a-antigravity", - "version": "0.2.0", + "version": "0.2.1", "description": "A2A (Agent-to-Agent) protocol wrapper for Google Antigravity SDK. Exposes Antigravity through the shared HTTP/JSON-RPC/REST/SSE A2A surface using a private Python SDK bridge.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -59,7 +59,7 @@ }, "dependencies": { "@a2a-js/sdk": "^1.0.0", - "@a2a-wrapper/core": "2.0.0", + "@a2a-wrapper/core": "2.1.0", "express": "^4.18.2", "uuid": "^9.0.0" }, diff --git a/a2a-claude/CHANGELOG.md b/a2a-claude/CHANGELOG.md index 9f5c85a..85e9c87 100644 --- a/a2a-claude/CHANGELOG.md +++ b/a2a-claude/CHANGELOG.md @@ -1,5 +1,146 @@ # a2a-claude +## 0.4.0 + +### Minor Changes + +- f3c7062: Handle Claude rate limit events instead of failing the turn generically. + + Rate-limit signals were previously unrecognised: `rate_limit_event`, + `system/api_retry`, and assistant `rate_limit` errors all fell through to a + debug log, and the turn surfaced as `failed` with `"Error during execution."` + + A rejection now ends the turn immediately with an `input-required` status naming + the limit type and reset time, plus structured metadata (`reason`, + `rateLimitType`, `resetsAt`, `resetsAtIso`, `utilization`, and `errorCode` / + `canPurchaseCredits` when the SDK reports them). The task stays non-terminal, so + the client continues the same conversation on the same task once the limit + resets. Configurable via `rateLimit.taskState` for clients that require a + terminal state. + + This does not shorten the SDK's own retry behaviour: a `system/api_retry` is + deliberately treated as a warning that does not end the turn, so the SDK's + internal retries still run to exhaustion inside the same `timeouts.prompt` + window. The turn ends only once the SDK gives up and emits an assistant + `rate_limit` error. Those retries are at least visible now, as `rate_limit` + sideband events with `action: "retrying"` carrying the SDK's `attempt`, + `maxRetries`, and `delayMs`. + + A rejection whose overage window is still open is treated as a warning rather + than a rejection, since the request may proceed on overage credits; if it does + not, the assistant `rate_limit` error still ends the turn. Limit details are + never fabricated — a limit type or reset time is inherited by a later signal + only from a snapshot that reported pressure, utilization is never inherited, and + a reset time that is not in the future is dropped. + + Adds a `rate_limit` sideband event type to `@a2a-wrapper/core`, gated by + `features.emitRateLimitEvents`. + +- 41e2d82: Hold the A2A Task open while Claude has background work in flight. + + A Task used to reach a terminal state as soon as Claude's first turn ended — + even when that turn had just started a background process and said it was + waiting on the result. A2A gives an agent no way to open a new turn against a + terminal Task, so the follow-up report had nowhere to land. + + The Task now stays in `working` for as long as Claude reports background work + running, and completes only once a turn ends with nothing left. Each turn + publishes its own `response` artifact and a non-final `working` status update + whose `metadata.backgroundTasks` lists what is still in flight. Chains of any + length work this way, as rounds of one Task rather than several Tasks. + + Controlled by `features.holdTaskForBackgroundWork` (default `true`; set + `false` for the old complete-at-first-result behavior) and + `features.emitBackgroundTaskEvents` (default `true`), which publishes a new + `background_tasks` sideband event — added to `@a2a-wrapper/core` — each time + the live set changes. + + Bumps `@anthropic-ai/claude-agent-sdk` from `0.3.202` to `0.3.245`. The + feature needs at least `0.3.235`, the first version to emit + `background_tasks_changed`. + + Three changes apply even with `holdTaskForBackgroundWork` off: + + - Queries now use streaming input rather than a string prompt. A string prompt + makes the SDK close the CLI subprocess's stdin on the first result, which + ends the process before a second round is possible. This is not switchable. + - `agent_started` / `agent_finished` are emitted once per A2A Task rather than + once per SDK turn. + - A success result with empty text no longer publishes an empty `response` + artifact. + + See the a2a-claude README for caveats, including how `claude.maxTurns` and + `timeouts.prompt` now span a held-open Task's rounds. + +- ddc0861: Allow `timeouts.prompt` to be disabled by setting it to `0` (or any value `<= 0`). Previously every turn was bounded at ten minutes by default with no way to opt out, which cut off legitimately long-running turns. + + Negative values were also a footgun: `setTimeout` coerces a negative delay to the next tick, so `prompt: -1` — the intuitive spelling for "no timeout" — aborted the turn immediately instead of disabling the bound. The timer is now armed only for positive values, matching the "set to `0` to disable" convention already used for `healthCheck`. + +- a9101a1: **Breaking:** a rate limit now always fails the task. The `rateLimit.taskState` + config option is removed. + + It previously defaulted to `input-required`, on the reasoning that leaving the + task open let the client continue the same conversation. That reasoning does not + hold: + + - **The interrupted turn cannot resume.** `ctx.task` only suppresses the initial + `Task` record; the prompt sent is always the new user message, and there is no + replay or continue-previous-turn logic. A follow-up on the open task is just a + new prompt appended to the conversation — exactly what a new task would send. + - **Continuity never depended on the task state.** It comes from the + `contextId` → Claude session mapping in `SessionManager`, which is indifferent + to how a task ended. A new task on the same `contextId` resumes the identical + Claude session. + - **`input-required` means the agent lacks information.** A rate limit lacks + quota; nothing the client sends unblocks it, only elapsed time. Clients with + generic `input-required` handling would prompt a human for input nobody wants. + - Publishing a non-terminal state alongside `final: true` was also internally + inconsistent. + + The status message now always points at the `contextId` rather than the closed + task, and still carries the structured metadata (`reason`, `rateLimitType`, + `resetsAt`, `resetsAtIso`, `utilization`) that an orchestrator needs to schedule + its own retry. `features.emitRateLimitEvents` is unchanged. + + Migration: remove any `rateLimit` block from your config. If your orchestrator + alerts on failed tasks, key the suppression on `metadata.reason === "rate_limit"`. + +- 3ec9e49: **Breaking:** session expiry is now disabled by default (`session.ttl` defaults + to `0`), and the background cleanup sweep with it (`session.cleanupInterval` + also defaults to `0`). Set `"session.ttl": 3600000` and + `"session.cleanupInterval": 300000` to restore the previous behaviour. + + Previously sessions expired one hour after their **first** message regardless of + activity, which silently dropped the `contextId` → Claude session mapping and + made a conversation lose all of its context with no error and only an + `info`-level log line. Evicting the record reclaimed no disk either — the wrapper + never deletes SDK session files, so eviction orphaned the transcript rather than + removing it. + + `session.ttl <= 0` now disables expiry in both eviction paths. A positive `ttl` + behaves as before. + + `cleanupInterval` is only ever consulted when `ttl > 0` — with expiry off there + is nothing to sweep — so leaving it at `300000` alongside `ttl: 0` was dead + configuration that read as if it did something. It now defaults to `0` to match, + and both example configs drop it entirely. If you set `ttl` on its own you get + expiry via the lazy check in `getOrCreate`, but a context that is never used + again holds its record until the process exits; set `cleanupInterval` too if you + want that reclaimed. Both disabled states are now logged at startup, so neither + can be lost silently. + + Known consequence: if a Claude session's on-disk transcript is removed while the + server is running, the stored `contextId` → `sessionId` mapping is now pinned for + the life of the process instead of being evicted within the hour, so turns on + that context keep failing to resume until the server restarts. Previously the + one-hour expiry masked this by self-healing. + +### Patch Changes + +- Updated dependencies [f3c7062] +- Updated dependencies [41e2d82] + - @a2a-wrapper/core@2.1.0 + ## 0.3.0 ### Minor Changes diff --git a/a2a-claude/package.json b/a2a-claude/package.json index b9d754f..d752c3f 100644 --- a/a2a-claude/package.json +++ b/a2a-claude/package.json @@ -1,6 +1,6 @@ { "name": "a2a-claude", - "version": "0.3.0", + "version": "0.4.0", "description": "A2A (Agent-to-Agent) protocol wrapper for Claude Code via the Claude Agent SDK. Drop a JSON config file in, get a fully-spec-compliant A2A server out. Supports permission modes, MCP tools, streaming sideband events, and multi-agent delegation.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -54,7 +54,7 @@ }, "dependencies": { "@a2a-js/sdk": "^1.0.0", - "@a2a-wrapper/core": "2.0.0", + "@a2a-wrapper/core": "2.1.0", "@anthropic-ai/claude-agent-sdk": "0.3.245", "express": "^4.18.2", "uuid": "^9.0.0" diff --git a/a2a-codex/CHANGELOG.md b/a2a-codex/CHANGELOG.md index 6ae8f35..08ecdf7 100644 --- a/a2a-codex/CHANGELOG.md +++ b/a2a-codex/CHANGELOG.md @@ -1,5 +1,13 @@ # a2a-codex +## 1.7.1 + +### Patch Changes + +- Updated dependencies [f3c7062] +- Updated dependencies [41e2d82] + - @a2a-wrapper/core@2.1.0 + ## 1.7.0 ### Minor Changes diff --git a/a2a-codex/package.json b/a2a-codex/package.json index b63ff93..97a5572 100644 --- a/a2a-codex/package.json +++ b/a2a-codex/package.json @@ -1,6 +1,6 @@ { "name": "a2a-codex", - "version": "1.7.0", + "version": "1.7.1", "description": "A2A (Agent-to-Agent) protocol wrapper for OpenAI Codex SDK. Drop a JSON config file in, get a fully-spec-compliant A2A server out. Supports repository sandboxing, MCP tools, streaming sideband events, and multi-agent delegation.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -54,7 +54,7 @@ }, "dependencies": { "@a2a-js/sdk": "^1.0.0", - "@a2a-wrapper/core": "2.0.0", + "@a2a-wrapper/core": "2.1.0", "@openai/codex-sdk": "^0.137.0", "express": "^4.18.2", "uuid": "^9.0.0" diff --git a/a2a-copilot/CHANGELOG.md b/a2a-copilot/CHANGELOG.md index 8d7c5b2..e482047 100644 --- a/a2a-copilot/CHANGELOG.md +++ b/a2a-copilot/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.8.1 + +### Patch Changes + +- Updated dependencies [f3c7062] +- Updated dependencies [41e2d82] + - @a2a-wrapper/core@2.1.0 + ## 1.8.0 ### Minor Changes diff --git a/a2a-copilot/package.json b/a2a-copilot/package.json index 597892b..1ace20c 100644 --- a/a2a-copilot/package.json +++ b/a2a-copilot/package.json @@ -1,6 +1,6 @@ { "name": "a2a-copilot", - "version": "1.8.0", + "version": "1.8.1", "description": "A2A (Agent-to-Agent) protocol wrapper for the GitHub Copilot SDK. Drop a JSON config file in, get a fully-spec-compliant A2A server out. Supports any agent persona, MCP tool servers, streaming, context building, and multi-turn conversations.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -57,7 +57,7 @@ }, "dependencies": { "@a2a-js/sdk": "^1.0.0", - "@a2a-wrapper/core": "2.0.0", + "@a2a-wrapper/core": "2.1.0", "@github/copilot-sdk": "^1.0.0", "express": "^4.18.2", "uuid": "^9.0.0" diff --git a/a2a-opencode/CHANGELOG.md b/a2a-opencode/CHANGELOG.md index e2bd3ad..9e0ef82 100644 --- a/a2a-opencode/CHANGELOG.md +++ b/a2a-opencode/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.7.1 + +### Patch Changes + +- Updated dependencies [f3c7062] +- Updated dependencies [41e2d82] + - @a2a-wrapper/core@2.1.0 + ## 1.7.0 ### Minor Changes diff --git a/a2a-opencode/package.json b/a2a-opencode/package.json index 53aade1..c91dc41 100644 --- a/a2a-opencode/package.json +++ b/a2a-opencode/package.json @@ -1,6 +1,6 @@ { "name": "a2a-opencode", - "version": "1.7.0", + "version": "1.7.1", "description": "A2A (Agent-to-Agent) protocol wrapper for OpenCode. Drop a JSON config file in, get a fully-spec-compliant A2A server out. Supports any agent persona, MCP tool servers, SSE streaming with polling fallback, context building, and multi-turn conversations.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -53,7 +53,7 @@ }, "dependencies": { "@a2a-js/sdk": "^1.0.0", - "@a2a-wrapper/core": "2.0.0", + "@a2a-wrapper/core": "2.1.0", "@opencode-ai/sdk": "^1.15.13", "express": "^4.18.2", "swagger-ui-express": "^5.0.1", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index df4be88..fa46717 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,77 @@ # Changelog +## 2.1.0 + +### Minor Changes + +- f3c7062: Handle Claude rate limit events instead of failing the turn generically. + + Rate-limit signals were previously unrecognised: `rate_limit_event`, + `system/api_retry`, and assistant `rate_limit` errors all fell through to a + debug log, and the turn surfaced as `failed` with `"Error during execution."` + + A rejection now ends the turn immediately with an `input-required` status naming + the limit type and reset time, plus structured metadata (`reason`, + `rateLimitType`, `resetsAt`, `resetsAtIso`, `utilization`, and `errorCode` / + `canPurchaseCredits` when the SDK reports them). The task stays non-terminal, so + the client continues the same conversation on the same task once the limit + resets. Configurable via `rateLimit.taskState` for clients that require a + terminal state. + + This does not shorten the SDK's own retry behaviour: a `system/api_retry` is + deliberately treated as a warning that does not end the turn, so the SDK's + internal retries still run to exhaustion inside the same `timeouts.prompt` + window. The turn ends only once the SDK gives up and emits an assistant + `rate_limit` error. Those retries are at least visible now, as `rate_limit` + sideband events with `action: "retrying"` carrying the SDK's `attempt`, + `maxRetries`, and `delayMs`. + + A rejection whose overage window is still open is treated as a warning rather + than a rejection, since the request may proceed on overage credits; if it does + not, the assistant `rate_limit` error still ends the turn. Limit details are + never fabricated — a limit type or reset time is inherited by a later signal + only from a snapshot that reported pressure, utilization is never inherited, and + a reset time that is not in the future is dropped. + + Adds a `rate_limit` sideband event type to `@a2a-wrapper/core`, gated by + `features.emitRateLimitEvents`. + +- 41e2d82: Hold the A2A Task open while Claude has background work in flight. + + A Task used to reach a terminal state as soon as Claude's first turn ended — + even when that turn had just started a background process and said it was + waiting on the result. A2A gives an agent no way to open a new turn against a + terminal Task, so the follow-up report had nowhere to land. + + The Task now stays in `working` for as long as Claude reports background work + running, and completes only once a turn ends with nothing left. Each turn + publishes its own `response` artifact and a non-final `working` status update + whose `metadata.backgroundTasks` lists what is still in flight. Chains of any + length work this way, as rounds of one Task rather than several Tasks. + + Controlled by `features.holdTaskForBackgroundWork` (default `true`; set + `false` for the old complete-at-first-result behavior) and + `features.emitBackgroundTaskEvents` (default `true`), which publishes a new + `background_tasks` sideband event — added to `@a2a-wrapper/core` — each time + the live set changes. + + Bumps `@anthropic-ai/claude-agent-sdk` from `0.3.202` to `0.3.245`. The + feature needs at least `0.3.235`, the first version to emit + `background_tasks_changed`. + + Three changes apply even with `holdTaskForBackgroundWork` off: + + - Queries now use streaming input rather than a string prompt. A string prompt + makes the SDK close the CLI subprocess's stdin on the first result, which + ends the process before a second round is possible. This is not switchable. + - `agent_started` / `agent_finished` are emitted once per A2A Task rather than + once per SDK turn. + - A success result with empty text no longer publishes an empty `response` + artifact. + + See the a2a-claude README for caveats, including how `claude.maxTurns` and + `timeouts.prompt` now span a held-open Task's rounds. + ## 2.0.0 ### Major Changes diff --git a/packages/core/package.json b/packages/core/package.json index 326ac59..0c8504a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@a2a-wrapper/core", - "version": "2.0.0", + "version": "2.1.0", "description": "Shared infrastructure core for A2A protocol wrapper projects. Provides logging, configuration loading, event publishing, agent card building, server bootstrapping, session management, and CLI scaffolding.", "type": "module", "exports": {