super-dsh 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/agent-agy/bridge/agy_bridge.py +250 -0
  2. package/agent-agy/bridge/gemini_openai_server.mjs +98 -0
  3. package/agent-agy/cordis.patch.yml +49 -0
  4. package/agent-agy/dist/adapter.d.ts +15 -0
  5. package/agent-agy/dist/adapter.js +42 -0
  6. package/agent-agy/dist/agent-preset-agy.d.ts +47 -0
  7. package/agent-agy/dist/agent-preset-agy.js +169 -0
  8. package/agent-agy/dist/agent-preset-projection.d.ts +31 -0
  9. package/agent-agy/dist/agent-preset-projection.js +33 -0
  10. package/agent-agy/dist/agent.d.ts +137 -0
  11. package/agent-agy/dist/agent.js +493 -0
  12. package/agent-agy/dist/agy-cli-client.d.ts +137 -0
  13. package/agent-agy/dist/agy-cli-client.js +301 -0
  14. package/agent-agy/dist/agy-client.d.ts +160 -0
  15. package/agent-agy/dist/agy-client.js +252 -0
  16. package/agent-agy/dist/agy-sessions.d.ts +24 -0
  17. package/agent-agy/dist/agy-sessions.js +116 -0
  18. package/agent-agy/dist/agy-store.d.ts +39 -0
  19. package/agent-agy/dist/agy-store.js +83 -0
  20. package/agent-agy/dist/inbox.d.ts +26 -0
  21. package/agent-agy/dist/inbox.js +53 -0
  22. package/agent-agy/dist/index.d.ts +80 -0
  23. package/agent-agy/dist/index.js +505 -0
  24. package/agent-agy/dist/models.d.ts +41 -0
  25. package/agent-agy/dist/models.js +74 -0
  26. package/agent-agy/dist/world-plugin.d.ts +9 -0
  27. package/agent-agy/dist/world-plugin.js +97 -0
  28. package/agent-agy/package.json +64 -0
  29. package/agent-claude/cordis.patch.yml +42 -0
  30. package/agent-claude/dist/adapter.js +62 -0
  31. package/agent-claude/dist/agent-preset-claude.js +169 -0
  32. package/agent-claude/dist/agent-preset-projection.js +30 -0
  33. package/agent-claude/dist/agent.js +1271 -0
  34. package/agent-claude/dist/claude-client.js +357 -0
  35. package/agent-claude/dist/claude-events.js +223 -0
  36. package/agent-claude/dist/claude-home.js +29 -0
  37. package/agent-claude/dist/commands.js +182 -0
  38. package/agent-claude/dist/content.js +134 -0
  39. package/agent-claude/dist/inbox.js +53 -0
  40. package/agent-claude/dist/index.js +555 -0
  41. package/agent-claude/dist/input-queue.js +64 -0
  42. package/agent-claude/dist/interaction.js +271 -0
  43. package/agent-claude/dist/models.js +158 -0
  44. package/agent-claude/dist/permission.js +120 -0
  45. package/agent-claude/dist/session-id.js +20 -0
  46. package/agent-claude/dist/session-map.js +165 -0
  47. package/agent-claude/dist/world-plugin.js +14 -0
  48. package/agent-claude/package.json +74 -0
  49. package/agent-codex/README.md +74 -0
  50. package/agent-codex/cordis.patch.yml +77 -0
  51. package/agent-codex/dist/adapter.js +55 -0
  52. package/agent-codex/dist/agent-preset-codex.js +171 -0
  53. package/agent-codex/dist/agent-preset-projection.js +37 -0
  54. package/agent-codex/dist/agent.js +1056 -0
  55. package/agent-codex/dist/app-home.js +65 -0
  56. package/agent-codex/dist/codex-client.js +469 -0
  57. package/agent-codex/dist/codex-events.js +297 -0
  58. package/agent-codex/dist/codex-store.js +190 -0
  59. package/agent-codex/dist/inbox.js +53 -0
  60. package/agent-codex/dist/index.js +605 -0
  61. package/agent-codex/dist/models.js +152 -0
  62. package/agent-codex/dist/permission.js +71 -0
  63. package/agent-codex/dist/session-map.js +170 -0
  64. package/agent-codex/dist/spike.js +46 -0
  65. package/agent-codex/dist/world-plugin.js +96 -0
  66. package/agent-codex/package.json +78 -0
  67. package/agent-hermes/README.md +144 -0
  68. package/agent-hermes/cordis.patch.yml +83 -0
  69. package/agent-hermes/dist/adapter.js +83 -0
  70. package/agent-hermes/dist/agent-preset-hermes.js +171 -0
  71. package/agent-hermes/dist/agent-preset-projection.js +34 -0
  72. package/agent-hermes/dist/agent.js +1068 -0
  73. package/agent-hermes/dist/hermes-client.js +953 -0
  74. package/agent-hermes/dist/hermes-events.js +289 -0
  75. package/agent-hermes/dist/hermes-store.js +158 -0
  76. package/agent-hermes/dist/inbox.js +53 -0
  77. package/agent-hermes/dist/index.js +541 -0
  78. package/agent-hermes/dist/models.js +324 -0
  79. package/agent-hermes/dist/permission.js +60 -0
  80. package/agent-hermes/dist/world-plugin.js +101 -0
  81. package/agent-hermes/package.json +76 -0
  82. package/agent-hub/cordis.patch.yml +12 -0
  83. package/agent-hub/dist/agent-roster.d.ts +34 -0
  84. package/agent-hub/dist/agent-roster.js +27 -0
  85. package/agent-hub/dist/carrier.d.ts +43 -0
  86. package/agent-hub/dist/carrier.js +241 -0
  87. package/agent-hub/dist/client-shim.d.ts +28 -0
  88. package/agent-hub/dist/client-shim.js +251 -0
  89. package/agent-hub/dist/envelope.d.ts +54 -0
  90. package/agent-hub/dist/envelope.js +92 -0
  91. package/agent-hub/dist/gateway.d.ts +28 -0
  92. package/agent-hub/dist/gateway.js +18 -0
  93. package/agent-hub/dist/index-pass.d.ts +22 -0
  94. package/agent-hub/dist/index-pass.js +47 -0
  95. package/agent-hub/dist/index.d.ts +29 -0
  96. package/agent-hub/dist/index.js +29 -0
  97. package/agent-hub/dist/labels.d.ts +45 -0
  98. package/agent-hub/dist/labels.js +83 -0
  99. package/agent-hub/dist/ownership.d.ts +37 -0
  100. package/agent-hub/dist/ownership.js +54 -0
  101. package/agent-hub/dist/roster.d.ts +28 -0
  102. package/agent-hub/dist/roster.js +38 -0
  103. package/agent-hub/dist/rpc.d.ts +38 -0
  104. package/agent-hub/dist/rpc.js +52 -0
  105. package/agent-hub/dist/spawn-world.d.ts +46 -0
  106. package/agent-hub/dist/spawn-world.js +72 -0
  107. package/agent-hub/dist/targets.d.ts +33 -0
  108. package/agent-hub/dist/targets.js +30 -0
  109. package/agent-hub/dist/world-entry.d.ts +31 -0
  110. package/agent-hub/dist/world-entry.js +51 -0
  111. package/agent-hub/dist/world-host.d.ts +69 -0
  112. package/agent-hub/dist/world-host.js +44 -0
  113. package/agent-hub/dist/world-join.d.ts +16 -0
  114. package/agent-hub/dist/world-join.js +122 -0
  115. package/agent-hub/dist/world-mount.d.ts +52 -0
  116. package/agent-hub/dist/world-mount.js +52 -0
  117. package/agent-hub/dist/world-mux.d.ts +72 -0
  118. package/agent-hub/dist/world-mux.js +224 -0
  119. package/agent-hub/dist/world-provision.d.ts +20 -0
  120. package/agent-hub/dist/world-provision.js +122 -0
  121. package/agent-hub/dist/world-web-server.d.ts +162 -0
  122. package/agent-hub/dist/world-web-server.js +248 -0
  123. package/agent-hub/lib/client/index.js +242 -0
  124. package/agent-hub/package.json +65 -0
  125. package/agent-omp/README.md +77 -0
  126. package/agent-omp/cordis.patch.yml +92 -0
  127. package/agent-omp/dist/adapter.js +36 -0
  128. package/agent-omp/dist/agent-preset-omp.js +171 -0
  129. package/agent-omp/dist/agent-preset-projection.js +36 -0
  130. package/agent-omp/dist/agent.js +1145 -0
  131. package/agent-omp/dist/app-home.js +86 -0
  132. package/agent-omp/dist/discovery.js +116 -0
  133. package/agent-omp/dist/inbox.js +53 -0
  134. package/agent-omp/dist/index.js +574 -0
  135. package/agent-omp/dist/knobs.js +50 -0
  136. package/agent-omp/dist/lazy-rpc.js +161 -0
  137. package/agent-omp/dist/mobile/gesture.js +148 -0
  138. package/agent-omp/dist/mobile/zoom-guard.js +294 -0
  139. package/agent-omp/dist/mobile-boot.js +38 -0
  140. package/agent-omp/dist/models.js +299 -0
  141. package/agent-omp/dist/omp-cli.js +147 -0
  142. package/agent-omp/dist/omp-disk-discovery.js +178 -0
  143. package/agent-omp/dist/omp-store.js +518 -0
  144. package/agent-omp/dist/pairing.js +45 -0
  145. package/agent-omp/dist/permission.js +96 -0
  146. package/agent-omp/dist/protocol.js +13 -0
  147. package/agent-omp/dist/rpc-types.js +1 -0
  148. package/agent-omp/dist/sdk-client.js +378 -0
  149. package/agent-omp/dist/sidecar-client.js +195 -0
  150. package/agent-omp/dist/store/adapter.js +47 -0
  151. package/agent-omp/dist/store/db.js +210 -0
  152. package/agent-omp/dist/store/index.js +59 -0
  153. package/agent-omp/dist/store/reconcile.js +51 -0
  154. package/agent-omp/dist/store/schema.js +40 -0
  155. package/agent-omp/dist/world-plugin.js +96 -0
  156. package/agent-omp/package.json +97 -0
  157. package/agent-omp/sidecar/main.ts +481 -0
  158. package/agent-pi/README.md +67 -0
  159. package/agent-pi/cordis.patch.yml +80 -0
  160. package/agent-pi/dist/adapter.js +53 -0
  161. package/agent-pi/dist/agent-preset-pi.js +169 -0
  162. package/agent-pi/dist/agent-preset-projection.js +29 -0
  163. package/agent-pi/dist/agent.js +949 -0
  164. package/agent-pi/dist/inbox.js +53 -0
  165. package/agent-pi/dist/index.js +595 -0
  166. package/agent-pi/dist/knobs.js +24 -0
  167. package/agent-pi/dist/models.js +200 -0
  168. package/agent-pi/dist/permission.js +66 -0
  169. package/agent-pi/dist/pi-client.js +224 -0
  170. package/agent-pi/dist/pi-events.js +155 -0
  171. package/agent-pi/dist/pi-home.js +55 -0
  172. package/agent-pi/dist/safe-json.js +25 -0
  173. package/agent-pi/dist/session-map.js +119 -0
  174. package/agent-pi/dist/world-plugin.js +97 -0
  175. package/agent-pi/package.json +77 -0
  176. package/cordis.patch.yml +22 -19
  177. package/package.json +88 -25
  178. package/client.js +0 -4
@@ -0,0 +1,144 @@
1
+ # @pgmi-builds/agent-adapter-hermes
2
+
3
+ Hermes provider for DeepSeek Harness (dsh) — an AgentFactory that embeds the
4
+ Nous Research Hermes Agent via the TUI gateway JSON-RPC (`python -m
5
+ tui_gateway.entry`) and bridges its session surface into Dash Agent/Session
6
+ contracts (Agent Worlds AW-H; parity round 2026-09-17 = Task M1 of
7
+ `docs/superpowers/plans/2026-09-17-aw-five-adapter-parity-fixes.md`).
8
+
9
+ ## Layout
10
+
11
+ - `src/models.ts` — gateway `model.options` → Dash model catalog (trim rules,
12
+ r4 id dedupe, provider-name cache, slug list). Pure + fail-soft.
13
+ - `src/adapter.ts` — `HermesLlmAdapter`: one route per real gateway provider
14
+ slug; `providerInfo` display names; ids stay verbatim selection strings.
15
+ - `src/index.ts` — `HermesProvider` (AgentFactory): creation transaction,
16
+ boot route registration + atomic swap, default-model push, session map.
17
+ - `src/agent.ts` — `HermesAgent`: wire→DSH event bridge, usage conversion,
18
+ turn-error classification, resume self-heal, title/todo mirroring.
19
+ - `src/hermes-events.ts` — PURE gateway-event → omp-wire projector.
20
+ - `src/hermes-client.ts` — one client = one gateway child = one session
21
+ (spawn/env/ready/turn-settle/approval bridge; liveness getters; adoption
22
+ listener; opt-in idle-probe reaper).
23
+ - `src/hermes-store.ts` — `<dshHome>/agents/hermes/dsh-sessions.json` map.
24
+ - `test/` — imports `dist/`; build first (`npm run build`), then
25
+ `node --test test/*.test.mjs`. The world-plugin smoke needs the repo farm:
26
+ run with `DSH_HOME=<repo>/.tests` (it refuses prod homes).
27
+
28
+ ## Per-adapter rulings (2026-09-17 M1; recorded per dev-rules §4/§12)
29
+
30
+ 1. **Model grouping by real provider slug** (RC-3 fix). Boot registers the
31
+ single placeholder route `hermes` (the selector stays alive while the async
32
+ probe runs); when the first `model.options` probe resolves, the
33
+ registration atomically swaps to the DISTINCT surviving provider slugs
34
+ (`AdapterRegistrationHandle.replace` — validated in full, one synchronous
35
+ section). `listModels(provider)` filters by the entry's own `provider`;
36
+ `resolveModel` matches the (provider, id) pair. Model ids are NEVER
37
+ reformatted: they are the gateway's verbatim selection strings
38
+ (`session.create {model}` / `/model <id>` consume them as-is — wire
39
+ contract). The default-model push and the per-session route pin
40
+ (`model/selection`, `request/context`) carry `{provider: slug, model: id}`,
41
+ canonicalized through the catalog entry (the r4 dedupe gives every id ONE
42
+ provider route, so a pinned route always resolves).
43
+ 2. **Catalog trims** (the "579-model wall" fix), applied at mapping time in
44
+ `mapHermesModelOptions`:
45
+ - `source: "virtual"` rows drop (the `moa` synthesizer is not a selectable
46
+ endpoint);
47
+ - mirrored endpoints with IDENTICAL model-id sets collapse onto one row —
48
+ first in gateway order wins, except a later `is_current` mirror displaces
49
+ a non-current winner (fixture: `copilot`/`copilot-acp`,
50
+ `zai-plan`/`zhipu`; 17 providers → 14 groups, 579 → 526 listed ids);
51
+ - endpoints with MORE than 50 models reorder `featured_models` first
52
+ (gateway order), remainder alphabetically; smaller rows keep gateway
53
+ order (the 47-model openrouter row is untouched).
54
+ The `authenticated !== true` filter predates this ruling and is unchanged.
55
+ 3. **Cross-provider id dedupe stays (r4)**: an id listed under several slugs
56
+ keeps ONE canonical route (first surviving row, current-row preferred).
57
+ Rationale: the wire sends only the model id, so a duplicate listing would
58
+ fabricate provider-specific selection the gateway cannot honor; canonical
59
+ routes keep every pinned route resolvable. Consequence: multi-homed ids
60
+ (e.g. `kimi-k3` under copilot/qwen-cn/kimi-cn) list under their canonical
61
+ route only.
62
+ 4. **`todo/write`** (typed transcript): the gateway's whole-list
63
+ `todo.updated {todos, revision}` snapshot → wire `todo_updated` (projector;
64
+ DSH-shaped items: trimmed content, status ∈ {pending, in_progress,
65
+ completed}; `cancelled`/unknown statuses and duplicate/blank content drop —
66
+ the DSH `todo/write` invariant has no cancelled status and forbids
67
+ repeats) → the agent appends the log-only `todo/write {todos}` snapshot,
68
+ only inside an open turn (upstream invariant), latest-wins. Log-only
69
+ semantics kept (upstream `tool-todo` contract); the todo tool pair still
70
+ renders through `tool_execution_*` as before.
71
+ 5. **`session/title` mirror**: gateway `session.title {session_id, title}` →
72
+ wire `session_title` (pi wire parity) → `session/title
73
+ {title, messageSeqs: [], source:{kind:"provider", provider:"hermes"}}`,
74
+ deduped, fail-soft, never affects the turn. The client-side `session.info`
75
+ title capture stays (feeds `session.create`'s title + tracing).
76
+ 6. **Turn usage** (RC-6 fix). Fixture verdict (`gateway-events.sample.json`
77
+ index 13): the gateway's `total` is CONTEXT-WIDE, not per-message —
78
+ `total 26805 = prompt 26803 + completion 2` and `prompt === context_used`
79
+ (the whole re-sent window), so trusting it would inflate every turn.
80
+ `convertUsage` therefore synthesizes the per-attempt-provable
81
+ `totalTokens = inputTokens + outputTokens` (fixture: 19251 + 2 = 19253),
82
+ which the DSH token-meter fold accepts (`normalizeUsage` needs `totalTokens`
83
+ or BOTH cache buckets; the gateway shape has none — the pre-fix sample
84
+ folded to `undefined` every turn). `reasoningTokens` rides only when
85
+ `reasoning ≤ output` (Dash: reasoning ⊆ output; the fold rejects larger
86
+ values). No cache tokens are invented (the gateway reports none —
87
+ `cache_hit_pct` is a percentage).
88
+ 7. **Resume self-heal over lazy spawn** (RC-4 fix, ruling 4 of the plan; full
89
+ lazy spawn deferred):
90
+ - The client exposes `usable` / `closed` / `failure` liveness getters.
91
+ - On a CLIENT-TERMINAL failure (child exit, ready timeout, close — the
92
+ client's `usable` is false) the agent's failure path — and the cold-start
93
+ path — triggers the full idle-exit dispose (`#onIdleExit`), so the host
94
+ unregisters the dead agent and re-resumes a FRESH client on the next
95
+ prompt. Ordinary per-turn failures never dispose.
96
+ - The spawn-grace reaper is now OPT-IN (`spawn({spawnGraceMs})`) and only
97
+ the self-closing catalog-probe client arms it (env
98
+ `HERMES_SPAWN_GRACE_MS`, default 10 min, `0` disables). AGENT-HELD
99
+ clients never arm it: a view-time eager resume may legitimately sit
100
+ unprompted far beyond any grace, and reaping it stamped the terminal
101
+ "hermes gateway client closed" failure that wedged every later prompt
102
+ (the reported wedge). Accepted trade-off until full lazy spawn lands: a
103
+ resumed-but-never-prompted session pins its gateway child until the host
104
+ disposes the agent (session close / owner unload).
105
+ - Turn errors are CLASSIFIED instead of a bare UNKNOWN:
106
+ `GatewayRpcError` 4001/4006 → `NATIVE_SESSION_GONE` (message names the
107
+ stored gateway session), gateway child exit/error → `GATEWAY_CRASH`,
108
+ dead client → `CLIENT_CLOSED`. The code renders in the Web UI error chip
109
+ (`turn/end {kind:"error", error:{message, code}}`).
110
+ - `stored_session_id` DRIFT tolerance: adoption
111
+ (session.create/resume response) fires the client's `onAdopted` listener;
112
+ the provider's map upsert always tracks the latest adopted pair, so a
113
+ gateway that remints the durable key on resume cannot strand future
114
+ resumes on a stale key.
115
+ 8. **Model list / switching semantics** (unchanged, recorded): selection
116
+ applies to the session's pinned route immediately (next request); a fresh
117
+ session receives the model at `session.create`. The gateway resolves its
118
+ own provider from the model id; the adapter does not second-guess it.
119
+ 9. **Homes** (dev-rules §5/§13): the Hermes runtime keeps its native
120
+ `~/.hermes` home — never redirected, never seeded. `<dshHome>/agents/hermes/`
121
+ holds only the adapter's DSH-side state (`dsh-sessions.json`).
122
+
123
+ ## Testing
124
+
125
+ ```bash
126
+ npm run build
127
+ DSH_HOME=<repo>/.tests node --test test/*.test.mjs
128
+ ```
129
+
130
+ All unit/fixture tests fake the gateway child (`setGatewayFactory`) — no real
131
+ python child in tests except the opt-in live suite
132
+ (`hermes-client.live.test.mjs`, skips without a live gateway).
133
+
134
+ ## Trap: `npm install` materializes the hub link
135
+
136
+ This package depends on `@pgmi-builds/agent-hub` via `file:../agent-hub`. A
137
+ bare `npm install` replaces the symlink with a PHYSICAL copy → a second hub
138
+ instance in the same process → every world webServer stays `pending` forever.
139
+ After any `npm install` here, re-link it:
140
+
141
+ ```bash
142
+ rm -rf node_modules/@pgmi-builds/agent-hub
143
+ ln -s ../../../../agent-worlds/agent-hub node_modules/@pgmi-builds/agent-hub
144
+ ```
@@ -0,0 +1,83 @@
1
+ # @pgmi-builds/agent-adapter-hermes bundle patch (AW-H TUI-gateway line, omp-web form).
2
+ # This file is the `dsh.bundle.patch` layer of the adapter package: when the
3
+ # hermes world profile mounts the bundle, the boot merges THIS patch — mount
4
+ # the Hermes provider plus disable the native components it replaces.
5
+ #
6
+ # Profile-specific values are deliberately NOT here: `webserver.port` (port
7
+ # choice) belongs to the world/profile patch layer (the hermes-standalone
8
+ # profile carries the 127.0.0.1:4985 listener posture).
9
+
10
+ # Mount the Hermes provider: a Cordis Service that registers an AgentFactory
11
+ # on ctx.agents. The provider drives the Hermes Agent TUI gateway (one
12
+ # spawned `python -m tui_gateway.entry` child per session, JSON-RPC) plus
13
+ # resume (dsh-sessions.json mapping, "mapping only"); the model selector is
14
+ # served by a Hermes-backed LlmAdapter publishing every model under the
15
+ # single `hermes` route (gateway model.options, TTL-cached).
16
+ - insert:
17
+ - id: hermes-provider
18
+ name: '@pgmi-builds/agent-adapter-hermes'
19
+
20
+ # Hermes owns the live agent transcript (the gateway's session state); the
21
+ # built-in loop must not double-run alongside the gateway child — the
22
+ # provider bridges turns into the DSH session log itself.
23
+ - id: agent-loop
24
+ disabled: true
25
+
26
+ # The native routes register deepseek-official / pi-ai providers; the Hermes
27
+ # provider registers its own adapter (the single `hermes` route) on ctx.llm.
28
+ # Leaving them mounted would advertise native models alongside Hermes's.
29
+ - id: llm-deepseek
30
+ disabled: true
31
+ - id: llm-pi-ai
32
+ disabled: true
33
+
34
+ # Hermes is single-mode: the gateway drives tools itself, so no Dash preset
35
+ # composition is needed (the provider ships the fixed single-preset roster).
36
+ - id: agent-presets
37
+ disabled: true
38
+
39
+ # The upstream jsonl persistence row STAYS MOUNTED (2026-09-17): the provider
40
+ # writes the DSH session log through it (create/open/append/close), and that
41
+ # log is the WebUI read surface (list/read/replay/workspace grouping are
42
+ # ordinary DSH services over it). Hermes owns the LIVE transcript in its own
43
+ # gateway — the DSH jsonl copy duplicates it by design (session storage
44
+ # duplication accepted, user ruling 2026-09-17).
45
+
46
+ # Hermes approval is RUNTIME: gateway `approval.request` events bridge into
47
+ # Dash `ctx.approval` and answers flow back via `approval.respond` (runtime
48
+ # bridge in src/permission.ts) — there is no launch-only flag to map. The
49
+ # `permission` row below therefore only fixes the DSH approval service's
50
+ # default posture (and its UI presentation); default to danger-full-access.
51
+ # Restate the full 3-preset table: a patch with only defaultPreset silently
52
+ # drops the bundle's 3-preset table to the plugin's built-in 2.
53
+ - id: permission
54
+ config:
55
+ presets:
56
+ read-only:
57
+ sandbox: read-only
58
+ approval: ask
59
+ workspace-write:
60
+ sandbox: workspace-write
61
+ approval: ask
62
+ danger-full-access:
63
+ sandbox: danger-full-access
64
+ approval: never
65
+ defaultPreset: danger-full-access
66
+
67
+ # Directory picker: the stock `directory-picker-auto` is never a simple alias —
68
+ # it RESOLVES the interaction once per boot and mounts BOTH faces through the
69
+ # loader: the host backend package AND the matching CLIENT SURFACE package
70
+ # (`dsh-client-ui-directory-picker-<kind>`). The client surface is what
71
+ # occupies the workspace picker's directory-flow hole; with the hole empty the
72
+ # client hides the "add workspace" entry entirely (WorkspacePicker: `flowAvailable
73
+ # ? [ADD_WORKSPACE] : []`). NEVER just `disabled: true` this row — that removed
74
+ # the button. Pin the in-app browser by mounting both faces of `browse`
75
+ # ourselves (backend first: the surface's browser half drives the capability the
76
+ # backend registers) and unmounting the auto row.
77
+ - insert:
78
+ - id: directory-picker-browse
79
+ name: '@deepseek-ai/dsh-host-directory-picker-browse'
80
+ - id: directory-picker-browse-surface
81
+ name: '@deepseek-ai/dsh-client-ui-directory-picker-browse'
82
+ - id: directory-picker
83
+ disabled: true
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Hermes-backed `LlmAdapter` registered on `ctx.llm` by the Hermes provider.
3
+ *
4
+ * The browser model selector never touches the Hermes agent directly: it is an
5
+ * RPC round-trip through the apiproxy, which reads `ctx.llm.listProviders /
6
+ * listModels / resolveModel` to build the catalog. This adapter answers those
7
+ * queries from the gateway's live model catalog (`models.ts`: `model.options`
8
+ * RPC, TTL-cached), one route per REAL gateway provider slug (2026-09-17
9
+ * parity ruling) — never the native deepseek-official / pi-ai routes, which
10
+ * the profile disables. The provider boots with the single placeholder route
11
+ * `hermes` and atomically swaps to the distinct slugs once the first catalog
12
+ * probe resolves (`AdapterRegistrationHandle.replace`), so the selector shows
13
+ * real groups (DeepSeek / OpenRouter / …) instead of one ~579-model bucket.
14
+ *
15
+ * The catalog is ASYNC (a gateway RPC), so the adapter is constructed with a
16
+ * `() => Promise<HermesCatalog>` supplier (the provider's memoized
17
+ * probe-client-then-close promise) instead of a home path. `providerInfo` is
18
+ * a synchronous surface, so it serves the last-known gateway row name via
19
+ * the models.ts module cache (capitalized-slug fallback before the first
20
+ * fetch); the async `listModels` / `resolveModel` await the supplier and
21
+ * filter by the entry's own `provider` slug.
22
+ *
23
+ * Model ids stay the VERBATIM gateway selection strings (`session.create
24
+ * {model}` / `/model <id>` consume them as-is); because the r4 dedupe keeps
25
+ * one canonical entry per id, `resolveModel` matches on the (provider, id)
26
+ * pair — a route only ever lists ids that resolve under it.
27
+ *
28
+ * `stream` is never dispatched: Hermes owns generation through its gateway
29
+ * child (`HermesAgent`), so the adapter only serves catalog/metadata queries.
30
+ * It throws rather than fabricating a wire route the harness would misuse.
31
+ */
32
+ import { LlmAdapter, LlmError, } from "@deepseek-ai/dsh-llm";
33
+ import { hermesProviderDisplayName } from "./models.js";
34
+ /**
35
+ * The boot placeholder route every Hermes model is served under until the
36
+ * first catalog probe resolves and the registration swaps to the real slugs.
37
+ */
38
+ export const HERMES_PROVIDER_ID = "hermes";
39
+ export class HermesLlmAdapter extends LlmAdapter {
40
+ catalog;
41
+ /**
42
+ * `catalog` = the async catalog supplier — the provider's memoized
43
+ * probe-client-then-close promise, so catalog reads never depend on
44
+ * construction-time context.
45
+ */
46
+ constructor(catalog) {
47
+ super();
48
+ this.catalog = catalog;
49
+ }
50
+ providerInfo(provider) {
51
+ // Synchronous surface: serves the last-known gateway row name (models.ts
52
+ // module cache, written on every successful fetch); capitalized-slug
53
+ // fallback before the first fetch — the placeholder `hermes` route then
54
+ // renders as "Hermes".
55
+ return { id: provider, name: hermesProviderDisplayName(provider) };
56
+ }
57
+ async listModels(provider) {
58
+ const catalog = await this.catalog();
59
+ return catalog.models
60
+ .filter((model) => model.provider === provider)
61
+ .map((model) => ({
62
+ provider,
63
+ id: model.id,
64
+ name: model.label,
65
+ }));
66
+ }
67
+ async resolveModel(provider, model) {
68
+ const catalog = await this.catalog();
69
+ const found = catalog.models.find((candidate) => candidate.id === model && candidate.provider === provider);
70
+ if (found === undefined) {
71
+ throw new LlmError(`Hermes provider "${provider}" does not serve model "${model}"`, "MODEL_NOT_FOUND");
72
+ }
73
+ return {
74
+ provider,
75
+ id: found.id,
76
+ name: found.label,
77
+ ...(found.contextWindow !== undefined && found.contextWindow > 0 ? { context: { contextWindow: found.contextWindow } } : {}),
78
+ };
79
+ }
80
+ stream(_options) {
81
+ throw new LlmError("the Hermes adapter does not stream: Hermes owns generation through its gateway agent", "UNSUPPORTED_STREAM");
82
+ }
83
+ }
@@ -0,0 +1,171 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { Remote, RemoteError, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
36
+ const HERMES_PRESET = Object.freeze({
37
+ id: "hermes",
38
+ trust: "system",
39
+ path: "",
40
+ name: "Hermes",
41
+ description: "Hermes agent via the agent-hermes adapter",
42
+ });
43
+ const COMPOSITION_TEXT = [
44
+ "# Hermes (fixed roster)",
45
+ "",
46
+ "This deployment runs exactly one agent mode: the Hermes provider bridges Dash",
47
+ "sessions to a native Hermes agent over the TUI gateway JSON-RPC. There is no",
48
+ "per-session plugin composition to configure, so this preset mounts nothing.",
49
+ "",
50
+ "rows: []",
51
+ "",
52
+ ].join("\n");
53
+ /** The standing scope key every `hermes` session reads presenters through. */
54
+ const STANDING_KEY = {};
55
+ let SingleHermesPresetRoster = (() => {
56
+ let _classSuper = TypertRemoteService;
57
+ let _instanceExtraInitializers = [];
58
+ let _remoteList_decorators;
59
+ let _remoteRead_decorators;
60
+ let _remoteCopy_decorators;
61
+ let _remoteDelete_decorators;
62
+ let _remoteSelect_decorators;
63
+ return class SingleHermesPresetRoster extends _classSuper {
64
+ static {
65
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
66
+ _remoteList_decorators = [Remote("list")];
67
+ _remoteRead_decorators = [Remote("read")];
68
+ _remoteCopy_decorators = [Remote("copy")];
69
+ _remoteDelete_decorators = [Remote("deletePreset")];
70
+ _remoteSelect_decorators = [Remote("select")];
71
+ __esDecorate(this, null, _remoteList_decorators, { kind: "method", name: "remoteList", static: false, private: false, access: { has: obj => "remoteList" in obj, get: obj => obj.remoteList }, metadata: _metadata }, null, _instanceExtraInitializers);
72
+ __esDecorate(this, null, _remoteRead_decorators, { kind: "method", name: "remoteRead", static: false, private: false, access: { has: obj => "remoteRead" in obj, get: obj => obj.remoteRead }, metadata: _metadata }, null, _instanceExtraInitializers);
73
+ __esDecorate(this, null, _remoteCopy_decorators, { kind: "method", name: "remoteCopy", static: false, private: false, access: { has: obj => "remoteCopy" in obj, get: obj => obj.remoteCopy }, metadata: _metadata }, null, _instanceExtraInitializers);
74
+ __esDecorate(this, null, _remoteDelete_decorators, { kind: "method", name: "remoteDelete", static: false, private: false, access: { has: obj => "remoteDelete" in obj, get: obj => obj.remoteDelete }, metadata: _metadata }, null, _instanceExtraInitializers);
75
+ __esDecorate(this, null, _remoteSelect_decorators, { kind: "method", name: "remoteSelect", static: false, private: false, access: { has: obj => "remoteSelect" in obj, get: obj => obj.remoteSelect }, metadata: _metadata }, null, _instanceExtraInitializers);
76
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
77
+ }
78
+ constructor(ctx) {
79
+ super(ctx, "agentPresets");
80
+ __runInitializers(this, _instanceExtraInitializers);
81
+ }
82
+ get defaultId() {
83
+ return HERMES_PRESET.id;
84
+ }
85
+ get roots() {
86
+ return [];
87
+ }
88
+ get authorable() {
89
+ return false;
90
+ }
91
+ async list() {
92
+ return [HERMES_PRESET];
93
+ }
94
+ async resolve(id) {
95
+ if (id === undefined || id === HERMES_PRESET.id)
96
+ return HERMES_PRESET;
97
+ throw new RemoteError("agent-preset/not-found", `agent-presets: preset "${id}" not found (available: hermes)`, { agentPreset: id, available: [HERMES_PRESET.id] });
98
+ }
99
+ async mount(_agentCtx, id) {
100
+ return this.resolve(id);
101
+ }
102
+ async recompose(_agentCtx, id) {
103
+ return this.resolve(id);
104
+ }
105
+ async read(id) {
106
+ await this.resolve(id);
107
+ return COMPOSITION_TEXT;
108
+ }
109
+ // ── Remote RPC surface (alpha: agentPresets routes come from @Remote) ────
110
+ // The stock dsh-host-apiproxy mapped cordis methods to routes; alpha serves
111
+ // them from @Remote decorators on a TypertRemoteService. A plain Service
112
+ // registers no routes, which is why Settings → Agent Preset 404'd.
113
+ async remoteList() {
114
+ if (process.env.HERMES_TRACE === "1")
115
+ process.stderr.write("[hermes-roster] remoteList INVOKED\n");
116
+ return {
117
+ presets: [
118
+ {
119
+ id: HERMES_PRESET.id,
120
+ trust: HERMES_PRESET.trust,
121
+ isDefault: true,
122
+ name: HERMES_PRESET.name,
123
+ description: HERMES_PRESET.description,
124
+ },
125
+ ],
126
+ authorable: this.authorable,
127
+ };
128
+ }
129
+ async remoteRead(agentPreset) {
130
+ const preset = await this.resolve(agentPreset);
131
+ return {
132
+ agentPreset: preset.id,
133
+ trust: preset.trust,
134
+ content: await this.read(preset.id),
135
+ name: preset.name,
136
+ description: preset.description,
137
+ };
138
+ }
139
+ async remoteCopy(from, id, name) {
140
+ await this.copy(from, id, name);
141
+ }
142
+ async remoteDelete(id) {
143
+ await this.remove(id);
144
+ }
145
+ /** Fixed roster: one preset, so selecting it is a no-op ack; anything else is unknown. */
146
+ async remoteSelect(agent, agentPreset) {
147
+ const preset = await this.resolve(agentPreset);
148
+ return preset.id;
149
+ }
150
+ async copy(_from, id, _name) {
151
+ throw new RemoteError("agent-preset/read-only", `agent-presets: preset "${id}" cannot be written: the Hermes roster is fixed and ships exactly one preset`, { agentPreset: id, reason: "the Hermes roster is fixed and ships exactly one preset" });
152
+ }
153
+ async remove(id) {
154
+ throw new RemoteError("agent-preset/read-only", `agent-presets: preset "${id}" cannot be written: the Hermes roster is fixed and ships exactly one preset`, { agentPreset: id, reason: "the Hermes roster is fixed and ships exactly one preset" });
155
+ }
156
+ serviceFor(_agent, _name) {
157
+ return undefined;
158
+ }
159
+ composeFrom(_agentCtx, _parentCtx) {
160
+ return undefined;
161
+ }
162
+ composedPreset(_agentCtx) {
163
+ return HERMES_PRESET.id;
164
+ }
165
+ async standingKeyFor(id) {
166
+ await this.resolve(id);
167
+ return STANDING_KEY;
168
+ }
169
+ };
170
+ })();
171
+ export { SingleHermesPresetRoster };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The `agentPreset` session projection, owned by the adapter.
3
+ *
4
+ * Upstream registers this fold from the `dsh-agent-presets` package, which our
5
+ * patch disables (the Hermes provider replaces preset composition wholesale).
6
+ * But the Web UI depends on the projection regardless: the preset hero chip
7
+ * renders only when `session.projectionValues.agentPreset` resolves
8
+ * (`presetOf` in ui-agent-preset/seat-store.ts), and the session-header label
9
+ * reads it too. Without a registrant the projection is absent for every
10
+ * adapter session and both surfaces stay blank — roster or no roster.
11
+ *
12
+ * Same fold as upstream (packages/preset/agent-presets/src/session.ts):
13
+ * initialized from the creation header, advanced by `agent-preset/selected`
14
+ * events, which this adapter synthesizes (`"hermes"`) on every session it
15
+ * prepares. Registered under the provider's own fiber via
16
+ * `ctx.inject(['sessionProjections'])`, so the key lives exactly as long as
17
+ * the provider is mounted.
18
+ */
19
+ import { z } from "zod";
20
+ const agentPresetSchema = z.union([z.string(), z.null()]);
21
+ /** Current Session preset, initialized from its header and advanced by selection events. */
22
+ export const hermesAgentPresetProjection = {
23
+ key: "agentPreset",
24
+ stateSchema: agentPresetSchema,
25
+ // adapter-hermes is single-preset: default every session to "hermes" so the
26
+ // header chip resolves for scan-native (never-resumed) sessions too,
27
+ // instead of only those whose log carries an `agent-preset/selected` event.
28
+ init: (header) => header.agentPreset ?? "hermes",
29
+ apply: (state, event) => event.type === "agent-preset/selected"
30
+ ? event.data.agentPreset
31
+ : state,
32
+ wire: { viewSchema: agentPresetSchema, view: (state) => state },
33
+ stateVersion: 1,
34
+ };