Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
{
"$schema": "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json",
"name": "Amazon Bedrock AgentCore Managed Agent (Alpha)",
"id": "io.camunda.connectors.agenticai.agentcore.harness.v1",
"description": "[Alpha] Drive an Amazon Bedrock AgentCore Harness through a re-entrant tool-call loop, exposing the AHSP inner elements as inline_function tools.",
"keywords": ["AI", "AI Agent", "Amazon", "AWS", "AgentCore", "Harness", "Bedrock"],
"version": 1,
"category": {
"id": "connectors",
"name": "Connectors"
},
"appliesTo": ["bpmn:SubProcess"],
"elementType": {
"value": "bpmn:AdHocSubProcess"
},
"engines": {
"camunda": "^8.10"
},
"groups": [
{
"id": "harness",
"label": "Harness",
"openByDefault": true
},
{
"id": "authentication",
"label": "AWS credentials",
"openByDefault": true
},
{
"id": "userPrompt",
"label": "User prompt",
"openByDefault": true
},
{
"id": "advanced",
"label": "Advanced",
"openByDefault": false
},
{
"id": "output",
"label": "Output mapping"
},
{
"id": "error",
"label": "Error handling"
}
],
"properties": [
{
"value": "io.camunda.agenticai:agentcore-harness:1",
"binding": {
"property": "type",
"type": "zeebe:taskDefinition"
},
"type": "Hidden"
},
{
"id": "outputCollection",
"binding": {
"property": "outputCollection",
"type": "zeebe:adHoc"
},
"value": "toolCallResults",
"type": "Hidden"
},
{
"id": "outputElement",
"binding": {
"property": "outputElement",
"type": "zeebe:adHoc"
},
"value": "={\n id: toolCall._meta.id,\n name: toolCall._meta.name,\n content: toolCallResult\n}",
"type": "Hidden"
},
{
"id": "harness.harnessArn",
"label": "Harness ARN",
"description": "Full ARN of the deployed AgentCore Harness, e.g. arn:aws:bedrock-agentcore:us-west-2:111122223333:harness/helpdesk-9aBcDeFgHi.",
"feel": "optional",
"group": "harness",
"binding": {
"name": "harness.harnessArn",
"type": "zeebe:input"
},
"constraints": {
"notEmpty": true
},
"type": "String"
},
{
"id": "harness.region",
"label": "Region",
"description": "AWS region of the harness (e.g. us-west-2). Inferred from harnessArn when omitted.",
"optional": true,
"feel": "optional",
"group": "harness",
"binding": {
"name": "harness.region",
"type": "zeebe:input"
},
"type": "String"
},
{
"id": "harness.allowedTools",
"label": "Allowed tools (FEEL list)",
"description": "Optional list of tool names to scope the harness to (typically the AHSP inner element ids). Leave empty to use harness defaults.",
"optional": true,
"feel": "required",
"group": "harness",
"binding": {
"name": "harness.allowedTools",
"type": "zeebe:input"
},
"type": "String"
},
{
"id": "authentication.type",
"label": "Authentication",
"description": "How to authenticate against AWS.",
"value": "credentials",
"group": "authentication",
"binding": {
"name": "authentication.type",
"type": "zeebe:input"
},
"type": "Dropdown",
"choices": [
{
"name": "Static credentials",
"value": "credentials"
},
{
"name": "Default credentials chain",
"value": "defaultCredentialsChain"
}
]
},
{
"id": "authentication.accessKey",
"label": "Access key ID",
"description": "AWS access key id, e.g. {{secrets.AWS_ACCESS_KEY_ID}}.",
"feel": "optional",
"group": "authentication",
"binding": {
"name": "authentication.accessKey",
"type": "zeebe:input"
},
"constraints": {
"notEmpty": true
},
"condition": {
"property": "authentication.type",
"equals": "credentials",
"type": "simple"
},
"type": "String"
},
{
"id": "authentication.secretKey",
"label": "Secret key",
"description": "AWS secret access key, e.g. {{secrets.AWS_SECRET_ACCESS_KEY}}.",
"feel": "optional",
"group": "authentication",
"binding": {
"name": "authentication.secretKey",
"type": "zeebe:input"
},
"constraints": {
"notEmpty": true
},
"condition": {
"property": "authentication.type",
"equals": "credentials",
"type": "simple"
},
"type": "String"
},
{
"id": "userPrompt",
"label": "User prompt",
"description": "First-turn user message sent to the harness. Continuation turns are driven by tool results from the AHSP inner elements.",
"feel": "optional",
"group": "userPrompt",
"binding": {
"name": "userPrompt",
"type": "zeebe:input"
},
"constraints": {
"notEmpty": true
},
"type": "Text"
},
{
"id": "maxIterations",
"label": "Max iterations",
"description": "Maximum number of tool-call iterations before forcing completion.",
"optional": true,
"feel": "optional",
"group": "advanced",
"binding": {
"name": "maxIterations",
"type": "zeebe:input"
},
"type": "String"
},
{
"id": "resultVariable",
"label": "Result variable",
"description": "Name of variable to store the response in",
"value": "response",
"group": "output",
"binding": {
"source": "=agent",
"type": "zeebe:output"
},
"type": "String"
},
{
"id": "resultExpression",
"label": "Result expression",
"description": "Expression to map the response into process variables",
"feel": "required",
"group": "output",
"binding": {
"key": "resultExpression",
"type": "zeebe:taskHeader"
},
"type": "Text"
},
{
"id": "errorExpression",
"label": "Error expression",
"description": "Expression to handle errors. Details in the <a href=\"https://docs.camunda.io/docs/components/connectors/use-connectors/#bpmn-errors\" target=\"_blank\">documentation</a>.",
"feel": "required",
"group": "error",
"binding": {
"key": "errorExpression",
"type": "zeebe:taskHeader"
},
"type": "Text"
}
],
"icon": {
"contents": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzIzMkYzRSI+PHBhdGggZD0iTTEyIDJDNi40OCAyIDIgNi40OCAyIDEyczQuNDggMTAgMTAgMTAgMTAtNC40OCAxMC0xMFMxNy41MiAyIDEyIDJ6bTAgMThjLTQuNDEgMC04LTMuNTktOC04czMuNTktOCA4LTggOCAzLjU5IDggOC0zLjU5IDgtOCA4em0tMS0xM2gydjZoLTJ6bTAgOGgydjJoLTJ6Ii8+PC9zdmc+"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.agenticai.aiagent.agentcoreharness;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.camunda.connector.agenticai.adhoctoolsschema.model.AdHocToolElement;
import io.camunda.connector.agenticai.aiagent.model.AgentContext;
import io.camunda.connector.agenticai.aiagent.model.request.JobWorkerAgentRequest;
import io.camunda.connector.agenticai.aiagent.model.request.JobWorkerAgentRequest.JobWorkerAgentRequestData;
import io.camunda.connector.agenticai.aiagent.model.request.PromptConfiguration.SystemPromptConfiguration;
import io.camunda.connector.agenticai.aiagent.model.request.PromptConfiguration.UserPromptConfiguration;
import io.camunda.connector.agenticai.aiagent.model.request.provider.BedrockProviderConfiguration.AwsAuthentication;
import io.camunda.connector.agenticai.model.tool.ToolCallResult;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.List;

/**
* Request model for the AgentCore Harness job worker.
*
* @param toolElements the ad-hoc subprocess inner elements (become inline_function tools)
* @param agentContext the agent context from previous iterations
* @param toolCallResults results from tool executions
* @param harness harness configuration (ARN, region, allowed tools)
* @param authentication AWS authentication configuration
* @param userPrompt the user prompt for the first turn
* @param maxIterations maximum iterations before forcing completion
*/
public record AgentCoreHarnessRequest(
@JsonProperty("adHocSubProcessElements") List<AdHocToolElement> toolElements,
@Valid AgentContext agentContext,
List<ToolCallResult> toolCallResults,
@Valid @NotNull HarnessConfiguration harness,
@Valid @NotNull AwsAuthentication authentication,
@NotBlank String userPrompt,
Integer maxIterations) {

/**
* Harness-specific configuration.
*
* @param harnessArn full ARN of the deployed AgentCore Harness
* @param region AWS region (optional, inferred from ARN if omitted)
* @param allowedTools optional list of tool names to scope the harness to
*/
public record HarnessConfiguration(
@NotBlank String harnessArn, String region, List<String> allowedTools) {

/** Extract region from ARN if not explicitly provided. */
public String effectiveRegion() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💭 Nice feature, but currently i think the region is an explicity and mandatory config param, which we should also enforce in such a case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The region inference from ARN was added for convenience since the ARN always contains the region (arn:aws:bedrock-agentcore:REGION:ACCOUNT:harness/NAME). But I can make it mandatory for consistency with other AWS connectors.

if (region != null && !region.isBlank()) {
return region;
}
// ARN format: arn:aws:bedrock-agentcore:REGION:ACCOUNT:harness/NAME
if (harnessArn != null && harnessArn.startsWith("arn:aws:")) {
String[] parts = harnessArn.split(":");
if (parts.length >= 4) {
return parts[3];
}
}
return "us-east-1"; // default
}
}

/**
* Convert to the standard JobWorkerAgentRequest format for compatibility with existing handlers.
*/
public JobWorkerAgentRequest toAgentRequest() {
return new JobWorkerAgentRequest(
toolElements,
agentContext,
toolCallResults,
null, // provider is not used for Harness
new JobWorkerAgentRequestData(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💭 I think this shows that we need to adjust the JobWorkerExecutionContext to maybe have a different type of AgentRequest that it can carry, as currently you are glueing here a lot of data to a completely different execution model.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

True, this is a workaround to reuse the existing JobWorkerAgentRequestHandler. A cleaner approach would be to introduce a more generic AgentExecutionContext, or something that doesn't assume the Langchain provider model. I'd suggest we track this as a follow-up refactor to keep this PR focused on the Harness integration. WDYT?

new SystemPromptConfiguration(null), // system prompt comes from Harness config
new UserPromptConfiguration(userPrompt, null),
null, // memory
null, // limits
null, // events
null // response
));
}
}
Loading
Loading