@fias/arche-sdk 2.21.0 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridge.d.ts +33 -3
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +98 -15
- package/dist/bridge.js.map +1 -1
- package/dist/bridge.test.js +173 -0
- package/dist/bridge.test.js.map +1 -1
- package/dist/generated/permissions.d.ts +1 -1
- package/dist/generated/permissions.d.ts.map +1 -1
- package/dist/generated/permissions.js +2 -0
- package/dist/generated/permissions.js.map +1 -1
- package/dist/hooks.d.ts +55 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +100 -18
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.test.js +57 -1
- package/dist/hooks.test.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +309 -34
- package/dist/invocation-params.d.ts +92 -0
- package/dist/invocation-params.d.ts.map +1 -0
- package/dist/invocation-params.js +180 -0
- package/dist/invocation-params.js.map +1 -0
- package/dist/invocation-params.test.d.ts +2 -0
- package/dist/invocation-params.test.d.ts.map +1 -0
- package/dist/invocation-params.test.js +140 -0
- package/dist/invocation-params.test.js.map +1 -0
- package/dist/panels.d.ts.map +1 -1
- package/dist/panels.js.map +1 -1
- package/dist/panels.test.js +1 -3
- package/dist/panels.test.js.map +1 -1
- package/dist/types.d.ts +133 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/default/AGENTS.md +93 -3
- package/templates/default/CLAUDE.md +93 -3
package/dist/index.mjs
CHANGED
|
@@ -114,19 +114,137 @@ function installSandboxDialogShims(win = typeof window === "undefined" ? void 0
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
// src/invocation-params.ts
|
|
118
|
+
var ENTITY_INVOCATION_HISTORY_LIMITS = {
|
|
119
|
+
maxTurns: 40,
|
|
120
|
+
maxTurnChars: 1e5,
|
|
121
|
+
maxTotalChars: 15e4
|
|
122
|
+
};
|
|
123
|
+
var ENTITY_INVOCATION_REQUEST_LIMITS = {
|
|
124
|
+
textBytes: 256 * 1024,
|
|
125
|
+
visionBytes: 1536 * 1024,
|
|
126
|
+
envelopeBytes: 1024
|
|
127
|
+
};
|
|
128
|
+
function serializedBytes(value) {
|
|
129
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
130
|
+
}
|
|
131
|
+
function carriesImages(params) {
|
|
132
|
+
return Array.isArray(params.images) && params.images.length > 0;
|
|
133
|
+
}
|
|
134
|
+
function invocationPayloadByteLimit(params) {
|
|
135
|
+
const { textBytes, visionBytes, envelopeBytes } = ENTITY_INVOCATION_REQUEST_LIMITS;
|
|
136
|
+
return (carriesImages(params) ? visionBytes : textBytes) - envelopeBytes;
|
|
137
|
+
}
|
|
138
|
+
function checkInvocationRequestSize(payload) {
|
|
139
|
+
const bytes = serializedBytes(payload);
|
|
140
|
+
const limit = invocationPayloadByteLimit(payload);
|
|
141
|
+
if (bytes > limit) {
|
|
142
|
+
return {
|
|
143
|
+
ok: false,
|
|
144
|
+
message: `The request is ${bytes} bytes; ${carriesImages(payload) ? "a call with images" : "a call without images"} may be at most ${limit}. Send less history (fitHistoryToLimits with { request }) or a shorter input.`
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return { ok: true, value: bytes };
|
|
148
|
+
}
|
|
149
|
+
var REASONING_EFFORTS = ["off", "low", "medium", "high"];
|
|
150
|
+
function isPlainObject(value) {
|
|
151
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
152
|
+
}
|
|
153
|
+
function checkInvocationHistory(value) {
|
|
154
|
+
if (value === void 0) return { ok: true, value: void 0 };
|
|
155
|
+
const { maxTurns, maxTurnChars, maxTotalChars } = ENTITY_INVOCATION_HISTORY_LIMITS;
|
|
156
|
+
if (!Array.isArray(value)) return { ok: false, message: "history: must be an array" };
|
|
157
|
+
if (value.length > maxTurns) {
|
|
158
|
+
return { ok: false, message: `history: at most ${maxTurns} turns` };
|
|
159
|
+
}
|
|
160
|
+
let total = 0;
|
|
161
|
+
for (let i = 0; i < value.length; i++) {
|
|
162
|
+
const turn = value[i];
|
|
163
|
+
if (!isPlainObject(turn)) return { ok: false, message: `history.${i}: must be an object` };
|
|
164
|
+
const extra = Object.keys(turn).filter((k) => k !== "role" && k !== "content");
|
|
165
|
+
if (extra.length > 0) {
|
|
166
|
+
return { ok: false, message: `history.${i}: unknown field "${extra[0]}"` };
|
|
167
|
+
}
|
|
168
|
+
if (turn.role !== "user" && turn.role !== "assistant") {
|
|
169
|
+
return { ok: false, message: `history.${i}.role: must be "user" or "assistant"` };
|
|
170
|
+
}
|
|
171
|
+
if (typeof turn.content !== "string") {
|
|
172
|
+
return { ok: false, message: `history.${i}.content: must be a string` };
|
|
173
|
+
}
|
|
174
|
+
if (turn.content.length > maxTurnChars) {
|
|
175
|
+
return { ok: false, message: `history.${i}.content: at most ${maxTurnChars} characters` };
|
|
176
|
+
}
|
|
177
|
+
total += turn.content.length;
|
|
178
|
+
}
|
|
179
|
+
if (total > maxTotalChars) {
|
|
180
|
+
return { ok: false, message: `history: at most ${maxTotalChars} characters in total` };
|
|
181
|
+
}
|
|
182
|
+
return { ok: true, value };
|
|
183
|
+
}
|
|
184
|
+
function checkReasoningParameter(value) {
|
|
185
|
+
if (value === void 0) return { ok: true, value: void 0 };
|
|
186
|
+
if (!isPlainObject(value))
|
|
187
|
+
return { ok: false, message: "parameters.reasoning: must be an object" };
|
|
188
|
+
const extra = Object.keys(value).filter((k) => k !== "effort" && k !== "includeThinking");
|
|
189
|
+
if (extra.length > 0) {
|
|
190
|
+
return { ok: false, message: `parameters.reasoning: unknown field "${extra[0]}"` };
|
|
191
|
+
}
|
|
192
|
+
if (!REASONING_EFFORTS.includes(value.effort)) {
|
|
193
|
+
return {
|
|
194
|
+
ok: false,
|
|
195
|
+
message: `parameters.reasoning.effort: must be one of ${REASONING_EFFORTS.join(", ")}`
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (value.includeThinking !== void 0 && typeof value.includeThinking !== "boolean") {
|
|
199
|
+
return { ok: false, message: "parameters.reasoning.includeThinking: must be a boolean" };
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
ok: true,
|
|
203
|
+
value: {
|
|
204
|
+
effort: value.effort,
|
|
205
|
+
includeThinking: value.includeThinking === true
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function fitHistoryToLimits(turns, options = {}) {
|
|
210
|
+
const limits = ENTITY_INVOCATION_HISTORY_LIMITS;
|
|
211
|
+
const maxTurns = Math.min(options.maxTurns ?? limits.maxTurns, limits.maxTurns);
|
|
212
|
+
const request = options.request ?? {};
|
|
213
|
+
let bytesLeft = invocationPayloadByteLimit(request) - serializedBytes({ ...request, stream: true, history: [] });
|
|
214
|
+
const kept = [];
|
|
215
|
+
let total = 0;
|
|
216
|
+
for (let i = turns.length - 1; i >= 0 && kept.length < maxTurns; i--) {
|
|
217
|
+
const turn = turns[i];
|
|
218
|
+
const content = turn.content.length > limits.maxTurnChars ? turn.content.slice(turn.content.length - limits.maxTurnChars) : turn.content;
|
|
219
|
+
if (total + content.length > limits.maxTotalChars) break;
|
|
220
|
+
const bytes = serializedBytes({ role: turn.role, content }) + (kept.length > 0 ? 1 : 0);
|
|
221
|
+
if (bytes > bytesLeft) break;
|
|
222
|
+
bytesLeft -= bytes;
|
|
223
|
+
total += content.length;
|
|
224
|
+
kept.push({ role: turn.role, content });
|
|
225
|
+
}
|
|
226
|
+
return kept.reverse();
|
|
227
|
+
}
|
|
228
|
+
|
|
117
229
|
// src/bridge.ts
|
|
118
230
|
var messageCounter = 0;
|
|
119
231
|
function generateMessageId() {
|
|
120
232
|
return `msg_${Date.now()}_${++messageCounter}`;
|
|
121
233
|
}
|
|
122
234
|
var FiasBridgeError = class extends Error {
|
|
123
|
-
constructor(message, code) {
|
|
235
|
+
constructor(message, code, requestId) {
|
|
124
236
|
super(message);
|
|
125
237
|
this.name = "FiasBridgeError";
|
|
126
238
|
this.code = code;
|
|
239
|
+
if (requestId) this.requestId = requestId;
|
|
127
240
|
}
|
|
128
241
|
toJSON() {
|
|
129
|
-
return {
|
|
242
|
+
return {
|
|
243
|
+
name: "FiasBridgeError",
|
|
244
|
+
code: this.code,
|
|
245
|
+
message: this.message,
|
|
246
|
+
...this.requestId ? { requestId: this.requestId } : {}
|
|
247
|
+
};
|
|
130
248
|
}
|
|
131
249
|
};
|
|
132
250
|
function mergeThemeWithDefaults(incoming) {
|
|
@@ -141,6 +259,8 @@ function mergeThemeWithDefaults(incoming) {
|
|
|
141
259
|
};
|
|
142
260
|
}
|
|
143
261
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
262
|
+
var STREAM_IDLE_TIMEOUT_MS = 12e4;
|
|
263
|
+
var STREAM_MAX_DURATION_MS = 15 * 6e4;
|
|
144
264
|
var FiasBridge = class {
|
|
145
265
|
constructor() {
|
|
146
266
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
@@ -151,6 +271,8 @@ var FiasBridge = class {
|
|
|
151
271
|
this.permissions = [];
|
|
152
272
|
this.theme = null;
|
|
153
273
|
this.vendoredAssets = null;
|
|
274
|
+
this.textModels = null;
|
|
275
|
+
this.textModelListeners = /* @__PURE__ */ new Set();
|
|
154
276
|
this.currentPath = "";
|
|
155
277
|
this.hostOrigin = "";
|
|
156
278
|
this.themeListeners = /* @__PURE__ */ new Set();
|
|
@@ -204,6 +326,7 @@ var FiasBridge = class {
|
|
|
204
326
|
this.permissions = initMsg.payload.permissions;
|
|
205
327
|
this.theme = mergeThemeWithDefaults(initMsg.payload.theme);
|
|
206
328
|
this.vendoredAssets = initMsg.payload.vendoredAssets ?? null;
|
|
329
|
+
this.textModels = initMsg.payload.textModels ?? null;
|
|
207
330
|
this.currentPath = initMsg.payload.currentPath;
|
|
208
331
|
this.initialized = true;
|
|
209
332
|
this.initResolve?.();
|
|
@@ -220,6 +343,15 @@ var FiasBridge = class {
|
|
|
220
343
|
}
|
|
221
344
|
return;
|
|
222
345
|
}
|
|
346
|
+
if (data.type === "text_models_update") {
|
|
347
|
+
if (Array.isArray(data.payload)) {
|
|
348
|
+
this.textModels = data.payload;
|
|
349
|
+
for (const listener of this.textModelListeners) {
|
|
350
|
+
listener(this.textModels);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
223
355
|
if (data.type === "navigate_update") {
|
|
224
356
|
this.currentPath = data.payload;
|
|
225
357
|
for (const listener of this.navigationListeners) {
|
|
@@ -254,10 +386,15 @@ var FiasBridge = class {
|
|
|
254
386
|
return;
|
|
255
387
|
}
|
|
256
388
|
if (data.type === "stream_token") {
|
|
257
|
-
const { messageId, text } = data;
|
|
389
|
+
const { messageId, text, channel } = data;
|
|
258
390
|
const pending = this.pendingRequests.get(messageId);
|
|
259
|
-
if (pending
|
|
260
|
-
|
|
391
|
+
if (!pending) return;
|
|
392
|
+
pending.onActivity?.();
|
|
393
|
+
if (typeof text !== "string" || channel === "keepalive") return;
|
|
394
|
+
if (channel === "thinking") {
|
|
395
|
+
pending.onThinking?.(text);
|
|
396
|
+
} else {
|
|
397
|
+
pending.onToken?.(text);
|
|
261
398
|
}
|
|
262
399
|
return;
|
|
263
400
|
}
|
|
@@ -326,12 +463,14 @@ var FiasBridge = class {
|
|
|
326
463
|
const pending = this.pendingRequests.get(response.messageId);
|
|
327
464
|
if (!pending) return;
|
|
328
465
|
clearTimeout(pending.timer);
|
|
466
|
+
pending.cleanup?.();
|
|
329
467
|
this.pendingRequests.delete(response.messageId);
|
|
330
468
|
if (response.error) {
|
|
331
469
|
pending.reject(
|
|
332
470
|
new FiasBridgeError(
|
|
333
471
|
response.error || "Bridge request failed",
|
|
334
|
-
response.errorCode ?? "BRIDGE_ERROR"
|
|
472
|
+
response.errorCode ?? "BRIDGE_ERROR",
|
|
473
|
+
response.errorRequestId
|
|
335
474
|
)
|
|
336
475
|
);
|
|
337
476
|
} else {
|
|
@@ -447,6 +586,17 @@ var FiasBridge = class {
|
|
|
447
586
|
getCurrentPath() {
|
|
448
587
|
return this.currentPath;
|
|
449
588
|
}
|
|
589
|
+
/**
|
|
590
|
+
* The live text-model catalog, or null until the host has delivered it (or
|
|
591
|
+
* when the plugin lacks `entities:invoke`). See `useTextModels`.
|
|
592
|
+
*/
|
|
593
|
+
getTextModels() {
|
|
594
|
+
return this.textModels;
|
|
595
|
+
}
|
|
596
|
+
onTextModelsUpdate(listener) {
|
|
597
|
+
this.textModelListeners.add(listener);
|
|
598
|
+
return () => this.textModelListeners.delete(listener);
|
|
599
|
+
}
|
|
450
600
|
onThemeUpdate(listener) {
|
|
451
601
|
this.themeListeners.add(listener);
|
|
452
602
|
return () => this.themeListeners.delete(listener);
|
|
@@ -500,21 +650,62 @@ var FiasBridge = class {
|
|
|
500
650
|
* resolves with the final EntityInvocationResult when the host sends the
|
|
501
651
|
* normal response message.
|
|
502
652
|
*/
|
|
503
|
-
async requestStream(payload,
|
|
653
|
+
async requestStream(payload, callbacks) {
|
|
654
|
+
const { onToken, onThinking, signal } = typeof callbacks === "function" ? { onToken: callbacks } : callbacks;
|
|
504
655
|
await this.waitForInit();
|
|
656
|
+
const outbound = { ...payload, stream: true };
|
|
657
|
+
const size = checkInvocationRequestSize(outbound);
|
|
658
|
+
if (!size.ok) {
|
|
659
|
+
throw new FiasBridgeError(size.message, "REQUEST_TOO_LARGE");
|
|
660
|
+
}
|
|
505
661
|
return new Promise((resolve, reject) => {
|
|
662
|
+
if (signal?.aborted) {
|
|
663
|
+
reject(new FiasBridgeError("Stream aborted before it started", "ABORTED"));
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
506
666
|
const messageId = generateMessageId();
|
|
507
|
-
const
|
|
667
|
+
const fail = (error) => {
|
|
668
|
+
const pending2 = this.pendingRequests.get(messageId);
|
|
669
|
+
if (!pending2) return;
|
|
670
|
+
clearTimeout(pending2.timer);
|
|
671
|
+
pending2.cleanup?.();
|
|
508
672
|
this.pendingRequests.delete(messageId);
|
|
509
|
-
reject(
|
|
510
|
-
}
|
|
511
|
-
|
|
673
|
+
reject(error);
|
|
674
|
+
};
|
|
675
|
+
const idleTimer = () => setTimeout(
|
|
676
|
+
() => fail(
|
|
677
|
+
new FiasBridgeError("Bridge streaming request timed out: entity_invoke", "TIMEOUT")
|
|
678
|
+
),
|
|
679
|
+
STREAM_IDLE_TIMEOUT_MS
|
|
680
|
+
);
|
|
681
|
+
const maxTimer = setTimeout(
|
|
682
|
+
() => fail(
|
|
683
|
+
new FiasBridgeError(
|
|
684
|
+
"Bridge streaming request exceeded its maximum duration: entity_invoke",
|
|
685
|
+
"TIMEOUT"
|
|
686
|
+
)
|
|
687
|
+
),
|
|
688
|
+
STREAM_MAX_DURATION_MS
|
|
689
|
+
);
|
|
690
|
+
const onAbort = () => fail(new FiasBridgeError("Stream aborted", "ABORTED"));
|
|
691
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
692
|
+
const pending = {
|
|
512
693
|
resolve,
|
|
513
694
|
reject,
|
|
514
|
-
timer,
|
|
515
|
-
onToken
|
|
516
|
-
|
|
517
|
-
|
|
695
|
+
timer: idleTimer(),
|
|
696
|
+
onToken,
|
|
697
|
+
onThinking,
|
|
698
|
+
onActivity: () => {
|
|
699
|
+
clearTimeout(pending.timer);
|
|
700
|
+
pending.timer = idleTimer();
|
|
701
|
+
},
|
|
702
|
+
cleanup: () => {
|
|
703
|
+
clearTimeout(maxTimer);
|
|
704
|
+
signal?.removeEventListener("abort", onAbort);
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
this.pendingRequests.set(messageId, pending);
|
|
708
|
+
this.send("entity_invoke", outbound, messageId);
|
|
518
709
|
});
|
|
519
710
|
}
|
|
520
711
|
/**
|
|
@@ -528,10 +719,12 @@ var FiasBridge = class {
|
|
|
528
719
|
}
|
|
529
720
|
for (const pending of this.pendingRequests.values()) {
|
|
530
721
|
clearTimeout(pending.timer);
|
|
722
|
+
pending.cleanup?.();
|
|
531
723
|
pending.reject(new FiasBridgeError("Bridge destroyed", "BRIDGE_DESTROYED"));
|
|
532
724
|
}
|
|
533
725
|
this.pendingRequests.clear();
|
|
534
726
|
this.themeListeners.clear();
|
|
727
|
+
this.textModelListeners.clear();
|
|
535
728
|
this.navigationListeners.clear();
|
|
536
729
|
this.stepNavigationListeners.clear();
|
|
537
730
|
this.previewStateProviders.clear();
|
|
@@ -1016,34 +1209,54 @@ function useFiasStorage() {
|
|
|
1016
1209
|
}
|
|
1017
1210
|
function useEntityInvocation() {
|
|
1018
1211
|
const bridge = useBridge();
|
|
1019
|
-
const [
|
|
1212
|
+
const [inFlight, setInFlight] = useState2(0);
|
|
1020
1213
|
const [result, setResult] = useState2(null);
|
|
1021
1214
|
const [error, setError] = useState2(null);
|
|
1022
1215
|
const [streamingText, setStreamingText] = useState2("");
|
|
1023
1216
|
const invoke = useCallback(
|
|
1024
|
-
async (params) => {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1217
|
+
async (params, options) => {
|
|
1218
|
+
const usesSharedSlots = !options?.onToken;
|
|
1219
|
+
setInFlight((n) => n + 1);
|
|
1220
|
+
if (usesSharedSlots) {
|
|
1221
|
+
setError(null);
|
|
1222
|
+
setStreamingText("");
|
|
1223
|
+
}
|
|
1028
1224
|
try {
|
|
1029
|
-
const res = await bridge.requestStream(params,
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1225
|
+
const res = await bridge.requestStream(params, {
|
|
1226
|
+
onToken: (token) => {
|
|
1227
|
+
if (options?.onToken) {
|
|
1228
|
+
options.onToken(token);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
flushSync(() => {
|
|
1232
|
+
setStreamingText((prev) => prev + token);
|
|
1233
|
+
});
|
|
1234
|
+
},
|
|
1235
|
+
onThinking: options?.onThinking,
|
|
1236
|
+
signal: options?.signal
|
|
1033
1237
|
});
|
|
1034
|
-
setResult(res);
|
|
1238
|
+
if (usesSharedSlots) setResult(res);
|
|
1035
1239
|
return res;
|
|
1036
1240
|
} catch (err) {
|
|
1037
1241
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
1038
|
-
setError(e);
|
|
1242
|
+
if (usesSharedSlots) setError(e);
|
|
1039
1243
|
throw e;
|
|
1040
1244
|
} finally {
|
|
1041
|
-
|
|
1245
|
+
setInFlight((n) => n - 1);
|
|
1042
1246
|
}
|
|
1043
1247
|
},
|
|
1044
1248
|
[bridge]
|
|
1045
1249
|
);
|
|
1046
|
-
return { invoke, isLoading, result, error, streamingText };
|
|
1250
|
+
return { invoke, isLoading: inFlight > 0, result, error, streamingText };
|
|
1251
|
+
}
|
|
1252
|
+
function useTextModels() {
|
|
1253
|
+
const bridge = useBridge();
|
|
1254
|
+
const [models, setModels] = useState2(bridge.getTextModels() ?? []);
|
|
1255
|
+
useEffect2(() => {
|
|
1256
|
+
setModels(bridge.getTextModels() ?? []);
|
|
1257
|
+
return bridge.onTextModelsUpdate(setModels);
|
|
1258
|
+
}, [bridge]);
|
|
1259
|
+
return models;
|
|
1047
1260
|
}
|
|
1048
1261
|
function useImageGeneration() {
|
|
1049
1262
|
const bridge = useBridge();
|
|
@@ -1968,7 +2181,7 @@ function useVaultDocuments() {
|
|
|
1968
2181
|
);
|
|
1969
2182
|
}
|
|
1970
2183
|
var SAVE_CONTENT_BODY_LANE_MAX_BYTES = 2e5;
|
|
1971
|
-
var BRIDGE_BODY_TEXT_MAX_SERIALIZED_BYTES =
|
|
2184
|
+
var BRIDGE_BODY_TEXT_MAX_SERIALIZED_BYTES = ENTITY_INVOCATION_REQUEST_LIMITS.textBytes - 16 * 1024;
|
|
1972
2185
|
function fitsBridgeBodyAsJsonText(text, utf8Bytes) {
|
|
1973
2186
|
if (text.length * 6 <= BRIDGE_BODY_TEXT_MAX_SERIALIZED_BYTES) return true;
|
|
1974
2187
|
const escapeOverhead = JSON.stringify(text).length - text.length;
|
|
@@ -2336,9 +2549,54 @@ function useVaultUserDocuments() {
|
|
|
2336
2549
|
},
|
|
2337
2550
|
[bridge]
|
|
2338
2551
|
);
|
|
2552
|
+
const workspace = useMemo2(
|
|
2553
|
+
() => ({
|
|
2554
|
+
list: async (options) => {
|
|
2555
|
+
const res = await invokeEntityOp(
|
|
2556
|
+
bridge,
|
|
2557
|
+
VAULT_USER_DOCUMENTS_ENTITY_ID,
|
|
2558
|
+
"list_workspace_documents",
|
|
2559
|
+
{ limit: options?.limit, offset: options?.offset, search: options?.search }
|
|
2560
|
+
);
|
|
2561
|
+
return res.documents;
|
|
2562
|
+
},
|
|
2563
|
+
get: (documentId, options) => invokeEntityOp(
|
|
2564
|
+
bridge,
|
|
2565
|
+
VAULT_USER_DOCUMENTS_ENTITY_ID,
|
|
2566
|
+
"get_workspace_document",
|
|
2567
|
+
{ documentId, includeContent: options?.includeContent }
|
|
2568
|
+
),
|
|
2569
|
+
getDownloadUrl: async (documentId) => {
|
|
2570
|
+
const res = await invokeEntityOp(bridge, VAULT_USER_DOCUMENTS_ENTITY_ID, "get_workspace_document_url", { documentId });
|
|
2571
|
+
return {
|
|
2572
|
+
url: res.url,
|
|
2573
|
+
expiresAt: new Date(res.expiresAt).getTime(),
|
|
2574
|
+
contentType: res.contentType
|
|
2575
|
+
};
|
|
2576
|
+
},
|
|
2577
|
+
getBytes: async (documentId) => {
|
|
2578
|
+
const res = await invokeEntityOp(bridge, VAULT_USER_DOCUMENTS_ENTITY_ID, "get_workspace_document_bytes", { documentId });
|
|
2579
|
+
return {
|
|
2580
|
+
document: res.document,
|
|
2581
|
+
bytes: base64ToBytes(res.bytesBase64),
|
|
2582
|
+
contentType: res.contentType
|
|
2583
|
+
};
|
|
2584
|
+
}
|
|
2585
|
+
}),
|
|
2586
|
+
[bridge]
|
|
2587
|
+
);
|
|
2339
2588
|
return useMemo2(
|
|
2340
|
-
() => ({
|
|
2341
|
-
|
|
2589
|
+
() => ({
|
|
2590
|
+
pick,
|
|
2591
|
+
requestEditAccess,
|
|
2592
|
+
saveContent,
|
|
2593
|
+
list,
|
|
2594
|
+
get,
|
|
2595
|
+
getDownloadUrl,
|
|
2596
|
+
getBytes,
|
|
2597
|
+
workspace
|
|
2598
|
+
}),
|
|
2599
|
+
[pick, requestEditAccess, saveContent, list, get, getDownloadUrl, getBytes, workspace]
|
|
2342
2600
|
);
|
|
2343
2601
|
}
|
|
2344
2602
|
var COMMUNITY_ASSET_URL_REFRESH_BUFFER_MS = 3e4;
|
|
@@ -2687,7 +2945,8 @@ var VALID_PLUGIN_PERMISSIONS = [
|
|
|
2687
2945
|
"vault:documents:write",
|
|
2688
2946
|
"vault:user-documents:edit",
|
|
2689
2947
|
"vault:user-documents:read",
|
|
2690
|
-
"vault:user-documents:write"
|
|
2948
|
+
"vault:user-documents:write",
|
|
2949
|
+
"vault:workspace-documents:read"
|
|
2691
2950
|
];
|
|
2692
2951
|
function isValidPluginPermission(perm) {
|
|
2693
2952
|
return VALID_PLUGIN_PERMISSIONS.includes(perm);
|
|
@@ -2718,7 +2977,8 @@ var PLUGIN_PERMISSION_DESCRIPTIONS = {
|
|
|
2718
2977
|
"vault:documents:write": "Create and manage its own files, in its own folder of your Vault.",
|
|
2719
2978
|
"vault:user-documents:edit": "Save changes to files of yours that you let it edit \u2014 you choose each file, earlier versions are kept unless you turned version history off, and you can remove access any time in Vault \u2192 Arche Access.",
|
|
2720
2979
|
"vault:user-documents:read": "Read documents YOU choose to share with it from your Vault \u2014 you pick each document, and you can remove access any time in Vault \u2192 Arche Access.",
|
|
2721
|
-
"vault:user-documents:write": "Save its work to your Documents \u2014 you choose the folder and the name each time."
|
|
2980
|
+
"vault:user-documents:write": "Save its work to your Documents \u2014 you choose the folder and the name each time.",
|
|
2981
|
+
"vault:workspace-documents:read": "Read every document you can see in a team workspace \u2014 only after that workspace's owner or admin approves it there, and never files marked proprietary."
|
|
2722
2982
|
};
|
|
2723
2983
|
|
|
2724
2984
|
// src/fias.ts
|
|
@@ -5059,7 +5319,13 @@ function validateAnimation(value, path, issues) {
|
|
|
5059
5319
|
}
|
|
5060
5320
|
rejectUnknownKeys(value, ["type", "durationMs", "easing"], path, issues);
|
|
5061
5321
|
checkOptionalEnum(value.type, `${path}.type`, issues, ANIMATION_TYPES);
|
|
5062
|
-
checkOptionalIntRange(
|
|
5322
|
+
checkOptionalIntRange(
|
|
5323
|
+
value.durationMs,
|
|
5324
|
+
`${path}.durationMs`,
|
|
5325
|
+
issues,
|
|
5326
|
+
0,
|
|
5327
|
+
ANIMATION_MAX_DURATION_MS
|
|
5328
|
+
);
|
|
5063
5329
|
checkOptionalEnum(value.easing, `${path}.easing`, issues, ANIMATION_EASINGS);
|
|
5064
5330
|
}
|
|
5065
5331
|
var THEME_COLOR_FIELDS = ["bg", "fg", "border", "accent", "accentFg", "scrim"];
|
|
@@ -5201,6 +5467,8 @@ export {
|
|
|
5201
5467
|
AUDIO_VOICE_CHANGER_SURFACE_KEY,
|
|
5202
5468
|
AUDIO_VOICE_DESIGN_SURFACE_KEY,
|
|
5203
5469
|
DARK_THEME,
|
|
5470
|
+
ENTITY_INVOCATION_HISTORY_LIMITS,
|
|
5471
|
+
ENTITY_INVOCATION_REQUEST_LIMITS,
|
|
5204
5472
|
FONT_CATALOG,
|
|
5205
5473
|
FONT_PAIRINGS,
|
|
5206
5474
|
FiasBridge,
|
|
@@ -5240,17 +5508,23 @@ export {
|
|
|
5240
5508
|
PANEL_TITLE_MAX_LENGTH,
|
|
5241
5509
|
PLUGIN_CONTENT_ENTITY_ID,
|
|
5242
5510
|
PLUGIN_PERMISSION_DESCRIPTIONS,
|
|
5511
|
+
REASONING_EFFORTS,
|
|
5243
5512
|
SDK_BRIDGE_PROTOCOL_VERSION,
|
|
5244
5513
|
SDK_REQUIRES_HOST_PROTOCOL_VERSION,
|
|
5245
5514
|
THEME_CATALOG,
|
|
5246
5515
|
VALID_PLUGIN_PERMISSIONS,
|
|
5516
|
+
checkInvocationHistory,
|
|
5517
|
+
checkInvocationRequestSize,
|
|
5518
|
+
checkReasoningParameter,
|
|
5247
5519
|
ensureFontLoaded,
|
|
5248
5520
|
fetchVaultDocumentDownloadUrl,
|
|
5249
5521
|
fias,
|
|
5522
|
+
fitHistoryToLimits,
|
|
5250
5523
|
getBridge,
|
|
5251
5524
|
getDefaultTheme,
|
|
5252
5525
|
getFontPairingById,
|
|
5253
5526
|
getThemeById,
|
|
5527
|
+
invocationPayloadByteLimit,
|
|
5254
5528
|
isValidPluginPermission,
|
|
5255
5529
|
resetBridge,
|
|
5256
5530
|
useArcheAssets,
|
|
@@ -5299,6 +5573,7 @@ export {
|
|
|
5299
5573
|
useSmartVectorize,
|
|
5300
5574
|
useStepNavigation,
|
|
5301
5575
|
useSurface,
|
|
5576
|
+
useTextModels,
|
|
5302
5577
|
useVaultDocuments,
|
|
5303
5578
|
useVaultUserDocuments,
|
|
5304
5579
|
validatePanelAction,
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Limits and validation for the multi-turn fields of an AI `entity_invoke`:
|
|
3
|
+
* `history` (prior conversation turns) and `parameters.reasoning`.
|
|
4
|
+
*
|
|
5
|
+
* ONE implementation, deliberately placed in the SDK. It is dependency-free, so
|
|
6
|
+
* it can run in three places that must never disagree:
|
|
7
|
+
* - the platform bridges, which reject a malformed call with `INVALID_PARAMS`;
|
|
8
|
+
* - the dev harness's MOCK mode, which must reject the same calls offline
|
|
9
|
+
* (the harness is published to npm and may only depend on this SDK);
|
|
10
|
+
* - plugins, which use `fitHistoryToLimits` to trim a conversation BEFORE
|
|
11
|
+
* sending it rather than finding out from a rejected call.
|
|
12
|
+
*/
|
|
13
|
+
import type { EntityInvocationParams, EntityInvocationTurn, ReasoningEffort } from './types';
|
|
14
|
+
/**
|
|
15
|
+
* Bounds on `EntityInvocationParams.history`, in characters. They are the
|
|
16
|
+
* validator's rules, not a promise that a call fits: the request must ALSO fit
|
|
17
|
+
* the bridge's byte limit (`ENTITY_INVOCATION_REQUEST_LIMITS`), and a character
|
|
18
|
+
* can serialize to up to 4 bytes (CJK 3, emoji 4, a newline or quote 2). Trim
|
|
19
|
+
* with `fitHistoryToLimits(turns, { request })`, which applies both.
|
|
20
|
+
*/
|
|
21
|
+
export declare const ENTITY_INVOCATION_HISTORY_LIMITS: {
|
|
22
|
+
readonly maxTurns: 40;
|
|
23
|
+
readonly maxTurnChars: 100000;
|
|
24
|
+
readonly maxTotalChars: 150000;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The platform bridge's request-size ceilings, in bytes of the serialized
|
|
28
|
+
* (UTF-8 JSON) request. A text-only `entity_invoke` travels on the 256 KB
|
|
29
|
+
* route; one carrying images on the 1.5 MB vision route. Mirrors the server's
|
|
30
|
+
* `PLUGIN_BRIDGE_BODY_LIMIT_BYTES` / `PLUGIN_BRIDGE_VISION_BODY_LIMIT_BYTES`
|
|
31
|
+
* (pinned by `tests/architecture/invocation-params-parity.test.ts`).
|
|
32
|
+
* `envelopeBytes` is kept free for what the host wraps around the payload.
|
|
33
|
+
*/
|
|
34
|
+
export declare const ENTITY_INVOCATION_REQUEST_LIMITS: {
|
|
35
|
+
readonly textBytes: number;
|
|
36
|
+
readonly visionBytes: number;
|
|
37
|
+
readonly envelopeBytes: 1024;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* The most bytes an `entity_invoke` payload may serialize to: the limit of the
|
|
41
|
+
* route it will travel on, less the host's envelope.
|
|
42
|
+
*/
|
|
43
|
+
export declare function invocationPayloadByteLimit(params: {
|
|
44
|
+
images?: unknown;
|
|
45
|
+
}): number;
|
|
46
|
+
/**
|
|
47
|
+
* Whether an `entity_invoke` payload fits the bridge's request limit. The SDK
|
|
48
|
+
* checks this before sending, so an oversized call fails with
|
|
49
|
+
* `REQUEST_TOO_LARGE` instead of an opaque HTTP 413 from the server.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkInvocationRequestSize(payload: Record<string, unknown>): InvocationParamCheck<number>;
|
|
52
|
+
export declare const REASONING_EFFORTS: readonly ReasoningEffort[];
|
|
53
|
+
export type InvocationParamCheck<T> = {
|
|
54
|
+
ok: true;
|
|
55
|
+
value: T | undefined;
|
|
56
|
+
} | {
|
|
57
|
+
ok: false;
|
|
58
|
+
message: string;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Validate a `history` value. `undefined` is valid (no history). Roles are
|
|
62
|
+
* `user` / `assistant` only, so a caller can never inject a second system
|
|
63
|
+
* message; unknown turn fields are rejected, not dropped.
|
|
64
|
+
*/
|
|
65
|
+
export declare function checkInvocationHistory(value: unknown): InvocationParamCheck<EntityInvocationTurn[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Validate `parameters.reasoning`. `undefined` is valid (no reasoning request);
|
|
68
|
+
* `includeThinking` defaults to `false`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function checkReasoningParameter(value: unknown): InvocationParamCheck<{
|
|
71
|
+
effort: ReasoningEffort;
|
|
72
|
+
includeThinking: boolean;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* The newest suffix of `turns` that fits: the character caps in
|
|
76
|
+
* `ENTITY_INVOCATION_HISTORY_LIMITS` AND the bridge's byte limit, optionally
|
|
77
|
+
* capped at `maxTurns` (e.g. a "last 20 messages" window).
|
|
78
|
+
*
|
|
79
|
+
* Pass the rest of the call as `request` (input, systemPrompt, images,
|
|
80
|
+
* parameters — everything but `history`) so the byte budget is what that call
|
|
81
|
+
* leaves over on the route it will take. Without it the budget assumes the
|
|
82
|
+
* history is all there is, which a real call can still exceed.
|
|
83
|
+
*
|
|
84
|
+
* Older turns are dropped first; a single turn longer than the per-turn cap
|
|
85
|
+
* keeps its most recent text. Every turn sent is billed as input on every call,
|
|
86
|
+
* so a smaller window is also cheaper.
|
|
87
|
+
*/
|
|
88
|
+
export declare function fitHistoryToLimits(turns: readonly EntityInvocationTurn[], options?: {
|
|
89
|
+
maxTurns?: number;
|
|
90
|
+
request?: Omit<EntityInvocationParams, 'history'>;
|
|
91
|
+
}): EntityInvocationTurn[];
|
|
92
|
+
//# sourceMappingURL=invocation-params.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invocation-params.d.ts","sourceRoot":"","sources":["../src/invocation-params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE7F;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC;;;;CAInC,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC;;;;CAInC,CAAC;AAWX;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAG/E;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,oBAAoB,CAAC,MAAM,CAAC,CAY9B;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EAAqC,CAAC;AAE9F,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,SAAS,CAAA;CAAE,GAClC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAMnC;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,GACb,oBAAoB,CAAC,oBAAoB,EAAE,CAAC,CA8B9C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,oBAAoB,CAAC;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CAwB7E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,oBAAoB,EAAE,EACtC,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC,CAAA;CAAO,GACrF,oBAAoB,EAAE,CA0BxB"}
|