@ai-matrx/agents 0.18.1 → 0.19.1
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/CHANGELOG.md +73 -0
- package/dist/content-transfer/index.cjs.map +1 -1
- package/dist/content-transfer/index.js.map +1 -1
- package/dist/content-transfer/react/index.cjs.map +1 -1
- package/dist/content-transfer/react/index.js.map +1 -1
- package/dist/mandates/index.cjs +2 -2
- package/dist/mandates/index.cjs.map +1 -1
- package/dist/mandates/index.d.cts +4 -4
- package/dist/mandates/index.d.ts +4 -4
- package/dist/mandates/index.js +2 -2
- package/dist/mandates/index.js.map +1 -1
- package/dist/sources/react/index.cjs +130 -18
- package/dist/sources/react/index.cjs.map +1 -1
- package/dist/sources/react/index.d.cts +46 -5
- package/dist/sources/react/index.d.ts +46 -5
- package/dist/sources/react/index.js +130 -18
- package/dist/sources/react/index.js.map +1 -1
- package/dist/sources/runtime/index.cjs +337 -201
- package/dist/sources/runtime/index.cjs.map +1 -1
- package/dist/sources/runtime/index.d.cts +109 -10
- package/dist/sources/runtime/index.d.ts +109 -10
- package/dist/sources/runtime/index.js +337 -201
- package/dist/sources/runtime/index.js.map +1 -1
- package/mandates/snapshots/keys.0.18.3.json +652 -0
- package/mandates/snapshots/keys.0.18.4.json +652 -0
- package/mandates/snapshots/keys.0.18.5.json +652 -0
- package/mandates/snapshots/keys.0.19.1.json +652 -0
- package/package.json +3 -3
|
@@ -8,12 +8,12 @@ function deliveryPatch(delivery) {
|
|
|
8
8
|
var DELIVERY_WORDS = {
|
|
9
9
|
direct: {
|
|
10
10
|
label: "Include the text",
|
|
11
|
-
hint: "
|
|
11
|
+
hint: "Sent in full",
|
|
12
12
|
summary: "Text included"
|
|
13
13
|
},
|
|
14
14
|
context: {
|
|
15
15
|
label: "Let the AI look it up",
|
|
16
|
-
hint: "
|
|
16
|
+
hint: "Read as needed",
|
|
17
17
|
summary: "Looked up when needed"
|
|
18
18
|
}
|
|
19
19
|
};
|
|
@@ -90,7 +90,7 @@ function resumableInput(draft) {
|
|
|
90
90
|
case "youtube":
|
|
91
91
|
return input.url?.trim() ? input : null;
|
|
92
92
|
case "audio":
|
|
93
|
-
return input.fileId ? input : null;
|
|
93
|
+
return input.fileId || input.text?.trim() ? input : null;
|
|
94
94
|
default:
|
|
95
95
|
return null;
|
|
96
96
|
}
|
|
@@ -106,12 +106,12 @@ function reloadedCard(draft, status) {
|
|
|
106
106
|
return { action: "lost", sentence: RELOADED_WHILE_ADDING };
|
|
107
107
|
}
|
|
108
108
|
var MAX_KEPT_TEXT_KNOB = { feature: "sources", key: "max_kept_draft_chars" };
|
|
109
|
-
var NOT_KEPT_FOR_RELOAD = "Too large to
|
|
109
|
+
var NOT_KEPT_FOR_RELOAD = "Too large to restore if the page reloads before it is added.";
|
|
110
110
|
var WAITING_FOR_ORGANIZATION = "Waiting for an organization \u2014 choose one and this continues by itself.";
|
|
111
111
|
var KEEP_WAITING_FOR_ORGANIZATION = "Read. Waiting for an organization to keep it \u2014 choose one and it is kept by itself.";
|
|
112
112
|
|
|
113
113
|
// sources/runtime/fileSource.ts
|
|
114
|
-
var UNREADABLE = "
|
|
114
|
+
var UNREADABLE = "Can't read this file \u2014 add a PDF, Word or text copy.";
|
|
115
115
|
function nextFileStep(status, ctx) {
|
|
116
116
|
const pdId = status?.processed_document_id ?? null;
|
|
117
117
|
if (pdId) return { do: "keep", processedDocumentId: pdId };
|
|
@@ -119,7 +119,7 @@ function nextFileStep(status, ctx) {
|
|
|
119
119
|
if (status?.state === "failed")
|
|
120
120
|
return {
|
|
121
121
|
do: "unreadable",
|
|
122
|
-
reason: status.error?.message ? `
|
|
122
|
+
reason: status.error?.message ? `Can't read this file: ${status.error.message}. Add it again.` : UNREADABLE
|
|
123
123
|
};
|
|
124
124
|
if (!ctx.started) return { do: "start" };
|
|
125
125
|
return { do: "unreadable", reason: UNREADABLE };
|
|
@@ -235,191 +235,10 @@ function totalChars(value) {
|
|
|
235
235
|
return value.sources.filter((entry) => entry.state === "ready" || entry.state === "processing").reduce((sum, entry) => sum + manifestEntryChars(entry), 0);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
// sources/runtime/plan.ts
|
|
239
|
-
var HEAVY_SHARE = 0.7;
|
|
240
|
-
var PAGE_SUFFIX = (page) => page !== void 0 && page > 0 ? ` (page ${page})` : "";
|
|
241
|
-
function renderedPartChars(segment, chars) {
|
|
242
|
-
return `### Chunk ${segment.id}${PAGE_SUFFIX(segment.page)}`.length + 1 + chars;
|
|
243
|
-
}
|
|
244
|
-
function capParts(parts, maxChars) {
|
|
245
|
-
if (!maxChars) return { kept: parts.map((seg) => ({ seg, chars: seg.chars })), capped: false };
|
|
246
|
-
const kept = [];
|
|
247
|
-
let used = 0;
|
|
248
|
-
for (const seg of parts) {
|
|
249
|
-
if (used + seg.chars <= maxChars) {
|
|
250
|
-
kept.push({ seg, chars: seg.chars });
|
|
251
|
-
used += seg.chars;
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
const room = maxChars - used;
|
|
255
|
-
if (room > 0 && kept.length === 0) kept.push({ seg, chars: room });
|
|
256
|
-
return { kept, capped: true };
|
|
257
|
-
}
|
|
258
|
-
return { kept, capped: false };
|
|
259
|
-
}
|
|
260
|
-
function chosenForm(entry, ref) {
|
|
261
|
-
const key = ref.representation ?? entry.default_form;
|
|
262
|
-
return entry.forms.find((f) => f.form === key) ?? entry.forms.find((f) => f.form === entry.default_form) ?? null;
|
|
263
|
-
}
|
|
264
|
-
function isUsable(entry) {
|
|
265
|
-
return entry.state === "ready" || entry.state === "processing";
|
|
266
|
-
}
|
|
267
|
-
function measure(entry, ref) {
|
|
268
|
-
const form = chosenForm(entry, ref);
|
|
269
|
-
const formChars = form?.chars ?? 0;
|
|
270
|
-
const formLabel = form?.label ?? "Text";
|
|
271
|
-
const segments = entry.segments ?? null;
|
|
272
|
-
if (segments && segments.length > 0) {
|
|
273
|
-
const wanted = ref.include_segments?.length ? new Set(ref.include_segments) : null;
|
|
274
|
-
const chosen = wanted ? segments.filter((s) => wanted.has(s.id)) : segments;
|
|
275
|
-
const { kept, capped: capped2 } = capParts(chosen, ref.max_chars);
|
|
276
|
-
const body = kept.reduce((sum, k) => sum + renderedPartChars(k.seg, k.chars), 0);
|
|
277
|
-
const sentChars = kept.length ? body + 2 * (kept.length - 1) : 0;
|
|
278
|
-
return {
|
|
279
|
-
formChars,
|
|
280
|
-
formLabel,
|
|
281
|
-
sentChars,
|
|
282
|
-
exact: true,
|
|
283
|
-
partsSent: kept.length,
|
|
284
|
-
partsTotal: segments.length,
|
|
285
|
-
capped: capped2
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
const capped = ref.max_chars !== void 0 && formChars > ref.max_chars;
|
|
289
|
-
return {
|
|
290
|
-
formChars,
|
|
291
|
-
formLabel,
|
|
292
|
-
sentChars: capped ? ref.max_chars ?? formChars : formChars,
|
|
293
|
-
exact: false,
|
|
294
|
-
partsSent: null,
|
|
295
|
-
partsTotal: null,
|
|
296
|
-
capped
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
function planSourceReview(input) {
|
|
300
|
-
const estimateTokens = input.estimateTokens ?? estimateSourceTokens;
|
|
301
|
-
const windowIsFallback = !input.modelWindowTokens || input.modelWindowTokens <= 0;
|
|
302
|
-
const windowTokens = windowIsFallback ? input.fallbackWindowTokens : input.modelWindowTokens;
|
|
303
|
-
let sentChars = 0;
|
|
304
|
-
const entries = input.manifest.sources.map((entry, index) => {
|
|
305
|
-
const ref = input.refs[index] ?? entry.ref;
|
|
306
|
-
const m = measure(entry, ref);
|
|
307
|
-
const base = { index, ref, entry, ...m };
|
|
308
|
-
if (!isUsable(entry)) {
|
|
309
|
-
return { ...base, status: "unusable", sentChars: 0, sentTokens: 0 };
|
|
310
|
-
}
|
|
311
|
-
if (sourceDelivery(ref) === "context") {
|
|
312
|
-
return { ...base, status: "on_demand", sentChars: 0, sentTokens: 0 };
|
|
313
|
-
}
|
|
314
|
-
if (estimateTokens(sentChars + m.sentChars) > windowTokens) {
|
|
315
|
-
return { ...base, status: "left_out", sentTokens: estimateTokens(m.sentChars) };
|
|
316
|
-
}
|
|
317
|
-
sentChars += m.sentChars;
|
|
318
|
-
return { ...base, status: "included", sentTokens: estimateTokens(m.sentChars) };
|
|
319
|
-
});
|
|
320
|
-
const sentTokens = estimateTokens(sentChars);
|
|
321
|
-
const leftOut = entries.filter((e) => e.status === "left_out");
|
|
322
|
-
const share = windowTokens > 0 ? sentTokens / windowTokens : 0;
|
|
323
|
-
const anythingGoesIn = entries.some((e) => e.status === "included" || e.status === "on_demand");
|
|
324
|
-
const verdict = !anythingGoesIn && leftOut.length === 0 ? "empty" : leftOut.length > 0 ? "too_much" : share >= HEAVY_SHARE ? "heavy" : "fine";
|
|
325
|
-
const kept = entries.filter((e) => e.status !== "left_out").map(
|
|
326
|
-
(e) => createSourceRef(e.ref.resource_type, e.ref.resource_id, {
|
|
327
|
-
representation: e.ref.representation,
|
|
328
|
-
include_segments: e.ref.include_segments,
|
|
329
|
-
delivery: e.ref.delivery,
|
|
330
|
-
max_chars: e.ref.max_chars,
|
|
331
|
-
promote: e.ref.promote,
|
|
332
|
-
exclude: e.ref.exclude
|
|
333
|
-
})
|
|
334
|
-
);
|
|
335
|
-
const grounding = input.base.grounding === "selected" && !kept.some((r) => r.include_segments?.length) ? void 0 : input.base.grounding;
|
|
336
|
-
const sourceSet = createSourceSet(kept, {
|
|
337
|
-
topic: input.base.topic,
|
|
338
|
-
grounding,
|
|
339
|
-
retrieve_query: input.base.retrieve_query,
|
|
340
|
-
target_model_id: input.targetModelId ?? input.base.target_model_id
|
|
341
|
-
});
|
|
342
|
-
return {
|
|
343
|
-
entries,
|
|
344
|
-
sentChars,
|
|
345
|
-
sentTokens,
|
|
346
|
-
windowTokens,
|
|
347
|
-
windowIsFallback,
|
|
348
|
-
verdict,
|
|
349
|
-
share,
|
|
350
|
-
leftOut,
|
|
351
|
-
sourceSet
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// sources/runtime/client.ts
|
|
356
|
-
function marked(options) {
|
|
357
|
-
return {
|
|
358
|
-
bodyCarriedRead: true,
|
|
359
|
-
...options?.organizationId ? { organizationId: options.organizationId } : {},
|
|
360
|
-
...options?.signal ? { signal: options.signal } : {}
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
function createSourcesClient(transport) {
|
|
364
|
-
return {
|
|
365
|
-
manifest: (sourceSet, options) => transport.post("/sources/manifest", { source_set: sourceSet }, marked(options)),
|
|
366
|
-
resolve: (sourceSet, options) => transport.post("/sources/resolve", { source_set: sourceSet }, marked(options)),
|
|
367
|
-
searchParts: (ref, query, options) => transport.post("/sources/parts/search", { source_ref: ref, query }, marked(options))
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
var SourceDoorError = class extends Error {
|
|
371
|
-
status;
|
|
372
|
-
body;
|
|
373
|
-
constructor(status, message, body) {
|
|
374
|
-
super(message);
|
|
375
|
-
this.name = "SourceDoorError";
|
|
376
|
-
this.status = status;
|
|
377
|
-
this.body = body;
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
function refusalMessage(status, body) {
|
|
381
|
-
if (body && typeof body === "object") {
|
|
382
|
-
const record = body;
|
|
383
|
-
const error = record.error;
|
|
384
|
-
if (error && typeof error === "object") {
|
|
385
|
-
const message = error.user_message ?? error.message;
|
|
386
|
-
if (typeof message === "string" && message) return message;
|
|
387
|
-
}
|
|
388
|
-
if (typeof record.detail === "string" && record.detail) return record.detail;
|
|
389
|
-
}
|
|
390
|
-
return `The server answered ${status}.`;
|
|
391
|
-
}
|
|
392
|
-
function createFetchSourcesTransport(options) {
|
|
393
|
-
const base = options.baseUrl.replace(/\/+$/, "");
|
|
394
|
-
return {
|
|
395
|
-
async post(path, body, call) {
|
|
396
|
-
const doFetch = options.fetch ?? fetch;
|
|
397
|
-
const headers = {
|
|
398
|
-
"Content-Type": "application/json",
|
|
399
|
-
...options.headers ? await options.headers() : {}
|
|
400
|
-
};
|
|
401
|
-
if (call.organizationId) headers[options.organizationHeader ?? "X-Organization-Id"] = call.organizationId;
|
|
402
|
-
const response = await doFetch(`${base}${path}`, {
|
|
403
|
-
method: "POST",
|
|
404
|
-
headers,
|
|
405
|
-
body: JSON.stringify(body),
|
|
406
|
-
...call.signal ? { signal: call.signal } : {}
|
|
407
|
-
});
|
|
408
|
-
const text = await response.text();
|
|
409
|
-
let parsed = null;
|
|
410
|
-
try {
|
|
411
|
-
parsed = text ? JSON.parse(text) : null;
|
|
412
|
-
} catch {
|
|
413
|
-
parsed = text;
|
|
414
|
-
}
|
|
415
|
-
if (!response.ok) throw new SourceDoorError(response.status, refusalMessage(response.status, parsed), parsed);
|
|
416
|
-
return parsed;
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
|
|
421
238
|
// sources/runtime/state.ts
|
|
422
239
|
var EMPTY_SOURCE_SET_STATE = Object.freeze({ cards: Object.freeze([]), topic: "" });
|
|
240
|
+
var PARTS_MATCHED_BY_PAGE = "The clean version is ready \u2014 your parts were matched to it by page.";
|
|
241
|
+
var PARTS_NOT_MATCHED = "The clean version is ready, but your parts could not be matched to it \u2014 choose parts again. Until then the whole Source goes in.";
|
|
423
242
|
var SAME_SOURCE_AGAIN = "You added this again \u2014 it is the same Source, so it is listed once.";
|
|
424
243
|
function isSourceDraft(value) {
|
|
425
244
|
return !!value && typeof value === "object" && typeof value.kind === "string" && typeof value.label === "string";
|
|
@@ -486,7 +305,7 @@ function settleCard(state, id, patch, options = {}) {
|
|
|
486
305
|
}));
|
|
487
306
|
}
|
|
488
307
|
function failCard(state, id, sentence) {
|
|
489
|
-
return replaceCard(state, id, (c) => ({ ...c, status: "error", error: sentence }));
|
|
308
|
+
return replaceCard(state, id, (c) => ({ ...c, status: "error", error: sentence, manifest: null }));
|
|
490
309
|
}
|
|
491
310
|
function restartCard(state, id) {
|
|
492
311
|
return replaceCard(state, id, (c) => ({ ...c, status: "resolving", error: null }));
|
|
@@ -502,7 +321,68 @@ function updateCardRef(state, id, options) {
|
|
|
502
321
|
return replaceCard(state, id, (c) => {
|
|
503
322
|
if (!c.draft.ref) return c;
|
|
504
323
|
const ref = createSourceRef(c.draft.ref.resource_type, c.draft.ref.resource_id, { ...c.draft.ref, ...options });
|
|
505
|
-
return { ...c, draft: { ...c.draft, ref } };
|
|
324
|
+
return rememberPickedParts({ ...c, draft: { ...c.draft, ref } });
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
function rememberPickedParts(card) {
|
|
328
|
+
const ids = card.draft.ref?.include_segments ?? [];
|
|
329
|
+
if (ids.length === 0) {
|
|
330
|
+
return card.draft.pickedParts === void 0 ? card : { ...card, draft: { ...card.draft, pickedParts: void 0 } };
|
|
331
|
+
}
|
|
332
|
+
const segments = card.manifest?.segments ?? [];
|
|
333
|
+
const known = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));
|
|
334
|
+
const picked = [];
|
|
335
|
+
for (const id of ids) {
|
|
336
|
+
const segment = segments.find((s) => s.id === id);
|
|
337
|
+
if (segment) {
|
|
338
|
+
const pages = partPages(segment);
|
|
339
|
+
picked.push({ id, label: segment.label, ...pages ? { pages } : {} });
|
|
340
|
+
} else {
|
|
341
|
+
const before = known.get(id);
|
|
342
|
+
if (before) picked.push(before);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return { ...card, draft: { ...card.draft, pickedParts: picked.length ? picked : void 0 } };
|
|
346
|
+
}
|
|
347
|
+
function withNote(notes, note, drop = []) {
|
|
348
|
+
const kept = (notes ?? []).filter((n) => n !== note && !drop.includes(n));
|
|
349
|
+
return [...kept, note];
|
|
350
|
+
}
|
|
351
|
+
function carryPickedParts(card, entry) {
|
|
352
|
+
const ref = card.draft.ref;
|
|
353
|
+
const picked = ref?.include_segments ?? [];
|
|
354
|
+
const segments = entry.segments ?? [];
|
|
355
|
+
if (!ref || picked.length === 0 || segments.length === 0) return card;
|
|
356
|
+
const ids = new Set(segments.map((s) => s.id));
|
|
357
|
+
const stale = picked.filter((id) => !ids.has(id));
|
|
358
|
+
if (stale.length === 0) return card;
|
|
359
|
+
const remembered = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));
|
|
360
|
+
const oldSegments = card.manifest?.segments ?? [];
|
|
361
|
+
const spans = [];
|
|
362
|
+
let unknown = 0;
|
|
363
|
+
for (const id of stale) {
|
|
364
|
+
const old = oldSegments.find((s) => s.id === id);
|
|
365
|
+
const pages = remembered.get(id)?.pages ?? (old ? partPages(old) : null);
|
|
366
|
+
if (pages) spans.push(pages);
|
|
367
|
+
else unknown += 1;
|
|
368
|
+
}
|
|
369
|
+
const keep = new Set(picked.filter((id) => ids.has(id)));
|
|
370
|
+
for (const segment of segments) {
|
|
371
|
+
const pages = partPages(segment);
|
|
372
|
+
if (pages && spans.some(([from, to]) => pages[0] <= to && pages[1] >= from)) keep.add(segment.id);
|
|
373
|
+
}
|
|
374
|
+
const nextIds = segments.filter((s) => keep.has(s.id)).map((s) => s.id);
|
|
375
|
+
const matched = unknown === 0 && nextIds.length > 0;
|
|
376
|
+
const nextRef = createSourceRef(ref.resource_type, ref.resource_id, {
|
|
377
|
+
...ref,
|
|
378
|
+
include_segments: matched ? nextIds : void 0
|
|
379
|
+
});
|
|
380
|
+
const note = matched ? PARTS_MATCHED_BY_PAGE : PARTS_NOT_MATCHED;
|
|
381
|
+
const other = matched ? PARTS_NOT_MATCHED : PARTS_MATCHED_BY_PAGE;
|
|
382
|
+
return rememberPickedParts({
|
|
383
|
+
...card,
|
|
384
|
+
manifest: entry,
|
|
385
|
+
draft: { ...card.draft, ref: nextRef, notes: withNote(card.draft.notes, note, [other]) }
|
|
506
386
|
});
|
|
507
387
|
}
|
|
508
388
|
function setCardWaitForClean(state, id, wait) {
|
|
@@ -511,14 +391,24 @@ function setCardWaitForClean(state, id, wait) {
|
|
|
511
391
|
function setSourceTopic(state, topic) {
|
|
512
392
|
return state.topic === topic ? state : { ...state, topic };
|
|
513
393
|
}
|
|
514
|
-
function
|
|
394
|
+
function removedInReview(reviewed, answer) {
|
|
395
|
+
const kept = new Set(answer.sources.map(sourceKey));
|
|
396
|
+
return new Set(reviewed.sources.map(sourceKey).filter((k) => !kept.has(k)));
|
|
397
|
+
}
|
|
398
|
+
function applyReviewedSourceSet(state, set, reviewed) {
|
|
515
399
|
let next = state;
|
|
516
|
-
|
|
400
|
+
if (reviewed) {
|
|
401
|
+
const removed = removedInReview(reviewed, set);
|
|
402
|
+
for (const card of state.cards) {
|
|
403
|
+
if (card.draft.ref && removed.has(sourceKey(card.draft.ref))) next = removeCard(next, card.id);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
for (const card of next.cards) {
|
|
517
407
|
const ref = card.draft.ref;
|
|
518
408
|
if (!ref) continue;
|
|
519
409
|
const match = set.sources.find((r) => sameSourceRef(r, ref));
|
|
520
410
|
if (!match) continue;
|
|
521
|
-
next = replaceCard(next, card.id, (c) => ({ ...c, draft: { ...c.draft, ref: match } }));
|
|
411
|
+
next = replaceCard(next, card.id, (c) => rememberPickedParts({ ...c, draft: { ...c.draft, ref: match } }));
|
|
522
412
|
}
|
|
523
413
|
return set.topic !== void 0 ? setSourceTopic(next, set.topic) : next;
|
|
524
414
|
}
|
|
@@ -528,7 +418,13 @@ function applyManifest(state, manifest) {
|
|
|
528
418
|
const ref = card.draft.ref;
|
|
529
419
|
if (!ref || card.status !== "ready") continue;
|
|
530
420
|
const entry = manifest.sources.find((e) => sameSourceRef(e.ref, ref));
|
|
531
|
-
if (entry)
|
|
421
|
+
if (!entry) continue;
|
|
422
|
+
next = replaceCard(next, card.id, (c) => {
|
|
423
|
+
const carried = carryPickedParts(c, entry);
|
|
424
|
+
if (carried !== c) return carried;
|
|
425
|
+
const measured = { ...c, manifest: entry };
|
|
426
|
+
return c.draft.ref?.include_segments?.length && !c.draft.pickedParts ? rememberPickedParts(measured) : measured;
|
|
427
|
+
});
|
|
532
428
|
}
|
|
533
429
|
return next;
|
|
534
430
|
}
|
|
@@ -601,6 +497,27 @@ function selectTotalChars(state) {
|
|
|
601
497
|
model_context_tokens: null
|
|
602
498
|
});
|
|
603
499
|
}
|
|
500
|
+
function sourceEntryChars(entry, ref) {
|
|
501
|
+
if (entry.state !== "ready" && entry.state !== "processing") return null;
|
|
502
|
+
return totalChars({
|
|
503
|
+
__kind: "source_manifest",
|
|
504
|
+
sources: [{ ...entry, ref }],
|
|
505
|
+
total_chars: 0,
|
|
506
|
+
estimated_tokens: 0,
|
|
507
|
+
model_context_tokens: null
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
function sourceCardChars(card) {
|
|
511
|
+
return card.manifest && card.draft.ref ? sourceEntryChars(card.manifest, card.draft.ref) : null;
|
|
512
|
+
}
|
|
513
|
+
function sourceCardState(card) {
|
|
514
|
+
if (card.status === "pending" || card.status === "resolving") return "adding";
|
|
515
|
+
if (card.status === "error") return card.error === WAITING_FOR_ORGANIZATION ? "waiting_for_organization" : "failed";
|
|
516
|
+
return card.manifest?.state ?? "unmeasured";
|
|
517
|
+
}
|
|
518
|
+
function sourceCardMeasuredState(card) {
|
|
519
|
+
return card.status === "ready" ? card.manifest?.state ?? null : null;
|
|
520
|
+
}
|
|
604
521
|
function selectSettled(state) {
|
|
605
522
|
return state.cards.every((c) => c.status === "ready");
|
|
606
523
|
}
|
|
@@ -622,6 +539,190 @@ function withDisplayNames(resolved, cards) {
|
|
|
622
539
|
};
|
|
623
540
|
}
|
|
624
541
|
|
|
542
|
+
// sources/runtime/plan.ts
|
|
543
|
+
var HEAVY_SHARE = 0.7;
|
|
544
|
+
var PAGE_SUFFIX = (page) => page !== void 0 && page > 0 ? ` (page ${page})` : "";
|
|
545
|
+
function renderedPartChars(segment, chars) {
|
|
546
|
+
return `### Chunk ${segment.id}${PAGE_SUFFIX(segment.page)}`.length + 1 + chars;
|
|
547
|
+
}
|
|
548
|
+
function capParts(parts, maxChars) {
|
|
549
|
+
if (!maxChars) return { kept: parts.map((seg) => ({ seg, chars: seg.chars })), capped: false };
|
|
550
|
+
const kept = [];
|
|
551
|
+
let used = 0;
|
|
552
|
+
for (const seg of parts) {
|
|
553
|
+
if (used + seg.chars <= maxChars) {
|
|
554
|
+
kept.push({ seg, chars: seg.chars });
|
|
555
|
+
used += seg.chars;
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
const room = maxChars - used;
|
|
559
|
+
if (room > 0 && kept.length === 0) kept.push({ seg, chars: room });
|
|
560
|
+
return { kept, capped: true };
|
|
561
|
+
}
|
|
562
|
+
return { kept, capped: false };
|
|
563
|
+
}
|
|
564
|
+
function chosenForm(entry, ref) {
|
|
565
|
+
const key = ref.representation ?? entry.default_form;
|
|
566
|
+
return entry.forms.find((f) => f.form === key) ?? entry.forms.find((f) => f.form === entry.default_form) ?? null;
|
|
567
|
+
}
|
|
568
|
+
function isUsable(entry) {
|
|
569
|
+
return entry.state === "ready" || entry.state === "processing";
|
|
570
|
+
}
|
|
571
|
+
function measure(entry, ref) {
|
|
572
|
+
const form = chosenForm(entry, ref);
|
|
573
|
+
const formChars = form?.chars ?? 0;
|
|
574
|
+
const formLabel = form?.label ?? "Text";
|
|
575
|
+
const segments = entry.segments ?? null;
|
|
576
|
+
if (segments && segments.length > 0) {
|
|
577
|
+
const wanted = ref.include_segments?.length ? new Set(ref.include_segments) : null;
|
|
578
|
+
const chosen = wanted ? segments.filter((s) => wanted.has(s.id)) : segments;
|
|
579
|
+
const { kept, capped: capped2 } = capParts(chosen, ref.max_chars);
|
|
580
|
+
const body = kept.reduce((sum, k) => sum + renderedPartChars(k.seg, k.chars), 0);
|
|
581
|
+
const sentChars = kept.length ? body + 2 * (kept.length - 1) : 0;
|
|
582
|
+
return {
|
|
583
|
+
formChars,
|
|
584
|
+
formLabel,
|
|
585
|
+
sentChars,
|
|
586
|
+
exact: true,
|
|
587
|
+
partsSent: kept.length,
|
|
588
|
+
partsTotal: segments.length,
|
|
589
|
+
capped: capped2
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
const capped = ref.max_chars !== void 0 && formChars > ref.max_chars;
|
|
593
|
+
return {
|
|
594
|
+
formChars,
|
|
595
|
+
formLabel,
|
|
596
|
+
sentChars: capped ? ref.max_chars ?? formChars : formChars,
|
|
597
|
+
exact: false,
|
|
598
|
+
partsSent: null,
|
|
599
|
+
partsTotal: null,
|
|
600
|
+
capped
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function planSourceReview(input) {
|
|
604
|
+
const estimateTokens = input.estimateTokens ?? estimateSourceTokens;
|
|
605
|
+
const windowIsFallback = !input.modelWindowTokens || input.modelWindowTokens <= 0;
|
|
606
|
+
const windowTokens = windowIsFallback ? input.fallbackWindowTokens : input.modelWindowTokens;
|
|
607
|
+
let sentChars = 0;
|
|
608
|
+
const entries = input.manifest.sources.map((entry, index) => {
|
|
609
|
+
const ref = input.refs[index] ?? entry.ref;
|
|
610
|
+
const m = measure(entry, ref);
|
|
611
|
+
const base = { index, ref, entry, ...m, chars: sourceEntryChars(entry, ref) ?? 0 };
|
|
612
|
+
if (!isUsable(entry)) {
|
|
613
|
+
return { ...base, status: "unusable", sentChars: 0, sentTokens: 0 };
|
|
614
|
+
}
|
|
615
|
+
if (sourceDelivery(ref) === "context") {
|
|
616
|
+
return { ...base, status: "on_demand", sentChars: 0, sentTokens: 0 };
|
|
617
|
+
}
|
|
618
|
+
if (estimateTokens(sentChars + m.sentChars) > windowTokens) {
|
|
619
|
+
return { ...base, status: "left_out", sentTokens: estimateTokens(m.sentChars) };
|
|
620
|
+
}
|
|
621
|
+
sentChars += m.sentChars;
|
|
622
|
+
return { ...base, status: "included", sentTokens: estimateTokens(m.sentChars) };
|
|
623
|
+
});
|
|
624
|
+
const sentTokens = estimateTokens(sentChars);
|
|
625
|
+
const leftOut = entries.filter((e) => e.status === "left_out");
|
|
626
|
+
const share = windowTokens > 0 ? sentTokens / windowTokens : 0;
|
|
627
|
+
const anythingGoesIn = entries.some((e) => e.status === "included" || e.status === "on_demand");
|
|
628
|
+
const verdict = !anythingGoesIn && leftOut.length === 0 ? "empty" : leftOut.length > 0 ? "too_much" : share >= HEAVY_SHARE ? "heavy" : "fine";
|
|
629
|
+
const kept = entries.filter((e) => e.status !== "left_out").map(
|
|
630
|
+
(e) => createSourceRef(e.ref.resource_type, e.ref.resource_id, {
|
|
631
|
+
representation: e.ref.representation,
|
|
632
|
+
include_segments: e.ref.include_segments,
|
|
633
|
+
delivery: e.ref.delivery,
|
|
634
|
+
max_chars: e.ref.max_chars,
|
|
635
|
+
promote: e.ref.promote,
|
|
636
|
+
exclude: e.ref.exclude
|
|
637
|
+
})
|
|
638
|
+
);
|
|
639
|
+
const grounding = input.base.grounding === "selected" && !kept.some((r) => r.include_segments?.length) ? void 0 : input.base.grounding;
|
|
640
|
+
const sourceSet = createSourceSet(kept, {
|
|
641
|
+
topic: input.base.topic,
|
|
642
|
+
grounding,
|
|
643
|
+
retrieve_query: input.base.retrieve_query,
|
|
644
|
+
target_model_id: input.targetModelId ?? input.base.target_model_id
|
|
645
|
+
});
|
|
646
|
+
return {
|
|
647
|
+
entries,
|
|
648
|
+
chars: entries.filter((e) => e.status === "included").reduce((sum, e) => sum + e.chars, 0),
|
|
649
|
+
sentChars,
|
|
650
|
+
sentTokens,
|
|
651
|
+
windowTokens,
|
|
652
|
+
windowIsFallback,
|
|
653
|
+
verdict,
|
|
654
|
+
share,
|
|
655
|
+
leftOut,
|
|
656
|
+
sourceSet
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// sources/runtime/client.ts
|
|
661
|
+
function marked(options) {
|
|
662
|
+
return {
|
|
663
|
+
bodyCarriedRead: true,
|
|
664
|
+
...options?.organizationId ? { organizationId: options.organizationId } : {},
|
|
665
|
+
...options?.signal ? { signal: options.signal } : {}
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
function createSourcesClient(transport) {
|
|
669
|
+
return {
|
|
670
|
+
manifest: (sourceSet, options) => transport.post("/sources/manifest", { source_set: sourceSet }, marked(options)),
|
|
671
|
+
resolve: (sourceSet, options) => transport.post("/sources/resolve", { source_set: sourceSet }, marked(options)),
|
|
672
|
+
searchParts: (ref, query, options) => transport.post("/sources/parts/search", { source_ref: ref, query }, marked(options))
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
var SourceDoorError = class extends Error {
|
|
676
|
+
status;
|
|
677
|
+
body;
|
|
678
|
+
constructor(status, message, body) {
|
|
679
|
+
super(message);
|
|
680
|
+
this.name = "SourceDoorError";
|
|
681
|
+
this.status = status;
|
|
682
|
+
this.body = body;
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
function refusalMessage(status, body) {
|
|
686
|
+
if (body && typeof body === "object") {
|
|
687
|
+
const record = body;
|
|
688
|
+
const error = record.error;
|
|
689
|
+
if (error && typeof error === "object") {
|
|
690
|
+
const message = error.user_message ?? error.message;
|
|
691
|
+
if (typeof message === "string" && message) return message;
|
|
692
|
+
}
|
|
693
|
+
if (typeof record.detail === "string" && record.detail) return record.detail;
|
|
694
|
+
}
|
|
695
|
+
return `The server answered ${status}.`;
|
|
696
|
+
}
|
|
697
|
+
function createFetchSourcesTransport(options) {
|
|
698
|
+
const base = options.baseUrl.replace(/\/+$/, "");
|
|
699
|
+
return {
|
|
700
|
+
async post(path, body, call) {
|
|
701
|
+
const doFetch = options.fetch ?? fetch;
|
|
702
|
+
const headers = {
|
|
703
|
+
"Content-Type": "application/json",
|
|
704
|
+
...options.headers ? await options.headers() : {}
|
|
705
|
+
};
|
|
706
|
+
if (call.organizationId) headers[options.organizationHeader ?? "X-Organization-Id"] = call.organizationId;
|
|
707
|
+
const response = await doFetch(`${base}${path}`, {
|
|
708
|
+
method: "POST",
|
|
709
|
+
headers,
|
|
710
|
+
body: JSON.stringify(body),
|
|
711
|
+
...call.signal ? { signal: call.signal } : {}
|
|
712
|
+
});
|
|
713
|
+
const text = await response.text();
|
|
714
|
+
let parsed = null;
|
|
715
|
+
try {
|
|
716
|
+
parsed = text ? JSON.parse(text) : null;
|
|
717
|
+
} catch {
|
|
718
|
+
parsed = text;
|
|
719
|
+
}
|
|
720
|
+
if (!response.ok) throw new SourceDoorError(response.status, refusalMessage(response.status, parsed), parsed);
|
|
721
|
+
return parsed;
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
625
726
|
// sources/runtime/controller.ts
|
|
626
727
|
function randomId() {
|
|
627
728
|
const cryptoApi = globalThis.crypto;
|
|
@@ -755,8 +856,8 @@ function createSourceSetController(adapter) {
|
|
|
755
856
|
hasRef: (resourceType, resourceId) => hasSourceRef(store.getState(), resourceType, resourceId),
|
|
756
857
|
liveCount: () => store.getState().cards.length,
|
|
757
858
|
toSourceSet: (options = {}) => selectSourceSet(store.getState(), options),
|
|
758
|
-
applySourceSet(set) {
|
|
759
|
-
commit(applyReviewedSourceSet(store.getState(), set));
|
|
859
|
+
applySourceSet(set, options = {}) {
|
|
860
|
+
commit(applyReviewedSourceSet(store.getState(), set, options.reviewed));
|
|
760
861
|
},
|
|
761
862
|
async manifest() {
|
|
762
863
|
const refs = readySourceRefs(store.getState());
|
|
@@ -1041,20 +1142,45 @@ function createSourceIntake(set, deps) {
|
|
|
1041
1142
|
});
|
|
1042
1143
|
await hold(() => landPaste(id, trimmed, name));
|
|
1043
1144
|
},
|
|
1145
|
+
async addRecordedText(text, name) {
|
|
1146
|
+
const trimmed = text.trim();
|
|
1147
|
+
if (!trimmed) return;
|
|
1148
|
+
const max = deps.maxKeptChars();
|
|
1149
|
+
const kept = max !== null && trimmed.length <= max;
|
|
1150
|
+
const id = set.addPending({
|
|
1151
|
+
kind: "audio",
|
|
1152
|
+
label: name?.trim() || "Recording",
|
|
1153
|
+
origin: "Recording",
|
|
1154
|
+
input: kept ? { text: trimmed, name } : void 0,
|
|
1155
|
+
notes: kept ? void 0 : [NOT_KEPT_FOR_RELOAD]
|
|
1156
|
+
});
|
|
1157
|
+
await hold(() => landPaste(id, trimmed, name));
|
|
1158
|
+
},
|
|
1044
1159
|
async addWebPage(raw) {
|
|
1045
1160
|
const url = /^https?:\/\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;
|
|
1046
1161
|
const id = set.addPending({ kind: "web", label: hostOf(url), origin: url, input: { url } });
|
|
1047
1162
|
await hold(() => landWebPage(id, url));
|
|
1048
1163
|
},
|
|
1049
|
-
|
|
1164
|
+
beginWebPage(raw) {
|
|
1165
|
+
const url = /^https?:\/\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;
|
|
1166
|
+
return set.addPending({ kind: "web", label: hostOf(url), origin: url, input: { url } });
|
|
1167
|
+
},
|
|
1168
|
+
async addScrapedPage(page, pendingId) {
|
|
1050
1169
|
const label = page.title || hostOf(page.url);
|
|
1170
|
+
const cardFor = () => {
|
|
1171
|
+
if (pendingId && set.restart(pendingId)) {
|
|
1172
|
+
set.updateDraft(pendingId, { label, origin: page.url, input: { url: page.url } });
|
|
1173
|
+
return pendingId;
|
|
1174
|
+
}
|
|
1175
|
+
return set.addPending({ kind: "web", label, origin: page.url, input: { url: page.url } });
|
|
1176
|
+
};
|
|
1051
1177
|
if (!page.processedDocumentId) {
|
|
1052
|
-
const id2 =
|
|
1178
|
+
const id2 = cardFor();
|
|
1053
1179
|
await hold(() => landPaste(id2, page.text, label));
|
|
1054
1180
|
return;
|
|
1055
1181
|
}
|
|
1056
1182
|
const pdId = page.processedDocumentId;
|
|
1057
|
-
const id =
|
|
1183
|
+
const id = cardFor();
|
|
1058
1184
|
await hold(async () => {
|
|
1059
1185
|
let notes = [];
|
|
1060
1186
|
try {
|
|
@@ -1129,7 +1255,8 @@ function createSourceIntake(set, deps) {
|
|
|
1129
1255
|
return true;
|
|
1130
1256
|
}
|
|
1131
1257
|
case "audio":
|
|
1132
|
-
void transcribeRecording(card.id, input.fileId
|
|
1258
|
+
if (input.fileId) void transcribeRecording(card.id, input.fileId, card.draft.label);
|
|
1259
|
+
else void landPaste(card.id, (input.text ?? "").trim(), input.name);
|
|
1133
1260
|
return true;
|
|
1134
1261
|
default:
|
|
1135
1262
|
return false;
|
|
@@ -1257,6 +1384,8 @@ export {
|
|
|
1257
1384
|
KEEP_WAITING_FOR_ORGANIZATION,
|
|
1258
1385
|
MAX_KEPT_TEXT_KNOB,
|
|
1259
1386
|
NOT_KEPT_FOR_RELOAD,
|
|
1387
|
+
PARTS_MATCHED_BY_PAGE,
|
|
1388
|
+
PARTS_NOT_MATCHED,
|
|
1260
1389
|
RELOADED_RESUMING,
|
|
1261
1390
|
RELOADED_WHILE_ADDING,
|
|
1262
1391
|
SAME_SOURCE_AGAIN,
|
|
@@ -1270,6 +1399,7 @@ export {
|
|
|
1270
1399
|
applyReviewedSourceSet,
|
|
1271
1400
|
cardsToResume,
|
|
1272
1401
|
cardsWaitingForOrganization,
|
|
1402
|
+
carryPickedParts,
|
|
1273
1403
|
chosenForm,
|
|
1274
1404
|
continueAfterOrganization,
|
|
1275
1405
|
createFetchSourcesTransport,
|
|
@@ -1303,7 +1433,9 @@ export {
|
|
|
1303
1433
|
readySourceRefs,
|
|
1304
1434
|
registeredFileEdge,
|
|
1305
1435
|
reloadedCard,
|
|
1436
|
+
rememberPickedParts,
|
|
1306
1437
|
removeCard,
|
|
1438
|
+
removedInReview,
|
|
1307
1439
|
renderedPartChars,
|
|
1308
1440
|
restartCard,
|
|
1309
1441
|
restoredCards,
|
|
@@ -1317,7 +1449,11 @@ export {
|
|
|
1317
1449
|
setSourceTopic,
|
|
1318
1450
|
settleCard,
|
|
1319
1451
|
sourceAttachTargets,
|
|
1452
|
+
sourceCardChars,
|
|
1453
|
+
sourceCardMeasuredState,
|
|
1454
|
+
sourceCardState,
|
|
1320
1455
|
sourceDelivery,
|
|
1456
|
+
sourceEntryChars,
|
|
1321
1457
|
sourceKey,
|
|
1322
1458
|
sourceRecoveryGuards,
|
|
1323
1459
|
sourceRoomLeft,
|