Replies: 3 comments
|
I added a runnable, test-only reproduction pinned to Harness It mounts real pnpm exec vitest run packages/host/apiproxy/tests/api-proxy-view.spec.ts -t 'Discussion #4166' --reporter=verboseThe current expected result is one passing control and one explicit failing regression: the cold view is I’m leaving this as a reference-only branch rather than opening an external PR. Happy to adapt the regression around whichever provider-neutral fix maintainers prefer. |
|
orry, I made a mistake. My tests were actually built from the latest Harness repository, and the correct version is dsh-0.1.1-rc.2 (commit b150a55). |
|
Thanks for confirming that the reproduction target was
The implementation adds an opt-in durable presenter identity:
Compatibility:
Verification on the exact tree:
Since the upstream contribution route does not accept external PRs, this is a reference branch/commit for maintainers to review, adapt, or lift. Happy to revise it around maintainer feedback. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
A tool registered on a live agent scope may legitimately shadow a same-name tool from its preset. Live presentation resolves through the agent and uses the definition that actually executed. After that agent is gone,
session.historyresolves presenters through the recorded preset's standing key instead. The former agent layer is absent, so a same-name preset definition wins—even though it did not execute the logged call.When the two definitions have different argument schemas, the standing definition's
defineToolwrapper soft-rejects the logged arguments before its presenter runs. The result falls back to a generic card. PersistedpresentationMetacannot help because the registry chooses the wrong definition first.This means a scoped shadow tool can render correctly live but lose its result card after restart/cold history.
Concrete downstream case
dsh-better-editissue #25 asks why its hash-anchorededitresults never render as diff cards.The plugin is mounted on the host plane and, at
agent/session-start, registers itseditonagent.ctx, intentionally shadowing the preset's built-inedit(install, registration). Its arguments are{ path, edits }; the built-in edit expects{ file_path, old_string, new_string }.I implemented the apparent fix locally: structured canonical output carrying diff data,
output.presentationMeta, defensive metadata narrowing, andpresentResult. Live presentation and JSON-round-tripped metadata worked, and 679 tests passed. A separate registry/history review found the cold-path failure, so I did not publish that patch as a PR.Cold replay does this:
editat the preset standing key.{ path, edits }against the built-in schema.The correct diff metadata is present but never reaches the presenter that understands it.
Source path
Current master inspected at
b150a551b8d465e31e418e1b2eaf5e79bbb7d28e:ToolRuntime.register()stores the whole definition in the caller's layer; same-layer duplicates fail.ToolRuntime.get(name, scope)returns the nearest visible same-name definition.viewFor()selects that definition by logged name before invokingpresentCall/presentResult.agentPresets.standingKeyFor(...), without resuming an agent.The individual pieces are internally consistent, but the log stores only the tool name/arguments/result metadata—not the identity of the scoped definition/presenter that produced them.
Why the plugin cannot repair this cleanly
editpresenter/definition loses to the preset's nearer built-inedit.editin the standing layer collides with the built-in definition.There is currently no presenter-only registry or supported arbitrary-scope presentation overlay.
Minimal regression
editon a preset standing scope.editdefinition on a child live-agent scope, with incompatible arguments and a diff presenter.card: "diff".sessions.historyfor the same log.A sibling preset that never installed the shadow should continue resolving the official edit presenter.
Possible provider-neutral seams
Either of these would make the invariant representable without restoring execution authority:
presentationKey/definition identity recorded with tool events plus a separate registry of pure presenters. Cold history resolves by that key; unknown or obsolete keys fall back generically.ToolEventViewat execution time and let history replay it after validating the view schema.The first keeps current presenters reusable and versionable; the second makes historical rendering independent of current composition. In either design, the presentation identity must not grant tool execution, metadata remains untrusted/validated, and failure should retain today's generic fallback.
Environment
0.1.0-rc.6contracts.b150a551b8d465e31e418e1b2eaf5e79bbb7d28e.All reactions