@pome-sh/cli 0.23.1 → 0.23.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 CHANGED
@@ -79,8 +79,19 @@ Three rules CI must honor:
79
79
  whose criteria could not all be graded exits `1` rather than mapping its
80
80
  partial score to a code — a run whose checks never ran is not a green CI
81
81
  signal. The cost is stated rather than hidden: **`1` cannot tell "the agent
82
- regressed" from "we could not grade it."** Read the verdict word printed
83
- beside the score (`INCOMPLETE` vs a sub-threshold number) to separate them.
82
+ regressed" from "we could not grade it."** To separate them programmatically,
83
+ do not compare `score` against `pass_threshold` yourself a run with a third
84
+ of its criteria unevaluated can still read `score: 100, pass_threshold: 100`
85
+ with nothing in those two fields alone saying so. Read `state` in the
86
+ `verdict.json` a hosted `pome run` writes to
87
+ `<artifacts-dir>/<task-slug>/<session-id>/verdict.json`: `"pass"`, `"fail"`,
88
+ or `"incomplete"` — the same word the terminal prints beside the score, and
89
+ the field to gate on. The `evaluated` / `not_evaluated` / `pre_satisfied` /
90
+ `total` counts alongside it say how much of the task `score` covers:
91
+ **`score` is a percentage over `evaluated` alone**, so `not_evaluated > 0`
92
+ means `score` is silent about part of the run, and `evaluated: 0` means it
93
+ scored nothing at all (the cloud sends `0` there for want of a denominator
94
+ — "nothing was scored", not "nothing was correct").
84
95
  - **Trial groups map as a whole.** `pome run -n k` (k>1) collapses the whole
85
96
  group to one code: `0` = at least one trial completed and every completed
86
97
  trial passed; `1` = at least one completed trial failed its threshold **or was
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "pome-sh",
3
- "version": "0.23.1",
4
- "git_sha": "f57142b584d0bbeaa6b1c3e6194daf2723ed6d3c",
5
- "build_time": "2026-08-10T12:44:52.803Z"
3
+ "version": "0.23.3",
4
+ "git_sha": "204c5f6614ced8b27fca8c26a0ca11ce0f618b2b",
5
+ "build_time": "2026-08-10T14:34:56.429Z"
6
6
  }
@@ -183,7 +183,7 @@ async function checkTwinReachable(_configDir) {
183
183
  });
184
184
  let harness;
185
185
  try {
186
- const { bootTwin } = await import('./twinHarness-5CKZY7OP.js');
186
+ const { bootTwin } = await import('./twinHarness-VH4HVKSS.js');
187
187
  harness = await bootTwin({
188
188
  twin: "github",
189
189
  seedState: void 0,
@@ -1,4 +1,4 @@
1
- import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-5GDTUVXT.js';
1
+ import { TWIN_NAMES, isTwinName, TWIN_REGISTRY } from './chunk-T6ZGCJSG.js';
2
2
  import { createFileBackedRecorderStore, createRecorderStore } from './chunk-TV5S6WQV.js';
3
3
 
4
4
  // src/recorder/recorder.ts
@@ -2,7 +2,7 @@ import { criterionSchema, finalizeResponseSchema, HostedDiscardRefusedError, Hos
2
2
  import { seedSchema, parseSeed, defaultSeedState as defaultSeedState$2 } from './chunk-SGDUD7KK.js';
3
3
  import { gmailSeedSchema, defaultSeedState } from './chunk-NJ246QPJ.js';
4
4
  import { linearSeedSchema, defaultSeedState as defaultSeedState$1 } from './chunk-ZKID2HS3.js';
5
- import { isTwinName, TWIN_REGISTRY } from './chunk-5GDTUVXT.js';
5
+ import { isTwinName, TWIN_REGISTRY } from './chunk-T6ZGCJSG.js';
6
6
  import { toTwinHttpEventRow } from './chunk-TV5S6WQV.js';
7
7
  import { redactEvent, redactSecrets } from './chunk-SG6ZTIMT.js';
8
8
  import { mkdir, appendFile, writeFile, readFile } from 'node:fs/promises';
@@ -1265,15 +1265,23 @@ function twinSkipSuffix(result) {
1265
1265
  function criteriaWord(n) {
1266
1266
  return n === 1 ? "criterion" : "criteria";
1267
1267
  }
1268
+ function evaluationCounts(score) {
1269
+ const evaluated = score.total_required;
1270
+ const notEvaluated = score.skipped + score.errored - score.preSatisfied;
1271
+ return {
1272
+ evaluated,
1273
+ notEvaluated,
1274
+ preSatisfied: score.preSatisfied,
1275
+ total: evaluated + notEvaluated + score.preSatisfied
1276
+ };
1277
+ }
1268
1278
  function scoreCountsSummary(score) {
1269
1279
  return `${score.passed ?? 0} passed, ${score.failed ?? 0} failed, ${score.skipped ?? 0} skipped, ${score.errored ?? 0} errored`;
1270
1280
  }
1271
1281
  function runScoreLine(score, passThreshold, unevaluatedNumericLabel) {
1272
1282
  const status = scoreStatus(score, passThreshold);
1273
1283
  if (status === "incomplete") {
1274
- const allExcluded = score.skipped + score.errored;
1275
- const unreached = allExcluded - score.preSatisfied;
1276
- const total = score.total_required + allExcluded;
1284
+ const { notEvaluated: unreached, total } = evaluationCounts(score);
1277
1285
  if (score.total_required === 0 && unreached === 0 && score.preSatisfied > 0) {
1278
1286
  return `score: incomplete \u2014 nothing was at risk (${score.preSatisfied} ${criteriaWord(score.preSatisfied)} already true in the seed); ${scoreCountsSummary(score)}; ${unevaluatedNumericLabel}: ${score.satisfaction}/100`;
1279
1287
  }
@@ -1630,4 +1638,4 @@ function splitCommand(command) {
1630
1638
  return file ? { file, args } : null;
1631
1639
  }
1632
1640
 
1633
- export { createHostedClient, criterionMarkerLabel, isPreSatisfied, markerFor, outcomeOf, parseGitHubSeedState, parseTaskFile, perTwinReturnedByCloud, readCodeCriteria, readConfigTwins, readLatestRun, readMetaSummary, redactJsonl, runAgentCommand, runScoreLine, scoreCountsSummary, scoreFromFinalizeResponse, scoreStatus, seedStateForTwin, toTwinHttpEvent, twinSkipSuffix, uploadRunBlobs, writeRunArtifactsCore };
1641
+ export { createHostedClient, criterionMarkerLabel, evaluationCounts, isPreSatisfied, markerFor, outcomeOf, parseGitHubSeedState, parseTaskFile, perTwinReturnedByCloud, readCodeCriteria, readConfigTwins, readLatestRun, readMetaSummary, redactJsonl, runAgentCommand, runScoreLine, scoreCountsSummary, scoreFromFinalizeResponse, scoreStatus, seedStateForTwin, toTwinHttpEvent, twinSkipSuffix, uploadRunBlobs, writeRunArtifactsCore };
@@ -1,7 +1,7 @@
1
1
  import { getAvailablePort } from './chunk-XDU6TD4O.js';
2
2
  import { buildEgressAllowlist, readBlockedEgress } from './chunk-CBFKZZBR.js';
3
- import { parseTaskFile, seedStateForTwin, runAgentCommand, writeRunArtifactsCore } from './chunk-Z32CZ45D.js';
4
- import { createRecorder, bootTwin } from './chunk-TG22SRUL.js';
3
+ import { parseTaskFile, seedStateForTwin, runAgentCommand, writeRunArtifactsCore } from './chunk-LI7RLYVA.js';
4
+ import { createRecorder, bootTwin } from './chunk-2R46XQAL.js';
5
5
  import { eventSchema } from './chunk-VBATFCWR.js';
6
6
  import { redactSecrets, redactEvent } from './chunk-SG6ZTIMT.js';
7
7
  import { serve } from '@hono/node-server';
@@ -12,7 +12,7 @@ var package_default3 = {
12
12
 
13
13
  // ../packages/twin-gmail/package.json
14
14
  var package_default4 = {
15
- version: "0.3.6"};
15
+ version: "0.4.0"};
16
16
 
17
17
  // ../packages/twin-linear/package.json
18
18
  var package_default5 = {
@@ -128,9 +128,9 @@ var TWIN_REGISTRY = {
128
128
  portEnvName: "GMAIL_TWIN_PORT",
129
129
  tokenEnvName: "POME_GMAIL_TOKEN",
130
130
  version: package_default4.version,
131
- defaultSeed: async () => (await import('./src-RK3UVW3W.js')).defaultSeedState(),
131
+ defaultSeed: async () => (await import('./src-3BV32GLS.js')).defaultSeedState(),
132
132
  async boot({ seedState, runId, recorder }) {
133
- const { createGmailTwinApp, GmailDomain, openGmailTwinDatabase, parseSeed } = await import('./src-RK3UVW3W.js');
133
+ const { createGmailTwinApp, GmailDomain, openGmailTwinDatabase, parseSeed } = await import('./src-3BV32GLS.js');
134
134
  const db = openGmailTwinDatabase(":memory:");
135
135
  const seed = parseSeed(seedState);
136
136
  const domain = new GmailDomain(db);
@@ -1,5 +1,5 @@
1
1
  import { readManifest, normalizeManifestTwins } from './chunk-KUVTL4NZ.js';
2
- import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus } from './chunk-Z32CZ45D.js';
2
+ import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, evaluationCounts } from './chunk-LI7RLYVA.js';
3
3
  import { MOUNTED_TWINS, HostedAuthError, HostedDiscardRefusedError, HostedQuotaError, HostedOrchError, HostedTrialError, agentResponseSchema } from './chunk-PQYIAA6K.js';
4
4
  import { redactSecrets, redactEvent } from './chunk-SG6ZTIMT.js';
5
5
  import { existsSync } from 'node:fs';
@@ -11,8 +11,13 @@ import { promisify } from 'node:util';
11
11
  import { createInterface } from 'node:readline';
12
12
  import { randomUUID, createHash } from 'node:crypto';
13
13
 
14
- var VERDICT_ARTIFACT_VERSION = 1;
14
+ var VERDICT_ARTIFACT_VERSION = 2;
15
15
  var VERDICT_FILENAME = "verdict.json";
16
+ var VALID_STATES = /* @__PURE__ */ new Set([
17
+ "pass",
18
+ "fail",
19
+ "incomplete"
20
+ ]);
16
21
  async function writeVerdictArtifact(runDir, verdict) {
17
22
  await writeFile(
18
23
  join(runDir, VERDICT_FILENAME),
@@ -21,7 +26,7 @@ async function writeVerdictArtifact(runDir, verdict) {
21
26
  "utf8"
22
27
  );
23
28
  }
24
- function isVerdictArtifact(parsed) {
29
+ function looksLikeVerdictArtifactBase(parsed) {
25
30
  if (typeof parsed !== "object" || parsed === null) return false;
26
31
  const v = parsed;
27
32
  if (v.source !== "cloud-finalize") return false;
@@ -40,33 +45,46 @@ function isVerdictArtifact(parsed) {
40
45
  return typeof criterion === "object" && criterion !== null && typeof criterion.text === "string" && typeof result.reason === "string" && typeof result.passed === "boolean" && typeof result.skipped === "boolean";
41
46
  });
42
47
  }
43
- function normalizeVerdictArtifact(parsed) {
44
- const { scenario_path: legacyPath, task_path: taskPath, ...rest } = parsed;
45
- return { ...rest, task_path: taskPath ?? legacyPath };
48
+ function isVerdictArtifact(parsed) {
49
+ if (!looksLikeVerdictArtifactBase(parsed)) return false;
50
+ const v = parsed;
51
+ if (v.version !== VERDICT_ARTIFACT_VERSION) return false;
52
+ if (typeof v.task_path !== "string") return false;
53
+ if (typeof v.state !== "string" || !VALID_STATES.has(v.state)) return false;
54
+ if (typeof v.evaluated !== "number") return false;
55
+ if (typeof v.not_evaluated !== "number") return false;
56
+ if (typeof v.pre_satisfied !== "number") return false;
57
+ if (typeof v.total !== "number") return false;
58
+ return true;
46
59
  }
47
- async function readVerdictArtifact(runDir) {
60
+ async function readVerdictArtifactDetailed(runDir) {
48
61
  const path = join(runDir, VERDICT_FILENAME);
49
62
  let raw;
50
63
  try {
51
64
  raw = await readFile(path, "utf8");
52
65
  } catch {
53
- return null;
66
+ return { status: "unreadable" };
54
67
  }
68
+ let parsed;
55
69
  try {
56
- const parsed = JSON.parse(raw);
57
- if (!isVerdictArtifact(parsed)) return null;
58
- return { runDir, verdict: normalizeVerdictArtifact(parsed) };
70
+ parsed = JSON.parse(raw);
59
71
  } catch {
60
- return null;
72
+ return { status: "unreadable" };
61
73
  }
74
+ if (!looksLikeVerdictArtifactBase(parsed)) return { status: "unreadable" };
75
+ const version = typeof parsed.version === "number" ? parsed.version : null;
76
+ if (version !== VERDICT_ARTIFACT_VERSION) return { status: "stale-version", version };
77
+ if (!isVerdictArtifact(parsed)) return { status: "unreadable" };
78
+ return { status: "ok", trial: { runDir, verdict: parsed } };
62
79
  }
63
- async function scanVerdictArtifacts(artifactsRoot) {
64
- const found = [];
80
+ async function scanVerdictArtifactsDetailed(artifactsRoot) {
81
+ const trials = [];
82
+ const staleVersionDirs = [];
65
83
  let slugs;
66
84
  try {
67
85
  slugs = await readdir(artifactsRoot);
68
86
  } catch {
69
- return found;
87
+ return { trials, staleVersionDirs };
70
88
  }
71
89
  for (const slug of slugs) {
72
90
  const slugDir = join(artifactsRoot, slug);
@@ -77,11 +95,13 @@ async function scanVerdictArtifacts(artifactsRoot) {
77
95
  continue;
78
96
  }
79
97
  for (const runId of runIds) {
80
- const trial = await readVerdictArtifact(join(slugDir, runId));
81
- if (trial) found.push(trial);
98
+ const runDir = join(slugDir, runId);
99
+ const result = await readVerdictArtifactDetailed(runDir);
100
+ if (result.status === "ok") trials.push(result.trial);
101
+ else if (result.status === "stale-version") staleVersionDirs.push(runDir);
82
102
  }
83
103
  }
84
- return found;
104
+ return { trials, staleVersionDirs };
85
105
  }
86
106
  function groupRunSets(trials) {
87
107
  const byKey = /* @__PURE__ */ new Map();
@@ -116,21 +136,35 @@ function latestFailedRunSet(sets) {
116
136
  return null;
117
137
  }
118
138
  async function discoverRunSet(target) {
119
- const anchor = await readVerdictArtifact(target);
120
- if (anchor) {
139
+ const anchorResult = await readVerdictArtifactDetailed(target);
140
+ if (anchorResult.status === "stale-version") {
141
+ return { kind: "trial-dir", set: null, totalSets: 0, staleVersionCount: 1 };
142
+ }
143
+ if (anchorResult.status === "ok") {
144
+ const anchor = anchorResult.trial;
121
145
  const root = join(target, "..", "..");
122
- const sets2 = groupRunSets(await scanVerdictArtifacts(root));
146
+ const { trials: trials2, staleVersionDirs: staleVersionDirs2 } = await scanVerdictArtifactsDetailed(root);
147
+ const sets2 = groupRunSets(trials2);
123
148
  const own = sets2.find(
124
149
  (s) => anchor.verdict.group_id !== null && s.groupId === anchor.verdict.group_id || anchor.verdict.group_id === null && s.trials.length === 1 && s.trials[0].verdict.session_id === anchor.verdict.session_id
125
150
  ) ?? groupRunSets([anchor])[0];
126
- return { kind: "trial-dir", set: own, totalSets: Math.max(sets2.length, 1) };
151
+ return {
152
+ kind: "trial-dir",
153
+ set: own,
154
+ totalSets: Math.max(sets2.length, 1),
155
+ staleVersionCount: staleVersionDirs2.length
156
+ };
157
+ }
158
+ if (!existsSync(target)) {
159
+ return { kind: "root", set: null, totalSets: 0, staleVersionCount: 0 };
127
160
  }
128
- if (!existsSync(target)) return { kind: "root", set: null, totalSets: 0 };
129
- const sets = groupRunSets(await scanVerdictArtifacts(target));
161
+ const { trials, staleVersionDirs } = await scanVerdictArtifactsDetailed(target);
162
+ const sets = groupRunSets(trials);
130
163
  return {
131
164
  kind: "root",
132
165
  set: latestFailedRunSet(sets),
133
- totalSets: sets.length
166
+ totalSets: sets.length,
167
+ staleVersionCount: staleVersionDirs.length
134
168
  };
135
169
  }
136
170
  async function loadTrialEvents(runDir) {
@@ -1067,6 +1101,7 @@ async function runTaskHosted(options) {
1067
1101
  const verdict = scoreStatus(score, scenario.config.passThreshold);
1068
1102
  const exitCode = verdict === "pass" ? 0 : 1;
1069
1103
  try {
1104
+ const counts = evaluationCounts(score);
1070
1105
  await writeVerdictArtifact(artifacts.runDir, {
1071
1106
  version: VERDICT_ARTIFACT_VERSION,
1072
1107
  source: "cloud-finalize",
@@ -1079,7 +1114,12 @@ async function runTaskHosted(options) {
1079
1114
  judge_model: score.judge_model,
1080
1115
  score: finalized.score,
1081
1116
  pass_threshold: scenario.config.passThreshold,
1117
+ state: verdict,
1082
1118
  passed: exitCode === 0,
1119
+ evaluated: counts.evaluated,
1120
+ not_evaluated: counts.notEvaluated,
1121
+ pre_satisfied: counts.preSatisfied,
1122
+ total: counts.total,
1083
1123
  criteria_results: score.results,
1084
1124
  duration_ms: durationMs,
1085
1125
  finalized_at: (/* @__PURE__ */ new Date()).toISOString()
@@ -1176,4 +1216,4 @@ async function abandonBestEffort(client, sessionId, errorCode) {
1176
1216
  }
1177
1217
  }
1178
1218
 
1179
- export { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, DEFAULT_DOCS_SITE_ORIGIN, clearLocalCredentials, discoverRunSet, ensurePomeGitignored, friendlyHostedError, loadTrialEvents, persistCredentialsAfterLogin, postAgentResolver, readLinkCache, resolveCachedAgentId, resolveCredentials, resolveRunAgentIdentity, resolveSeams, runSessionCreate, runSessionList, runSessionStop, runTaskHosted, writeLinkCache };
1219
+ export { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, DEFAULT_DOCS_SITE_ORIGIN, VERDICT_ARTIFACT_VERSION, clearLocalCredentials, discoverRunSet, ensurePomeGitignored, friendlyHostedError, loadTrialEvents, persistCredentialsAfterLogin, postAgentResolver, readLinkCache, resolveCachedAgentId, resolveCredentials, resolveRunAgentIdentity, resolveSeams, runSessionCreate, runSessionList, runSessionStop, runTaskHosted, writeLinkCache };
@@ -1,16 +1,16 @@
1
1
  import { newGroupId, reassuranceBox, twinReadyLine, trialsHeaderLine, trialLine, summaryLines, evaluatingLine, criterionPhrase } from './chunk-RGZBC7NF.js';
2
2
  import { DemoCapacityError, capacityLabel, parseCapacityMarker, capacityKindFrom } from './chunk-ZX4WNSZ5.js';
3
- import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-54OLERUK.js';
3
+ import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-M4P2435M.js';
4
4
  import { getAvailablePort } from './chunk-XDU6TD4O.js';
5
5
  import './chunk-CBFKZZBR.js';
6
- import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-Z32CZ45D.js';
6
+ import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-LI7RLYVA.js';
7
7
  import './chunk-NW7HGA2K.js';
8
8
  import { HostedQuotaError, HostedOrchError } from './chunk-PQYIAA6K.js';
9
9
  import './chunk-SGDUD7KK.js';
10
10
  import './chunk-NJ246QPJ.js';
11
11
  import './chunk-ZKID2HS3.js';
12
- import { bootTwin } from './chunk-TG22SRUL.js';
13
- import './chunk-5GDTUVXT.js';
12
+ import { bootTwin } from './chunk-2R46XQAL.js';
13
+ import './chunk-T6ZGCJSG.js';
14
14
  import './chunk-TV5S6WQV.js';
15
15
  import './chunk-VBATFCWR.js';
16
16
  import './chunk-SG6ZTIMT.js';
@@ -1,13 +1,13 @@
1
1
  import { newGroupId, criterionPhrase } from './chunk-RGZBC7NF.js';
2
- import { runTaskHosted, resolveRunAgentIdentity } from './chunk-BCI7KJRH.js';
2
+ import { runTaskHosted, resolveRunAgentIdentity } from './chunk-ZJU4JMHY.js';
3
3
  import './chunk-KUVTL4NZ.js';
4
- import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-Z32CZ45D.js';
4
+ import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-LI7RLYVA.js';
5
5
  import './chunk-NW7HGA2K.js';
6
6
  import { HostedQuotaError, HostedTrialError } from './chunk-PQYIAA6K.js';
7
7
  import './chunk-SGDUD7KK.js';
8
8
  import './chunk-NJ246QPJ.js';
9
9
  import './chunk-ZKID2HS3.js';
10
- import './chunk-5GDTUVXT.js';
10
+ import './chunk-T6ZGCJSG.js';
11
11
  import './chunk-TV5S6WQV.js';
12
12
  import './chunk-VBATFCWR.js';
13
13
  import './chunk-SG6ZTIMT.js';
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, loadTrialEvents, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-BCI7KJRH.js';
2
+ import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, loadTrialEvents, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-ZJU4JMHY.js';
3
3
  import { readManifest, writeManifest, MANIFEST_JSON, readRequiredManifest, normalizeManifestTwins } from '../../chunk-KUVTL4NZ.js';
4
- import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-54OLERUK.js';
4
+ import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-M4P2435M.js';
5
5
  import '../../chunk-XDU6TD4O.js';
6
6
  import '../../chunk-CBFKZZBR.js';
7
- import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, readConfigTwins, scoreCountsSummary, markerFor, outcomeOf, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-Z32CZ45D.js';
7
+ import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, readConfigTwins, scoreCountsSummary, markerFor, outcomeOf, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-LI7RLYVA.js';
8
8
  import '../../chunk-NW7HGA2K.js';
9
9
  import { MOUNTED_TWINS, deriveAgentSlug, exitCodeFor, HostedUsageError, HostedOrchError, HostedAuthError, HostedQuotaError } from '../../chunk-PQYIAA6K.js';
10
10
  import { TAPE_ASSERTABLE_TOOLS } from '../../chunk-FKZZWWYC.js';
@@ -15,8 +15,8 @@ import '../../chunk-NJ246QPJ.js';
15
15
  import { LINEAR_CHECKS } from '../../chunk-XBT6ZLBG.js';
16
16
  import '../../chunk-ZKID2HS3.js';
17
17
  import { oneOf, defineCheck, repoRef, VACUITY_SENTINEL_NUMBER, childStatePath, VACUITY_SENTINEL, statePath, templateSlots, renderCheck, checksDigest, checkPattern, checkNearMissPattern } from '../../chunk-JWJYNAWI.js';
18
- import '../../chunk-TG22SRUL.js';
19
- import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-5GDTUVXT.js';
18
+ import '../../chunk-2R46XQAL.js';
19
+ import { TWIN_NAME_LIST, isTwinName, createGitHubSmokeApp } from '../../chunk-T6ZGCJSG.js';
20
20
  import '../../chunk-TV5S6WQV.js';
21
21
  import { isLegacyEventRow, eventSchema } from '../../chunk-VBATFCWR.js';
22
22
  import { redactEvent, redactSecrets } from '../../chunk-SG6ZTIMT.js';
@@ -4497,7 +4497,7 @@ var DEFAULT_AGENT_FILE = "examples/agents/scripted-triage-agent.ts";
4497
4497
  var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
4498
4498
  var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
4499
4499
  function readPackageVersion() {
4500
- if ("0.23.1".length > 0) return "0.23.1";
4500
+ if ("0.23.3".length > 0) return "0.23.3";
4501
4501
  try {
4502
4502
  const here = dirname(fileURLToPath(import.meta.url));
4503
4503
  const candidates = [
@@ -4952,7 +4952,7 @@ function createProgram() {
4952
4952
  return;
4953
4953
  }
4954
4954
  {
4955
- const { runDoctorChecks } = await import('../../checks-GOJ5XLD5.js');
4955
+ const { runDoctorChecks } = await import('../../checks-MSUPRIKQ.js');
4956
4956
  const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
4957
4957
  const doctorReport = await runDoctorChecks({ mode: useLocal ? "full" : "hosted" });
4958
4958
  if (!doctorReport.ok) {
@@ -4990,7 +4990,7 @@ function createProgram() {
4990
4990
  taskForRuns.config.runs
4991
4991
  );
4992
4992
  if (k > 1) {
4993
- const { runTrialGroup } = await import('../../runTrialGroup-O7DQIB7T.js');
4993
+ const { runTrialGroup } = await import('../../runTrialGroup-G4OOARX2.js');
4994
4994
  const fileForRerun = relative(process.cwd(), file);
4995
4995
  const rerunCommand = defaultTask ? options.trials !== void 0 ? `pome run -n ${k}` : "pome run" : `pome run ${fileForRerun && !fileForRerun.startsWith("..") ? fileForRerun : file} -n ${k}`;
4996
4996
  const groupResult = await runTrialGroup({
@@ -5084,7 +5084,7 @@ function createProgram() {
5084
5084
  process.exitCode = 5;
5085
5085
  return;
5086
5086
  }
5087
- const { runDemo } = await import('../../runDemo-Q3WATCYJ.js');
5087
+ const { runDemo } = await import('../../runDemo-LLR4FAS4.js');
5088
5088
  const result = await runDemo({
5089
5089
  apiBase: opts.apiUrl.replace(/\/$/, ""),
5090
5090
  dashboardBase: process.env.POME_DASHBOARD_URL ?? DEFAULT_DASHBOARD_URL,
@@ -5102,7 +5102,7 @@ function createProgram() {
5102
5102
  program.command("doctor").description(
5103
5103
  "Check the agent\u2194twin wiring: pome.json (or pome.yaml) present + valid, the local twin boots + serves, requests routed to the twin (not a hardcoded production host), egress floor active. On failure prints one named cause (file:line where knowable) + one concrete fix and exits non-zero."
5104
5104
  ).action(async () => {
5105
- const { runDoctorChecks } = await import('../../checks-GOJ5XLD5.js');
5105
+ const { runDoctorChecks } = await import('../../checks-MSUPRIKQ.js');
5106
5106
  const { renderDoctorReport } = await import('../../render-ZQQ4UMNO.js');
5107
5107
  const report = await runDoctorChecks();
5108
5108
  for (const line of renderDoctorReport(report, { passNote: true })) console.error(line);
@@ -5189,10 +5189,17 @@ function createProgram() {
5189
5189
  }
5190
5190
  const root = target ?? "runs";
5191
5191
  const discovery = await discoverRunSet(resolve(root));
5192
- if (discovery.totalSets === 0) {
5192
+ if (discovery.staleVersionCount > 0) {
5193
5193
  console.error(
5194
- `No finalized run sets under ${root} \u2014 hosted \`pome run\` records a verdict.json per trial; run one first (or point fix-prompt at your artifacts dir).`
5194
+ `${discovery.staleVersionCount} verdict.json file(s) under ${root} are not artifact version ${VERDICT_ARTIFACT_VERSION} (the only version this CLI reads) and were skipped \u2014 re-run \`pome run\` to record those trials again.`
5195
5195
  );
5196
+ }
5197
+ if (discovery.totalSets === 0) {
5198
+ if (discovery.staleVersionCount === 0) {
5199
+ console.error(
5200
+ `No finalized run sets under ${root} \u2014 hosted \`pome run\` records a verdict.json per trial; run one first (or point fix-prompt at your artifacts dir).`
5201
+ );
5202
+ }
5196
5203
  process.exitCode = 5;
5197
5204
  return;
5198
5205
  }
@@ -5234,7 +5241,7 @@ function createProgram() {
5234
5241
  ).description(
5235
5242
  "Start a standalone twin as a long-lived foreground server (Ctrl-C to stop)"
5236
5243
  ).action(async (name, options) => {
5237
- const { runTwinStartCommand } = await import('../../twinStart-WIGOQFAI.js');
5244
+ const { runTwinStartCommand } = await import('../../twinStart-FR2NH7YE.js');
5238
5245
  await runTwinStartCommand(name, options);
5239
5246
  });
5240
5247
  twin.command("reset").argument("[name]", "Twin name (default: github)", "github").description("Reset standalone twin state").action(async (name) => {
@@ -2197,10 +2197,10 @@ var mcp_tools_list_meta_default = {
2197
2197
  substrate: "live-wire-unauth",
2198
2198
  endpoint: "https://gmailmcp.googleapis.com/mcp/v1",
2199
2199
  method: "tools/list",
2200
- protocol: "JSON-RPC 2.0 over HTTP (accept: application/json, text/event-stream)",
2200
+ protocol: "JSON-RPC 2.0 over HTTP",
2201
2201
  protocolVersion: "2025-03-26",
2202
- captureDate: "2026-07-20",
2203
- rawFileSha256: "6ef35bad568967015c101f89e995148c4eb2131b3a6dd244f7237058abae8e7a",
2202
+ captureDate: "2026-08-10",
2203
+ rawFileSha256: "fd2b12868289aee89798c218a7ea2307fc475935d3d912c2a3c35b5d75ae21ee",
2204
2204
  liveToolCount: 13,
2205
2205
  liveToolOrder: [
2206
2206
  "create_draft",
@@ -2218,7 +2218,7 @@ var mcp_tools_list_meta_default = {
2218
2218
  "create_label"
2219
2219
  ],
2220
2220
  configuration: {
2221
- auth: "none \u2014 the unauthenticated read answered HTTP 200 for both tools/list and initialize (Developer Preview)",
2221
+ auth: "none",
2222
2222
  deploymentSelector: "none \u2014 the endpoint exposes no toolset, tool-filter or read-only selector, so there is exactly one surface to read",
2223
2223
  requestHeaders: {
2224
2224
  "content-type": "application/json",
@@ -2229,17 +2229,19 @@ var mcp_tools_list_meta_default = {
2229
2229
  jsonrpc: "2.0",
2230
2230
  id: 1
2231
2231
  },
2232
- matchesExaminee: "an examinee pointing an MCP client at this URL gets this listing; there is no configuration axis on which the two could differ",
2233
- completeness: "exact"
2232
+ matchesExaminee: "exactly, for all 13 tools \u2014 name, description, inputSchema, outputSchema and annotations are Google's own bytes, and an examinee pointing an MCP client at the endpoint above gets this listing.",
2233
+ completeness: "exact",
2234
+ derivation: "the upstream golden in full \u2014 all 13 tools, no subtraction. Produced by scripts/adopt-upstream-mcp-fixture.ts from fixtures/mcp-tools-list/gmail.raw.json at rawFileSha256 fd2b12868289aee89798c218a7ea2307fc475935d3d912c2a3c35b5d75ae21ee, whose bytes this file copies verbatim."
2234
2235
  },
2235
2236
  notes: [
2236
- "Gate 1 expands the OSS launch set from the Gate-0 ten-tool freeze to the full live 13-tool listing. The three promoted from Developer Preview are get_message, apply_sensitive_thread_label and apply_sensitive_message_label.",
2237
- "Schemas, annotations and descriptions are the live capture's, verbatim.",
2238
- "DELIBERATE DIVERGENCE: F-1326 re-read the same endpoint on 2026-08-06 and got the same 13 names with different schemas and descriptions (fixtures/mcp-tools-list/gmail.meta.json, rawFileSha256 93085540\u2026). This twin keeps serving the 2026-07-20 oracle. Adopting the newer bytes changes what the twin serves, which is a behavioural change F-1325 does not make; the lane that compares the two is F-1327. This is not an oversight.",
2237
+ "F-1400: these bytes are Google's, adopted rather than transcribed. The fixture that shipped before this one was the same endpoint read on 2026-07-20 and was never refreshed, so the twin advertised a seventeen-day-old listing and pome-cloud's mcp_diff reported 34 findings across 11 tools \u2014 all of them the vendor moving, none of them a twin defect. Produced by scripts/adopt-upstream-mcp-fixture.ts; `npm run gate:mcp-fixture -w @pome-sh/twin-gmail` re-derives and diffs.",
2238
+ "13 tools, which is every tool the capture carries. Unlike twin-slack's adoption there is no suppression list: nothing here is withheld, so raw.json is byte-identical to fixtures/mcp-tools-list/gmail.raw.json and the two shas agree.",
2239
+ "Descriptions, schemas and annotations are the capture's verbatim. Three of its claims are behavioural and were implemented in the same change rather than merely served: Message.bccRecipients, Label.messagesTotal/messagesUnread, and a list_labels that answers with ALL labels \u2014 the July listing said 'all user-defined labels' and the twin returned exactly those.",
2240
+ "list_labels takes no arguments in this listing. The July capture declared pageSize/pageToken and the twin paginated; Google has since removed both, along with nextPageToken from the response, so the twin answers every label in one page. LIMITS.md's MCP page-size row no longer names this tool.",
2239
2241
  "Authenticated tools/call success envelopes were unavailable; the reconstructed shapes live in mcp-tools-call.representative.json and the live unauthenticated error envelope in mcp-tools-call-unauth-error.raw.json.",
2240
2242
  "initialize returned protocolVersion=2025-03-26 (mcp-initialize.raw.json)."
2241
2243
  ],
2242
- canonicalFileSha256: "44ae70afa53697967b7b38e9320b9032a906a9d42201eab08c8f1f3b89ca3c52",
2244
+ canonicalFileSha256: "91d290ddb244d0736df1a6b81901aabf754b8d474c9343b487b65d3485dfaa19",
2243
2245
  files: {
2244
2246
  raw: "mcp-tools-list.raw.json",
2245
2247
  canonical: "mcp-tools-list.canonical.json"
@@ -2247,7 +2249,7 @@ var mcp_tools_list_meta_default = {
2247
2249
  };
2248
2250
 
2249
2251
  // ../packages/twin-gmail/dist/fixtures/mcp-tools-list.raw.json
2250
- var mcp_tools_list_raw_default = { id: 1, jsonrpc: "2.0", result: { tools: [{ annotations: { destructiveHint: false, idempotentHint: false, openWorldHint: false, readOnlyHint: false, title: "Creates a new draft email in the authenticated user's Gmail account." }, description: "Creates a new draft email in the authenticated user's Gmail account.\n\nThis tool takes recipient addresses, a subject, and body content as inputs. It returns the ID of the created Gmail draft. If the draft is created as a reply to an existing message, the ID of the original message should be passed to the tool in the replyToMessageId field. Creating drafts with attachments is not supported yet.\n", inputSchema: { $defs: { Attachment: { description: "Represents an attachment to be included in an email.", properties: { content: { description: "Required. The base64-encoded content of the attachment.", format: "byte", type: "string" }, filename: { description: 'Optional. The name of the file to be attached, e.g. "invoice.pdf". For inline attachments, this is used for Content-ID generation. For regular attachments, filename is used to specify the filename to email clients. If not provided, the attachment may be received with no name.', type: "string" }, id: { description: "Optional. Output only. When present, contains the ID of an external attachment that can be retrieved in a separate `GetMessageAttachment` request.", readOnly: true, type: "string" }, inline: { description: "Optional. If true, this attachment is handled as inline. An inline attachment is a content that is intended to be displayed within the body of an HTML email, as opposed to being listed as a separate file for download. If false or absent, defaults to false, and it's treated as a regular attachment.", type: "boolean" }, mimeType: { description: 'Optional. The field representing a content or media type must use IANA MIME type, https://www.iana.org/assignments/media-types/media-types.xhtml. If not provided, defaults to "application/octet-stream".', type: "string" } }, required: ["content"], type: "object" } }, description: "Request message for CreateDraft RPC.", properties: { attachments: { description: "Optional. The attachments to include in the email. The combined size of attachments in the message cannot exceed 25MB. If you need to send files larger than 25MB, upload the file to Drive first and then insert the Drive link into body or html_body.", items: { $ref: "#/$defs/Attachment" }, type: "array" }, bcc: { description: 'Optional. The blind carbon copy recipients of the email draft. Each string MUST be a valid plain email address (e.g., "user@example.com"). The "Name " format is NOT supported by this tool.', items: { type: "string" }, type: "array" }, body: { description: "Optional. The main body content of the email draft. If html_body is also provided, this field is treated as the plain-text alternative.", type: "string" }, cc: { description: 'Optional. The carbon copy recipients of the email draft. Each string MUST be a valid plain email address (e.g., "user@example.com"). The "Name " format is NOT supported by this tool.', items: { type: "string" }, type: "array" }, htmlBody: { description: "The HTML content of the email draft. If provided, this will be used as the rich-text version of the email.", type: "string" }, replyToMessageId: { description: "Optional. The ID of the message to reply to. If provided, this will be used as the reply-to message ID for the email draft, and the `body` and `html_body` will be appended to the original message body.", type: "string" }, subject: { description: "Optional. The subject line of the email. Defaults to empty if not provided.", type: "string" }, to: { description: 'Optional. The primary recipients of the email draft. Each string MUST be a valid plain email address (e.g., "user@example.com"). The "Name " format is NOT supported by this tool.', items: { type: "string" }, type: "array" } }, type: "object" }, name: "create_draft", outputSchema: { description: "Details of a draft.", properties: { bccRecipients: { description: "List of 'Bcc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, ccRecipients: { description: "List of 'Cc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, date: { description: "Date of the draft in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML body content of the draft, if available.", type: "string" }, id: { description: "The unique identifier of the draft resource.", type: "string" }, plaintextBody: { description: "Plain text body content, if available.", type: "string" }, subject: { description: "The subject line of the draft message.", type: "string" }, threadId: { description: "The ID of the thread this draft belongs to.", type: "string" }, toRecipients: { description: "List of 'To' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: false, openWorldHint: false, readOnlyHint: true, title: "Lists draft emails from the authenticated user's Gmail account." }, description: "Lists draft emails from the authenticated user's Gmail account.\n\nThis tool can filter drafts based on a query string and supports pagination. It returns a list of drafts, including their IDs and subjects (unless `view` is set to `DRAFT_VIEW_METADATA_ONLY`). `page_token` can be used to paginate the results. To retrieve subsequent pages of results, use the `page_token` returned in the previous response.\n\nThe `view` parameter controls which fields are populated in the response. By default (or with `DRAFT_VIEW_FULL`), it returns full content. Use `DRAFT_VIEW_METADATA_ONLY` to exclude sensitive content like subject and body. \n", inputSchema: { description: "Request message for ListDrafts RPC.", properties: { pageSize: { description: "Optional. The maximum number of drafts to return. If unspecified, defaults to 20. The maximum allowed value is 50.", format: "int32", type: "integer" }, pageToken: { description: "Optional. A token received from a previous list_drafts call to retrieve the next page of results. Leave empty to fetch the first page. This is primarily used for pagination to continue fetching results from where the previous `ListDraft` call left off, especially when the number of drafts matching the query exceeds the page_size limit.", type: "string" }, query: { description: 'Examples: "subject:OneMCP Update" "from:gduser1@workspacesamples.dev" "to:gduser2@workspacesamples.dev AND newer_than:7d" "project proposal has:attachment" "is:unread" A space or a dash (`-`) will separate a number while a dot (`.`) will be a decimal. For example, `01.2047-100` is considered two numbers: `01.2047` and `100`. Note: If we want to ensure all drafts for the query are returned, we can paginate the results by making repeated calls to the tool until the response contains an empty list of drafts.', type: "string" }, view: { description: "Optional. Controls the fields populated for drafts in the draft list.", enum: ["DRAFT_VIEW_UNSPECIFIED", "DRAFT_VIEW_METADATA_ONLY", "DRAFT_VIEW_FULL"], type: "string", "x-google-enum-descriptions": ["Maps to DRAFT_VIEW_FULL for backward compatibility.", "Metadata only: does not include subject, plaintext_body, html_body.", "Metadata + UGC (Default behavior)."] } }, type: "object" }, name: "list_drafts", outputSchema: { $defs: { Draft: { description: "Details of a draft.", properties: { bccRecipients: { description: "List of 'Bcc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, ccRecipients: { description: "List of 'Cc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, date: { description: "Date of the draft in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML body content of the draft, if available.", type: "string" }, id: { description: "The unique identifier of the draft resource.", type: "string" }, plaintextBody: { description: "Plain text body content, if available.", type: "string" }, subject: { description: "The subject line of the draft message.", type: "string" }, threadId: { description: "The ID of the thread this draft belongs to.", type: "string" }, toRecipients: { description: "List of 'To' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" } }, type: "object" } }, description: "Response message for ListDrafts RPC.", properties: { drafts: { description: "List of drafts.", items: { $ref: "#/$defs/Draft" }, type: "array" }, nextPageToken: { description: "A token that can be used in a subsequent call to retrieve the next page of drafts. If the number of drafts matching the query exceeds the page_size limit, the response will contain a `next_page_token`. To retrieve the next page of results, pass this token in the `page_token` field of the next `ListDraftsRequest`.", type: "string" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "Retrieves a specific email thread from the authenticated user's Gmail account." }, description: "Retrieves a specific email thread from the authenticated user's Gmail account, including a list of its messages.\n\nThe optional `message_format` parameter controls the format of the messages returned. By default (or with `FULL_CONTENT`), it returns the full content of messages. Use `MINIMAL` to include only subject and snippet (excluding body). Use `METADATA_ONLY` to include only basic metadata (message ID, thread ID, labels, timestamp, and size estimate). \n", inputSchema: { description: "Request message for GetThread RPC.", properties: { messageFormat: { description: "Optional. Specifies the format of the messages returned within the thread. Defaults to FULL_CONTENT. Note: If you need body content or attachments, use FULL_CONTENT. When using MINIMAL, the plaintext_body and attachment_ids fields will not be populated. If you are unsure which format to use, rely on the default behavior by using FULL_CONTENT.", enum: ["MESSAGE_FORMAT_UNSPECIFIED", "MINIMAL", "FULL_CONTENT", "METADATA_ONLY"], type: "string", "x-google-enum-descriptions": ["Defaults to FULL_CONTENT.", "Returns message snippets and key headers (Subject, From, To, Cc, Date).", 'Returns all information in "MINIMAL" plus the full body content of each message.', "Metadata only: does not include subject, snippet, body, attachment filenames."] }, threadId: { description: "Required. The unique identifier of the thread to fetch.", type: "string" } }, required: ["threadId"], type: "object" }, name: "get_thread", outputSchema: { $defs: { AttachmentMetadata: { description: "Represents an attachment associated with a message.", properties: { filename: { description: "The filename of the attachment.", type: "string" }, id: { description: "Output only. The ID of the attachment.", readOnly: true, type: "string" }, mimeType: { description: "The MIME type of the attachment.", type: "string" } }, type: "object" }, Message: { description: "Message within a thread.", properties: { attachmentIds: { description: "Output only. The attachment ids, only populated if MessageFormat was FULL_CONTENT.", items: { type: "string" }, readOnly: true, type: "array" }, attachments: { description: "Output only. The attachments, only populated if MessageFormat was FULL_CONTENT.", items: { $ref: "#/$defs/AttachmentMetadata" }, readOnly: true, type: "array" }, ccRecipients: { description: "CC recipient email addresses.", items: { type: "string" }, type: "array" }, date: { description: "Date of the message in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML content of the email, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, id: { description: "The unique identifier of the message.", type: "string" }, labelIds: { description: 'The ids of the labels attached to the message. Includes ids of user labels and standard system labels limited to "INBOX", "SPAM", "TRASH", "UNREAD", "STARRED", "IMPORTANT", "SENT", "DRAFT", "CHAT".', items: { type: "string" }, type: "array" }, plaintextBody: { description: "Full body content, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, sender: { description: "Sender email address.", type: "string" }, snippet: { description: "Snippet of the message body.", type: "string" }, subject: { description: "The message subject extracted from headers:", type: "string" }, toRecipients: { description: "To recipient email addresses.", items: { type: "string" }, type: "array" } }, type: "object" } }, description: "Thread containing a list of messages.", properties: { id: { description: "The unique identifier of the thread.", type: "string" }, messages: { description: "A list of messages in the thread, ordered chronologically.", items: { $ref: "#/$defs/Message" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "Retrieves a specific email message from the authenticated user's Gmail account." }, description: 'Retrieves a specific email message from the authenticated user\'s Gmail account by its unique message ID.\n\nUse this tool to inspect a single, individual email when you already know its message ID. If the user wants to read a specific email in detail, check the exact wording of a message, or examine attachment metadata for a single email, this is the right tool. It is not suitable for retrieving entire conversations or viewing back-and-forth discussion threads; use the \'get_thread\' tool instead.\nKey indicators include if the user asks for the full content of a specific message ID returned by a previous search, or if the query asks to inspect a specific individual email rather than an entire thread.\nExample user prompts are: "Get the full text of message ID 18f123456789abcd.", "Read the latest message in that thread from Alice.", and "What are the attachment names in the email I just received from HR?" \n\nThe optional `messageFormat` parameter controls the format of the message returned. By default (or with `FULL_CONTENT`), it returns the full content of the message. Use `MINIMAL` to include only subject and snippet (excluding body). Use `METADATA_ONLY` to include only basic metadata (message ID, thread ID, labels, timestamp, and size estimate). \n', inputSchema: { description: "Request message for GetMessage RPC.", properties: { messageFormat: { description: "Optional. Specifies the format of the message returned. Defaults to FULL_CONTENT.", enum: ["MESSAGE_FORMAT_UNSPECIFIED", "MINIMAL", "FULL_CONTENT", "METADATA_ONLY"], type: "string", "x-google-enum-descriptions": ["Defaults to FULL_CONTENT.", "Returns message snippets and key headers (Subject, From, To, Cc, Date).", 'Returns all information in "MINIMAL" plus the full body content of each message.', "Metadata only: does not include subject, snippet, body, attachment filenames."] }, messageId: { description: "Required. The unique identifier of the message to fetch.", type: "string" } }, required: ["messageId"], type: "object" }, name: "get_message", outputSchema: { $defs: { AttachmentMetadata: { description: "Represents an attachment associated with a message.", properties: { filename: { description: "The filename of the attachment.", type: "string" }, id: { description: "Output only. The ID of the attachment.", readOnly: true, type: "string" }, mimeType: { description: "The MIME type of the attachment.", type: "string" } }, type: "object" } }, description: "Message within a thread.", properties: { attachmentIds: { description: "Output only. The attachment ids, only populated if MessageFormat was FULL_CONTENT.", items: { type: "string" }, readOnly: true, type: "array" }, attachments: { description: "Output only. The attachments, only populated if MessageFormat was FULL_CONTENT.", items: { $ref: "#/$defs/AttachmentMetadata" }, readOnly: true, type: "array" }, ccRecipients: { description: "CC recipient email addresses.", items: { type: "string" }, type: "array" }, date: { description: "Date of the message in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML content of the email, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, id: { description: "The unique identifier of the message.", type: "string" }, labelIds: { description: 'The ids of the labels attached to the message. Includes ids of user labels and standard system labels limited to "INBOX", "SPAM", "TRASH", "UNREAD", "STARRED", "IMPORTANT", "SENT", "DRAFT", "CHAT".', items: { type: "string" }, type: "array" }, plaintextBody: { description: "Full body content, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, sender: { description: "Sender email address.", type: "string" }, snippet: { description: "Snippet of the message body.", type: "string" }, subject: { description: "The message subject extracted from headers:", type: "string" }, toRecipients: { description: "To recipient email addresses.", items: { type: "string" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "Searches for email threads from the authenticated user's Gmail account." }, description: "Lists email threads from the authenticated user's Gmail account.\n\nThis tool can filter threads based on a query string and supports pagination. It returns a list of threads, including their IDs and related messages. Each related message contains details like a snippet of the message body, the subject, the sender, the recipients etc. The `view` parameter controls which fields are populated in the related messages. By default (or with `THREAD_VIEW_MINIMAL`), it includes subject and snippet. Use `THREAD_VIEW_METADATA_ONLY` to exclude subject and snippet. Note that the full message bodies are not returned by this tool; use the 'get_thread' tool with a thread ID to fetch the full message body if needed. Threads with excluded criteria may still appear in the results. This occurs because Gmail identifies matching messages first. For example, if you search for -is:starred, Gmail will find an entire thread if it contains at least one unstarred message, even if other emails in that same conversation are starred.\n", inputSchema: { description: "Request message for SearchThreads RPC.", properties: { includeTrash: { description: "Optional. Include drafts from TRASH in the results. Defaults to false.", type: "boolean" }, pageSize: { description: "Optional. The maximum number of threads to return. If unspecified, defaults to 20. The maximum allowed value is 50.", format: "int32", type: "integer" }, pageToken: { description: "Optional. Page token to retrieve a specific page of results in the list. Leave empty to fetch the first page. This is primarily used for pagination to continue fetching results from where the previous `SearchThreads` call left off, especially when the number of threads matching the query exceeds the page_size limit.", type: "string" }, query: { description: 'Optional. A query string to filter the threads. Natural language queries must be pre-converted into Gmail syntax queries to use this tool. If omitted, all threads (excluding spam and trash by default) are listed. Supported Operators by Category: Sender & Recipient: from: - Sent from a specific person. to: - Sent to a specific person. cc: - Specific people in Cc. bcc: - Specific people in Bcc. deliveredto: - Delivered to a specific address. list: - From a specific mailing list. Time & Date: after:YYYY/MM/DD / newer:YYYY/MM/DD - Received after a date. before:YYYY/MM/DD / older:YYYY/MM/DD - Received before a date. older_than: - Older than a duration (e.g., 1y, 2d). newer_than: - Newer than a duration. Content: subject: - Words in the subject line. has: - Has specific content types (attachment, drive, youtube, document). filename: - Attachment with a specific name or type. "" - Search for an exact word or phrase. (e.g., "holiday", "holiday vacation"). + - Match a word exactly. (e.g., +holiday, +unicorn) rfc822msgid: - Specific message ID header. AROUND - Find words near each other (e.g., holiday AROUND 10 vacation). Labels & Categories: label: - Under a specific label. The tool accepts label IDs, not display names. Use the list_labels tool to get the ID. category: - In a category (primary, social, promotions, updates, forums, reservations, purchases). in: - Search in specific labels (archive, snoozed, trash, sent, inbox). E.g., `in:trash`, `in:inbox`. Archived and sent messages are included by default; use `-in:archive` and `-in:sent` to exclude them. Drafts are explicitly excluded by default by the tool. Use `in:inbox` to restrict search to the inbox only. has:userlabels - Has any user labels. has:nouserlabels - Does not have any user labels. has:*-star - Specific star colors (if enabled, e.g., has:yellow-star). in:draft - Search in drafts. -in:draft means exclude drafts from the search results. in:sent - Search in sent messages. in:anywhere - Search in all folders (including spam and trash). Status: is: - Search by status (important, starred, unread, read, muted). Size: size: - Specific size in bytes. larger: / smaller: - Larger or smaller than a size (e.g., 10M for 10 MB). Logic & Grouping: AND - Match all criteria (default behavior). OR or { } - Match one or more criteria (e.g., from:amy OR from:david, {from:amy from:david}). - (minus) - Exclude criteria (e.g., -movie). ( ) - Group multiple search terms (e.g., subject:(dinner film)). Examples: "subject:OneMCP Update" "from:user@example.com" "to:user2@example.com AND newer_than:7d" "project proposal has:attachment" "is:unread -in:draft"', type: "string" }, view: { description: "Optional. Controls the fields populated for threads in the thread list.", enum: ["THREAD_VIEW_UNSPECIFIED", "THREAD_VIEW_METADATA_ONLY", "THREAD_VIEW_MINIMAL"], type: "string", "x-google-enum-descriptions": ["Maps to DRAFT_VIEW_FULL for backward compatibility.", "Metadata only: does not include subject, plaintext_body, html_body.", "Minimal: includes subject and snippet, but no body."] } }, type: "object" }, name: "search_threads", outputSchema: { $defs: { AttachmentMetadata: { description: "Represents an attachment associated with a message.", properties: { filename: { description: "The filename of the attachment.", type: "string" }, id: { description: "Output only. The ID of the attachment.", readOnly: true, type: "string" }, mimeType: { description: "The MIME type of the attachment.", type: "string" } }, type: "object" }, Message: { description: "Message within a thread.", properties: { attachmentIds: { description: "Output only. The attachment ids, only populated if MessageFormat was FULL_CONTENT.", items: { type: "string" }, readOnly: true, type: "array" }, attachments: { description: "Output only. The attachments, only populated if MessageFormat was FULL_CONTENT.", items: { $ref: "#/$defs/AttachmentMetadata" }, readOnly: true, type: "array" }, ccRecipients: { description: "CC recipient email addresses.", items: { type: "string" }, type: "array" }, date: { description: "Date of the message in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML content of the email, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, id: { description: "The unique identifier of the message.", type: "string" }, labelIds: { description: 'The ids of the labels attached to the message. Includes ids of user labels and standard system labels limited to "INBOX", "SPAM", "TRASH", "UNREAD", "STARRED", "IMPORTANT", "SENT", "DRAFT", "CHAT".', items: { type: "string" }, type: "array" }, plaintextBody: { description: "Full body content, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, sender: { description: "Sender email address.", type: "string" }, snippet: { description: "Snippet of the message body.", type: "string" }, subject: { description: "The message subject extracted from headers:", type: "string" }, toRecipients: { description: "To recipient email addresses.", items: { type: "string" }, type: "array" } }, type: "object" }, Thread: { description: "Thread containing a list of messages.", properties: { id: { description: "The unique identifier of the thread.", type: "string" }, messages: { description: "A list of messages in the thread, ordered chronologically.", items: { $ref: "#/$defs/Message" }, type: "array" } }, type: "object" } }, description: "Response message for SearchThreads RPC.", properties: { nextPageToken: { description: "A token that can be used in a subsequent call to retrieve the next page of threads. Present only if there are more results. If the number of threads matching the query exceeds the page_size limit, the response will contain a `next_page_token`. To retrieve the next page of results, pass this token in the `page_token` field of the next `SearchThreadsRequest`.", type: "string" }, resultCountEstimate: { description: 'The estimated result count for this query. It should be treated as a lower bound, so for example if it is 500, then the count can be reported to the user as "500+".', format: "int64", type: "string" }, threads: { description: "List of thread summaries.", items: { $ref: "#/$defs/Thread" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Adds labels to a thread." }, description: "Adds labels to an entire thread in the authenticated user's Gmail account. This operation affects all messages currently in the thread and any future messages added to it.\n\nIf unsure of the thread ID, use the `search_threads` tool first.\n\nIf unsure of a user label's ID, use the `list_labels` tool first to discover available labels and their IDs. To add a trash label or a spam label on to a thread, please use the `apply_sensitive_thread_label` tool instead.\n", inputSchema: { description: "Request message for LabelThread RPC.", properties: { labelIds: { description: "Required. The unique identifiers of the labels to add. Can be a system label ID (e.g., 'INBOX', 'TRASH', 'SPAM', 'STARRED', 'UNREAD', 'IMPORTANT') or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the list_labels tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, threadId: { description: "Required. The unique identifier of the thread to add labels to.", type: "string" } }, required: ["threadId", "labelIds"], type: "object" }, name: "label_thread", outputSchema: { description: "Response message for LabelThread RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Removes labels from a thread." }, description: "Removes labels from an entire thread in the authenticated user's Gmail account. If unsure of the thread ID, use the `search_threads` tool first. If unsure of a user label's ID, use the `list_labels` tool first.", inputSchema: { description: "Request message for UnlabelThread RPC.", properties: { labelIds: { description: "Required. The unique identifiers of the labels to remove. Can be a system label ID (e.g., 'INBOX', 'TRASH', 'SPAM', 'STARRED', 'UNREAD', 'IMPORTANT') or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the list_labels tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, threadId: { description: "Required. The unique identifier of the thread to remove labels from.", type: "string" } }, required: ["threadId", "labelIds"], type: "object" }, name: "unlabel_thread", outputSchema: { description: "Response message for UnlabelThread RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Adds a sensitive label (Trash or Spam) to a thread." }, description: "Adds a sensitive label (Trash or Spam) to an entire thread in the authenticated user's Gmail account. This operation affects all messages currently in the thread and any future messages added to it.\n\nUse this tool to trash or mark a thread as spam. If unsure of the thread ID, use the `search_threads` tool first.\n", inputSchema: { description: "Request message for ApplySensitiveThreadLabel RPC.", properties: { labelOption: { description: "Required. The sensitive label option to add.", enum: ["LABEL_OPTION_UNSPECIFIED", "TRASH", "SPAM"], type: "string", "x-google-enum-descriptions": ["Unspecified label option.", "Trash label.", "Spam label."] }, threadId: { description: "Required. The ID of the thread to add the label to.", type: "string" } }, required: ["threadId", "labelOption"], type: "object" }, name: "apply_sensitive_thread_label", outputSchema: { description: "Response message for ApplySensitiveThreadLabel RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "Lists user labels." }, description: "Lists all user-defined labels available in the authenticated user's Gmail account. Use this tool to discover the `id` of a user label before calling `label_thread`, `unlabel_thread`, `label_message`, or `unlabel_message`. System labels are not returned by this tool but can be used with their well-known IDs: 'INBOX', 'TRASH', 'SPAM', 'STARRED', 'UNREAD', 'IMPORTANT', 'CHAT', 'DRAFT', 'SENT'.", inputSchema: { description: "Request message for ListLabels RPC.", properties: { pageSize: { description: "Optional. The maximum number of labels to return.", format: "int32", type: "integer" }, pageToken: { description: "Optional. Page token to retrieve a specific page of results in the list.", type: "string" } }, type: "object" }, name: "list_labels", outputSchema: { $defs: { Label: { description: "Details of a label.", properties: { color: { $ref: "#/$defs/LabelColor", description: "Optional. The color of the label." }, labelId: { description: "The unique identifier of the label.", type: "string" }, name: { description: "The human-readable display name of the label.", type: "string" }, threadsTotal: { description: "The total number of threads under the label.", format: "int32", type: "integer" }, threadsUnread: { description: "The number of unread threads under the label.", format: "int32", type: "integer" } }, type: "object" }, LabelColor: { description: "The color of the label.", properties: { backgroundColor: { description: 'The background color of the label, represented as a hex string (e.g., "#ffffff"). Only the following predefined set of color values are allowed: # 000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, # fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, # f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, # efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, # e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, # cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, # ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, # 822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c, # 464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, # 711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, # 594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, # c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, # 662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765', type: "string" }, textColor: { description: 'The text color of the label, represented as a hex string (e.g., "#000000"). Only the following predefined set of color values are allowed: # 000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, # fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, # f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, # efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, # e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, # cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, # ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, # 822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c, # 464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, # 711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, # 594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, # c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, # 662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765', type: "string" } }, type: "object" } }, description: "Response message for ListLabels RPC.", properties: { labels: { description: "List of user labels in the user's account.", items: { $ref: "#/$defs/Label" }, type: "array" }, nextPageToken: { description: "Token to retrieve the next page of results in the list.", type: "string" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Adds labels to a message." }, description: "Adds one or more labels to a specific message in the authenticated user's Gmail account.\n\nTo find the message ID, use tools like `search_threads` or `get_thread`. If unsure of a user label's ID, use the `list_labels` tool first to discover available labels and their IDs. To add a trash label or a spam label on to a message, please use the `apply_sensitive_message_label` tool instead.\n", inputSchema: { description: "Request message for LabelMessage RPC.", properties: { labelIds: { description: "Required. The IDs of the labels to add. Can be a system label ID (e.g., 'INBOX', 'TRASH', 'SPAM', 'STARRED', 'UNREAD', 'IMPORTANT') or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the list_labels tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, messageId: { description: "Required. The ID of the message to add the labels to.", type: "string" } }, required: ["messageId", "labelIds"], type: "object" }, name: "label_message", outputSchema: { description: "Response message for LabelMessage RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Removes labels from a message." }, description: "Removes one or more labels from a specific message in the authenticated user's Gmail account. To find the message ID, use tools like `search_threads` or `get_thread`. If unsure of a user label's ID, use the `list_labels` tool first to discover available labels and their IDs.", inputSchema: { description: "Request message for UnlabelMessage RPC.", properties: { labelIds: { description: "Required. The IDs of the labels to remove. Can be a system label ID (e.g., 'INBOX', 'TRASH', 'SPAM', 'STARRED', 'UNREAD', 'IMPORTANT') or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the list_labels tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, messageId: { description: "Required. The ID of the message to remove the labels from.", type: "string" } }, required: ["messageId", "labelIds"], type: "object" }, name: "unlabel_message", outputSchema: { description: "Response message for UnlabelMessage RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Adds a sensitive label (Trash or Spam) to a message." }, description: "Adds a sensitive label (Trash or Spam) to a specific message in the authenticated user's Gmail account.\n\nUse this tool to trash or mark a message as spam. To find the message ID, use tools like `search_threads` or `get_thread`.\n", inputSchema: { description: "Request message for ApplySensitiveMessageLabel RPC.", properties: { labelOption: { description: "Required. The sensitive label option to add.", enum: ["LABEL_OPTION_UNSPECIFIED", "TRASH", "SPAM"], type: "string", "x-google-enum-descriptions": ["Unspecified label option.", "Trash label.", "Spam label."] }, messageId: { description: "Required. The ID of the message to add the label to.", type: "string" } }, required: ["messageId", "labelOption"], type: "object" }, name: "apply_sensitive_message_label", outputSchema: { description: "Response message for ApplySensitiveMessageLabel RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: false, openWorldHint: false, readOnlyHint: false, title: "Creates a new label." }, description: "Creates a new label in the authenticated user's Gmail account.\nSupports creating nested labels (sub-labels) using a forward slash (e.g., 'Projects/Alpha/Sprint-1').\nBy default, parent labels will be automatically created if they do not exist.\n", inputSchema: { $defs: { LabelColor: { description: "The color of the label.", properties: { backgroundColor: { description: 'The background color of the label, represented as a hex string (e.g., "#ffffff"). Only the following predefined set of color values are allowed: # 000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, # fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, # f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, # efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, # e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, # cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, # ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, # 822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c, # 464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, # 711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, # 594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, # c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, # 662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765', type: "string" }, textColor: { description: 'The text color of the label, represented as a hex string (e.g., "#000000"). Only the following predefined set of color values are allowed: # 000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, # fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, # f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, # efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, # e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, # cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, # ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, # 822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c, # 464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, # 711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, # 594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, # c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, # 662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765', type: "string" } }, type: "object" } }, description: "Request message for CreateLabel RPC.", properties: { autoCreateParentLabels: { description: "Optional. Whether to automatically create parent labels for nested labels (separated by '/'). Defaults to true.", type: "boolean" }, color: { $ref: "#/$defs/LabelColor", description: "Optional. The color of the label." }, displayName: { description: "Required. The display name of the label to create.", type: "string" } }, required: ["displayName"], type: "object" }, name: "create_label", outputSchema: { $defs: { LabelColor: { description: "The color of the label.", properties: { backgroundColor: { description: 'The background color of the label, represented as a hex string (e.g., "#ffffff"). Only the following predefined set of color values are allowed: # 000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, # fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, # f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, # efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, # e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, # cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, # ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, # 822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c, # 464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, # 711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, # 594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, # c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, # 662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765', type: "string" }, textColor: { description: 'The text color of the label, represented as a hex string (e.g., "#000000"). Only the following predefined set of color values are allowed: # 000000, #434343, #666666, #999999, #cccccc, #efefef, #f3f3f3, #ffffff, # fb4c2f, #ffad47, #fad165, #16a766, #43d692, #4a86e8, #a479e2, #f691b3, # f6c5be, #ffe6c7, #fef1d1, #b9e4d0, #c6f3de, #c9daf8, #e4d7f5, #fcdee8, # efa093, #ffd6a2, #fce8b3, #89d3b2, #a0eac9, #a4c2f4, #d0bcf1, #fbc8d9, # e66550, #ffbc6b, #fcda83, #44b984, #68dfa9, #6d9eeb, #b694e8, #f7a7c0, # cc3a21, #eaa041, #f2c960, #149e60, #3dc789, #3c78d8, #8e63ce, #e07798, # ac2b16, #cf8933, #d5ae49, #0b804b, #2a9c68, #285bac, #653e9b, #b65775, # 822111, #a46a21, #aa8831, #076239, #1a764d, #1c4587, #41236d, #83334c, # 464646, #e7e7e7, #0d3472, #b6cff5, #0d3b44, #98d7e4, #3d188e, #e3d7ff, # 711a36, #fbd3e0, #8a1c0a, #f2b2a8, #7a2e0b, #ffc8af, #7a4706, #ffdeb5, # 594c05, #fbe983, #684e07, #fdedc1, #0b4f30, #b3efd3, #04502e, #a2dcc1, # c2c2c2, #4986e7, #2da2bb, #b99aff, #994a64, #f691b2, #ff7537, #ffad46, # 662e37, #ebdbde, #cca6ac, #094228, #42d692, #16a765', type: "string" } }, type: "object" } }, description: "Details of a label.", properties: { color: { $ref: "#/$defs/LabelColor", description: "Optional. The color of the label." }, labelId: { description: "The unique identifier of the label.", type: "string" }, name: { description: "The human-readable display name of the label.", type: "string" }, threadsTotal: { description: "The total number of threads under the label.", format: "int32", type: "integer" }, threadsUnread: { description: "The number of unread threads under the label.", format: "int32", type: "integer" } }, type: "object" } }] } };
2252
+ var mcp_tools_list_raw_default = { id: 1, jsonrpc: "2.0", result: { tools: [{ annotations: { destructiveHint: false, idempotentHint: false, openWorldHint: false, readOnlyHint: false, title: "Create draft email" }, description: "Creates a new draft email in the authenticated user's Gmail account.\n\nThis tool takes recipient addresses, a subject, and body content as inputs. If the draft is created as a reply to an existing message, the ID of the original message should be passed to the tool in the replyToMessageId field.\n\nReturns a Draft object with only the `id` field populated.\n", inputSchema: { $defs: { Attachment: { description: "Represents an attachment to be included in an email.", properties: { content: { description: "Required. The base64-encoded content of the attachment.", format: "byte", type: "string" }, filename: { description: 'Optional. The name of the file to be attached, e.g. "invoice.pdf". For inline attachments, this is used for Content-ID generation. For regular attachments, filename is used to specify the filename to email clients. If not provided, the attachment may be received with no name.', type: "string" }, id: { description: "Optional. Output only. When present, contains the ID of an external attachment that can be retrieved in a separate `GetMessageAttachment` request.", readOnly: true, type: "string" }, inline: { description: "Optional. If true, this attachment is handled as inline. An inline attachment is a content that is intended to be displayed within the body of an HTML email, as opposed to being listed as a separate file for download. If false or absent, defaults to false, and it's treated as a regular attachment.", type: "boolean" }, mimeType: { description: 'Optional. The field representing a content or media type must use IANA MIME type, https://www.iana.org/assignments/media-types/media-types.xhtml. If not provided, defaults to "application/octet-stream".', type: "string" } }, required: ["content"], type: "object" } }, description: "Request message for CreateDraft RPC.", properties: { attachments: { description: "Optional. The attachments to include in the email. The combined size of attachments in the message cannot exceed 25MB. If you need to send files larger than 25MB, upload the file to Drive first and then insert the Drive link into `body` or `html_body`.", items: { $ref: "#/$defs/Attachment" }, type: "array" }, bcc: { description: 'Optional. The blind carbon copy recipients of the email draft. Each string MUST be a valid plain email address (e.g., "user@example.com"). The "Name " format is NOT supported by this tool.', items: { type: "string" }, type: "array" }, body: { description: "Optional. The main body content of the email draft. If `html_body` is also provided, this field is treated as the plain-text alternative.", type: "string" }, cc: { description: 'Optional. The carbon copy recipients of the email draft. Each string MUST be a valid plain email address (e.g., "user@example.com"). The "Name " format is NOT supported by this tool.', items: { type: "string" }, type: "array" }, htmlBody: { description: "The HTML content of the email draft. If provided, this will be used as the rich-text version of the email.", type: "string" }, replyToMessageId: { description: "Optional. The ID of the message to reply to. If provided, this will be used as the reply-to message ID for the email draft, and the `body` and `html_body` will be appended to the original message body.", type: "string" }, subject: { description: "Optional. The subject line of the email. Defaults to empty if not provided.", type: "string" }, to: { description: 'Optional. The primary recipients of the email draft. Each string MUST be a valid plain email address (e.g., "user@example.com"). The "Name " format is NOT supported by this tool.', items: { type: "string" }, type: "array" } }, type: "object" }, name: "create_draft", outputSchema: { description: "Details of a draft.", properties: { bccRecipients: { description: "List of 'Bcc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, ccRecipients: { description: "List of 'Cc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, date: { description: "Date of the draft in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML body content of the draft, if available.", type: "string" }, id: { description: "The unique identifier of the draft resource.", type: "string" }, plaintextBody: { description: "Plain text body content, if available.", type: "string" }, subject: { description: "The subject line of the draft message.", type: "string" }, threadId: { description: "The ID of the thread this draft belongs to.", type: "string" }, toRecipients: { description: "List of 'To' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: false, openWorldHint: false, readOnlyHint: true, title: "List draft emails" }, description: "Lists draft emails from the authenticated user's Gmail account.\n\nThis tool can filter drafts based on a query string and supports pagination. It returns a list of drafts, including their IDs and subjects (unless `view` is set to `DRAFT_VIEW_METADATA_ONLY`). `page_token` can be used to paginate the results. To retrieve subsequent pages of results, use the `page_token` returned in the previous response.\n\nThe `view` parameter controls which fields are populated in the response. By default (or with `DRAFT_VIEW_FULL`), it returns full content. Use `DRAFT_VIEW_METADATA_ONLY` to exclude sensitive content like subject and body. \n", inputSchema: { description: "Request message for ListDrafts RPC.", properties: { pageSize: { description: "Optional. The maximum number of drafts to return. If unspecified, defaults to 20. The maximum allowed value is 50.", format: "int32", type: "integer" }, pageToken: { description: "Optional. A token received from a previous list_drafts call to retrieve the next page of results. Leave empty to fetch the first page. This is primarily used for pagination to continue fetching results from where the previous `ListDraft` call left off, especially when the number of drafts matching the query exceeds the page_size limit.", type: "string" }, query: { description: "Examples: - `subject:OneMCP Update` - `from:gduser1@workspacesamples.dev` - `to:gduser2@workspacesamples.dev AND newer_than:7d` - `project proposal has:attachment` - `is:unread` A space or a dash (`-`) will separate a number while a dot (`.`) will be a decimal. For example, `01.2047-100` is considered two numbers: `01.2047` and `100`. Note: If we want to ensure all drafts for the query are returned, we can paginate the results by making repeated calls to the tool until the response contains an empty list of drafts.", type: "string" }, view: { description: "Optional. Controls the fields populated for drafts in the draft list. Defaults to returning metadata only (`id`, `thread_id`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`). Set to `DRAFT_VIEW_FULL` to include `subject` and `plaintext_body` content.", enum: ["DRAFT_VIEW_UNSPECIFIED", "DRAFT_VIEW_METADATA_ONLY", "DRAFT_VIEW_FULL"], type: "string", "x-google-enum-descriptions": ["Unspecified view. Defaults to DRAFT_VIEW_METADATA_ONLY.", "Returns metadata only (`id`, `thread_id`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`); omits `subject` and `plaintext_body` content.", "Returns full draft content, including `subject` and `plaintext_body` in addition to draft metadata."] } }, type: "object" }, name: "list_drafts", outputSchema: { $defs: { Draft: { description: "Details of a draft.", properties: { bccRecipients: { description: "List of 'Bcc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, ccRecipients: { description: "List of 'Cc' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" }, date: { description: "Date of the draft in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML body content of the draft, if available.", type: "string" }, id: { description: "The unique identifier of the draft resource.", type: "string" }, plaintextBody: { description: "Plain text body content, if available.", type: "string" }, subject: { description: "The subject line of the draft message.", type: "string" }, threadId: { description: "The ID of the thread this draft belongs to.", type: "string" }, toRecipients: { description: "List of 'To' recipient email addresses extracted from headers.", items: { type: "string" }, type: "array" } }, type: "object" } }, description: "Response message for ListDrafts RPC.", properties: { drafts: { description: "List of drafts.", items: { $ref: "#/$defs/Draft" }, type: "array" }, nextPageToken: { description: "A token that can be used in a subsequent call to retrieve the next page of drafts. If the number of drafts matching the query exceeds the page_size limit, the response will contain a `next_page_token`. To retrieve the next page of results, pass this token in the `page_token` field of the next `ListDraftsRequest`.", type: "string" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "Get email thread" }, description: "Retrieves a specific email thread from the authenticated user's Gmail account, including a list of its messages.\n\nThe optional `messageFormat` parameter controls the format of the messages returned. By default (or with `FULL_CONTENT`), it returns the full content of messages. Use `MINIMAL` to include only subject and snippet (excluding body). Use `METADATA_ONLY` to include only basic metadata (message ID, thread ID, labels, timestamp, and size estimate). \n", inputSchema: { description: "Request message for GetThread RPC.", properties: { messageFormat: { description: "Optional. Specifies the format of the messages returned within the thread. Defaults to `FULL_CONTENT`. Note: `MINIMAL` format returns `id`, `snippet`, `subject`, `sender`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`, `label_ids`. `METADATA_ONLY` format returns `id`, `sender`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`, `label_ids`. `FULL_CONTENT` returns `id`, `snippet`, `subject`, `sender`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`, `label_ids`, `attachment_ids`, `plaintext_body`, `html_body`, `attachments`.", enum: ["MESSAGE_FORMAT_UNSPECIFIED", "MINIMAL", "FULL_CONTENT", "METADATA_ONLY"], type: "string", "x-google-enum-descriptions": ["Defaults to FULL_CONTENT.", "Returns message snippets and key headers (Subject, From, To, Cc, Date).", 'Returns all information in "MINIMAL" plus the full body content of each message.', "Metadata only: does not include subject, snippet, body, attachment filenames."] }, threadId: { description: "Required. The unique identifier of the thread to fetch.", type: "string" } }, required: ["threadId"], type: "object" }, name: "get_thread", outputSchema: { $defs: { AttachmentMetadata: { description: "Represents an attachment associated with a message.", properties: { filename: { description: "The filename of the attachment.", type: "string" }, id: { description: "Output only. The ID of the attachment.", readOnly: true, type: "string" }, mimeType: { description: "The MIME type of the attachment.", type: "string" } }, type: "object" }, Message: { description: "Message within a thread.", properties: { attachmentIds: { description: "Output only. The attachment ids, only populated if MessageFormat was FULL_CONTENT.", items: { type: "string" }, readOnly: true, type: "array" }, attachments: { description: "Output only. The attachments, only populated if MessageFormat was FULL_CONTENT.", items: { $ref: "#/$defs/AttachmentMetadata" }, readOnly: true, type: "array" }, bccRecipients: { description: "BCC recipient email addresses.", items: { type: "string" }, type: "array" }, ccRecipients: { description: "CC recipient email addresses.", items: { type: "string" }, type: "array" }, date: { description: "Date of the message in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML content of the email, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, id: { description: "The unique identifier of the message.", type: "string" }, labelIds: { description: "The ids of the labels attached to the message. Includes ids of user labels and standard system labels limited to `INBOX`, `SPAM`, `TRASH`, `UNREAD`, `STARRED`, `IMPORTANT`, `SENT`, `DRAFT`, `CHAT`.", items: { type: "string" }, type: "array" }, plaintextBody: { description: "Full body content, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, sender: { description: "Sender email address.", type: "string" }, snippet: { description: "Snippet of the message body.", type: "string" }, subject: { description: "The message subject extracted from headers:", type: "string" }, toRecipients: { description: "To recipient email addresses.", items: { type: "string" }, type: "array" } }, type: "object" } }, description: "Thread containing a list of messages.", properties: { id: { description: "The unique identifier of the thread.", type: "string" }, messages: { description: "A list of messages in the thread, ordered chronologically.", items: { $ref: "#/$defs/Message" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "Get email message" }, description: 'Retrieves a specific email message from the authenticated user\'s Gmail account by its unique message ID.\n\nUse this tool to inspect a single, individual email when you already know its message ID. If the user wants to read a specific email in detail, check the exact wording of a message, or examine attachment metadata for a single email, this is the right tool. It is not suitable for retrieving entire conversations or viewing back-and-forth discussion threads; use the \'get_thread\' tool instead.\nKey indicators include if the user asks for the full content of a specific message ID returned by a previous search, or if the query asks to inspect a specific individual email rather than an entire thread.\nExample user prompts are: "Get the full text of message ID 18f123456789abcd.", "Read the latest message in that thread from Alice.", and "What are the attachment names in the email I just received from HR?" \n\nThe optional `messageFormat` parameter controls the format of the message returned. By default (or with `FULL_CONTENT`), it returns the full content of the message. Use `MINIMAL` to include only subject and snippet (excluding body). Use `METADATA_ONLY` to include only basic metadata (message ID, thread ID, labels, timestamp, and size estimate). \n', inputSchema: { description: "Request message for GetMessage RPC.", properties: { messageFormat: { description: "Optional. Specifies the format of the message returned. Defaults to FULL_CONTENT.", enum: ["MESSAGE_FORMAT_UNSPECIFIED", "MINIMAL", "FULL_CONTENT", "METADATA_ONLY"], type: "string", "x-google-enum-descriptions": ["Defaults to FULL_CONTENT.", "Returns message snippets and key headers (Subject, From, To, Cc, Date).", 'Returns all information in "MINIMAL" plus the full body content of each message.', "Metadata only: does not include subject, snippet, body, attachment filenames."] }, messageId: { description: "Required. The unique identifier of the message to fetch.", type: "string" } }, required: ["messageId"], type: "object" }, name: "get_message", outputSchema: { $defs: { AttachmentMetadata: { description: "Represents an attachment associated with a message.", properties: { filename: { description: "The filename of the attachment.", type: "string" }, id: { description: "Output only. The ID of the attachment.", readOnly: true, type: "string" }, mimeType: { description: "The MIME type of the attachment.", type: "string" } }, type: "object" } }, description: "Message within a thread.", properties: { attachmentIds: { description: "Output only. The attachment ids, only populated if MessageFormat was FULL_CONTENT.", items: { type: "string" }, readOnly: true, type: "array" }, attachments: { description: "Output only. The attachments, only populated if MessageFormat was FULL_CONTENT.", items: { $ref: "#/$defs/AttachmentMetadata" }, readOnly: true, type: "array" }, bccRecipients: { description: "BCC recipient email addresses.", items: { type: "string" }, type: "array" }, ccRecipients: { description: "CC recipient email addresses.", items: { type: "string" }, type: "array" }, date: { description: "Date of the message in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML content of the email, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, id: { description: "The unique identifier of the message.", type: "string" }, labelIds: { description: "The ids of the labels attached to the message. Includes ids of user labels and standard system labels limited to `INBOX`, `SPAM`, `TRASH`, `UNREAD`, `STARRED`, `IMPORTANT`, `SENT`, `DRAFT`, `CHAT`.", items: { type: "string" }, type: "array" }, plaintextBody: { description: "Full body content, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, sender: { description: "Sender email address.", type: "string" }, snippet: { description: "Snippet of the message body.", type: "string" }, subject: { description: "The message subject extracted from headers:", type: "string" }, toRecipients: { description: "To recipient email addresses.", items: { type: "string" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "Search email threads" }, description: "Lists email threads from the authenticated user's Gmail account.\n\nThis tool can filter threads based on a query string and supports pagination. It returns a list of threads, including their IDs and related messages. Each related message contains details like a snippet of the message body, the subject, the sender, the recipients etc. The `view` parameter controls which fields are populated in the related messages. By default (or with `THREAD_VIEW_MINIMAL`), it includes subject and snippet. Use `THREAD_VIEW_METADATA_ONLY` to exclude subject and snippet. Note that the full message bodies are not returned by this tool; use the 'get_thread' tool with a thread ID to fetch the full message body if needed. Threads with excluded criteria may still appear in the results. This occurs because Gmail identifies matching messages first. For example, if you search for -is:starred, Gmail will find an entire thread if it contains at least one unstarred message, even if other emails in that same conversation are starred.\n", inputSchema: { description: "Request message for SearchThreads RPC.", properties: { includeTrash: { description: "Optional. Include threads from TRASH in the results. Defaults to false.", type: "boolean" }, pageSize: { description: "Optional. The maximum number of threads to return. If unspecified, defaults to 20. The maximum allowed value is 50.", format: "int32", type: "integer" }, pageToken: { description: "Optional. Page token to retrieve a specific page of results in the list. Leave empty to fetch the first page. This is primarily used for pagination to continue fetching results from where the previous `SearchThreads` call left off, especially when the number of threads matching the query exceeds the page_size limit.", type: "string" }, query: { description: 'Optional. A query string to filter the threads. Natural language queries must be pre-converted into Gmail syntax queries to use this tool. If omitted, all threads (excluding spam and trash by default) are listed. Supported Operators by Category: Sender & Recipient: - `from:` \u2014 Sent from a specific person. - `to:` \u2014 Sent to a specific person. - `cc:` \u2014 Specific people in Cc. - `bcc:` \u2014 Specific people in Bcc. - `deliveredto:` \u2014 Delivered to a specific address. - `list:` \u2014 From a specific mailing list. Time & Date: - `after:YYYY/MM/DD` / `newer:YYYY/MM/DD` \u2014 Received after a date. - `before:YYYY/MM/DD` / `older:YYYY/MM/DD` \u2014 Received before a date. - `older_than:` \u2014 Older than a duration (for example, `1y`, `2d`). - `newer_than:` \u2014 Newer than a duration. Content: - `subject:` \u2014 Words in the subject line. - `has:` \u2014 Has specific content types (attachment, drive, youtube, document). - `filename:` \u2014 Attachment with a specific name or type. - `""` \u2014 Search for an exact word or phrase. (for example, `"holiday"`, `"holiday vacation"`). - `+` \u2014 Match a word exactly. (for example, `+holiday`, `+unicorn`) - `rfc822msgid:` \u2014 Specific message ID header. - `AROUND ` \u2014 Find words near each other (for example, `holiday AROUND 10 vacation`). Labels & Categories: - `label:` \u2014 Under a specific label. The tool accepts label IDs, not display names. Use the list_labels tool to get the ID. - `category:` \u2014 In a category (primary, social, promotions, updates, forums, reservations, purchases). - `in:` \u2014 Search in specific labels (archive, snoozed, trash, sent, inbox). For example, `in:trash`, `in:inbox`. Archived and sent messages are included by default; use `-in:archive` and `-in:sent` to exclude them. Drafts are explicitly excluded by default by the tool. Use `in:inbox` to restrict search to the inbox only. - `has:userlabels` \u2014 Has any user labels. - `has:nouserlabels` \u2014 Does not have any user labels. - `has:*-star` \u2014 Specific star colors (if enabled, for example, `has:yellow-star`). - `in:draft` \u2014 Search in drafts. -in:draft means exclude drafts from the search results. - `in:sent` \u2014 Search in sent messages. - `in:anywhere` \u2014 Search in all folders (including spam and trash). Status: - `is:` \u2014 Search by status (important, starred, unread, read, muted). Size: - `size:` \u2014 Specific size in bytes. - `larger:` / `smaller:` \u2014 Larger or smaller than a size (for example, `10M` for 10 MB). Logic & Grouping: - `AND` \u2014 Match all criteria (default behavior). - `OR` or `{ }` \u2014 Match one or more criteria (for example, `from:amy OR from:david`, `{from:amy from:david}`). - `-` (minus) \u2014 Exclude criteria (for example, `-movie`). - `( )` \u2014 Group multiple search terms (for example, `subject:(dinner film)`). Examples: - `subject:OneMCP Update` - `from:user@example.com` - `to:user2@example.com AND newer_than:7d` - `project proposal has:attachment` - `is:unread -in:draft`', type: "string" }, view: { description: "Optional. Controls the fields populated for threads in the thread list. Defaults to `THREAD_VIEW_MINIMAL`. `THREAD_VIEW_MINIMAL` returns `id`, `snippet`, `subject`, `sender`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`, `label_ids`. `THREAD_VIEW_METADATA_ONLY` returns `id`, `sender`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`, `label_ids`.", enum: ["THREAD_VIEW_UNSPECIFIED", "THREAD_VIEW_METADATA_ONLY", "THREAD_VIEW_MINIMAL"], type: "string", "x-google-enum-descriptions": ["Maps to THREAD_VIEW_MINIMAL for backward compatibility.", "Returns `id`, `sender`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`, `label_ids`.", "Returns `id`, `snippet`, `subject`, `sender`, `to_recipients`, `cc_recipients`, `bcc_recipients`, `date`, `label_ids`."] } }, type: "object" }, name: "search_threads", outputSchema: { $defs: { AttachmentMetadata: { description: "Represents an attachment associated with a message.", properties: { filename: { description: "The filename of the attachment.", type: "string" }, id: { description: "Output only. The ID of the attachment.", readOnly: true, type: "string" }, mimeType: { description: "The MIME type of the attachment.", type: "string" } }, type: "object" }, Message: { description: "Message within a thread.", properties: { attachmentIds: { description: "Output only. The attachment ids, only populated if MessageFormat was FULL_CONTENT.", items: { type: "string" }, readOnly: true, type: "array" }, attachments: { description: "Output only. The attachments, only populated if MessageFormat was FULL_CONTENT.", items: { $ref: "#/$defs/AttachmentMetadata" }, readOnly: true, type: "array" }, bccRecipients: { description: "BCC recipient email addresses.", items: { type: "string" }, type: "array" }, ccRecipients: { description: "CC recipient email addresses.", items: { type: "string" }, type: "array" }, date: { description: "Date of the message in ISO 8601 format (YYYY-MM-DD).", type: "string" }, htmlBody: { description: "The HTML content of the email, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, id: { description: "The unique identifier of the message.", type: "string" }, labelIds: { description: "The ids of the labels attached to the message. Includes ids of user labels and standard system labels limited to `INBOX`, `SPAM`, `TRASH`, `UNREAD`, `STARRED`, `IMPORTANT`, `SENT`, `DRAFT`, `CHAT`.", items: { type: "string" }, type: "array" }, plaintextBody: { description: "Full body content, only populated if MessageFormat was FULL_CONTENT.", type: "string" }, sender: { description: "Sender email address.", type: "string" }, snippet: { description: "Snippet of the message body.", type: "string" }, subject: { description: "The message subject extracted from headers:", type: "string" }, toRecipients: { description: "To recipient email addresses.", items: { type: "string" }, type: "array" } }, type: "object" }, Thread: { description: "Thread containing a list of messages.", properties: { id: { description: "The unique identifier of the thread.", type: "string" }, messages: { description: "A list of messages in the thread, ordered chronologically.", items: { $ref: "#/$defs/Message" }, type: "array" } }, type: "object" } }, description: "Response message for SearchThreads RPC.", properties: { nextPageToken: { description: "A token that can be used in a subsequent call to retrieve the next page of threads. Present only if there are more results. If the number of threads matching the query exceeds the page_size limit, the response will contain a `next_page_token`. To retrieve the next page of results, pass this token in the `page_token` field of the next `SearchThreadsRequest`.", type: "string" }, resultCountEstimate: { description: 'The estimated result count for this query. It should be treated as a lower bound, so for example if it is 500, then the count can be reported to the user as "500+".', format: "int64", type: "string" }, threads: { description: "List of thread summaries.", items: { $ref: "#/$defs/Thread" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Add labels to thread" }, description: "Adds labels to an entire thread in the authenticated user's Gmail account. This operation affects all messages currently in the thread and any future messages added to it.\n\nIf unsure of the thread ID, use the `search_threads` tool first.\n\nIf unsure of a user label's ID, use the `list_labels` tool first to discover available labels and their IDs. To add a Trash label or a Spam label to a thread, or move a specific thread to Trash, please use the `apply_sensitive_thread_label` tool instead.\n", inputSchema: { description: "Request message for LabelThread RPC.", properties: { labelIds: { description: "Required. The unique identifiers of the labels to add. Can be a system label ID (e.g., `INBOX`, `STARRED`, `UNREAD`, `IMPORTANT`) or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the `list_labels` tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, threadId: { description: "Required. The unique identifier of the thread to add labels to.", type: "string" } }, required: ["threadId", "labelIds"], type: "object" }, name: "label_thread", outputSchema: { description: "Response message for LabelThread RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Remove labels from thread" }, description: "Removes labels from an entire thread in the authenticated user's Gmail account. If unsure of the thread ID, use the `search_threads` tool first. If unsure of a user label's ID, use the `list_labels` tool first.", inputSchema: { description: "Request message for UnlabelThread RPC.", properties: { labelIds: { description: "Required. The unique identifiers of the labels to remove. Can be a system label ID (e.g., `INBOX`, `TRASH`, `SPAM`, `STARRED`, `UNREAD`, `IMPORTANT`) or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the `list_labels` tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, threadId: { description: "Required. The unique identifier of the thread to remove labels from.", type: "string" } }, required: ["threadId", "labelIds"], type: "object" }, name: "unlabel_thread", outputSchema: { description: "Response message for UnlabelThread RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Apply sensitive label (Trash or Spam) to thread" }, description: "Adds a sensitive label (Trash or Spam) to an entire thread in the authenticated user's Gmail account. This operation affects all messages currently in the thread and any future messages added to it.\n\nUse this tool to trash a thread, mark a thread as spam, or move the specified thread to Trash.\n\nTo find the thread ID, use the `search_threads` tool first.\n", inputSchema: { description: "Request message for ApplySensitiveThreadLabel RPC.", properties: { labelOption: { description: "Required. The sensitive label option to add.", enum: ["LABEL_OPTION_UNSPECIFIED", "TRASH", "SPAM"], type: "string", "x-google-enum-descriptions": ["Unspecified label option.", "Trash label.", "Spam label."] }, threadId: { description: "Required. The ID of the thread to add the label to.", type: "string" } }, required: ["threadId", "labelOption"], type: "object" }, name: "apply_sensitive_thread_label", outputSchema: { description: "Response message for ApplySensitiveThreadLabel RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: true, title: "List labels" }, description: "Lists all labels available in the authenticated user's Gmail account. Use this tool to discover the `id` of a label before calling `label_thread`, `unlabel_thread`, `label_message`, or `unlabel_message`. Note: the system labels, `DRAFT` and `SENT`, cannot be set on messages and are read only.", inputSchema: { description: "Request message for ListLabels RPC.", properties: {}, type: "object" }, name: "list_labels", outputSchema: { $defs: { Label: { description: "Details of a label.", properties: { color: { $ref: "#/$defs/LabelColor", description: "Optional. The color of the label." }, labelId: { description: "The unique identifier of the label.", type: "string" }, messagesTotal: { description: "The total number of messages under the label.", format: "int32", type: "integer" }, messagesUnread: { description: "The number of unread messages under the label.", format: "int32", type: "integer" }, name: { description: "The human-readable display name of the label.", type: "string" }, threadsTotal: { description: "The total number of threads under the label.", format: "int32", type: "integer" }, threadsUnread: { description: "The number of unread threads under the label.", format: "int32", type: "integer" } }, type: "object" }, LabelColor: { description: "The color of the label.", properties: { backgroundColor: { description: 'The background color of the label, represented as a hex string (e.g., "#ffffff"). Only the following predefined set of color values are allowed: `#000000`, `#434343`, `#666666`, `#999999`, `#cccccc`, `#efefef`, `#f3f3f3`, `#ffffff`, `#fb4c2f`, `#ffad47`, `#fad165`, `#16a766`, `#43d692`, `#4a86e8`, `#a479e2`, `#f691b3`, `#f6c5be`, `#ffe6c7`, `#fef1d1`, `#b9e4d0`, `#c6f3de`, `#c9daf8`, `#e4d7f5`, `#fcdee8`, `#efa093`, `#ffd6a2`, `#fce8b3`, `#89d3b2`, `#a0eac9`, `#a4c2f4`, `#d0bcf1`, `#fbc8d9`, `#e66550`, `#ffbc6b`, `#fcda83`, `#44b984`, `#68dfa9`, `#6d9eeb`, `#b694e8`, `#f7a7c0`, `#cc3a21`, `#eaa041`, `#f2c960`, `#149e60`, `#3dc789`, `#3c78d8`, `#8e63ce`, `#e07798`, `#ac2b16`, `#cf8933`, `#d5ae49`, `#0b804b`, `#2a9c68`, `#285bac`, `#653e9b`, `#b65775`, `#822111`, `#a46a21`, `#aa8831`, `#076239`, `#1a764d`, `#1c4587`, `#41236d`, `#83334c`, `#464646`, `#e7e7e7`, `#0d3472`, `#b6cff5`, `#0d3b44`, `#98d7e4`, `#3d188e`, `#e3d7ff`, `#711a36`, `#fbd3e0`, `#8a1c0a`, `#f2b2a8`, `#7a2e0b`, `#ffc8af`, `#7a4706`, `#ffdeb5`, `#594c05`, `#fbe983`, `#684e07`, `#fdedc1`, `#0b4f30`, `#b3efd3`, `#04502e`, `#a2dcc1`, `#c2c2c2`, `#4986e7`, `#2da2bb`, `#b99aff`, `#994a64`, `#f691b2`, `#ff7537`, `#ffad46`, `#662e37`, `#ebdbde`, `#cca6ac`, `#094228`, `#42d692`, `#16a765`', type: "string" }, textColor: { description: 'The text color of the label, represented as a hex string (e.g., "#000000"). Only the following predefined set of color values are allowed: `#000000`, `#434343`, `#666666`, `#999999`, `#cccccc`, `#efefef`, `#f3f3f3`, `#ffffff`, `#fb4c2f`, `#ffad47`, `#fad165`, `#16a766`, `#43d692`, `#4a86e8`, `#a479e2`, `#f691b3`, `#f6c5be`, `#ffe6c7`, `#fef1d1`, `#b9e4d0`, `#c6f3de`, `#c9daf8`, `#e4d7f5`, `#fcdee8`, `#efa093`, `#ffd6a2`, `#fce8b3`, `#89d3b2`, `#a0eac9`, `#a4c2f4`, `#d0bcf1`, `#fbc8d9`, `#e66550`, `#ffbc6b`, `#fcda83`, `#44b984`, `#68dfa9`, `#6d9eeb`, `#b694e8`, `#f7a7c0`, `#cc3a21`, `#eaa041`, `#f2c960`, `#149e60`, `#3dc789`, `#3c78d8`, `#8e63ce`, `#e07798`, `#ac2b16`, `#cf8933`, `#d5ae49`, `#0b804b`, `#2a9c68`, `#285bac`, `#653e9b`, `#b65775`, `#822111`, `#a46a21`, `#aa8831`, `#076239`, `#1a764d`, `#1c4587`, `#41236d`, `#83334c`, `#464646`, `#e7e7e7`, `#0d3472`, `#b6cff5`, `#0d3b44`, `#98d7e4`, `#3d188e`, `#e3d7ff`, `#711a36`, `#fbd3e0`, `#8a1c0a`, `#f2b2a8`, `#7a2e0b`, `#ffc8af`, `#7a4706`, `#ffdeb5`, `#594c05`, `#fbe983`, `#684e07`, `#fdedc1`, `#0b4f30`, `#b3efd3`, `#04502e`, `#a2dcc1`, `#c2c2c2`, `#4986e7`, `#2da2bb`, `#b99aff`, `#994a64`, `#f691b2`, `#ff7537`, `#ffad46`, `#662e37`, `#ebdbde`, `#cca6ac`, `#094228`, `#42d692`, `#16a765`', type: "string" } }, type: "object" } }, description: "Response message for ListLabels RPC.", properties: { labels: { description: "List of all labels in the user's account.", items: { $ref: "#/$defs/Label" }, type: "array" } }, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Add labels to message" }, description: "Adds one or more labels to a specific message in the authenticated user's Gmail account.\n\nTo find the message ID, use tools like `search_threads` or `get_thread`. If unsure of a user label's ID, use the `list_labels` tool first to discover available labels and their IDs.\nTo add a Trash label or a Spam label to a message, or move a specific message to Trash, please use the `apply_sensitive_message_label` tool instead.\n", inputSchema: { description: "Request message for LabelMessage RPC.", properties: { labelIds: { description: "Required. The IDs of the labels to add. Can be a system label ID (e.g., `INBOX`, `STARRED`, `UNREAD`, `IMPORTANT`) or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the `list_labels` tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, messageId: { description: "Required. The ID of the message to add the labels to.", type: "string" } }, required: ["messageId", "labelIds"], type: "object" }, name: "label_message", outputSchema: { description: "Response message for LabelMessage RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Remove labels from message" }, description: "Removes one or more labels from a specific message in the authenticated user's Gmail account. To find the message ID, use tools like `search_threads` or `get_thread`. If unsure of a user label's ID, use the `list_labels` tool first to discover available labels and their IDs.", inputSchema: { description: "Request message for UnlabelMessage RPC.", properties: { labelIds: { description: "Required. The IDs of the labels to remove. Can be a system label ID (e.g., `INBOX`, `TRASH`, `SPAM`, `STARRED`, `UNREAD`, `IMPORTANT`) or a user-defined label ID. The tool accepts `label_ids` and not label names. Use the `list_labels` tool to get the corresponding label id to a display name for user-defined labels.", items: { type: "string" }, type: "array" }, messageId: { description: "Required. The ID of the message to remove the labels from.", type: "string" } }, required: ["messageId", "labelIds"], type: "object" }, name: "unlabel_message", outputSchema: { description: "Response message for UnlabelMessage RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: true, idempotentHint: true, openWorldHint: false, readOnlyHint: false, title: "Apply sensitive label (Trash or Spam) to message" }, description: "Adds a sensitive label (Trash or Spam) to a specific message in the authenticated user's Gmail account.\n\nUse this tool to trash a message, mark a message as spam, or move the specified message to Trash.\n\nTo find the message ID, use tools like `search_threads` or `get_thread`. To find the draft message ID, use tools like `list_drafts`.\n", inputSchema: { description: "Request message for ApplySensitiveMessageLabel RPC.", properties: { labelOption: { description: "Required. The sensitive label option to add.", enum: ["LABEL_OPTION_UNSPECIFIED", "TRASH", "SPAM"], type: "string", "x-google-enum-descriptions": ["Unspecified label option.", "Trash label.", "Spam label."] }, messageId: { description: "Required. The ID of the message to add the label to.", type: "string" } }, required: ["messageId", "labelOption"], type: "object" }, name: "apply_sensitive_message_label", outputSchema: { description: "Response message for ApplySensitiveMessageLabel RPC.", properties: {}, type: "object" } }, { annotations: { destructiveHint: false, idempotentHint: false, openWorldHint: false, readOnlyHint: false, title: "Create label" }, description: "Creates a new label in the authenticated user's Gmail account.\nSupports creating nested labels (sub-labels) using a forward slash (e.g., 'Projects/Alpha/Sprint-1').\nBy default, parent labels will be automatically created if they do not exist.\n", inputSchema: { $defs: { LabelColor: { description: "The color of the label.", properties: { backgroundColor: { description: 'The background color of the label, represented as a hex string (e.g., "#ffffff"). Only the following predefined set of color values are allowed: `#000000`, `#434343`, `#666666`, `#999999`, `#cccccc`, `#efefef`, `#f3f3f3`, `#ffffff`, `#fb4c2f`, `#ffad47`, `#fad165`, `#16a766`, `#43d692`, `#4a86e8`, `#a479e2`, `#f691b3`, `#f6c5be`, `#ffe6c7`, `#fef1d1`, `#b9e4d0`, `#c6f3de`, `#c9daf8`, `#e4d7f5`, `#fcdee8`, `#efa093`, `#ffd6a2`, `#fce8b3`, `#89d3b2`, `#a0eac9`, `#a4c2f4`, `#d0bcf1`, `#fbc8d9`, `#e66550`, `#ffbc6b`, `#fcda83`, `#44b984`, `#68dfa9`, `#6d9eeb`, `#b694e8`, `#f7a7c0`, `#cc3a21`, `#eaa041`, `#f2c960`, `#149e60`, `#3dc789`, `#3c78d8`, `#8e63ce`, `#e07798`, `#ac2b16`, `#cf8933`, `#d5ae49`, `#0b804b`, `#2a9c68`, `#285bac`, `#653e9b`, `#b65775`, `#822111`, `#a46a21`, `#aa8831`, `#076239`, `#1a764d`, `#1c4587`, `#41236d`, `#83334c`, `#464646`, `#e7e7e7`, `#0d3472`, `#b6cff5`, `#0d3b44`, `#98d7e4`, `#3d188e`, `#e3d7ff`, `#711a36`, `#fbd3e0`, `#8a1c0a`, `#f2b2a8`, `#7a2e0b`, `#ffc8af`, `#7a4706`, `#ffdeb5`, `#594c05`, `#fbe983`, `#684e07`, `#fdedc1`, `#0b4f30`, `#b3efd3`, `#04502e`, `#a2dcc1`, `#c2c2c2`, `#4986e7`, `#2da2bb`, `#b99aff`, `#994a64`, `#f691b2`, `#ff7537`, `#ffad46`, `#662e37`, `#ebdbde`, `#cca6ac`, `#094228`, `#42d692`, `#16a765`', type: "string" }, textColor: { description: 'The text color of the label, represented as a hex string (e.g., "#000000"). Only the following predefined set of color values are allowed: `#000000`, `#434343`, `#666666`, `#999999`, `#cccccc`, `#efefef`, `#f3f3f3`, `#ffffff`, `#fb4c2f`, `#ffad47`, `#fad165`, `#16a766`, `#43d692`, `#4a86e8`, `#a479e2`, `#f691b3`, `#f6c5be`, `#ffe6c7`, `#fef1d1`, `#b9e4d0`, `#c6f3de`, `#c9daf8`, `#e4d7f5`, `#fcdee8`, `#efa093`, `#ffd6a2`, `#fce8b3`, `#89d3b2`, `#a0eac9`, `#a4c2f4`, `#d0bcf1`, `#fbc8d9`, `#e66550`, `#ffbc6b`, `#fcda83`, `#44b984`, `#68dfa9`, `#6d9eeb`, `#b694e8`, `#f7a7c0`, `#cc3a21`, `#eaa041`, `#f2c960`, `#149e60`, `#3dc789`, `#3c78d8`, `#8e63ce`, `#e07798`, `#ac2b16`, `#cf8933`, `#d5ae49`, `#0b804b`, `#2a9c68`, `#285bac`, `#653e9b`, `#b65775`, `#822111`, `#a46a21`, `#aa8831`, `#076239`, `#1a764d`, `#1c4587`, `#41236d`, `#83334c`, `#464646`, `#e7e7e7`, `#0d3472`, `#b6cff5`, `#0d3b44`, `#98d7e4`, `#3d188e`, `#e3d7ff`, `#711a36`, `#fbd3e0`, `#8a1c0a`, `#f2b2a8`, `#7a2e0b`, `#ffc8af`, `#7a4706`, `#ffdeb5`, `#594c05`, `#fbe983`, `#684e07`, `#fdedc1`, `#0b4f30`, `#b3efd3`, `#04502e`, `#a2dcc1`, `#c2c2c2`, `#4986e7`, `#2da2bb`, `#b99aff`, `#994a64`, `#f691b2`, `#ff7537`, `#ffad46`, `#662e37`, `#ebdbde`, `#cca6ac`, `#094228`, `#42d692`, `#16a765`', type: "string" } }, type: "object" } }, description: "Request message for CreateLabel RPC.", properties: { autoCreateParentLabels: { description: "Optional. Whether to automatically create parent labels for nested labels (separated by '/'). Defaults to true.", type: "boolean" }, color: { $ref: "#/$defs/LabelColor", description: "Optional. The color of the label." }, displayName: { description: "Required. The display name of the label to create.", type: "string" } }, required: ["displayName"], type: "object" }, name: "create_label", outputSchema: { $defs: { LabelColor: { description: "The color of the label.", properties: { backgroundColor: { description: 'The background color of the label, represented as a hex string (e.g., "#ffffff"). Only the following predefined set of color values are allowed: `#000000`, `#434343`, `#666666`, `#999999`, `#cccccc`, `#efefef`, `#f3f3f3`, `#ffffff`, `#fb4c2f`, `#ffad47`, `#fad165`, `#16a766`, `#43d692`, `#4a86e8`, `#a479e2`, `#f691b3`, `#f6c5be`, `#ffe6c7`, `#fef1d1`, `#b9e4d0`, `#c6f3de`, `#c9daf8`, `#e4d7f5`, `#fcdee8`, `#efa093`, `#ffd6a2`, `#fce8b3`, `#89d3b2`, `#a0eac9`, `#a4c2f4`, `#d0bcf1`, `#fbc8d9`, `#e66550`, `#ffbc6b`, `#fcda83`, `#44b984`, `#68dfa9`, `#6d9eeb`, `#b694e8`, `#f7a7c0`, `#cc3a21`, `#eaa041`, `#f2c960`, `#149e60`, `#3dc789`, `#3c78d8`, `#8e63ce`, `#e07798`, `#ac2b16`, `#cf8933`, `#d5ae49`, `#0b804b`, `#2a9c68`, `#285bac`, `#653e9b`, `#b65775`, `#822111`, `#a46a21`, `#aa8831`, `#076239`, `#1a764d`, `#1c4587`, `#41236d`, `#83334c`, `#464646`, `#e7e7e7`, `#0d3472`, `#b6cff5`, `#0d3b44`, `#98d7e4`, `#3d188e`, `#e3d7ff`, `#711a36`, `#fbd3e0`, `#8a1c0a`, `#f2b2a8`, `#7a2e0b`, `#ffc8af`, `#7a4706`, `#ffdeb5`, `#594c05`, `#fbe983`, `#684e07`, `#fdedc1`, `#0b4f30`, `#b3efd3`, `#04502e`, `#a2dcc1`, `#c2c2c2`, `#4986e7`, `#2da2bb`, `#b99aff`, `#994a64`, `#f691b2`, `#ff7537`, `#ffad46`, `#662e37`, `#ebdbde`, `#cca6ac`, `#094228`, `#42d692`, `#16a765`', type: "string" }, textColor: { description: 'The text color of the label, represented as a hex string (e.g., "#000000"). Only the following predefined set of color values are allowed: `#000000`, `#434343`, `#666666`, `#999999`, `#cccccc`, `#efefef`, `#f3f3f3`, `#ffffff`, `#fb4c2f`, `#ffad47`, `#fad165`, `#16a766`, `#43d692`, `#4a86e8`, `#a479e2`, `#f691b3`, `#f6c5be`, `#ffe6c7`, `#fef1d1`, `#b9e4d0`, `#c6f3de`, `#c9daf8`, `#e4d7f5`, `#fcdee8`, `#efa093`, `#ffd6a2`, `#fce8b3`, `#89d3b2`, `#a0eac9`, `#a4c2f4`, `#d0bcf1`, `#fbc8d9`, `#e66550`, `#ffbc6b`, `#fcda83`, `#44b984`, `#68dfa9`, `#6d9eeb`, `#b694e8`, `#f7a7c0`, `#cc3a21`, `#eaa041`, `#f2c960`, `#149e60`, `#3dc789`, `#3c78d8`, `#8e63ce`, `#e07798`, `#ac2b16`, `#cf8933`, `#d5ae49`, `#0b804b`, `#2a9c68`, `#285bac`, `#653e9b`, `#b65775`, `#822111`, `#a46a21`, `#aa8831`, `#076239`, `#1a764d`, `#1c4587`, `#41236d`, `#83334c`, `#464646`, `#e7e7e7`, `#0d3472`, `#b6cff5`, `#0d3b44`, `#98d7e4`, `#3d188e`, `#e3d7ff`, `#711a36`, `#fbd3e0`, `#8a1c0a`, `#f2b2a8`, `#7a2e0b`, `#ffc8af`, `#7a4706`, `#ffdeb5`, `#594c05`, `#fbe983`, `#684e07`, `#fdedc1`, `#0b4f30`, `#b3efd3`, `#04502e`, `#a2dcc1`, `#c2c2c2`, `#4986e7`, `#2da2bb`, `#b99aff`, `#994a64`, `#f691b2`, `#ff7537`, `#ffad46`, `#662e37`, `#ebdbde`, `#cca6ac`, `#094228`, `#42d692`, `#16a765`', type: "string" } }, type: "object" } }, description: "Details of a label.", properties: { color: { $ref: "#/$defs/LabelColor", description: "Optional. The color of the label." }, labelId: { description: "The unique identifier of the label.", type: "string" }, messagesTotal: { description: "The total number of messages under the label.", format: "int32", type: "integer" }, messagesUnread: { description: "The number of unread messages under the label.", format: "int32", type: "integer" }, name: { description: "The human-readable display name of the label.", type: "string" }, threadsTotal: { description: "The total number of threads under the label.", format: "int32", type: "integer" }, threadsUnread: { description: "The number of unread threads under the label.", format: "int32", type: "integer" } }, type: "object" } }] } };
2251
2253
  var email = z.string().trim().email();
2252
2254
  var pageSize = z.number().int().min(1).max(50).optional();
2253
2255
  var pageToken = z.string().optional();
@@ -2307,10 +2309,7 @@ var sensitiveMessageLabelInputSchema = z.object({
2307
2309
  labelOption: z.enum(["LABEL_OPTION_UNSPECIFIED", "TRASH", "SPAM"]),
2308
2310
  messageId: z.string().min(1)
2309
2311
  }).passthrough();
2310
- var listLabelsInputSchema = z.object({
2311
- pageSize,
2312
- pageToken
2313
- }).passthrough();
2312
+ var listLabelsInputSchema = z.object({}).passthrough();
2314
2313
  var messageLabelsInputSchema = z.object({
2315
2314
  labelIds,
2316
2315
  messageId: z.string().min(1)
@@ -2339,6 +2338,7 @@ var attachmentOutputSchema = z.object({
2339
2338
  var messageOutputSchema = z.object({
2340
2339
  attachmentIds: z.array(z.string()).optional(),
2341
2340
  attachments: z.array(attachmentOutputSchema).optional(),
2341
+ bccRecipients: z.array(z.string()).optional(),
2342
2342
  ccRecipients: z.array(z.string()).optional(),
2343
2343
  date: z.string().optional(),
2344
2344
  htmlBody: z.string().optional(),
@@ -2357,6 +2357,8 @@ var threadOutputSchema = z.object({
2357
2357
  var labelOutputSchema = z.object({
2358
2358
  color: labelColorSchema.optional(),
2359
2359
  labelId: z.string().optional(),
2360
+ messagesTotal: z.number().int().optional(),
2361
+ messagesUnread: z.number().int().optional(),
2360
2362
  name: z.string().optional(),
2361
2363
  threadsTotal: z.number().int().optional(),
2362
2364
  threadsUnread: z.number().int().optional()
@@ -2374,7 +2376,7 @@ var mcpOutputSchemas = {
2374
2376
  label_thread: z.object({}).passthrough(),
2375
2377
  unlabel_thread: z.object({}).passthrough(),
2376
2378
  apply_sensitive_thread_label: z.object({}).passthrough(),
2377
- list_labels: z.object({ labels: z.array(labelOutputSchema).optional(), nextPageToken: z.string().optional() }).passthrough(),
2379
+ list_labels: z.object({ labels: z.array(labelOutputSchema).optional() }).passthrough(),
2378
2380
  label_message: z.object({}).passthrough(),
2379
2381
  unlabel_message: z.object({}).passthrough(),
2380
2382
  apply_sensitive_message_label: z.object({}).passthrough(),
@@ -2530,15 +2532,15 @@ var implementations = {
2530
2532
  list_labels: {
2531
2533
  schema: listLabelsInputSchema,
2532
2534
  mutation: false,
2533
- handler: (domain, args, ctx) => {
2534
- const input = args;
2535
- const email2 = identityFromSession(ctx.session).email;
2536
- const page = paginate(domain, email2, "labels.list", domain.listUserLabels(email2), input.pageSize, input.pageToken, {});
2537
- return {
2538
- labels: page.items.map(labelResult),
2539
- ...page.nextPageToken ? { nextPageToken: page.nextPageToken } : {}
2540
- };
2541
- }
2535
+ // "Lists all labels available in the authenticated user's Gmail account."
2536
+ // ALL of them, system included, and in one answer — the adopted listing
2537
+ // takes no page arguments and offers no nextPageToken back. The July
2538
+ // listing this twin used to serve said "all user-defined labels", which is
2539
+ // what `listUserLabels` returns and what this handler used to call; the
2540
+ // widening is Google's and F-1400 is the twin following it.
2541
+ handler: (domain, _args, ctx) => ({
2542
+ labels: domain.labels(identityFromSession(ctx.session).email).map(labelResult)
2543
+ })
2542
2544
  },
2543
2545
  label_message: labelMessageImplementation(true),
2544
2546
  unlabel_message: labelMessageImplementation(false),
@@ -2564,16 +2566,13 @@ var implementations = {
2564
2566
  const parts = input.displayName.split("/");
2565
2567
  for (let index = 1; index < parts.length; index += 1) {
2566
2568
  const parent = parts.slice(0, index).join("/");
2567
- const exists = domain.listUserLabels(email2).some((label3) => label3.name.toLowerCase() === parent.toLowerCase());
2569
+ const exists = domain.listUserLabels(email2).some((label2) => label2.name.toLowerCase() === parent.toLowerCase());
2568
2570
  if (!exists)
2569
2571
  domain.createLabel(email2, parent);
2570
2572
  }
2571
2573
  }
2572
2574
  const created = domain.createLabel(email2, input.displayName, input.color);
2573
- const label2 = domain.listUserLabels(email2).find((item) => item.id === created.id);
2574
- if (!label2)
2575
- throw new Error("Created label was not found");
2576
- return labelResult(label2);
2575
+ return labelResult(domain.label(email2, created.id));
2577
2576
  })
2578
2577
  }
2579
2578
  };
@@ -2650,7 +2649,11 @@ function messageResult(message, format) {
2650
2649
  subject: message.subject,
2651
2650
  sender: message.from,
2652
2651
  toRecipients: message.to,
2653
- ccRecipients: message.cc
2652
+ ccRecipients: message.cc,
2653
+ // F-1400: the adopted listing declares it on Message, so it is served
2654
+ // wherever the other two recipient lists are — `get_message`, `get_thread`
2655
+ // and the threads `search_threads` nests.
2656
+ bccRecipients: message.bcc
2654
2657
  };
2655
2658
  if (format === "minimal")
2656
2659
  return minimal;
@@ -2669,10 +2672,20 @@ function messageResult(message, format) {
2669
2672
  };
2670
2673
  }
2671
2674
  function labelResult(label2) {
2675
+ const color = {
2676
+ ...label2.textColor ? { textColor: label2.textColor } : {},
2677
+ ...label2.backgroundColor ? { backgroundColor: label2.backgroundColor } : {}
2678
+ };
2672
2679
  return {
2673
2680
  labelId: label2.id,
2674
2681
  name: label2.name,
2675
- ...label2.color ? { color: label2.color } : {},
2682
+ ...Object.keys(color).length > 0 ? { color } : {},
2683
+ // F-1400: the August listing declares the message counters beside the
2684
+ // thread ones. The domain has counted both all along — the REST
2685
+ // serializer already published all four — so this was a projection that
2686
+ // dropped two fields, not a measurement the twin could not make.
2687
+ messagesTotal: label2.messagesTotal,
2688
+ messagesUnread: label2.messagesUnread,
2676
2689
  threadsTotal: label2.threadsTotal,
2677
2690
  threadsUnread: label2.threadsUnread
2678
2691
  };
@@ -0,0 +1,5 @@
1
+ export { UnsupportedTwinError, bootTwin } from './chunk-2R46XQAL.js';
2
+ export { STRIPE_LOCAL_ACCOUNT_ID } from './chunk-T6ZGCJSG.js';
3
+ import './chunk-TV5S6WQV.js';
4
+ import './chunk-VBATFCWR.js';
5
+ import './chunk-SG6ZTIMT.js';
@@ -1,5 +1,5 @@
1
- import { bootTwin } from './chunk-TG22SRUL.js';
2
- import { isTwinName, TWIN_NAMES, defaultPortFor, TWIN_REGISTRY } from './chunk-5GDTUVXT.js';
1
+ import { bootTwin } from './chunk-2R46XQAL.js';
2
+ import { isTwinName, TWIN_NAMES, defaultPortFor, TWIN_REGISTRY } from './chunk-T6ZGCJSG.js';
3
3
  import './chunk-TV5S6WQV.js';
4
4
  import './chunk-VBATFCWR.js';
5
5
  import './chunk-SG6ZTIMT.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pome-sh/cli",
3
- "version": "0.23.1",
3
+ "version": "0.23.3",
4
4
  "description": "Digital-twin testing for AI agents \u2014 run tasks against resettable local or hosted twins and record tool-call traces for evaluation on pome.sh.",
5
5
  "keywords": [
6
6
  "ai",
@@ -1,5 +0,0 @@
1
- export { UnsupportedTwinError, bootTwin } from './chunk-TG22SRUL.js';
2
- export { STRIPE_LOCAL_ACCOUNT_ID } from './chunk-5GDTUVXT.js';
3
- import './chunk-TV5S6WQV.js';
4
- import './chunk-VBATFCWR.js';
5
- import './chunk-SG6ZTIMT.js';