feat(agentic-ai): add native Anthropic provider for the v2 AI Agent connectors - #8069
Draft
maff wants to merge 35 commits into
Draft
feat(agentic-ai): add native Anthropic provider for the v2 AI Agent connectors#8069maff wants to merge 35 commits into
maff wants to merge 35 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a native Anthropic Messages provider to the v2 AI Agent connectors.
Changes:
- Adds direct and compatible Anthropic backends, converters, streaming, reasoning, caching, and proxy support.
- Registers the provider and regenerates standard/hybrid templates.
- Adds unit, integration, wire-format, and real-provider tests.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
AgentTestFixtures.java |
Adds v2 template fixtures. |
AgentSubProcessAnthropicPromptCachingTests.java |
Tests prompt caching. |
AgentSubProcessAnthropicReasoningEffortTests.java |
Tests reasoning and effort. |
BaseAnthropicNativeSubProcessTest.java |
Adds native Anthropic E2E plumbing. |
ProviderWireFormatSmokeTests.java |
Adds v2 Anthropic fixture coverage. |
AbstractAnthropicMessagesWireFormatFixture.java |
Shares Anthropic fixture behavior. |
AnthropicMessagesV1WireFormatFixture.java |
Retains v1 fixture configuration. |
AnthropicMessagesV2WireFormatFixture.java |
Adds native v2 fixture configuration. |
StreamingAnthropicMessagesSseChatModelStubs.java |
Adds Anthropic SSE stubs. |
ProviderWireFormatFixture.java |
Supports fixture-specific templates. |
AgentResponseAssert.java |
Corrects assertion helper naming. |
AgentSubProcessResponseAssert.java |
Adds metrics and provider-content assertions. |
RealProviderApiSmokeIT.java |
Adds real Anthropic acceptance scenarios. |
native-provider-acceptance-agent.bpmn |
Adds native-provider acceptance process. |
agenticai-ai-agent-subprocess.v2.json |
Exposes Anthropic subprocess settings. |
agenticai-ai-agent-task.v2.json |
Exposes Anthropic task settings. |
agenticai-ai-agent-subprocess.v2-hybrid.json |
Updates hybrid subprocess template. |
agenticai-ai-agent-task.v2-hybrid.json |
Updates hybrid task template. |
pom.xml |
Adds Anthropic SDK and OkHttp dependencies. |
AgentTaskV2Function.java |
Adds the model-options property group. |
AnthropicChatModelApi.java |
Executes streaming Anthropic calls. |
AnthropicChatModelApiFactory.java |
Builds direct and compatible clients. |
AnthropicContentConverter.java |
Converts domain content blocks. |
AnthropicEffort.java |
Defines effort levels. |
AnthropicMessageRequestConverter.java |
Builds Messages API requests. |
AnthropicMessageResponseConverter.java |
Converts Anthropic responses. |
AnthropicMessageStreamAssembler.java |
Accumulates streamed events. |
AnthropicReasoningValidator.java |
Validates thinking configuration. |
ThinkingMode.java |
Defines thinking modes. |
AgenticAiAnthropicProviderConfiguration.java |
Registers the native factory. |
anthropic/package-info.java |
Enables null-marked Anthropic code. |
AnthropicChatModelConfiguration.java |
Defines v2 Anthropic configuration. |
ProviderConfiguration.java |
Adds Anthropic to the provider union. |
CompatibleAuthentication.java |
Defines compatible-backend authentication. |
v2/shared/package-info.java |
Enables null-marked shared models. |
HttpTransportSupport.java |
Adds provider-neutral proxy resolution. |
transport/package-info.java |
Enables null-marked transport code. |
JsonPayloadLogging.java |
Adds safe JSON logging. |
AgenticAiConnectorsAutoConfiguration.java |
Imports Anthropic and transport beans. |
AiAgentV2TemplateGenerationTest.java |
Verifies generated Anthropic fields. |
AnthropicChatModelApiFactoryClientTest.java |
Tests client and proxy wiring. |
AnthropicChatModelApiFactoryTest.java |
Tests factory selection and creation. |
AnthropicChatModelApiTest.java |
Tests execution and lifecycle behavior. |
AnthropicContentConverterTest.java |
Tests content conversion. |
AnthropicMessageRequestConverterTest.java |
Tests request mapping. |
AnthropicMessageResponseConverterTest.java |
Tests response mapping. |
AnthropicMessageStreamAssemblerTest.java |
Tests stream accumulation and workaround. |
AnthropicChatModelConfigurationTest.java |
Tests binding and validation. |
HttpTransportSupportTest.java |
Tests proxy resolution. |
AgenticAiConnectorsAutoConfigurationTest.java |
Tests factory registration. |
ai-agent.md |
Documents the native provider implementation. |
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 51 out of 51 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
connectors/agentic-ai/connector-agentic-ai/src/main/java/io/camunda/connector/agenticai/aiagent/model/request/v2/AnthropicChatModelConfiguration.java:273
- The
maxTokens == nullearly return skips the cross-field check even thoughAnthropicMessageRequestConvertersubstitutesDEFAULT_MAX_TOKENS = 4096. An enabled-thinking configuration with a budget of 4096 or more therefore passes validation but is sent withmax_tokens: 4096, which Anthropic rejects because the budget must be smaller. Validate against the effective default too, ideally by sharing the default between the model validation and request converter.
maff
force-pushed
the
agentic-ai/v2-config-types
branch
from
July 27, 2026 15:58
486d0dd to
cdd7ce7
Compare
maff
force-pushed
the
agentic-ai/native-anthropic-provider
branch
from
July 27, 2026 16:56
e33d5ac to
d9df976
Compare
maff
force-pushed
the
agentic-ai/v2-config-types
branch
4 times, most recently
from
July 28, 2026 20:13
0a8c50e to
c3df2ca
Compare
…transport HttpTransportSupport duplicated the pre-existing, LangChain4j-scoped ChatModelHttpProxySupport (JDK/AWS/Azure proxy builders) even though the native Anthropic OkHttp client factory only ever calls okHttpProxy(). Trim it down to that single method, built directly on ProxyConfiguration, so it stays a small framework-neutral OkHttp-only proxy helper instead of a second copy of logic that already lives elsewhere. Also add real behavioral coverage for the previously-untested proxy application branch in AnthropicOkHttpClientFactory (both the plain and credentialed paths, via a real HttpTransportSupport and a minimal in-process fake HTTP proxy), and document why compatible-backend requestParameters() is intentionally not applied at client-construction time (no client-level hook in the vendor SDK; belongs to the request converter instead).
… template group maxTokens/temperature/topP/topK belong in "model-options" alongside other provider model-parameter groups, not the general "model" group.
…d of beta The native Anthropic provider (content/request/response converters, stream assembler, and chat model API) now targets com.anthropic.models.messages.* and client.messages() instead of the beta Messages client. Skills and server-tool support, the reason the beta client was originally used, are out of scope for this PR, and the stable client fully covers everything this provider ships (thinking, effort, caching, tool calling, multimodal content, and pause_turn handling all carry over unchanged).
Ports the native (v2, own-LLM-layer) Anthropic Messages provider's WireMock-based e2e coverage into the target module, adapted to its already-renamed subprocess/task package split and migrated from the beta to the stable Anthropic SDK surface: - Extend ProviderWireFormatFixture with elementTemplatePath/ elementTemplateBaselineProperties default hooks so a fixture can redirect the shared smoke-test suite to a different element template. - Factor AnthropicMessagesWireFormatFixture's shared wire-format plumbing into AbstractAnthropicMessagesWireFormatFixture so both the v1 (langchain4j-bridge) and new v2 (native) fixtures can reuse it. - Add StreamingAnthropicMessagesSseChatModelStubs, stubbing the native provider's streamed SSE response shape using the stable com.anthropic.models.messages.* SDK types (mirroring the main-source converters' beta->stable migration), trimmed to the turns this PR ships (text/tool-call, thinking, redacted thinking) and dropping Skills/code-execution server-tool-use coverage. - Add StreamingAnthropicMessagesWireFormatFixture and wire it into ProviderWireFormatSmokeTests as a fifth fixture row, plus the new v2 element-template constants in AgentTestFixtures. - Port the reasoning/effort wire-mapping and round-trip tests (AgentSubProcessAnthropicReasoningEffortTests), dropping the capability-matrix-driven validation-failure test this worktree has no subsystem for. - Add a new AgentSubProcessAnthropicPromptCachingTests asserting the enablePromptCaching template property adds/omits the wire-level cache_control field.
… explanation Reword without naming ModelCapabilitiesResolver/AnthropicReasoningCapabilities, which don't exist on this branch.
…tension example Point §12/§18/§25.1 at AnthropicChatModelApiFactory/AnthropicChatModelConfiguration as the reference implementation for a fully native (non-LangChain4J) ChatModel provider, alongside the existing LangChain4J-bridge example.
…el options group Drop the single-implementation AnthropicClientFactory interface and fold its sole implementation's construction responsibility directly into AnthropicOkHttpClientFactory. Trim planning-session references (task numbers, capability-matrix history, LangChain4J asides) out of Anthropic provider Javadoc, keeping only what's true of the current code. Clarify which document formats the Anthropic Messages API accepts natively versus falling back to a JSON reference. Move the "Model options" property group to sit right after "Model" in the v2 element templates, with a title-cased label matching the other groups' sentence-case convention, and regenerate the templates.
…trim stub docs Rename AnthropicMessagesWireFormatFixture/StreamingAnthropicMessagesWireFormatFixture to AnthropicMessagesV1WireFormatFixture/AnthropicMessagesV2WireFormatFixture and their apiName() strings to match, since the two fixtures already correspond to the v1/v2 element templates and this makes that explicit instead of naming one "streaming". Drop the "langchain4j-bridge" wording (no such bridge class exists) from the shared abstract fixture's Javadoc. In the SSE stub class, remove the out-of-scope-server-tools sentence and the class-level coupling to the native provider class name (nothing about the stubs is tied to a specific client), and replace a fabricated tracksToolInput() method reference with the actual, verifiable reason a redacted-thinking block has no delta accumulation: the SDK defines no delta type for it.
…y assertions Extract the duplicated element-template/backend-wiring plumbing shared by AgentSubProcessAnthropicReasoningEffortTests and AgentSubProcessAnthropicPromptCachingTests into a new BaseAnthropicNativeSubProcessTest. Replace the single-purpose hasReasoningTokensGreaterThanZero/hasCacheCreationTokensGreaterThanZero/ hasCacheReadTokensGreaterThanZero assertions with a generic metricsSatisfy(consumer) plus a hasReasoningTokens() convenience built on it, and inline the cache-token checks at their one call site. Fix the hasResponseTestSatisfying typo (-> hasResponseTextSatisfying) on both response-assertion classes. Clean up RealProviderApiSmokeIT: drop the unused LLM-judge SpringBootTest properties (never invoked anywhere in this class), remove FQCN usages in favor of imports, reference the system prompt as a FEEL variable instead of an escaped string literal, drop the unused follow-up-user-prompt branch and the empty-documents default, hoist scattered constants to the top of the class, and rewrite comments that described deferred/future work or assumed knowledge of the porting process to instead describe the current behavior.
…roviderApiSmokeIT RealProviderApiSmokeIT referenced this classpath resource but it was never added to this branch (it only existed on the vertical-pilot branch it was ported from).
…icChatModelApiFactory Drop the AnthropicOkHttpClientFactory class and move its buildClient logic directly into AnthropicChatModelApiFactory as a package-private static method, since it had exactly one caller and its own construction wasn't a meaningful seam. The dedicated wire-level test moves with it (renamed to AnthropicChatModelApiFactoryClientTest), still calling the method directly. Stop sending a placeholder x-api-key for compatible backends configured with no authentication: verified empirically that the SDK client builder neither requires an api key to build nor to send a request without one, so the placeholder was unnecessary; the header is now simply omitted. Clarify why compatible-backend headers/queryParameters are applied at the client level while requestParameters are applied per-request in the message converter.
…e Anthropic converter Match the LangChain4J-routed provider's behavior (DocumentToContentConverterImpl, which throws DocumentConversionException): the native Anthropic converter now throws a ConnectorException for a document content type that maps to none of Anthropic's native blocks (image, PDF, text-family), instead of silently degrading to a JSON reference of the document. Also clarifies that base64Source(String) already sets both source.type and source.media_type for PDF document blocks, matching Anthropic's documented wire shape.
…r request, not per client Move header and query-parameter application for the compatible backend from client construction (AnthropicChatModelApiFactory) to request building (AnthropicMessageRequestConverter), alongside the existing request (body) parameter merge. The client is short-lived (built fresh per job worker execution, never reused across calls), so there's no benefit to setting them at construction time, and MessageCreateParams.Builder already exposes putAdditionalHeader/putAdditionalQueryParam/putAdditionalBodyProperty uniformly -- no need to split the three across two places.
…e wording Move enablePromptCaching out of AnthropicConnection into a new nested AnthropicModelParameters.AnthropicPromptCaching record (a single enabled flag for now), since prompt caching is a per-model-call concern like temperature/effort/thinking, not a connection-level setting, and a record keeps room for a future cache-type or TTL knob without changing the wire shape. The element-template property moves from provider.anthropic.enablePromptCaching to provider.anthropic.model.parameters.promptCaching.enabled; its tooltip is trimmed to state what it does rather than repeating TTL/wire-format detail already covered by the linked docs. Elevate effort and thinking to the first two fields of AnthropicModelParameters, ahead of the raw numeric knobs. Rename the backend discriminator's UI label from "Connection" to "Backend" to match the AnthropicBackend type name, and merge the endpoint property's separate tooltip about the appended /v1/messages suffix into its description. Rename the AnthropicChatModelApiFactory bean method to aiAgentAnthropicChatModelApiFactory, and note in AgenticAiAnthropicProviderConfiguration's Javadoc that it mirrors AgenticAiLangChain4JChatModelConfiguration's dedicated-and-imported pattern for the LangChain4J-routed providers. Drop a comment explaining Java's lack of import-aliasing syntax from AnthropicMessageResponseConverter, keeping only the actual reason for the fully-qualified reference (the SDK's own StopReason name clash).
docs/superpowers/specs/2026-07-23-native-anthropic-task0-findings.md was a Task 0 scratch note from planning; it doesn't belong in the shipped diff.
…der docs - ai-agent.md no longer names AnthropicChatModelConfiguration as "the first built-in v2 member and the reference implementation"; the v2 ProviderConfiguration extension point is described generically instead, so the list of native providers doesn't need updating as more are added. - HttpTransportSupport's class javadoc dropped the comparison to the LangChain4J-side proxy support and just states what the class does. - AnthropicMessageRequestConverter#applyOutputConfig dropped a comment referencing the LangChain4J-routed path.
pause_turn previously mapped to a null domain StopReason (reasoning being that it's surfaced as a ChatResult.Continuation, not a finished turn), but that also hid it from AssistantMessage.stopReason(), the one field meant to carry the vendor's finish reason in normalized form. It now falls through to the existing UnknownStopReason(raw) branch like any other value without a dedicated domain mapping, so the assistant message always carries a stop reason regardless of how the result is surfaced.
… model config - Endpoint description drops the "e.g. Anthropic API" clause. - Effort tooltip no longer explains every dropdown choice inline (the dropdown itself already lists them); shortened to what effort controls plus a link to the docs, with the link on its own visual line. - Thinking-mode tooltip uses <code> for the option values and drops the semicolon-joined single-paragraph shape. - Thinking budget tokens tooltip: "Max" -> "Maximum", and drops the "required and used only when enabled" clause -- the field's own @TemplateProperty.PropertyCondition already hides it unless thinking mode is 'enabled', so the constraint doesn't need restating in prose. - Thinking display tooltip explains what happens when left unset. - promptCaching moved to sit right after thinking in AnthropicModelParameters (was last, after the model-options group fields). Element templates regenerated to match.
…t per create() AnthropicChatModelApiFactory is a singleton Spring bean, but create() was building fresh AnthropicContentConverter/AnthropicMessageRequestConverter/ AnthropicMessageResponseConverter instances on every call even though none of them depend on per-request state (only on the injected ObjectMapper). They're now built once in the constructor and reused across all create() calls; the per-request AnthropicClient itself is unaffected (still built fresh per job, since it depends on the request's backend/timeout). Also drop buildClient's package-private visibility, which existed solely so AnthropicChatModelApiFactoryClientTest could call it directly. buildClient is now private, and the client test drives it through the public surface instead (factory.create() + ChatModel#execute() against a real WireMock SSE-streamed response) for everything reachable that way. The one thing that isn't reachable through the public surface is the direct anthropic-api backend's wire-level api-key header, since that backend always targets the production Anthropic URL and there's no way to redirect it from outside the class; AnthropicChatModelApiFactoryTest still covers that it builds a working ChatModel.
AnthropicContentConverter classified any image/* document as an image block, but Anthropic's Messages API only accepts JPEG, PNG, GIF, and WebP; other image types (SVG, BMP, TIFF, ...) were forwarded and rejected remotely with a 400. Restrict classification to the same four MIME types already used by the LangChain4J-routed DocumentToContentConverterImpl.
maxTokens and topK allowed zero, temperature and topP had no upper bound, and an enabled thinking budget was never checked against maxTokens -- all three passed connector-side validation and failed only as a remote 400. Constrain maxTokens/topK to >= 1, bound temperature/topP to [0, 1], and add a cross-field check that rejects a thinking budget that isn't smaller than maxTokens when thinking is enabled. Also mark the thinking budget tokens field as required (rather than optional) while its condition is active, matching the runtime validator which already rejects a null budget when thinking mode is enabled.
…gContent/ProviderContent envelope ReasoningContent gains a provider discriminator and ProviderContent drops its redundant blockType (every payload already self-describes its own shape via an internal type field). Update the Anthropic response/request converters and their tests to the new two/three-arg constructors, and drop the now-unused blockType parameter (and its dead expectedServerToolBlockType helper) from the e2e provider-content assertion.
…ntConverter ReasoningContent/ProviderContent payload is no longer nullable (the compact constructor rejects null), so the null-payload branches were unreachable. Remove the guards and the two tests exercising the now-impossible case.
ProviderConfiguration.backend() was removed as unused; the AnthropicChatModelConfiguration override and its assertions are now dead code. The nested AnthropicConnection.backend() field accessor (used for actual client construction) is untouched.
Relocate the native-Anthropic subprocess e2e tests into the subprocess.v2 package to extend BaseAgentSubProcessV2Test and configure the provider via the providerConfigurer() hook, dropping the duplicated createProcessInstance override and element-template accessor overrides it replaces. Follow the AI_AGENT_SUB_PROCESS_V2_ELEMENT_TEMPLATE_* fixture rename through the remaining wire-format fixture and smoke test.
maff
force-pushed
the
agentic-ai/native-anthropic-provider
branch
from
July 28, 2026 20:18
d9df976 to
c23863b
Compare
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.
Description
Adds a native (non-LangChain4J) Anthropic provider for the v2 AI Agent connectors, implementing
AnthropicChatModelConfigurationas a newProviderConfigurationmember and driving the AnthropicJava SDK's Messages client directly through the
ChatModel/ChatModelFactoryprovider SPIintroduced in #8043.
anthropic-api(direct, API key) andcompatible(arbitrary Anthropic-compatibleendpoint; API key or no auth; custom headers/query params/body parameters) backends.
multimodal user input), reasoning/extended thinking (
enabled/adaptive/disabled, byte-identicalround-trip of thinking/redacted-thinking blocks),
effort, prompt caching (automatic, top-levelcache_control), structured JSON output, and provider server-tool content preserved losslessly.Streams every call (
createStreaming) and accumulates to the sameMessageshape a non-streamingcall would produce.
HttpTransportSupport), shared with future OkHttp-basedproviders.
StopReason, treatspause_turnas aChatResult.Continuation, and enforces the existing content-filter guard.hybrid variants).
Related issues
closes #8055
Checklist
ai-agent.mdupdated for the provider SPI/native-provider sections touched bythis change.