@fias/arche-sdk 2.21.0 → 2.23.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/entity-ops.d.ts +3 -0
- package/dist/entity-ops.d.ts.map +1 -1
- package/dist/entity-ops.js +4 -1
- package/dist/entity-ops.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 +4 -0
- package/dist/generated/permissions.js.map +1 -1
- package/dist/hooks.d.ts +82 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +143 -20
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.test.js +93 -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 +14 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +329 -36
- 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/protocol.d.ts +8 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +8 -0
- package/dist/protocol.js.map +1 -1
- package/dist/types.d.ts +219 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/default/AGENTS.md +140 -4
- package/templates/default/CLAUDE.md +140 -4
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();
|
|
@@ -877,6 +1070,7 @@ var VAULT_USER_DOCUMENTS_ENTITY_ID = "ent_intg_vault_documents_0000000";
|
|
|
877
1070
|
var VAULT_ARCHE_DOCUMENTS_ENTITY_ID = "ent_intg_vault_arche_docs_000000";
|
|
878
1071
|
var COMMUNITY_ASSETS_ENTITY_ID = "ent_intg_community_assets_000000";
|
|
879
1072
|
var DOCUMENT_SIGN_ENTITY_ID = "ent_intg_document_sign_000000000";
|
|
1073
|
+
var COMPANY_EMAIL_SEND_ENTITY_ID = "ent_intg_company_email_send_0000";
|
|
880
1074
|
var COMMUNITY_ASSET_MAX_URL_BATCH = 50;
|
|
881
1075
|
var COMMUNITY_ASSET_MAX_PUBLISH_BATCH = 20;
|
|
882
1076
|
async function invokeEntityOp(bridge, entityId, op, args = {}) {
|
|
@@ -1016,34 +1210,54 @@ function useFiasStorage() {
|
|
|
1016
1210
|
}
|
|
1017
1211
|
function useEntityInvocation() {
|
|
1018
1212
|
const bridge = useBridge();
|
|
1019
|
-
const [
|
|
1213
|
+
const [inFlight, setInFlight] = useState2(0);
|
|
1020
1214
|
const [result, setResult] = useState2(null);
|
|
1021
1215
|
const [error, setError] = useState2(null);
|
|
1022
1216
|
const [streamingText, setStreamingText] = useState2("");
|
|
1023
1217
|
const invoke = useCallback(
|
|
1024
|
-
async (params) => {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1218
|
+
async (params, options) => {
|
|
1219
|
+
const usesSharedSlots = !options?.onToken;
|
|
1220
|
+
setInFlight((n) => n + 1);
|
|
1221
|
+
if (usesSharedSlots) {
|
|
1222
|
+
setError(null);
|
|
1223
|
+
setStreamingText("");
|
|
1224
|
+
}
|
|
1028
1225
|
try {
|
|
1029
|
-
const res = await bridge.requestStream(params,
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1226
|
+
const res = await bridge.requestStream(params, {
|
|
1227
|
+
onToken: (token) => {
|
|
1228
|
+
if (options?.onToken) {
|
|
1229
|
+
options.onToken(token);
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
flushSync(() => {
|
|
1233
|
+
setStreamingText((prev) => prev + token);
|
|
1234
|
+
});
|
|
1235
|
+
},
|
|
1236
|
+
onThinking: options?.onThinking,
|
|
1237
|
+
signal: options?.signal
|
|
1033
1238
|
});
|
|
1034
|
-
setResult(res);
|
|
1239
|
+
if (usesSharedSlots) setResult(res);
|
|
1035
1240
|
return res;
|
|
1036
1241
|
} catch (err) {
|
|
1037
1242
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
1038
|
-
setError(e);
|
|
1243
|
+
if (usesSharedSlots) setError(e);
|
|
1039
1244
|
throw e;
|
|
1040
1245
|
} finally {
|
|
1041
|
-
|
|
1246
|
+
setInFlight((n) => n - 1);
|
|
1042
1247
|
}
|
|
1043
1248
|
},
|
|
1044
1249
|
[bridge]
|
|
1045
1250
|
);
|
|
1046
|
-
return { invoke, isLoading, result, error, streamingText };
|
|
1251
|
+
return { invoke, isLoading: inFlight > 0, result, error, streamingText };
|
|
1252
|
+
}
|
|
1253
|
+
function useTextModels() {
|
|
1254
|
+
const bridge = useBridge();
|
|
1255
|
+
const [models, setModels] = useState2(bridge.getTextModels() ?? []);
|
|
1256
|
+
useEffect2(() => {
|
|
1257
|
+
setModels(bridge.getTextModels() ?? []);
|
|
1258
|
+
return bridge.onTextModelsUpdate(setModels);
|
|
1259
|
+
}, [bridge]);
|
|
1260
|
+
return models;
|
|
1047
1261
|
}
|
|
1048
1262
|
function useImageGeneration() {
|
|
1049
1263
|
const bridge = useBridge();
|
|
@@ -1237,8 +1451,8 @@ function useFiasNavigation() {
|
|
|
1237
1451
|
};
|
|
1238
1452
|
}, [bridge]);
|
|
1239
1453
|
const navigateTo = useCallback(
|
|
1240
|
-
(path) => {
|
|
1241
|
-
bridge.request("navigate", { path });
|
|
1454
|
+
(path, opts) => {
|
|
1455
|
+
bridge.request("navigate", { path, ...opts?.replace ? { replace: true } : {} });
|
|
1242
1456
|
},
|
|
1243
1457
|
[bridge]
|
|
1244
1458
|
);
|
|
@@ -1968,7 +2182,7 @@ function useVaultDocuments() {
|
|
|
1968
2182
|
);
|
|
1969
2183
|
}
|
|
1970
2184
|
var SAVE_CONTENT_BODY_LANE_MAX_BYTES = 2e5;
|
|
1971
|
-
var BRIDGE_BODY_TEXT_MAX_SERIALIZED_BYTES =
|
|
2185
|
+
var BRIDGE_BODY_TEXT_MAX_SERIALIZED_BYTES = ENTITY_INVOCATION_REQUEST_LIMITS.textBytes - 16 * 1024;
|
|
1972
2186
|
function fitsBridgeBodyAsJsonText(text, utf8Bytes) {
|
|
1973
2187
|
if (text.length * 6 <= BRIDGE_BODY_TEXT_MAX_SERIALIZED_BYTES) return true;
|
|
1974
2188
|
const escapeOverhead = JSON.stringify(text).length - text.length;
|
|
@@ -2336,9 +2550,54 @@ function useVaultUserDocuments() {
|
|
|
2336
2550
|
},
|
|
2337
2551
|
[bridge]
|
|
2338
2552
|
);
|
|
2553
|
+
const workspace = useMemo2(
|
|
2554
|
+
() => ({
|
|
2555
|
+
list: async (options) => {
|
|
2556
|
+
const res = await invokeEntityOp(
|
|
2557
|
+
bridge,
|
|
2558
|
+
VAULT_USER_DOCUMENTS_ENTITY_ID,
|
|
2559
|
+
"list_workspace_documents",
|
|
2560
|
+
{ limit: options?.limit, offset: options?.offset, search: options?.search }
|
|
2561
|
+
);
|
|
2562
|
+
return res.documents;
|
|
2563
|
+
},
|
|
2564
|
+
get: (documentId, options) => invokeEntityOp(
|
|
2565
|
+
bridge,
|
|
2566
|
+
VAULT_USER_DOCUMENTS_ENTITY_ID,
|
|
2567
|
+
"get_workspace_document",
|
|
2568
|
+
{ documentId, includeContent: options?.includeContent }
|
|
2569
|
+
),
|
|
2570
|
+
getDownloadUrl: async (documentId) => {
|
|
2571
|
+
const res = await invokeEntityOp(bridge, VAULT_USER_DOCUMENTS_ENTITY_ID, "get_workspace_document_url", { documentId });
|
|
2572
|
+
return {
|
|
2573
|
+
url: res.url,
|
|
2574
|
+
expiresAt: new Date(res.expiresAt).getTime(),
|
|
2575
|
+
contentType: res.contentType
|
|
2576
|
+
};
|
|
2577
|
+
},
|
|
2578
|
+
getBytes: async (documentId) => {
|
|
2579
|
+
const res = await invokeEntityOp(bridge, VAULT_USER_DOCUMENTS_ENTITY_ID, "get_workspace_document_bytes", { documentId });
|
|
2580
|
+
return {
|
|
2581
|
+
document: res.document,
|
|
2582
|
+
bytes: base64ToBytes(res.bytesBase64),
|
|
2583
|
+
contentType: res.contentType
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
}),
|
|
2587
|
+
[bridge]
|
|
2588
|
+
);
|
|
2339
2589
|
return useMemo2(
|
|
2340
|
-
() => ({
|
|
2341
|
-
|
|
2590
|
+
() => ({
|
|
2591
|
+
pick,
|
|
2592
|
+
requestEditAccess,
|
|
2593
|
+
saveContent,
|
|
2594
|
+
list,
|
|
2595
|
+
get,
|
|
2596
|
+
getDownloadUrl,
|
|
2597
|
+
getBytes,
|
|
2598
|
+
workspace
|
|
2599
|
+
}),
|
|
2600
|
+
[pick, requestEditAccess, saveContent, list, get, getDownloadUrl, getBytes, workspace]
|
|
2342
2601
|
);
|
|
2343
2602
|
}
|
|
2344
2603
|
var COMMUNITY_ASSET_URL_REFRESH_BUFFER_MS = 3e4;
|
|
@@ -2398,6 +2657,20 @@ async function fetchCommunityAssetUrls(bridge, assetIds) {
|
|
|
2398
2657
|
}
|
|
2399
2658
|
return hits;
|
|
2400
2659
|
}
|
|
2660
|
+
function useCompanyEmail() {
|
|
2661
|
+
const bridge = useBridge();
|
|
2662
|
+
const send = useCallback(
|
|
2663
|
+
async (params) => {
|
|
2664
|
+
const res = await bridge.request("entity_invoke", {
|
|
2665
|
+
entityId: COMPANY_EMAIL_SEND_ENTITY_ID,
|
|
2666
|
+
payload: params
|
|
2667
|
+
});
|
|
2668
|
+
return res.output;
|
|
2669
|
+
},
|
|
2670
|
+
[bridge]
|
|
2671
|
+
);
|
|
2672
|
+
return useMemo2(() => ({ send }), [send]);
|
|
2673
|
+
}
|
|
2401
2674
|
function useCommunityAssets() {
|
|
2402
2675
|
const bridge = useBridge();
|
|
2403
2676
|
const publish = useCallback(
|
|
@@ -2670,6 +2943,7 @@ var VALID_PLUGIN_PERMISSIONS = [
|
|
|
2670
2943
|
"data:store",
|
|
2671
2944
|
"data:workspace",
|
|
2672
2945
|
"docsign:envelopes:read",
|
|
2946
|
+
"email:company:send",
|
|
2673
2947
|
"entities:audio_generate",
|
|
2674
2948
|
"entities:client_invoke",
|
|
2675
2949
|
"entities:image_edit",
|
|
@@ -2687,7 +2961,8 @@ var VALID_PLUGIN_PERMISSIONS = [
|
|
|
2687
2961
|
"vault:documents:write",
|
|
2688
2962
|
"vault:user-documents:edit",
|
|
2689
2963
|
"vault:user-documents:read",
|
|
2690
|
-
"vault:user-documents:write"
|
|
2964
|
+
"vault:user-documents:write",
|
|
2965
|
+
"vault:workspace-documents:read"
|
|
2691
2966
|
];
|
|
2692
2967
|
function isValidPluginPermission(perm) {
|
|
2693
2968
|
return VALID_PLUGIN_PERMISSIONS.includes(perm);
|
|
@@ -2701,6 +2976,7 @@ var PLUGIN_PERMISSION_DESCRIPTIONS = {
|
|
|
2701
2976
|
"data:store": "Save structured data in this arche's own private database.",
|
|
2702
2977
|
"data:workspace": "Create team workspaces and manage their members.",
|
|
2703
2978
|
"docsign:envelopes:read": "Check on signature requests it started for you \u2014 who has signed, and what is still outstanding.",
|
|
2979
|
+
"email:company:send": "Send email as your Company from its own address (e.g. team@yourcompany.com) \u2014 only after a Company admin allows this app to, and only to the people they choose. Each email is charged to the person using the app.",
|
|
2704
2980
|
"entities:audio_generate": "Generate audio with platform AI \u2014 costs credits.",
|
|
2705
2981
|
"entities:client_invoke": "Use free on-device tools (grammar check, translation) in your browser.",
|
|
2706
2982
|
"entities:image_edit": "Edit images with platform AI \u2014 costs credits.",
|
|
@@ -2718,7 +2994,8 @@ var PLUGIN_PERMISSION_DESCRIPTIONS = {
|
|
|
2718
2994
|
"vault:documents:write": "Create and manage its own files, in its own folder of your Vault.",
|
|
2719
2995
|
"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
2996
|
"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."
|
|
2997
|
+
"vault:user-documents:write": "Save its work to your Documents \u2014 you choose the folder and the name each time.",
|
|
2998
|
+
"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
2999
|
};
|
|
2723
3000
|
|
|
2724
3001
|
// src/fias.ts
|
|
@@ -5059,7 +5336,13 @@ function validateAnimation(value, path, issues) {
|
|
|
5059
5336
|
}
|
|
5060
5337
|
rejectUnknownKeys(value, ["type", "durationMs", "easing"], path, issues);
|
|
5061
5338
|
checkOptionalEnum(value.type, `${path}.type`, issues, ANIMATION_TYPES);
|
|
5062
|
-
checkOptionalIntRange(
|
|
5339
|
+
checkOptionalIntRange(
|
|
5340
|
+
value.durationMs,
|
|
5341
|
+
`${path}.durationMs`,
|
|
5342
|
+
issues,
|
|
5343
|
+
0,
|
|
5344
|
+
ANIMATION_MAX_DURATION_MS
|
|
5345
|
+
);
|
|
5063
5346
|
checkOptionalEnum(value.easing, `${path}.easing`, issues, ANIMATION_EASINGS);
|
|
5064
5347
|
}
|
|
5065
5348
|
var THEME_COLOR_FIELDS = ["bg", "fg", "border", "accent", "accentFg", "scrim"];
|
|
@@ -5201,6 +5484,8 @@ export {
|
|
|
5201
5484
|
AUDIO_VOICE_CHANGER_SURFACE_KEY,
|
|
5202
5485
|
AUDIO_VOICE_DESIGN_SURFACE_KEY,
|
|
5203
5486
|
DARK_THEME,
|
|
5487
|
+
ENTITY_INVOCATION_HISTORY_LIMITS,
|
|
5488
|
+
ENTITY_INVOCATION_REQUEST_LIMITS,
|
|
5204
5489
|
FONT_CATALOG,
|
|
5205
5490
|
FONT_PAIRINGS,
|
|
5206
5491
|
FiasBridge,
|
|
@@ -5240,17 +5525,23 @@ export {
|
|
|
5240
5525
|
PANEL_TITLE_MAX_LENGTH,
|
|
5241
5526
|
PLUGIN_CONTENT_ENTITY_ID,
|
|
5242
5527
|
PLUGIN_PERMISSION_DESCRIPTIONS,
|
|
5528
|
+
REASONING_EFFORTS,
|
|
5243
5529
|
SDK_BRIDGE_PROTOCOL_VERSION,
|
|
5244
5530
|
SDK_REQUIRES_HOST_PROTOCOL_VERSION,
|
|
5245
5531
|
THEME_CATALOG,
|
|
5246
5532
|
VALID_PLUGIN_PERMISSIONS,
|
|
5533
|
+
checkInvocationHistory,
|
|
5534
|
+
checkInvocationRequestSize,
|
|
5535
|
+
checkReasoningParameter,
|
|
5247
5536
|
ensureFontLoaded,
|
|
5248
5537
|
fetchVaultDocumentDownloadUrl,
|
|
5249
5538
|
fias,
|
|
5539
|
+
fitHistoryToLimits,
|
|
5250
5540
|
getBridge,
|
|
5251
5541
|
getDefaultTheme,
|
|
5252
5542
|
getFontPairingById,
|
|
5253
5543
|
getThemeById,
|
|
5544
|
+
invocationPayloadByteLimit,
|
|
5254
5545
|
isValidPluginPermission,
|
|
5255
5546
|
resetBridge,
|
|
5256
5547
|
useArcheAssets,
|
|
@@ -5258,6 +5549,7 @@ export {
|
|
|
5258
5549
|
useAudioGeneration,
|
|
5259
5550
|
useClientEntity,
|
|
5260
5551
|
useCommunityAssets,
|
|
5552
|
+
useCompanyEmail,
|
|
5261
5553
|
useDataSubscription,
|
|
5262
5554
|
useDocumentSign,
|
|
5263
5555
|
useElevenLabsAudioIsolation,
|
|
@@ -5299,6 +5591,7 @@ export {
|
|
|
5299
5591
|
useSmartVectorize,
|
|
5300
5592
|
useStepNavigation,
|
|
5301
5593
|
useSurface,
|
|
5594
|
+
useTextModels,
|
|
5302
5595
|
useVaultDocuments,
|
|
5303
5596
|
useVaultUserDocuments,
|
|
5304
5597
|
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"}
|