@opengeni/contracts 1.3.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-config.d.ts +1 -0
- package/dist/atlassian.js +2 -2
- package/dist/{chunk-AIEC5DTX.js → chunk-IBQ2IDBV.js} +2 -2
- package/dist/{chunk-LLFQJL3S.js → chunk-LGT7XRX7.js} +94 -9
- package/dist/chunk-LGT7XRX7.js.map +1 -0
- package/dist/{chunk-RYEHNSO7.js → chunk-TCXCRBPF.js} +45 -10
- package/dist/chunk-TCXCRBPF.js.map +1 -0
- package/dist/connect.js +2 -2
- package/dist/connection-authority.js +3 -3
- package/dist/google-drive.js +2 -2
- package/dist/host-mcp-bindings.js +3 -3
- package/dist/index.d.ts +57 -1
- package/dist/index.js +6 -2
- package/dist/mcp-structured-content.d.ts +25 -0
- package/dist/personal-github.js +2 -2
- package/dist/tool-action-review.d.ts +2 -0
- package/dist/tool-review-presentation.js +1 -1
- package/dist/transcription-recordings.d.ts +21 -0
- package/package.json +1 -1
- package/src/agent-config.ts +4 -1
- package/src/index.ts +32 -1
- package/src/mcp-structured-content.ts +81 -0
- package/src/tool-action-review.ts +1 -0
- package/src/tool-review-presentation.ts +76 -14
- package/src/transcription-recordings.ts +3 -0
- package/dist/chunk-LLFQJL3S.js.map +0 -1
- package/dist/chunk-RYEHNSO7.js.map +0 -1
- /package/dist/{chunk-AIEC5DTX.js.map → chunk-IBQ2IDBV.js.map} +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const TranscriptionRecordingErrorCode: z.ZodEnum<{
|
|
3
|
+
allowance_exhausted: "allowance_exhausted";
|
|
3
4
|
cancelled: "cancelled";
|
|
5
|
+
insufficient_credits: "insufficient_credits";
|
|
4
6
|
invalid_audio: "invalid_audio";
|
|
7
|
+
monthly_model_cost_limit: "monthly_model_cost_limit";
|
|
5
8
|
network: "network";
|
|
6
9
|
not_supported: "not_supported";
|
|
7
10
|
permission_denied: "permission_denied";
|
|
@@ -71,8 +74,11 @@ export declare const TranscriptionRecordingSegment: z.ZodObject<{
|
|
|
71
74
|
durationMilliseconds: z.ZodNumber;
|
|
72
75
|
byteLength: z.ZodNumber;
|
|
73
76
|
errorCode: z.ZodNullable<z.ZodEnum<{
|
|
77
|
+
allowance_exhausted: "allowance_exhausted";
|
|
74
78
|
cancelled: "cancelled";
|
|
79
|
+
insufficient_credits: "insufficient_credits";
|
|
75
80
|
invalid_audio: "invalid_audio";
|
|
81
|
+
monthly_model_cost_limit: "monthly_model_cost_limit";
|
|
76
82
|
network: "network";
|
|
77
83
|
not_supported: "not_supported";
|
|
78
84
|
permission_denied: "permission_denied";
|
|
@@ -108,8 +114,11 @@ export declare const TranscriptionRecording: z.ZodObject<{
|
|
|
108
114
|
transcriptText: z.ZodNullable<z.ZodString>;
|
|
109
115
|
languages: z.ZodArray<z.ZodString>;
|
|
110
116
|
errorCode: z.ZodNullable<z.ZodEnum<{
|
|
117
|
+
allowance_exhausted: "allowance_exhausted";
|
|
111
118
|
cancelled: "cancelled";
|
|
119
|
+
insufficient_credits: "insufficient_credits";
|
|
112
120
|
invalid_audio: "invalid_audio";
|
|
121
|
+
monthly_model_cost_limit: "monthly_model_cost_limit";
|
|
113
122
|
network: "network";
|
|
114
123
|
not_supported: "not_supported";
|
|
115
124
|
permission_denied: "permission_denied";
|
|
@@ -150,8 +159,11 @@ export declare const TranscriptionRecordingResponse: z.ZodObject<{
|
|
|
150
159
|
transcriptText: z.ZodNullable<z.ZodString>;
|
|
151
160
|
languages: z.ZodArray<z.ZodString>;
|
|
152
161
|
errorCode: z.ZodNullable<z.ZodEnum<{
|
|
162
|
+
allowance_exhausted: "allowance_exhausted";
|
|
153
163
|
cancelled: "cancelled";
|
|
164
|
+
insufficient_credits: "insufficient_credits";
|
|
154
165
|
invalid_audio: "invalid_audio";
|
|
166
|
+
monthly_model_cost_limit: "monthly_model_cost_limit";
|
|
155
167
|
network: "network";
|
|
156
168
|
not_supported: "not_supported";
|
|
157
169
|
permission_denied: "permission_denied";
|
|
@@ -181,8 +193,11 @@ export declare const TranscriptionRecordingResponse: z.ZodObject<{
|
|
|
181
193
|
durationMilliseconds: z.ZodNumber;
|
|
182
194
|
byteLength: z.ZodNumber;
|
|
183
195
|
errorCode: z.ZodNullable<z.ZodEnum<{
|
|
196
|
+
allowance_exhausted: "allowance_exhausted";
|
|
184
197
|
cancelled: "cancelled";
|
|
198
|
+
insufficient_credits: "insufficient_credits";
|
|
185
199
|
invalid_audio: "invalid_audio";
|
|
200
|
+
monthly_model_cost_limit: "monthly_model_cost_limit";
|
|
186
201
|
network: "network";
|
|
187
202
|
not_supported: "not_supported";
|
|
188
203
|
permission_denied: "permission_denied";
|
|
@@ -221,8 +236,11 @@ export declare const TranscriptionRecordingListResponse: z.ZodObject<{
|
|
|
221
236
|
transcriptText: z.ZodNullable<z.ZodString>;
|
|
222
237
|
languages: z.ZodArray<z.ZodString>;
|
|
223
238
|
errorCode: z.ZodNullable<z.ZodEnum<{
|
|
239
|
+
allowance_exhausted: "allowance_exhausted";
|
|
224
240
|
cancelled: "cancelled";
|
|
241
|
+
insufficient_credits: "insufficient_credits";
|
|
225
242
|
invalid_audio: "invalid_audio";
|
|
243
|
+
monthly_model_cost_limit: "monthly_model_cost_limit";
|
|
226
244
|
network: "network";
|
|
227
245
|
not_supported: "not_supported";
|
|
228
246
|
permission_denied: "permission_denied";
|
|
@@ -264,8 +282,11 @@ export declare const UploadTranscriptionRecordingChunkResponse: z.ZodObject<{
|
|
|
264
282
|
transcriptText: z.ZodNullable<z.ZodString>;
|
|
265
283
|
languages: z.ZodArray<z.ZodString>;
|
|
266
284
|
errorCode: z.ZodNullable<z.ZodEnum<{
|
|
285
|
+
allowance_exhausted: "allowance_exhausted";
|
|
267
286
|
cancelled: "cancelled";
|
|
287
|
+
insufficient_credits: "insufficient_credits";
|
|
268
288
|
invalid_audio: "invalid_audio";
|
|
289
|
+
monthly_model_cost_limit: "monthly_model_cost_limit";
|
|
269
290
|
network: "network";
|
|
270
291
|
not_supported: "not_supported";
|
|
271
292
|
permission_denied: "permission_denied";
|
package/package.json
CHANGED
package/src/agent-config.ts
CHANGED
|
@@ -423,8 +423,11 @@ export type AgentFunctionToolClass = AgentCapabilityId | "runtime" | "sandbox";
|
|
|
423
423
|
|
|
424
424
|
/** Tools served outside the first-party MCP catalog, by the name the model sees. */
|
|
425
425
|
export const AGENT_FUNCTION_TOOL_CAPABILITIES = {
|
|
426
|
-
//
|
|
426
|
+
// Web search: the provider-hosted `web_search`/`x_search` tools, or
|
|
427
|
+
// Opengeni's provider-agnostic `web_search` and `web_fetch` function tools
|
|
428
|
+
// (one transport per turn; the capability is the same).
|
|
427
429
|
web_search: "webSearch",
|
|
430
|
+
web_fetch: "webSearch",
|
|
428
431
|
x_search: "webSearch",
|
|
429
432
|
image_generation: "media",
|
|
430
433
|
// Runtime function tools.
|
package/src/index.ts
CHANGED
|
@@ -115,6 +115,7 @@ export * from "./editable-artifact-serialized-commit";
|
|
|
115
115
|
export * from "./signup-attribution";
|
|
116
116
|
export * from "./product-lifecycle-facts";
|
|
117
117
|
export * from "./tool-catalog";
|
|
118
|
+
export * from "./mcp-structured-content";
|
|
118
119
|
export * from "./mcp-oauth";
|
|
119
120
|
export * from "./tool-result-spill";
|
|
120
121
|
export * from "./interaction";
|
|
@@ -1864,6 +1865,9 @@ export const TranscriptionErrorCode = z.enum([
|
|
|
1864
1865
|
"too_large",
|
|
1865
1866
|
"invalid_audio",
|
|
1866
1867
|
"unknown",
|
|
1868
|
+
"insufficient_credits",
|
|
1869
|
+
"allowance_exhausted",
|
|
1870
|
+
"monthly_model_cost_limit",
|
|
1867
1871
|
]);
|
|
1868
1872
|
export type TranscriptionErrorCode = z.infer<typeof TranscriptionErrorCode>;
|
|
1869
1873
|
|
|
@@ -2120,6 +2124,7 @@ export const VoiceInputProviderId = z.enum([
|
|
|
2120
2124
|
"codex-subscription",
|
|
2121
2125
|
"openai",
|
|
2122
2126
|
"azure-openai",
|
|
2127
|
+
"azure-mai",
|
|
2123
2128
|
]);
|
|
2124
2129
|
export type VoiceInputProviderId = z.infer<typeof VoiceInputProviderId>;
|
|
2125
2130
|
|
|
@@ -5016,6 +5021,8 @@ export type PromotionalCreditScope = z.infer<typeof PromotionalCreditScope>;
|
|
|
5016
5021
|
export const PromotionalCreditBalance = PromotionalCreditScope.extend({
|
|
5017
5022
|
grantId: z.string().uuid(),
|
|
5018
5023
|
remainingMicros: z.number().int().nonnegative(),
|
|
5024
|
+
/** Also pays for dictation and live voice, like general credits (signup credits). */
|
|
5025
|
+
coversVoice: z.boolean().optional(),
|
|
5019
5026
|
});
|
|
5020
5027
|
export type PromotionalCreditBalance = z.infer<typeof PromotionalCreditBalance>;
|
|
5021
5028
|
|
|
@@ -7072,7 +7079,7 @@ export const CodexRealtimeWebrtcResponse = z
|
|
|
7072
7079
|
.min(1)
|
|
7073
7080
|
.max(1024 * 1024),
|
|
7074
7081
|
version: CodexRealtimeWebrtcVersion,
|
|
7075
|
-
model: z.
|
|
7082
|
+
model: z.enum(["gpt-live-1-boulder-alpha", "opengeni-azure/gpt-live-1"]),
|
|
7076
7083
|
connectionId: z.string().uuid(),
|
|
7077
7084
|
connectionEpoch: z.number().int().positive(),
|
|
7078
7085
|
startupFenceSequence: z.number().int().nonnegative(),
|
|
@@ -7229,6 +7236,7 @@ export const SyncSessionRealtimeLedgerResponse = z
|
|
|
7229
7236
|
export type SyncSessionRealtimeLedgerResponse = z.infer<typeof SyncSessionRealtimeLedgerResponse>;
|
|
7230
7237
|
|
|
7231
7238
|
export const SessionRealtimeModel = z.enum([
|
|
7239
|
+
"opengeni-azure/gpt-live-1",
|
|
7232
7240
|
"gpt-live-1-boulder-alpha",
|
|
7233
7241
|
"supergrok/grok-voice-think-fast-2.0",
|
|
7234
7242
|
"opengeni-gateway/openai/gpt-realtime-2.1",
|
|
@@ -7247,6 +7255,12 @@ export const WorkspaceRealtimeModelCatalogItem = z.object({
|
|
|
7247
7255
|
description: z.string().min(1),
|
|
7248
7256
|
available: z.boolean(),
|
|
7249
7257
|
unavailableReason: z.string().nullable(),
|
|
7258
|
+
/**
|
|
7259
|
+
* Machine-readable reason when unavailable. Credit refusals use the same
|
|
7260
|
+
* codes as voice input (`insufficient_credits`, `allowance_exhausted`,
|
|
7261
|
+
* `monthly_model_cost_limit`).
|
|
7262
|
+
*/
|
|
7263
|
+
unavailableCode: z.string().min(1).max(64).nullable().optional(),
|
|
7250
7264
|
recommended: z.boolean(),
|
|
7251
7265
|
});
|
|
7252
7266
|
export type WorkspaceRealtimeModelCatalogItem = z.infer<typeof WorkspaceRealtimeModelCatalogItem>;
|
|
@@ -7302,9 +7316,21 @@ export const EndSessionRealtimeRequest = RenewSessionRealtimeRequest.extend({
|
|
|
7302
7316
|
});
|
|
7303
7317
|
export type EndSessionRealtimeRequest = z.infer<typeof EndSessionRealtimeRequest>;
|
|
7304
7318
|
|
|
7319
|
+
/**
|
|
7320
|
+
* Server instruction to end a live call now. Deployment-funded voice returns
|
|
7321
|
+
* it from a heartbeat when credits run out; the lease is then no longer
|
|
7322
|
+
* extended, so the client should drain and end the call gracefully.
|
|
7323
|
+
*/
|
|
7324
|
+
export const SessionRealtimeStopInstruction = z.object({
|
|
7325
|
+
code: z.string().min(1).max(64),
|
|
7326
|
+
message: z.string().min(1).max(512),
|
|
7327
|
+
});
|
|
7328
|
+
export type SessionRealtimeStopInstruction = z.infer<typeof SessionRealtimeStopInstruction>;
|
|
7329
|
+
|
|
7305
7330
|
export const SessionRealtimeMutationResponse = z.object({
|
|
7306
7331
|
mode: SessionRealtimeMode,
|
|
7307
7332
|
replay: z.boolean(),
|
|
7333
|
+
stop: SessionRealtimeStopInstruction.optional(),
|
|
7308
7334
|
});
|
|
7309
7335
|
export type SessionRealtimeMutationResponse = z.infer<typeof SessionRealtimeMutationResponse>;
|
|
7310
7336
|
|
|
@@ -12082,6 +12108,11 @@ export const CapabilityRuntime = z.object({
|
|
|
12082
12108
|
]),
|
|
12083
12109
|
})
|
|
12084
12110
|
.optional(),
|
|
12111
|
+
// Server-derived connectability: present when the connector's OAuth
|
|
12112
|
+
// authorization server refuses self-registration, so connecting needs an
|
|
12113
|
+
// operator-registered client. `configured` is whether this deployment has
|
|
12114
|
+
// one; connector surfaces offer the row only when it is true.
|
|
12115
|
+
operatorOAuthClient: z.object({ configured: z.boolean() }).optional(),
|
|
12085
12116
|
});
|
|
12086
12117
|
export type CapabilityRuntime = z.infer<typeof CapabilityRuntime>;
|
|
12087
12118
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { AttemptToolResult } from "./tool-catalog";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Remove the backwards-compatibility text copy of an MCP result's
|
|
5
|
+
* `structuredContent`.
|
|
6
|
+
*
|
|
7
|
+
* The MCP specification asks a server that returns `structuredContent` to also
|
|
8
|
+
* return the same value serialized in a text content block. Printing or sending
|
|
9
|
+
* both pays for the payload twice, and the text copy pays again for JSON string
|
|
10
|
+
* escaping inside the result envelope.
|
|
11
|
+
*
|
|
12
|
+
* The envelope (`content`, `structuredContent`, `_meta`, `isError`, extension
|
|
13
|
+
* fields) and its key order are kept. Only a plain `{type: "text", text}` block
|
|
14
|
+
* whose text parses as JSON to a value equal to `structuredContent` is removed.
|
|
15
|
+
* Prose, differing JSON, annotated text, images, resources, and every other
|
|
16
|
+
* block stay. A text block whose JSON carries an integer outside the IEEE-754
|
|
17
|
+
* safe range also stays, because its digits may be more precise than the
|
|
18
|
+
* parsed `structuredContent`. Numbers compare by IEEE-754 value.
|
|
19
|
+
*
|
|
20
|
+
* Results without a removable block are returned as the same object.
|
|
21
|
+
*
|
|
22
|
+
* Callers: the runtime's model-facing MCP projection, and the default
|
|
23
|
+
* `ogtool call` print. The native Connected Machine client implements the
|
|
24
|
+
* same rule in `agent/crates/opengeni-agent/src/codemode.rs`; keep them equal.
|
|
25
|
+
*/
|
|
26
|
+
export function omitStructuredContentTextDuplicates<T extends AttemptToolResult>(result: T): T {
|
|
27
|
+
const structured: unknown = result.structuredContent;
|
|
28
|
+
if (structured === undefined || structured === null) return result;
|
|
29
|
+
const content = result.content.filter(
|
|
30
|
+
(entry) => !isPlainTextBlock(entry) || !textDuplicatesStructuredContent(entry.text, structured),
|
|
31
|
+
);
|
|
32
|
+
if (content.length === result.content.length) return result;
|
|
33
|
+
return { ...result, content };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isPlainTextBlock(entry: unknown): entry is { type: "text"; text: string } {
|
|
37
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
|
|
38
|
+
const record = entry as Record<string, unknown>;
|
|
39
|
+
if (record.type !== "text" || typeof record.text !== "string") return false;
|
|
40
|
+
// Annotations or _meta are block-level facts the structured value lacks.
|
|
41
|
+
return Object.keys(record).every((key) => key === "type" || key === "text");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function textDuplicatesStructuredContent(text: string, structured: unknown): boolean {
|
|
45
|
+
const trimmed = text.replace(/^[ \t\n\r]+/u, "");
|
|
46
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return false;
|
|
47
|
+
let parsed: unknown;
|
|
48
|
+
try {
|
|
49
|
+
parsed = JSON.parse(text);
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return !containsUnsafeInteger(parsed) && jsonValuesEqual(parsed, structured);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function containsUnsafeInteger(value: unknown): boolean {
|
|
57
|
+
if (typeof value === "number") return Number.isInteger(value) && !Number.isSafeInteger(value);
|
|
58
|
+
if (Array.isArray(value)) return value.some(containsUnsafeInteger);
|
|
59
|
+
if (value && typeof value === "object") return Object.values(value).some(containsUnsafeInteger);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function jsonValuesEqual(left: unknown, right: unknown): boolean {
|
|
64
|
+
if (left === right) return true;
|
|
65
|
+
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
69
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return left.every((entry, index) => jsonValuesEqual(entry, right[index]));
|
|
73
|
+
}
|
|
74
|
+
const leftRecord = left as Record<string, unknown>;
|
|
75
|
+
const rightRecord = right as Record<string, unknown>;
|
|
76
|
+
const leftKeys = Object.keys(leftRecord);
|
|
77
|
+
if (leftKeys.length !== Object.keys(rightRecord).length) return false;
|
|
78
|
+
return leftKeys.every(
|
|
79
|
+
(key) => Object.hasOwn(rightRecord, key) && jsonValuesEqual(leftRecord[key], rightRecord[key]),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -14,7 +14,17 @@ export function toolReviewFieldLabel(key: string): string {
|
|
|
14
14
|
const label = key
|
|
15
15
|
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
16
16
|
.replace(/[_-]+/g, " ")
|
|
17
|
-
.replace(/\bids?\b/gi, (word) => (word.length === 3 ? "IDs" : "ID"))
|
|
17
|
+
.replace(/\bids?\b/gi, (word) => (word.length === 3 ? "IDs" : "ID"))
|
|
18
|
+
.replace(
|
|
19
|
+
/\b(api|url|uri|http|https|ip|sql|json|html)(s?)\b/gi,
|
|
20
|
+
(_word, name: string, plural: string) => `${name.toUpperCase()}${plural}`,
|
|
21
|
+
)
|
|
22
|
+
// Sentence case, keeping acronyms: "Working Directory" → "Working directory".
|
|
23
|
+
.replace(
|
|
24
|
+
/(?<=\S\s+)([A-Z])([a-z]+)\b/g,
|
|
25
|
+
(_word, first: string, rest: string) => `${first.toLowerCase()}${rest}`,
|
|
26
|
+
)
|
|
27
|
+
.trim();
|
|
18
28
|
return label.charAt(0).toUpperCase() + label.slice(1);
|
|
19
29
|
}
|
|
20
30
|
export function decodeReviewArguments(value: unknown): Record<string, unknown> | null {
|
|
@@ -85,8 +95,35 @@ export function toolReviewFields(
|
|
|
85
95
|
(field) =>
|
|
86
96
|
field.path !== "/contentSha256" && field.path !== "/htmlBody" && field.preview !== "",
|
|
87
97
|
)
|
|
88
|
-
.map((field) => ({
|
|
89
|
-
|
|
98
|
+
.map((field) => ({
|
|
99
|
+
...field,
|
|
100
|
+
label: field.path === "/textBody" ? "Message" : field.label,
|
|
101
|
+
path: `/$email${field.path}`,
|
|
102
|
+
...(field.path === "/attachments"
|
|
103
|
+
? {
|
|
104
|
+
preview: context
|
|
105
|
+
.email!.attachments.map((attachment) => attachment.name)
|
|
106
|
+
.join(", ")
|
|
107
|
+
.slice(0, 240),
|
|
108
|
+
}
|
|
109
|
+
: {}),
|
|
110
|
+
})),
|
|
111
|
+
...original.fields.filter(
|
|
112
|
+
(field) =>
|
|
113
|
+
![
|
|
114
|
+
"/raw",
|
|
115
|
+
"/expectedContentSha256",
|
|
116
|
+
"/from",
|
|
117
|
+
"/to",
|
|
118
|
+
"/cc",
|
|
119
|
+
"/bcc",
|
|
120
|
+
"/subject",
|
|
121
|
+
"/body",
|
|
122
|
+
"/textBody",
|
|
123
|
+
"/htmlBody",
|
|
124
|
+
"/attachments",
|
|
125
|
+
].includes(field.path),
|
|
126
|
+
),
|
|
90
127
|
];
|
|
91
128
|
return {
|
|
92
129
|
fields: fields.slice(0, 16),
|
|
@@ -98,13 +135,26 @@ export function toolReviewFields(
|
|
|
98
135
|
fields: entries.slice(0, 16).map(([key, value], index) => {
|
|
99
136
|
const hidden = protectedReviewField(key, context?.protectedFields);
|
|
100
137
|
const safe = hidden ? "[Protected value]" : value;
|
|
101
|
-
const count = Array.isArray(value) ? value.length : undefined;
|
|
138
|
+
const count = !hidden && Array.isArray(value) ? value.length : undefined;
|
|
139
|
+
const compactList =
|
|
140
|
+
!hidden &&
|
|
141
|
+
Array.isArray(value) &&
|
|
142
|
+
value.length > 0 &&
|
|
143
|
+
value.length <= 4 &&
|
|
144
|
+
value.every(
|
|
145
|
+
(entry) =>
|
|
146
|
+
typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean",
|
|
147
|
+
)
|
|
148
|
+
? value.map(valueText).join(", ")
|
|
149
|
+
: undefined;
|
|
102
150
|
const text =
|
|
103
|
-
|
|
104
|
-
?
|
|
105
|
-
:
|
|
106
|
-
? `${
|
|
107
|
-
:
|
|
151
|
+
compactList !== undefined
|
|
152
|
+
? compactList
|
|
153
|
+
: count !== undefined
|
|
154
|
+
? `${count.toLocaleString("en-US")} item${count === 1 ? "" : "s"}`
|
|
155
|
+
: safe && typeof safe === "object"
|
|
156
|
+
? `${Object.keys(safe).length} field${Object.keys(safe).length === 1 ? "" : "s"}`
|
|
157
|
+
: valueText(safe);
|
|
108
158
|
return {
|
|
109
159
|
path: fieldPointer(key, index),
|
|
110
160
|
label: bound(
|
|
@@ -115,7 +165,10 @@ export function toolReviewFields(
|
|
|
115
165
|
),
|
|
116
166
|
preview: bound(text, 240),
|
|
117
167
|
...(count !== undefined ? { count } : {}),
|
|
118
|
-
truncated:
|
|
168
|
+
truncated:
|
|
169
|
+
!hidden &&
|
|
170
|
+
(text.length > 240 ||
|
|
171
|
+
(compactList === undefined && typeof value === "object" && value !== null)),
|
|
119
172
|
...(hidden ? { protected: true } : {}),
|
|
120
173
|
};
|
|
121
174
|
}),
|
|
@@ -132,7 +185,14 @@ export function toolReviewAction(
|
|
|
132
185
|
"title" | "approveLabel" | "effects" | "consequence" | "selectionCount" | "selectionKind"
|
|
133
186
|
> {
|
|
134
187
|
const fallback = {
|
|
135
|
-
title:
|
|
188
|
+
title:
|
|
189
|
+
context?.title ??
|
|
190
|
+
bound(
|
|
191
|
+
toolReviewFieldLabel(
|
|
192
|
+
toolName.replace(/^mcp_[^_]+__/, "").replace(/^batch[_-](?=[a-z])/i, ""),
|
|
193
|
+
),
|
|
194
|
+
256,
|
|
195
|
+
),
|
|
136
196
|
approveLabel: "Approve action",
|
|
137
197
|
effects: [] as string[],
|
|
138
198
|
};
|
|
@@ -152,8 +212,10 @@ export function toolReviewAction(
|
|
|
152
212
|
const selectionCount = ids?.every((id) => typeof id === "string") ? new Set(ids).size : undefined;
|
|
153
213
|
const noun =
|
|
154
214
|
selectionCount === undefined
|
|
155
|
-
?
|
|
156
|
-
|
|
215
|
+
? thread
|
|
216
|
+
? "conversations"
|
|
217
|
+
: "messages"
|
|
218
|
+
: `${selectionCount.toLocaleString("en-US")} ${thread ? "conversation" : "message"}${selectionCount === 1 ? "" : "s"}`;
|
|
157
219
|
const addValues = toolName.startsWith("label_") ? args.labelIds : args.addLabelIds;
|
|
158
220
|
const adds = Array.isArray(addValues)
|
|
159
221
|
? addValues.filter((v): v is string => typeof v === "string")
|
|
@@ -200,7 +262,7 @@ export function toolReviewAction(
|
|
|
200
262
|
...(trash
|
|
201
263
|
? { consequence: "Messages stay recoverable in Trash until Gmail deletes them." }
|
|
202
264
|
: thread
|
|
203
|
-
? { consequence: "Applies to every message in the
|
|
265
|
+
? { consequence: "Applies to every message in the conversation." }
|
|
204
266
|
: {}),
|
|
205
267
|
};
|
|
206
268
|
}
|
|
@@ -12,6 +12,9 @@ export const TranscriptionRecordingErrorCode = z.enum([
|
|
|
12
12
|
"too_large",
|
|
13
13
|
"invalid_audio",
|
|
14
14
|
"unknown",
|
|
15
|
+
"insufficient_credits",
|
|
16
|
+
"allowance_exhausted",
|
|
17
|
+
"monthly_model_cost_limit",
|
|
15
18
|
]);
|
|
16
19
|
export type TranscriptionRecordingErrorCode = z.infer<typeof TranscriptionRecordingErrorCode>;
|
|
17
20
|
|