@ggui-ai/mcp-server-handlers 0.7.0 → 0.9.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/blueprints/index.d.ts +2 -2
- package/dist/blueprints/index.d.ts.map +1 -1
- package/dist/blueprints/index.js +1 -1
- package/dist/blueprints/search-blueprints.d.ts +64 -12
- package/dist/blueprints/search-blueprints.d.ts.map +1 -1
- package/dist/blueprints/search-blueprints.js +166 -16
- package/dist/renders/amend.d.ts +57 -0
- package/dist/renders/amend.d.ts.map +1 -0
- package/dist/renders/amend.js +64 -0
- package/dist/renders/apply-ggui-session-patch.d.ts +4 -0
- package/dist/renders/apply-ggui-session-patch.d.ts.map +1 -1
- package/dist/renders/apply-ggui-session-patch.js +1 -1
- package/dist/renders/assert-props-contract.d.ts +5 -4
- package/dist/renders/assert-props-contract.d.ts.map +1 -1
- package/dist/renders/assert-props-contract.js +6 -5
- package/dist/renders/code-delivery-events.d.ts +45 -29
- package/dist/renders/code-delivery-events.d.ts.map +1 -1
- package/dist/renders/code-delivery-events.js +42 -25
- package/dist/renders/consume.js +1 -1
- package/dist/renders/decide-handshake.d.ts +15 -0
- package/dist/renders/decide-handshake.d.ts.map +1 -1
- package/dist/renders/decide-handshake.js +18 -0
- package/dist/renders/declare-tool-catalog.js +1 -1
- package/dist/renders/handshake.d.ts.map +1 -1
- package/dist/renders/handshake.js +58 -12
- package/dist/renders/index.d.ts +5 -1
- package/dist/renders/index.d.ts.map +1 -1
- package/dist/renders/index.js +5 -1
- package/dist/renders/props-mutation-core.d.ts +60 -0
- package/dist/renders/props-mutation-core.d.ts.map +1 -0
- package/dist/renders/props-mutation-core.js +339 -0
- package/dist/renders/render.d.ts +2 -0
- package/dist/renders/render.d.ts.map +1 -1
- package/dist/renders/render.js +61 -32
- package/dist/renders/runtime-pull.d.ts +122 -0
- package/dist/renders/runtime-pull.d.ts.map +1 -0
- package/dist/renders/runtime-pull.js +178 -0
- package/dist/renders/runtime-telemetry.d.ts +60 -0
- package/dist/renders/runtime-telemetry.d.ts.map +1 -0
- package/dist/renders/runtime-telemetry.js +76 -0
- package/dist/renders/slice-meta-derivation.d.ts +146 -6
- package/dist/renders/slice-meta-derivation.d.ts.map +1 -1
- package/dist/renders/slice-meta-derivation.js +190 -8
- package/dist/renders/submit-action.d.ts +9 -0
- package/dist/renders/submit-action.d.ts.map +1 -1
- package/dist/renders/submit-action.js +70 -1
- package/dist/renders/update.d.ts +33 -42
- package/dist/renders/update.d.ts.map +1 -1
- package/dist/renders/update.js +99 -230
- package/package.json +7 -7
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
* on top when wrapping these into its tool-handler shape (a wider
|
|
24
24
|
* `SharedHandler<ToolContext>` re-export).
|
|
25
25
|
*/
|
|
26
|
-
export { createSearchBlueprintsHandler, MIN_SIMILARITY_SCORE, MANIFEST_EXACT_NAME_SCORE, MANIFEST_SUBSTRING_SCORE, } from './search-blueprints.js';
|
|
27
|
-
export type { SearchBlueprintsDeps } from './search-blueprints.js';
|
|
26
|
+
export { createSearchBlueprintsHandler, DEFAULT_REGISTRY_SEARCH_TIMEOUT_MS, MIN_SIMILARITY_SCORE, MANIFEST_EXACT_NAME_SCORE, MANIFEST_SUBSTRING_SCORE, } from './search-blueprints.js';
|
|
27
|
+
export type { SearchBlueprintsDeps, SearchBlueprintsRegistrySource, } from './search-blueprints.js';
|
|
28
28
|
export { createListFeaturedBlueprintsHandler } from './list-featured-blueprints.js';
|
|
29
29
|
export type { ListFeaturedBlueprintsDeps, ListFeaturedBlueprintsOutput, } from './list-featured-blueprints.js';
|
|
30
30
|
export { createRenderBlueprintHandler } from './render-blueprint.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blueprints/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blueprints/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EACL,6BAA6B,EAC7B,kCAAkC,EAClC,oBAAoB,EACpB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,oBAAoB,EACpB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mCAAmC,EAAE,MAAM,+BAA+B,CAAC;AACpF,YAAY,EACV,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,oCAAoC,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,oCAAoC,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,oCAAoC,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,uCAAuC,EAAE,MAAM,oCAAoC,CAAC;AAC7F,OAAO,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/blueprints/index.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* on top when wrapping these into its tool-handler shape (a wider
|
|
24
24
|
* `SharedHandler<ToolContext>` re-export).
|
|
25
25
|
*/
|
|
26
|
-
export { createSearchBlueprintsHandler, MIN_SIMILARITY_SCORE, MANIFEST_EXACT_NAME_SCORE, MANIFEST_SUBSTRING_SCORE, } from './search-blueprints.js';
|
|
26
|
+
export { createSearchBlueprintsHandler, DEFAULT_REGISTRY_SEARCH_TIMEOUT_MS, MIN_SIMILARITY_SCORE, MANIFEST_EXACT_NAME_SCORE, MANIFEST_SUBSTRING_SCORE, } from './search-blueprints.js';
|
|
27
27
|
export { createListFeaturedBlueprintsHandler } from './list-featured-blueprints.js';
|
|
28
28
|
export { createRenderBlueprintHandler } from './render-blueprint.js';
|
|
29
29
|
export { createValidateBlueprintHandler } from './validate-blueprint.js';
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* ggui_search_blueprints — search across every discoverable blueprint
|
|
3
3
|
* on this server.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* by id:
|
|
5
|
+
* Up to three sources are consulted in parallel, then merged +
|
|
6
|
+
* de-duplicated by id:
|
|
7
7
|
*
|
|
8
8
|
* 1. **Manifest source** (optional `BlueprintProvider`) — authored
|
|
9
9
|
* UIs declared in `ggui.json#blueprints.include`. Matched by
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
* producer that has written into the scope. Continues to honor
|
|
20
20
|
* `MIN_SIMILARITY_SCORE`.
|
|
21
21
|
*
|
|
22
|
+
* 3. **Registry source** (optional, opt-in via deps.registry) —
|
|
23
|
+
* bounded public /search call for published blueprint
|
|
24
|
+
* candidates; appended after local hits, degrades typed on
|
|
25
|
+
* failure.
|
|
26
|
+
*
|
|
22
27
|
* When both sources return the same id (a manifest blueprint that
|
|
23
28
|
* also has a cached generation), the manifest entry wins — its
|
|
24
29
|
* metadata is the source of truth and its name/description don't
|
|
@@ -26,8 +31,12 @@
|
|
|
26
31
|
* max of the two so a lexical OR semantic hit keeps the entry in
|
|
27
32
|
* the top band.
|
|
28
33
|
*
|
|
29
|
-
* The merge
|
|
30
|
-
* after sort
|
|
34
|
+
* The local merge (manifest + semantic) is trimmed to the top-N
|
|
35
|
+
* after sort, so it stays within `limit`. Registry candidates are
|
|
36
|
+
* bounded by the same `limit` on their own request and append AFTER
|
|
37
|
+
* that trim rather than sharing its budget, so the final `results`
|
|
38
|
+
* count can reach up to 2×`limit`. `total` reflects the pre-trim
|
|
39
|
+
* local match count plus the appended registry count.
|
|
31
40
|
*
|
|
32
41
|
* ## Why merge vs. a dedicated tool
|
|
33
42
|
*
|
|
@@ -38,8 +47,8 @@
|
|
|
38
47
|
* the split the server already knows how to make.
|
|
39
48
|
*
|
|
40
49
|
* Pure over `@ggui-ai/mcp-server-core`'s seams. No AWS imports. No
|
|
41
|
-
* config loading.
|
|
42
|
-
* when
|
|
50
|
+
* config loading. A composing host may wrap this with its own
|
|
51
|
+
* logging when assembling the server.
|
|
43
52
|
*/
|
|
44
53
|
import { z } from 'zod';
|
|
45
54
|
import type { BlueprintProvider, EmbeddingProvider, VectorStore } from '@ggui-ai/mcp-server-core';
|
|
@@ -65,6 +74,30 @@ export declare const MANIFEST_EXACT_NAME_SCORE = 1;
|
|
|
65
74
|
* stronger signal.
|
|
66
75
|
*/
|
|
67
76
|
export declare const MANIFEST_SUBSTRING_SCORE = 0.7;
|
|
77
|
+
/**
|
|
78
|
+
* Default budget for the registry `/search` round-trip. The registry
|
|
79
|
+
* source is advisory — a slow registry must never stall the local
|
|
80
|
+
* sources past this bound. Operator-overridable per-deps.
|
|
81
|
+
*/
|
|
82
|
+
export declare const DEFAULT_REGISTRY_SEARCH_TIMEOUT_MS = 3000;
|
|
83
|
+
/**
|
|
84
|
+
* Registry-backed discovery source configuration. Presence of this
|
|
85
|
+
* object on `SearchBlueprintsDeps` ACTIVATES the source (opt-in —
|
|
86
|
+
* a zero-config server never makes an outbound registry request).
|
|
87
|
+
*/
|
|
88
|
+
export interface SearchBlueprintsRegistrySource {
|
|
89
|
+
/**
|
|
90
|
+
* Registry host (`host[:port]`). Absent = `DEFAULT_BUNDLE_HOST`.
|
|
91
|
+
* Scheme derives via `bundleHostScheme` — http for loopback,
|
|
92
|
+
* https otherwise (the same resolution the gadget bundleHost
|
|
93
|
+
* uses).
|
|
94
|
+
*/
|
|
95
|
+
readonly host?: string;
|
|
96
|
+
/** Fetch budget in ms. Default `DEFAULT_REGISTRY_SEARCH_TIMEOUT_MS`. */
|
|
97
|
+
readonly timeoutMs?: number;
|
|
98
|
+
/** Injectable fetch for tests. Defaults to the global fetch. */
|
|
99
|
+
readonly fetch?: typeof fetch;
|
|
100
|
+
}
|
|
68
101
|
export interface SearchBlueprintsDeps {
|
|
69
102
|
readonly embedding: EmbeddingProvider;
|
|
70
103
|
readonly vectors: VectorStore;
|
|
@@ -74,29 +107,48 @@ export interface SearchBlueprintsDeps {
|
|
|
74
107
|
* included in the search results alongside the semantic
|
|
75
108
|
* `VectorStore` matches.
|
|
76
109
|
*
|
|
77
|
-
* Omitted = semantic-only behavior (the pre-merge default)
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* `ManifestBlueprintProvider` at boot and threads it through
|
|
110
|
+
* Omitted = semantic-only behavior (the pre-merge default) — a
|
|
111
|
+
* composing host can run without a manifest provider bound to this
|
|
112
|
+
* handler. This package's own `createGguiServer` constructs a
|
|
113
|
+
* `ManifestBlueprintProvider` at boot and threads it through by
|
|
114
|
+
* default.
|
|
81
115
|
*/
|
|
82
116
|
readonly blueprints?: BlueprintProvider;
|
|
117
|
+
/**
|
|
118
|
+
* Optional registry discovery source. When bound, the handler
|
|
119
|
+
* queries the registry's public `/search` for published blueprint
|
|
120
|
+
* candidates and appends them after the local sources. Omitted =
|
|
121
|
+
* no outbound registry traffic (the zero-config default).
|
|
122
|
+
*/
|
|
123
|
+
readonly registry?: SearchBlueprintsRegistrySource;
|
|
83
124
|
}
|
|
84
125
|
declare const inputSchema: {
|
|
85
126
|
readonly query: z.ZodString;
|
|
86
127
|
readonly limit: z.ZodOptional<z.ZodNumber>;
|
|
128
|
+
readonly tool: z.ZodOptional<z.ZodString>;
|
|
129
|
+
readonly server: z.ZodOptional<z.ZodString>;
|
|
87
130
|
};
|
|
88
131
|
declare const outputSchema: {
|
|
89
132
|
results: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
90
133
|
total: z.ZodNumber;
|
|
91
134
|
query: z.ZodString;
|
|
135
|
+
degradedSources: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
136
|
+
source: z.ZodLiteral<"registry">;
|
|
137
|
+
reason: z.ZodEnum<{
|
|
138
|
+
unreachable: "unreachable";
|
|
139
|
+
timeout: "timeout";
|
|
140
|
+
invalid_response: "invalid_response";
|
|
141
|
+
}>;
|
|
142
|
+
}, z.core.$strip>>>;
|
|
92
143
|
};
|
|
93
144
|
/**
|
|
94
145
|
* Build a search-blueprints handler bound to concrete `embedding` +
|
|
95
146
|
* `vectors` implementations (required) + an optional manifest
|
|
96
147
|
* `BlueprintProvider`. Tests inject in-memory fakes from
|
|
97
148
|
* `@ggui-ai/mcp-server-core/in-memory`; production hosts bind to
|
|
98
|
-
*
|
|
99
|
-
* `ManifestBlueprintProvider` for the
|
|
149
|
+
* their own operator-configured embedding + vector-store providers
|
|
150
|
+
* for the semantic source and a `ManifestBlueprintProvider` for the
|
|
151
|
+
* manifest source.
|
|
100
152
|
*/
|
|
101
153
|
export declare function createSearchBlueprintsHandler(deps: SearchBlueprintsDeps): SharedHandler<typeof inputSchema, typeof outputSchema, GguiSearchBlueprintsOutput>;
|
|
102
154
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-blueprints.d.ts","sourceRoot":"","sources":["../../src/blueprints/search-blueprints.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"search-blueprints.d.ts","sourceRoot":"","sources":["../../src/blueprints/search-blueprints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAEV,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAKL,KAAK,0BAA0B,EAChC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,IAAM,CAAC;AAE7C;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,OAAO,CAAC;AAEvD;;;;GAIG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,gEAAgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,8BAA8B,CAAC;CACpD;AAID,QAAA,MAAM,WAAW;;;;;CAA6B,CAAC;AAE/C,QAAA,MAAM,YAAY;;;;;;;;;;;;CAkBjB,CAAC;AAKF;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,oBAAoB,GACzB,aAAa,CAAC,OAAO,WAAW,EAAE,OAAO,YAAY,EAAE,0BAA0B,CAAC,CAyDpF"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* ggui_search_blueprints — search across every discoverable blueprint
|
|
3
3
|
* on this server.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* by id:
|
|
5
|
+
* Up to three sources are consulted in parallel, then merged +
|
|
6
|
+
* de-duplicated by id:
|
|
7
7
|
*
|
|
8
8
|
* 1. **Manifest source** (optional `BlueprintProvider`) — authored
|
|
9
9
|
* UIs declared in `ggui.json#blueprints.include`. Matched by
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
* producer that has written into the scope. Continues to honor
|
|
20
20
|
* `MIN_SIMILARITY_SCORE`.
|
|
21
21
|
*
|
|
22
|
+
* 3. **Registry source** (optional, opt-in via deps.registry) —
|
|
23
|
+
* bounded public /search call for published blueprint
|
|
24
|
+
* candidates; appended after local hits, degrades typed on
|
|
25
|
+
* failure.
|
|
26
|
+
*
|
|
22
27
|
* When both sources return the same id (a manifest blueprint that
|
|
23
28
|
* also has a cached generation), the manifest entry wins — its
|
|
24
29
|
* metadata is the source of truth and its name/description don't
|
|
@@ -26,8 +31,12 @@
|
|
|
26
31
|
* max of the two so a lexical OR semantic hit keeps the entry in
|
|
27
32
|
* the top band.
|
|
28
33
|
*
|
|
29
|
-
* The merge
|
|
30
|
-
* after sort
|
|
34
|
+
* The local merge (manifest + semantic) is trimmed to the top-N
|
|
35
|
+
* after sort, so it stays within `limit`. Registry candidates are
|
|
36
|
+
* bounded by the same `limit` on their own request and append AFTER
|
|
37
|
+
* that trim rather than sharing its budget, so the final `results`
|
|
38
|
+
* count can reach up to 2×`limit`. `total` reflects the pre-trim
|
|
39
|
+
* local match count plus the appended registry count.
|
|
31
40
|
*
|
|
32
41
|
* ## Why merge vs. a dedicated tool
|
|
33
42
|
*
|
|
@@ -38,11 +47,11 @@
|
|
|
38
47
|
* the split the server already knows how to make.
|
|
39
48
|
*
|
|
40
49
|
* Pure over `@ggui-ai/mcp-server-core`'s seams. No AWS imports. No
|
|
41
|
-
* config loading.
|
|
42
|
-
* when
|
|
50
|
+
* config loading. A composing host may wrap this with its own
|
|
51
|
+
* logging when assembling the server.
|
|
43
52
|
*/
|
|
44
53
|
import { z } from 'zod';
|
|
45
|
-
import { flatToBlueprintSource, searchBlueprintsInputShape, } from '@ggui-ai/protocol';
|
|
54
|
+
import { bundleHostScheme, DEFAULT_BUNDLE_HOST, flatToBlueprintSource, searchBlueprintsInputShape, } from '@ggui-ai/protocol';
|
|
46
55
|
/**
|
|
47
56
|
* Matches the hosted `MIN_SIMILARITY_SCORE`. Below this is noise —
|
|
48
57
|
* callers that want stricter matching post-filter by `score`.
|
|
@@ -63,6 +72,12 @@ export const MANIFEST_EXACT_NAME_SCORE = 1.0;
|
|
|
63
72
|
* stronger signal.
|
|
64
73
|
*/
|
|
65
74
|
export const MANIFEST_SUBSTRING_SCORE = 0.7;
|
|
75
|
+
/**
|
|
76
|
+
* Default budget for the registry `/search` round-trip. The registry
|
|
77
|
+
* source is advisory — a slow registry must never stall the local
|
|
78
|
+
* sources past this bound. Operator-overridable per-deps.
|
|
79
|
+
*/
|
|
80
|
+
export const DEFAULT_REGISTRY_SEARCH_TIMEOUT_MS = 3000;
|
|
66
81
|
// Canonical SSoT shape — authored once in `@ggui-ai/protocol`
|
|
67
82
|
// (`schemas/mcp.ts`).
|
|
68
83
|
const inputSchema = searchBlueprintsInputShape;
|
|
@@ -76,32 +91,42 @@ const outputSchema = {
|
|
|
76
91
|
results: z.array(z.record(z.string(), z.unknown())),
|
|
77
92
|
total: z.number().int().nonnegative(),
|
|
78
93
|
query: z.string(),
|
|
94
|
+
degradedSources: z
|
|
95
|
+
.array(z.object({
|
|
96
|
+
source: z.literal('registry'),
|
|
97
|
+
reason: z.enum(['unreachable', 'timeout', 'invalid_response']),
|
|
98
|
+
}))
|
|
99
|
+
.optional(),
|
|
79
100
|
};
|
|
80
101
|
/**
|
|
81
102
|
* Build a search-blueprints handler bound to concrete `embedding` +
|
|
82
103
|
* `vectors` implementations (required) + an optional manifest
|
|
83
104
|
* `BlueprintProvider`. Tests inject in-memory fakes from
|
|
84
105
|
* `@ggui-ai/mcp-server-core/in-memory`; production hosts bind to
|
|
85
|
-
*
|
|
86
|
-
* `ManifestBlueprintProvider` for the
|
|
106
|
+
* their own operator-configured embedding + vector-store providers
|
|
107
|
+
* for the semantic source and a `ManifestBlueprintProvider` for the
|
|
108
|
+
* manifest source.
|
|
87
109
|
*/
|
|
88
110
|
export function createSearchBlueprintsHandler(deps) {
|
|
89
111
|
return {
|
|
90
112
|
name: 'ggui_search_blueprints',
|
|
91
113
|
title: 'Search blueprints',
|
|
92
114
|
audience: ['agent'],
|
|
93
|
-
description: "Search this app's blueprints —
|
|
115
|
+
description: "Search this app's blueprints — manifest-declared UIs (ggui.json#blueprints.include), previously cached generations, and, when a registry is configured, published blueprint candidates from the artifact registry. Local sources match by name/description and cosine similarity; registry candidates are advisory matches appended after local results, labeled origin 'registry'. Optional tool/server filters narrow registry candidates to artifacts declaring those MCP tool bindings. The agent can decide to reuse a match or generate from scratch; installing a registry candidate remains a human/operator act.",
|
|
94
116
|
inputSchema,
|
|
95
117
|
outputSchema,
|
|
96
118
|
async handler(rawInput, ctx) {
|
|
97
|
-
const { query, limit = 10 } = z
|
|
98
|
-
|
|
119
|
+
const { query, limit = 10, tool, server } = z
|
|
120
|
+
.object(inputSchema)
|
|
121
|
+
.parse(rawInput);
|
|
122
|
+
// Fan out all sources in parallel. The manifest source is a
|
|
99
123
|
// pure metadata read (cheap); the semantic source is one
|
|
100
|
-
// `embed` + one `query` round-trip
|
|
101
|
-
//
|
|
102
|
-
const [semantic, manifest] = await Promise.all([
|
|
124
|
+
// `embed` + one `query` round-trip; the registry source is a
|
|
125
|
+
// bounded HTTP call that degrades typed instead of throwing.
|
|
126
|
+
const [semantic, manifest, registry] = await Promise.all([
|
|
103
127
|
searchSemantic(deps, ctx.appId, query, limit),
|
|
104
128
|
searchManifest(deps.blueprints, query, limit),
|
|
129
|
+
searchRegistry(deps.registry, { query, tool, server, limit }, ctx.signal),
|
|
105
130
|
]);
|
|
106
131
|
// Merge + dedupe by id. Manifest entries win on collision —
|
|
107
132
|
// their metadata is author-curated and cannot drift against a
|
|
@@ -117,7 +142,15 @@ export function createSearchBlueprintsHandler(deps) {
|
|
|
117
142
|
}
|
|
118
143
|
const merged = Array.from(byId.values()).sort((a, b) => b.score - a.score);
|
|
119
144
|
const trimmed = merged.slice(0, limit);
|
|
120
|
-
|
|
145
|
+
// Registry candidates append AFTER the local sources (advisory
|
|
146
|
+
// per the discovery design §3) and never displace a local id.
|
|
147
|
+
const registryHits = registry.hits.filter((hit) => !byId.has(hit.id));
|
|
148
|
+
return {
|
|
149
|
+
results: [...trimmed, ...registryHits],
|
|
150
|
+
total: merged.length + registryHits.length,
|
|
151
|
+
query,
|
|
152
|
+
...(registry.degraded ? { degradedSources: [registry.degraded] } : {}),
|
|
153
|
+
};
|
|
121
154
|
},
|
|
122
155
|
};
|
|
123
156
|
}
|
|
@@ -222,3 +255,120 @@ function toManifestHit(entry, queryLower) {
|
|
|
222
255
|
function asString(value) {
|
|
223
256
|
return typeof value === 'string' ? value : '';
|
|
224
257
|
}
|
|
258
|
+
/**
|
|
259
|
+
* Wire subset of the registry `GET /search` response this handler
|
|
260
|
+
* consumes. Local on purpose: this package does not depend on the
|
|
261
|
+
* registry server implementation, and zod's default strip semantics
|
|
262
|
+
* keep the guard forward-compatible with response additions.
|
|
263
|
+
*/
|
|
264
|
+
const registrySearchEntrySchema = z.object({
|
|
265
|
+
artifactId: z.string().min(1),
|
|
266
|
+
latestVersion: z.string().min(1),
|
|
267
|
+
kind: z.string(),
|
|
268
|
+
description: z.string().optional(),
|
|
269
|
+
mcpTools: z.array(z.object({ server: z.string().optional(), tool: z.string() })).optional(),
|
|
270
|
+
scopeVerification: z.enum(['verified', 'unverified']).optional(),
|
|
271
|
+
});
|
|
272
|
+
const registrySearchResponseSchema = z.object({
|
|
273
|
+
results: z.array(registrySearchEntrySchema),
|
|
274
|
+
});
|
|
275
|
+
/**
|
|
276
|
+
* Registry-source branch: bounded public `/search` call. Inactive
|
|
277
|
+
* (empty hits, no degradation) when no registry source is
|
|
278
|
+
* configured. Never throws — every failure mode maps onto the typed
|
|
279
|
+
* `degraded` indication so the merged tool result always succeeds.
|
|
280
|
+
*/
|
|
281
|
+
async function searchRegistry(registry, filters, signal) {
|
|
282
|
+
if (!registry)
|
|
283
|
+
return { hits: [] };
|
|
284
|
+
// Operator-override-then-default host resolution — the same
|
|
285
|
+
// precedence + scheme rule as gadget bundleHost (`DEFAULT_BUNDLE_HOST`
|
|
286
|
+
// + `bundleHostScheme` from `@ggui-ai/protocol`).
|
|
287
|
+
const host = typeof registry.host === 'string' && registry.host.length > 0
|
|
288
|
+
? registry.host
|
|
289
|
+
: DEFAULT_BUNDLE_HOST;
|
|
290
|
+
const params = new URLSearchParams();
|
|
291
|
+
params.set('q', filters.query);
|
|
292
|
+
// This tool's kind scope is blueprints; gadget discovery is served
|
|
293
|
+
// by the registry HTTP surface directly.
|
|
294
|
+
params.set('kind', 'blueprint');
|
|
295
|
+
if (filters.tool !== undefined)
|
|
296
|
+
params.set('tool', filters.tool);
|
|
297
|
+
if (filters.server !== undefined)
|
|
298
|
+
params.set('server', filters.server);
|
|
299
|
+
params.set('limit', String(filters.limit));
|
|
300
|
+
const url = `${bundleHostScheme(host)}://${host}/search?${params.toString()}`;
|
|
301
|
+
const timeoutMs = registry.timeoutMs ?? DEFAULT_REGISTRY_SEARCH_TIMEOUT_MS;
|
|
302
|
+
const signals = [AbortSignal.timeout(timeoutMs)];
|
|
303
|
+
if (signal)
|
|
304
|
+
signals.push(signal);
|
|
305
|
+
const fetchImpl = registry.fetch ?? fetch;
|
|
306
|
+
let res;
|
|
307
|
+
try {
|
|
308
|
+
res = await fetchImpl(url, {
|
|
309
|
+
method: 'GET',
|
|
310
|
+
headers: { accept: 'application/json' },
|
|
311
|
+
signal: AbortSignal.any(signals),
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
const reason = err instanceof Error && err.name === 'TimeoutError' ? 'timeout' : 'unreachable';
|
|
316
|
+
return { hits: [], degraded: { source: 'registry', reason } };
|
|
317
|
+
}
|
|
318
|
+
if (!res.ok) {
|
|
319
|
+
// Undici doesn't return the socket to the pool until the body is
|
|
320
|
+
// consumed or canceled. We never read this body (non-2xx), so
|
|
321
|
+
// cancel it explicitly — a rejecting cancel() must still surface
|
|
322
|
+
// the already-typed degradation, not throw past this branch.
|
|
323
|
+
try {
|
|
324
|
+
await res.body?.cancel();
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
// Deliberately swallowed — see comment above.
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
hits: [],
|
|
331
|
+
degraded: { source: 'registry', reason: 'invalid_response' },
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
let body;
|
|
335
|
+
try {
|
|
336
|
+
body = await res.json();
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
return {
|
|
340
|
+
hits: [],
|
|
341
|
+
degraded: { source: 'registry', reason: 'invalid_response' },
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
const parsed = registrySearchResponseSchema.safeParse(body);
|
|
345
|
+
if (!parsed.success) {
|
|
346
|
+
return {
|
|
347
|
+
hits: [],
|
|
348
|
+
degraded: { source: 'registry', reason: 'invalid_response' },
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
return { hits: parsed.data.results.map(toRegistryHit) };
|
|
352
|
+
}
|
|
353
|
+
function toRegistryHit(entry) {
|
|
354
|
+
return {
|
|
355
|
+
id: `${entry.artifactId}@${entry.latestVersion}`,
|
|
356
|
+
name: entry.artifactId,
|
|
357
|
+
description: entry.description ?? '',
|
|
358
|
+
category: entry.kind,
|
|
359
|
+
// Registry search rows carry no contract details — honest empties.
|
|
360
|
+
props: [],
|
|
361
|
+
callbacks: [],
|
|
362
|
+
featured: false,
|
|
363
|
+
relevance: 'match',
|
|
364
|
+
// The registry source computes no similarity. Entries always
|
|
365
|
+
// append AFTER the score-sorted local sources, so this value
|
|
366
|
+
// carries no ranking weight; 0 is the honest "not measured".
|
|
367
|
+
score: 0,
|
|
368
|
+
origin: 'registry',
|
|
369
|
+
artifactId: entry.artifactId,
|
|
370
|
+
version: entry.latestVersion,
|
|
371
|
+
...(entry.mcpTools ? { mcpTools: entry.mcpTools } : {}),
|
|
372
|
+
...(entry.scopeVerification ? { scopeVerification: entry.scopeVerification } : {}),
|
|
373
|
+
};
|
|
374
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ggui_amend` — in-place props mutation on the ALREADY-MOUNTED card
|
|
3
|
+
* (#483 tool split). Same wire grammar as `ggui_update`
|
|
4
|
+
* (replace/merge via the shared {@link runPropsMutation} core), the
|
|
5
|
+
* opposite mount identity:
|
|
6
|
+
*
|
|
7
|
+
* - NO history record: the head epoch is untouched by construction
|
|
8
|
+
* (the core advances it only for `ggui_update`).
|
|
9
|
+
* - NO `_meta.ui` on the tool DECLARATION and NO `resultMeta` — this
|
|
10
|
+
* is a plain data tool. Hosts never reserve a per-result view for
|
|
11
|
+
* it (hosts mint views from `_meta` on UI-bound success results —
|
|
12
|
+
* live-proven 2026-08-12), so nothing new appears in the
|
|
13
|
+
* conversation. The mounted card receives the new props over the
|
|
14
|
+
* live-channel ladder (WS / SSE / polling / bridge-pull); the
|
|
15
|
+
* spec tool-result forwarding path is deliberately not part of
|
|
16
|
+
* this tool's contract.
|
|
17
|
+
*
|
|
18
|
+
* Git reading: `ggui_update` = commit (new history entry);
|
|
19
|
+
* `ggui_amend` = commit --amend (fix up the current one).
|
|
20
|
+
*/
|
|
21
|
+
import { z } from 'zod';
|
|
22
|
+
import type { SharedHandler } from '../types.js';
|
|
23
|
+
import { mutationInputSchema } from './props-mutation-core.js';
|
|
24
|
+
import type { GguiUpdateHandlerDeps } from './update.js';
|
|
25
|
+
/**
|
|
26
|
+
* Same seam set as `ggui_update` on purpose — the two tools share ONE
|
|
27
|
+
* mutation core, so composers wire ONE deps object for both. The
|
|
28
|
+
* slice-meta options (`mintWsToken` / `runtimeUrl` / theme plumbing)
|
|
29
|
+
* are simply never read on the amend path (no result meta exists to
|
|
30
|
+
* emit them into).
|
|
31
|
+
*/
|
|
32
|
+
export type GguiAmendHandlerDeps = GguiUpdateHandlerDeps;
|
|
33
|
+
declare const outputSchema: {
|
|
34
|
+
readonly sessionId: z.ZodString;
|
|
35
|
+
readonly updated: z.ZodBoolean;
|
|
36
|
+
/**
|
|
37
|
+
* The BARE live-head URI — amend targets the mounted card and never
|
|
38
|
+
* mints a record, so there is no pinned URI to return and no epoch
|
|
39
|
+
* field (the history number is untouched by construction).
|
|
40
|
+
*/
|
|
41
|
+
readonly resourceUri: z.ZodString;
|
|
42
|
+
/** No-op feedback channel — same semantics as ggui_update's. */
|
|
43
|
+
readonly warning: z.ZodOptional<z.ZodString>;
|
|
44
|
+
};
|
|
45
|
+
interface AmendOutput {
|
|
46
|
+
sessionId: string;
|
|
47
|
+
updated: boolean;
|
|
48
|
+
resourceUri: string;
|
|
49
|
+
warning?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the OSS `ggui_amend` handler. Additive, like `update:` — server
|
|
53
|
+
* composers opt in via the dedicated `amend:` slot.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createGguiAmendHandler(deps: GguiAmendHandlerDeps): SharedHandler<typeof mutationInputSchema, typeof outputSchema, AmendOutput>;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=amend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amend.d.ts","sourceRoot":"","sources":["../../src/renders/amend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,mBAAmB,EAEpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAEzD,QAAA,MAAM,YAAY;;;IAGhB;;;;OAIG;;IAEH,gEAAgE;;CAExD,CAAC;AAEX,UAAU,WAAW;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,oBAAoB,GACzB,aAAa,CAAC,OAAO,mBAAmB,EAAE,OAAO,YAAY,EAAE,WAAW,CAAC,CA0B7E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ggui_amend` — in-place props mutation on the ALREADY-MOUNTED card
|
|
3
|
+
* (#483 tool split). Same wire grammar as `ggui_update`
|
|
4
|
+
* (replace/merge via the shared {@link runPropsMutation} core), the
|
|
5
|
+
* opposite mount identity:
|
|
6
|
+
*
|
|
7
|
+
* - NO history record: the head epoch is untouched by construction
|
|
8
|
+
* (the core advances it only for `ggui_update`).
|
|
9
|
+
* - NO `_meta.ui` on the tool DECLARATION and NO `resultMeta` — this
|
|
10
|
+
* is a plain data tool. Hosts never reserve a per-result view for
|
|
11
|
+
* it (hosts mint views from `_meta` on UI-bound success results —
|
|
12
|
+
* live-proven 2026-08-12), so nothing new appears in the
|
|
13
|
+
* conversation. The mounted card receives the new props over the
|
|
14
|
+
* live-channel ladder (WS / SSE / polling / bridge-pull); the
|
|
15
|
+
* spec tool-result forwarding path is deliberately not part of
|
|
16
|
+
* this tool's contract.
|
|
17
|
+
*
|
|
18
|
+
* Git reading: `ggui_update` = commit (new history entry);
|
|
19
|
+
* `ggui_amend` = commit --amend (fix up the current one).
|
|
20
|
+
*/
|
|
21
|
+
import { z } from 'zod';
|
|
22
|
+
import { mutationInputSchema, runPropsMutation, } from './props-mutation-core.js';
|
|
23
|
+
const outputSchema = {
|
|
24
|
+
sessionId: z.string(),
|
|
25
|
+
updated: z.boolean(),
|
|
26
|
+
/**
|
|
27
|
+
* The BARE live-head URI — amend targets the mounted card and never
|
|
28
|
+
* mints a record, so there is no pinned URI to return and no epoch
|
|
29
|
+
* field (the history number is untouched by construction).
|
|
30
|
+
*/
|
|
31
|
+
resourceUri: z.string(),
|
|
32
|
+
/** No-op feedback channel — same semantics as ggui_update's. */
|
|
33
|
+
warning: z.string().optional(),
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Build the OSS `ggui_amend` handler. Additive, like `update:` — server
|
|
37
|
+
* composers opt in via the dedicated `amend:` slot.
|
|
38
|
+
*/
|
|
39
|
+
export function createGguiAmendHandler(deps) {
|
|
40
|
+
return {
|
|
41
|
+
name: 'ggui_amend',
|
|
42
|
+
title: 'Amend',
|
|
43
|
+
// Deliberately NO `_meta` — see the module docstring. Declaring
|
|
44
|
+
// the UI binding here would make hosts treat amend results as
|
|
45
|
+
// renderable views, which is exactly what this tool exists to
|
|
46
|
+
// avoid.
|
|
47
|
+
audience: ['agent'],
|
|
48
|
+
description: deps.description ??
|
|
49
|
+
"Update the rendered UI's props IN PLACE — repaint the currently mounted card without adding a new card to the conversation; the history number does not advance. This is the DEFAULT mutation of the render/update family for reacting to user gestures (see ggui_update for the new-card variant). USE THIS AFTER ANY DOMAIN-TOOL CALL THAT CHANGED DATA THE UI SHOWS — e.g. you handled a `todo_toggle`/`cart_add`/`note_save` event from `ggui_consume`, mutated backend state, and the user is staring at stale props. Skipping this leaves the card frozen on the old state and is the #1 wire bug. Pattern: `consume → domain-tool → ggui_amend → loop`. The card repaints WITHOUT losing scroll position, focus, or uncommitted input. Two mutation modes: (1) `{sessionId, kind:'replace', props}` — full props replacement. (2) `{sessionId, kind:'merge', patch}` — RFC 7396 JSON Merge Patch; send ONLY the delta (null deletes a key; arrays fully replace). Prefer `merge` after a single domain-tool mutation. Both modes validate the FINAL props against the GguiSession's `propsSpec` (when declared) and reject on violation. For a state MILESTONE that deserves its own new card in the conversation — or when the original card is no longer visible or usable — use ggui_update instead (it renders the state as a new card and advances the history number).",
|
|
50
|
+
inputSchema: mutationInputSchema,
|
|
51
|
+
outputSchema,
|
|
52
|
+
async handler(input, ctx) {
|
|
53
|
+
const r = await runPropsMutation(deps, 'ggui_amend', input, ctx);
|
|
54
|
+
return {
|
|
55
|
+
sessionId: r.sessionId,
|
|
56
|
+
updated: r.updated,
|
|
57
|
+
resourceUri: r.mountResourceUri,
|
|
58
|
+
...(r.warning !== undefined ? { warning: r.warning } : {}),
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
// NO resultMeta — a `_meta`-carrying success result would make
|
|
62
|
+
// hosts mint a per-result view (live-proven), defeating the tool.
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -45,10 +45,14 @@ export type ApplyGguiSessionPatchInput<T extends GguiSessionTarget> = {
|
|
|
45
45
|
readonly render: T;
|
|
46
46
|
readonly mode: 'replace';
|
|
47
47
|
readonly props: JsonObject;
|
|
48
|
+
/** Error attribution for propsSpec violations (#483). Default `'ggui_update'`. */
|
|
49
|
+
readonly tool?: 'ggui_update' | 'ggui_amend';
|
|
48
50
|
} | {
|
|
49
51
|
readonly render: T;
|
|
50
52
|
readonly mode: 'merge';
|
|
51
53
|
readonly patch: JsonObject;
|
|
54
|
+
/** Error attribution for propsSpec violations (#483). Default `'ggui_update'`. */
|
|
55
|
+
readonly tool?: 'ggui_amend' | 'ggui_update';
|
|
52
56
|
};
|
|
53
57
|
export interface ApplyGguiSessionPatchResult<T extends GguiSessionTarget> {
|
|
54
58
|
/** The updated render (post-patch). Safe to persist. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-ggui-session-patch.d.ts","sourceRoot":"","sources":["../../src/renders/apply-ggui-session-patch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG1E;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;CAC7B;AAED,MAAM,MAAM,0BAA0B,CAAC,CAAC,SAAS,iBAAiB,IAC9D;IACE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"apply-ggui-session-patch.d.ts","sourceRoot":"","sources":["../../src/renders/apply-ggui-session-patch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG1E;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;CAC7B;AAED,MAAM,MAAM,0BAA0B,CAAC,CAAC,SAAS,iBAAiB,IAC9D;IACE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;CAC9C,GACD;IACE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC;CAC9C,CAAC;AAEN,MAAM,WAAW,2BAA2B,CAAC,CAAC,SAAS,iBAAiB;IACtE,wDAAwD;IACxD,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,UAAU,GAChB,UAAU,CAwBZ;AAED,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,iBAAiB,EAC/D,KAAK,EAAE,0BAA0B,CAAC,CAAC,CAAC,GACnC,2BAA2B,CAAC,CAAC,CAAC,CAyBhC"}
|
|
@@ -49,7 +49,7 @@ export function applyGguiSessionPatch(input) {
|
|
|
49
49
|
// unknown-key strictness. For merge mode, this catches the case
|
|
50
50
|
// where the patch's null-delete would orphan a required field, or
|
|
51
51
|
// a recursive merge would introduce an undeclared key.
|
|
52
|
-
assertPropsContract(existing.propsSpec, finalProps);
|
|
52
|
+
assertPropsContract(existing.propsSpec, finalProps, input.tool ?? 'ggui_update');
|
|
53
53
|
// Spread preserves T's other fields; the `props` override lands on
|
|
54
54
|
// top. The spread infers `T & { props: JsonObject }`, which is
|
|
55
55
|
// assignable to `T` — no cast needed.
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* Contract:
|
|
6
6
|
* - `spec === undefined` → no-op (matches legacy ggui_update: missing
|
|
7
7
|
* propsSpec is permissive, no validation runs).
|
|
8
|
-
* - Otherwise validate; on failure throw `ContractViolationError`
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* - Otherwise validate; on failure throw `ContractViolationError`
|
|
9
|
+
* attributed to the calling tool (`ggui_update` by default —
|
|
10
|
+
* `ggui_amend` threads its own name, #483) so the error envelope
|
|
11
|
+
* names the tool the agent actually called.
|
|
11
12
|
*
|
|
12
13
|
* This helper is the centralized enforcement point for props contracts —
|
|
13
14
|
* every mutation path that applies new props to a render SHOULD go
|
|
@@ -15,5 +16,5 @@
|
|
|
15
16
|
* bypass validation entirely.
|
|
16
17
|
*/
|
|
17
18
|
import { type PropsSpec } from '@ggui-ai/protocol';
|
|
18
|
-
export declare function assertPropsContract(spec: PropsSpec | undefined, patch: Record<string, unknown
|
|
19
|
+
export declare function assertPropsContract(spec: PropsSpec | undefined, patch: Record<string, unknown>, tool?: 'ggui_update' | 'ggui_amend'): void;
|
|
19
20
|
//# sourceMappingURL=assert-props-contract.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-props-contract.d.ts","sourceRoot":"","sources":["../../src/renders/assert-props-contract.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"assert-props-contract.d.ts","sourceRoot":"","sources":["../../src/renders/assert-props-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,mBAAmB,CAAC;AAE3B,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,GAAG,SAAS,EAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,GAAE,aAAa,GAAG,YAA4B,GACjD,IAAI,CASN"}
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* Contract:
|
|
6
6
|
* - `spec === undefined` → no-op (matches legacy ggui_update: missing
|
|
7
7
|
* propsSpec is permissive, no validation runs).
|
|
8
|
-
* - Otherwise validate; on failure throw `ContractViolationError`
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* - Otherwise validate; on failure throw `ContractViolationError`
|
|
9
|
+
* attributed to the calling tool (`ggui_update` by default —
|
|
10
|
+
* `ggui_amend` threads its own name, #483) so the error envelope
|
|
11
|
+
* names the tool the agent actually called.
|
|
11
12
|
*
|
|
12
13
|
* This helper is the centralized enforcement point for props contracts —
|
|
13
14
|
* every mutation path that applies new props to a render SHOULD go
|
|
@@ -15,13 +16,13 @@
|
|
|
15
16
|
* bypass validation entirely.
|
|
16
17
|
*/
|
|
17
18
|
import { ContractViolationError, validatePropsData, } from '@ggui-ai/protocol';
|
|
18
|
-
export function assertPropsContract(spec, patch) {
|
|
19
|
+
export function assertPropsContract(spec, patch, tool = 'ggui_update') {
|
|
19
20
|
if (!spec)
|
|
20
21
|
return;
|
|
21
22
|
const result = validatePropsData(patch, spec);
|
|
22
23
|
if (!result.valid) {
|
|
23
24
|
throw new ContractViolationError({
|
|
24
|
-
tool
|
|
25
|
+
tool,
|
|
25
26
|
violations: result.violations,
|
|
26
27
|
});
|
|
27
28
|
}
|