Closes the two loose ends left in this PR so the release does not need a
follow-up.
A2AWorkers indexed clients with agentClients.put(agentType, client), so two
clients claiming one type last-one-wins on discovery order and one disappears
silently. Before #1358 the single-client injection raised
NoUniqueBeanDefinitionException, so this traded a loud failure for an invisible
one — and defaulting agentType() to "conductor" earlier in this PR makes the
collision easier to hit, since an implementation that forgets to override now
matches the built-in client. Keep the first registration and log which client was
ignored, on both the Spring and SDK paths.
Adds ExternalAgentClientGatingTest over the two external clients, which had no
coverage at all: absent when the AI integration is off, registered together with
CredentialResolutionService when on, reporting their own agent types with no
credentials configured anywhere, and — the regression that motivated the
qualifier — Azure Foundry still resolving its OkHttpClient when a second
OkHttpClient bean exists. Verified the last case fails without the qualifier
(NoUniqueBeanDefinitionException: found 2) and passes with it.
The dropped "AGENT (conductor) requires 'name'" validation from #1358 is
deliberate and stays dropped: the delegate now also serves bedrock and
azure-foundry, whose identity comes from rawConfig/assistantId rather than a
name, which is why the remaining messages were genericised to "AGENT requires
'prompt'".
Verified: :conductor-agentspan:test 560 tests, :conductor-ai:test 750 tests, 0
failures; :conductor-test-harness:compileTestJava clean; spotless clean.
#1358 added agentType() as an abstract method on the public
ConductorAgentClient interface. That is a source- and binary-breaking change in
a minor release: every external implementation — SDK-backed worker adapters and
any host supplying its own agent control plane — stops compiling until it adds
the method, even though "conductor" is the only value such an implementation
could reasonably return.
Default it to "conductor" so those implementations keep working, and let clients
backing another runtime override. The literal is inlined rather than referencing
A2AService.AGENT_TYPE_CONDUCTOR (same value, asserted by the javadoc) to keep
this boundary interface import-free, as it is today.
The in-tree implementations are unaffected: ServiceConductorAgentClient already
returns the same value explicitly, and the bedrock / azure-foundry clients
override.
Verified: ./gradlew :conductor-ai:test :conductor-agentspan:test — 0 failures.
Also confirmed downstream: with this plus the client gating in this PR, an
embedding host that previously needed both a component-scan workaround and its
own agentType() override compiles and boots clean with neither, under AI enabled
and disabled.
google-java-format enforces a 100-char line limit; the single-line
/** … */ comments added for basePath/agentBasePath fields and the
agentUrl helper exceeded that limit.
Adds A2ANativeAgentFacade and A2AAgentServerResource in the agentspan module
to mirror the workflow-side A2A server at /api/a2a/agent/{name}. Native agents
are listed via AgentService, started via AgentService.start(), and execution
tracking reuses the same workflow-state mapping as the workflow side.
Closes#1407
Renames the default A2A server base path from /a2a to /api/a2a/workflow
to align with Conductor's /api prefix convention and reserve /api/a2a/agent
for future native-agent exposure.
- conductor.ai.grok.api-key now falls back XAI_API_KEY -> GROK_API_KEY,
so the org secret (GROK_API_KEY, which the tests already gate on) also
configures the server-side provider; XAI_API_KEY still wins when set.
- BedrockTest.IntegrationTests chat test: legacy bare claude-3-haiku id
-> current us. Haiku 4.5 inference profile (same two failures the
media test hit live: profile required, Legacy model blocked).
- GeminiVertexTest Vertex chat test: retired gemini-1.5-flash ->
gemini-2.5-flash.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
claude-3-haiku is marked Legacy by the provider and Bedrock rejects it
after 30 days of inactivity ("Access denied. This Model is marked by
provider as Legacy"). Use the active Haiku 4.5 US inference profile.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bearer-token auth works, but Bedrock rejects the bare model id for
on-demand throughput ("Retry your request with the ID or ARN of an
inference profile") — use the us. cross-region profile id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- OpenAITest / AzureOpenAITest: testChatCompletionWithImageMedia on
gpt-4o-mini — both ride OpenAIResponsesChatModel's input_image path
(pre-existing support; this locks it live at each endpoint).
- BedrockTest: new BearerIntegrationTests nest gated on
AWS_BEARER_TOKEN_BEDROCK (the dedicated org secret, matching the
server's conductor.ai.bedrock.bearerToken binding) — kept separate
from the access-key nest because the CI AWS keys are provisioned for
artifact publishing and may lack Bedrock permissions. Media flows via
Spring AI Converse image blocks; model claude-3-haiku (vision-capable,
same id as the existing bedrock tests).
- Workflow wires the new secrets (OPENAI, AZURE_OPENAI key+endpoint,
AWS_BEARER_TOKEN_BEDROCK, AWS_REGION).
Verified locally: Anthropic and OpenAI pass against the live APIs;
keyless providers skip. Azure/Bedrock get their first live run on this
PR's workflow run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds testChatCompletionWithImageMedia to the key-gated IntegrationTests
nests of Anthropic (#1238), Grok and Perplexity (#1243), and a new
GEMINI_API_KEY-gated ApiKeyIntegrationTests nest for Gemini (#1241,
AI-Studio mode — the mode the server uses with conductor.ai.gemini.api-key),
complementing the existing Cohere test (#1246). Each sends the repo's
token image (MELON7391) to a vision model and asserts transcription —
a pass proves the adapter attached the media; the token cannot be guessed.
Vision models verified against provider docs: claude-haiku-4-5,
gemini-2.5-flash, grok-4.5 (docs.x.ai image understanding), sonar
(Perplexity image attachments, data-URI image_url).
New workflow llm-media-integration.yml runs the suite on GitHub with the
org-level provider secrets (weekly cron + workflow_dispatch + PR runs on
workflow changes). Tests self-skip per absent key (COHERE_API_KEY is not
configured today), so the run stays green with per-provider status.
Verified locally: Anthropic passes against the live API; keyless
providers skip. Full gemini/grok/perplexity verification happens on the
PR's own workflow run via org secrets.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PostConstruct ran too early: ServiceConductorAgentClient could not initialize
because its chain (AgentService → WorkflowExecutorOps → SystemTaskRegistry
@DependsOn workerTaskAnnotationScanner → A2AWorkers) creates a circular
initialization dependency with A2AWorkers still in creation.
Replace @PostConstruct registerAgentClients() with a clients() accessor that
performs a double-checked lazy load on first AGENT/CANCEL_AGENT task execution,
at which point all Spring beans are fully initialized.
Add conductor.a2a.server.expose-all=true property so every registered
workflow is automatically available as an A2A agent without requiring
per-workflow metadata (a2a.enabled=true) or explicit exposedWorkflows
config. Useful for development and single-tenant deployments.
- Add agentType() to UnusedConductorAgentClient and FakeConductorAgentClient
(required by the new abstract method on the interface)
- Wrap single ConductorAgentClient args in List.of() in all test constructors
(non-Spring A2AWorkers constructor now takes List<ConductorAgentClient>)
- Stub conductorAgentClient.agentType() to "conductor" in A2ACancelWorkerTest
so the mock is registered under the expected routing key
The 'name' field is conductor-internal (identifies which embedded agent
workflow to call). External agents (Azure Foundry, Bedrock) don't use it
and would fail unnecessarily. Each client's startAgent() already validates
its own required fields. Kept the prompt check which is universal.
The constructor injection of List<ConductorAgentClient> caused a cycle:
A2AWorkers → ServiceConductorAgentClient → AgentService →
WorkflowServiceImpl → WorkflowExecutorOps → A2AWorkers.
Fix: Spring constructor now takes ApplicationContext instead of the
client list. A @PostConstruct method populates the agentClients map via
ApplicationContext.getBeansOfType() after all beans are constructed.
Non-Spring constructor (SDK/tests) is unchanged and still accepts a list.
SdkBytes.bytes() does not exist; use asUtf8String() directly on the
SdkBytes returned by PayloadPart.bytes(). Also removed the leftover
ConditionalOnProperty imports from BedrockAgentClient and
AzureFoundryAgentClient (annotations were removed earlier).
Add agentType() to ConductorAgentClient interface so each implementation
self-declares its routing key. A2AWorkers now takes List<ConductorAgentClient>,
builds a map at startup, and routes by agentType on the request — no
conditional logic, no @ConditionalOnProperty flags.
- conductor → ServiceConductorAgentClient (existing)
- bedrock → BedrockAgentClient (new)
- azure-foundry → AzureFoundryAgentClient (new)
- anything else → A2A remote path (existing fallback)
Adding a new platform is now: implement ConductorAgentClient, declare
agentType(), register as a Spring bean — nothing else changes.
- TokenProvider interface + StaticTokenProvider + OAuthTokenProvider (with
Entra ID factory, thread-safe token cache with 60s refresh buffer)
- AgentCredentialConfig model with Platform enum for extensibility
- credentialRef field on ConductorAgentStartRequest so callers can point
to a named secret without embedding credentials in the request
- BedrockAgentClient: streams Bedrock Agent Runtime responses, buffers
output, surfaces returnControl events as WAITING state; falls back to
default AWS credential chain when no credentialRef is set
- AzureFoundryAgentClient: A2A over HTTP with Entra ID bearer token auth;
per-execution state map so getAgentStatus/respond/cancelAgent all have
endpoint context without callers needing to pass it again
- KnownProviderEnvVars: added AZURE_CLIENT_ID/SECRET/TENANT_ID,
AZURE_FOUNDRY_ENDPOINT, BEDROCK_AGENT_ID/ALIAS_ID for auto-seeding
The OpenAI provider's embeddings/responses/image/speech API clients append paths
like "/embeddings" and expect the base URL to already contain the "/v1" segment.
A host-only integration Base URL (e.g. "https://api.openai.com") therefore 404s
(older builds had the client add "/v1" itself, so this is also a backward-compat
regression). Normalize the configured base URL so it always ends in "/v1"
(idempotent): host-only, ".../v1", ".../v1/", and blank all resolve correctly.
Scoped to the OpenAI provider (OpenAI.java) only — the shared API classes are not
changed, so Azure OpenAI (base ".../openai/v1", azureAuth) and Perplexity/Grok
(OpenAIChatCompletionsApi with their own paths) are unaffected. The video API
still receives the /v1-stripped base as before.
AnthropicChatModel.convertMessage() built the USER message from
userMsg.getText() only and silently dropped userMsg.getMedia(), so
images passed via the media input path never reached Claude — the model
received a text-only message and hallucinated. The OpenAI provider
already forwards media; Anthropic did not.
Convert user media into Anthropic image content blocks (base64 source)
alongside the text, mirroring OpenAIResponsesChatModel. Adds a
ContentBlock.image(mediaType, base64Data) factory (the image block type
and Source were already modeled, just unused).
Adds AnthropicChatModelMediaTest, which captures the outgoing
MessagesRequest and asserts the user message carries an image content
block with the verbatim base64 payload. Verified it fails before the fix
(media dropped -> bare string content) and passes after.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* remove(server-lite): delete server-lite module and all references
Removes the server-lite Gradle subproject, its source code, build
scripts, and all CI/CD references. The server module with ui-next
is the canonical distribution going forward.
* fix(test): de-flake NestedForkJoinSubWorkflowSpec retry assertions
After retry(), the parent workflow is pushed onto the decider queue and
the background sweeper (sweeperThreadCount=1) can re-open CANCELED JOIN
tasks to IN_PROGRESS before the post-retry snapshot is read. Relax the
two pre-sweep JOIN assertions to accept either CANCELED (not yet swept)
or IN_PROGRESS (already re-opened), matching the fix applied to
HierarchicalForkJoinSubworkflowRetrySpec in #1148 and RerunSpec in #1206.
* Revert "fix(test): de-flake NestedForkJoinSubWorkflowSpec retry assertions"
This reverts commit 9a2bfad711c267cc845ac7e940605d119b5af638.
* feat(a2a): durable A2A protocol — client, server, observability
Add Agent2Agent (A2A) protocol support to the AI module, in both directions.
Client: CALL_AGENT / GET_AGENT_CARD / CANCEL_AGENT_TASK system tasks call remote
A2A agents over JSON-RPC with poll, streaming (SSE), and push modes. Durable by
design — deterministic messageId, state in the execution (not a thread), liveness
guards, and a push backstop. SSRF-guarded (IPv6 ULA + cloud-metadata; redirects off).
Server: expose any workflow as an A2A agent (one agent per workflow), idempotent
message/send -> startWorkflow (RETURN_EXISTING), tasks/get / tasks/cancel, and
multi-turn resume (a follow-up message/send completes the paused HUMAN/WAIT task
instead of starting a duplicate).
Observability: Micrometer counters via the shared Monitors registry and MDC
correlation keys across the A2A code paths.
Gated by conductor.integrations.ai.enabled (client) and conductor.a2a.server.enabled
(server).
* test(a2a): unit, real-agent interop, and real-engine durability tests
- Unit/wire tests (MockWebServer), embedded-agent e2e, push callback, server
JSON-RPC dispatch + multi-turn resume, mapper/worker, and observability.
- A2ASdkInteropTest: drives the client against the official a2a-sdk reference
agent launched as a subprocess (discovery, send, poll, streaming, message-mode);
self-skips when no Python with a2a-sdk is available.
- A2ADurableEngineEndToEndTest (test-harness): CALL_AGENT through the real decider
+ AsyncSystemTaskExecutor + Redis, proving crash/restart resume from persistence.
* docs(a2a): integration guide, examples, UI task types, design notes
- docs/devguide/ai/a2a-integration.md (AI Cookbook nav) with worked examples:
call/expose, multi-turn resume request/response, and push end-to-end.
- ai/examples: call / get-card / server + streaming / push / multi-turn / cancel,
indexed in the examples README; runnable interop + durable demos under test
resources.
- ui-next: register CALL_AGENT / GET_AGENT_CARD / CANCEL_AGENT_TASK task types.
- design/a2a: protocol study, durability proposal, and server design notes.
Note: a CI step to install a2a-sdk (so A2ASdkInteropTest runs in the build job)
is left as a follow-up — it needs a token with the `workflow` scope to land.
* refactor(a2a): move inbound server auth to enterprise (OSS open by default)
The A2A server's optional shared-secret api-key (conductor.a2a.server.api-key)
is removed from OSS: the server is now open by default, matching OSS Conductor
REST. Inbound authentication (API keys, OAuth/OIDC, mTLS, per-skill scopes,
signed Agent Cards) belongs to the enterprise build; front OSS with a
gateway/firewall.
Unchanged and kept in OSS as safe-by-default guards: client SSRF protection,
push-callback token auth, cross-agent execution isolation, and client→remote
per-call auth headers.
Removes authorized()/apiKey + the two api-key tests; docs and design notes
updated.
* docs(a2a): error-handling/troubleshooting, multi-agent + client multi-turn + LLM-pick examples
Docs: add an error-handling & retries section (FAILED vs FAILED_WITH_TERMINAL_ERROR
mapping for HTTP/JSON-RPC/SSRF/liveness) + a troubleshooting table; flesh out the
client multi-turn section with a worked SWITCH-on-input-required snippet; add an
"orchestrating multiple agents" subsection.
Examples (validated by ExampleWorkflowValidationTest):
- 27-a2a-multi-agent: FORK_JOIN calling agents in parallel → JOIN.
- 28-a2a-llm-pick-skill: GET_AGENT_CARD → LLM_CHAT_COMPLETE → CALL_AGENT.
- 29-a2a-client-multi-turn: SWITCH on input-required, re-call with same context/taskId.
* refactor(a2a)!: rename CALL_AGENT→AGENT, CANCEL_AGENT_TASK→CANCEL_AGENT + add agentType
Generalize the agent task types ahead of multi-runtime support:
- CALL_AGENT → AGENT (class CallAgentTask → AgentTask), CANCEL_AGENT_TASK →
CANCEL_AGENT. GET_AGENT_CARD kept (discovery/"Agent Card" is A2A-specific).
- New input field `agentType` (default "a2a") on all three tasks — the extension
point for native runtimes (langgraph, openai, …). Unknown values are rejected
with a clear error; only "a2a" is implemented today.
Updated across enum, handlers, request models, mapper, callback, tests,
test-harness, examples, docs, design notes, and the ui-next task registration.
BREAKING CHANGE: workflows using type "CALL_AGENT"/"CANCEL_AGENT_TASK" must switch
to "AGENT"/"CANCEL_AGENT".
* docs(a2a): clean up post-rename residue (grammar, example names, phrasing)
Fix 'A AGENT'→'An AGENT' grammar (A2AMetrics, design), reword example descriptions and a doc sentence left awkward by the mechanical rename, and update legacy example workflow names (a2a_call_agent_* → a2a_agent_*).
* feat(a2a): server-side message/stream (SSE)
Exposed workflow-agents now support A2A message/stream. The endpoint returns an
SSE stream driven off a dedicated daemon pool: the initial Task, status-update
events as the workflow's A2A state changes, artifact-update events as output is
produced, and a final status-update at a terminal/input-required state (or when
the stream window elapses). The agent advertises capabilities.streaming=true.
A web-agnostic A2AStreamSink keeps SseEmitter out of A2AWorkflowAgent so the
stream driver stays unit-testable. Config: conductor.a2a.server.stream-poll-
interval-millis (500), stream-max-duration-seconds (300).
Tests: a mocked unit test asserting the task → artifact-update → final
status-update sequence, and a real-HTTP loopback (our client message/stream
against the server's SSE) aggregating to a completed task with artifacts.
Docs + design notes updated (streaming moves from follow-up to shipped).
* Update A2ADurableEngineEndToEndTest.java
* Update A2ADurableEngineEndToEndTest.java
* refactor(a2a): simplify client/server task code (no behavior change)
- AgentTask: replace hand-rolled isBlank/firstNonBlank/stripTrailingSlash/
asInt/asLong helpers with commons-lang3 StringUtils + Number-only reads;
reuse parseRequest().getPollIntervalSeconds() for pollInterval; dedup
stateOf via A2AResults; fix the stale {@link #isAsyncComplete} javadoc to
describe the real backstop-poll mechanism
- A2ACallbackResource: drop the deprecated query-param token path (untested,
no legacy clients on a feature branch); StringUtils for isBlank
- A2AServerResource/A2AWorkflowAgent: delete the duplicate basePath()/URL
building (delegate to the agent's agentUrl/new agentCardUrl); drop the
no-op `id == null ? null : id` ternaries
- remove dead fields A2AMessage.referenceTaskIds and PushNotificationConfig.id
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(a2a): add mermaid use-case diagrams (client & server directions)
Diagrams rendering both A2A directions — Conductor as client (workflow calls
remote agents via the AGENT task) and as server (a workflow exposed as an A2A
agent):
- docs/devguide/ai/a2a-integration.md: both-directions overview flowchart,
AGENT lifecycle sequence (poll/push/stream), FORK_JOIN→JOIN multi-agent
fan-out, and the server message/send→workflow→tasks/get sequence
- design/a2a/08: overview flowchart + a sequence per direction (A/B)
- design/a2a/10: server sequence emphasizing the streaming and multi-turn
resume paths
Rendered via pymdownx.superfences (mkdocs) and natively on GitHub.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(ai)!: rename package ai.models -> ai.model (singular)
Align the AI module with conductor-oss package conventions: every model
package in the codebase (com.netflix.conductor.common.model, core.model,
grpc/proto/model, ai.a2a.model) is singular `model` — `ai.models` was the
only plural `models` package in the entire repo, and sat one letter away
from the singular ai.a2a.model, which read as an inconsistency.
Pure mechanical rename: git mv of the package dir (history preserved) plus
package-decl/import/FQN updates across the module (main + test) and one doc
reference in ai/CONTRIBUTING.md. No type or behavior changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix /a2a endpoint not being reachable
* style: spotlessApply
* fix and upgrade version
* refactor for agentspan
* feat: add SQLite (sqlite-vec) vector database backend
Add an embedded, zero-infrastructure VectorDB backend implemented with the
sqlite-vec extension, alongside the existing pgvector/MongoDB/Pinecone backends.
- SqliteVectorDB stores embeddings in a vec0 virtual table and runs KNN via the
sqlite-vec MATCH operator (l2/cosine/l1).
- The native vec0 binaries (linux/macos/windows) are downloaded + checksum-verified
at build time (downloadSqliteVec) and bundled as jar resources; SqliteVecExtensions
extracts the right one at runtime.
- SqliteVectorDBAutoConfiguration registers a "default" instance automatically when
conductor.db.type=sqlite and conductor.integrations.ai.enabled=true, so the
all-in-one SQLite server gets a working vector store with no external dependency.
- Adds unit tests, a real end-to-end round-trip test, a RAG example
(30-rag-sqlite-vec.json), and documentation.
Note: a dedicated Linux e2e CI job (.github/workflows/ci.yml) is intentionally not
included here because the push token lacks the GitHub `workflow` scope; it must be
committed separately with a workflow-scoped token.
* test: enable workflow execution lock in integration profile to fix flaky specs
The integration-test profile disabled conductor.app.workflow-execution-lock-enabled
(since 2021), so acquireLock() was a no-op and the background WorkflowSweeper could
decide a workflow concurrently with specs' manual sweep()/asyncSystemTaskExecutor
calls. Two simultaneous decides could schedule duplicate tasks, intermittently
failing exact task-count assertions (FailureWorkflowSpec, and
HierarchicalForkJoinSubworkflowRetrySpec).
Enable the lock (matching production defaults; local_only lock is already configured)
so decides are serialized. Full :conductor-test-harness:test passes (252 tests).
* fix(build): wire downloadSqliteVec as a resource source so all consumers depend on it
The generated sqlite-vec resource directory is consumed by sourcesJar (and other
resource consumers), but only processResources depended on downloadSqliteVec. Gradle's
task-dependency validation (run as part of `build`) failed sourcesJar with an implicit
dependency error. Register the task provider itself as the resource srcDir so every
consumer depends on it automatically.
* fix(ai): harden sqlite-vec backend after review
Follow-up fixes from a deep review of the SQLite/sqlite-vec backend:
- SqliteVectorDB.upsertEmbeddings: restore autoCommit(true) in a finally block
so connections are never returned to the Hikari pool in manual-commit mode.
- SqliteVectorDB.getSqliteClient: validate the extension path against an
allowlist before interpolating it into load_extension(...).
- SqliteVectorDBAutoConfiguration.resolveDbPath: strip JDBC URL query params
(e.g. ?busy_timeout=15000&journal_mode=WAL) so the derived *_vectordb.db path
is a valid filename.
- SqliteVecExtensions: re-extract the bundled binary if the cached temp file was
deleted between calls (stale-cache guard).
- VectorDBProvider: warn when an auto-registered default is skipped because an
explicit instance with the same name already exists.
Adds SqliteVectorDBAutoConfigurationTest (resolveDbPath cases incl. query
params), SqliteVecExtensionsTest (platform detection), and a rollback/
autocommit-restore test in SqliteVectorDBTest.
* feat(ui-next): config forms for all AI / agentic task types
Wire up the workflow-editor task form dispatcher, Add-Task menu, icons, task
generators and JSON schemas for every AI task type exposed by the `ai/` module,
so each gets a real config form instead of the generic JSON editor.
- New bespoke forms: AGENT, GET_AGENT_CARD, CANCEL_AGENT, LIST_MCP_TOOLS,
CALL_MCP_TOOL, GENERATE_IMAGE, GENERATE_AUDIO, GENERATE_VIDEO, GENERATE_PDF,
LLM_SEARCH_EMBEDDINGS.
- Wire the existing-but-unwired LLM forms (chat/text complete, embeddings,
index text/document, search index, get document) into TaskFormContent.
- LLM_CHAT_COMPLETE: OSS plain "Instructions" textarea (enterprise prompt-name
picker remains pluggable via the plugin registry).
- A2A forms: agentType as a fixed A2A/Conductor radio; multi-row headers via the
shared HTTP headers editor; pushNotification is a boolean toggle.
- CALL_MCP_TOOL arguments accept inline JSON or a ${variable} reference.
- Media-gen + search-embeddings reuse the field-driven LLMFormFields for
provider/model/vectorDB/embedding selection (server-backed dropdowns).
- Full field coverage vs the backend input models; numeric fields use coerceTo
so the workflow JSON stores real numbers while still accepting ${variables}.
- A2A tasks added to the Agentic Orchestration quick-add section.
* fix(ui-next): address PR review on AI task forms
- Schemas.ts: add the new AI/agentic task types to genericSchema's type enum so
the code (JSON) editor no longer warns "type is not one of ..." for AGENT,
GENERATE_*, *_MCP_*, LLM_SEARCH_EMBEDDINGS, CHUNK_TEXT, LIST_FILES, PARSE_DOCUMENT.
- AgentTaskForm: fix spacing so the "Push backstop poll" field's floating label
no longer collides with the push-notification toggle (group switches, separate
the input row).
- LLMSearchEmbeddingsTaskForm: add spacing so the helper text no longer collides
with the Query field's floating label.
- QuickAddMenu: fill the two empty Agentic Orchestration slots (Call MCP Tool,
Generate Image) for a clean two-row grid.
* fix(ui-next): snug node height for AI/agentic task cards
AI task cards render header-only content (no custom body), but fell through to
the DEFAULT node height (100px), leaving empty space below the label on the
canvas. Size the AI/agentic header-only task family to 80px (matching the
header-only FORK_JOIN node) so the cards fit their content.
---------
Co-authored-by: Nicholas Cole <68611647+NicholasDCole@users.noreply.github.com>
Co-authored-by: nicholascole <nicholas.colesd@gmail.com>