@ggui-ai/mcp-server 0.2.0-alpha.4 → 0.4.0-rc.0
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.
- package/dist/admin-blueprints-transport.d.ts.map +1 -1
- package/dist/admin-blueprints-transport.js +2 -1
- package/dist/admin-oauth-providers-transport.d.ts.map +1 -1
- package/dist/admin-oauth-providers-transport.js +7 -5
- package/dist/api-renders-routes.d.ts +85 -0
- package/dist/api-renders-routes.d.ts.map +1 -0
- package/dist/api-renders-routes.js +372 -0
- package/dist/build-mcp.d.ts +2 -2
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +64 -5
- package/dist/code-routes.d.ts +47 -0
- package/dist/code-routes.d.ts.map +1 -0
- package/dist/code-routes.js +81 -0
- package/dist/code-store-fs.js +2 -2
- package/dist/console-auth.d.ts +10 -10
- package/dist/console-auth.d.ts.map +1 -1
- package/dist/console-auth.js +5 -5
- package/dist/console-blueprint-routes.d.ts +71 -0
- package/dist/console-blueprint-routes.d.ts.map +1 -0
- package/dist/console-blueprint-routes.js +348 -0
- package/dist/console-chat-routes.d.ts +80 -0
- package/dist/console-chat-routes.d.ts.map +1 -0
- package/dist/console-chat-routes.js +204 -0
- package/dist/console-config-routes.d.ts +37 -0
- package/dist/console-config-routes.d.ts.map +1 -0
- package/dist/console-config-routes.js +91 -0
- package/dist/console-headers.d.ts +1 -1
- package/dist/console-info-routes.d.ts +84 -0
- package/dist/console-info-routes.d.ts.map +1 -0
- package/dist/console-info-routes.js +135 -0
- package/dist/console-keys-routes.d.ts +50 -0
- package/dist/console-keys-routes.d.ts.map +1 -0
- package/dist/console-keys-routes.js +222 -0
- package/dist/console-llm-keys-routes.d.ts +47 -0
- package/dist/console-llm-keys-routes.d.ts.map +1 -0
- package/dist/console-llm-keys-routes.js +443 -0
- package/dist/console-mcp-tools-routes.d.ts +41 -0
- package/dist/console-mcp-tools-routes.d.ts.map +1 -0
- package/dist/console-mcp-tools-routes.js +60 -0
- package/dist/console-registry-routes.d.ts +66 -0
- package/dist/console-registry-routes.d.ts.map +1 -0
- package/dist/console-registry-routes.js +276 -0
- package/dist/console-session-routes.d.ts +89 -0
- package/dist/console-session-routes.d.ts.map +1 -0
- package/dist/console-session-routes.js +385 -0
- package/dist/console-sessions-routes.d.ts +52 -0
- package/dist/console-sessions-routes.d.ts.map +1 -0
- package/dist/console-sessions-routes.js +106 -0
- package/dist/console-static-routes.d.ts +54 -0
- package/dist/console-static-routes.d.ts.map +1 -0
- package/dist/console-static-routes.js +190 -0
- package/dist/console-theme-routes.d.ts +3 -3
- package/dist/console-theme-routes.js +1 -1
- package/dist/console-timeline.d.ts +5 -5
- package/dist/console-timeline.d.ts.map +1 -1
- package/dist/console-timeline.js +27 -26
- package/dist/console-welcome.js +2 -2
- package/dist/email-login.d.ts.map +1 -1
- package/dist/email-login.js +2 -3
- package/dist/ggui-session-channel/action-ingress.d.ts +54 -0
- package/dist/ggui-session-channel/action-ingress.d.ts.map +1 -0
- package/dist/ggui-session-channel/action-ingress.js +228 -0
- package/dist/ggui-session-channel/channel-subscriptions.d.ts +97 -0
- package/dist/ggui-session-channel/channel-subscriptions.d.ts.map +1 -0
- package/dist/ggui-session-channel/channel-subscriptions.js +224 -0
- package/dist/ggui-session-channel/internal-types.d.ts +102 -0
- package/dist/ggui-session-channel/internal-types.d.ts.map +1 -0
- package/dist/ggui-session-channel/internal-types.js +6 -0
- package/dist/ggui-session-channel/outbound.d.ts +81 -0
- package/dist/ggui-session-channel/outbound.d.ts.map +1 -0
- package/dist/ggui-session-channel/outbound.js +174 -0
- package/dist/ggui-session-channel/socket-router.d.ts +38 -0
- package/dist/ggui-session-channel/socket-router.d.ts.map +1 -0
- package/dist/ggui-session-channel/socket-router.js +213 -0
- package/dist/ggui-session-channel/subscribe.d.ts +165 -0
- package/dist/ggui-session-channel/subscribe.d.ts.map +1 -0
- package/dist/ggui-session-channel/subscribe.js +370 -0
- package/dist/ggui-session-channel/subscriber-lifecycle.d.ts +40 -0
- package/dist/ggui-session-channel/subscriber-lifecycle.d.ts.map +1 -0
- package/dist/ggui-session-channel/subscriber-lifecycle.js +123 -0
- package/dist/ggui-session-channel.d.ts +425 -0
- package/dist/ggui-session-channel.d.ts.map +1 -0
- package/dist/ggui-session-channel.js +262 -0
- package/dist/health-routes.d.ts +76 -0
- package/dist/health-routes.d.ts.map +1 -0
- package/dist/health-routes.js +145 -0
- package/dist/index.d.ts +10 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -9
- package/dist/instructions-presets.d.ts +3 -3
- package/dist/instructions-presets.js +24 -24
- package/dist/llm-backed-negotiator.d.ts +68 -67
- package/dist/llm-backed-negotiator.d.ts.map +1 -1
- package/dist/llm-backed-negotiator.js +82 -221
- package/dist/mcp-apps-outbound.d.ts +47 -48
- package/dist/mcp-apps-outbound.d.ts.map +1 -1
- package/dist/mcp-apps-outbound.js +154 -177
- package/dist/mcp-endpoint-routes.d.ts +88 -0
- package/dist/mcp-endpoint-routes.d.ts.map +1 -0
- package/dist/mcp-endpoint-routes.js +359 -0
- package/dist/mcp-mounts.d.ts +2 -76
- package/dist/mcp-mounts.d.ts.map +1 -1
- package/dist/mcp-mounts.js +0 -76
- package/dist/oauth-as-routes.d.ts +60 -0
- package/dist/oauth-as-routes.d.ts.map +1 -0
- package/dist/oauth-as-routes.js +82 -0
- package/dist/oauth-clients-routes.d.ts +39 -0
- package/dist/oauth-clients-routes.d.ts.map +1 -0
- package/dist/oauth-clients-routes.js +87 -0
- package/dist/oauth-login-types.d.ts +1 -20
- package/dist/oauth-login-types.d.ts.map +1 -1
- package/dist/oauth-login-types.js +30 -7
- package/dist/oauth-login.d.ts.map +1 -1
- package/dist/oauth-login.js +3 -2
- package/dist/oauth-providers-store.d.ts.map +1 -1
- package/dist/oauth-providers-store.js +5 -5
- package/dist/oauth.d.ts +9 -8
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +41 -19
- package/dist/pairing-transport.d.ts.map +1 -1
- package/dist/pairing-transport.js +2 -1
- package/dist/request-context.d.ts +2 -2
- package/dist/request-context.js +2 -2
- package/dist/reserved-validators.d.ts.map +1 -1
- package/dist/reserved-validators.js +9 -1
- package/dist/route-param.d.ts +9 -0
- package/dist/route-param.d.ts.map +1 -0
- package/dist/route-param.js +10 -0
- package/dist/runtime-bundle-route.d.ts +43 -0
- package/dist/runtime-bundle-route.d.ts.map +1 -0
- package/dist/runtime-bundle-route.js +80 -0
- package/dist/schema-compat.d.ts +64 -62
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +23 -51
- package/dist/server.d.ts +179 -193
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +644 -3759
- package/dist/storage.d.ts +5 -5
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +5 -5
- package/dist/thread-transport.d.ts.map +1 -1
- package/dist/thread-transport.js +4 -3
- package/dist/user-session-auth.d.ts +7 -21
- package/dist/user-session-auth.d.ts.map +1 -1
- package/dist/user-session-auth.js +7 -28
- package/package.json +16 -15
- package/dist/mcp-apps-inbound.d.ts +0 -86
- package/dist/mcp-apps-inbound.d.ts.map +0 -1
- package/dist/mcp-apps-inbound.js +0 -283
- package/dist/render-channel.d.ts +0 -694
- package/dist/render-channel.d.ts.map +0 -1
- package/dist/render-channel.js +0 -1775
|
@@ -38,20 +38,20 @@
|
|
|
38
38
|
* already-shipped `--mcp-instructions` CLI flag and operator configs.
|
|
39
39
|
*/
|
|
40
40
|
/**
|
|
41
|
-
* Action-routing
|
|
42
|
-
* `default` by the `aggressive` and `always` presets — `default`
|
|
41
|
+
* Action-routing detail (submit_action → consume-pipe loop). Layered
|
|
42
|
+
* atop `default` by the `aggressive` and `always` presets — `default`
|
|
43
43
|
* already covers the actionSpec wire shape via the MENTAL MODEL
|
|
44
44
|
* block; this paragraph adds the host-side dispatch semantics that
|
|
45
45
|
* matter when an operator wants the LLM to also reason about how the
|
|
46
46
|
* underlying tools/call envelopes flow.
|
|
47
47
|
*/
|
|
48
|
-
const ACTION_ROUTING_PARAGRAPH = "Action routing: every actionSpec entry is a GESTURE — a discrete event the agent reacts to on its next turn. When the user interacts, the iframe relays the action through `ggui_runtime_submit_action` to the server, which appends the event onto a per-
|
|
48
|
+
const ACTION_ROUTING_PARAGRAPH = "Action routing: every actionSpec entry is a GESTURE — a discrete event the agent reacts to on its next turn. When the user interacts, the iframe relays the action through `ggui_runtime_submit_action` to the server, which appends the event onto a per-render pipe. Your `ggui_consume` long-poll unblocks mid-turn with the event payload plus a uiContext snapshot of every declared contextSpec slot. There is no synchronous server-side tool-fire — `actions drive turns` is a structural invariant (docs/principles/actions-vs-context.md): an action always waits for the agent. Cross-MCP `nextStep` hints work the same way: the agent reads the event's `actionData.nextStep`, decides whether to honor it, and calls the named tool on the next turn (the tool MAY live on a different MCP server — declare it in `agentCapabilities.tools` so the cross-ref invariant passes).";
|
|
49
49
|
/**
|
|
50
50
|
* Worked invocation example. Layered atop the `aggressive` content by
|
|
51
51
|
* `always` only — shows the literal handshake → render pattern an
|
|
52
52
|
* operator can copy.
|
|
53
53
|
*/
|
|
54
|
-
const WORKED_EXAMPLE_PARAGRAPH = "Example: ggui_handshake({ intent: 'a settings panel for notification preferences', blueprintDraft: { contract: {...}, variance: { persona: 'minimalist' } } }) returns { handshakeId: 'h_…', suggestion: { origin: 'cache' | 'agent' | 'synth', blueprintMeta: { blueprintId
|
|
54
|
+
const WORKED_EXAMPLE_PARAGRAPH = "Example: ggui_handshake({ intent: 'a settings panel for notification preferences', blueprintDraft: { contract: {...}, variance: { persona: 'minimalist' } } }) returns { handshakeId: 'h_…', suggestion: { origin: 'cache' | 'agent' | 'synth', blueprintMeta: { blueprintId?, contractHash, codeHash?, source?, variance }, amendments?, validationFindings? }, contractHash: '<hex>' }. props is REQUIRED on every render (pass props: {} when the contract declares no propsSpec). ACCEPT PATH: ggui_render({ handshakeId: 'h_…', props: {} }) — OMIT override to reuse the proposed blueprintId verbatim; response carries the minted sessionId. OVERRIDE PATH: ggui_render({ handshakeId: 'h_…', props: {}, override: { contract: { ...refined } } }) — STRICT fresh draft against override.contract (server does NOT repair). override: { variance: {...} } instead re-aims the variant (persona/aesthetic/context/seedPrompt) while keeping the agreed contract.";
|
|
55
55
|
/**
|
|
56
56
|
* The default-preset body, captured as a const so `aggressive` and
|
|
57
57
|
* `always` can layer additional paragraphs on top without diverging
|
|
@@ -68,7 +68,7 @@ const DEFAULT_PRESET_BODY = [
|
|
|
68
68
|
'',
|
|
69
69
|
' • actionSpec — client → agent (discrete events). User gestures (clicks, submits) that drive the agent\'s NEXT TURN. Each entry has a `label`, optional `schema` for the payload, and optional `nextStep: "<toolName>"`. When `nextStep` is present, it names the tool the agent SHOULD call next AND the same name MUST also appear in `agentCapabilities.tools` (cross-ref invariant; rejection code `cross_reference_unresolved`). Omit `nextStep` entirely when the agent should decide freely from broader context (open-ended form submits). e.g. a feedback form has `submit` on actionSpec with `nextStep:"record_feedback"` (and `record_feedback` listed under `agentCapabilities.tools`).',
|
|
70
70
|
'',
|
|
71
|
-
' • contextSpec — client → agent (observed state, not events). Continuous client state the agent observes — slider position, draft text, current selection. Use contextSpec when you need to KNOW the state but don\'t need to ACT on every change. On MCP Apps hosts the runtime auto-mirrors the snapshot into the host\'s widget-context surface (the agent sees it on the next turn without polling). On raw MCP clients there is no auto-mirror — call
|
|
71
|
+
' • contextSpec — client → agent (observed state, not events). Continuous client state the agent observes — slider position, draft text, current selection. Use contextSpec when you need to KNOW the state but don\'t need to ACT on every change. On MCP Apps hosts the runtime auto-mirrors the snapshot into the host\'s widget-context surface (the agent sees it on the next turn without polling). On raw MCP clients there is no auto-mirror — call ggui_get_session to read `contextSnapshot` when you need the latest values. e.g. a calendar has `selectedDate` on contextSpec.',
|
|
72
72
|
'',
|
|
73
73
|
' • streamSpec — agent → client (live updates). Live outbound channels for streaming data to the UI mid-render — chat tokens, progress events, log lines, time-series data. Each entry has a `schema` for the frame shape; you push frames via ggui_emit. e.g. a chat surface has `assistantMessage` on streamSpec for token-by-token output.',
|
|
74
74
|
'',
|
|
@@ -80,39 +80,39 @@ const DEFAULT_PRESET_BODY = [
|
|
|
80
80
|
'',
|
|
81
81
|
'TOOL PREREQUISITES (read once, internalize):',
|
|
82
82
|
' • `ggui_handshake` is a prerequisite for `ggui_render` ONLY. It returns the contract+code negotiation state (`handshakeId`) that `ggui_render` consumes. Call it BEFORE rendering a NEW UI.',
|
|
83
|
-
' • `ggui_consume` and `ggui_update` operate on EXISTING
|
|
84
|
-
' • Each `
|
|
83
|
+
' • `ggui_consume` and `ggui_update` operate on EXISTING sessions identified by `sessionId` and require NO handshake. The `sessionId` was minted by an earlier `ggui_render` call; it identifies the live iframe the user is interacting with. Calling `ggui_handshake` before `ggui_consume`/`ggui_update` is a category error — it would mint a SEPARATE new session that the user can\'t see, orphaning whichever live iframe the gesture targeted.',
|
|
84
|
+
' • Each `sessionId` is the agent\'s persistent handle to one specific live iframe. Reuse it across consume/update for as long as the user is interacting with that UI; only call `ggui_handshake` again when you need to spawn a genuinely new UI surface.',
|
|
85
85
|
'',
|
|
86
86
|
' 1. ggui_handshake — FIRST CALL for any UI. Negotiate a contract for the next render. Post {intent, blueprintDraft: {contract, variance?, generator?}}. `variance` is optional and steers cache lookup + gen by axis: `persona` ("minimalist", "playful"), `aesthetic` ("dense", "spacious"), `seedPrompt` (deterministic seed). HANDSHAKE IS FORGIVING — it ALWAYS returns a handshakeId + a CONFORMING contract, even when your draft is malformed: the server cache-matches an existing blueprint OR repairs your draft until it passes validation. The suggestion carries origin: cache (an existing blueprint matched — delivered instantly) | agent (your draft was already clean) | synth (your draft had problems and the server repaired it; `suggestion.validationFindings` lists exactly what was wrong so you learn for next time). CRITICAL: a synth result is NOT an error and NOT a request to retry — the returned contract is READY. Accept it and call ggui_render. Do NOT re-call ggui_handshake hoping for a different origin — that is a loop that wastes turns and changes nothing.',
|
|
87
87
|
'',
|
|
88
|
-
' 2. ggui_render — deliver the UI. handshakeId is REQUIRED (from step 1); calling render without it fails with `handshake_not_found`.
|
|
88
|
+
' 2. ggui_render — deliver the UI. handshakeId is REQUIRED (from step 1); calling render without it fails with `handshake_not_found`. props is ALSO REQUIRED on every call — send {handshakeId, props} (pass props: {} when the contract declares no propsSpec). OMIT `override` to use the handshake suggestion verbatim — THE NORMAL PATH, since the contract is already conforming. To commit to a FRESH draft of your own, add {handshakeId, props, override:{contract:{...}}}. OVERRIDE IS STRICT: a forced override.contract MUST already conform — the server does NOT repair it (override means "use mine exactly"). Alternatively {handshakeId, props, override:{variance:{...}}} re-aims the variant (persona/aesthetic/context/seedPrompt) while keeping the agreed contract. Prefer omitting override; override only when the suggestion genuinely is not what you want AND your replacement is correct. Response includes the minted `sessionId` — your handle for every follow-up call. Handshake records are SINGLE-USE and expire after 10 minutes. On error: `handshake_not_found` → call ggui_handshake again; `contract_violation` / `missing_props` (props don\'t match propsSpec) → fix props and retry with the SAME handshakeId; `override_contract_invalid` (your override.contract failed validation) → drop override entirely, re-run ggui_handshake with that draft (which WILL repair it), and render the suggestion — do NOT retry override with the same draft.',
|
|
89
89
|
'',
|
|
90
90
|
' 3. NEXT STEP — read the render response. If it carries a `nextStep` field, call that tool with the given args. Render only emits `nextStep` when the contract declared a non-empty actionSpec (i.e., the UI has interactive buttons/forms); in that case nextStep names ggui_consume and your job is to long-poll for the user\'s gesture. If the render response has NO nextStep, the UI is pure-display (props only, no actionSpec) — you can end your turn; the user reads the UI and types their next prompt when they\'re ready.',
|
|
91
91
|
'',
|
|
92
|
-
' 4. ggui_consume (when render said to) — long-poll for user interaction. Keyed by
|
|
92
|
+
' 4. ggui_consume (when render said to) — long-poll for user interaction. Keyed by sessionId. Blocks up to ~15 min (deployment-configurable); returns when an actionSpec event arrives or the session closes. Each return carries `{events, status}`: `events[]` is the discrete action(s) the user just took. Each event is an envelope `{intent, actionData, uiContext, actionId, firedAt}` — `actionData` is WHAT the user did (action name + validated payload, plus `nextStep` hint if the author declared one); `uiContext` is the iframe-local snapshot of every declared contextSpec slot AT THE MOMENT the action fired (form fields, selected tab, slider value, scroll position — whatever the contract declared). Both inform your reaction without a second round trip. Honor each event\'s `actionData.nextStep` hint if the tool is available, then loop back to step 1 to render the response. Continue until consume returns status:"completed" or no further follow-up is needed.',
|
|
93
93
|
'',
|
|
94
|
-
' 5. ggui_update — reflect the new state in the UI. After ANY domain-tool call whose result changed data the rendered UI displays (e.g. `todo_toggle` flips a todo\'s `done`, `cart_add_item` extends a cart, `note_save` persists text), you MUST immediately call `ggui_update` with the refreshed props so the user sees what just happened. The rendered UI does NOT auto-refresh — it only shows the props it was last given. Skipping `ggui_update` after a state-mutating tool call leaves the user staring at stale state and is the #1 wire bug. Pattern: `consume → domain-tool → ggui_update → loop to consume`. Two modes: `{
|
|
94
|
+
' 5. ggui_update — reflect the new state in the UI. After ANY domain-tool call whose result changed data the rendered UI displays (e.g. `todo_toggle` flips a todo\'s `done`, `cart_add_item` extends a cart, `note_save` persists text), you MUST immediately call `ggui_update` with the refreshed props so the user sees what just happened. The rendered UI does NOT auto-refresh — it only shows the props it was last given. Skipping `ggui_update` after a state-mutating tool call leaves the user staring at stale state and is the #1 wire bug. Pattern: `consume → domain-tool → ggui_update → loop to consume`. Two modes: `{sessionId, kind:"replace", props}` sends the FULL new props map (use when most fields changed or you want deterministic restoration); `{sessionId, kind:"merge", patch}` sends ONLY the delta as RFC 7396 JSON Merge Patch (shallow merge, recurse on nested objects, `null` deletes a key, arrays fully replace — use when most props stay the same and only one or two fields changed). Prefer `merge` after a single domain-tool mutation; prefer `replace` when restoring state or when most fields changed. The only times you skip `ggui_update` are: (a) the domain tool was pure-read (todo_list, search, etc.) AND its result wasn\'t for the UI, or (b) the contract has no propsSpec (pure-display with no mutable state).',
|
|
95
95
|
'',
|
|
96
96
|
'In short: let the protocol\'s `nextStep` fields drive routing. Every ggui_* tool whose response logically chains forwards (handshake → render → consume) emits a nextStep when there IS a next step; the absence of nextStep means "you\'re done with this thread for now."',
|
|
97
97
|
'',
|
|
98
|
-
'═══ REHYDRATED USER GESTURES (
|
|
98
|
+
'═══ REHYDRATED USER GESTURES (sessionId-carrying user messages) ═══',
|
|
99
99
|
'',
|
|
100
|
-
'When the user reloads the page after interacting with a rendered UI, the iframe re-mounts but the agent process may have lost its `ggui_consume` long-poll. Subsequent clicks in the rehydrated iframe arrive as a USER MESSAGE that carries an explicit `
|
|
100
|
+
'When the user reloads the page after interacting with a rendered UI, the iframe re-mounts but the agent process may have lost its `ggui_consume` long-poll. Subsequent clicks in the rehydrated iframe arrive as a USER MESSAGE that carries an explicit `sessionId` — either as a structured directive block (host-synthesized prefix wrapping the user prose) or as a typed slice the host passes through. EITHER WAY, the rule is the same:',
|
|
101
101
|
'',
|
|
102
|
-
' • The named `
|
|
103
|
-
' • REQUIRED first tool call: `ggui_consume({
|
|
104
|
-
' • DO NOT call `ggui_handshake` for a rehydrated-gesture message. Handshaking mints a SEPARATE new
|
|
102
|
+
' • The named `sessionId` identifies an EXISTING live iframe. Treat the message as a continuation of THAT session, not as a fresh request.',
|
|
103
|
+
' • REQUIRED first tool call: `ggui_consume({sessionId: <the-named-id>})` to drain the queued gesture. This returns the event the user fired; act on it with the appropriate domain tool, then `ggui_update({sessionId, ...})` on the SAME sessionId.',
|
|
104
|
+
' • DO NOT call `ggui_handshake` for a rehydrated-gesture message. Handshaking mints a SEPARATE new session the user can\'t see, orphaning the live iframe they actually clicked. This is the most common reload-flow regression — when in doubt and you see a `sessionId` named in the user message, your first tool call is `ggui_consume({sessionId})`, full stop.',
|
|
105
105
|
'',
|
|
106
106
|
'Worked example — user reload + click:',
|
|
107
107
|
'',
|
|
108
|
-
' 1. User reloads the page; the iframe for
|
|
108
|
+
' 1. User reloads the page; the iframe for session `s_abc123` re-mounts.',
|
|
109
109
|
' 2. User clicks "undo" in the iframe.',
|
|
110
|
-
' 3. Agent receives a user message containing `
|
|
111
|
-
' 4. Agent calls `ggui_consume({
|
|
110
|
+
' 3. Agent receives a user message containing `sessionId: s_abc123` (in a host-synthesized directive or as a structured slice).',
|
|
111
|
+
' 4. Agent calls `ggui_consume({sessionId: "s_abc123"})` — NOT `ggui_handshake`.',
|
|
112
112
|
' 5. Consume returns the click event; agent calls `todo_toggle({id: 1, done: false})`.',
|
|
113
|
-
' 6. Agent calls `ggui_update({
|
|
113
|
+
' 6. Agent calls `ggui_update({sessionId: "s_abc123", kind: "merge", patch: {todos: [...]}})`.',
|
|
114
114
|
'',
|
|
115
|
-
'The same flow applies whether the message arrives mid-conversation or as the very first turn after the user opens a saved chat URL — the
|
|
115
|
+
'The same flow applies whether the message arrives mid-conversation or as the very first turn after the user opens a saved chat URL — the sessionId is the source of truth for which iframe to address.',
|
|
116
116
|
'',
|
|
117
117
|
'═══ COMPLEMENTARY TOOLS ═══',
|
|
118
118
|
'',
|
|
@@ -120,7 +120,7 @@ const DEFAULT_PRESET_BODY = [
|
|
|
120
120
|
'',
|
|
121
121
|
' • ggui_emit — push frames to a streamSpec channel on a delivered UI. Use when the contract declared streamSpec (chat tokens, progress bars, live data). Frames must match the channel\'s declared `schema`. The live channel of the wire carries these.',
|
|
122
122
|
'',
|
|
123
|
-
' •
|
|
123
|
+
' • ggui_get_session / ggui_list_sessions — inspect current session state if you\'ve lost track of what\'s on screen. ggui_get_session returns the session including its `contextSnapshot` — the canonical way to read contextSpec values from a raw MCP client. ggui_list_sessions enumerates every session in the current host conversation (paired by `_meta["ai.ggui/host-session"]` on the inbound call).',
|
|
124
124
|
'',
|
|
125
125
|
'═══ HOST RENDERING ═══',
|
|
126
126
|
'',
|
|
@@ -157,9 +157,9 @@ export const MCP_INSTRUCTIONS_PRESETS = {
|
|
|
157
157
|
default: DEFAULT_PRESET_BODY.join('\n'),
|
|
158
158
|
/**
|
|
159
159
|
* Default protocol primer + the host-side action-routing detail
|
|
160
|
-
* (
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* (submit_action relay → per-render pipe → `ggui_consume` drain).
|
|
161
|
+
* Pick when the operator wants the LLM to also reason about how
|
|
162
|
+
* the underlying tools/call envelopes flow.
|
|
163
163
|
*/
|
|
164
164
|
aggressive: [...DEFAULT_PRESET_BODY, '', ACTION_ROUTING_PARAGRAPH].join('\n'),
|
|
165
165
|
/**
|
|
@@ -1,59 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LLM-backed `HandshakeNegotiator` for the OSS server.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `@ggui-ai/
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* vector-store wiring — those are absent on OSS by default and
|
|
10
|
-
* `negotiate()` handles missing RAG deps gracefully.
|
|
4
|
+
* A thin adapter over the SHARED handshake-decision core
|
|
5
|
+
* (`decideHandshake` in `@ggui-ai/mcp-server-handlers`). This file owns
|
|
6
|
+
* only this server's seams; the decision spine is shared verbatim
|
|
7
|
+
* across every negotiator binding of the server family — same code,
|
|
8
|
+
* different adapter.
|
|
11
9
|
*
|
|
12
|
-
* ##
|
|
10
|
+
* ## OSS adapter seams
|
|
13
11
|
*
|
|
14
|
-
*
|
|
12
|
+
* - **LLM** — `buildLlmCaller` composes BYOK credentials + a
|
|
13
|
+
* `ProviderAdapter` from `@ggui-ai/ui-gen/providers` into an
|
|
14
|
+
* `LLMCaller` (anthropic / openai / google / openrouter / bedrock).
|
|
15
|
+
* The adapter's `resolveLlm(ctx)` returns it, or `undefined` when no
|
|
16
|
+
* creds resolve (⇒ the core returns a no-LLM `create` fallback).
|
|
17
|
+
* - **Pools** — a single per-app blueprint pool from `deps.cache`
|
|
18
|
+
* (scope defaults to `ctx.appId`). Absent ⇒ no pools ⇒ synth-only.
|
|
19
|
+
* - **warn** — `console.warn` for swallowed operational errors.
|
|
15
20
|
*
|
|
16
|
-
*
|
|
17
|
-
* creds → returns a "create" result with a `no-creds` reason.
|
|
18
|
-
* 2. Selects the matching `ProviderAdapter` for the resolved
|
|
19
|
-
* provider (anthropic / openai / google / openrouter / bedrock).
|
|
20
|
-
* 3. Wraps the adapter into an `LLMCaller` (single-shot text
|
|
21
|
-
* completion).
|
|
22
|
-
* 4. Calls `negotiate(deps, input)` with `embedding: undefined,
|
|
23
|
-
* vectors: undefined` — RAG search is skipped, decision LLM
|
|
24
|
-
* runs against an empty candidate list, returns a sensible
|
|
25
|
-
* create/update decision based on session state + agent
|
|
26
|
-
* prompt.
|
|
27
|
-
* 5. Maps the `NegotiateResult` onto the OSS-shape
|
|
28
|
-
* `HandshakeNegotiatorResult`.
|
|
21
|
+
* ## Shared decision spine (in the core, not here)
|
|
29
22
|
*
|
|
30
|
-
*
|
|
23
|
+
* find-similar across pools (exact-key → coverage guard → judge →
|
|
24
|
+
* atomic reuse) ⇒ else synth-repair create via
|
|
25
|
+
* `ensureConformingContract`. Operational errors fail open; programmer
|
|
26
|
+
* errors re-throw. See `decide-handshake.ts` for the full contract.
|
|
31
27
|
*
|
|
32
|
-
*
|
|
33
|
-
* open: returns a "create" result with the error reason. Bugs
|
|
34
|
-
* (TypeError / ReferenceError / RangeError / SyntaxError) re-throw
|
|
35
|
-
* — those are programmer errors that should surface, not be
|
|
36
|
-
* silently swallowed.
|
|
28
|
+
* ## selectVariant
|
|
37
29
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* One LLM call per handshake (when creds resolve). Operators
|
|
41
|
-
* concerned about cost can either (a) skip handshake and call
|
|
42
|
-
* `ggui_render` directly with `{story}`, or (b) bind a different
|
|
43
|
-
* negotiator (e.g., the cache-backed one for read-only cache
|
|
44
|
-
* lookups) via `createGguiServer({handshake: {negotiator: ...}})`.
|
|
30
|
+
* The optional LLM-driven variant-selection seam is OSS-specific and
|
|
31
|
+
* stays on this binding (it is not part of the shared decide spine).
|
|
45
32
|
*
|
|
46
33
|
* ## Default binding
|
|
47
34
|
*
|
|
48
|
-
* Bound by default in `createGguiServer` when handshake is enabled
|
|
49
|
-
*
|
|
50
|
-
* same `negotiate()` pipeline, just with degraded RAG when local
|
|
51
|
-
* infrastructure isn't bound.
|
|
35
|
+
* Bound by default in `createGguiServer` when handshake is enabled AND a
|
|
36
|
+
* `resolveLlm` is wired into `generation`.
|
|
52
37
|
*/
|
|
53
|
-
import type { EmbeddingProvider, LlmSelection, ProviderKeyRef, VariantSelectionContext, VariantSelectionDecision, VectorStore } from "@ggui-ai/mcp-server-core";
|
|
38
|
+
import type { BlueprintIndex, EmbeddingProvider, LlmSelection, ProviderKeyRef, VariantSelectionContext, VariantSelectionDecision, VectorStore } from "@ggui-ai/mcp-server-core";
|
|
54
39
|
import type { HandlerContext } from "@ggui-ai/mcp-server-handlers";
|
|
55
|
-
import { type HandshakeNegotiator, type InstalledBlueprintsProvider } from "@ggui-ai/mcp-server-handlers/renders";
|
|
56
|
-
import {
|
|
40
|
+
import { type BlueprintPool, type HandshakeNegotiator, type InstalledBlueprintsProvider, type ToolIdentityCatalogStore } from "@ggui-ai/mcp-server-handlers/renders";
|
|
41
|
+
import type { LLMCaller } from "@ggui-ai/negotiator";
|
|
57
42
|
import type { Blueprint } from "@ggui-ai/protocol";
|
|
58
43
|
/**
|
|
59
44
|
* Wrap a resolved BYOK credential pair into an `LLMCaller` the
|
|
@@ -98,34 +83,22 @@ export interface LlmBackedHandshakeNegotiatorDeps {
|
|
|
98
83
|
providerKey: ProviderKeyRef;
|
|
99
84
|
} | null> | null;
|
|
100
85
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
*
|
|
107
|
-
* fast path. When bound, every `decide()` call first asks
|
|
108
|
-
* `matchBlueprint` whether the agent's draft canonical-key-equals
|
|
109
|
-
* an already-registered blueprint. A hit short-circuits the synth
|
|
110
|
-
* LLM round-trip and returns `origin: 'cache'` with the cached
|
|
111
|
-
* blueprint's contract + codeHash.
|
|
112
|
-
*
|
|
113
|
-
* The exact-key strategy is the only safe match when a contract is
|
|
114
|
-
* supplied (see the fuzzy-match gate in `blueprint-matcher.ts` —
|
|
115
|
-
* fuzzy matches across non-equal canonical contracts let cached
|
|
116
|
-
* call sites drift from the request's actionSpec/contextSpec wire
|
|
117
|
-
* surface).
|
|
118
|
-
* Semantic strategy fires only when contract is omitted, which the
|
|
119
|
-
* handshake input schema today disallows.
|
|
86
|
+
* Blueprint-registry deps for the handshake-time find-similar match
|
|
87
|
+
* (exact-key → coverage guard → judge). When bound, the shared
|
|
88
|
+
* `decideHandshake` core probes this registry (as a single per-app
|
|
89
|
+
* pool) before the synth path: an exact-key or semantic hit
|
|
90
|
+
* short-circuits the synth LLM round-trip and returns `origin:
|
|
91
|
+
* 'cache'` with the matched blueprint's contract + codeHash.
|
|
120
92
|
*
|
|
121
93
|
* Optional so deployments without RAG infrastructure (no embedding
|
|
122
94
|
* / vector store) continue to use the synth-only path. Mirrors the
|
|
123
|
-
* shape used by `
|
|
95
|
+
* shape used by the render handler (`render.ts`) so a single
|
|
124
96
|
* `generationWithCache.cache` value threads into both seams.
|
|
125
97
|
*/
|
|
126
98
|
cache?: {
|
|
127
99
|
readonly embedding: EmbeddingProvider;
|
|
128
100
|
readonly vectorStore: VectorStore;
|
|
101
|
+
readonly index: BlueprintIndex;
|
|
129
102
|
};
|
|
130
103
|
/**
|
|
131
104
|
* Marketplace-install bridge. When wired alongside
|
|
@@ -136,13 +109,41 @@ export interface LlmBackedHandshakeNegotiatorDeps {
|
|
|
136
109
|
* without a separate synth round-trip.
|
|
137
110
|
*/
|
|
138
111
|
installedBlueprints?: InstalledBlueprintsProvider;
|
|
112
|
+
/**
|
|
113
|
+
* Per-app tool-identity catalog store (READ side). When wired, the
|
|
114
|
+
* shared `decideHandshake` core runs `canonicalizeToolIdentity`
|
|
115
|
+
* against `catalogStore.get(ctx.appId)` BEFORE keying — rewriting each
|
|
116
|
+
* tool's `serverInfo` to the canonical identity the host runtime
|
|
117
|
+
* declared via `ggui_runtime_declare_tool_catalog`, so blueprint reuse
|
|
118
|
+
* is framework-invariant. Absent ⇒ the canonicalization step is a
|
|
119
|
+
* no-op (Tier 2). The SAME instance the declaration handler writes.
|
|
120
|
+
*/
|
|
121
|
+
catalogStore?: ToolIdentityCatalogStore;
|
|
122
|
+
/**
|
|
123
|
+
* Read-only shared/seed pools (cross-deployment reuse). Appended to
|
|
124
|
+
* adapter.pools AFTER the per-app pool, so a deployment's own
|
|
125
|
+
* blueprints win on exact-key first-match. Each is typically built by
|
|
126
|
+
* `buildSeedPool` from a distributable artifact. Absent ⇒ no shared pool.
|
|
127
|
+
*/
|
|
128
|
+
readonly seedPools?: readonly BlueprintPool[];
|
|
139
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Build the handshake pool list: the per-app pool (from `cache`) first —
|
|
132
|
+
* so a deployment's own blueprints win on exact-key first-match — then
|
|
133
|
+
* any read-only seed pools.
|
|
134
|
+
*/
|
|
135
|
+
export declare function assembleHandshakePools(deps: Pick<LlmBackedHandshakeNegotiatorDeps, 'cache' | 'installedBlueprints' | 'seedPools'>): BlueprintPool[];
|
|
140
136
|
/**
|
|
141
137
|
* Build an LLM-backed `HandshakeNegotiator` for the OSS server.
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* (
|
|
138
|
+
*
|
|
139
|
+
* Thin wrapper over the shared `decideHandshake` core
|
|
140
|
+
* (`@ggui-ai/mcp-server-handlers`): injects the OSS adapter — a BYOK
|
|
141
|
+
* LLM resolver (`resolveLlm` → `buildLlmCaller`) and a single per-app
|
|
142
|
+
* blueprint pool (`deps.cache`, scope defaults to `ctx.appId`). The
|
|
143
|
+
* decision spine (find-similar → coverage guard → judge → atomic
|
|
144
|
+
* reuse, else synth-repair create) is shared verbatim across every
|
|
145
|
+
* negotiator binding; only the injected adapter differs.
|
|
146
|
+
* `selectVariant` is specific to this binding.
|
|
146
147
|
*
|
|
147
148
|
* @public
|
|
148
149
|
*/
|
|
@@ -155,7 +156,7 @@ export declare function createLlmBackedHandshakeNegotiator(deps: LlmBackedHandsh
|
|
|
155
156
|
* token budget on the user message (candidate JSON) is more useful
|
|
156
157
|
* than verbose system framing.
|
|
157
158
|
*/
|
|
158
|
-
export declare const VARIANT_SELECTION_SYSTEM_PROMPT = "You are the variant selector for the ggui UI matcher. You receive a shortlist of pre-built UI blueprint variants and a request context. Pick the variant that best fits the request.\n\nEach variant carries:\n - blueprintId: stable identity (you MUST echo back exactly one of these).\n -
|
|
159
|
+
export declare const VARIANT_SELECTION_SYSTEM_PROMPT = "You are the variant selector for the ggui UI matcher. You receive a shortlist of pre-built UI blueprint variants and a request context. Pick the variant that best fits the request.\n\nEach variant carries:\n - blueprintId: stable identity (you MUST echo back exactly one of these).\n - source: provenance. {kind:\"llm\", generator, model} = engine-generated (advanced generators win on visual polish; default generators win on simplicity). {kind:\"user\"} = operator-registered hand-authored code. {kind:\"curated\"} = catalog-shipped system blueprint.\n - validatorScore: optional 0-1 self-assessed quality from the advanced generator's validators. Higher is better, undefined \u21D2 unknown.\n - isOperatorDefault: true \u21D2 the human operator pinned this as the default. Strong signal.\n - variance.persona: free-form tag (\"minimalist\", \"data-dense\", \"mobile-first\"\u2026).\n - variance.aesthetic: optional free-form tag (\"glassy\", \"flat\", \"editorial\"\u2026).\n - variance.context: small structured signal (theme, accent, \u2026).\n - variance.seedPrompt: the operator's original prose that produced this variant.\n\nThe request context carries the same fields. Match on:\n 1. variance.persona equality / closeness (strongest non-pin signal).\n 2. variance.aesthetic equality / closeness.\n 3. variance.context overlap (shared keys + values).\n 4. seedPrompt semantic similarity to context.intent.\n\nHonor operator pins (isOperatorDefault: true) unless variance.persona / variance.aesthetic on the request clearly contradicts the pinned variant \u2014 that's the only case where you should override the pin.\n\nCalibrate confidence honestly. Return high (\u2265 0.7) only when a clear best match exists. Return low (< 0.6) when signals are weak \u2014 the orchestration falls back to a deterministic ladder in that case. The fallback is safe; over-confident picks are NOT.";
|
|
159
160
|
/**
|
|
160
161
|
* Build the user-message payload for the variant-selection prompt.
|
|
161
162
|
* The candidate list is projected to a compact JSON shape that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-backed-negotiator.d.ts","sourceRoot":"","sources":["../src/llm-backed-negotiator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"llm-backed-negotiator.d.ts","sourceRoot":"","sources":["../src/llm-backed-negotiator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAEjB,YAAY,EACZ,cAAc,EACd,uBAAuB,EACvB,wBAAwB,EACxB,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAEL,KAAK,aAAa,EAElB,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC9B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,GAAG,SAAS,CAmD9F;AA6ED;;;GAGG;AACH,MAAM,WAAW,gCAAgC;IAC/C;;;;;;OAMG;IACH,UAAU,EAAE,CACV,GAAG,EAAE,cAAc,KAEjB;QAAE,SAAS,EAAE,YAAY,CAAC;QAAC,WAAW,EAAE,cAAc,CAAA;KAAE,GACxD,OAAO,CAAC;QAAE,SAAS,EAAE,YAAY,CAAC;QAAC,WAAW,EAAE,cAAc,CAAA;KAAE,GAAG,IAAI,CAAC,GACxE,IAAI,CAAC;IACT;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE;QACN,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;QACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;QAClC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;KAChC,CAAC;IACF;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,2BAA2B,CAAC;IAClD;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,CAAC,gCAAgC,EAAE,OAAO,GAAG,qBAAqB,GAAG,WAAW,CAAC,GAC1F,aAAa,EAAE,CAQjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,gCAAgC,GACrC,mBAAmB,CA6DrB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,m3DAoBgN,CAAC;AAqC7P;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,SAAS,SAAS,EAAE,EAChC,OAAO,EAAE,uBAAuB,GAC/B,MAAM,CA2CR;AA8CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,OAAO,GAAG,wBAAwB,CAyBpF"}
|