@ai-matrx/agents 0.18.1 → 0.18.5

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.
@@ -27,6 +27,8 @@ __export(runtime_exports, {
27
27
  KEEP_WAITING_FOR_ORGANIZATION: () => KEEP_WAITING_FOR_ORGANIZATION,
28
28
  MAX_KEPT_TEXT_KNOB: () => MAX_KEPT_TEXT_KNOB,
29
29
  NOT_KEPT_FOR_RELOAD: () => NOT_KEPT_FOR_RELOAD,
30
+ PARTS_MATCHED_BY_PAGE: () => PARTS_MATCHED_BY_PAGE,
31
+ PARTS_NOT_MATCHED: () => PARTS_NOT_MATCHED,
30
32
  RELOADED_RESUMING: () => RELOADED_RESUMING,
31
33
  RELOADED_WHILE_ADDING: () => RELOADED_WHILE_ADDING,
32
34
  SAME_SOURCE_AGAIN: () => SAME_SOURCE_AGAIN,
@@ -40,6 +42,7 @@ __export(runtime_exports, {
40
42
  applyReviewedSourceSet: () => applyReviewedSourceSet,
41
43
  cardsToResume: () => cardsToResume,
42
44
  cardsWaitingForOrganization: () => cardsWaitingForOrganization,
45
+ carryPickedParts: () => carryPickedParts,
43
46
  chosenForm: () => chosenForm,
44
47
  continueAfterOrganization: () => continueAfterOrganization,
45
48
  createFetchSourcesTransport: () => createFetchSourcesTransport,
@@ -73,6 +76,7 @@ __export(runtime_exports, {
73
76
  readySourceRefs: () => readySourceRefs,
74
77
  registeredFileEdge: () => registeredFileEdge,
75
78
  reloadedCard: () => reloadedCard,
79
+ rememberPickedParts: () => rememberPickedParts,
76
80
  removeCard: () => removeCard,
77
81
  renderedPartChars: () => renderedPartChars,
78
82
  restartCard: () => restartCard,
@@ -87,7 +91,11 @@ __export(runtime_exports, {
87
91
  setSourceTopic: () => setSourceTopic,
88
92
  settleCard: () => settleCard,
89
93
  sourceAttachTargets: () => sourceAttachTargets,
94
+ sourceCardChars: () => sourceCardChars,
95
+ sourceCardMeasuredState: () => sourceCardMeasuredState,
96
+ sourceCardState: () => sourceCardState,
90
97
  sourceDelivery: () => sourceDelivery,
98
+ sourceEntryChars: () => sourceEntryChars,
91
99
  sourceKey: () => sourceKey,
92
100
  sourceRecoveryGuards: () => sourceRecoveryGuards,
93
101
  sourceRoomLeft: () => sourceRoomLeft,
@@ -110,12 +118,12 @@ function deliveryPatch(delivery) {
110
118
  var DELIVERY_WORDS = {
111
119
  direct: {
112
120
  label: "Include the text",
113
- hint: "The text is handed to the AI with your request, so it reads all of it before it starts.",
121
+ hint: "Sent in full",
114
122
  summary: "Text included"
115
123
  },
116
124
  context: {
117
125
  label: "Let the AI look it up",
118
- hint: "Nothing is sent up front. The AI opens this Source and reads the parts it needs while it works \u2014 best for very large Sources.",
126
+ hint: "Read as needed",
119
127
  summary: "Looked up when needed"
120
128
  }
121
129
  };
@@ -192,7 +200,7 @@ function resumableInput(draft) {
192
200
  case "youtube":
193
201
  return input.url?.trim() ? input : null;
194
202
  case "audio":
195
- return input.fileId ? input : null;
203
+ return input.fileId || input.text?.trim() ? input : null;
196
204
  default:
197
205
  return null;
198
206
  }
@@ -208,12 +216,12 @@ function reloadedCard(draft, status) {
208
216
  return { action: "lost", sentence: RELOADED_WHILE_ADDING };
209
217
  }
210
218
  var MAX_KEPT_TEXT_KNOB = { feature: "sources", key: "max_kept_draft_chars" };
211
- var NOT_KEPT_FOR_RELOAD = "Too large to keep on this device, so it will not come back if the page reloads before it is added.";
219
+ var NOT_KEPT_FOR_RELOAD = "Too large to restore if the page reloads before it is added.";
212
220
  var WAITING_FOR_ORGANIZATION = "Waiting for an organization \u2014 choose one and this continues by itself.";
213
221
  var KEEP_WAITING_FOR_ORGANIZATION = "Read. Waiting for an organization to keep it \u2014 choose one and it is kept by itself.";
214
222
 
215
223
  // sources/runtime/fileSource.ts
216
- var UNREADABLE = "The file is stored, but it could not be read into a Source, so nothing in it can be used yet. Remove it, or add a different copy (a PDF, Word file or plain text reads best).";
224
+ var UNREADABLE = "Can't read this file \u2014 add a PDF, Word or text copy.";
217
225
  function nextFileStep(status, ctx) {
218
226
  const pdId = status?.processed_document_id ?? null;
219
227
  if (pdId) return { do: "keep", processedDocumentId: pdId };
@@ -221,7 +229,7 @@ function nextFileStep(status, ctx) {
221
229
  if (status?.state === "failed")
222
230
  return {
223
231
  do: "unreadable",
224
- reason: status.error?.message ? `The file could not be read: ${status.error.message}. Remove it, or add it again.` : UNREADABLE
232
+ reason: status.error?.message ? `Can't read this file: ${status.error.message}. Add it again.` : UNREADABLE
225
233
  };
226
234
  if (!ctx.started) return { do: "start" };
227
235
  return { do: "unreadable", reason: UNREADABLE };
@@ -337,191 +345,10 @@ function totalChars(value) {
337
345
  return value.sources.filter((entry) => entry.state === "ready" || entry.state === "processing").reduce((sum, entry) => sum + manifestEntryChars(entry), 0);
338
346
  }
339
347
 
340
- // sources/runtime/plan.ts
341
- var HEAVY_SHARE = 0.7;
342
- var PAGE_SUFFIX = (page) => page !== void 0 && page > 0 ? ` (page ${page})` : "";
343
- function renderedPartChars(segment, chars) {
344
- return `### Chunk ${segment.id}${PAGE_SUFFIX(segment.page)}`.length + 1 + chars;
345
- }
346
- function capParts(parts, maxChars) {
347
- if (!maxChars) return { kept: parts.map((seg) => ({ seg, chars: seg.chars })), capped: false };
348
- const kept = [];
349
- let used = 0;
350
- for (const seg of parts) {
351
- if (used + seg.chars <= maxChars) {
352
- kept.push({ seg, chars: seg.chars });
353
- used += seg.chars;
354
- continue;
355
- }
356
- const room = maxChars - used;
357
- if (room > 0 && kept.length === 0) kept.push({ seg, chars: room });
358
- return { kept, capped: true };
359
- }
360
- return { kept, capped: false };
361
- }
362
- function chosenForm(entry, ref) {
363
- const key = ref.representation ?? entry.default_form;
364
- return entry.forms.find((f) => f.form === key) ?? entry.forms.find((f) => f.form === entry.default_form) ?? null;
365
- }
366
- function isUsable(entry) {
367
- return entry.state === "ready" || entry.state === "processing";
368
- }
369
- function measure(entry, ref) {
370
- const form = chosenForm(entry, ref);
371
- const formChars = form?.chars ?? 0;
372
- const formLabel = form?.label ?? "Text";
373
- const segments = entry.segments ?? null;
374
- if (segments && segments.length > 0) {
375
- const wanted = ref.include_segments?.length ? new Set(ref.include_segments) : null;
376
- const chosen = wanted ? segments.filter((s) => wanted.has(s.id)) : segments;
377
- const { kept, capped: capped2 } = capParts(chosen, ref.max_chars);
378
- const body = kept.reduce((sum, k) => sum + renderedPartChars(k.seg, k.chars), 0);
379
- const sentChars = kept.length ? body + 2 * (kept.length - 1) : 0;
380
- return {
381
- formChars,
382
- formLabel,
383
- sentChars,
384
- exact: true,
385
- partsSent: kept.length,
386
- partsTotal: segments.length,
387
- capped: capped2
388
- };
389
- }
390
- const capped = ref.max_chars !== void 0 && formChars > ref.max_chars;
391
- return {
392
- formChars,
393
- formLabel,
394
- sentChars: capped ? ref.max_chars ?? formChars : formChars,
395
- exact: false,
396
- partsSent: null,
397
- partsTotal: null,
398
- capped
399
- };
400
- }
401
- function planSourceReview(input) {
402
- const estimateTokens = input.estimateTokens ?? estimateSourceTokens;
403
- const windowIsFallback = !input.modelWindowTokens || input.modelWindowTokens <= 0;
404
- const windowTokens = windowIsFallback ? input.fallbackWindowTokens : input.modelWindowTokens;
405
- let sentChars = 0;
406
- const entries = input.manifest.sources.map((entry, index) => {
407
- const ref = input.refs[index] ?? entry.ref;
408
- const m = measure(entry, ref);
409
- const base = { index, ref, entry, ...m };
410
- if (!isUsable(entry)) {
411
- return { ...base, status: "unusable", sentChars: 0, sentTokens: 0 };
412
- }
413
- if (sourceDelivery(ref) === "context") {
414
- return { ...base, status: "on_demand", sentChars: 0, sentTokens: 0 };
415
- }
416
- if (estimateTokens(sentChars + m.sentChars) > windowTokens) {
417
- return { ...base, status: "left_out", sentTokens: estimateTokens(m.sentChars) };
418
- }
419
- sentChars += m.sentChars;
420
- return { ...base, status: "included", sentTokens: estimateTokens(m.sentChars) };
421
- });
422
- const sentTokens = estimateTokens(sentChars);
423
- const leftOut = entries.filter((e) => e.status === "left_out");
424
- const share = windowTokens > 0 ? sentTokens / windowTokens : 0;
425
- const anythingGoesIn = entries.some((e) => e.status === "included" || e.status === "on_demand");
426
- const verdict = !anythingGoesIn && leftOut.length === 0 ? "empty" : leftOut.length > 0 ? "too_much" : share >= HEAVY_SHARE ? "heavy" : "fine";
427
- const kept = entries.filter((e) => e.status !== "left_out").map(
428
- (e) => createSourceRef(e.ref.resource_type, e.ref.resource_id, {
429
- representation: e.ref.representation,
430
- include_segments: e.ref.include_segments,
431
- delivery: e.ref.delivery,
432
- max_chars: e.ref.max_chars,
433
- promote: e.ref.promote,
434
- exclude: e.ref.exclude
435
- })
436
- );
437
- const grounding = input.base.grounding === "selected" && !kept.some((r) => r.include_segments?.length) ? void 0 : input.base.grounding;
438
- const sourceSet = createSourceSet(kept, {
439
- topic: input.base.topic,
440
- grounding,
441
- retrieve_query: input.base.retrieve_query,
442
- target_model_id: input.targetModelId ?? input.base.target_model_id
443
- });
444
- return {
445
- entries,
446
- sentChars,
447
- sentTokens,
448
- windowTokens,
449
- windowIsFallback,
450
- verdict,
451
- share,
452
- leftOut,
453
- sourceSet
454
- };
455
- }
456
-
457
- // sources/runtime/client.ts
458
- function marked(options) {
459
- return {
460
- bodyCarriedRead: true,
461
- ...options?.organizationId ? { organizationId: options.organizationId } : {},
462
- ...options?.signal ? { signal: options.signal } : {}
463
- };
464
- }
465
- function createSourcesClient(transport) {
466
- return {
467
- manifest: (sourceSet, options) => transport.post("/sources/manifest", { source_set: sourceSet }, marked(options)),
468
- resolve: (sourceSet, options) => transport.post("/sources/resolve", { source_set: sourceSet }, marked(options)),
469
- searchParts: (ref, query, options) => transport.post("/sources/parts/search", { source_ref: ref, query }, marked(options))
470
- };
471
- }
472
- var SourceDoorError = class extends Error {
473
- status;
474
- body;
475
- constructor(status, message, body) {
476
- super(message);
477
- this.name = "SourceDoorError";
478
- this.status = status;
479
- this.body = body;
480
- }
481
- };
482
- function refusalMessage(status, body) {
483
- if (body && typeof body === "object") {
484
- const record = body;
485
- const error = record.error;
486
- if (error && typeof error === "object") {
487
- const message = error.user_message ?? error.message;
488
- if (typeof message === "string" && message) return message;
489
- }
490
- if (typeof record.detail === "string" && record.detail) return record.detail;
491
- }
492
- return `The server answered ${status}.`;
493
- }
494
- function createFetchSourcesTransport(options) {
495
- const base = options.baseUrl.replace(/\/+$/, "");
496
- return {
497
- async post(path, body, call) {
498
- const doFetch = options.fetch ?? fetch;
499
- const headers = {
500
- "Content-Type": "application/json",
501
- ...options.headers ? await options.headers() : {}
502
- };
503
- if (call.organizationId) headers[options.organizationHeader ?? "X-Organization-Id"] = call.organizationId;
504
- const response = await doFetch(`${base}${path}`, {
505
- method: "POST",
506
- headers,
507
- body: JSON.stringify(body),
508
- ...call.signal ? { signal: call.signal } : {}
509
- });
510
- const text = await response.text();
511
- let parsed = null;
512
- try {
513
- parsed = text ? JSON.parse(text) : null;
514
- } catch {
515
- parsed = text;
516
- }
517
- if (!response.ok) throw new SourceDoorError(response.status, refusalMessage(response.status, parsed), parsed);
518
- return parsed;
519
- }
520
- };
521
- }
522
-
523
348
  // sources/runtime/state.ts
524
349
  var EMPTY_SOURCE_SET_STATE = Object.freeze({ cards: Object.freeze([]), topic: "" });
350
+ var PARTS_MATCHED_BY_PAGE = "The clean version is ready \u2014 your parts were matched to it by page.";
351
+ 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.";
525
352
  var SAME_SOURCE_AGAIN = "You added this again \u2014 it is the same Source, so it is listed once.";
526
353
  function isSourceDraft(value) {
527
354
  return !!value && typeof value === "object" && typeof value.kind === "string" && typeof value.label === "string";
@@ -588,7 +415,7 @@ function settleCard(state, id, patch, options = {}) {
588
415
  }));
589
416
  }
590
417
  function failCard(state, id, sentence) {
591
- return replaceCard(state, id, (c) => ({ ...c, status: "error", error: sentence }));
418
+ return replaceCard(state, id, (c) => ({ ...c, status: "error", error: sentence, manifest: null }));
592
419
  }
593
420
  function restartCard(state, id) {
594
421
  return replaceCard(state, id, (c) => ({ ...c, status: "resolving", error: null }));
@@ -604,7 +431,68 @@ function updateCardRef(state, id, options) {
604
431
  return replaceCard(state, id, (c) => {
605
432
  if (!c.draft.ref) return c;
606
433
  const ref = createSourceRef(c.draft.ref.resource_type, c.draft.ref.resource_id, { ...c.draft.ref, ...options });
607
- return { ...c, draft: { ...c.draft, ref } };
434
+ return rememberPickedParts({ ...c, draft: { ...c.draft, ref } });
435
+ });
436
+ }
437
+ function rememberPickedParts(card) {
438
+ const ids = card.draft.ref?.include_segments ?? [];
439
+ if (ids.length === 0) {
440
+ return card.draft.pickedParts === void 0 ? card : { ...card, draft: { ...card.draft, pickedParts: void 0 } };
441
+ }
442
+ const segments = card.manifest?.segments ?? [];
443
+ const known = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));
444
+ const picked = [];
445
+ for (const id of ids) {
446
+ const segment = segments.find((s) => s.id === id);
447
+ if (segment) {
448
+ const pages = partPages(segment);
449
+ picked.push({ id, label: segment.label, ...pages ? { pages } : {} });
450
+ } else {
451
+ const before = known.get(id);
452
+ if (before) picked.push(before);
453
+ }
454
+ }
455
+ return { ...card, draft: { ...card.draft, pickedParts: picked.length ? picked : void 0 } };
456
+ }
457
+ function withNote(notes, note, drop = []) {
458
+ const kept = (notes ?? []).filter((n) => n !== note && !drop.includes(n));
459
+ return [...kept, note];
460
+ }
461
+ function carryPickedParts(card, entry) {
462
+ const ref = card.draft.ref;
463
+ const picked = ref?.include_segments ?? [];
464
+ const segments = entry.segments ?? [];
465
+ if (!ref || picked.length === 0 || segments.length === 0) return card;
466
+ const ids = new Set(segments.map((s) => s.id));
467
+ const stale = picked.filter((id) => !ids.has(id));
468
+ if (stale.length === 0) return card;
469
+ const remembered = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));
470
+ const oldSegments = card.manifest?.segments ?? [];
471
+ const spans = [];
472
+ let unknown = 0;
473
+ for (const id of stale) {
474
+ const old = oldSegments.find((s) => s.id === id);
475
+ const pages = remembered.get(id)?.pages ?? (old ? partPages(old) : null);
476
+ if (pages) spans.push(pages);
477
+ else unknown += 1;
478
+ }
479
+ const keep = new Set(picked.filter((id) => ids.has(id)));
480
+ for (const segment of segments) {
481
+ const pages = partPages(segment);
482
+ if (pages && spans.some(([from, to]) => pages[0] <= to && pages[1] >= from)) keep.add(segment.id);
483
+ }
484
+ const nextIds = segments.filter((s) => keep.has(s.id)).map((s) => s.id);
485
+ const matched = unknown === 0 && nextIds.length > 0;
486
+ const nextRef = createSourceRef(ref.resource_type, ref.resource_id, {
487
+ ...ref,
488
+ include_segments: matched ? nextIds : void 0
489
+ });
490
+ const note = matched ? PARTS_MATCHED_BY_PAGE : PARTS_NOT_MATCHED;
491
+ const other = matched ? PARTS_NOT_MATCHED : PARTS_MATCHED_BY_PAGE;
492
+ return rememberPickedParts({
493
+ ...card,
494
+ manifest: entry,
495
+ draft: { ...card.draft, ref: nextRef, notes: withNote(card.draft.notes, note, [other]) }
608
496
  });
609
497
  }
610
498
  function setCardWaitForClean(state, id, wait) {
@@ -620,7 +508,7 @@ function applyReviewedSourceSet(state, set) {
620
508
  if (!ref) continue;
621
509
  const match = set.sources.find((r) => sameSourceRef(r, ref));
622
510
  if (!match) continue;
623
- next = replaceCard(next, card.id, (c) => ({ ...c, draft: { ...c.draft, ref: match } }));
511
+ next = replaceCard(next, card.id, (c) => rememberPickedParts({ ...c, draft: { ...c.draft, ref: match } }));
624
512
  }
625
513
  return set.topic !== void 0 ? setSourceTopic(next, set.topic) : next;
626
514
  }
@@ -630,7 +518,13 @@ function applyManifest(state, manifest) {
630
518
  const ref = card.draft.ref;
631
519
  if (!ref || card.status !== "ready") continue;
632
520
  const entry = manifest.sources.find((e) => sameSourceRef(e.ref, ref));
633
- if (entry) next = replaceCard(next, card.id, (c) => ({ ...c, manifest: entry }));
521
+ if (!entry) continue;
522
+ next = replaceCard(next, card.id, (c) => {
523
+ const carried = carryPickedParts(c, entry);
524
+ if (carried !== c) return carried;
525
+ const measured = { ...c, manifest: entry };
526
+ return c.draft.ref?.include_segments?.length && !c.draft.pickedParts ? rememberPickedParts(measured) : measured;
527
+ });
634
528
  }
635
529
  return next;
636
530
  }
@@ -703,6 +597,27 @@ function selectTotalChars(state) {
703
597
  model_context_tokens: null
704
598
  });
705
599
  }
600
+ function sourceEntryChars(entry, ref) {
601
+ if (entry.state !== "ready" && entry.state !== "processing") return null;
602
+ return totalChars({
603
+ __kind: "source_manifest",
604
+ sources: [{ ...entry, ref }],
605
+ total_chars: 0,
606
+ estimated_tokens: 0,
607
+ model_context_tokens: null
608
+ });
609
+ }
610
+ function sourceCardChars(card) {
611
+ return card.manifest && card.draft.ref ? sourceEntryChars(card.manifest, card.draft.ref) : null;
612
+ }
613
+ function sourceCardState(card) {
614
+ if (card.status === "pending" || card.status === "resolving") return "adding";
615
+ if (card.status === "error") return card.error === WAITING_FOR_ORGANIZATION ? "waiting_for_organization" : "failed";
616
+ return card.manifest?.state ?? "unmeasured";
617
+ }
618
+ function sourceCardMeasuredState(card) {
619
+ return card.status === "ready" ? card.manifest?.state ?? null : null;
620
+ }
706
621
  function selectSettled(state) {
707
622
  return state.cards.every((c) => c.status === "ready");
708
623
  }
@@ -724,6 +639,190 @@ function withDisplayNames(resolved, cards) {
724
639
  };
725
640
  }
726
641
 
642
+ // sources/runtime/plan.ts
643
+ var HEAVY_SHARE = 0.7;
644
+ var PAGE_SUFFIX = (page) => page !== void 0 && page > 0 ? ` (page ${page})` : "";
645
+ function renderedPartChars(segment, chars) {
646
+ return `### Chunk ${segment.id}${PAGE_SUFFIX(segment.page)}`.length + 1 + chars;
647
+ }
648
+ function capParts(parts, maxChars) {
649
+ if (!maxChars) return { kept: parts.map((seg) => ({ seg, chars: seg.chars })), capped: false };
650
+ const kept = [];
651
+ let used = 0;
652
+ for (const seg of parts) {
653
+ if (used + seg.chars <= maxChars) {
654
+ kept.push({ seg, chars: seg.chars });
655
+ used += seg.chars;
656
+ continue;
657
+ }
658
+ const room = maxChars - used;
659
+ if (room > 0 && kept.length === 0) kept.push({ seg, chars: room });
660
+ return { kept, capped: true };
661
+ }
662
+ return { kept, capped: false };
663
+ }
664
+ function chosenForm(entry, ref) {
665
+ const key = ref.representation ?? entry.default_form;
666
+ return entry.forms.find((f) => f.form === key) ?? entry.forms.find((f) => f.form === entry.default_form) ?? null;
667
+ }
668
+ function isUsable(entry) {
669
+ return entry.state === "ready" || entry.state === "processing";
670
+ }
671
+ function measure(entry, ref) {
672
+ const form = chosenForm(entry, ref);
673
+ const formChars = form?.chars ?? 0;
674
+ const formLabel = form?.label ?? "Text";
675
+ const segments = entry.segments ?? null;
676
+ if (segments && segments.length > 0) {
677
+ const wanted = ref.include_segments?.length ? new Set(ref.include_segments) : null;
678
+ const chosen = wanted ? segments.filter((s) => wanted.has(s.id)) : segments;
679
+ const { kept, capped: capped2 } = capParts(chosen, ref.max_chars);
680
+ const body = kept.reduce((sum, k) => sum + renderedPartChars(k.seg, k.chars), 0);
681
+ const sentChars = kept.length ? body + 2 * (kept.length - 1) : 0;
682
+ return {
683
+ formChars,
684
+ formLabel,
685
+ sentChars,
686
+ exact: true,
687
+ partsSent: kept.length,
688
+ partsTotal: segments.length,
689
+ capped: capped2
690
+ };
691
+ }
692
+ const capped = ref.max_chars !== void 0 && formChars > ref.max_chars;
693
+ return {
694
+ formChars,
695
+ formLabel,
696
+ sentChars: capped ? ref.max_chars ?? formChars : formChars,
697
+ exact: false,
698
+ partsSent: null,
699
+ partsTotal: null,
700
+ capped
701
+ };
702
+ }
703
+ function planSourceReview(input) {
704
+ const estimateTokens = input.estimateTokens ?? estimateSourceTokens;
705
+ const windowIsFallback = !input.modelWindowTokens || input.modelWindowTokens <= 0;
706
+ const windowTokens = windowIsFallback ? input.fallbackWindowTokens : input.modelWindowTokens;
707
+ let sentChars = 0;
708
+ const entries = input.manifest.sources.map((entry, index) => {
709
+ const ref = input.refs[index] ?? entry.ref;
710
+ const m = measure(entry, ref);
711
+ const base = { index, ref, entry, ...m, chars: sourceEntryChars(entry, ref) ?? 0 };
712
+ if (!isUsable(entry)) {
713
+ return { ...base, status: "unusable", sentChars: 0, sentTokens: 0 };
714
+ }
715
+ if (sourceDelivery(ref) === "context") {
716
+ return { ...base, status: "on_demand", sentChars: 0, sentTokens: 0 };
717
+ }
718
+ if (estimateTokens(sentChars + m.sentChars) > windowTokens) {
719
+ return { ...base, status: "left_out", sentTokens: estimateTokens(m.sentChars) };
720
+ }
721
+ sentChars += m.sentChars;
722
+ return { ...base, status: "included", sentTokens: estimateTokens(m.sentChars) };
723
+ });
724
+ const sentTokens = estimateTokens(sentChars);
725
+ const leftOut = entries.filter((e) => e.status === "left_out");
726
+ const share = windowTokens > 0 ? sentTokens / windowTokens : 0;
727
+ const anythingGoesIn = entries.some((e) => e.status === "included" || e.status === "on_demand");
728
+ const verdict = !anythingGoesIn && leftOut.length === 0 ? "empty" : leftOut.length > 0 ? "too_much" : share >= HEAVY_SHARE ? "heavy" : "fine";
729
+ const kept = entries.filter((e) => e.status !== "left_out").map(
730
+ (e) => createSourceRef(e.ref.resource_type, e.ref.resource_id, {
731
+ representation: e.ref.representation,
732
+ include_segments: e.ref.include_segments,
733
+ delivery: e.ref.delivery,
734
+ max_chars: e.ref.max_chars,
735
+ promote: e.ref.promote,
736
+ exclude: e.ref.exclude
737
+ })
738
+ );
739
+ const grounding = input.base.grounding === "selected" && !kept.some((r) => r.include_segments?.length) ? void 0 : input.base.grounding;
740
+ const sourceSet = createSourceSet(kept, {
741
+ topic: input.base.topic,
742
+ grounding,
743
+ retrieve_query: input.base.retrieve_query,
744
+ target_model_id: input.targetModelId ?? input.base.target_model_id
745
+ });
746
+ return {
747
+ entries,
748
+ chars: entries.filter((e) => e.status === "included").reduce((sum, e) => sum + e.chars, 0),
749
+ sentChars,
750
+ sentTokens,
751
+ windowTokens,
752
+ windowIsFallback,
753
+ verdict,
754
+ share,
755
+ leftOut,
756
+ sourceSet
757
+ };
758
+ }
759
+
760
+ // sources/runtime/client.ts
761
+ function marked(options) {
762
+ return {
763
+ bodyCarriedRead: true,
764
+ ...options?.organizationId ? { organizationId: options.organizationId } : {},
765
+ ...options?.signal ? { signal: options.signal } : {}
766
+ };
767
+ }
768
+ function createSourcesClient(transport) {
769
+ return {
770
+ manifest: (sourceSet, options) => transport.post("/sources/manifest", { source_set: sourceSet }, marked(options)),
771
+ resolve: (sourceSet, options) => transport.post("/sources/resolve", { source_set: sourceSet }, marked(options)),
772
+ searchParts: (ref, query, options) => transport.post("/sources/parts/search", { source_ref: ref, query }, marked(options))
773
+ };
774
+ }
775
+ var SourceDoorError = class extends Error {
776
+ status;
777
+ body;
778
+ constructor(status, message, body) {
779
+ super(message);
780
+ this.name = "SourceDoorError";
781
+ this.status = status;
782
+ this.body = body;
783
+ }
784
+ };
785
+ function refusalMessage(status, body) {
786
+ if (body && typeof body === "object") {
787
+ const record = body;
788
+ const error = record.error;
789
+ if (error && typeof error === "object") {
790
+ const message = error.user_message ?? error.message;
791
+ if (typeof message === "string" && message) return message;
792
+ }
793
+ if (typeof record.detail === "string" && record.detail) return record.detail;
794
+ }
795
+ return `The server answered ${status}.`;
796
+ }
797
+ function createFetchSourcesTransport(options) {
798
+ const base = options.baseUrl.replace(/\/+$/, "");
799
+ return {
800
+ async post(path, body, call) {
801
+ const doFetch = options.fetch ?? fetch;
802
+ const headers = {
803
+ "Content-Type": "application/json",
804
+ ...options.headers ? await options.headers() : {}
805
+ };
806
+ if (call.organizationId) headers[options.organizationHeader ?? "X-Organization-Id"] = call.organizationId;
807
+ const response = await doFetch(`${base}${path}`, {
808
+ method: "POST",
809
+ headers,
810
+ body: JSON.stringify(body),
811
+ ...call.signal ? { signal: call.signal } : {}
812
+ });
813
+ const text = await response.text();
814
+ let parsed = null;
815
+ try {
816
+ parsed = text ? JSON.parse(text) : null;
817
+ } catch {
818
+ parsed = text;
819
+ }
820
+ if (!response.ok) throw new SourceDoorError(response.status, refusalMessage(response.status, parsed), parsed);
821
+ return parsed;
822
+ }
823
+ };
824
+ }
825
+
727
826
  // sources/runtime/controller.ts
728
827
  function randomId() {
729
828
  const cryptoApi = globalThis.crypto;
@@ -1143,20 +1242,45 @@ function createSourceIntake(set, deps) {
1143
1242
  });
1144
1243
  await hold(() => landPaste(id, trimmed, name));
1145
1244
  },
1245
+ async addRecordedText(text, name) {
1246
+ const trimmed = text.trim();
1247
+ if (!trimmed) return;
1248
+ const max = deps.maxKeptChars();
1249
+ const kept = max !== null && trimmed.length <= max;
1250
+ const id = set.addPending({
1251
+ kind: "audio",
1252
+ label: name?.trim() || "Recording",
1253
+ origin: "Recording",
1254
+ input: kept ? { text: trimmed, name } : void 0,
1255
+ notes: kept ? void 0 : [NOT_KEPT_FOR_RELOAD]
1256
+ });
1257
+ await hold(() => landPaste(id, trimmed, name));
1258
+ },
1146
1259
  async addWebPage(raw) {
1147
1260
  const url = /^https?:\/\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;
1148
1261
  const id = set.addPending({ kind: "web", label: hostOf(url), origin: url, input: { url } });
1149
1262
  await hold(() => landWebPage(id, url));
1150
1263
  },
1151
- async addScrapedPage(page) {
1264
+ beginWebPage(raw) {
1265
+ const url = /^https?:\/\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;
1266
+ return set.addPending({ kind: "web", label: hostOf(url), origin: url, input: { url } });
1267
+ },
1268
+ async addScrapedPage(page, pendingId) {
1152
1269
  const label = page.title || hostOf(page.url);
1270
+ const cardFor = () => {
1271
+ if (pendingId && set.restart(pendingId)) {
1272
+ set.updateDraft(pendingId, { label, origin: page.url, input: { url: page.url } });
1273
+ return pendingId;
1274
+ }
1275
+ return set.addPending({ kind: "web", label, origin: page.url, input: { url: page.url } });
1276
+ };
1153
1277
  if (!page.processedDocumentId) {
1154
- const id2 = set.addPending({ kind: "web", label, origin: page.url, input: { url: page.url } });
1278
+ const id2 = cardFor();
1155
1279
  await hold(() => landPaste(id2, page.text, label));
1156
1280
  return;
1157
1281
  }
1158
1282
  const pdId = page.processedDocumentId;
1159
- const id = set.addPending({ kind: "web", label, origin: page.url, input: { url: page.url } });
1283
+ const id = cardFor();
1160
1284
  await hold(async () => {
1161
1285
  let notes = [];
1162
1286
  try {
@@ -1231,7 +1355,8 @@ function createSourceIntake(set, deps) {
1231
1355
  return true;
1232
1356
  }
1233
1357
  case "audio":
1234
- void transcribeRecording(card.id, input.fileId ?? "", card.draft.label);
1358
+ if (input.fileId) void transcribeRecording(card.id, input.fileId, card.draft.label);
1359
+ else void landPaste(card.id, (input.text ?? "").trim(), input.name);
1235
1360
  return true;
1236
1361
  default:
1237
1362
  return false;