Skip to content

fix(ai): ensure that tool calls batched in a single turn always run in parallel - #17623

Open
cdamus wants to merge 15 commits into
masterfrom
issue/17533-parallel-toolcalls
Open

fix(ai): ensure that tool calls batched in a single turn always run in parallel#17623
cdamus wants to merge 15 commits into
masterfrom
issue/17533-parallel-toolcalls

Conversation

@cdamus

@cdamus cdamus commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

What it does

Fixes #17533.

AI sub-agent delegations are ordinary tool calls, so whether several delegations issued by a coordinating agent in a single model turn run concurrently was decided entirely by each LLM provider's tool-call execution loop. Those loops were inconsistent: Anthropic and Google already ran a turn's tool calls in parallel, while the OpenAI Chat Completions, OpenAI Response API, Copilot, and Ollama providers ran them sequentially. As a result, parallel delegations (for example the PR reviewer or Architect fanning out explorations) executed one after another on those providers.

This PR makes the contract explicit and uniform: tool calls emitted within a single model response/turn are executed concurrently, since a model serializes genuinely dependent calls across turns instead of batching them.

  • Introduces an injectable ToolCallExecutor service in @theia/ai-core as the single common strategy for executing a turn's tool calls. It runs all matched handlers concurrently, applies uniform error handling (tool-not-found and thrown handlers become error results rather than rejections, so one failure never short-circuits its siblings), forwards cancellation, and returns results in input order so providers build their tool-result messages deterministically even though execution interleaves. It is bound in the root container so that downstream applications may rebind it.
  • Refactors every provider onto the executor: Anthropic and Google are pure drop-in refactors (they were already concurrent); the OpenAI Response API and Ollama loops are switched from sequential for loops to the executor
  • Replaces the OpenAI SDK runTools() runner, whose tool loop is strictly sequential, with a custom streaming/tool loop (ChatCompletionStreamingAsyncIterator) for the OpenAI Chat Completions and Copilot providers, so their turns also execute tool calls concurrently.
  • Introduces rebindable <provider>LanguageModelFactory bindings for instantiating the provider language models, so that downstream applications can substitute model implementations.
  • Fixes a latent listener leak in ChatResponseImpl: the per-content onDidChange forwarding listener registered by doAddContent was never disposed, and the stream parser re-adds preceding content (e.g. a tool call) on every streamed text token, so a tool call followed by a long text response accumulated one listener per token. This surfaced because functional parallel delegation drives the Explore agents through exactly that pattern.

Caution

Note to reviewers: the first two of these commits I consider to be quite straightforward and safe. The third, which reimplements in parallel the sequential mechanics of a third-party API that the OpenAI and Copilot providers were using, is more risky as it is quite a more complex change. So you might consider carving it off into a separate PR to merge the easier bits first. However, the original bug is not fixed without this change, because anybody using OpenAI ChatGPT model for subagent delegation will not see parallel execution without it: the AI preferences default to the Chat Completions API model implementation, which needs this more complex fix, instead of the Response API model, which relies on the simpler fix.

How to test

Select an OpenAI ChatGPT model (make sure that Response API is not enabled in the preferences) for the PR Reviewer agent and review this PR 😬 . Observe that the subagents looking at different aspects of the PR proceed not in sequence like this:

CleanShot 2026-06-04 at 12 30 09

but in parallel, like this:

CleanShot 2026-06-04 at 12 34 19

and in fact they may even finish out of order, like this:

CleanShot 2026-06-04 at 12 55 52

Then switch the OpenAI preferences to use the Response API and repeat the experiment.

Then repeat the experiment again with as many other models as you have access to.

Also check that you never see "Possible Emitter memory leak detected" warnings in the console during heavy sub-agent streaming.

Alternatively, a more focused experiment that additionally proves the ordering out outputs

The above experiment doesn't conclusively show (necessarily) that the outputs of parallel subagents are collated in the original request/call order. The following alternative scenario does.

Again, for all models that you have access to, and Open AI with and without Response API preference:

  1. Assign the model under test to the Architect agent and switch it to Plan Mode (Next) (that variant has no direct read/search tools and must delegate all exploration to the explore agent, and its prompt asks the model to batch delegations). Keep a fast, consistent model on the explore agent.
  2. Send a prompt that requires exploring several independent areas at once, e.g.: "Explore these four independent subsystems in parallel, delegating one Explore task per subsystem in a single batch and not waiting between them: packages/terminal, packages/debug, packages/search-in-workspace, packages/notebook. Summarize the main services and entry points of each."
  3. Observe that the delegated Explore sub-sessions run concurrently and (probably) complete out of order, while their results are collated back in request order by Architect. Compare wall-clock time to a single delegation. Repeat per provider by swapping the Architect's model.
  4. [Optional] Control: ask the Architect to explore the subsystems "one at a time, waiting for each result." Delegations should then run sequentially, confirming an agent can still serialize on purpose.

Also check that you never see "Possible Emitter memory leak detected" warnings in the console during heavy sub-agent streaming.

Follow-ups

  • The HuggingFace, Llamafile, and Vercel AI providers were intentionally left out of the executor refactor because Vercel already executes a step's tools concurrently. They could adopt the same pattern later for consistency.

Breaking changes

  • This PR introduces breaking changes and requires careful review. If yes, the breaking changes section in the changelog has been updated.

  • OpenAiLanguageModelsManagerImpl no longer injects OpenAiModelUtils or OpenAiResponseApiUtils and the openAiModelUtils and responseApiUtils protected fields were removed

  • OpenAiModel.createTools() and CopilotLanguageModel.createTools() now return ChatCompletionTool[] instead of RunnableToolFunctionWithoutParse[] because the OpenAI SDK runTools runner is no longer used

  • The provider language model classes (AnthropicModel, GoogleModel, OllamaModel, OpenAiModel, CopilotLanguageModel) no longer expose public constructors; instantiate them via the corresponding <provider>LanguageModelFactory instead

  • The exported OpenAiModelFactory and OllamaModelFactory symbols were renamed to OpenAiLanguageModelFactory and OllamaLanguageModelFactory

  • OpenAiModelUtils moved out of openai-language-model.ts into a new openai-model-utils.ts module

  • OpenAiModel and CopilotLanguageModel no longer have a protected toolCallExecutor field; ChatCompletionToolLoopOptions no longer has a toolCallExecutor property

Attribution

None.

Review checklist

Reminder for reviewers

@github-project-automation github-project-automation Bot moved this to Waiting on reviewers in PR Backlog Jun 4, 2026
@cdamus
cdamus force-pushed the issue/17533-parallel-toolcalls branch from 9c5d0c7 to 21d3093 Compare June 4, 2026 17:50
@cdamus

cdamus commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

I myself have tested this PR with:

  • Anthropic
  • Google
  • OpenAI (Chat Completions API)
  • OpenAI (Response API)
  • Ollama (using qwen3:8b)
  • Copilot

@cdamus
cdamus marked this pull request as ready for review June 5, 2026 12:46
cdamus added 3 commits June 8, 2026 07:57
…allExecutor

Agent delegations are ordinary tool calls, so whether parallel delegations
issued in a single model turn actually run concurrently was decided by each
provider's tool-call loop, and those loops were inconsistent: Anthropic and
Google ran them in parallel while the OpenAI Response API and Ollama ran them
sequentially. As a result, parallel delegations ran one-after-another on the
sequential providers.

Introduce an injectable `ToolCallExecutor` service in @theia/ai-core that
executes the tool calls of a single model turn concurrently (Promise.all) with
uniform error handling: tool-not-found and thrown handlers become error results
instead of rejections, so one failing call never short-circuits its siblings,
and results are returned in input order for deterministic message threading.
The concurrency contract ("tool calls in one turn run concurrently; the model
serializes dependent calls across turns") is documented on the service and on
ToolRequest.handler. The service is bound in DI so that adopters can rebind it.

Refactor Anthropic and Google onto the executor (no behavior change) and fix
the OpenAI Response API and Ollama providers to execute tool calls concurrently
while preserving their per-call side effects and ordering.

Part of #17533

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
ChatResponseImpl::doAddContent attached a forwarding onDidChange listener to
each newly added tool-call content but never disposed it. The stream parser
clears and re-adds prior content (including a preceding tool call) on every
streamed text token, so the same content accumulated one listener per token,
producing "Possible Emitter memory leak detected" warnings once an agent
streamed a long text response after a tool call. This surfaced via parallel
sub-agent delegation, which drives the Explore agents through exactly that
pattern.

Register the forwarding listeners against a DisposableCollection that
clearContent disposes, so that re-adding content no longer leaks listeners.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
The OpenAI Chat Completions and Copilot providers used the OpenAI SDK's
`chat.completions.runTools()` runner, whose built-in tool loop executes tool
calls strictly sequentially with no parallel option. As a result, parallel
agent delegations (which are tool calls) ran one after another on these
providers.

Replace the SDK runner with ChatCompletionStreamingAsyncIterator, which drives
the raw chunk stream and a multi-turn tool loop. The tool calls of each turn
are executed concurrently via the shared ToolCallExecutor; the iterator emits
the same stream-response part shapes as before (open / arguments-delta /
finished), threads the assistant tool_calls plus matching tool messages into
the next turn, honors maxChatCompletions, and aborts the in-flight stream on
cancellation. createTools now returns plain function tool definitions since the
SDK runner no longer invokes the handlers.

Fixes #17533

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
@cdamus
cdamus force-pushed the issue/17533-parallel-toolcalls branch from 21d3093 to 2084318 Compare June 8, 2026 11:58
@ndoschek
ndoschek requested review from eneufeld and sdirix June 11, 2026 07:46

@sdirix sdirix left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for the great PR 🎉

  • I tested all suggested models and in all of them parallel execution worked ✔️
  • I like the introduction of the model factories ✔️
    • Personally I would like to see them go one step further even, i.e. making the models themselves @injectable, but this could be part of a follow up
  • I like that we finally get rid of the runTools in OpenAI ✔️

Minor improvements:

  • I would remove some of the comments which are specific to the PR but not that important for the code
  • I would like to see different names for the new interfaces. See my comment

I noticed an issue (in general):

Cancelling parallel tool calls breaks the chat session when using Gemini models. This can be reproduced by instructing parallel code exploration or shell executions, cancelling the session and the trying to continue using the session.

The errors look like this:

Error 400:
Function call is missing a thought_signature in functionCall parts. This is required for tools to work correctly, and missing thought_signature may lead to degraded model performance. Additional data, function call `default_api:delegateToAgent` , position 14. Please refer to https://ai.google.dev/gemini-api/docs/thought-signatures for more details.

Note that I reproduced this is in current Theia as well so it's not a regression of this PR. If you see it in scope, please fix the issue here. If not, then I can create a dedicated ticket for this issue.

Comment thread packages/ai-openai/src/node/openai-response-api-utils.ts Outdated
Comment thread packages/ai-anthropic/src/node/anthropic-backend-module.ts
Comment thread packages/ai-core/src/common/tool-call-execution.ts Outdated
Comment thread packages/ai-anthropic/src/node/anthropic-language-model.ts Outdated
Comment thread packages/ai-anthropic/src/node/anthropic-language-model.ts Outdated
Comment thread packages/ai-openai/src/node/openai-backend-module.ts Outdated
Comment thread packages/ai-openai/src/node/openai-chat-completion-stream.ts Outdated
Comment thread packages/ai-openai/src/node/openai-language-model.ts Outdated
Comment thread packages/ai-openai/src/node/openai-language-model.ts Outdated
Comment thread packages/ai-openai/src/node/openai-response-api-utils.ts Outdated
@github-project-automation github-project-automation Bot moved this from Waiting on reviewers to Waiting on author in PR Backlog Jun 11, 2026
cdamus added 7 commits June 16, 2026 13:01
Remove comments in the code that don't explain anything that needed
explanation.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
Rename PreparedToolCall to ToolInvocation and ToolCallExecutionResult to
ToolCallOutcome, as suggested in review.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
Split ToolCallExecutor into a symbol & interface for substitutability.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
The executor holds no per-connection state, so bind it once in the root
container rather than per connection.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
The cap existed only to bound the OpenAI SDK runTools runner, which the
hand-rolled streaming tool loop replaced; the other providers run
uncapped.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
Make the provider language models @Injectable and bind them as
transient self-services. Their runtime configuration is injected
as a <provider>ModelParams object and their service dependencies
are injected separately; the <provider>LanguageModelFactory now
resolves the model from a child container that carries the params.
Public mutable fields are seeded from the params in @PostConstruct so
that the managers' patchLanguageModel/status mutations keep working.

Extract OpenAiModelUtils into its own file (openai-model-utils.ts) so
the model can inject it without a same-file forward-reference, per the
one-class-per-file guideline.

Use named loggers for new logging.

This lets adopters rebind any of these services to substitute custom
implementations.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
@cdamus

cdamus commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @sdirix this was really great feedback, so far 😀 I've pushed a merge and a bunch of commits to address your comments. I've also elected to take that further step that you mentioned in refactoring of the creation of the models, to bind the default implementation classes as transient self-services with their dependencies injected. Now the default factories just resolve the model implementations in child containers, widget-style.

I think though that the Gemini cancellation problem had best be raised as a separate issue; it really would be too much scope widening for this PR.

Let me know what you think of these changes!

@cdamus
cdamus requested a review from sdirix June 16, 2026 17:27
…l-subagents

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>

# Conflicts:
#	CHANGELOG.md
@sdirix

sdirix commented Jun 24, 2026

Copy link
Copy Markdown
Member

Can you resolve the merge conflicts?

@sdirix

sdirix commented Jun 24, 2026

Copy link
Copy Markdown
Member

Code looks good and I retested with the Anthropic models. I did not retest all other providers.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>

# Conflicts:
#	CHANGELOG.md
#	packages/ai-anthropic/src/node/anthropic-language-model.spec.ts
#	packages/ai-anthropic/src/node/anthropic-language-model.ts
#	packages/ai-anthropic/src/node/anthropic-language-models-manager-impl.ts
#	packages/ai-google/src/node/google-language-model.ts
#	packages/ai-google/src/node/google-language-models-manager-impl.ts
#	packages/ai-openai/src/node/openai-language-model.ts
@cdamus

cdamus commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @sdirix I've resolved merge conflicts in commit 41a1432. They were exclusively related to the server tools feature.

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>

# Conflicts:
#	CHANGELOG.md
#	packages/ai-anthropic/src/node/anthropic-language-model.spec.ts
#	packages/ai-anthropic/src/node/anthropic-language-model.ts
#	packages/ai-anthropic/src/node/anthropic-language-models-manager-impl.ts
#	packages/ai-chat/src/common/chat-model.ts
#	packages/ai-chat/src/common/chat-response-model.spec.ts
#	packages/ai-google/src/node/google-language-model.ts
#	packages/ai-google/src/node/google-language-models-manager-impl.ts
#	packages/ai-ollama/src/node/ollama-language-models-manager-impl.ts
#	packages/ai-openai/src/node/openai-language-model.spec.ts
#	packages/ai-openai/src/node/openai-language-model.ts
#	packages/ai-openai/src/node/openai-language-models-manager-impl.ts
#	packages/ai-openai/src/node/openai-response-api-utils.spec.ts
#	packages/ai-openai/src/node/openai-response-api-utils.ts
@cdamus

cdamus commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Hi @eneufeld and @sdirix I've integrated a lot of changes from master branch and resolved conflicts in commit dcbf0ae. The PR Reviewer still seems to be able to delegate in parallel to multiple sub-agents after this reconciliation 😀

@sdirix

sdirix commented Sep 1, 2026

Copy link
Copy Markdown
Member

@EclipseSourceAI

@EclipseSourceAI EclipseSourceAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Autonomous AI review.

This review was done by an AI agent and therefore may contain mistakes. Feel free to ignore any comment you disagree with. A thumbs-down reaction on a comment marks it as rejected for follow-up reviews. Noting why in a reply helps, since replies are read too.

Resolving all AI comments does not lead to an automatic approval. A maintainer still needs to review and sign off on the overall architecture and design.

To get an updated review after pushing changes, a maintainer may re-request a review from this account.

Running in Eclipse Enclave, submitted via review-guard-mcp

What this PR does

Makes "tool calls emitted in one model turn run concurrently" an explicit, provider-independent contract. A new injectable ToolCallExecutor in @theia/ai-core runs a turn's calls via Promise.all, normalizes errors (tool-not-found and thrown handlers become error results instead of rejections), forwards a cancellation token, and returns outcomes in input order. Anthropic and Google are drop-in refactors; the OpenAI Response API and Ollama loops switch from sequential for loops to the executor; and the OpenAI Chat Completions / Copilot path drops the SDK's runTools() runner in favour of a hand-written ChatCompletionStreamingAsyncIterator over the raw chunk stream. On top of that the provider model classes become @injectable and are created through new <provider>LanguageModelFactory bindings.

Review notes

I compiled the affected packages (tsc --build) and ran their specs: 235 passing, no type errors. I did not verify in the UI, since exercising parallel delegation needs live provider credentials that this run does not have. The author reports manual testing against all six providers and sdirix confirmed parallel execution across the tested models.

Where I would focus:

  • ChatCompletionStreamingAsyncIterator is the risky part, as the author flags himself. It reimplements the SDK's tool loop: delta accumulation keyed by index, the assistant/tool message pairing for the next turn, cancellation via controller.abort(). The tests cover the happy paths well. The one concrete gap I found is the "open" tool-call part being emitted before the function name is necessarily known (inline comment), which is unrecoverable downstream because merge never updates the name.
  • Executor semantics are sound. Input-order results, one onResult per call, a throwing onResult cannot break the batch, and the not-found/throw cases are covered by tool-call-execution.spec.ts. Ollama is the only caller that does not pass the cancellation token.
  • Reuse: the PR extracts AbstractStreamingResponseIterator but leaves ResponseApiToolCallIterator in the same file duplicating that queue verbatim.
  • Breaking changes: the CHANGELOG list is good but incomplete (two removed exported symbols plus the OpenAiModelUtils module move). Also the PR description is now stale: it says ToolCallExecutor is connection-scoped and lists an OpenAiResponseApiUtils scope change, but the final code binds both in the root container.
  • The console.* to ILogger conversions across the provider models are drive-by, though they follow naturally from making the models injectable. A maintainer should decide whether that is acceptable scope here.

Nothing I found looks like a merge blocker.

Comment thread packages/ai-openai/src/node/openai-chat-completion-stream.ts Outdated
Comment thread packages/ai-openai/src/node/streaming-response-iterator.ts
Comment thread packages/ai-ollama/src/node/ollama-language-model.ts Outdated
Comment thread packages/ai-openai/src/node/openai-chat-completion-stream.ts Outdated
Comment thread CHANGELOG.md Outdated
Comment thread packages/ai-ollama/src/package.spec.ts Outdated
…eview feedback

Addresses the EclipseSourceAI review and additional off-line review:

- ai-openai: withhold the "open" tool-call stream part until both id and
  name are known, so a call streamed with the name after the id never
  gets stuck nameless in the UI/replay.
- ai-openai: fold the duplicated producer/consumer queue of
  ResponseApiToolCallIterator onto the extracted
  AbstractStreamingResponseIterator base class.
- ai-openai: have ChatCompletionStreamingAsyncIterator inject
  ToolCallExecutor itself instead of threading it through
  ChatCompletionToolLoopOptions and every provider model.
- ai-openai: terminate ChatCompletionStreamingAsyncIterator promptly on
  cancellation instead of only aborting the provider stream, closing the
  race where a pending next() could stall behind an uninterruptible tool
  handler, where cancellation could still let queued tool calls start,
  and where a late tool result could leak out after cancellation.
- ai-ollama: thread the request's CancellationToken through
  processToolCalls into ToolCallExecutor and forward
  ToolInvocationContext through the tool handler adapter, which
  previously dropped both.
- ai-ollama: make processToolCalls protected (matching the other
  provider models) instead of casting around its private visibility in
  tests.
- CHANGELOG.md: list the additional breaking API changes the review
  flagged as missing (renamed <provider>ModelFactory symbols, moved
  OpenAiModelUtils, removed toolCallExecutor fields).

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>
@cdamus

cdamus commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Commit 395fa57 addresses all of the EclipseSourceAI bot's comments, plus an additional problem that I found myself in the OpenAI chat completion stream: cancellation did not promptly terminate the iterator while tools execute.

@EclipseSourceAI EclipseSourceAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Autonomous AI review.

This review was done by an AI agent and therefore may contain mistakes. Feel free to ignore any comment you disagree with. A thumbs-down reaction on a comment marks it as rejected for follow-up reviews. Noting why in a reply helps, since replies are read too.

Resolving all AI comments does not lead to an automatic approval. A maintainer still needs to review and sign off on the overall architecture and design.

To get an updated review after pushing changes, a maintainer may re-request a review from this account.

Running in Eclipse Enclave, submitted via review-guard-mcp

Follow-up review. Only one commit landed since my last pass (395fa57), and it's entirely a response to that review plus one extra fix the author found himself (prompt cancellation could stall behind an uninterruptible tool handler in ChatCompletionStreamingAsyncIterator, or let a late tool result leak out after cancellation). I traced through cancel()/handleIncoming()/dispose() and the new spec cases (including the two cancellation-race tests) and the fix is sound: done is checked before delivering any part, dispose() is idempotent, and the executor's cancellation token still reaches Ollama's tool handlers via ToolInvocationContext.

No new findings from this pass.

These previous comments can be resolved as they are now handled:

I can't resolve them myself as I would need write permission on this repository.

@sdirix

sdirix commented Sep 2, 2026

Copy link
Copy Markdown
Member

The changelog entries are now waaaaaaay too long and extensive for my taste.

…l-toolcalls

Signed-off-by: Christian W. Damus <cdamus@eclipsesource.com>

# Conflicts:
#	CHANGELOG.md
#	packages/ai-copilot/src/node/copilot-backend-module.ts
#	packages/ai-copilot/src/node/copilot-language-model.spec.ts
#	packages/ai-copilot/src/node/copilot-language-model.ts
#	packages/ai-copilot/src/node/copilot-language-models-manager-impl.ts
@cdamus

cdamus commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

The changelog entries are now waaaaaaay too long and extensive for my taste.

Thanks! I've resolved conflicts and tried to reduce the verbosity of the changelog, which was helped by all of my Copilot changes having been obviated by incoming feature work from master (all of the tool calling is now handled within the Copilot CLI, so no longer our responsibility).

@EclipseSourceAI EclipseSourceAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Autonomous AI review.

This review was done by an AI agent and therefore may contain mistakes. Feel free to ignore any comment you disagree with. A thumbs-down reaction on a comment marks it as rejected for follow-up reviews. Noting why in a reply helps, since replies are read too.

Resolving all AI comments does not lead to an automatic approval. A maintainer still needs to review and sign off on the overall architecture and design.

To get an updated review after pushing changes, a maintainer may re-request a review from this account.

Running in Eclipse Enclave, submitted via review-guard-mcp

Follow-up review. Since my last pass (commit 395fa57) the only thing that landed is the merge from master (commit 7802c24).

Checked the diff: ai-core, ai-openai, ai-anthropic, ai-google and ai-ollama have zero changes since 395fa57, so the code I already reviewed there is untouched. The CHANGELOG.md entries for this PR got reordered/reworded during conflict resolution but the content is the same, still complete and accurate about the breaking changes. ai-copilot is no longer touched by this PR at all: the Copilot CLI migration from master (#17919) replaced the REST-based CopilotLanguageModel this PR used to touch, so the tool-call concurrency question for Copilot is now handled entirely inside the CLI, outside this PR's scope, matching what the author said in the PR thread.

No new findings from this pass. All threads I raised earlier are already marked resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Waiting on author

Development

Successfully merging this pull request may close these issues.

Execute Agent delegations in parallel

3 participants