@ggui-ai/mcp-server 0.2.0-alpha.3 → 0.3.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 +1 -1
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +39 -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 +182 -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 +25 -25
- 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 -248
- 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 +204 -183
- 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
|
@@ -1,77 +1,43 @@
|
|
|
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 {
|
|
54
|
-
import {
|
|
55
|
-
import { blueprintKey } from "@ggui-ai/protocol/blueprint-key";
|
|
38
|
+
import { decideHandshake, } from "@ggui-ai/mcp-server-handlers/renders";
|
|
39
|
+
import { isRecord } from "@ggui-ai/protocol";
|
|
56
40
|
import { selectAdapter } from "@ggui-ai/ui-gen/providers";
|
|
57
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
58
|
-
/**
|
|
59
|
-
* Operational error classifier — mirrors the cloud helper. Bugs
|
|
60
|
-
* surface; provider failures + network blips degrade to a "create"
|
|
61
|
-
* stub so the agent isn't blocked by a transient infrastructure
|
|
62
|
-
* issue.
|
|
63
|
-
*/
|
|
64
|
-
function isOperationalError(err) {
|
|
65
|
-
if (err instanceof TypeError)
|
|
66
|
-
return false;
|
|
67
|
-
if (err instanceof ReferenceError)
|
|
68
|
-
return false;
|
|
69
|
-
if (err instanceof RangeError)
|
|
70
|
-
return false;
|
|
71
|
-
if (err instanceof SyntaxError)
|
|
72
|
-
return false;
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
41
|
/**
|
|
76
42
|
* Wrap a resolved BYOK credential pair into an `LLMCaller` the
|
|
77
43
|
* negotiator can call. The adapter is chosen via `selectAdapter`
|
|
@@ -194,202 +160,70 @@ async function anthropicCallStructured(args) {
|
|
|
194
160
|
}
|
|
195
161
|
return toolUse.input;
|
|
196
162
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
return {
|
|
213
|
-
action: "create",
|
|
214
|
-
reason,
|
|
215
|
-
suggestion,
|
|
216
|
-
effectiveContract: draftContract,
|
|
217
|
-
};
|
|
163
|
+
/**
|
|
164
|
+
* Build the handshake pool list: the per-app pool (from `cache`) first —
|
|
165
|
+
* so a deployment's own blueprints win on exact-key first-match — then
|
|
166
|
+
* any read-only seed pools.
|
|
167
|
+
*/
|
|
168
|
+
export function assembleHandshakePools(deps) {
|
|
169
|
+
const perAppPool = deps.cache
|
|
170
|
+
? {
|
|
171
|
+
registry: deps.cache,
|
|
172
|
+
...(deps.installedBlueprints ? { installedBlueprints: deps.installedBlueprints } : {}),
|
|
173
|
+
}
|
|
174
|
+
: undefined;
|
|
175
|
+
return [...(perAppPool ? [perAppPool] : []), ...(deps.seedPools ?? [])];
|
|
218
176
|
}
|
|
219
177
|
/**
|
|
220
178
|
* Build an LLM-backed `HandshakeNegotiator` for the OSS server.
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
* (
|
|
179
|
+
*
|
|
180
|
+
* Thin wrapper over the shared `decideHandshake` core
|
|
181
|
+
* (`@ggui-ai/mcp-server-handlers`): injects the OSS adapter — a BYOK
|
|
182
|
+
* LLM resolver (`resolveLlm` → `buildLlmCaller`) and a single per-app
|
|
183
|
+
* blueprint pool (`deps.cache`, scope defaults to `ctx.appId`). The
|
|
184
|
+
* decision spine (find-similar → coverage guard → judge → atomic
|
|
185
|
+
* reuse, else synth-repair create) is shared verbatim across every
|
|
186
|
+
* negotiator binding; only the injected adapter differs.
|
|
187
|
+
* `selectVariant` is specific to this binding.
|
|
225
188
|
*
|
|
226
189
|
* @public
|
|
227
190
|
*/
|
|
228
191
|
export function createLlmBackedHandshakeNegotiator(deps) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// componentCode hash so the paired push.accept short-circuits
|
|
239
|
-
// straight into commitCachedRender.
|
|
240
|
-
//
|
|
241
|
-
// No-match (or any throw) falls through to today's synth path
|
|
242
|
-
// — the negotiator stays useful when the registry is cold,
|
|
243
|
-
// when matchBlueprint hiccups, or when the deployment skipped
|
|
244
|
-
// the cache deps entirely.
|
|
245
|
-
if (deps.cache) {
|
|
246
|
-
try {
|
|
247
|
-
const matchDeps = {
|
|
248
|
-
registry: deps.cache,
|
|
249
|
-
...(deps.installedBlueprints ? { installedBlueprints: deps.installedBlueprints } : {}),
|
|
250
|
-
};
|
|
251
|
-
const matchResult = await matchBlueprint(matchDeps, ctx.appId, {
|
|
252
|
-
intent,
|
|
253
|
-
contract: draftContract,
|
|
254
|
-
});
|
|
255
|
-
if (matchResult.strategy === "exact-key") {
|
|
256
|
-
const matched = matchResult.blueprint;
|
|
257
|
-
const codeHash = createHash("sha256").update(matched.componentCode).digest("hex");
|
|
258
|
-
const suggestion = {
|
|
259
|
-
origin: "cache",
|
|
260
|
-
rationale: matchResult.reason,
|
|
261
|
-
blueprintMeta: {
|
|
262
|
-
blueprintId: matched.id,
|
|
263
|
-
contractHash: matched.contractKey,
|
|
264
|
-
codeHash,
|
|
265
|
-
generator: DEFAULT_GENERATOR_SLUG,
|
|
266
|
-
variance: {},
|
|
267
|
-
selectedReason: matchResult.reason,
|
|
268
|
-
},
|
|
269
|
-
};
|
|
270
|
-
return {
|
|
271
|
-
action: "reuse",
|
|
272
|
-
reason: matchResult.reason,
|
|
273
|
-
suggestion,
|
|
274
|
-
effectiveContract: matched.contract,
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
// Other strategies (no-match, semantic) fall through to
|
|
278
|
-
// the negotiate() path below. Semantic doesn't fire when
|
|
279
|
-
// a contract is supplied (the fuzzy-match gate blocks it);
|
|
280
|
-
// listing it here is structural completeness, not a
|
|
281
|
-
// reachable branch today.
|
|
282
|
-
}
|
|
283
|
-
catch (err) {
|
|
284
|
-
if (!isOperationalError(err))
|
|
285
|
-
throw err;
|
|
286
|
-
// Registry hiccup — log + fall through to synth so the
|
|
287
|
-
// handshake never crashes on a transient cache backend
|
|
288
|
-
// issue.
|
|
289
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
290
|
-
// eslint-disable-next-line no-console -- operator-visible signal
|
|
291
|
-
console.warn(`[llm-backed-negotiator] matchBlueprint exact-key probe failed; falling through to synth: ${message}`);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
192
|
+
// Capture the store so the adapter resolver closes over a concrete
|
|
193
|
+
// value (no `?.` chain inside the hot path; the spread below already
|
|
194
|
+
// gates on presence).
|
|
195
|
+
const catalogStore = deps.catalogStore;
|
|
196
|
+
const pools = assembleHandshakePools(deps);
|
|
197
|
+
const adapter = {
|
|
198
|
+
// BYOK seam: resolve per-ctx creds + wrap into an LLMCaller. No
|
|
199
|
+
// creds ⇒ undefined ⇒ the core returns a no-LLM create fallback.
|
|
200
|
+
resolveLlm: async (ctx) => {
|
|
294
201
|
const creds = await deps.resolveLlm(ctx);
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
...(declaredAgentTools.length > 0 ? { agentTools: declaredAgentTools } : {}),
|
|
306
|
-
...(gadgets !== undefined ? { gadgets } : {}),
|
|
307
|
-
},
|
|
308
|
-
config: {
|
|
309
|
-
appId: ctx.appId,
|
|
310
|
-
// Handshake runs ahead of any concrete render — no renderId
|
|
311
|
-
// is bound yet. The negotiator only uses `renderId` to key
|
|
312
|
-
// its optional `readRenderState` callback, which the OSS
|
|
313
|
-
// path doesn't wire here, so a stable placeholder works.
|
|
314
|
-
renderId: "handshake",
|
|
315
|
-
includeSharedPool: false,
|
|
316
|
-
},
|
|
317
|
-
});
|
|
318
|
-
const decision = result.decision;
|
|
319
|
-
const contract = decision.contract;
|
|
320
|
-
const contractHash = result.storedContractHash ?? blueprintKey(contract);
|
|
321
|
-
const draftHash = blueprintKey(draftContract);
|
|
322
|
-
const blueprintId = decision.blueprintId;
|
|
323
|
-
// Origin routing:
|
|
324
|
-
// - blueprintId present (cache hit) → origin: 'cache'
|
|
325
|
-
// - contract == draft → origin: 'agent'
|
|
326
|
-
// - contract != draft → origin: 'synth'
|
|
327
|
-
let suggestion;
|
|
328
|
-
if (blueprintId) {
|
|
329
|
-
suggestion = {
|
|
330
|
-
origin: "cache",
|
|
331
|
-
rationale: decision.reasoning ?? `cache match (${blueprintId})`,
|
|
332
|
-
blueprintMeta: {
|
|
333
|
-
blueprintId,
|
|
334
|
-
contractHash,
|
|
335
|
-
generator: "ui-gen-default-haiku-4-5",
|
|
336
|
-
variance: {},
|
|
337
|
-
},
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
else if (contractHash === draftHash) {
|
|
341
|
-
suggestion = {
|
|
342
|
-
origin: "agent",
|
|
343
|
-
rationale: decision.reasoning ?? "novel-but-clean contract",
|
|
344
|
-
blueprintMeta: {
|
|
345
|
-
blueprintId: `bp_${randomUUID()}`,
|
|
346
|
-
contractHash,
|
|
347
|
-
generator: "ui-gen-default-haiku-4-5",
|
|
348
|
-
variance: {},
|
|
349
|
-
},
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
else {
|
|
353
|
-
suggestion = {
|
|
354
|
-
origin: "synth",
|
|
355
|
-
rationale: decision.reasoning ?? "synth amended contract",
|
|
356
|
-
blueprintMeta: {
|
|
357
|
-
blueprintId: `bp_${randomUUID()}`,
|
|
358
|
-
contractHash,
|
|
359
|
-
generator: "ui-gen-default-haiku-4-5",
|
|
360
|
-
variance: {},
|
|
361
|
-
},
|
|
362
|
-
amendments: {
|
|
363
|
-
contractDiff: [
|
|
364
|
-
{
|
|
365
|
-
op: "replace",
|
|
366
|
-
path: "",
|
|
367
|
-
value: contract,
|
|
368
|
-
},
|
|
369
|
-
],
|
|
370
|
-
reasoning: decision.reasoning ?? "negotiator-amended contract",
|
|
371
|
-
},
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
return {
|
|
375
|
-
action: blueprintId ? "reuse" : "create",
|
|
376
|
-
reason: decision.reasoning ?? "negotiated",
|
|
377
|
-
suggestion,
|
|
378
|
-
effectiveContract: contract,
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
catch (err) {
|
|
382
|
-
if (!isOperationalError(err))
|
|
383
|
-
throw err;
|
|
384
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
385
|
-
const errorClass = err instanceof Error ? err.name : "unknown";
|
|
386
|
-
return buildCreateFallback(draftContract, `negotiator-degraded: ${errorClass} during decision LLM call — ${message}. Falling back to bare-create; the paired ggui_render will still generate the UI.`, estimatedLatencyMs);
|
|
387
|
-
}
|
|
202
|
+
return creds
|
|
203
|
+
? buildLlmCaller(creds.selection, creds.providerKey)
|
|
204
|
+
: undefined;
|
|
205
|
+
},
|
|
206
|
+
// Per-app pool first, then seed pools. No pools ⇒ the core takes
|
|
207
|
+
// the synth-only path.
|
|
208
|
+
...(pools.length > 0 ? { pools } : {}),
|
|
209
|
+
warn: (message) => {
|
|
210
|
+
// eslint-disable-next-line no-console -- operator-visible signal
|
|
211
|
+
console.warn(message);
|
|
388
212
|
},
|
|
213
|
+
// READ side of tool-identity canonicalization. When a catalog store
|
|
214
|
+
// is wired, the core resolves the per-app catalog by ctx.appId and
|
|
215
|
+
// runs canonicalizeToolIdentity before keying. Absent ⇒ the seam is
|
|
216
|
+
// a no-op (Tier 2).
|
|
217
|
+
...(catalogStore
|
|
218
|
+
? { toolIdentityCatalog: (ctx) => catalogStore.get(ctx.appId) }
|
|
219
|
+
: {}),
|
|
220
|
+
};
|
|
221
|
+
return {
|
|
222
|
+
decide: (input) => decideHandshake(adapter, input),
|
|
389
223
|
// LLM-driven variant selection. Reads each candidate's
|
|
390
224
|
// `variance` + `validatorScore` + `isOperatorDefault` + the
|
|
391
|
-
//
|
|
392
|
-
// current request's `intent` + `variance`, and returns a
|
|
225
|
+
// provenance (`source`), asks the LLM to pick the best fit for
|
|
226
|
+
// the current request's `intent` + `variance`, and returns a
|
|
393
227
|
// calibrated decision. The caller (`selectVariantWithLlm`)
|
|
394
228
|
// thresholds on `confidence`.
|
|
395
229
|
//
|
|
@@ -422,7 +256,7 @@ export const VARIANT_SELECTION_SYSTEM_PROMPT = `You are the variant selector for
|
|
|
422
256
|
|
|
423
257
|
Each variant carries:
|
|
424
258
|
- blueprintId: stable identity (you MUST echo back exactly one of these).
|
|
425
|
-
-
|
|
259
|
+
- 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.
|
|
426
260
|
- validatorScore: optional 0-1 self-assessed quality from the advanced generator's validators. Higher is better, undefined ⇒ unknown.
|
|
427
261
|
- isOperatorDefault: true ⇒ the human operator pinned this as the default. Strong signal.
|
|
428
262
|
- variance.persona: free-form tag ("minimalist", "data-dense", "mobile-first"…).
|
|
@@ -479,7 +313,7 @@ const VARIANT_SELECTION_TOOL_SCHEMA = {
|
|
|
479
313
|
export function buildVariantSelectionUserMessage(candidates, context) {
|
|
480
314
|
const projectedCandidates = candidates.map((c) => ({
|
|
481
315
|
blueprintId: c.blueprintId,
|
|
482
|
-
|
|
316
|
+
source: c.source,
|
|
483
317
|
...(c.validatorScore !== undefined ? { validatorScore: c.validatorScore } : {}),
|
|
484
318
|
...(c.isOperatorDefault === true ? { isOperatorDefault: true } : {}),
|
|
485
319
|
variance: {
|
|
@@ -557,7 +391,7 @@ async function runVariantSelectionLlm(llm, candidates, context) {
|
|
|
557
391
|
* `VariantSelectionResult.reason` for telemetry.
|
|
558
392
|
*/
|
|
559
393
|
export function parseVariantSelectionResponse(raw) {
|
|
560
|
-
if (raw
|
|
394
|
+
if (!isRecord(raw)) {
|
|
561
395
|
throw new Error("variant-selection: response is not an object");
|
|
562
396
|
}
|
|
563
397
|
const obj = raw;
|