-
Notifications
You must be signed in to change notification settings - Fork 57
feat(aws): agentcore harness adapter #7287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
16af6d9
10c027b
882d64d
aba3ff4
7fe879f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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() { | ||
| 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( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💭 I think this shows that we need to adjust the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, this is a workaround to reuse the existing |
||
| new SystemPromptConfiguration(null), // system prompt comes from Harness config | ||
| new UserPromptConfiguration(userPrompt, null), | ||
| null, // memory | ||
| null, // limits | ||
| null, // events | ||
| null // response | ||
| )); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.