idiolect-mcp 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -29
- package/package.json +1 -1
- package/progressive-catalog.json +185 -5887
- package/public-contract.js +12 -1
- package/server.mjs +31 -276
package/public-contract.js
CHANGED
|
@@ -81,5 +81,16 @@ export function publicMcpState(state, message, next, details = {}) {
|
|
|
81
81
|
delete safeDetails.state;
|
|
82
82
|
delete safeDetails.message;
|
|
83
83
|
delete safeDetails.next;
|
|
84
|
-
return {
|
|
84
|
+
return {
|
|
85
|
+
state,
|
|
86
|
+
message,
|
|
87
|
+
...safeDetails,
|
|
88
|
+
next: {
|
|
89
|
+
action: next.action,
|
|
90
|
+
tool: next.tool,
|
|
91
|
+
...(next.action === "retry" && typeof next.retryAfterSeconds === "number"
|
|
92
|
+
? { retryAfterSeconds: next.retryAfterSeconds }
|
|
93
|
+
: {}),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
85
96
|
}
|
package/server.mjs
CHANGED
|
@@ -47,7 +47,16 @@ export const accountRuntimeCompatibilityToolNames = Object.freeze([
|
|
|
47
47
|
"feedback",
|
|
48
48
|
"refine",
|
|
49
49
|
"profile",
|
|
50
|
-
"
|
|
50
|
+
"list_writing_samples",
|
|
51
|
+
"create_writing_profile",
|
|
52
|
+
"add_writing_samples",
|
|
53
|
+
"rename_writing_profile",
|
|
54
|
+
"set_current_writing_profile",
|
|
55
|
+
"set_default_writing_template",
|
|
56
|
+
"add_writing_rule",
|
|
57
|
+
"remove_writing_rule",
|
|
58
|
+
"remove_writing_sample",
|
|
59
|
+
"delete_writing_profile",
|
|
51
60
|
"learn_writing_style",
|
|
52
61
|
"get_my_voice",
|
|
53
62
|
"create_my_voice",
|
|
@@ -142,195 +151,14 @@ export function formatLegacyScoreVoiceResult(result) {
|
|
|
142
151
|
return `${lines}\n\n(${provenance} — higher = reads more like you; not a forensic identity claim.)`;
|
|
143
152
|
}
|
|
144
153
|
|
|
145
|
-
const CREDIT_STATES = new Set([
|
|
146
|
-
"free_beta",
|
|
147
|
-
"balance_available",
|
|
148
|
-
"low_balance",
|
|
149
|
-
"zero_balance",
|
|
150
|
-
"legacy_unlimited",
|
|
151
|
-
"accounting_unavailable",
|
|
152
|
-
]);
|
|
153
|
-
const CREDIT_MODES = new Set(["free", "credits"]);
|
|
154
|
-
|
|
155
154
|
function plainObject(value) {
|
|
156
155
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
function safeManageUrl(value) {
|
|
160
|
-
if (value === null) return null;
|
|
161
|
-
if (typeof value !== "string") return undefined;
|
|
162
|
-
try {
|
|
163
|
-
const parsed = new URL(value);
|
|
164
|
-
const accountOrigin = new URL(ACCOUNT_BASE).origin;
|
|
165
|
-
const firstParty = parsed.hostname === "idiolect.app" || parsed.hostname.endsWith(".idiolect.app");
|
|
166
|
-
if (
|
|
167
|
-
!["https:", "http:"].includes(parsed.protocol)
|
|
168
|
-
|| (parsed.origin !== accountOrigin && !firstParty)
|
|
169
|
-
|| parsed.pathname !== "/settings"
|
|
170
|
-
|| parsed.username
|
|
171
|
-
|| parsed.password
|
|
172
|
-
|| parsed.search !== "?section=credits"
|
|
173
|
-
|| parsed.hash
|
|
174
|
-
) return undefined;
|
|
175
|
-
return `${parsed.origin}/settings?section=credits`;
|
|
176
|
-
} catch {
|
|
177
|
-
return undefined;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function creditMessage(credits) {
|
|
182
|
-
const { state, balance, charged, manageUrl, mode } = credits;
|
|
183
|
-
if (state === "free_beta") {
|
|
184
|
-
return charged === 0
|
|
185
|
-
? "Free during beta. No credits are being used."
|
|
186
|
-
: "Completed free during beta. No credit was used.";
|
|
187
|
-
}
|
|
188
|
-
if (state === "legacy_unlimited") return "Unlimited generation access is active. Credits are not used.";
|
|
189
|
-
if (state === "accounting_unavailable") {
|
|
190
|
-
return mode === "free"
|
|
191
|
-
? "Free during beta. The credit balance is temporarily unavailable; generation remains available."
|
|
192
|
-
: "The credit balance is temporarily unavailable. Generation is paused; no credit was used.";
|
|
193
|
-
}
|
|
194
|
-
if (state === "zero_balance") {
|
|
195
|
-
return charged === 1
|
|
196
|
-
? "This request completed with the last credit."
|
|
197
|
-
: `The credit balance is 0. A draft or rewrite needs 1 credit. Credit management: ${manageUrl}.`;
|
|
198
|
-
}
|
|
199
|
-
if (charged === 1) return `1 credit used. ${balance} ${balance === 1 ? "remains" : "remain"}.`;
|
|
200
|
-
if (state === "low_balance") return `${balance} credit${balance === 1 ? "" : "s"} remain. Credit management: ${manageUrl}.`;
|
|
201
|
-
return `${balance} credits available. Each draft or rewrite uses 1 credit.`;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function validCreditInvariant(credits) {
|
|
205
|
-
const {
|
|
206
|
-
state,
|
|
207
|
-
mode,
|
|
208
|
-
balance,
|
|
209
|
-
balancePreview,
|
|
210
|
-
unitCost,
|
|
211
|
-
charged,
|
|
212
|
-
unlimited,
|
|
213
|
-
accountingAvailable,
|
|
214
|
-
generationAvailable,
|
|
215
|
-
purchaseRequired,
|
|
216
|
-
manageUrl,
|
|
217
|
-
} = credits;
|
|
218
|
-
if (state === "free_beta") {
|
|
219
|
-
return mode === "free" && balance !== null && balancePreview && unitCost === 0 && charged === 0
|
|
220
|
-
&& !unlimited && accountingAvailable && generationAvailable && !purchaseRequired && manageUrl === null;
|
|
221
|
-
}
|
|
222
|
-
if (state === "legacy_unlimited") {
|
|
223
|
-
return mode === "credits" && balance === null && !balancePreview && unitCost === 0 && charged === 0
|
|
224
|
-
&& unlimited && accountingAvailable && generationAvailable && !purchaseRequired && manageUrl === null;
|
|
225
|
-
}
|
|
226
|
-
if (state === "accounting_unavailable") {
|
|
227
|
-
return balance === null && !balancePreview && charged === 0 && !unlimited && !accountingAvailable
|
|
228
|
-
&& !purchaseRequired && manageUrl === null && unitCost === (mode === "free" ? 0 : 1)
|
|
229
|
-
&& generationAvailable === (mode === "free");
|
|
230
|
-
}
|
|
231
|
-
if (mode !== "credits" || balance === null || balancePreview || unitCost !== 1 || unlimited || !accountingAvailable) {
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
if (state === "balance_available") {
|
|
235
|
-
return balance > 5 && generationAvailable && !purchaseRequired && manageUrl === null;
|
|
236
|
-
}
|
|
237
|
-
if (state === "low_balance") {
|
|
238
|
-
return balance >= 1 && balance <= 5 && generationAvailable && !purchaseRequired && manageUrl !== null;
|
|
239
|
-
}
|
|
240
|
-
return state === "zero_balance" && balance === 0 && !generationAvailable && purchaseRequired && manageUrl !== null;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Rebuild the public credit envelope from known primitives only. Never copy an
|
|
245
|
-
* upstream message or unknown field into an MCP response.
|
|
246
|
-
*/
|
|
247
|
-
export function safeCreditPresentation(value) {
|
|
248
|
-
if (!plainObject(value)) return null;
|
|
249
|
-
const balance = value.balance;
|
|
250
|
-
const manageUrl = safeManageUrl(value.manageUrl);
|
|
251
|
-
if (
|
|
252
|
-
!CREDIT_STATES.has(value.state)
|
|
253
|
-
|| !CREDIT_MODES.has(value.mode)
|
|
254
|
-
|| !(balance === null || (Number.isSafeInteger(balance) && balance >= 0))
|
|
255
|
-
|| typeof value.balancePreview !== "boolean"
|
|
256
|
-
|| ![0, 1].includes(value.unitCost)
|
|
257
|
-
|| ![0, 1].includes(value.charged)
|
|
258
|
-
|| typeof value.unlimited !== "boolean"
|
|
259
|
-
|| typeof value.accountingAvailable !== "boolean"
|
|
260
|
-
|| typeof value.generationAvailable !== "boolean"
|
|
261
|
-
|| typeof value.purchaseRequired !== "boolean"
|
|
262
|
-
|| manageUrl === undefined
|
|
263
|
-
|| typeof value.replayed !== "boolean"
|
|
264
|
-
) return null;
|
|
265
|
-
|
|
266
|
-
const credits = {
|
|
267
|
-
state: value.state,
|
|
268
|
-
mode: value.mode,
|
|
269
|
-
balance,
|
|
270
|
-
balancePreview: value.balancePreview,
|
|
271
|
-
unitCost: value.unitCost,
|
|
272
|
-
charged: value.charged,
|
|
273
|
-
unlimited: value.unlimited,
|
|
274
|
-
accountingAvailable: value.accountingAvailable,
|
|
275
|
-
generationAvailable: value.generationAvailable,
|
|
276
|
-
purchaseRequired: value.purchaseRequired,
|
|
277
|
-
manageUrl,
|
|
278
|
-
replayed: value.replayed,
|
|
279
|
-
};
|
|
280
|
-
if (!validCreditInvariant(credits)) return null;
|
|
281
|
-
return { ...credits, message: creditMessage(credits) };
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function safeCreditToolErrorPayload(value) {
|
|
285
|
-
if (!plainObject(value) || !plainObject(value.error) || !plainObject(value.retry)) return null;
|
|
286
|
-
const credits = safeCreditPresentation(value.credits);
|
|
287
|
-
if (!credits) return null;
|
|
288
|
-
const purchaseRequired = value.status === "purchase_required"
|
|
289
|
-
&& value.error.code === "insufficient_credits"
|
|
290
|
-
&& credits.state === "zero_balance"
|
|
291
|
-
&& credits.mode === "credits"
|
|
292
|
-
&& credits.balance === 0
|
|
293
|
-
&& credits.charged === 0
|
|
294
|
-
&& value.retry.after === "balance_updated";
|
|
295
|
-
const accountingUnavailable = value.status === "accounting_unavailable"
|
|
296
|
-
&& value.error.code === "credit_accounting_unavailable"
|
|
297
|
-
&& credits.state === "accounting_unavailable"
|
|
298
|
-
&& credits.mode === "credits"
|
|
299
|
-
&& credits.charged === 0
|
|
300
|
-
&& value.retry.after === "accounting_available";
|
|
301
|
-
if (
|
|
302
|
-
(!purchaseRequired && !accountingUnavailable)
|
|
303
|
-
|| value.error.retryable !== true
|
|
304
|
-
|| value.retry.safe !== true
|
|
305
|
-
|| value.retry.idempotent !== true
|
|
306
|
-
|| value.retry.scope !== "pre_generation"
|
|
307
|
-
) return null;
|
|
308
|
-
|
|
309
|
-
const message = purchaseRequired
|
|
310
|
-
? `This request needs 1 credit; the balance is 0. Nothing was charged. Credit management: ${credits.manageUrl}. The same request remains safe to retry after the balance changes.`
|
|
311
|
-
: "The credit balance is temporarily unavailable. No generation started and no credit was used. The same request remains safe to retry after accounting recovers.";
|
|
312
|
-
return {
|
|
313
|
-
status: value.status,
|
|
314
|
-
message,
|
|
315
|
-
error: { code: value.error.code, retryable: true },
|
|
316
|
-
credits: { ...credits, message },
|
|
317
|
-
retry: {
|
|
318
|
-
safe: true,
|
|
319
|
-
idempotent: true,
|
|
320
|
-
scope: "pre_generation",
|
|
321
|
-
after: value.retry.after,
|
|
322
|
-
},
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
|
|
326
158
|
async function accountRequestError(res, toolName) {
|
|
327
159
|
if ((res.headers.get("content-type") || "").includes("application/json")) {
|
|
328
160
|
try {
|
|
329
161
|
const payload = await res.json();
|
|
330
|
-
const creditContent = safeCreditToolErrorPayload(payload);
|
|
331
|
-
if (creditContent) {
|
|
332
|
-
return new AccountRequestError(creditContent.message, res.status, creditContent);
|
|
333
|
-
}
|
|
334
162
|
const creationContent = toolName === "create_my_voice" ? safeCreationFailurePayload(payload) : null;
|
|
335
163
|
if (creationContent) {
|
|
336
164
|
return new AccountRequestError(creationContent.message, res.status, creationContent);
|
|
@@ -608,72 +436,6 @@ const PROVENANCE_OUTPUT_PROPERTIES = {
|
|
|
608
436
|
voice: SELECTED_VOICE_SCHEMA,
|
|
609
437
|
evidence: EVIDENCE_OUTPUT_SCHEMA,
|
|
610
438
|
};
|
|
611
|
-
const CREDIT_OUTPUT_SCHEMA = {
|
|
612
|
-
type: "object",
|
|
613
|
-
additionalProperties: false,
|
|
614
|
-
properties: {
|
|
615
|
-
state: {
|
|
616
|
-
type: "string",
|
|
617
|
-
enum: ["free_beta", "balance_available", "low_balance", "zero_balance", "legacy_unlimited", "accounting_unavailable"],
|
|
618
|
-
},
|
|
619
|
-
mode: { type: "string", enum: ["free", "credits"] },
|
|
620
|
-
balance: { type: ["integer", "null"], minimum: 0 },
|
|
621
|
-
balancePreview: { type: "boolean" },
|
|
622
|
-
unitCost: { type: "number", enum: [0, 1] },
|
|
623
|
-
charged: { type: "number", enum: [0, 1] },
|
|
624
|
-
unlimited: { type: "boolean" },
|
|
625
|
-
accountingAvailable: { type: "boolean" },
|
|
626
|
-
generationAvailable: { type: "boolean" },
|
|
627
|
-
purchaseRequired: { type: "boolean" },
|
|
628
|
-
manageUrl: { type: ["string", "null"] },
|
|
629
|
-
replayed: { type: "boolean" },
|
|
630
|
-
message: { type: "string" },
|
|
631
|
-
},
|
|
632
|
-
required: [
|
|
633
|
-
"state",
|
|
634
|
-
"mode",
|
|
635
|
-
"balance",
|
|
636
|
-
"balancePreview",
|
|
637
|
-
"unitCost",
|
|
638
|
-
"charged",
|
|
639
|
-
"unlimited",
|
|
640
|
-
"accountingAvailable",
|
|
641
|
-
"generationAvailable",
|
|
642
|
-
"purchaseRequired",
|
|
643
|
-
"manageUrl",
|
|
644
|
-
"replayed",
|
|
645
|
-
"message",
|
|
646
|
-
],
|
|
647
|
-
};
|
|
648
|
-
const CREDIT_ERROR_SCHEMA = {
|
|
649
|
-
type: "object",
|
|
650
|
-
additionalProperties: false,
|
|
651
|
-
properties: {
|
|
652
|
-
code: { type: "string", enum: ["insufficient_credits", "credit_accounting_unavailable"] },
|
|
653
|
-
retryable: { type: "boolean", enum: [true] },
|
|
654
|
-
},
|
|
655
|
-
required: ["code", "retryable"],
|
|
656
|
-
};
|
|
657
|
-
const CREDIT_RETRY_SCHEMA = {
|
|
658
|
-
type: "object",
|
|
659
|
-
additionalProperties: false,
|
|
660
|
-
properties: {
|
|
661
|
-
safe: { type: "boolean", enum: [true] },
|
|
662
|
-
idempotent: { type: "boolean", enum: [true] },
|
|
663
|
-
scope: { type: "string", enum: ["pre_generation"] },
|
|
664
|
-
after: { type: "string", enum: ["balance_updated", "accounting_available"] },
|
|
665
|
-
},
|
|
666
|
-
required: ["safe", "idempotent", "scope", "after"],
|
|
667
|
-
};
|
|
668
|
-
// Carried by a credit-gate refusal only; a completed draft or rewrite no longer reports
|
|
669
|
-
// credits (13 constants in free mode) or a status beside `state` (IDI-381).
|
|
670
|
-
const CREDIT_GENERATION_OUTPUT_PROPERTIES = {
|
|
671
|
-
status: { type: "string", enum: ["purchase_required", "accounting_unavailable"] },
|
|
672
|
-
message: { type: "string" },
|
|
673
|
-
credits: CREDIT_OUTPUT_SCHEMA,
|
|
674
|
-
error: CREDIT_ERROR_SCHEMA,
|
|
675
|
-
retry: CREDIT_RETRY_SCHEMA,
|
|
676
|
-
};
|
|
677
439
|
const NEXT_ACTION_SCHEMA = {
|
|
678
440
|
type: "object",
|
|
679
441
|
additionalProperties: false,
|
|
@@ -735,7 +497,6 @@ const REWRITE_OUTPUT_SCHEMA = {
|
|
|
735
497
|
reason: { type: ["string", "null"], description: "Present only when scoring is enabled and the engine did not measure; says why." },
|
|
736
498
|
voice: SELECTED_VOICE_SCHEMA,
|
|
737
499
|
evidence: EVIDENCE_OUTPUT_SCHEMA,
|
|
738
|
-
...CREDIT_GENERATION_OUTPUT_PROPERTIES,
|
|
739
500
|
...CAVEATS_OUTPUT_PROPERTY,
|
|
740
501
|
},
|
|
741
502
|
};
|
|
@@ -747,7 +508,6 @@ const DRAFT_OUTPUT_SCHEMA = {
|
|
|
747
508
|
reason: { type: ["string", "null"], description: "Present only when scoring is enabled and the engine did not measure; says why." },
|
|
748
509
|
voice: SELECTED_VOICE_SCHEMA,
|
|
749
510
|
evidence: EVIDENCE_OUTPUT_SCHEMA,
|
|
750
|
-
...CREDIT_GENERATION_OUTPUT_PROPERTIES,
|
|
751
511
|
...CAVEATS_OUTPUT_PROPERTY,
|
|
752
512
|
},
|
|
753
513
|
};
|
|
@@ -1012,20 +772,6 @@ const accountToolDefinitions = [
|
|
|
1012
772
|
]),
|
|
1013
773
|
annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: true, title: "Delete Writing Profile" },
|
|
1014
774
|
},
|
|
1015
|
-
{
|
|
1016
|
-
name: "get_credit_status",
|
|
1017
|
-
description:
|
|
1018
|
-
"Check the account's current generation-credit state. During the free beta, this confirms that no credits are being used.",
|
|
1019
|
-
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
1020
|
-
outputSchema: CREDIT_OUTPUT_SCHEMA,
|
|
1021
|
-
annotations: {
|
|
1022
|
-
readOnlyHint: true,
|
|
1023
|
-
idempotentHint: true,
|
|
1024
|
-
openWorldHint: false,
|
|
1025
|
-
destructiveHint: false,
|
|
1026
|
-
title: "Check Credit Status",
|
|
1027
|
-
},
|
|
1028
|
-
},
|
|
1029
775
|
{
|
|
1030
776
|
name: "score_voice",
|
|
1031
777
|
description:
|
|
@@ -1061,6 +807,12 @@ const accountToolDefinitions = [
|
|
|
1061
807
|
description:
|
|
1062
808
|
"The user's actual change request — length, tone, audience, what to cut or keep, make it sound less AI-written, roughen it up, or make it sound like I am talking. Kept separate from `text`: put the request here, never inside the prose to rewrite. `changeScope` carries magnitude; `instructions` carries the requested change.",
|
|
1063
809
|
},
|
|
810
|
+
language: {
|
|
811
|
+
type: "string",
|
|
812
|
+
minLength: 1,
|
|
813
|
+
maxLength: 100,
|
|
814
|
+
description: "The language for the finished writing, in plain words (for example 'French'). Set it only when the user asked for a specific language. Omit it to follow the request's language, or the source text's language for a rewrite.",
|
|
815
|
+
},
|
|
1064
816
|
changeScope: CHANGE_SCOPE_SCHEMA,
|
|
1065
817
|
effects: EFFECTS_SCHEMA,
|
|
1066
818
|
sourceAuthor: SOURCE_AUTHOR_SCHEMA,
|
|
@@ -1101,6 +853,12 @@ const accountToolDefinitions = [
|
|
|
1101
853
|
description:
|
|
1102
854
|
"`instructions` is the user's actual direction: how to write the piece — tone, length, format, structure, and what to leave out. Optional; omit it when the user gave none. Never paste directions into `brief`, which carries the material, and never put material here. A named output shape goes in `format`.",
|
|
1103
855
|
},
|
|
856
|
+
language: {
|
|
857
|
+
type: "string",
|
|
858
|
+
minLength: 1,
|
|
859
|
+
maxLength: 100,
|
|
860
|
+
description: "The language for the finished writing, in plain words (for example 'French'). Set it only when the user asked for a specific language. Omit it to follow the request's language, or the source text's language for a rewrite.",
|
|
861
|
+
},
|
|
1104
862
|
effects: EFFECTS_SCHEMA,
|
|
1105
863
|
briefAuthor: BRIEF_AUTHOR_SCHEMA,
|
|
1106
864
|
calibration: CALIBRATION_SCHEMA,
|
|
@@ -1468,18 +1226,7 @@ export async function handleAccountTool(name, args = {}) {
|
|
|
1468
1226
|
}
|
|
1469
1227
|
}
|
|
1470
1228
|
if (name === "get_credit_status") {
|
|
1471
|
-
|
|
1472
|
-
const credits = safeCreditPresentation(await accountRequest("/api/v1/credits", {
|
|
1473
|
-
toolName: "get_credit_status",
|
|
1474
|
-
}));
|
|
1475
|
-
if (!credits) return toolError("get_credit_status: Idiolect AI returned an invalid credit status.");
|
|
1476
|
-
return {
|
|
1477
|
-
content: [{ type: "text", text: credits.message }],
|
|
1478
|
-
structuredContent: credits,
|
|
1479
|
-
};
|
|
1480
|
-
} catch (error) {
|
|
1481
|
-
return accountToolError(error);
|
|
1482
|
-
}
|
|
1229
|
+
return toolError("This tool is no longer available. Refresh the Idiolect AI tool catalogue.");
|
|
1483
1230
|
}
|
|
1484
1231
|
|
|
1485
1232
|
if (name === "get_my_voice") {
|
|
@@ -1625,6 +1372,9 @@ export async function handleToolRequest(req) {
|
|
|
1625
1372
|
const instructions = typeof args.instructions === "string" && args.instructions.trim()
|
|
1626
1373
|
? args.instructions.trim()
|
|
1627
1374
|
: undefined;
|
|
1375
|
+
const language = typeof args.language === "string" && args.language.trim()
|
|
1376
|
+
? args.language.trim()
|
|
1377
|
+
: undefined;
|
|
1628
1378
|
const invalidChangeRequest = changeRequestError(args, "rewrite_in_voice");
|
|
1629
1379
|
if (invalidChangeRequest) return invalidChangeRequest;
|
|
1630
1380
|
const invalidSourceAuthor = authorProvenanceError(args, "rewrite_in_voice", "sourceAuthor");
|
|
@@ -1655,6 +1405,7 @@ export async function handleToolRequest(req) {
|
|
|
1655
1405
|
...(profileId !== undefined ? { voice: profileId } : {}),
|
|
1656
1406
|
...(targetRegister ? { targetRegister } : {}),
|
|
1657
1407
|
...(instructions ? { instructions } : {}),
|
|
1408
|
+
...(language ? { language } : {}),
|
|
1658
1409
|
...(changeScope !== undefined ? { changeScope } : {}),
|
|
1659
1410
|
...(effects !== undefined ? { effects } : {}),
|
|
1660
1411
|
...(sourceAuthor !== undefined ? { sourceAuthor } : {}),
|
|
@@ -1686,6 +1437,9 @@ export async function handleToolRequest(req) {
|
|
|
1686
1437
|
const instructions = typeof args.instructions === "string" && args.instructions.trim()
|
|
1687
1438
|
? args.instructions.trim()
|
|
1688
1439
|
: undefined;
|
|
1440
|
+
const language = typeof args.language === "string" && args.language.trim()
|
|
1441
|
+
? args.language.trim()
|
|
1442
|
+
: undefined;
|
|
1689
1443
|
const formats = new Set(["linkedin", "x_post", "x_thread", "newsletter", "generic"]);
|
|
1690
1444
|
const invalidChangeRequest = changeRequestError(args, "draft_in_voice");
|
|
1691
1445
|
if (invalidChangeRequest) return invalidChangeRequest;
|
|
@@ -1717,6 +1471,7 @@ export async function handleToolRequest(req) {
|
|
|
1717
1471
|
...(profileId !== undefined ? { voice: profileId } : {}),
|
|
1718
1472
|
...(format ? { format } : {}),
|
|
1719
1473
|
...(instructions ? { instructions } : {}),
|
|
1474
|
+
...(language ? { language } : {}),
|
|
1720
1475
|
...(changeScope !== undefined ? { changeScope } : {}),
|
|
1721
1476
|
...(effects !== undefined ? { effects } : {}),
|
|
1722
1477
|
...(briefAuthor !== undefined ? { briefAuthor } : {}),
|