[1/3] Add shared structured action contract discovery - #2991
Merged
George Ng (GeorgeNgMsft) merged 9 commits intoSep 18, 2026
Merged
Conversation
George Ng (GeorgeNgMsft)
added this pull request to stack #2994
September 11, 2026 07:20
George Ng (GeorgeNgMsft)
marked this pull request as ready for review
September 11, 2026 18:30
jebrans
approved these changes
Sep 11, 2026
Expose exact action discovery and closed TypeScript contracts through Dispatcher and RPC. Fingerprint execution-relevant schema and policy, report cached availability, and support trusted logical scope reuse without enabling execution. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Only expose active, enabled actions through discovery and exact contract lookup, and remove detailed availability state from the public protocol. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Return every matching closed contract from a required natural-language query, removing pagination, internal catalog filters, and the separate contract lookup. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Record BM25-style relevance ranking as the planned replacement for substring matching while preserving the two-call discovery and execution flow. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Dominic Nguyen (datduyng)
approved these changes
Sep 18, 2026
George Ng (GeorgeNgMsft)
force-pushed
the
georgengmsft-structured-action-contracts
branch
from
September 18, 2026 00:39
9ca20b7 to
7307a05
Compare
George Ng (GeorgeNgMsft)
removed this pull request from the merge queue due to a manual request
Sep 18, 2026
Use live action identity and current schema validation as the execution compatibility boundary instead of contract hashes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rio Yu (rioyu123)
pushed a commit
to rioyu123/TypeAgent
that referenced
this pull request
Sep 19, 2026
This PR adds a safe way for clients to run a specific TypeAgent action using structured input. It uses the dispatcher’s existing queue and action engine, asks the user before making changes, pauses when the action needs more information, and returns the action’s real result. It also lets the same conversation reconnect to unfinished work without allowing another client to take control. ## Where this fits This is layer 2 of the structured-action stack: 1. microsoft#2991 lets clients search for actions and inspect their input contracts. 2. **This PR safely runs the selected action and manages its lifecycle.** 3. microsoft#2993 exposes the feature through MCP and Direct Action adapters. microsoft#2991 has merged, so this draft now targets `main`. Native stack #2994 still tracks `[2991, 2992, 2993]`. ## What changed - Add `executeAction`, `continueAction`, and `cancelAction` to the public dispatcher API and dispatcher RPC. - Run typed actions through the existing dispatcher queue and `executeActions` engine. The implementation does not turn parameters back into command text or send them through natural-language interpretation. - Look up the requested action by its exact `schemaName` and `actionName`. Search ranking is only used to help clients discover actions; it never decides which action is executed. - Recheck the current scope, permissions, enabled state, readiness, input schema, parameters, and safety policy before the action starts and again after waits. - Ask for confirmation unless the action is explicitly marked read-only. A read-only action can still require confirmation, and a caller cannot bypass confirmation by claiming that it already has approval. - Pause and resume the same operation when an action asks a question, shows a form, proposes an edit, or requests a choice. Continuing an operation does not run the action again. - Cancel structured operations without choosing a default answer. This public `cancelAction` is separate from the existing internal agent-RPC cancellation message: it checks the conversation scope and returns a structured result. - Return clear outcomes: `completed`, `failed`, `cancelled`, `requires_interaction`, `unavailable`, or `execution_uncertain`. Completed operations include the real action output, values, and entities. - Guard child actions and flow steps separately while allowing them to use results created earlier in the same operation. The operation does not silently reuse context from an earlier conversation turn. - Add an opt-in reconnect token for structured actions. The token belongs to one conversation and stays in memory. A reconnect takes ownership from the old connection, while stale or unrelated clients are rejected. - Clean up cancelled SDK choices across in-process and agent-RPC execution without changing normal chat behavior. - Fix a Jest ESM issue where `signal-exit` could change the exported shape of `process` while tests were loading. ## API flow First, the client joins a conversation and opts into structured actions: ```ts const joined = await joinConversation(io, { conversationId, structuredActions: {}, }); const resumeToken = joined.structuredActions.resumeToken; ``` The client searches for an action through the API added in microsoft#2991, chooses one exact contract, and sends concrete parameters: ```ts const search = await dispatcher.searchActions({ query: "save this item" }); const result = await dispatcher.executeAction({ protocolVersion: 1, scopeId: search.scopeId, schemaName: "items", actionName: "save", parameters: { value: "example" }, }); ``` If the action needs confirmation or another answer, it returns `requires_interaction`. The client sends the answer back to the same operation: ```ts await dispatcher.continueAction({ protocolVersion: 1, scopeId: result.scopeId, operationId: result.operationId, interactionId: result.interactionId, response: { type: "confirmation", approved: true }, }); ``` Cancellation uses the same `scopeId` and `operationId`. If the client disconnects, it can rejoin the same conversation with the resume token instead of starting the action again. There is no contract fingerprint or `contract_stale` result. The dispatcher checks the current action definition and validates the current parameters each time it reaches an execution boundary. If the action was removed or disabled, it is unavailable. If its current input schema no longer accepts the parameters, execution fails before entering the handler. ## State limits To keep memory use bounded, each dispatcher context keeps at most 100 live operations. Operations and interactions expire after 10 minutes, and the latest 100 finished results are retained for 10 minutes. The server keeps at most 100 structured-action conversation bindings, which expire after 30 minutes without use. ## Validation - Built dispatcher types, dispatcher RPC, dispatcher, agent SDK, agent RPC, and the agent-server protocol, client, and server. - Passed the full dispatcher test run: 132 suites and 2,113 tests, with one pre-existing skip. - Passed 87 structured execution and discovery tests together. - Passed 63 focused RPC, SDK cancellation, reconnect, and server/host tests. - Passed the complexity, lint, test-debt, and circular-dependency checks with no new violations, skipped tests, or dependency cycles. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

This PR adds the shared Dispatcher foundation for progressive TypeAgent action discovery. A caller supplies a required free-text query and receives up to five complete contracts ranked by TypeAgent's existing semantic action index. If embeddings are unavailable or query ranking fails, discovery falls back to deterministic substring matching and returns every literal match. This is layer 1 of the three-PR refactor of #2973; it defines discovery and contracts but intentionally leaves guarded execution and MCP/Direct exposure to the next layers.
Changes
Dispatcher.searchActions({ query })and carries it through Dispatcher RPC without adding a separate contract lookup.ActionCandidateRankerseam insideagent-dispatcher;ActionSchemaSemanticMapimplements it using the existing action embeddings andsemanticSearchActionSchema()remains as a compatibility wrapper.schemaName/actionNameidentity, parameters, required and optional fields, nested definitions, enums, recursive references, policy, output metadata, and interaction metadata.Direct flow
The shared service is transport-neutral. This PR does not expose
searchActionsas an MCP tool yet, and Copilot cannot call it through MCP until layer 3 adds the thin adapter. Layer 2 adds guarded execution using live identity lookup and current parameter validation; there is no hidden schema hash/version equivalence check and nocontract_staleresult. Layer 2 also owns current availability and authorization checks, confirmation, structured results, and interaction lifecycle handling. Layer 3 adds the fixed MCP/Direct operations and conversation mapping. Ordinary user-originated natural language continues through TypeAgent's existing translation pipeline.Validation
agent-dispatcher,@typeagent/dispatcher-types,@typeagent/dispatcher-rpc, and affected dependents built successfully.