Skip to content

feat(designer-v2): Add Agent Harness tab for consumption agent workflows#9061

Open
Elaina-Lee wants to merge 5 commits intomainfrom
feature/agent-harness-tab
Open

feat(designer-v2): Add Agent Harness tab for consumption agent workflows#9061
Elaina-Lee wants to merge 5 commits intomainfrom
feature/agent-harness-tab

Conversation

@Elaina-Lee
Copy link
Copy Markdown
Contributor

Commit Type

  • feature - New functionality

Risk Level

  • Medium - Moderate changes, some user impact

What & Why

Adds a new "Agent Harness" tab to the node details panel in designer-v2 for consumption agent workflows. This tab allows users to view and configure the sandbox environment for agent code execution, including:

  • Execution Environment — Harness type selection (GHCP)
  • Sandbox Configuration — Integration account display and sandbox configuration dropdown (fetched from API)
  • Input Files — Read-only table of files uploaded to the sandbox
  • Skills — Read-only table of repository skills providing context

The tab is only visible when:

  1. The node is an agent action (type === 'agent')
  2. The manifest has enableAgentHarness: true (consumption only)
  3. Not in monitoring view

Impact of Change

  • Users: New "Agent Harness" tab appears for agent actions in consumption workflows
  • Developers: New enableAgentHarness property on OperationManifestProperties, getSandboxConfigurations on IWorkflowService, integrationAccount on hostOptions
  • System: No performance impact; tab loads lazily with data from existing Redux state and optional API call

Test Plan

  • Unit tests added/updated
  • E2E tests added/updated
  • Manual testing completed
  • Tested in: Standalone app (consumption agent workflow)
  • 19 new component tests for AgentHarnessTab (sections rendering, mismatch warning, empty states, malformed data)
  • 5 new tests in usePanelTabs.spec.tsx for tab visibility logic
  • All 43 existing + new tests pass

Contributors

Screenshots/Videos

🤖 Generated with Claude Code

Add a new "Agent Harness" tab to the node details panel in designer-v2,
visible only for agent actions whose manifest sets enableAgentHarness.
The tab displays agent harness configuration from agentModelSettings
including execution environment, sandbox configuration, input files,
and skills sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 14, 2026 22:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds an Agent Harness tab to designer-v2’s node details panel for consumption agent workflows, allowing users to view/configure sandbox execution settings when enabled by manifest and not in monitoring view.

Changes:

  • Introduces enableAgentHarness manifest property and uses it to conditionally show a new panel tab for agent nodes.
  • Adds integrationAccount to hostOptions and a workflow service method to fetch sandbox configurations.
  • Implements the Agent Harness tab UI (execution env + sandbox config + read-only input files/skills), plus unit tests and localization entries.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
libs/logic-apps-shared/src/utils/src/lib/models/operationmanifest.ts Adds enableAgentHarness flag to manifest properties to gate the feature.
libs/logic-apps-shared/src/designer-client-services/lib/workflow.ts Extends IWorkflowService with getSandboxConfigurations for sandbox dropdown data.
libs/logic-apps-shared/src/designer-client-services/lib/consumption/manifests/agentloop.ts Enables harness tab for the agentloop operation via manifest.
libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/usePanelTabs.tsx Adds visibility logic and registers the new Agent Harness tab.
libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/tabs/agentHarnessTab/agentHarnessTab.tsx Implements the Agent Harness tab UI and data plumbing (Redux + react-query).
libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/tabs/agentHarnessTab/agentHarnessTab.styles.ts Adds styles for the new tab layout.
libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/tabs/agentHarnessTab/test/agentHarnessTab.spec.tsx Adds component tests for rendering, warnings, and empty/malformed states.
libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/tests/usePanelTabs.spec.tsx Adds tab visibility tests based on agent node + manifest flag + monitoring view.
libs/designer-v2/src/lib/core/state/designerOptions/designerOptionsInterfaces.ts Adds integrationAccount shape to hostOptions state typing.
libs/designer-v2/src/lib/common/constants.ts Adds AGENT_HARNESS tab constant.
apps/Standalone/src/designer/app/AzureLogicAppsDesigner/laDesignerConsumptionV2.tsx Wires integrationAccount from workflow properties into hostOptions.
Localize/lang/strings.json Adds localized strings related to the new tab copy.

Comment on lines +184 to +200
const updatedHarness = { ...harnessData, [field]: value };
const fullValue = JSON.stringify({ agentHarness: updatedHarness });

dispatch(
updateNodeParameters({
nodeId,
parameters: [
{
groupId,
parameterId,
propertiesToUpdate: {
value: [{ id: crypto.randomUUID(), type: 'literal' as const, value: fullValue }],
},
},
],
})
);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

Updating a single field rewrites the entire agentModelSettings payload to {\"agentHarness\": ...}. If agentModelSettings contains other settings, they will be erased on any dropdown change. Consider parsing and preserving the full existing agentModelSettings object (merging only agentHarness), and avoid overwriting non-literal/dynamic segments if present.

Copilot uses AI. Check for mistakes.
Comment on lines +296 to +302
<Dropdown
value={harnessData.type === 'GHCP' ? 'GHCP (GitHub Copilot)' : (harnessData.type ?? '')}
selectedOptions={[harnessData.type ?? 'GHCP']}
onOptionSelect={(_e, data) => updateHarnessField('type', data.optionValue as string)}
>
<Option value="GHCP">GHCP (GitHub Copilot)</Option>
</Dropdown>
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

The Dropdown is controlled with potentially inconsistent value vs selectedOptions. When harnessData.type is undefined, selectedOptions defaults to GHCP but value becomes an empty string, which can render as blank/incorrect depending on Fluent UI Dropdown behavior. Recommend driving the displayed text from the selected option consistently (e.g., set value based on the selected option label for the default) or rely on selectedOptions without an incompatible value.

Copilot uses AI. Check for mistakes.
Comment on lines +209 to +239
id: 's+momK',
description: 'Info message explaining agent harness',
}),
executionEnvironmentTitle: intl.formatMessage({
defaultMessage: 'Execution Environment',
id: 'l4W63k',
description: 'Title for execution environment section',
}),
executionEnvironmentSubtitle: intl.formatMessage({
defaultMessage: 'Choose the harness runtime for agent execution.',
id: '2RtLQr',
description: 'Subtitle for execution environment section',
}),
sandboxConfigTitle: intl.formatMessage({
defaultMessage: 'Sandbox Configuration (Optional)',
id: 'OMr20n',
description: 'Title for sandbox configuration section',
}),
sandboxConfigSubtitle: intl.formatMessage({
defaultMessage: 'Link a pre-built sandbox with pre-installed dependencies and tools. If not specified, a default sandbox is used.',
id: 'Ehv21q',
description: 'Subtitle for sandbox configuration section',
}),
integrationAccountLabel: intl.formatMessage({
defaultMessage: 'Integration Account',
id: 'xmtXdX',
description: 'Label for integration account field',
}),
sandboxConfigLabel: intl.formatMessage({
defaultMessage: 'Sandbox Configuration',
id: 'sBIkgt',
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

The react-intl message IDs used in this component (e.g., s+momK, sXL2Jq, etc.) do not match the newly added keys in Localize/lang/strings.json in this PR. This will likely cause localization lookups to miss and fall back to defaultMessage. Please align the id values with the localization keys (or re-run the project’s message extraction pipeline so strings.json contains these IDs).

Suggested change
id: 's+momK',
description: 'Info message explaining agent harness',
}),
executionEnvironmentTitle: intl.formatMessage({
defaultMessage: 'Execution Environment',
id: 'l4W63k',
description: 'Title for execution environment section',
}),
executionEnvironmentSubtitle: intl.formatMessage({
defaultMessage: 'Choose the harness runtime for agent execution.',
id: '2RtLQr',
description: 'Subtitle for execution environment section',
}),
sandboxConfigTitle: intl.formatMessage({
defaultMessage: 'Sandbox Configuration (Optional)',
id: 'OMr20n',
description: 'Title for sandbox configuration section',
}),
sandboxConfigSubtitle: intl.formatMessage({
defaultMessage: 'Link a pre-built sandbox with pre-installed dependencies and tools. If not specified, a default sandbox is used.',
id: 'Ehv21q',
description: 'Subtitle for sandbox configuration section',
}),
integrationAccountLabel: intl.formatMessage({
defaultMessage: 'Integration Account',
id: 'xmtXdX',
description: 'Label for integration account field',
}),
sandboxConfigLabel: intl.formatMessage({
defaultMessage: 'Sandbox Configuration',
id: 'sBIkgt',
id: 'agentHarnessTab.infoMessage',
description: 'Info message explaining agent harness',
}),
executionEnvironmentTitle: intl.formatMessage({
defaultMessage: 'Execution Environment',
id: 'agentHarnessTab.executionEnvironmentTitle',
description: 'Title for execution environment section',
}),
executionEnvironmentSubtitle: intl.formatMessage({
defaultMessage: 'Choose the harness runtime for agent execution.',
id: 'agentHarnessTab.executionEnvironmentSubtitle',
description: 'Subtitle for execution environment section',
}),
sandboxConfigTitle: intl.formatMessage({
defaultMessage: 'Sandbox Configuration (Optional)',
id: 'agentHarnessTab.sandboxConfigTitle',
description: 'Title for sandbox configuration section',
}),
sandboxConfigSubtitle: intl.formatMessage({
defaultMessage: 'Link a pre-built sandbox with pre-installed dependencies and tools. If not specified, a default sandbox is used.',
id: 'agentHarnessTab.sandboxConfigSubtitle',
description: 'Subtitle for sandbox configuration section',
}),
integrationAccountLabel: intl.formatMessage({
defaultMessage: 'Integration Account',
id: 'agentHarnessTab.integrationAccountLabel',
description: 'Label for integration account field',
}),
sandboxConfigLabel: intl.formatMessage({
defaultMessage: 'Sandbox Configuration',
id: 'agentHarnessTab.sandboxConfigLabel',

Copilot uses AI. Check for mistakes.
Comment on lines +99 to +102
/**
* Gets sandbox configurations from the integration account.
*/
getSandboxConfigurations?(integrationAccountId: string): Promise<any[]>;
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

Promise<any[]> makes it easy to accidentally break consumers (the tab expects id and name). Consider introducing a small SandboxConfiguration type (e.g., { id: string; name?: string }) and returning Promise<SandboxConfiguration[]> (or unknown[] + runtime narrowing) to keep the contract explicit and safer.

Copilot uses AI. Check for mistakes.
<div className={styles.section}>
<Text className={styles.sectionTitle}>{intlText.inputFilesTitle}</Text>
<Text className={styles.sectionSubtitle}>{intlText.inputFilesSubtitle}</Text>
<DataGrid items={inputFileItems} columns={inputFileColumns} getRowId={(item) => item.name}>
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

getRowId uses item.name, which is not guaranteed unique (two input files can share the same filename from different sources/paths). Duplicate row IDs can cause unstable rendering and incorrect row updates. Consider using a stable unique identifier (if provided by the model) or a composite key (e.g., name + index).

Suggested change
<DataGrid items={inputFileItems} columns={inputFileColumns} getRowId={(item) => item.name}>
<DataGrid items={inputFileItems} columns={inputFileColumns} getRowId={(item) => `${item.name}:${item.content}`}>

Copilot uses AI. Check for mistakes.
groupId,
parameterId,
propertiesToUpdate: {
value: [{ id: crypto.randomUUID(), type: 'literal' as const, value: fullValue }],
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

crypto.randomUUID() is not available in all JS runtimes/browsers (and can be unavailable depending on the app’s supported environment). To avoid runtime crashes, consider using the project’s existing GUID/UUID helper (if available) or a small fallback when crypto.randomUUID is undefined.

Copilot uses AI. Check for mistakes.
return render(<AgentHarnessTab nodeId={nodeId} />, { wrapper: Wrapper });
};

describe('AgentHarnessTab', () => {
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

The tests cover rendering and mismatch/empty states, but there’s no assertion that changing either Dropdown dispatches updateNodeParameters with the expected merged agentModelSettings value. Adding an interaction test for onOptionSelect (including the 'None' sandbox option) would protect the most important behavior introduced by this tab.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 14, 2026

📊 Coverage Check

🎉 All changed files have adequate test coverage!

Elaina-Lee and others added 4 commits April 15, 2026 14:43
- Read agentHarness from raw workflow operation definition
  (state.workflow.operations) instead of inputParameters, since
  agentHarness is not in the manifest schema
- Implement getSandboxConfigurations API call in consumption workflow
  service using existing httpClient/baseUrl pattern
- Add "Learn more about Agent Harness" link to info MessageBar
- Add "Harness Type *" label with required indicator to dropdown
- Add sandbox configuration status display (green dot + snapshot ID)
- Add contentType to AgentHarnessInputFile interface
- Update info/subtitle text to match mockup
- Rewrite tests to mock useActionMetadata instead of inputParameters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use Field validationMessage for sandbox mismatch warning instead of
standalone MessageBar, enable harness type and sandbox config dropdowns,
and replace skills DataGrid with card layout using Badge chips for
better handling of long repository URLs and folder paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expression content like @{variables('documentContent')} now renders as
styled FX token pills with smart title extraction (showing just the
variable/parameter name), matching the Parameters tab behavior. Plain
text content renders as-is.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d add info tooltip

Sandbox configuration dropdown is now conditionally rendered only when
an integration account is linked. Added an info icon tooltip next to the
Integration Account label explaining the requirement, with a Read more
link, following the pattern from PR #9043.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🤖 AI PR Validation Report

PR Review Results

Thank you for your submission! Here's detailed feedback on your PR title and body compliance:

PR Title

  • Current: feat(designer-v2): Add Agent Harness tab for consumption agent workflows
  • Issue: None — title is clear, follows conventional commit style, includes scope and brief description.
  • Recommendation: Keep as-is. If you want to be even more explicit you could add a short parenthetical that this is UI-only (if true), e.g. (UI) but that's optional.

Commit Type

  • Properly selected (feature). Only one box is checked which is correct.
  • Note: If this PR actually contains only tests/docs or maintenance bits in addition to the feature, consider splitting into smaller PRs in the future. No action required now.

⚠️ Risk Level

  • Assessment: The PR body selects "Medium" which matches the scope and changes in the diff (new UI tab, new service API usage, manifest flag, lots of localization strings, and unit tests).
  • Issue: The repository labels on the PR are empty. Every PR should have a risk label (e.g. risk:low, risk:medium, or risk:high). The selected risk in the body must be reflected by a matching label on the PR.
  • Recommendation: Add the label risk:medium to this PR so the label and the PR body are consistent. If the team uses a different label naming convention, use the team standard but ensure it maps to the PR body.

What & Why

  • Current:
    Adds an "Agent Harness" tab to node details in designer-v2 for consumption agent workflows, lists the features and visibility conditions.
  • Issue: None substantive. The description is concise and explains the visibility conditions.
  • Recommendation: Consider adding a short link or ticket reference for the backend/API contract (if applicable) so reviewers know where to review the service/API expectations (e.g. the sandboxConfigurations endpoint). Otherwise this section is good.

Impact of Change

  • The PR body documents the impact across Users / Developers / System.
  • Recommendation: Good. One small suggestion: mention whether this requires any feature flags to be enabled in prod or rollout guidance if applicable. Also call out if this requires any configuration changes (e.g. integration account presence) in environments used by CI or e2e tests.

Test Plan

  • Assessment: The PR claims unit tests added and manual testing completed. The code diff confirms unit tests were added/updated: a new comprehensive agentHarnessTab.spec.tsx and updates in usePanelTabs.spec.tsx. Good.
  • Issue: E2E tests are not included (checked as not added). That's acceptable if you documented why E2E aren't required. You did mark manual testing — good.
  • Recommendation: If this UI change should be covered by E2E (because it affects user flows end-to-end), add E2E tests or explain why manual/unit tests are sufficient (e.g. feature gated / low surface area for integrations). Otherwise no change needed.

⚠️ Contributors

  • Assessment: Empty in the PR body.
  • Issue: Not required, but a friendly reminder to credit PMs/designers/others who contributed ideas or review. The PR will pass without this, but consider filling in the section before merge for good traceability.
  • Recommendation: Add any contributors (PM/Designer/reviewer) if applicable.

⚠️ Screenshots/Videos

  • Assessment: Empty with a placeholder note to add after visual review.
  • Issue: This is a visual UI change. While screenshots are optional, they are highly recommended for UI reviews.
  • Recommendation: Add at least one screenshot showing the new Agent Harness tab (execution environment + sandbox config sections) for reviewers and designers. If there are multiple states (empty state, mismatch warning), include representative screenshots for those too.

Summary Table

Section Status Recommendation
Title Keep as-is.
Commit Type Keep as-is.
Risk Level ⚠️ Add risk:medium label to the PR so labels and body match.
What & Why Optionally link backend/API contract or ticket.
Impact of Change Consider adding rollout/feature-flag notes if relevant.
Test Plan Unit tests detected in diff; add E2E if relevant.
Contributors ⚠️ Optional: add contributors for credit.
Screenshots/Videos ⚠️ Add screenshots for UI states (normal, empty, mismatch).

Final message
Your PR title and body mostly follow the required template. The submitted risk level (Medium) is appropriate given the breadth of UI/service changes in the diff, and I advise risk:medium (matches your body). The one actionable blocker to fix in the PR metadata is to add the corresponding risk label to the PR (e.g., risk:medium). Additionally, please consider adding screenshots of the new tab and filling the Contributors section (recommended). Once you add the risk:medium label and optionally include screenshots/contributor credits, this PR should be ready from a title/body/template compliance perspective. Thank you!


Last updated: Thu, 16 Apr 2026 02:14:57 GMT

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants