* Make DeclarativeWorkflowExecutor ChatProtocol-compatible for AsAIAgent hosting
Extends the existing DeclarativeWorkflowExecutor<TInput> root executor with
additional ChatProtocol-compatible input routes (string, ChatMessage,
IEnumerable<ChatMessage>, ChatMessage[], TurnToken) so that workflows built
via DeclarativeWorkflowBuilder.Build<TInput>(...) work both for direct
invocation and when hosted via Workflow.AsAIAgent(...).
- Each input message advances the declarative graph immediately; the
TurnToken that the host sends after the message batch is treated as a
no-op since the message has already been processed.
- Conversation id resolution now prefers persisted workflow system state,
then DeclarativeWorkflowOptions.ConversationId, then a newly created
conversation. This makes multi-turn invocations reuse the prior
conversation rather than creating a fresh one each turn.
- The separate DeclarativeChatProtocolStartExecutor and
DeclarativeWorkflowBuilder.BuildChatProtocol overloads introduced
earlier are removed; callers continue to use Build<TInput>(...).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use DeclarativeWorkflowContext when reading workflow conversation id
GetWorkflowConversation() requires a DeclarativeWorkflowContext (it calls ReadState which dynamic-casts via the DeclarativeContext helper). The chat-protocol auxiliary handlers receive a BoundWorkflowContext, so calling the extension on the raw IWorkflowContext throws `Invalid workflow context: BoundWorkflowContext`. Use the wrapped declarativeContext that we already constructed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: surface ExecutorFailedEvent as ErrorContent in AsAIAgent response
WorkflowSession.InvokeStageAsync only converted WorkflowErrorEvent into an ErrorContent payload. ExecutorFailedEvent fell through to the default branch which emits an empty AgentResponseUpdate carrying the event in RawRepresentation. OutputConverter then mapped that to a workflow_action item with status=failed and dropped the exception entirely, so callers got status=completed and error=null even when an executor threw.
- WorkflowSession.cs: add ExecutorFailedEvent case mirroring WorkflowErrorEvent. Honors _includeExceptionDetails.
- OutputConverter.cs: when an update carries both a WorkflowEvent in RawRepresentation and non-empty Contents, fall through to content processing so the unwrapped error (or any future content payload from a workflow event) is actually emitted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* improve: walk inner exceptions when surfacing ExecutorFailedEvent
DeclarativeActionExecutor wraps inner exceptions in DeclarativeActionException with a generic `Unhandled workflow failure` message, hiding the real cause. Walk InnerException so the response shows the full chain (e.g. the underlying HTTP 400 / auth error).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Surface declarative SendActivity output as chat content
SendActivityExecutor now emits AgentResponseEvent in addition to
MessageActivityEvent so chat protocols (e.g. AsAIAgent) receive the
formatted activity text. The existing MessageActivityEvent is preserved
for DevUI/observability.
Also extend WorkflowSession.WorkflowOutputEvent handling to accept
AgentResponse payloads, mapping them to their constituent ChatMessages.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Persist hosted-agent sessions to disk; fix System.LastMessageText
Adds FileSystemAgentSessionStore that writes the serialized AgentSession JSON
(which already embeds the workflow's in-memory checkpoint manager) to a per-
conversation file under /.checkpoints when running in a Foundry hosted env
or {cwd}/.checkpoints locally. Mirrors the python foundry_hosting._responses
FileCheckpointStorage pattern so multi-turn workflow state survives process
restarts without requiring callers to wire up storage themselves.
AddFoundryResponses now defaults to FileSystemAgentSessionStore.CreateDefault()
instead of InMemoryAgentSessionStore; callers can still override via DI.
Also fixes {System.LastMessageText} resolving empty: DeclarativeWorkflowExecutor
.AdvanceAsync was passing the message rehydrated from CreateMessageAsync to
SetLastMessageAsync, but ResponseItem -> ChatMessage round-trip drops the .Text
extension content. Use the original input ChatMessage (which still has the
user-supplied text) and copy the server-assigned MessageId across when present.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Close multi-modal input parity gaps with python foundry_hosting
InputConverter now mirrors the python _responses.py content handling:
- ComputerScreenshotContent maps to UriContent/HostedFileContent (was dropped).
- Plain TextContent and SummaryTextContent map to MEAI TextContent.
- MessageContentReasoningTextContent maps to MEAI TextReasoningContent.
- input_file with text/* file_data data URIs is decoded inline into
TextContent with a [File: name] prefix, matching python _convert_file_data
so {System.LastMessageText} surfaces the file body. Non-text data URIs and
hosted/url file references preserve filename as AdditionalProperties.
Image/file extraction logic is extracted into shared AppendImageContent and
AppendFileContent helpers used by both the fresh-input and history-replay
switches. Existing 37 InputConverter tests still pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Foundry hosting: round-trip tool-approval (HITL) content as mcp_approval_request/response
Closes the gap where Microsoft.Agents.AI.Foundry.Hosting silently dropped
MEAI ToolApprovalRequestContent/ToolApprovalResponseContent in both
directions. We now serialize them onto the wire as the standard Responses
API mcp_approval_request/mcp_approval_response items with
server_label='agent_framework', and parse the symmetric inbound shapes
back into MEAI content.
Wire format:
- The Responses API only standardizes mcp_approval_* as the approval
primitive. We declare AF as a virtual MCP server via the server_label
field, which is honest for AF's server-side tool-call holding pattern.
- The SDK enforces a strict {prefix}_{50hex} wire-id format, so we hash
the AF RequestId and persist a wireId<->afRequestId mapping in
AgentSession.StateBag so a later mcp_approval_response can be matched
back to the originating workflow request.
Coexists with the existing ConsentAwareMcpClientAIFunction flow
(AgentFrameworkResponseHandler.cs) which emits mcp_approval_request from
a side-channel, not via OutputConverter's content switch.
Known follow-up: python (foundry_hosting/_responses.py) has the same
output-side gap (ToolApprovalRequestContent emission). Out of scope here.
Tests: +9 unit tests covering both fresh-input and history-replay shapes,
StateBag mapping resolution, and the non-FunctionCallContent skip path.
Existing 108 converter tests still pass; full suite 370/370.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review feedback for hosted-declarative-dotnet
FileSystemAgentSessionStore reliability/scoping:
- Bound Sanitize() stackalloc at 256 chars, fall back to ArrayPool for longer ids so a long conversationId can no longer crash the hosting process with StackOverflowException.
- Use a Guid-suffixed temp file (\{path}.{guid}.tmp\) so concurrent SaveSessionAsync calls on the same conversation can no longer race on the same temp file. Best-effort temp cleanup on failure.
- Bucket session files by agent.Name when set so two keyed agents that happen to share a conversationId no longer overwrite each other's persisted state. Single-agent / unnamed-agent cases keep the original flat layout (Python parity).
DeclarativeWorkflowExecutor chat-protocol routing:
- ConfigureChatProtocolRoutes uses IsAssignableFrom rather than exact type equality so a broader TInput (object, base interfaces) does not have its inherited inputTransform shadowed by handlers we register here.
- HandleChatMessagesAsync / HandleChatMessageArrayAsync now advance through every message in the batch instead of keeping only the trailing one, so multi-message turns and replayed history are no longer silently truncated. AdvanceAsync gains a finalizeTurn flag so only the last message in the batch sends the result.
Tests:
- New FileSystemAgentSessionStoreTests covering constructor, fresh-session fallback for missing/empty files, root-directory creation, save/get round-trip, agent-Name scoping isolation, long conversationId, invalid-character sanitization, and concurrent-save behavior.
- New InputConverterTests covering AppendFileContent: text/* data URI decode (with and without filename prefix), non-text data URI passthrough, malformed data URI fallback, and filename propagation onto UriContent / HostedFileContent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add tests for remaining PR review feedback (C2, D1, E1)
C2: InputConverter — add 9 tests covering SDK content types that previously
had no coverage:
- SdkTextContent → TextContent (input + output paths)
- SummaryTextContent → TextContent (input + output paths)
- MessageContentReasoningTextContent → TextReasoningContent (input + output)
- ComputerScreenshotContent (HTTP URL → UriContent, data: URI → DataContent,
output path → UriContent)
D1: OutputConverter — add 2 tests for the WorkflowEvent + Contents fall-through:
- WorkflowEvent in RawRepresentation with text Contents must flow through
the content-processing path (text-delta event emitted).
- WorkflowEvent + ErrorContent must produce a failed event rather than be
swallowed by the workflow branch.
E1: SendActivityExecutor — extend CaptureActivityAsync to assert that the
executor emits an AgentResponseEvent carrying the activity text with the
correct ExecutorId and ChatRole.Assistant role.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Defense-in-depth: neutralize dot-segments in Sanitize and cap TryDecodeTextDataUri input size
Addresses claude-opus-4.6 security review on PR #5589:
- FileSystemAgentSessionStore.Sanitize now replaces all-dot segments
(., .., ...) with underscores so a developer-controlled agent.Name
cannot escape the root directory on Linux (where Path.GetInvalidFileNameChars
only contains NUL and '/').
- InputConverter.TryDecodeTextDataUri rejects encoded payloads larger than
16 MiB before calling Convert.FromBase64String, preventing a single
oversized data URI from triggering a multi-megabyte allocation.
- Adds unit tests covering both fixes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Linux-only failure in SaveSessionAsync_SanitizesInvalidPathCharactersAsync
'?' is in Path.GetInvalidFileNameChars only on Windows, not on Linux/macOS,
so the test failed on Ubuntu in CI. Use Path.GetInvalidFileNameChars()[0]
(skipping NUL) to pick a guaranteed-invalid character for the running OS,
and assert the result no longer contains it.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address claude-opus-4.6 security/reliability review feedback
WorkflowSession.cs:
- ExecutorFailedEvent handler no longer leaks the internal executor ID
in error messages. Mirror the WorkflowErrorEvent pattern: surface the
exception's Message when _includeExceptionDetails is true, fall back
to the generic 'An error occurred while executing the workflow.' otherwise.
This also resolves the failing WorkflowHostSmokeTests assertions.
FileSystemAgentSessionStore.cs:
- GetSessionPath no longer has a write side effect. Directory.CreateDirectory
for the per-agent bucket is now performed only on the SaveSessionAsync
path, so a read miss on GetSessionAsync no longer leaves an empty
directory on disk.
- Adds GetSessionAsync_NoExistingFile_DoesNotCreateAgentDirectoryAsync
to lock in the no-side-effect-on-read contract.
OutputConverterTests.cs:
- Strengthen ConvertUpdatesToEventsAsync_ToolApprovalRequest_NonFunctionToolCall_SkippedAsync
to assert exactly one event (the terminal ResponseCompletedEvent) so a
spurious output-item-added/-done leak would now fail the test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review: clean up comments and rename TryParseArguments
- Remove Python-codebase references from C# XML docs and inline comments.
- Drop fix-history comments referring to previously-resolved issues.
- Drop `Defense-in-depth:` prefixes; keep the concrete `what & why`.
- Drop `previously we kept only the trailing message` comment in
DeclarativeWorkflowExecutor; just describe current loop behavior.
- Rename InputConverter.TryParseArguments to ParseFunctionArgumentsObject
to make the intent obvious at the call site.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review: collision-free Sanitize, MAF-style refactors
- FileSystemAgentSessionStore.Sanitize now percent-encodes invalid chars
(and `%` itself) instead of replacing them with `_`, eliminating
collisions like `foo/bar` vs `foo_bar` mapping to the same bucket.
All-dot segments encode every dot so Windows trailing-dot trimming
cannot reintroduce a navigable name.
- AddFoundryResponses XML doc updated to accurately describe the default
store root (/.checkpoints when hosted, {cwd}/.checkpoints locally).
- DeclarativeWorkflowExecutor.ConfigureChatProtocolRoutes now uses exact
type equality instead of IsAssignableFrom so a broad TInput (e.g.
object) does not skip registering IEnumerable<ChatMessage>, which
ChatProtocolExtensions.IsChatProtocol requires verbatim.
- SendActivityExecutor uses context.YieldOutputAsync(response) instead
of manually constructing AgentResponseEvent, so the activity will
participate in any future OutputFilter coverage.
- WorkflowSession handles AgentResponseEvent in its own switch case,
avoiding the second typecheck against output.Data.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(workflows): bridge declarative HITL through Foundry hosting via IExternalRequestEnvelope
Introduce a new public interface IExternalRequestEnvelope in
Microsoft.Agents.AI.Workflows that lets the runtime peek through a
declarative-layer envelope without taking a circular reference back into
the declarative package. ExternalInputRequest (declarative) implements
it; ExternalInputResponse is constructed via the request's CreateResponse
factory. WorkflowSession unwraps inner AIContent on the request side and
rewraps the client's ChatMessage reply into an ExternalInputResponse on
the response side. PortableValue cannot deserialize directly into an
interface, so TryGetRequestEnvelope resolves the concrete type via
RequestPortInfo.RequestType (TypeId -> Type.GetType) before casting.
Public WorkflowHarness contract preserved: InvokeFunctionToolExecutor
and WorkflowActionVisitor are unchanged from upstream, so public
InvokeToolWorkflowTest scenarios continue to drive
ExternalInputRequest / ExternalInputResponse directly through the
harness.
AgentFrameworkResponseHandler: skip prior conversation history replay
when an existing session is being resumed (workflow checkpoint already
holds the prior messages).
WorkflowSession: when includeExceptionDetails is opted in, also unwrap
DeclarativeActionException so HITL failures are debuggable.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: alliscode <bentho@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add declarative HttpRequestAction support to workflows
* Clean up response body for diagnostics and fix tests.
* Fix merge with main.
* Remove redundant fallback for request content headers.
* Add declarative InvokeHttpRequest sample
* Fix solution file and update sample yaml comments
* Add final newline to sample class to fix formatting failure
* Add declarative HttpRequestAction support to workflows
* Clean up response body for diagnostics and fix tests.
* Fix merge with main.
* Remove redundant fallback for request content headers.
* fix: use HasSchema check in DetermineElementType to prevent empty records
When parsing JSON arrays containing objects without a predefined schema,
`DetermineElementType()` was creating a `VariableType` with an empty
(non-null) schema via `targetType.Schema?.Select(...) ?? []`. This caused
`ParseRecord` to take the schema-based parsing path, iterating over zero
schema fields and silently discarding all JSON properties.
The fix checks `targetType.HasSchema` and falls back to
`VariableType.RecordType` (which has `Schema = null`) when no schema is
defined, ensuring `ParseRecord` takes the dynamic `ParseValues()` path
that preserves all JSON properties.
Closes#4195
* test: add regression tests for schema-less JSON array-of-objects parsing (#4195)
Add two regression tests to JsonDocumentExtensionsTests:
1. ParseRecord_ObjectWithArrayOfObjects_NoSchema_PreservesNestedProperties
- Parses a JSON object containing an array of objects using
VariableType.RecordType (no schema) and verifies that nested
object properties (name, role) are preserved in each element.
- This is the exact scenario from issue #4195 where objects in
arrays were being returned as empty dictionaries.
2. ParseList_ArrayOfObjects_NoSchema_PreservesProperties
- Parses a JSON array of objects directly via ParseList with
VariableType.ListType (no schema) and verifies all properties
are preserved.
Both tests follow the existing Arrange/Act/Assert pattern and would
have failed before the DetermineElementType() fix (empty dictionaries
instead of populated ones).
* feat: Implement Polymorphic Routing
* feat: Add support for Send/Yield annotations with basic Executor
* Adds annotations to Declarative workflow executors
* fix: Address PR Comments
* Implicit filter in collection loops
* Remove debug / usused / superfluous code
* Fix ProtocolBuilder implicit output registrations
* Fix logic error in ExecuteRouteGeneratorTests.ClassWithManualConfigureProtocol_DoesNotGenerate
* fix: Solidify type checks and send/yield type registrations
* fix: Suppress generation of TurnTokens out of AggregateTurnMessagesExecutor
* Fixes an issue where ConcurrentEndExecutor is not expecting TurnTokens.
* fix: Add ProtocolBuilder support for chained-delegation
* Updates Declarative pacakge to rely on chained-delegation Send/Yield registration
* Renames DeclarativeActionExectuor's new ExecuteAsync to ExecuteActionAsync to avoid colliding with Executor.ExecutoeAsync
* fix: Address PR Comments
* Fixes type mapping in FanInEdgeRunner
* Fixes and expalins send/yield type registration in FunctionExecutor
* fixup: build-break
* fix: Add missing SendsMesage declaration to InvokeAzureAgentExecutor
* Initial Implementation of InvokeFunctionTool
* Added unit test for InvokeFunctionTool executor.
* Implemented unit and integration tests for InvokeFunctionTool.
* Add sample for InvokeFunctionTool in declarative workflows.
* Remove unused sample and updated comments.
* Updating to official OM release with InvokeFunctionTool
* Fix formatting issues.
* Updated PowerFx version
* Update test fixture
* Cleanup - Removed unused method in InvokeFunctionToolExecutor
* Update test based on PR feedback.
* Update based on PR comments
* Initial plan
* Add comprehensive unit tests for EditTableV2Executor
- Test AddItemOperation with record and scalar values
- Test ClearItemsOperation
- Test RemoveItemOperation
- Test TakeLastItemOperation (with items and empty table)
- Test TakeFirstItemOperation (with items and empty table)
- Test error cases (null ItemsVariable, non-table variable)
- Include ExecuteTestAsync and CreateModel helper methods
- All 10 tests passing
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
* Add comprehensive unit tests for EditTableV2Executor - complete with 100% coverage
- Added 13 comprehensive tests covering all code paths
- Test AddItemOperation with record and scalar values
- Test ClearItemsOperation
- Test RemoveItemOperation (including non-table value case)
- Test TakeLastItemOperation (with items and empty table)
- Test TakeFirstItemOperation (with items and empty table)
- Test error cases (null ItemsVariable, non-table variable, null operation values)
- Include ExecuteTestAsync and CreateModel helper methods
- 100% line and branch coverage achieved
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
* Update tests / refine product code
* Checkpoint
* Updated
* Update dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/SetTextVariableExecutorTest.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Address code review feedback
- Fix typo: rename metadataExpresssion to metadataExpression
- Fix test name in AddMessageWithMetadataAsync (was using wrong test name)
- Fix test name in ClearGlobalScopeAsync (was using wrong test name)
- Remove pre-population in SetTextVariableExecutorTest that made tests ineffective
- Use explicit .Where() filter in SetMultipleVariablesExecutorTest foreach loop
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: crickman <66376200+crickman@users.noreply.github.com>
Co-authored-by: Chris Rickman <crickman@microsoft.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat(workflows): Make telemetry opt-in via WithOpenTelemetry()
- Add WorkflowTelemetryOptions class with EnableSensitiveData property
- Add WorkflowTelemetryContext to manage ActivitySource lifecycle
- Add WithOpenTelemetry() extension method on WorkflowBuilder
- Update all workflow components to use telemetry context:
- WorkflowBuilder, Workflow, Executor
- InProcessRunnerContext, InProcessRunner
- LockstepRunEventStream, StreamingRunEventStream
- All edge runners (Direct, FanIn, FanOut, Response)
- Telemetry is now disabled by default
- Users must call WithOpenTelemetry() to enable spans/activities
BREAKING CHANGE: Workflow telemetry is now opt-in. Users who relied on
automatic telemetry must add .WithOpenTelemetry() to their workflow builder.
* refactor: Pass telemetry context as parameter instead of via interface
- Remove IWorkflowContextWithTelemetry interface
- Add internal ExecuteAsync overload that accepts WorkflowTelemetryContext
- Public ExecuteAsync delegates with WorkflowTelemetryContext.Disabled
- InProcessRunner passes TelemetryContext when calling ExecuteAsync
- BoundContext now implements IWorkflowContext (not the removed interface)
* Add optional ActivitySource parameter to WithOpenTelemetry
Allow users to provide their own ActivitySource when enabling telemetry,
giving them better control over the ActivitySource lifecycle. When not
provided, the framework creates one internally (existing behavior).
Changes:
- Add optional activitySource parameter to WithOpenTelemetry() extension
- Update WorkflowTelemetryContext to accept external ActivitySource
- Add unit test for user-provided ActivitySource scenario
* Add component-level telemetry control with disable flags
Allow users to selectively disable specific activity types via
WorkflowTelemetryOptions. All activities are enabled by default.
New disable flags:
- DisableWorkflowBuild: Disables workflow.build activities
- DisableWorkflowRun: Disables workflow_invoke activities
- DisableExecutorProcess: Disables executor.process activities
- DisableEdgeGroupProcess: Disables edge_group.process activities
- DisableMessageSend: Disables message.send activities
Added helper methods to WorkflowTelemetryContext for each activity type
and updated all activity creation sites to use them.
* Implement EnableSensitiveData to log executor input/output
When EnableSensitiveData is true in WorkflowTelemetryOptions, executor
input and output are logged as JSON-serialized attributes in the
executor.process activity.
New activity tags:
- executor.input: JSON serialized input message
- executor.output: JSON serialized output result (non-void only)
Added suppression attributes for AOT/trimming warnings since this is
an opt-in feature for debugging/diagnostics.
* Refactor activity start methods to centralize tagging logic
Move tagging logic into WorkflowTelemetryContext methods:
- StartExecutorProcessActivity now accepts executorId, executorType,
messageType, and message; sets all tags including executor.input
when EnableSensitiveData is true
- Added SetExecutorOutput method to set executor.output after execution
- StartMessageSendActivity now accepts sourceId, targetId, and message;
sets all tags including message.content when EnableSensitiveData is true
Simplified Executor.cs and InProcessRunnerContext.cs by removing
inline tagging code. Added message.content tag constant.
* Revert Python changes
* Update samples and code cleanup
* Fix file formatting
* Add comment
* Add telemetry configuration to declarative workflow
* Remove delays in tests
* Address comments
* Builds locally and tests pass
* Fix typo
* Updated
* Updated
* Fixed tests failing on net472 but not on dotnet10
---------
Co-authored-by: Chris Rickman <crickman@microsoft.com>
* Builds locally and tests pass
* Fix typo
* Reverted nuget config change to remove internal feed and map to new public object model package with renames.
* Renaming Bot object model in additional sample.
---------
Co-authored-by: Peter Ibekwe <peibekwe@microsoft.com>
* Upgrade to .NET 10
- Require .NET 10 SDK
- Include net10.0 assets in all assemblies
- Move net9.0-only targets to net10.0
- Update LangVersion to latest
- Remove complicated distinctions between debug target TFMs and release target TFMs
- Remove unnecessary package dependencies when built into netcoreapp
- Clean up some ifdefs
- Clean up some analyzer warnings
* Fix CI
* fix: Workflow Validation
* adds orphan validation to workflow builder
* adds tests for workflow validation
* expands on the underlying reasoning why type validation is not supported
* fixup: CodeGen template
* refactor: Unify ExecutorIsh and ExecutorRegistration => ExecutorBinding
* Switch to more modern Record type-tree for Sum Types
* Unify APIs for getting ExecutorBinding
* Fix an issue where workflows consisting entirely of cross-run shareable executors which are not instance-resettable do not properly clear state when running non-concurrently.
* feat: Simplify function-to-executor pattern
* refactor: Normalize API naming
* refactor: remove unused internals
* feat: Execution Mode for sharing a workflow among concurrent runs
* feat: Update WorkflowHostAgent to support concurrent execution
* Also update AsAgent APIs to support injecting a CheckpointManager and an IWorkflowExecutionEnvironment
* fix: Make Read logic consistent in DeclarativeWorkflowContext