glasspane-mcp 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dispatch.d.ts +1 -1
- package/dist/engine-client.d.ts +30 -4
- package/dist/index.js +136 -9
- package/dist/tools.d.ts +34 -4
- package/package.json +1 -1
package/dist/dispatch.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare const MCP_PROTOCOL_VERSION: "2025-06-18";
|
|
|
26
26
|
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly string[];
|
|
27
27
|
export declare const SERVER_INFO: {
|
|
28
28
|
readonly name: "glasspane-mcp";
|
|
29
|
-
readonly version: "1.1.
|
|
29
|
+
readonly version: "1.1.2";
|
|
30
30
|
};
|
|
31
31
|
export declare const PARSE_ERROR = -32700;
|
|
32
32
|
export declare const INVALID_REQUEST = -32600;
|
package/dist/engine-client.d.ts
CHANGED
|
@@ -12,10 +12,36 @@ export declare function daemonUnreachableRemedy(): string;
|
|
|
12
12
|
/** Env override for the daemon socket path (default below). */
|
|
13
13
|
export declare const ENGINE_SOCKET_ENV = "GLASSPANE_ENGINE_SOCK";
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* path
|
|
18
|
-
*
|
|
15
|
+
* Where this shell connects when nothing was named, in order: `GLASSPANE_ENGINE_SOCK`
|
|
16
|
+
* (the env var {@link ENGINE_SOCKET_ENV} spells), then the explicit
|
|
17
|
+
* `--socket-path` this shell's own CLI accepts, then the fallback below.
|
|
18
|
+
*
|
|
19
|
+
* The fallback is a **guess made from `$HOME`**, and it is worth being exact
|
|
20
|
+
* about which guess: `os.homedir()` reads `$HOME`, while the daemon's own
|
|
21
|
+
* default is `StateRoot.homeDefault()` = `NSHomeDirectory() + "/.glasspane"`,
|
|
22
|
+
* which on macOS does **not** consult `$HOME` — the same non-inheritance that
|
|
23
|
+
* has already cost this project real data, and the reason a caller cannot
|
|
24
|
+
* isolate a run by exporting `HOME`. So in a process whose `$HOME` points into
|
|
25
|
+
* a sandbox the two sides resolve **different directories**: this shell goes
|
|
26
|
+
* looking for `$HOME/.glasspane/engine.sock` inside the sandbox while the daemon
|
|
27
|
+
* is still serving only the socket under the real home. Nor is there a third
|
|
28
|
+
* case to cover by guessing better — a daemon started with `--state-dir <root>`
|
|
29
|
+
* listens on `<root>/daemon.sock`, which no value of `$HOME` points at.
|
|
30
|
+
*
|
|
31
|
+
* The reliable route is therefore to stop deriving and to say which socket: set
|
|
32
|
+
* `GLASSPANE_ENGINE_SOCK`, or pass `--socket-path`. The installer's launchd job
|
|
33
|
+
* hands the daemon an explicit `--socket-path` already, which is what makes an
|
|
34
|
+
* installed pair agree — so read that value back rather than recomputing it;
|
|
35
|
+
* this shell's `--help` gives the command.
|
|
36
|
+
*
|
|
37
|
+
* Deliberately not "fixed" by asking the daemon: before a connection exists
|
|
38
|
+
* there is no daemon to ask, and `hello` is itself answered after connecting.
|
|
39
|
+
* Matching the daemon's home lookup from Node would take an FFI call to
|
|
40
|
+
* `NSHomeDirectory()`, which this shell does not have.
|
|
41
|
+
*
|
|
42
|
+
* Single source all the same: the CLI argument parser in index.ts and the
|
|
43
|
+
* reconnecting transport both resolve the path through this function, so an env
|
|
44
|
+
* override cannot be honoured on one side only.
|
|
19
45
|
*/
|
|
20
46
|
export declare function defaultSocketPath(): string;
|
|
21
47
|
/** Fallback deadline for a method missing from the table below. */
|
package/dist/index.js
CHANGED
|
@@ -1075,9 +1075,11 @@ function evidenceSummaryLines(pack) {
|
|
|
1075
1075
|
}
|
|
1076
1076
|
const act = pack.signals.act;
|
|
1077
1077
|
lines.push(`act ${act.action} ${selectorText(act.selector)}: ${act.actConfirmed ? "confirmed" : "rejected"}`);
|
|
1078
|
-
if (pack.signals.axEvent !== void 0) {
|
|
1078
|
+
if (pack.signals.axEvent !== void 0 && pack.signals.axEvent !== null) {
|
|
1079
1079
|
const ax = pack.signals.axEvent;
|
|
1080
1080
|
lines.push(`axEvent: changed=${ax.axChanged} nodes=${ax.nodeCount} latencyMs=${doubleText(ax.latencyMs)}`);
|
|
1081
|
+
} else {
|
|
1082
|
+
lines.push(AX_EVENT_NOT_MEASURED);
|
|
1081
1083
|
}
|
|
1082
1084
|
lines.push(
|
|
1083
1085
|
pack.signals.handlerProbe !== void 0 && pack.signals.handlerProbe !== null ? handlerProbeText(pack.signals.handlerProbe) : HANDLER_PROBE_NOT_MEASURED
|
|
@@ -1085,7 +1087,7 @@ function evidenceSummaryLines(pack) {
|
|
|
1085
1087
|
lines.push(
|
|
1086
1088
|
pack.signals.stateDiff !== void 0 && pack.signals.stateDiff !== null ? stateDiffText(pack.signals.stateDiff) : STATE_DIFF_NOT_MEASURED
|
|
1087
1089
|
);
|
|
1088
|
-
if (pack.signals.pixelDiff !== void 0) {
|
|
1090
|
+
if (pack.signals.pixelDiff !== void 0 && pack.signals.pixelDiff !== null) {
|
|
1089
1091
|
const px = pack.signals.pixelDiff;
|
|
1090
1092
|
let line = `pixelDiff: changedRatio=${doubleText(px.changedPixelRatio)} windowId=${px.windowId}`;
|
|
1091
1093
|
if (px.bounds !== null) {
|
|
@@ -1093,14 +1095,20 @@ function evidenceSummaryLines(pack) {
|
|
|
1093
1095
|
line += ` bounds=${doubleText(b.x)},${doubleText(b.y)},${doubleText(b.width)},${doubleText(b.height)}`;
|
|
1094
1096
|
}
|
|
1095
1097
|
lines.push(line);
|
|
1098
|
+
} else {
|
|
1099
|
+
lines.push(PIXEL_DIFF_NOT_MEASURED);
|
|
1096
1100
|
}
|
|
1097
|
-
if (pack.signals.responsiveness !== void 0) {
|
|
1101
|
+
if (pack.signals.responsiveness !== void 0 && pack.signals.responsiveness !== null) {
|
|
1098
1102
|
const r = pack.signals.responsiveness;
|
|
1099
1103
|
lines.push(`responsiveness: responsive=${r.responsive} pingMs=${doubleText(r.pingMs)}`);
|
|
1104
|
+
} else {
|
|
1105
|
+
lines.push(RESPONSIVENESS_NOT_MEASURED);
|
|
1100
1106
|
}
|
|
1101
|
-
if (pack.signals.crash !== void 0) {
|
|
1107
|
+
if (pack.signals.crash !== void 0 && pack.signals.crash !== null) {
|
|
1102
1108
|
const c = pack.signals.crash;
|
|
1103
1109
|
lines.push(`crash: aliveBefore=${c.processAliveBefore} aliveAfter=${c.processAliveAfter}`);
|
|
1110
|
+
} else {
|
|
1111
|
+
lines.push(CRASH_NOT_MEASURED);
|
|
1104
1112
|
}
|
|
1105
1113
|
return lines;
|
|
1106
1114
|
}
|
|
@@ -1154,6 +1162,10 @@ function escapeHTML(value) {
|
|
|
1154
1162
|
var NO_DIAGNOSIS_TEXT = "\u2014 (no diagnosis recorded: this pack carries none; run gp_diagnose for this operationId, then gp_export_evidence again)";
|
|
1155
1163
|
var HANDLER_PROBE_NOT_MEASURED = "handlerProbe: not measured (no probe connection served this act window)";
|
|
1156
1164
|
var STATE_DIFF_NOT_MEASURED = "stateDiff: not measured (the probe reported no state channel)";
|
|
1165
|
+
var AX_EVENT_NOT_MEASURED = "axEvent: not measured (this pack carries no AX tree digest)";
|
|
1166
|
+
var PIXEL_DIFF_NOT_MEASURED = "pixelDiff: not measured (this pack carries no pixel comparison)";
|
|
1167
|
+
var RESPONSIVENESS_NOT_MEASURED = "responsiveness: not measured (this pack carries no responsiveness round trip)";
|
|
1168
|
+
var CRASH_NOT_MEASURED = "crash: not measured (this pack carries no process liveness sample)";
|
|
1157
1169
|
var MAX_HANDLERS_SHOWN = 8;
|
|
1158
1170
|
var MAX_ENTRIES_SHOWN = 8;
|
|
1159
1171
|
function sections(pack, diagnostics) {
|
|
@@ -1736,6 +1748,15 @@ var ObserveArgs = z5.strictObject({
|
|
|
1736
1748
|
maxDepth: OptionalDepthSchema,
|
|
1737
1749
|
role: OptionalRoleSchema
|
|
1738
1750
|
});
|
|
1751
|
+
var OptionalHitTargetSchema = z5.number().min(1).max(400).optional();
|
|
1752
|
+
var OptionalScaleSchema = z5.number().min(0.1).max(1).optional();
|
|
1753
|
+
var CaptureViewArgs = z5.strictObject({
|
|
1754
|
+
scale: OptionalScaleSchema
|
|
1755
|
+
});
|
|
1756
|
+
var AuditUiArgs = z5.strictObject({
|
|
1757
|
+
maxDepth: OptionalDepthSchema,
|
|
1758
|
+
minHitTargetPt: OptionalHitTargetSchema
|
|
1759
|
+
});
|
|
1739
1760
|
var ActArgs = z5.strictObject({
|
|
1740
1761
|
selector: SelectorSchema,
|
|
1741
1762
|
action: ActionSchema,
|
|
@@ -1828,7 +1849,7 @@ var TOOL_SPECS = [
|
|
|
1828
1849
|
},
|
|
1829
1850
|
{
|
|
1830
1851
|
name: "gp_act",
|
|
1831
|
-
description: "Perform a UI action on the attached app and confirm it. If the daemon reports GP_E_BUSY_INPUT (real user input is contaminating the window), retry later, or set degrade: true to proceed immediately with the contamination recorded in evidence (attribution becomes weak + contaminated=true) \u2014 never silently clean.",
|
|
1852
|
+
description: "Perform a UI action on the attached app and confirm it. If the daemon reports GP_E_BUSY_INPUT (real user input is contaminating the window), retry later, or set degrade: true to proceed immediately with the contamination recorded in evidence (attribution becomes weak + contaminated=true) \u2014 never silently clean. Prefer selector.identifier over selector.title to name the element: a title is not a stable handle (a measured case: every act against a title-keyed selector reported actConfirmed while the app's handler never ran, because the press resolved to something that was not the button). actConfirmed means the accessibility action was accepted \u2014 not that the intended element handled it; to prove the click itself, read the probe's handler hit or the state change, or assert_element against a value that the action is supposed to change.",
|
|
1832
1853
|
engineMethod: "act",
|
|
1833
1854
|
inputSchema: {
|
|
1834
1855
|
type: "object",
|
|
@@ -1861,6 +1882,34 @@ var TOOL_SPECS = [
|
|
|
1861
1882
|
},
|
|
1862
1883
|
validate: zodBridge(AssertElementArgs)
|
|
1863
1884
|
},
|
|
1885
|
+
{
|
|
1886
|
+
name: "gp_audit_ui",
|
|
1887
|
+
description: "Audit the attached app's layout for operability: element geometry plus deterministic rules report zero-sized or out-of-window controls (blocking), undersized hit targets, clipped elements and frame overlaps (advisory). The verdict distinguishes pass from insufficient: unmeasured geometry never counts as a clean result. Read-only \u2014 it records no operation.",
|
|
1888
|
+
engineMethod: "audit_ui",
|
|
1889
|
+
inputSchema: {
|
|
1890
|
+
type: "object",
|
|
1891
|
+
additionalProperties: false,
|
|
1892
|
+
properties: {
|
|
1893
|
+
maxDepth: { type: "integer", minimum: 1, maximum: 10 },
|
|
1894
|
+
minHitTargetPt: { type: "number", minimum: 1, maximum: 400 }
|
|
1895
|
+
}
|
|
1896
|
+
},
|
|
1897
|
+
validate: zodBridge(AuditUiArgs)
|
|
1898
|
+
},
|
|
1899
|
+
{
|
|
1900
|
+
name: "gp_capture_view",
|
|
1901
|
+
description: "Send the attached app's current window to your model once, as a PNG, for visual review. This is the only tool that moves image pixels, and it is a pass-through: the engine encodes the capture and writes nothing to disk (the result says persisted: false). Use it for what measurements cannot judge \u2014 visual taste, layout that reads as wrong, content with no accessibility tree. For anything assertable, prefer gp_audit_ui / gp_assert_element: a measurement repeats, a visual impression does not. `scale` is a pixel-density factor applied to the captured image (window size is reported separately in points as pointSize), and the summary states both the requested scale and the appliedScale actually present in the image. WARNING: the image enters this conversation, so anything your model provider logs will retain whatever was on screen. Needs the daemon's Screen Recording grant; oversized windows are refused with a suggested scale rather than silently downsampled.",
|
|
1902
|
+
engineMethod: "capture_view",
|
|
1903
|
+
inputSchema: {
|
|
1904
|
+
type: "object",
|
|
1905
|
+
additionalProperties: false,
|
|
1906
|
+
properties: {
|
|
1907
|
+
scale: { type: "number", minimum: 0.1, maximum: 1 }
|
|
1908
|
+
}
|
|
1909
|
+
},
|
|
1910
|
+
validate: zodBridge(CaptureViewArgs),
|
|
1911
|
+
execute: captureView
|
|
1912
|
+
},
|
|
1864
1913
|
{
|
|
1865
1914
|
name: "gp_diagnose",
|
|
1866
1915
|
description: "Diagnose the most recent (or the given) operation.",
|
|
@@ -1934,7 +1983,7 @@ var TOOL_SPECS = [
|
|
|
1934
1983
|
},
|
|
1935
1984
|
{
|
|
1936
1985
|
name: "gp_probe_status",
|
|
1937
|
-
description: "List GlassPaneProbe connections and whether the attached app has a live probe \u2014 probe presence is what makes T4/T5/T7/T8 verdicts and tier-1 checkpoint restores decidable. `probes` holds **live** registrations only (every row `connected: true`), so a probe that dropped is absent from it rather than flagged inside it: read `recentDisconnections` for that history (`pid`, `disconnectReason`, `disconnectedAt`, per-pid `drops`), and `disconnections` is just the total count since start. Each live row can also carry the frame-accounting that makes a zero verdict readable: `stateFramesUnmappedSource` (daemon-side, per pid), and `droppedEvents` / `droppedWrites` / `rejectedKeys` as the probe itself reported them \u2014 those are **absent when unreported**, which is not the same as zero, and `unmapableStateFrames` is the daemon-side total that survives a disconnect.",
|
|
1986
|
+
description: "List GlassPaneProbe connections and whether the attached app has a live probe \u2014 probe presence is what makes T4/T5/T7/T8 verdicts and tier-1 checkpoint restores decidable. `attachedHasProbe` is that yes/no for the attached app; `probes` holds **live** registrations only (every row `connected: true`), so a probe that dropped is absent from it rather than flagged inside it: read `recentDisconnections` for that history (`pid`, `disconnectReason`, `disconnectedAt`, per-pid `drops`), and `disconnections` is just the total count since start. Each live row can also carry the frame-accounting that makes a zero verdict readable: `stateFramesUnmappedSource` (daemon-side, per pid), and `droppedEvents` / `droppedWrites` / `rejectedKeys` as the probe itself reported them \u2014 those are **absent when unreported**, which is not the same as zero, and `unmapableStateFrames` is the daemon-side total that survives a disconnect. The same reply is where the T9 degradation watch is readable without performing an action, under `degradation` (absent when this daemon runs without T9 wired): `tier` is `healthy` / `watch` / `degrading`, and `judged` says whether that tier is a measurement at all \u2014 `judged: false` with `tier: healthy` means the window was too thin or too short to read, **not** that the app is clean; `basis` spells out which of those it is with the numbers, alongside `samples`/`minimumSamples` and `spanSeconds`/`minimumSpanSeconds`. `longSession` marks the window spanning at least the long-session threshold; it is context for the trend, and it never changes `tier` by itself. `drivers` appears only when something is trending, and `slopes` carries only the channels that produced one (`pingMsPerSec`, `memoryBytesPerSec`, `handlesPerSec`) \u2014 a channel missing from `slopes` was never read, which is not a rate of zero.",
|
|
1938
1987
|
engineMethod: "probe_status",
|
|
1939
1988
|
inputSchema: {
|
|
1940
1989
|
type: "object",
|
|
@@ -2161,6 +2210,69 @@ function packForReport(pack, measuredSchemaVersion) {
|
|
|
2161
2210
|
}
|
|
2162
2211
|
return { ...pack, schemaVersion: `${measuredSchemaVersion} (read as ${pack.schemaVersion})` };
|
|
2163
2212
|
}
|
|
2213
|
+
async function captureView(args, context) {
|
|
2214
|
+
try {
|
|
2215
|
+
const raw = await context.engine.call("capture_view", args);
|
|
2216
|
+
const body = raw ?? {};
|
|
2217
|
+
const png = body.pngBase64;
|
|
2218
|
+
if (typeof png !== "string" || png.length === 0) {
|
|
2219
|
+
return {
|
|
2220
|
+
content: [{ type: "text", text: formatToolError(
|
|
2221
|
+
GP_E_INTERNAL,
|
|
2222
|
+
"capture_view answered without a pngBase64 payload",
|
|
2223
|
+
"retry once; if it repeats, report this \u2014 the engine captured but the shell could not read the image"
|
|
2224
|
+
) }],
|
|
2225
|
+
isError: true
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
if (body.persisted !== false) {
|
|
2229
|
+
return {
|
|
2230
|
+
content: [{ type: "text", text: formatToolError(
|
|
2231
|
+
GP_E_INTERNAL,
|
|
2232
|
+
`capture_view answered without persisted:false (got ${JSON.stringify(body.persisted ?? null)})`,
|
|
2233
|
+
"do not treat this image as unsaved: the engine did not say so. Retry once, then report the frame shape \u2014 the pass-through guarantee is a claim about the protocol, not a default the shell may fill in"
|
|
2234
|
+
) }],
|
|
2235
|
+
isError: true
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
2238
|
+
const mimeType = typeof body.mimeType === "string" && body.mimeType.length > 0 ? body.mimeType : "image/png";
|
|
2239
|
+
const summary = canonicalJson({
|
|
2240
|
+
mimeType,
|
|
2241
|
+
byteCount: body.byteCount,
|
|
2242
|
+
pixelWidth: body.pixelWidth,
|
|
2243
|
+
pixelHeight: body.pixelHeight,
|
|
2244
|
+
scale: body.scale,
|
|
2245
|
+
// 实际应用的倍率与请求值都给出:静默降采样失败时,"appliedScale" 才是
|
|
2246
|
+
// 模型该信的那个数(它决定自己看到的是不是缩过的版本)。
|
|
2247
|
+
appliedScale: body.appliedScale,
|
|
2248
|
+
windowId: body.windowId,
|
|
2249
|
+
pointSize: body.pointSize,
|
|
2250
|
+
persisted: body.persisted
|
|
2251
|
+
});
|
|
2252
|
+
return {
|
|
2253
|
+
content: [
|
|
2254
|
+
{ type: "image", data: png, mimeType },
|
|
2255
|
+
{ type: "text", text: summary }
|
|
2256
|
+
],
|
|
2257
|
+
isError: false
|
|
2258
|
+
};
|
|
2259
|
+
} catch (error) {
|
|
2260
|
+
if (error instanceof EngineCallError) {
|
|
2261
|
+
return {
|
|
2262
|
+
content: [{ type: "text", text: formatToolErrorShape(error.toBody()) }],
|
|
2263
|
+
isError: true
|
|
2264
|
+
};
|
|
2265
|
+
}
|
|
2266
|
+
return {
|
|
2267
|
+
content: [{ type: "text", text: formatToolError(
|
|
2268
|
+
GP_E_INTERNAL,
|
|
2269
|
+
`internal shell error: ${String(error)}`,
|
|
2270
|
+
"see the MCP server logs and retry"
|
|
2271
|
+
) }],
|
|
2272
|
+
isError: true
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2164
2276
|
function mapEvidenceReadError(error) {
|
|
2165
2277
|
if (error instanceof EvidenceFrameShapeError) {
|
|
2166
2278
|
return {
|
|
@@ -2350,7 +2462,7 @@ var SUPPORTED_PROTOCOL_VERSIONS = [
|
|
|
2350
2462
|
"2025-03-26",
|
|
2351
2463
|
MCP_PROTOCOL_VERSION
|
|
2352
2464
|
];
|
|
2353
|
-
var SERVER_INFO = { name: "glasspane-mcp", version: "1.1.
|
|
2465
|
+
var SERVER_INFO = { name: "glasspane-mcp", version: "1.1.2" };
|
|
2354
2466
|
var PARSE_ERROR = -32700;
|
|
2355
2467
|
var INVALID_REQUEST = -32600;
|
|
2356
2468
|
var METHOD_NOT_FOUND = -32601;
|
|
@@ -2499,8 +2611,23 @@ function parseArgs(argv) {
|
|
|
2499
2611
|
var USAGE = `usage: glasspane-mcp [--socket-path <path>]
|
|
2500
2612
|
|
|
2501
2613
|
Bridges an AI agent (MCP stdio) to the GlassPane engine daemon.
|
|
2502
|
-
|
|
2503
|
-
|
|
2614
|
+
|
|
2615
|
+
Socket, in the order this shell resolves it:
|
|
2616
|
+
1. --socket-path <path>
|
|
2617
|
+
2. GLASSPANE_ENGINE_SOCK=<path>
|
|
2618
|
+
3. $HOME/.glasspane/engine.sock \u2014 a guess read from this process's HOME, not
|
|
2619
|
+
the daemon's rule: glasspaned's own default is the home folder the system
|
|
2620
|
+
reports, which a HOME you export does not move, and glasspaned --state-dir
|
|
2621
|
+
<dir> serves <dir>/daemon.sock instead.
|
|
2622
|
+
|
|
2623
|
+
So "nothing is listening on the default path" means this shell guessed a
|
|
2624
|
+
different directory, not that the daemon is dead. Connect to the socket the
|
|
2625
|
+
daemon is really on \u2014 read it, do not re-derive it:
|
|
2626
|
+
launchctl print gui/$(id -u)/com.glasspane.daemon # the installed job's --socket-path value
|
|
2627
|
+
glasspane-mcp --socket-path <that path> # or, equivalently:
|
|
2628
|
+
GLASSPANE_ENGINE_SOCK=<that path> glasspane-mcp
|
|
2629
|
+
A daemon started by hand with --state-dir has no launchd job to read: pass it
|
|
2630
|
+
<state-dir>/daemon.sock.
|
|
2504
2631
|
`;
|
|
2505
2632
|
var DRAIN_WAIT_MS = 3e4;
|
|
2506
2633
|
function logNote(text) {
|
package/dist/tools.d.ts
CHANGED
|
@@ -44,6 +44,25 @@ export declare const ObserveArgs: z.ZodObject<{
|
|
|
44
44
|
maxDepth?: number | undefined;
|
|
45
45
|
}>;
|
|
46
46
|
export type ObserveArgs = z.infer<typeof ObserveArgs>;
|
|
47
|
+
export declare const CaptureViewArgs: z.ZodObject<{
|
|
48
|
+
scale: z.ZodOptional<z.ZodNumber>;
|
|
49
|
+
}, "strict", z.ZodTypeAny, {
|
|
50
|
+
scale?: number | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
scale?: number | undefined;
|
|
53
|
+
}>;
|
|
54
|
+
export type CaptureViewArgs = z.infer<typeof CaptureViewArgs>;
|
|
55
|
+
export declare const AuditUiArgs: z.ZodObject<{
|
|
56
|
+
maxDepth: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
minHitTargetPt: z.ZodOptional<z.ZodNumber>;
|
|
58
|
+
}, "strict", z.ZodTypeAny, {
|
|
59
|
+
maxDepth?: number | undefined;
|
|
60
|
+
minHitTargetPt?: number | undefined;
|
|
61
|
+
}, {
|
|
62
|
+
maxDepth?: number | undefined;
|
|
63
|
+
minHitTargetPt?: number | undefined;
|
|
64
|
+
}>;
|
|
65
|
+
export type AuditUiArgs = z.infer<typeof AuditUiArgs>;
|
|
47
66
|
export declare const ActArgs: z.ZodObject<{
|
|
48
67
|
selector: z.ZodObject<{
|
|
49
68
|
role: z.ZodString;
|
|
@@ -248,12 +267,23 @@ export interface ToolExecuteContext {
|
|
|
248
267
|
*/
|
|
249
268
|
turn: TrailTurn;
|
|
250
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Content parts a tool may return. `image` exists for exactly one tool:
|
|
272
|
+
* `gp_capture_view`, whose whole point is handing one window image to the
|
|
273
|
+
* user's own model. It is a pass-through, not a store — the shell writes
|
|
274
|
+
* nothing to disk, so "no raw screenshot is persisted anywhere" stays true.
|
|
275
|
+
*/
|
|
276
|
+
export type ToolContent = {
|
|
277
|
+
type: "text";
|
|
278
|
+
text: string;
|
|
279
|
+
} | {
|
|
280
|
+
type: "image";
|
|
281
|
+
data: string;
|
|
282
|
+
mimeType: string;
|
|
283
|
+
};
|
|
251
284
|
/** Tool result shape shared by the default path and custom executors. */
|
|
252
285
|
export interface ToolResult {
|
|
253
|
-
content:
|
|
254
|
-
type: "text";
|
|
255
|
-
text: string;
|
|
256
|
-
}>;
|
|
286
|
+
content: ToolContent[];
|
|
257
287
|
isError: boolean;
|
|
258
288
|
}
|
|
259
289
|
export declare const TOOL_SPECS: readonly ToolSpec[];
|
package/package.json
CHANGED