-
Notifications
You must be signed in to change notification settings - Fork 97
feat(workflow-copilot): add copilot sdk task #2402
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
Open
DLehenbauer
wants to merge
10
commits into
microsoft:main
Choose a base branch
from
DLehenbauer:workfloweng
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,806
−13
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
18bd868
feat(workflow): add Copilot SDK task family and outputSchema to workf…
DLehenbauer 2db1038
feat(workflow): fixes for merge into main
DLehenbauer 879692d
Merge branch 'main' of https://github.com/microsoft/TypeAgent into wo…
DLehenbauer 149dc55
docs(workflow): drop inputSchema from TaskContext decision 0011
DLehenbauer d5b85b4
Merge remote-tracking branch 'origin/main' into workfloweng
DLehenbauer 88e231e
refactor(workflow-engine): tighten builtin task type annotations
DLehenbauer cacd4bc
docs(workflow-engine): note why math.divide and floor/round/ceil are …
DLehenbauer 4f9a4ae
Fix prettier formatting in d10-conventional-commit.json
DLehenbauer 6325442
Revert tighter builtin task type annotations; cast where consumed
DLehenbauer af9f672
docs(workflow-engine): preserve original math.divide comment
DLehenbauer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
354 changes: 354 additions & 0 deletions
354
ts/docs/design/workflowSystem/ir/decisions/0010-copilot-task-family.md
Large diffs are not rendered by default.
Oops, something went wrong.
141 changes: 141 additions & 0 deletions
141
ts/docs/design/workflowSystem/ir/decisions/0011-task-context-schema-awareness.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| # TaskContext schema awareness (decision 0011) | ||
|
|
||
| Status: **Adopted (v1).** Engine API extension; **not** an IR change. | ||
| Adds `outputSchema` to the `TaskContext` value the engine passes to | ||
| `task.execute`. The schema is populated from the dispatching node's | ||
| IR-declared `outputSchema` — i.e. existing IR data, made visible to | ||
| the task implementer. | ||
|
|
||
| Related: | ||
|
|
||
| - [../../principles/design-principles.md](../../principles/design-principles.md) — P4 ("each part can be understood / validated / tested without the whole, given only its declared boundary contract"). | ||
| - [0003-task-schema-source.md](0003-task-schema-source.md) — establishes that the IR node's `inputSchema`/`outputSchema` are authoritative (Option 1'). | ||
| - [0010-copilot-task-family.md](0010-copilot-task-family.md) — the first consumer; `copilot.invoke` reads `ctx.outputSchema` to drive its schema-guided turn loop. | ||
|
|
||
| ## 1. Problem | ||
|
|
||
| Decision 0003 establishes that for every task node the IR's declared | ||
| `inputSchema`/`outputSchema` is authoritative — it either restates the | ||
| registered task's contract verbatim or narrows it. The engine already | ||
| validates a task's return value against the IR-declared `outputSchema` | ||
| at runtime (`ir-v1.md` §5.2). | ||
|
|
||
| But today, the task implementation cannot **read** its own node's | ||
| declared `outputSchema`. `TaskContext` carries `runId`, `nodeId`, | ||
| `scopePath`, `signal`, `constraints` — but not the output schema. So | ||
| a task that wants to _use_ the schema as part of its computation (for | ||
| example, instructing an LLM agent to produce a value of a specific | ||
| shape, or driving a schema-aware transform) has no first-class access | ||
| to it. | ||
|
|
||
| ## 2. Decision | ||
|
|
||
| Add one field to `TaskContext`: | ||
|
|
||
| ```typescript | ||
| export interface TaskContext { | ||
| runId: string; | ||
| nodeId: string; | ||
| scopePath: string[]; | ||
| signal: AbortSignal; | ||
| constraints?: TaskConstraints; | ||
| /** | ||
| * The dispatching node's declared output schema, per IR §3.5. | ||
| * Authoritative for this call: equal to or a narrowing of the | ||
| * registered task's outputSchema (decision 0003 Option 1'). | ||
| * The engine validates the task's return value against this | ||
| * schema after execution (IR §5.2); tasks may also use it to | ||
| * shape their computation (e.g. schema-guided LLM responses). | ||
| */ | ||
| outputSchema: JSONSchema; | ||
| } | ||
| ``` | ||
|
|
||
| The engine's runner populates this field from the dispatching | ||
| `WorkflowNode`'s `outputSchema` before invoking `task.execute`. | ||
|
|
||
| `outputSchema` is declared as required (not optional) on `TaskContext`: | ||
| `TaskNode.outputSchema` is required by the IR contract | ||
| (`model/src/ir.ts`) and the static validator rejects task nodes that | ||
| omit it, so the runner can — and does — pass it unconditionally. | ||
|
|
||
| ## 3. Why this earns its place | ||
|
|
||
| This is a near-zero-cost extension that exposes existing IR data to | ||
| the task implementer. It satisfies: | ||
|
|
||
| - **P4 (boundary contract).** The IR-declared output schema _is_ half | ||
| of the task's boundary contract for this call (the other half — the | ||
| input — is already supplied as the `execute` argument). P4's | ||
| one-line test — _"Can I validate/test this part using only what its | ||
| boundary declares?"_ — is more directly satisfied when the task | ||
| itself can see its declared output shape, not merely have it | ||
| enforced from outside. | ||
| - **Decision 0003 alignment.** 0003 made the IR's output schema | ||
| authoritative. Making it visible to the task is the natural | ||
| consequence: if the IR is the source of truth, the task should be | ||
| able to consult that source. | ||
| - **Generality.** The change is not Copilot-specific. Any future | ||
| schema-aware task benefits without re-litigating: a structured- | ||
| response variant of `llm.generate`, a `json.transform` task that | ||
| reshapes input to the declared output, an MCP bridge that maps | ||
| the node's schema onto the upstream protocol, etc. | ||
|
|
||
| ## 4. Why this is NOT an IR change | ||
|
|
||
| No IR field is added or removed. `outputSchema` already exists on | ||
| every task node (`ir-v1.md` §3.5). This decision changes only: | ||
|
|
||
| - `workflow-model/src/taskDefinition.ts` — the `TaskContext` interface. | ||
| - `workflow-engine/src/runner.ts` — the runner populates the new | ||
| field when constructing the per-call `TaskContext`. | ||
|
|
||
| `ir-v1.md` does not need editing. No validator rule changes. No | ||
| existing IR document semantics change. | ||
|
|
||
| ## 5. Alternatives considered | ||
|
|
||
| ### A. Pass the schema in via a side-channel (e.g., a per-runId map) | ||
|
|
||
| Reject. Hides the contract from the task's documented interface; | ||
| implementers have to know the side-channel exists. The whole point of | ||
| `TaskContext` is to be the documented per-call contract handed to | ||
| tasks. | ||
|
|
||
| ### B. Have schema-aware tasks accept a `responseSchema` field on input | ||
|
|
||
| Reject. Creates duplicate declarations of the same shape (the IR | ||
| node's `outputSchema` and the task's input `responseSchema`) which | ||
| must agree by convention but the engine can't enforce in a way that's | ||
| visible at one read site. P5 ("would a reader be surprised?") — yes, | ||
| because they'd have to know the redundancy is required. | ||
|
|
||
| ### C. Defer until the next schema-aware task earns the change | ||
|
|
||
| Reject. The cost of the change is essentially zero (one field on a | ||
| context object, one population site in the runner). Doing it now | ||
| means decision 0010 (Copilot task family) lands cleanly and any | ||
| future schema-aware task gets the same affordance for free. Doing | ||
| it later means doing the migration of test fixtures and the runner | ||
| twice. | ||
|
|
||
| ## 6. Implementation notes | ||
|
|
||
| - **No test-fixture cascade.** A scan of `engine/test/` and | ||
| `model/test/` confirms no test directly constructs a `TaskContext`; | ||
| all task execution flows through `WorkflowEngine.run`. The runner | ||
| populates the new field from the node it is dispatching, so | ||
| existing tests continue to work without per-fixture changes. | ||
| - **Schema is a JSON value, not an Ajv validator.** The runner does | ||
| NOT pre-compile a per-task `submit_response` validator or otherwise | ||
| cache schemas keyed by node — each task that wants to validate | ||
| against the schema brings its own validator (e.g. Ajv instance). | ||
| Keeping `TaskContext.outputSchema` as a plain `JSONSchema` mirrors | ||
| how `TaskDefinition.outputSchema` is typed today. | ||
|
|
||
| ## 7. Cross-references | ||
|
|
||
| - [../../principles/design-principles.md](../../principles/design-principles.md) — P4. | ||
| - [0003-task-schema-source.md](0003-task-schema-source.md) — what made the IR's schemas the authoritative source this decision exposes. | ||
| - [0010-copilot-task-family.md](0010-copilot-task-family.md) — first consumer. | ||
| - [../ir-v1.md](../ir-v1.md) §3.5 (task node `outputSchema`), §5.2 (engine-side runtime output schema validation that this decision does **not** change). |
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
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
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.