From c4da7cef255d6244da4307fdab2c9cd79a83630a Mon Sep 17 00:00:00 2001 From: Evan Mattson <35585003+moonbox3@users.noreply.github.com> Date: Tue, 11 Aug 2026 08:37:03 +0900 Subject: [PATCH 1/2] Fix broken Harness Agent bookmarks (#1085) --- .../agents/background-responses.md | 2 +- agent-framework/concepts/harness.md | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/agent-framework/agents/background-responses.md b/agent-framework/agents/background-responses.md index 9982fb19..df3f3a91 100644 --- a/agent-framework/agents/background-responses.md +++ b/agent-framework/agents/background-responses.md @@ -273,7 +273,7 @@ Background responses require an explicit session via `agent.WithSession(session) A Harness Agent remains a standard Agent Framework agent, so provider background responses use the same per-run options documented above. Harness construction doesn't enable provider background responses automatically: set `AllowBackgroundResponses` in .NET or `options={"background": True}` in Python when starting the run, keep the session, and persist continuation tokens when the operation must survive a process restart. -This is separate from [background agents](background-agents.md#use-background-agents-with-harnessed-agent), which delegate work to child agents rather than continuing one provider request. +This is separate from [background agents](background-agents.md#use-background-agents-with-harness-agent), which delegate work to child agents rather than continuing one provider request. ## Best Practices diff --git a/agent-framework/concepts/harness.md b/agent-framework/concepts/harness.md index 4ecc9bad..e613542d 100644 --- a/agent-framework/concepts/harness.md +++ b/agent-framework/concepts/harness.md @@ -36,27 +36,27 @@ The Harness composes existing Agent Framework building blocks rather than defini 1. **Middleware and decorators** — add approval handling, observability, and optional bounded looping. 1. **Application UX** — streams responses, displays progress, and collects input such as tool approvals. -The resulting object remains a normal Agent Framework agent: a `HarnessAgent` that derives from `AIAgent` in .NET, or an `Agent` returned by `create_harness_agent` in Python. Its sessions use the same [session](./agents/conversations/session.md#use-sessions-with-harnessed-agent) and [context provider](./agents/conversations/context-providers.md#use-context-providers-with-harnessed-agent) abstractions as other agents. +The resulting object remains a normal Agent Framework agent: a `HarnessAgent` that derives from `AIAgent` in .NET, or an `Agent` returned by `create_harness_agent` in Python. Its sessions use the same [session](./agents/conversations/session.md#use-sessions-with-harness-agent) and [context provider](./agents/conversations/context-providers.md#use-context-providers-with-harness-agent) abstractions as other agents. ## Harness capability matrix | Capability | Harness behavior | Canonical guidance | |---|---|---| | Function invocation | Enabled with a configurable per-request iteration limit. | [Function tools](../agents/tools/function-tools.md#use-function-tools-with-harnessed-agent) | -| Per-service-call history persistence | Persists history after each model call in a tool-calling run. | [Sessions](./agents/conversations/session.md#use-sessions-with-harnessed-agent) | -| Compaction | Enabled when token limits or a custom strategy are supplied. | [Compaction](./agents/conversations/compaction.md#use-compaction-with-harnessed-agent) | -| Todo tracking | Enabled by default. | [Planning and todos](../agents/planning-and-todos.md#use-planning-and-todos-with-harnessed-agent) | -| Agent modes | Plan and execute modes are enabled by default. | [Planning and todos](../agents/planning-and-todos.md#use-planning-and-todos-with-harnessed-agent) | -| File memory and file access | Session file memory is enabled by default; shared file access is opt-in. | [Context providers](./agents/conversations/context-providers.md#use-context-providers-with-harnessed-agent) | +| Per-service-call history persistence | Persists history after each model call in a tool-calling run. | [Sessions](./agents/conversations/session.md#use-sessions-with-harness-agent) | +| Compaction | Enabled when token limits or a custom strategy are supplied. | [Compaction](./agents/conversations/compaction.md#use-compaction-with-harness-agent) | +| Todo tracking | Enabled by default. | [Planning and todos](../agents/planning-and-todos.md#use-planning-and-todos-with-harness-agent) | +| Agent modes | Plan and execute modes are enabled by default. | [Planning and todos](../agents/planning-and-todos.md#use-planning-and-todos-with-harness-agent) | +| File memory and file access | Session file memory is enabled by default; shared file access is opt-in. | [Context providers](./agents/conversations/context-providers.md#use-context-providers-with-harness-agent) | | Tool approval | Standing approvals and auto-approval rules are enabled by default. | [Tool approval](../agents/tools/tool-approval.md#use-tool-approval-with-harnessed-agent) | | OpenTelemetry | Agent observability is enabled by default. | [Observability](../agents/observability.md#use-observability-with-harnessed-agent) | | Web search | Added by default where the selected chat client supports it. | [Web search](../agents/tools/web-search.md#use-web-search-with-harnessed-agent) | -| Agent Skills | Enabled by default in .NET; opt-in through a provider or paths in Python. | [Agent Skills](../agents/skills.md#use-agent-skills-with-harnessed-agent) | -| Background agents | Optional parallel delegation to named child agents. | [Background agents](../agents/background-agents.md#use-background-agents-with-harnessed-agent) | +| Agent Skills | Enabled by default in .NET; opt-in through a provider or paths in Python. | [Agent Skills](../agents/skills.md#use-agent-skills-with-harness-agent) | +| Background agents | Optional parallel delegation to named child agents. | [Background agents](../agents/background-agents.md#use-background-agents-with-harness-agent) | | Shell execution | Composed from the shell package; the Python factory can wire it automatically. | [Shell tools](../integrations/by-component/tools/shell-tools.md#use-shell-tools-with-harnessed-agent) | -| Looping | Optional bounded re-invocation driven by evaluators or predicates. | [Agent looping](../agents/looping.md#use-looping-with-harnessed-agent) | +| Looping | Optional bounded re-invocation driven by evaluators or predicates. | [Agent looping](../agents/looping.md#use-looping-with-harness-agent) | -Background-agent delegation is separate from provider-managed [background responses](../agents/background-responses.md#use-background-responses-with-harnessed-agent). Background agents run child agents on delegated tasks; background responses poll or resume one provider request by using a continuation token. +Background-agent delegation is separate from provider-managed [background responses](../agents/background-responses.md#use-background-responses-with-harness-agent). Background agents run child agents on delegated tasks; background responses poll or resume one provider request by using a continuation token. ::: zone pivot="programming-language-csharp" @@ -198,11 +198,11 @@ The repository doesn't currently include a packaged Go Harness terminal sample. ## Next steps > [!div class="nextstepaction"] -> [Plan work and track todos](../agents/planning-and-todos.md#use-planning-and-todos-with-harnessed-agent) +> [Plan work and track todos](../agents/planning-and-todos.md#use-planning-and-todos-with-harness-agent) ### Go deeper -- [Looping](../agents/looping.md#use-looping-with-harnessed-agent) -- [Background agents](../agents/background-agents.md#use-background-agents-with-harnessed-agent) -- [Compaction](./agents/conversations/compaction.md#use-compaction-with-harnessed-agent) +- [Looping](../agents/looping.md#use-looping-with-harness-agent) +- [Background agents](../agents/background-agents.md#use-background-agents-with-harness-agent) +- [Compaction](./agents/conversations/compaction.md#use-compaction-with-harness-agent) - [Shell tools](../integrations/by-component/tools/shell-tools.md#use-shell-tools-with-harnessed-agent) From 38a5ebfeeed0b7c3ca8493d67b60b8ee460d6605 Mon Sep 17 00:00:00 2001 From: Peter Ibekwe <109177538+peibekwe@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:04:11 -0700 Subject: [PATCH 2/2] Document .NET workflow protocol declaration attributes (#1086) --- .../concepts/workflows/executors.md | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/agent-framework/concepts/workflows/executors.md b/agent-framework/concepts/workflows/executors.md index b1c3b52e..acc32299 100644 --- a/agent-framework/concepts/workflows/executors.md +++ b/agent-framework/concepts/workflows/executors.md @@ -5,7 +5,7 @@ zone_pivot_groups: programming-languages author: TaoChenOSU ms.topic: article ms.author: taochen -ms.date: 07/01/2026 +ms.date: 08/11/2026 ms.service: agent-framework --- @@ -20,6 +20,7 @@ ms.service: agent-framework | Function-Based Executors | ✅ | ✅ | ✅ | | | Explicit Type Parameters | ❌ | ✅ | ❌ | Python-specific | | The WorkflowContext Object | ✅ | ✅ | ✅ | | + | Declaring Protocol Types | ✅ | ❌ | ❌ | C#-specific protocol declaration attributes | | Designating Terminal and Intermediate Outputs | ❌ | ✅ | ❌ | Python-specific | | Agent Executors | ❌ | ❌ | ✅ | Go-specific | | Executor Lifecycle | ❌ | ❌ | ✅ | Go-specific | @@ -137,6 +138,47 @@ internal sealed partial class LogExecutor() : Executor("LogExecutor") } ``` +## Declaring Protocol Types + +An executor's protocol declares the message types it may send to connected executors and the output types it may yield. The workflow validates calls to `SendMessageAsync` and `YieldOutputAsync` against these declarations and throws an `InvalidOperationException` when an executor uses an undeclared type. + +Use `[SendsMessage]` to declare sent message types and `[YieldsOutput]` to declare yielded output types. These attributes describe the executor's capabilities; they do not send or yield values themselves. Apply each attribute multiple times when the executor uses multiple types. + +For executors with a single typed handler, derive from `Executor` or `Executor` and override `HandleAsync`: + +```csharp +internal sealed record ProcessRequest(string Text); +internal sealed record ProgressUpdate(string Status); + +[SendsMessage(typeof(ProgressUpdate))] +[YieldsOutput(typeof(string))] +internal sealed partial class ProcessingExecutor() + : Executor("ProcessingExecutor") +{ + public override async ValueTask HandleAsync( + ProcessRequest message, + IWorkflowContext context, + CancellationToken cancellationToken = default) + { + await context.SendMessageAsync( + new ProgressUpdate("Processing started"), + cancellationToken); + + await context.YieldOutputAsync( + message.Text.ToUpperInvariant(), + cancellationToken); + } +} +``` + +When the workflows source generator is referenced, a class with `[SendsMessage]` or `[YieldsOutput]` must be declared `partial` so the generator can add its protocol configuration. + +For source-generated executors with `[MessageHandler]` methods, declare types used by one handler with its `Send` and `Yield` named arguments, such as `[MessageHandler(Send = [typeof(ProgressUpdate)], Yield = [typeof(string)])]`. Use class-level `[SendsMessage]` and `[YieldsOutput]` when the declarations apply to the entire executor. + +Non-void handler return types are automatically added to the sent and yielded protocol types when `ExecutorOptions.AutoSendMessageHandlerResultObject` and `ExecutorOptions.AutoYieldOutputHandlerResultObject` are enabled. Both options are enabled by default. Explicit declarations are therefore primarily needed for additional types emitted directly through `SendMessageAsync` or `YieldOutputAsync`. + +`[YieldsOutput]` permits the executor to yield a type, but it does not designate the executor as a terminal output source. Register the executor with `WorkflowBuilder.WithOutputFrom` for its yielded values to surface to the workflow caller. + ::: zone-end ::: zone pivot="programming-language-python"