@ggui-ai/mcp-server 0.1.0-rc.3 → 0.2.0-alpha.3
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/README.md +1 -1
- package/dist/build-mcp.d.ts +8 -8
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +53 -12
- package/dist/console-auth.d.ts +7 -7
- package/dist/console-auth.d.ts.map +1 -1
- package/dist/console-auth.js +4 -4
- package/dist/console-cache.d.ts +2 -2
- package/dist/console-cache.d.ts.map +1 -1
- package/dist/console-cache.js +10 -10
- package/dist/console-headers.d.ts +2 -2
- package/dist/console-headers.js +2 -2
- package/dist/console-payloads.d.ts +3 -3
- package/dist/console-payloads.d.ts.map +1 -1
- package/dist/console-payloads.js +10 -10
- package/dist/console-timeline.d.ts +12 -30
- package/dist/console-timeline.d.ts.map +1 -1
- package/dist/console-timeline.js +44 -45
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/instructions-presets.d.ts +1 -1
- package/dist/instructions-presets.d.ts.map +1 -1
- package/dist/instructions-presets.js +40 -22
- package/dist/llm-backed-negotiator.d.ts +6 -6
- package/dist/llm-backed-negotiator.d.ts.map +1 -1
- package/dist/llm-backed-negotiator.js +92 -91
- package/dist/mcp-apps-inbound.d.ts +3 -3
- package/dist/mcp-apps-inbound.d.ts.map +1 -1
- package/dist/mcp-apps-inbound.js +28 -23
- package/dist/mcp-apps-outbound.d.ts +136 -121
- package/dist/mcp-apps-outbound.d.ts.map +1 -1
- package/dist/mcp-apps-outbound.js +384 -414
- package/dist/mcp-mounts.d.ts +21 -20
- package/dist/mcp-mounts.d.ts.map +1 -1
- package/dist/mcp-mounts.js +25 -29
- package/dist/{session-channel.d.ts → render-channel.d.ts} +145 -102
- package/dist/render-channel.d.ts.map +1 -0
- package/dist/{session-channel.js → render-channel.js} +481 -462
- package/dist/schema-compat.d.ts +11 -11
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +6 -6
- package/dist/server.d.ts +224 -219
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1498 -1963
- package/dist/storage.d.ts +7 -7
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +12 -12
- package/package.json +12 -11
- package/dist/render-gate.d.ts +0 -87
- package/dist/render-gate.d.ts.map +0 -1
- package/dist/render-gate.js +0 -77
- package/dist/render-rate-limit.d.ts +0 -59
- package/dist/render-rate-limit.d.ts.map +0 -1
- package/dist/render-rate-limit.js +0 -73
- package/dist/render-signing.d.ts +0 -98
- package/dist/render-signing.d.ts.map +0 -1
- package/dist/render-signing.js +0 -113
- package/dist/session-channel.d.ts.map +0 -1
package/dist/console-timeline.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { applyDevtoolSecurityHeaders } from './console-headers.js';
|
|
2
2
|
/**
|
|
3
|
-
* Drain {@link
|
|
3
|
+
* Drain {@link RenderStore.observe} into an array. The observe iterator
|
|
4
4
|
* with `{ tail: false }` resolves cleanly after replaying every stored
|
|
5
5
|
* event, so this is a plain `for await`. Bound by the store's per-
|
|
6
|
-
*
|
|
6
|
+
* render retention (in-memory: full history; hosted: store-defined).
|
|
7
7
|
*/
|
|
8
|
-
async function
|
|
8
|
+
async function drainRenderEvents(renderStore, renderId) {
|
|
9
9
|
const out = [];
|
|
10
|
-
for await (const event of
|
|
10
|
+
for await (const event of renderStore.observe(renderId, {
|
|
11
11
|
fromSeq: 1,
|
|
12
12
|
tail: false,
|
|
13
13
|
})) {
|
|
@@ -21,9 +21,9 @@ async function drainSessionEvents(sessionStore, sessionId) {
|
|
|
21
21
|
* function does not re-implement auth (matches the
|
|
22
22
|
* `mountConsoleLlmTraceRoutes` shape in console-llm-trace.ts).
|
|
23
23
|
*/
|
|
24
|
-
export function mountConsoleTimelineRoutes(app,
|
|
25
|
-
// GET /ggui/console/timeline/
|
|
26
|
-
app.get('/ggui/console/timeline/
|
|
24
|
+
export function mountConsoleTimelineRoutes(app, renderStore, streamBuffer) {
|
|
25
|
+
// GET /ggui/console/timeline/renders?limit=<n>
|
|
26
|
+
app.get('/ggui/console/timeline/renders', async (req, res) => {
|
|
27
27
|
applyDevtoolSecurityHeaders(res);
|
|
28
28
|
const limitRaw = req.query['limit'];
|
|
29
29
|
let limit = 50;
|
|
@@ -34,86 +34,85 @@ export function mountConsoleTimelineRoutes(app, sessionStore, streamBuffer) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
// Zero-config shape: no store wired (pure-MCP boot) → empty list.
|
|
37
|
-
if (!
|
|
38
|
-
const body = {
|
|
37
|
+
if (!renderStore) {
|
|
38
|
+
const body = { renders: [], total: 0 };
|
|
39
39
|
res.json(body);
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
try {
|
|
43
43
|
// No status filter — operators want to debug completed +
|
|
44
|
-
// expired
|
|
44
|
+
// expired renders, not just live ones. Limit is post-filter
|
|
45
45
|
// so the response stays bounded.
|
|
46
|
-
const
|
|
46
|
+
const stored = await renderStore.list({});
|
|
47
47
|
const summaries = [];
|
|
48
48
|
const now = Date.now();
|
|
49
|
-
for (const
|
|
49
|
+
for (const row of stored) {
|
|
50
50
|
let streamSeq = 0;
|
|
51
51
|
if (streamBuffer) {
|
|
52
52
|
try {
|
|
53
|
-
streamSeq = await streamBuffer.currentSeq(
|
|
53
|
+
streamSeq = await streamBuffer.currentSeq(row.id);
|
|
54
54
|
}
|
|
55
55
|
catch {
|
|
56
56
|
// Stream-cursor lookup is best-effort metadata; an
|
|
57
57
|
// adapter error must not blank the picker.
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
// Compute status from
|
|
61
|
-
// surface its private `closed` flag
|
|
62
|
-
// We mirror the
|
|
60
|
+
// Compute status from render state (the store doesn't
|
|
61
|
+
// surface its private `closed` flag uniformly across impls).
|
|
62
|
+
// We mirror the InMemoryRenderStore's rule:
|
|
63
63
|
// expired = expiresAt <= now, otherwise active. The
|
|
64
64
|
// 'completed' state needs the closed flag to disambiguate;
|
|
65
65
|
// we report 'active' until eviction. Operators reading the
|
|
66
66
|
// detail pane get the authoritative status from the store.
|
|
67
|
-
const status =
|
|
67
|
+
const status = row.expiresAt <= now ? 'expired' : 'active';
|
|
68
68
|
summaries.push({
|
|
69
|
-
|
|
70
|
-
appId:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
lastActivityAt: session.lastActivityAt,
|
|
69
|
+
renderId: row.id,
|
|
70
|
+
appId: row.appId,
|
|
71
|
+
createdAt: row.createdAt,
|
|
72
|
+
lastActivityAt: row.lastActivityAt,
|
|
74
73
|
status,
|
|
75
74
|
streamSeq,
|
|
76
75
|
});
|
|
77
76
|
}
|
|
78
|
-
// Most-recent activity first. Tiebreak on
|
|
77
|
+
// Most-recent activity first. Tiebreak on renderId for
|
|
79
78
|
// stable ordering across reloads.
|
|
80
79
|
summaries.sort((a, b) => {
|
|
81
80
|
const byRecency = b.lastActivityAt - a.lastActivityAt;
|
|
82
81
|
if (byRecency !== 0)
|
|
83
82
|
return byRecency;
|
|
84
|
-
return a.
|
|
83
|
+
return a.renderId.localeCompare(b.renderId);
|
|
85
84
|
});
|
|
86
85
|
const trimmed = summaries.slice(0, limit);
|
|
87
86
|
const body = {
|
|
88
|
-
|
|
87
|
+
renders: trimmed,
|
|
89
88
|
total: summaries.length,
|
|
90
89
|
};
|
|
91
90
|
res.json(body);
|
|
92
91
|
}
|
|
93
92
|
catch (err) {
|
|
94
93
|
res.status(500).json({
|
|
95
|
-
error: '
|
|
94
|
+
error: 'timeline_renders_list_failed',
|
|
96
95
|
message: err instanceof Error
|
|
97
|
-
? `
|
|
98
|
-
: `
|
|
96
|
+
? `Render store failed to list — ${err.message}`
|
|
97
|
+
: `Render store failed to list — ${String(err)}`,
|
|
99
98
|
});
|
|
100
99
|
}
|
|
101
100
|
});
|
|
102
|
-
// GET /ggui/console/timeline/:
|
|
103
|
-
app.get('/ggui/console/timeline/:
|
|
101
|
+
// GET /ggui/console/timeline/:renderId/events
|
|
102
|
+
app.get('/ggui/console/timeline/:renderId/events', async (req, res) => {
|
|
104
103
|
applyDevtoolSecurityHeaders(res);
|
|
105
|
-
const
|
|
106
|
-
if (!
|
|
104
|
+
const renderId = req.params['renderId'];
|
|
105
|
+
if (!renderId || renderId.length === 0) {
|
|
107
106
|
res.status(400).json({
|
|
108
|
-
error: '
|
|
109
|
-
message: '
|
|
107
|
+
error: 'invalid_render_id',
|
|
108
|
+
message: 'renderId path parameter is required',
|
|
110
109
|
});
|
|
111
110
|
return;
|
|
112
111
|
}
|
|
113
112
|
// Zero-config shape: no store wired → empty events.
|
|
114
|
-
if (!
|
|
113
|
+
if (!renderStore) {
|
|
115
114
|
const body = {
|
|
116
|
-
|
|
115
|
+
renderId,
|
|
117
116
|
events: [],
|
|
118
117
|
streamSeq: 0,
|
|
119
118
|
status: 'unknown',
|
|
@@ -122,14 +121,14 @@ export function mountConsoleTimelineRoutes(app, sessionStore, streamBuffer) {
|
|
|
122
121
|
return;
|
|
123
122
|
}
|
|
124
123
|
try {
|
|
125
|
-
const
|
|
126
|
-
if (!
|
|
124
|
+
const stored = await renderStore.get(renderId);
|
|
125
|
+
if (!stored) {
|
|
127
126
|
// 404 is the right status — but we still return a well-
|
|
128
127
|
// formed body so the SPA can render an "expired/dropped"
|
|
129
128
|
// notice without a special-case branch. Body matches the
|
|
130
129
|
// schema; status code disambiguates.
|
|
131
130
|
const body = {
|
|
132
|
-
|
|
131
|
+
renderId,
|
|
133
132
|
events: [],
|
|
134
133
|
streamSeq: 0,
|
|
135
134
|
status: 'unknown',
|
|
@@ -137,20 +136,20 @@ export function mountConsoleTimelineRoutes(app, sessionStore, streamBuffer) {
|
|
|
137
136
|
res.status(404).json(body);
|
|
138
137
|
return;
|
|
139
138
|
}
|
|
140
|
-
const events = await
|
|
139
|
+
const events = await drainRenderEvents(renderStore, renderId);
|
|
141
140
|
let streamSeq = 0;
|
|
142
141
|
if (streamBuffer) {
|
|
143
142
|
try {
|
|
144
|
-
streamSeq = await streamBuffer.currentSeq(
|
|
143
|
+
streamSeq = await streamBuffer.currentSeq(renderId);
|
|
145
144
|
}
|
|
146
145
|
catch {
|
|
147
146
|
// Best-effort. Inbound events stand on their own.
|
|
148
147
|
}
|
|
149
148
|
}
|
|
150
149
|
const now = Date.now();
|
|
151
|
-
const status =
|
|
150
|
+
const status = stored.expiresAt <= now ? 'expired' : 'active';
|
|
152
151
|
const body = {
|
|
153
|
-
|
|
152
|
+
renderId,
|
|
154
153
|
events,
|
|
155
154
|
streamSeq,
|
|
156
155
|
status,
|
|
@@ -161,8 +160,8 @@ export function mountConsoleTimelineRoutes(app, sessionStore, streamBuffer) {
|
|
|
161
160
|
res.status(500).json({
|
|
162
161
|
error: 'timeline_events_drain_failed',
|
|
163
162
|
message: err instanceof Error
|
|
164
|
-
? `
|
|
165
|
-
: `
|
|
163
|
+
? `Render store failed to drain — ${err.message}`
|
|
164
|
+
: `Render store failed to drain — ${String(err)}`,
|
|
166
165
|
});
|
|
167
166
|
}
|
|
168
167
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
* The `ggui serve` CLI command boots this server with the OSS defaults.
|
|
27
27
|
*/
|
|
28
28
|
export type { HandlerContext, SharedHandler } from '@ggui-ai/mcp-server-handlers';
|
|
29
|
-
export type { GadgetDescriptor,
|
|
29
|
+
export type { GadgetDescriptor, McpUiDisplayMode, Render, SystemRender, } from '@ggui-ai/protocol';
|
|
30
30
|
export type { GenerationCredentials, GenerationDeps, } from '@ggui-ai/mcp-server-handlers';
|
|
31
|
-
export { NO_CREDENTIALS_SYSTEM_CARD_KIND,
|
|
31
|
+
export { NO_CREDENTIALS_SYSTEM_CARD_KIND, buildNoCredentialsRender, } from '@ggui-ai/mcp-server-handlers';
|
|
32
32
|
export { createGguiServer, defaultHandlers } from './server.js';
|
|
33
33
|
export type { CreateGguiServerOptions, GguiServer, } from './server.js';
|
|
34
34
|
export { FileSystemCodeStore } from './code-store-fs.js';
|
|
@@ -38,14 +38,14 @@ export { composeWiredActionRouterFromMounts } from './mcp-mounts.js';
|
|
|
38
38
|
export type { McpService, ServicePath } from './mcp-mounts.js';
|
|
39
39
|
export { validateMcpServices, validateServicePath } from './mcp-mounts.js';
|
|
40
40
|
export { composePreviewReservedValidator, mergeReservedValidators, } from './reserved-validators.js';
|
|
41
|
-
export {
|
|
42
|
-
export type { SchemaCompatFinding, SchemaCompatMode, SchemaCompatReport,
|
|
41
|
+
export { checkRenderSchemaCompat, DEFAULT_SCHEMA_COMPAT_MODE, SchemaCompatError, } from './schema-compat.js';
|
|
42
|
+
export type { SchemaCompatFinding, SchemaCompatMode, SchemaCompatReport, RenderContractShape, ToolSchemaRef, } from './schema-compat.js';
|
|
43
43
|
export type { ServerInfo } from './build-mcp.js';
|
|
44
44
|
export { UnauthenticatedError, DEFAULT_BUILDER_APP_ID, defaultAppIdFromIdentity, } from './auth.js';
|
|
45
45
|
export { createConsoleLogger } from './logger.js';
|
|
46
46
|
export type { Logger } from './logger.js';
|
|
47
|
-
export {
|
|
48
|
-
export type {
|
|
47
|
+
export { createRenderChannelServer, DEFAULT_RENDER_CHANNEL_PATH, DEFAULT_WIRED_TOOL_TIMEOUT_MS, } from './render-channel.js';
|
|
48
|
+
export type { RenderChannelOptions, RenderChannelServer, WiredActionContext, WiredActionRouter, } from './render-channel.js';
|
|
49
49
|
export { resolveStorageFromConfig } from './storage.js';
|
|
50
50
|
export type { ResolveStorageFromConfigOptions, ResolvedStorageStores, } from './storage.js';
|
|
51
51
|
export { DEFAULT_PAIRING_ADMIN_INIT_PATH, DEFAULT_PAIRING_PATH, mountPairingTransport, } from './pairing-transport.js';
|
|
@@ -97,6 +97,6 @@ export type { DiscoveredPrimitiveCatalog } from '@ggui-ai/project-config/node';
|
|
|
97
97
|
export type { LoadedTheme } from '@ggui-ai/project-config/node';
|
|
98
98
|
export type { OperatorConfig } from '@ggui-ai/project-config';
|
|
99
99
|
export type { ThemeWriter, ThemeFileUploader, } from './console-theme-routes.js';
|
|
100
|
-
export type { LlmProvider, LlmSelection, ProviderKeyRef, UiGenerateEvent, UiGenerateInput, UiGenerateResult, UiGenerator, GeneratorTier, GeneratorRegistry, GeneratorSlugParts, } from '@ggui-ai/mcp-server-core';
|
|
100
|
+
export type { LlmProvider, LlmRoute, LlmSelection, ProviderKeyRef, UiGenerateEvent, UiGenerateInput, UiGenerateResult, UiGenerator, GeneratorTier, GeneratorRegistry, GeneratorSlugParts, } from '@ggui-ai/mcp-server-core';
|
|
101
101
|
export { formatGeneratorSlug, isValidGeneratorSlug, parseGeneratorSlug, } from '@ggui-ai/mcp-server-core';
|
|
102
102
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAKlF,YAAY,EACV,gBAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
* The `ggui serve` CLI command boots this server with the OSS defaults.
|
|
27
27
|
*/
|
|
28
28
|
// No-credentials fallback helpers — re-exported so the OSS CLI can
|
|
29
|
-
// build the no-credentials card
|
|
29
|
+
// build the no-credentials card render (pointing at the resolved
|
|
30
30
|
// `/settings` URL) without taking a direct `@ggui-ai/mcp-server-handlers`
|
|
31
31
|
// dependency.
|
|
32
|
-
export { NO_CREDENTIALS_SYSTEM_CARD_KIND,
|
|
32
|
+
export { NO_CREDENTIALS_SYSTEM_CARD_KIND, buildNoCredentialsRender, } from '@ggui-ai/mcp-server-handlers';
|
|
33
33
|
export { createGguiServer, defaultHandlers } from './server.js';
|
|
34
34
|
// Content-addressable code delivery (2026-05-03). FileSystemCodeStore
|
|
35
35
|
// is the OSS dev default; in-memory variant ships in
|
|
@@ -48,10 +48,10 @@ export { composePreviewReservedValidator, mergeReservedValidators, } from './res
|
|
|
48
48
|
// type, the canonical error, and the default mode constant. Consumers
|
|
49
49
|
// embedding their own endpoint paths (custom hosted wrappers) can
|
|
50
50
|
// reuse the helper directly.
|
|
51
|
-
export {
|
|
51
|
+
export { checkRenderSchemaCompat, DEFAULT_SCHEMA_COMPAT_MODE, SchemaCompatError, } from './schema-compat.js';
|
|
52
52
|
export { UnauthenticatedError, DEFAULT_BUILDER_APP_ID, defaultAppIdFromIdentity, } from './auth.js';
|
|
53
53
|
export { createConsoleLogger } from './logger.js';
|
|
54
|
-
export {
|
|
54
|
+
export { createRenderChannelServer, DEFAULT_RENDER_CHANNEL_PATH, DEFAULT_WIRED_TOOL_TIMEOUT_MS, } from './render-channel.js';
|
|
55
55
|
export { resolveStorageFromConfig } from './storage.js';
|
|
56
56
|
export { DEFAULT_PAIRING_ADMIN_INIT_PATH, DEFAULT_PAIRING_PATH, mountPairingTransport, } from './pairing-transport.js';
|
|
57
57
|
// End-user browser-session cookie + login routes. Cookie + endpoints
|
|
@@ -103,7 +103,7 @@ export { InMemoryShortCodeIndex } from '@ggui-ai/mcp-server-core/in-memory';
|
|
|
103
103
|
export { InMemoryAuthAdapter } from '@ggui-ai/mcp-server-core/in-memory';
|
|
104
104
|
// In-memory rate-limiter + quota-store reference adapters. Re-exported
|
|
105
105
|
// for the same reason as `InMemoryAuthAdapter` — CLI hosts can compose
|
|
106
|
-
// `--public-demo` posture (per-IP rate limit on
|
|
106
|
+
// `--public-demo` posture (per-IP rate limit on ggui_render) without
|
|
107
107
|
// taking a direct `@ggui-ai/mcp-server-core` dep. The default fallback
|
|
108
108
|
// inside `createGguiServer` is `NoopRateLimiter`; this is the smallest
|
|
109
109
|
// non-trivial alternative.
|
|
@@ -61,7 +61,7 @@ export declare const MCP_INSTRUCTIONS_PRESETS: {
|
|
|
61
61
|
readonly aggressive: string;
|
|
62
62
|
/**
|
|
63
63
|
* `aggressive` + a worked invocation example. Useful when the
|
|
64
|
-
* operator wants the LLM to see a complete handshake →
|
|
64
|
+
* operator wants the LLM to see a complete handshake → render
|
|
65
65
|
* pattern at boot.
|
|
66
66
|
*/
|
|
67
67
|
readonly always: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions-presets.d.ts","sourceRoot":"","sources":["../src/instructions-presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;
|
|
1
|
+
{"version":3,"file":"instructions-presets.d.ts","sourceRoot":"","sources":["../src/instructions-presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AA8GH;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;IACnC;;;;OAIG;;IAGH;;;;;OAKG;;IAGH;;;;OAIG;;IASH;;;OAGG;;IAIH;;;;OAIG;;CAEK,CAAC;AAEX;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,OAAO,wBAAwB,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,GAAG,MAAM,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,oBAAoB,GAAG,SAAS,GACtC,MAAM,GAAG,SAAS,CAWpB"}
|
|
@@ -48,10 +48,10 @@
|
|
|
48
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-stack-item 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
|
-
* `always` only — shows the literal handshake →
|
|
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({
|
|
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?, generator, variance }, amendments?, validationFindings? }, contractHash: '<hex>' }. ACCEPT PATH: ggui_render({ handshakeId: 'h_…', decision: { kind: 'accept' } }) — reuses the provisional blueprintId; response carries the minted renderId. OVERRIDE PATH: ggui_render({ handshakeId: 'h_…', decision: { kind: 'override', blueprintDraft: { contract: { ...refined } } } }) — mints a fresh blueprintId against your new draft.";
|
|
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_render 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
|
'',
|
|
@@ -78,49 +78,67 @@ const DEFAULT_PRESET_BODY = [
|
|
|
78
78
|
'',
|
|
79
79
|
'Every chat that touches ggui follows this loop:',
|
|
80
80
|
'',
|
|
81
|
-
'
|
|
81
|
+
'TOOL PREREQUISITES (read once, internalize):',
|
|
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 renders identified by `renderId` and require NO handshake. The `renderId` 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 render that the user can\'t see, orphaning whichever live iframe the gesture targeted.',
|
|
84
|
+
' • Each `renderId` 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.',
|
|
82
85
|
'',
|
|
83
|
-
'
|
|
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 lets you steer cache lookup + gen by axis: `persona` ("minimalist", "playful"), `aesthetic` ("dense", "spacious"), `intentContext` (free-form usage notes), `seedPrompt` (deterministic seed). Server runs BlueprintSearch + contract-validation in parallel and returns a handshakeId + suggestion (origin: cache | agent | synth). cache → blueprint already exists, render delivers it instantly. agent → novel-but-clean draft, gen runs on render. synth → your draft failed validation, server amended it; diff is on suggestion.amendments.',
|
|
84
87
|
'',
|
|
85
|
-
'
|
|
88
|
+
' 2. ggui_render — deliver the UI. handshakeId is REQUIRED (from step 1); calling render without it fails with `handshake_not_found`. Send {handshakeId, decision: {kind:"accept"}} to use the suggestion verbatim, OR {handshakeId, decision: {kind:"override", blueprintDraft:{...}}} to mint fresh against a new draft. If the contract declares propsSpec, props is REQUIRED. Response includes the minted `renderId` — 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` (props don\'t match propsSpec) / `contract_schema_invalid` (an inner JSON Schema is malformed) / `cross_reference_unresolved` (`actionSpec[*].nextStep` or `streamSpec[*].source.tool` names a tool not in `agentCapabilities.tools`) / `schema_mismatch_error` (action schema not a subset of the named tool\'s inputSchema) / `missing_props` → fix the input and retry with the SAME handshakeId (still valid until consumed).',
|
|
86
89
|
'',
|
|
87
|
-
'
|
|
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.',
|
|
88
91
|
'',
|
|
89
|
-
'
|
|
92
|
+
' 4. ggui_consume (when render said to) — long-poll for user interaction. Keyed by renderId. Blocks up to ~15 min (deployment-configurable); returns when an actionSpec event arrives or the render 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.',
|
|
90
93
|
'',
|
|
91
|
-
'
|
|
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: `{renderId, kind:"replace", props}` sends the FULL new props map (use when most fields changed or you want deterministic restoration); `{renderId, 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).',
|
|
92
95
|
'',
|
|
93
|
-
'In short: let the protocol\'s `nextStep` fields drive routing. Every ggui_* tool whose response logically chains forwards (
|
|
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."',
|
|
94
97
|
'',
|
|
95
|
-
'═══
|
|
98
|
+
'═══ REHYDRATED USER GESTURES (renderId-carrying user messages) ═══',
|
|
96
99
|
'',
|
|
97
|
-
'
|
|
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 `renderId` — 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:',
|
|
98
101
|
'',
|
|
99
|
-
' •
|
|
102
|
+
' • The named `renderId` identifies an EXISTING live iframe. Treat the message as a continuation of THAT render, not as a fresh request.',
|
|
103
|
+
' • REQUIRED first tool call: `ggui_consume({renderId: <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({renderId, ...})` on the SAME renderId.',
|
|
104
|
+
' • DO NOT call `ggui_handshake` for a rehydrated-gesture message. Handshaking mints a SEPARATE new render 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 `renderId` named in the user message, your first tool call is `ggui_consume({renderId})`, full stop.',
|
|
105
|
+
'',
|
|
106
|
+
'Worked example — user reload + click:',
|
|
107
|
+
'',
|
|
108
|
+
' 1. User reloads the page; the iframe for render `r_abc123` re-mounts.',
|
|
109
|
+
' 2. User clicks "undo" in the iframe.',
|
|
110
|
+
' 3. Agent receives a user message containing `renderId: r_abc123` (in a host-synthesized directive or as a structured slice).',
|
|
111
|
+
' 4. Agent calls `ggui_consume({renderId: "r_abc123"})` — NOT `ggui_handshake`.',
|
|
112
|
+
' 5. Consume returns the click event; agent calls `todo_toggle({id: 1, done: false})`.',
|
|
113
|
+
' 6. Agent calls `ggui_update({renderId: "r_abc123", kind: "merge", patch: {todos: [...]}})`.',
|
|
100
114
|
'',
|
|
101
|
-
'
|
|
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 renderId is the source of truth for which iframe to address.',
|
|
102
116
|
'',
|
|
103
|
-
'
|
|
117
|
+
'═══ COMPLEMENTARY TOOLS ═══',
|
|
118
|
+
'',
|
|
119
|
+
' • ggui_update — refresh a delivered UI with new props WITHOUT destroying it. Two modes: `kind:"replace"` (full props) or `kind:"merge"` (RFC 7396 delta — see step 5). ALWAYS call this after any state-mutating tool call; re-rendering would lose scroll position, focus, and uncommitted input. Forgetting `ggui_update` after a mutation is the most common protocol bug.',
|
|
120
|
+
'',
|
|
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.',
|
|
104
122
|
'',
|
|
105
|
-
' •
|
|
123
|
+
' • ggui_get_render / ggui_list_renders — inspect current render state if you\'ve lost track of what\'s on screen. ggui_get_render returns the render including its `contextSnapshot` — the canonical way to read contextSpec values from a raw MCP client. ggui_list_renders enumerates every render in the current host conversation (paired by `_meta["ai.ggui/host-session"]` on the inbound call).',
|
|
106
124
|
'',
|
|
107
125
|
'═══ HOST RENDERING ═══',
|
|
108
126
|
'',
|
|
109
|
-
'Two host shapes consume
|
|
127
|
+
'Two host shapes consume render output identically — your job is the same:',
|
|
110
128
|
'',
|
|
111
|
-
' • MCP Apps hosts (claude.ai, MCP-Apps-aware desktop clients) —
|
|
129
|
+
' • MCP Apps hosts (claude.ai, MCP-Apps-aware desktop clients) — render responses carry the rendered UI inline via `_meta["ai.ggui/render"]`; the host displays it automatically. The user interacts with the UI directly, and contextSpec snapshots flow back into your widget-context surface without any agent action.',
|
|
112
130
|
'',
|
|
113
|
-
' • Plain MCP clients (Claude Agent SDK without MCP Apps host adapter, raw CLI clients) —
|
|
131
|
+
' • Plain MCP clients (Claude Agent SDK without MCP Apps host adapter, raw CLI clients) — render responses carry a renderer URL in the structured content; the host either embeds it as an iframe or displays it as a link. Wire flow is identical (handshake → render → consume); only the rendering surface differs.',
|
|
114
132
|
'',
|
|
115
133
|
'Rendered UIs are LIVE — actionSpec entries route back to you as events you receive via consume (each gesture\'s payload validated against the entry\'s declared schema). You don\'t write glue code for any of this; declaring the spec at handshake time is enough.',
|
|
116
134
|
'',
|
|
117
135
|
'═══ TOOL DISCOVERY (lazy-loading hosts) ═══',
|
|
118
136
|
'',
|
|
119
|
-
'Some MCP hosts (notably claude.ai\'s connector model) use PROGRESSIVE tool discovery — only a small priority subset of tools is warmed at conversation start; the rest must be explicitly discovered via `tool_search` before they\'re callable. The ggui_* loop crosses this boundary on every
|
|
137
|
+
'Some MCP hosts (notably claude.ai\'s connector model) use PROGRESSIVE tool discovery — only a small priority subset of tools is warmed at conversation start; the rest must be explicitly discovered via `tool_search` before they\'re callable. The ggui_* loop crosses this boundary on every render: handshake/render warm easily because you call them early, but `ggui_consume` and `ggui_update` are needed AFTER render and the host may not have loaded them yet.',
|
|
120
138
|
'',
|
|
121
139
|
'SYMPTOM: a tool call fails with a message like "tool has not been loaded yet — call tool_search first" or "you do not have the correct parameter names." RECOVERY: call `tool_search` with the tool name as a query (e.g. `tool_search({ query: "ggui_consume" })`), wait for the load to complete, then retry the original call with the same args. Same pattern for `ggui_update`. After one successful `tool_search` per tool per conversation, subsequent calls work directly.',
|
|
122
140
|
'',
|
|
123
|
-
'WHEN IN DOUBT: if the
|
|
141
|
+
'WHEN IN DOUBT: if the render response carries `nextStep`, the host has effectively asked you to call that tool. Don\'t skip ggui_consume because the host whined about it being unloaded — `tool_search` first, then call. Skipping it leaves the user staring at a UI whose actions silently never reach the agent — the worst protocol failure mode.',
|
|
124
142
|
];
|
|
125
143
|
/**
|
|
126
144
|
* Preset name → instruction-string map. Operators select a preset by
|
|
@@ -146,7 +164,7 @@ export const MCP_INSTRUCTIONS_PRESETS = {
|
|
|
146
164
|
aggressive: [...DEFAULT_PRESET_BODY, '', ACTION_ROUTING_PARAGRAPH].join('\n'),
|
|
147
165
|
/**
|
|
148
166
|
* `aggressive` + a worked invocation example. Useful when the
|
|
149
|
-
* operator wants the LLM to see a complete handshake →
|
|
167
|
+
* operator wants the LLM to see a complete handshake → render
|
|
150
168
|
* pattern at boot.
|
|
151
169
|
*/
|
|
152
170
|
always: [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
*
|
|
40
40
|
* One LLM call per handshake (when creds resolve). Operators
|
|
41
41
|
* concerned about cost can either (a) skip handshake and call
|
|
42
|
-
* `
|
|
42
|
+
* `ggui_render` directly with `{story}`, or (b) bind a different
|
|
43
43
|
* negotiator (e.g., the cache-backed one for read-only cache
|
|
44
44
|
* lookups) via `createGguiServer({handshake: {negotiator: ...}})`.
|
|
45
45
|
*
|
|
@@ -50,11 +50,11 @@
|
|
|
50
50
|
* same `negotiate()` pipeline, just with degraded RAG when local
|
|
51
51
|
* infrastructure isn't bound.
|
|
52
52
|
*/
|
|
53
|
-
import {
|
|
54
|
-
import type {
|
|
55
|
-
import type
|
|
56
|
-
import { type
|
|
57
|
-
import type { Blueprint } from
|
|
53
|
+
import type { EmbeddingProvider, LlmSelection, ProviderKeyRef, VariantSelectionContext, VariantSelectionDecision, VectorStore } from "@ggui-ai/mcp-server-core";
|
|
54
|
+
import type { HandlerContext } from "@ggui-ai/mcp-server-handlers";
|
|
55
|
+
import { type HandshakeNegotiator, type InstalledBlueprintsProvider } from "@ggui-ai/mcp-server-handlers/renders";
|
|
56
|
+
import { type LLMCaller } from "@ggui-ai/negotiator";
|
|
57
|
+
import type { Blueprint } from "@ggui-ai/protocol";
|
|
58
58
|
/**
|
|
59
59
|
* Wrap a resolved BYOK credential pair into an `LLMCaller` the
|
|
60
60
|
* negotiator can call. The adapter is chosen via `selectAdapter`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-backed-negotiator.d.ts","sourceRoot":"","sources":["../src/llm-backed-negotiator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"llm-backed-negotiator.d.ts","sourceRoot":"","sources":["../src/llm-backed-negotiator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EACV,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,EAGL,KAAK,mBAAmB,EAExB,KAAK,2BAA2B,EAEjC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAqC,MAAM,mBAAmB,CAAC;AAmBtF;;;;;;;;;;;;;;;;;;;;;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;;;OAGG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,KAAK,CAAC,EAAE;QACN,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;QACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;KACnC,CAAC;IACF;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,2BAA2B,CAAC;CACnD;AA8BD;;;;;;;;GAQG;AACH,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,gCAAgC,GACrC,mBAAmB,CA2MrB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,2wDAoBgN,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"}
|