Commit 98aa1a3
* docs: add responder (interactive skills) design spec #303
Adds the approved design for an LLM-backed surrogate user that answers a skill's follow-up questions per task under inputs.responder, with reply/stop/abstain classification, a runner-driven follow-up loop reusing the agent session, and distinct result tagging for abstain (StatusError) and cap-exhaustion.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: add responder (interactive skills) implementation plan #303
Bite-sized TDD task breakdown covering the inputs.responder config model and validation, the internal/responder package (persistent surrogate-user session with reply/stop/abstain classification), the runner-driven follow-up loop, ResponderInfo reporting, JSON schema, docs, and dashboard surfacing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add inputs.responder config model #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: validate inputs.responder fields and mutual exclusivity #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add responder decision types and tools #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add responder Classifier with persistent session #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add ResponderInfo to RunResult #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: add injectable responder classifier factory to runner #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: drive interactive skills via responder loop #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use persistent responder session with explicit teardown #303
Responder Classify used EphemeralSession=true, which the engine deletes after the first turn, breaking session resume and dropping instructions on every subsequent turn. Switch to a persistent (non-ephemeral) session, add Classifier.Close plus CopilotEngine.DeleteSession to tear it down explicitly, and call Close via defer at the end of the responder loop with a detached context so cleanup runs even on cancellation. Capture sessionID before the error check so an error-with-decision still persists the session id.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add inputs.responder to task JSON schema #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: document inputs.responder for interactive skills #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: surface responder outcome in dashboard #303
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: rebuild dashboard bundle and fix lint misspelling #303
Rebuild web/dist/index.html so its asset hash matches the freshly built bundle (fixes TestIndexHTMLReferencesExistingAssets after the responder dashboard change) and correct a misspelling flagged by golangci-lint in the responder cleanup comment.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: free responder session usage collector on DeleteSession #303
A non-ephemeral session registers in both e.sessions and e.usageCollectors, but DeleteSession only removed it from e.sessions, orphaning the usage collector for the engine's lifetime. Each responder-driven task leaked one collector; under concurrent runs this accumulated monotonically. Also delete the usageCollectors entry under its mutex.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: remove implementation plan
* fix(responder): surface tool errors and drop dead cap-exhausted flag
Addresses three review comments on PR #304:
* Reject duplicate decision tool calls in the same turn instead of
letting handler order silently pick the winner. The recorder now
returns an error on the second call and Classify surfaces it.
* Propagate mapstructure decode failures from each tool handler so
malformed arguments become a 'responder tool call invalid' error
rather than a fabricated empty reply/abstain.
* Drop the unused lastWasReply flag and the dead initial
ResponderOutcomeCompleted seed in the responder loop. The loop can
only exit normally after a reply, so the post-loop branch
unconditionally records cap_exhausted. Removed the now-unused
ResponderOutcomeCompleted constant.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(responder): synchronize decision recorder against concurrent tool calls #303
The Copilot SDK dispatches each tool call on its own goroutine, so parallel decision calls in one turn raced on the recorder's set/decision/err fields and the previous guardDuplicate check was a non-atomic read-then-act. Guard all fields with a sync.Mutex and route every handler through atomic record/fail methods so the duplicate check-and-set cannot interleave. Adds TestDecisionToolsConcurrentCallsRecordOne, which fires all three tools from goroutines and asserts exactly one decision wins, passing under go test -race.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs(responder): drop stale completed value from ResponderInfo.Outcome comment #303
ResponderOutcomeCompleted was removed earlier in this work, so listing completed as a possible Outcome is misleading; the field is now documented as one of stopped, abstained, cap_exhausted, error.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(schema): make inputs.responder and inputs.follow_up_prompts mutually exclusive #303
follow_up_prompts was defined at the schema root rather than under inputs, so with additionalProperties false the correct inputs.follow_up_prompts placement was being rejected; move it into the inputs object and add a not constraint forbidding responder and follow_up_prompts together so the schema mirrors the runtime Validate contract and editors warn before run time. Adds TestValidateTaskBytes_FollowUpPrompts and TestValidateTaskBytes_ResponderAndFollowUpsMutuallyExclusive.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(execution): delete remote responder session before dropping local tracking #303
DeleteSession removed the session from e.sessions and e.usageCollectors before issuing the remote delete, so a failed remote call left the session untracked, leaking it and losing usage collection. Issue the remote delete first and only drop local tracking on success; on failure the error surfaces and the session stays registered for shutdown cleanup. Adds TestCopilotEngine_DeleteSession_PropagatesRemoteError covering the empty-id no-op, remote-error, and success paths.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(responder): reword cap-exhaustion log to not assert agent intent #303
At cap exhaustion we cannot know whether the agent would have asked again, so the previous message claiming the agent was still asking questions was misleading. Reword the warning and comment to state that the reply budget was exhausted before the responder signaled stop or abstain.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(web): type responder outcome as a string-literal union #303
ResponderInfo.outcome was typed as string, losing exhaustiveness checking in the dashboard. Introduce a ResponderOutcome union (stopped, abstained, cap_exhausted, error) so rendering and styling stay type-safe as outcomes evolve. Rebuilds the embedded dashboard bundle.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(responder): reject empty reply and abstain-reason tool arguments #303
mapstructure decodes a missing or blank answer/reason to an empty string, so the responder could send the agent an empty reply or record a reasonless abstain even though both tool schemas mark the field required. Treat a whitespace-only answer or reason as a handler failure via d.fail so Classify surfaces a clear error instead of fabricating a blank decision. Adds TestDecisionToolsRejectEmptyReply and TestDecisionToolsRejectEmptyAbstainReason covering the missing and blank cases.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7b36ee8 commit 98aa1a3
22 files changed
Lines changed: 1655 additions & 12 deletions
File tree
- docs/plans
- internal
- execution
- models
- orchestration
- responder
- validation
- webapi
- schemas
- site/src/content/docs
- guides
- reference
- web
- dist
- src
- api
- components
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1207 | 1207 | | |
1208 | 1208 | | |
1209 | 1209 | | |
| 1210 | + | |
| 1211 | + | |
| 1212 | + | |
| 1213 | + | |
| 1214 | + | |
| 1215 | + | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
| 1231 | + | |
| 1232 | + | |
| 1233 | + | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + | |
| 1237 | + | |
1210 | 1238 | | |
1211 | 1239 | | |
1212 | 1240 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
0 commit comments