@ai-matrx/agents 0.18.5 → 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 +26 -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 +14 -4
- package/dist/sources/react/index.cjs.map +1 -1
- package/dist/sources/react/index.d.cts +11 -3
- package/dist/sources/react/index.d.ts +11 -3
- package/dist/sources/react/index.js +14 -4
- package/dist/sources/react/index.js.map +1 -1
- package/dist/sources/runtime/index.cjs +15 -4
- package/dist/sources/runtime/index.cjs.map +1 -1
- package/dist/sources/runtime/index.d.cts +22 -5
- package/dist/sources/runtime/index.d.ts +22 -5
- package/dist/sources/runtime/index.js +15 -4
- package/dist/sources/runtime/index.js.map +1 -1
- package/mandates/snapshots/keys.0.19.1.json +652 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../sources/react/index.ts","../../../sources/index.ts","../../../sources/runtime/delivery.ts","../../../sources/runtime/partsSearch.ts","../../../sources/runtime/interrupted.ts","../../../sources/runtime/fileSource.ts","../../../sources/runtime/state.ts","../../../sources/runtime/controller.ts","../../../sources/runtime/intake.ts","../../../sources/runtime/recovery.ts"],"sourcesContent":["/**\n * `@ai-matrx/agents/sources/react` — thin React hooks over the Source runtime\n * (`@ai-matrx/agents/sources/runtime`). No logic lives here that a non-React\n * client could not reach through the runtime itself: the hooks subscribe,\n * schedule, and hand back the same controller.\n *\n * const set = useSourceSet(adapter, { persistenceReady });\n * const intake = useSourceIntake(set, deps);\n * useSourceRecovery(set, intake, runner, { organizationId, readFileState });\n * const search = useSourcePartsSearch(client, ref, query);\n *\n * A host binds the adapter to its own store once (memoized per surface) —\n * the web app binds Redux; another client binds its own.\n */\n\nimport { useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { createSourceRef, type ResolvedSourceSet, type SourceRef, type SourceSet } from \"../index\";\nimport {\n cardsToResume,\n cardsWaitingForOrganization,\n continueAfterOrganization,\n createSourceIntake,\n createSourceSetController,\n fileSourcePollDelayMs,\n isAskableFileCard,\n isWordQuery,\n lookAtFileCards,\n readPersistedSourceInput,\n resumeInterrupted,\n type FileRecoveryDeps,\n type PartMatchIds,\n type SourceCardModel,\n type SourceDelivery,\n type SourceIntake,\n type SourceIntakeDeps,\n type SourceLandingBodyBase,\n type SourceSetActions,\n type SourceSetAdapter,\n type SourceSetConfig,\n type SourceSetController,\n type SourceFileRunner,\n type SourcesClient,\n} from \"../runtime/index\";\n\nconst noSubscribe = () => () => {};\n\n/**\n * The latest value of a callback, read inside effects without re-running them\n * (React 18 has no `useEffectEvent`; the peer range starts at 18). The ref is\n * refreshed by an effect declared BEFORE the effects that read it, so they\n * always see this render's closure.\n */\nfunction useLatest<T>(value: T): { readonly current: T } {\n const ref = useRef(value);\n useEffect(() => {\n ref.current = value;\n });\n return ref;\n}\nconst noSaved = () => undefined;\n\nexport interface UseSourceSetOptions {\n /**\n * The draft store has been read back (a device store loads a moment after\n * the page). While false, \"nothing picked\" is not known — `restoring` stays\n * true. Default true.\n */\n persistenceReady?: boolean | undefined;\n /** The host's choices, re-read on every render. Default: the adapter's config. */\n config?: SourceSetConfig | undefined;\n}\n\nexport interface UseSourceSetResult extends SourceSetActions {\n /** Every picked Source, in the order picked. */\n sources: SourceCardModel[];\n topic: string;\n /** The frozen v1 payload, built from the ready Sources. */\n toSourceSet: (options?: { targetModelId?: string | undefined }) => SourceSet;\n /** Apply a set the review page returned (forms, parts, caps, delivery). */\n applySourceSet: (set: SourceSet) => void;\n /** POST /sources/resolve — the grounded text for a generator. */\n resolve: (options?: { targetModelId?: string | undefined }) => Promise<ResolvedSourceSet>;\n /** Switch back any Source set to a delivery the host cannot use (with a note). */\n fitDeliveries: (deliveries?: readonly SourceDelivery[]) => void;\n /** How many more Sources fit under the host's max. */\n roomLeft: () => number;\n /** Characters that will go in (the server's measurement; 0 until measured). */\n totalChars: number;\n measuring: boolean;\n /** Why the measurement failed, with its remedy. */\n manifestError: string | null;\n /** Every Source finished landing (nothing pending) and none failed. */\n settled: boolean;\n /** The saved draft is not read back yet — show a loading state, never an empty one. */\n restoring: boolean;\n /** The controller itself, for non-React code on the same surface. */\n controller: SourceSetController;\n}\n\n/**\n * THE hook for one Source input. `adapter` must be stable for a surface\n * (memoize it); a new adapter builds a new controller.\n */\nexport function useSourceSet(adapter: SourceSetAdapter, options: UseSourceSetOptions = {}): UseSourceSetResult {\n const controller = useMemo(() => createSourceSetController(adapter), [adapter]);\n controller.configure(options.config ?? adapter.config ?? {});\n const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);\n const meta = useSyncExternalStore(controller.subscribeMeta, controller.getMeta, controller.getMeta);\n const persistence = adapter.persistence;\n const saved = useSyncExternalStore(\n persistence?.subscribe ?? noSubscribe,\n persistence ? persistence.load : noSaved,\n persistence ? persistence.load : noSaved,\n );\n\n useEffect(() => {\n adapter.store.init?.();\n }, [adapter]);\n\n // Restore the saved draft once, the moment it is read back.\n useEffect(() => {\n controller.restore(saved);\n }, [controller, saved]);\n\n const savedCount = readPersistedSourceInput(saved).sources.length;\n const ready = options.persistenceReady ?? true;\n\n return {\n controller,\n sources: state.cards as SourceCardModel[],\n topic: state.topic,\n addReady: controller.addReady,\n addPending: controller.addPending,\n settle: controller.settle,\n fail: controller.fail,\n restart: controller.restart,\n updateDraft: controller.updateDraft,\n remove: controller.remove,\n updateRef: controller.updateRef,\n setWaitForClean: controller.setWaitForClean,\n setTopic: controller.setTopic,\n hasRef: controller.hasRef,\n liveCount: controller.liveCount,\n manifest: controller.manifest,\n toSourceSet: controller.toSourceSet,\n applySourceSet: controller.applySourceSet,\n resolve: controller.resolve,\n fitDeliveries: controller.fitDeliveries,\n roomLeft: controller.roomLeft,\n totalChars: controller.totalChars(),\n measuring: meta.measuring,\n manifestError: meta.manifestError,\n settled: controller.settled(),\n // Not read back yet, or read back but the restore has not landed in the\n // store (one render between the two) — both would draw a false \"empty\".\n restoring: !ready || (savedCount > 0 && state.cards.length === 0),\n };\n}\n\n/** Every landing door, over the set. Rebuilt each render (closures only — nothing to keep). */\nexport function useSourceIntake<Body extends SourceLandingBodyBase>(\n set: SourceSetActions,\n deps: SourceIntakeDeps<Body>,\n): SourceIntake {\n return createSourceIntake(set, deps);\n}\n\nexport interface UseSourceRecoveryOptions extends FileRecoveryDeps {}\n\n/**\n * Never lose input, and follow stored files' Sources — call once per screen\n * that sits on `useSourceSet` + `useSourceIntake`.\n */\nexport function useSourceRecovery(\n set: Pick<UseSourceSetResult, \"sources\" | \"fail\" | \"manifest\">,\n intake: Pick<SourceIntake, \"resume\" | \"fileLanded\">,\n runner: SourceFileRunner,\n options: UseSourceRecoveryOptions,\n): void {\n // ── Never lose input: land again what a reload cut off ─────────────────────\n const resumeKey = cardsToResume(set.sources)\n .map((s) => s.id)\n .join(\",\");\n const latest = useLatest({ set, intake, runner, options });\n useEffect(() => {\n if (resumeKey) resumeInterrupted(latest.current.set.sources, latest.current.intake);\n }, [resumeKey, latest]);\n\n // ── Waited for an organization: go on the moment one is set ─────────────────\n const waitingForOrgKey = options.organizationId\n ? cardsWaitingForOrganization(set.sources)\n .map((s) => s.id)\n .join(\",\")\n : \"\";\n useEffect(() => {\n if (waitingForOrgKey) continueAfterOrganization(latest.current.set.sources, latest.current.intake);\n }, [waitingForOrgKey, latest]);\n\n // ── A stored file's Source: read the SERVER's state, never this tab's memory.\n // Held for an organization (V2-F #3): no organization known = nothing asked.\n // Picking one changes the key, so the look starts by itself.\n const waitingKey = set.sources\n .filter((c) => isAskableFileCard(c, options))\n .map((c) => `${c.id}:${c.draft.fileId}`)\n .join(\",\");\n useEffect(() => {\n if (!waitingKey) return undefined;\n const ac = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const look = (round: number) => {\n timer = setTimeout(async () => {\n const now = latest.current;\n const again = await lookAtFileCards(now.set.sources, {\n set: now.set,\n intake: now.intake,\n runner: now.runner,\n signal: ac.signal,\n ...now.options,\n });\n if (again && !ac.signal.aborted) look(round + 1);\n }, fileSourcePollDelayMs(round));\n };\n look(0);\n return () => {\n ac.abort();\n if (timer) clearTimeout(timer);\n };\n }, [waitingKey, latest]);\n}\n\n/** How long typing must pause before the server is asked. */\nconst SEARCH_DEBOUNCE_MS = 250;\n\nconst COULD_NOT_SEARCH =\n \"Only part titles and opening words are searched — the full text could not be searched just now.\";\n\nexport interface SourcePartsSearchState {\n /** Ids of the parts whose text holds every word (undefined until answered). */\n matches: PartMatchIds | undefined;\n /** The server is being asked about the current words (\"Searching inside the text…\"). */\n reading: boolean;\n /** Said under the search when the text could not be searched (titles and previews still match). */\n error: string | null;\n /** More parts matched than the server returns; the list shown is the first of them. */\n truncated: boolean;\n}\n\n/**\n * Which of one Source's parts hold every word a person typed, answered by the\n * server (`POST /sources/parts/search` — ids only; the whole text never comes\n * to the client). Asked only for words (never a page or a range), after the\n * person pauses typing.\n */\nexport function useSourcePartsSearch(\n client: Pick<SourcesClient, \"searchParts\">,\n ref: SourceRef | null,\n query: string,\n): SourcePartsSearchState {\n const [state, setState] = useState<{\n key: string;\n matches?: PartMatchIds;\n truncated?: boolean;\n error?: string;\n } | null>(null);\n const resourceType = ref?.resource_type ?? \"\";\n const resourceId = ref?.resource_id ?? \"\";\n const representation = ref?.representation ?? undefined;\n const words = isWordQuery(query) ? query.trim().toLowerCase().split(/\\s+/).join(\" \") : \"\";\n const key = resourceId && words ? `${resourceType}:${resourceId}:${representation ?? \"\"}:${words}` : null;\n const latestClient = useLatest(client);\n\n useEffect(() => {\n if (!key) return undefined;\n // The whole Source in the chosen form: the person's picked parts never narrow a search.\n const whole = createSourceRef(resourceType, resourceId, { representation });\n const controller = new AbortController();\n const timer = setTimeout(() => {\n latestClient.current\n .searchParts(whole, words, { signal: controller.signal })\n .then((found) => {\n if (controller.signal.aborted) return;\n if (found.unavailable) {\n setState({\n key,\n error: `Only part titles and opening words are searched — ${\n found.detail ?? \"the full text could not be searched.\"\n }`,\n });\n return;\n }\n setState({ key, matches: new Set(found.segment_ids ?? []), truncated: !!found.truncated });\n })\n .catch(() => {\n if (!controller.signal.aborted) setState({ key, error: COULD_NOT_SEARCH });\n });\n }, SEARCH_DEBOUNCE_MS);\n return () => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [key, resourceType, resourceId, representation, words, latestClient]);\n\n const mine = key && state && state.key === key ? state : null;\n return {\n matches: mine?.matches,\n reading: !!key && !mine,\n error: mine?.error ?? null,\n truncated: mine?.truncated ?? false,\n };\n}\n","/**\n * `@ai-matrx/agents/sources` — THE ONE SOURCE PAYLOAD (contract v1, frozen 2026-09-27).\n *\n * Every request that is built from a person's Sources carries them as a\n * `SourceSet`: a list of `SourceRef` pointers (never blobs) plus how the model\n * should be grounded in them. The server answers with a `SourceManifest`\n * (sizes and states, never bodies — POST /sources/manifest) or a\n * `ResolvedSourceSet` (grounded text for generators — POST /sources/resolve).\n *\n * Contract of record: common-docs `projects/unified-source-input/DESIGN.md`\n * § \"Contract v1 — FROZEN\". A shape change here is an AMENDMENT there first,\n * with its Pydantic twin beside aidream's `parse_resource_reference`.\n *\n * `SourceRef` IS the existing `resource_ref` pointer already on the wire\n * (aidream `services/conversation_context/resource_context.py`), extended with\n * optional fields only — never coin a second pointer type.\n *\n * Pure module: no React, no I/O, no \"use client\".\n */\n\nexport const RESOURCE_REF_KIND = \"resource_ref\" as const;\nexport const SOURCE_SET_KIND = \"source_set\" as const;\nexport const SOURCE_MANIFEST_KIND = \"source_manifest\" as const;\nexport const RESOLVED_SOURCE_SET_KIND = \"resolved_source_set\" as const;\n\n/** The wire version every `SourceSet` carries. */\nexport const SOURCE_SET_VERSION = 1 as const;\n\n/** A bounded preview of one representation promoted into the prompt. */\nexport interface ResourcePromotion {\n representation: string;\n max_chars?: number;\n}\n\nexport type SourceDelivery = \"direct\" | \"context\";\nexport type SourceGrounding = \"whole\" | \"selected\" | \"retrieve\";\n\n/** The pointer — the existing `resource_ref` envelope, extended (all new fields optional). */\nexport interface SourceRef {\n __kind: typeof RESOURCE_REF_KIND;\n /** Server resource token: \"file\" (A2; \"cld_file\" is a server alias) | \"processed_document\" | \"note\" | \"fc_set\" | … */\n resource_type: string;\n resource_id: string;\n /** \"clean\" | \"raw\" | \"pdf\" | a family representation key. Omitted = server's Clean → Raw → original fallback. */\n representation?: string;\n /** Hand-picked Segment ids (rag.kg_chunks ids or \"<resource_id>:<n>\"). */\n include_segments?: string[];\n /** Include the text (default \"direct\") | the AI fetches it on demand (\"context\"). */\n delivery?: SourceDelivery;\n /** Per-Source cap chosen on the review page. */\n max_chars?: number;\n promote?: ResourcePromotion | ResourcePromotion[];\n exclude?: string[];\n}\n\nexport interface SourceSet {\n __kind: typeof SOURCE_SET_KIND;\n version: typeof SOURCE_SET_VERSION;\n sources: SourceRef[];\n /** Only for \"Just a topic\". */\n topic?: string;\n /** Default \"whole\". */\n grounding?: SourceGrounding;\n /** Required in spirit when grounding = \"retrieve\". */\n retrieve_query?: string;\n /** The model whose context window sets the budget. */\n target_model_id?: string;\n}\n\nexport type SourceState = \"ready\" | \"processing\" | \"failed\" | \"unavailable\";\n\nexport interface SourceManifestForm {\n form: string;\n label: string;\n chars: number;\n available: boolean;\n}\n\nexport interface SourceManifestSegment {\n id: string;\n /** \"Page 7\", \"Pages 22–24\" (a part spanning pages), \"0:04–2:31\", a heading path, \"Part 3\". */\n label: string;\n page?: number;\n chars: number;\n /**\n * Amendment A5: the part's opening words (about 160 characters, whitespace\n * collapsed) — never its body. Lets a person see what a part says and find\n * a part by its words.\n */\n preview?: string;\n}\n\nexport interface SourceManifestEntry {\n ref: SourceRef;\n label: string;\n resource_type: string;\n state: SourceState;\n state_detail?: string;\n forms: SourceManifestForm[];\n default_form: string;\n segments?: SourceManifestSegment[];\n}\n\n/** POST /sources/manifest { source_set } → sizes and states, never bodies. */\nexport interface SourceManifest {\n __kind: typeof SOURCE_MANIFEST_KIND;\n sources: SourceManifestEntry[];\n total_chars: number;\n estimated_tokens: number;\n /** null = unknown model; the UI says so. */\n model_context_tokens: number | null;\n}\n\nexport interface ResolvedSourceSegment {\n id: string;\n page?: number;\n chars: number;\n}\n\nexport interface ResolvedSource {\n ref: SourceRef;\n label: string;\n form_used: string;\n /** Grounded: \"### Chunk <id> (page N)\" blocks; never re-chunked. */\n text: string;\n segments: ResolvedSourceSegment[];\n file_id?: string;\n processed_document_id?: string;\n /** \"processing\" = the raw fallback was used. */\n state: \"ready\" | \"processing\";\n truncated: boolean;\n /** Every stand-in announces itself. */\n notes: string[];\n}\n\n/** A1 (2026-09-27): \"not_ready\" = a file not yet read. */\nexport type DroppedSourceReason =\n | \"no_access\"\n | \"missing\"\n | \"failed\"\n | \"over_budget\"\n | \"not_ready\";\n\nexport interface DroppedSource {\n ref: SourceRef;\n reason: DroppedSourceReason;\n /** A1: what happened and what to do. */\n detail?: string;\n}\n\n/** POST /sources/resolve { source_set } → grounded text for generators. */\nexport interface ResolvedSourceSet {\n __kind: typeof RESOLVED_SOURCE_SET_KIND;\n sources: ResolvedSource[];\n dropped: DroppedSource[];\n total_chars: number;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers\n// ---------------------------------------------------------------------------\n\n/** Builder options. `undefined` is accepted everywhere so callers can forward an existing ref's optional fields. */\nexport interface SourceRefOptions {\n representation?: string | undefined;\n include_segments?: readonly string[] | undefined;\n delivery?: SourceDelivery | undefined;\n max_chars?: number | undefined;\n promote?: ResourcePromotion | ResourcePromotion[] | undefined;\n exclude?: readonly string[] | undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Build one pointer. Empty optional fields are omitted (so the wire stays\n * minimal and equal pointers serialise equally); `exclude` is trimmed,\n * lower-cased and de-duplicated exactly as the server normalises it;\n * `include_segments` is de-duplicated in order. Throws on an empty type or id —\n * a pointer to nothing is never built silently.\n */\nexport function createSourceRef(\n resourceType: string,\n resourceId: string,\n options: SourceRefOptions = {},\n): SourceRef {\n const resource_type = resourceType.trim();\n const resource_id = resourceId.trim();\n if (!resource_type) throw new Error(\"createSourceRef: resource_type is required\");\n if (!resource_id) throw new Error(\"createSourceRef: resource_id is required\");\n if (\n options.max_chars !== undefined &&\n (!Number.isInteger(options.max_chars) || options.max_chars <= 0)\n ) {\n throw new Error(\"createSourceRef: max_chars must be a positive integer\");\n }\n const exclude = Array.from(\n new Set(\n (options.exclude ?? [])\n .map((value) => value.trim().toLowerCase())\n .filter(Boolean),\n ),\n );\n const include_segments = Array.from(\n new Set((options.include_segments ?? []).map((id) => id.trim()).filter(Boolean)),\n );\n return {\n __kind: RESOURCE_REF_KIND,\n resource_type,\n resource_id,\n ...(options.representation ? { representation: options.representation } : {}),\n ...(include_segments.length ? { include_segments } : {}),\n ...(options.delivery ? { delivery: options.delivery } : {}),\n ...(options.max_chars !== undefined ? { max_chars: options.max_chars } : {}),\n ...(options.promote ? { promote: options.promote } : {}),\n ...(exclude.length ? { exclude } : {}),\n };\n}\n\nexport function isSourceRef(value: unknown): value is SourceRef {\n return (\n isRecord(value) &&\n value.__kind === RESOURCE_REF_KIND &&\n typeof value.resource_type === \"string\" &&\n value.resource_type.length > 0 &&\n typeof value.resource_id === \"string\" &&\n value.resource_id.length > 0\n );\n}\n\nexport interface SourceSetOptions {\n topic?: string | undefined;\n grounding?: SourceGrounding | undefined;\n retrieve_query?: string | undefined;\n target_model_id?: string | undefined;\n}\n\n/**\n * Build one envelope. Duplicate pointers (same type + id + representation) are\n * collapsed, keeping the first. `grounding: \"retrieve\"` without a query and\n * `grounding: \"selected\"` with no Source carrying `include_segments` throw —\n * both would otherwise resolve to something the person never asked for.\n */\nexport function createSourceSet(\n sources: readonly SourceRef[],\n options: SourceSetOptions = {},\n): SourceSet {\n const seen = new Set<string>();\n const unique: SourceRef[] = [];\n for (const ref of sources) {\n if (!isSourceRef(ref)) throw new Error(\"createSourceSet: every source must be a resource_ref\");\n const key = `${ref.resource_type}\\u0000${ref.resource_id}\\u0000${ref.representation ?? \"\"}`;\n if (seen.has(key)) continue;\n seen.add(key);\n unique.push(ref);\n }\n const topic = options.topic?.trim();\n const retrieve_query = options.retrieve_query?.trim();\n if (options.grounding === \"retrieve\" && !retrieve_query) {\n throw new Error('createSourceSet: grounding \"retrieve\" needs a retrieve_query');\n }\n if (\n options.grounding === \"selected\" &&\n !unique.some((ref) => (ref.include_segments?.length ?? 0) > 0)\n ) {\n throw new Error('createSourceSet: grounding \"selected\" needs at least one Source with include_segments');\n }\n return {\n __kind: SOURCE_SET_KIND,\n version: SOURCE_SET_VERSION,\n sources: unique,\n ...(topic ? { topic } : {}),\n ...(options.grounding ? { grounding: options.grounding } : {}),\n ...(retrieve_query ? { retrieve_query } : {}),\n ...(options.target_model_id ? { target_model_id: options.target_model_id } : {}),\n };\n}\n\n/** Structural guard for a wire value claiming to be a v1 `SourceSet`. */\nexport function isSourceSet(value: unknown): value is SourceSet {\n return (\n isRecord(value) &&\n value.__kind === SOURCE_SET_KIND &&\n value.version === SOURCE_SET_VERSION &&\n Array.isArray(value.sources) &&\n value.sources.every(isSourceRef)\n );\n}\n\nfunction manifestEntryChars(entry: SourceManifestEntry): number {\n const selected = entry.ref.include_segments;\n let chars: number;\n if (selected?.length && entry.segments?.length) {\n const wanted = new Set(selected);\n chars = entry.segments\n .filter((segment) => wanted.has(segment.id))\n .reduce((sum, segment) => sum + segment.chars, 0);\n } else {\n const formKey = entry.ref.representation ?? entry.default_form;\n const form =\n entry.forms.find((candidate) => candidate.form === formKey) ??\n entry.forms.find((candidate) => candidate.form === entry.default_form);\n chars = form?.chars ?? 0;\n }\n return entry.ref.max_chars !== undefined ? Math.min(chars, entry.ref.max_chars) : chars;\n}\n\n/**\n * Characters that will actually go in, computed from the Sources themselves\n * (never trusting a stale `total_chars`):\n * - `ResolvedSourceSet`: the sum of every resolved text's length.\n * - `SourceManifest`: per Source, the chosen form's size (the ref's\n * `representation`, else `default_form`), or the picked Segments' sizes when\n * `include_segments` is set, capped by the ref's `max_chars`. Sources whose\n * state is \"failed\" or \"unavailable\" contribute nothing — they cannot go in.\n */\nexport function totalChars(value: SourceManifest | ResolvedSourceSet): number {\n if (value.__kind === RESOLVED_SOURCE_SET_KIND) {\n return value.sources.reduce((sum, source) => sum + source.text.length, 0);\n }\n return value.sources\n .filter((entry) => entry.state === \"ready\" || entry.state === \"processing\")\n .reduce((sum, entry) => sum + manifestEntryChars(entry), 0);\n}\n","/**\n * How the AI gets a Source — THE one source of truth for delivery.\n *\n * The frozen contract (`SourceRef.delivery`, `@ai-matrx/agents/sources`) has\n * two values and a default: absent / \"direct\" = the text is handed to the AI\n * with the request; \"context\" = nothing is sent up front and the AI opens the\n * Source while it works. The server (aidream `source_resolution.py`) reads\n * exactly this field and nothing else — `promote` / `exclude` are NOT read on\n * the Source path.\n *\n * Every screen that shows or changes delivery (the Source card, \"Review what\n * goes in\", the planner) reads it through `sourceDelivery` and says it with\n * `DELIVERY_WORDS`, so a card can never say one thing while the review and the\n * request say another (V1-A: the card said \"Nothing is copied in\" — chat's\n * attachment editor's wording — while the review said \"Include the text\" and\n * the request carried the text).\n */\n\nimport type { SourceDelivery, SourceRef, SourceRefOptions } from \"../index\";\n\nexport type { SourceDelivery };\n\n/** The delivery a pointer asks for — absent means the contract default, \"direct\". */\nexport function sourceDelivery(ref: Pick<SourceRef, \"delivery\"> | null | undefined): SourceDelivery {\n return ref?.delivery === \"context\" ? \"context\" : \"direct\";\n}\n\n/**\n * The patch that sets a delivery. \"direct\" is the default, so it clears the\n * field (the wire stays minimal, exactly as the review has always written it).\n * Looking a Source up sends no text, so parts and a size limit no longer apply.\n */\nexport function deliveryPatch(\n delivery: SourceDelivery,\n): Pick<SourceRefOptions, \"delivery\" | \"include_segments\" | \"max_chars\"> {\n return delivery === \"context\"\n ? { delivery: \"context\", include_segments: undefined, max_chars: undefined }\n : { delivery: undefined };\n}\n\nexport interface DeliveryWords {\n /** The choice's name on a control. */\n label: string;\n /** Two or three words under the control: what happens (copy law R9). */\n hint: string;\n /** The short phrase a summary line uses. */\n summary: string;\n}\n\nexport const DELIVERY_WORDS: Record<SourceDelivery, DeliveryWords> = {\n direct: {\n label: \"Include the text\",\n hint: \"Sent in full\",\n summary: \"Text included\",\n },\n context: {\n label: \"Let the AI look it up\",\n hint: \"Read as needed\",\n summary: \"Looked up when needed\",\n },\n};\n\n/** The choices, in the order every control shows them. */\nexport const DELIVERY_CHOICES: ReadonlyArray<{ value: SourceDelivery } & DeliveryWords> = (\n [\"direct\", \"context\"] as const\n).map((value) => ({ value, ...DELIVERY_WORDS[value] }));\n\n/**\n * What a HOST can use. Not every host can take every delivery: a generator\n * that needs the text up front (flashcards' segmented generator reads the\n * resolved text and nothing else) gets NOTHING from a Source set to \"look it\n * up\" — V2 verifier shots 06/26: the request went out with `delivery:\n * \"context\"` and the page said \"None of the Sources had any text\", which was\n * false. So a host declares the deliveries it can use (`SourceInputProps.\n * deliveries`); the card and the review offer only those, and a Source already\n * set to something the host cannot use is switched back — with a note on it.\n * Omitted = both (a host whose AI can open Sources while it works).\n */\nexport function allowedDeliveries(\n deliveries: readonly SourceDelivery[] | undefined,\n): readonly SourceDelivery[] {\n const allowed = ([\"direct\", \"context\"] as const).filter((d) => !deliveries || deliveries.includes(d));\n // A host that lists nothing it can use still gets the contract default.\n return allowed.length > 0 ? allowed : [\"direct\"];\n}\n\n/** The choices one host offers, in the order every control shows them. */\nexport function deliveryChoicesFor(\n deliveries: readonly SourceDelivery[] | undefined,\n): ReadonlyArray<{ value: SourceDelivery } & DeliveryWords> {\n const allowed = allowedDeliveries(deliveries);\n return DELIVERY_CHOICES.filter((c) => allowed.includes(c.value));\n}\n\n/** The sentence a switched-back Source carries — every intervention announces itself. */\nexport function deliverySwitchedNote(to: SourceDelivery): string {\n return to === \"direct\"\n ? `This Source was set to \"${DELIVERY_WORDS.context.label}\", which this page cannot use — it needs the text up front — so it was switched back to \"${DELIVERY_WORDS.direct.label}\".`\n : `This Source was set to \"${DELIVERY_WORDS.direct.label}\", which this page cannot use, so it was switched to \"${DELIVERY_WORDS.context.label}\".`;\n}\n\n/**\n * Fit a pointer to what the host can use. Returns the patch to apply (null\n * when it already fits) and the delivery it lands on.\n */\nexport function fitDelivery(\n ref: Pick<SourceRef, \"delivery\"> | null | undefined,\n deliveries: readonly SourceDelivery[] | undefined,\n): { patch: ReturnType<typeof deliveryPatch>; to: SourceDelivery } | null {\n if (!ref) return null;\n const allowed = allowedDeliveries(deliveries);\n const current = sourceDelivery(ref);\n if (allowed.includes(current)) return null;\n const to = allowed[0]!;\n return { patch: deliveryPatch(to), to };\n}\n","/**\n * Finding a part of a Source — THE one matcher, used by the Source card's\n * \"Choose parts\" and by \"Review what goes in\".\n *\n * A query is one of:\n * - a page number (\"12\") — the part that covers that page;\n * - a page range (\"3-10\", \"3–10\", \"3 to 10\") — every part inside it;\n * - words — every word must appear in the part's label or its preview (the\n * opening words the manifest carries, contract amendment A5), matched here;\n * or the part is one the server found holding every word in its full text\n * (`POST /sources/parts/search`, via `useSourcePartsSearch`).\n *\n * A part spanning several pages (\"Pages 22–24\") covers each of them: the\n * manifest's numeric `page` is its first page and the label names the span.\n *\n * V1-A: the search promised \"words\" but matched only labels, so\n * \"photosynthesis\" found nothing in a biology course.\n */\n\nimport type { SourceManifestSegment } from \"../index\";\n\n/** A manifest part, with the A5 preview (optional on the wire). */\nexport type SourcePart = SourceManifestSegment & { preview?: string };\n\n/** The ids of parts the server found holding every word (`useSourcePartsSearch`). */\nexport type PartMatchIds = ReadonlySet<string>;\n\nconst RANGE_RE = /^(\\d+)\\s*(?:-|–|—|to)\\s*(\\d+)$/;\nconst SPAN_RE = /(\\d+)\\s*[–—-]\\s*(\\d+)/;\n\n/** The pages a part covers: its label's span (\"Pages 22–24\") or its one page. */\nexport function partPages(part: SourcePart): [number, number] | null {\n if (part.page === undefined || part.page === null) return null;\n const span = /^pages?\\s/i.test(part.label) ? SPAN_RE.exec(part.label) : null;\n if (span) return [Number(span[1]), Number(span[2])];\n return [part.page, part.page];\n}\n\n/** True when a query is words (not a page or a range) — only then is the text searched. */\nexport function isWordQuery(query: string): boolean {\n const q = query.trim().toLowerCase();\n return q.length > 0 && !/^\\d+$/.test(q) && !RANGE_RE.test(q);\n}\n\nfunction normalise(text: string): string {\n return text.toLowerCase().replace(/\\s+/g, \" \");\n}\n\nexport function matchesPart(part: SourcePart, query: string, serverMatches?: PartMatchIds): boolean {\n const q = query.trim().toLowerCase();\n if (!q) return true;\n const pages = partPages(part);\n const range = RANGE_RE.exec(q);\n if (range && pages) {\n const from = Math.min(Number(range[1]), Number(range[2]));\n const to = Math.max(Number(range[1]), Number(range[2]));\n return pages[0] <= to && pages[1] >= from;\n }\n if (/^\\d+$/.test(q) && pages) {\n const n = Number(q);\n return pages[0] <= n && n <= pages[1];\n }\n if (part.id.toLowerCase() === q) return true;\n if (serverMatches?.has(part.id)) return true;\n const haystack = normalise([part.label, part.preview ?? \"\"].join(\" \"));\n return q\n .split(/\\s+/)\n .filter(Boolean)\n .every((word) => haystack.includes(word));\n}\n\n/** The parts a query shows, in the Source's own order. */\nexport function findParts<T extends SourcePart>(\n parts: readonly T[],\n query: string,\n serverMatches?: PartMatchIds,\n): T[] {\n return parts.filter((p) => matchesPart(p, query, serverMatches));\n}\n","/**\n * What a Source that was still landing becomes when the page reloads.\n *\n * Never lose input (table stakes): the pasted text, the link, or an\n * already-uploaded recording is kept in the draft (`SourceDraft.input`), so\n * the input picks it up again by itself — the landing door dedupes by content\n * hash, so landing it a second time reuses the same Source, never a copy.\n * A file that was mid-upload cannot come back (its bytes lived only in the\n * browser tab); the card says so honestly and keeps the file's name so the\n * person can choose it again in one click.\n */\n\nimport type { SourceDraft, SourceIntakeInput } from \"./types\";\n\n/** Shown while a kept input is being landed again after a reload. */\nexport const RELOADED_RESUMING =\n \"The page reloaded while this was being added — picking it up again.\";\n\n/** A kept input exists but has not been re-landed (it will be, or the person can press Try again). */\nexport const RELOADED_WHILE_ADDING =\n \"This was still being added when the page reloaded, so it did not finish. Add it again.\";\n\n/** The kinds whose landing can be repeated from what the draft kept. */\nexport function resumableInput(draft: SourceDraft): SourceIntakeInput | null {\n const input = draft.input;\n if (!input) return null;\n switch (draft.kind) {\n case \"paste\":\n return input.text?.trim() ? input : null;\n case \"web\":\n case \"youtube\":\n return input.url?.trim() ? input : null;\n case \"audio\":\n // An uploaded recording re-transcribes from its file; one recorded in\n // place (the Voice Pad) is already text and lands again from it.\n return input.fileId || input.text?.trim() ? input : null;\n default:\n return null;\n }\n}\n\n/** The sentence for a file whose upload the reload cut off. */\nexport function uploadCutOffSentence(draft: SourceDraft): string {\n return `\"${draft.label}\" was still uploading when the page reloaded, so it did not arrive. Choose it again to add it.`;\n}\n\nexport interface ReloadedCard {\n /** \"resume\" = land the kept input again now; \"reoffer\" = the person must re-choose a file. */\n action: \"resume\" | \"reoffer\" | \"lost\";\n sentence: string;\n}\n\n/**\n * The one decision: a card that was `pending`/`resolving` when the page\n * unloaded. Cards in any other state are restored unchanged (returns null).\n */\nexport function reloadedCard(\n draft: SourceDraft,\n status: \"pending\" | \"resolving\" | \"ready\" | \"error\",\n): ReloadedCard | null {\n if (status !== \"pending\" && status !== \"resolving\") return null;\n if (resumableInput(draft)) return { action: \"resume\", sentence: RELOADED_RESUMING };\n if (draft.kind === \"upload\" || draft.kind === \"image\" || draft.kind === \"audio\")\n return { action: \"reoffer\", sentence: uploadCutOffSentence(draft) };\n return { action: \"lost\", sentence: RELOADED_WHILE_ADDING };\n}\n\n/**\n * The knob for the largest pasted text kept in the device draft (it would\n * crowd the draft store). Read by the intake; while unread nothing is kept and\n * the card says so.\n */\nexport const MAX_KEPT_TEXT_KNOB = { feature: \"sources\", key: \"max_kept_draft_chars\" } as const;\n\n/** Said on a pasted card whose text is too large (or the limit unreadable) to keep for a reload. */\nexport const NOT_KEPT_FOR_RELOAD =\n \"Too large to restore if the page reloads before it is added.\";\n\n/**\n * A landing stopped only because no organization is chosen yet. The card\n * waits; the moment one is set the intake lands every waiting card again from\n * what its draft kept (state, never an in-memory queue — it survives a reload).\n */\nexport const WAITING_FOR_ORGANIZATION =\n \"Waiting for an organization — choose one and this continues by itself.\";\n\n/** A read Source whose keep waits for an organization; kept again once one is set. */\nexport const KEEP_WAITING_FOR_ORGANIZATION =\n \"Read. Waiting for an organization to keep it — choose one and it is kept by itself.\";\n","/**\n * fileSource — how a stored file on a Source card becomes its Source, decided\n * from the SERVER's state alone (USI-3e). Pure: the one read\n * (`/files/{id}/rag-status`) and the file's own organization are INJECTED by\n * the host (`SourceFileState` below), never imported.\n *\n * The server owns reading a file: every upload's finalize already starts the\n * one processing run (the file adapters → a `processed_documents` row), and\n * `/files/{id}/rag-status` merges that run's lifecycle row with the Source it\n * made. So a card never starts its own run while one is live, a reload simply\n * reads the state again (re-attach, never a second job), and a file someone\n * already had (\"use the one you already have\", or picked from Files) is kept\n * the moment its existing Source is seen.\n */\n\nimport type { SourceCardModel } from \"./types\";\n\n/** The part of the server's `/files/{id}/rag-status` answer the decision reads. */\nexport interface FileSourceStatus {\n state: string;\n processed_document_id?: string | null | undefined;\n error?: { message?: string | null | undefined; [detail: string]: unknown } | null | undefined;\n}\n\nexport type FileSourceStep =\n /** The Source exists: keep it and file it against the thing being made. */\n | { do: \"keep\"; processedDocumentId: string }\n /** A run is reading it now (server-side or this tab's own). Look again soon. */\n | { do: \"wait\" }\n /** Nothing is reading it and it has no Source yet: start the one run. */\n | { do: \"start\" }\n /** It cannot become a Source; say why, and stop looking. */\n | { do: \"unreadable\"; reason: string };\n\nexport interface FileSourceContext {\n /** This card already started a run in this page's life. */\n started: boolean;\n /** This tab's processing runner has a live run for the file. */\n localRunning: boolean;\n}\n\nconst UNREADABLE = \"Can't read this file — add a PDF, Word or text copy.\";\n\n/** The one decision. `status` is the server's `/files/{id}/rag-status` answer. */\nexport function nextFileStep(\n status: FileSourceStatus | null,\n ctx: FileSourceContext,\n): FileSourceStep {\n const pdId = status?.processed_document_id ?? null;\n if (pdId) return { do: \"keep\", processedDocumentId: pdId };\n if (ctx.localRunning || status?.state === \"running\") return { do: \"wait\" };\n if (status?.state === \"failed\")\n return {\n do: \"unreadable\",\n reason: status.error?.message\n ? `Can't read this file: ${status.error.message}. Add it again.`\n : UNREADABLE,\n };\n if (!ctx.started) return { do: \"start\" };\n return { do: \"unreadable\", reason: UNREADABLE };\n}\n\n/** How long to wait before looking again: quick at first, then spaced out. */\nexport function fileSourcePollDelayMs(round: number): number {\n if (round < 5) return 3_000;\n if (round < 20) return 6_000;\n return 15_000;\n}\n\n/** A stored file on a card whose Source is not known yet — the recovery reads its state. */\nexport function isWaitingFileCard(card: SourceCardModel): boolean {\n return (\n card.status === \"ready\" &&\n card.draft.ref?.resource_type === \"file\" &&\n !!card.draft.fileId &&\n !card.draft.processedDocumentId\n );\n}\n\n/**\n * True while a waiting file card cannot be asked about yet: `/files/{id}/\n * rag-status` answers only with an organization (the file's own, when the\n * host knows it, or the one the person picked). Without one every read was a\n * refused 400 — every ~3 s, piling up as page errors (V2-F #3). So the card\n * is HELD: it says it is waiting for an organization, offers the one picker,\n * and nothing is asked until one is known.\n *\n * `fileOrganizationId` is the host's lookup of a file's own organization\n * (omitted = the host does not know it).\n */\nexport function fileCardHeldForOrganization(\n card: SourceCardModel,\n activeOrganizationId: string | null | undefined,\n fileOrganizationId?: (fileId: string) => string | null | undefined,\n): boolean {\n if (!isWaitingFileCard(card)) return false;\n if (activeOrganizationId) return false;\n return !fileOrganizationId?.(card.draft.fileId as string);\n}\n","/**\n * The source-list state machine — pure reducers and selectors over\n * `SourceSetState`. Every function returns a NEW state (or the same one when\n * nothing changed) and never touches a store, a network or a clock; the\n * controller (`controller.ts`) applies them through the host's store adapter.\n *\n * The rules here are the ones the web app's Source input has always kept:\n * - landing the same Source twice keeps ONE card and says so on it;\n * - a settled card drops the input it kept for a reload;\n * - a card cut off mid-landing by a reload is restored as an error the\n * input resolves (`interrupted.ts`), never a spinner forever;\n * - a new Source starts on the host's default form.\n */\n\nimport {\n createSourceRef,\n createSourceSet,\n totalChars as sumChars,\n type ResolvedSourceSet,\n type SourceManifest,\n type SourceManifestEntry,\n type SourceRef,\n type SourceRefOptions,\n type SourceSet,\n} from \"../index\";\nimport { deliverySwitchedNote, fitDelivery, type SourceDelivery } from \"./delivery\";\nimport { reloadedCard, WAITING_FOR_ORGANIZATION } from \"./interrupted\";\nimport { partPages } from \"./partsSearch\";\nimport type {\n PersistedSourceCard,\n PersistedSourceInput,\n SourceCardModel,\n SourceDraft,\n SourcePickedPart,\n SourceSetState,\n} from \"./types\";\n\nexport const EMPTY_SOURCE_SET_STATE: SourceSetState = Object.freeze({ cards: Object.freeze([]), topic: \"\" }) as SourceSetState;\n\n/** Said when a Source's parts were re-read (the clean version landed) and the pick was carried over by page. */\nexport const PARTS_MATCHED_BY_PAGE = \"The clean version is ready — your parts were matched to it by page.\";\n\n/** Said when a pick could not be carried over to the Source's new parts: the whole Source goes in until parts are chosen again. */\nexport const PARTS_NOT_MATCHED =\n \"The clean version is ready, but your parts could not be matched to it — choose parts again. Until then the whole Source goes in.\";\n\n/** Said on the one card kept when the same Source lands twice. */\nexport const SAME_SOURCE_AGAIN = \"You added this again — it is the same Source, so it is listed once.\";\n\nexport function isSourceDraft(value: unknown): value is SourceDraft {\n return (\n !!value &&\n typeof value === \"object\" &&\n typeof (value as SourceDraft).kind === \"string\" &&\n typeof (value as SourceDraft).label === \"string\"\n );\n}\n\nexport function sameSourceRef(\n a: Pick<SourceRef, \"resource_type\" | \"resource_id\">,\n b: Pick<SourceRef, \"resource_type\" | \"resource_id\">,\n): boolean {\n return a.resource_type === b.resource_type && a.resource_id === b.resource_id;\n}\n\n/** \"<resource_type>:<resource_id>\" — how a Source is keyed across screens. */\nexport function sourceKey(ref: { resource_type: string; resource_id: string }): string {\n return `${ref.resource_type}:${ref.resource_id}`;\n}\n\n/** The draft kind a registry token is picked as. */\nexport function draftKindForToken(token: string): SourceDraft[\"kind\"] {\n if (token === \"file\") return \"files\";\n if (token === \"note\") return \"notes\";\n if (token === \"processed_document\") return \"your_sources\";\n return \"records\";\n}\n\n/** A new pointer starts on the host's default form (never over one already chosen). */\nexport function withDefaultForm(ref: SourceRef, defaultForm: string | undefined): SourceRef {\n return defaultForm && !ref.representation\n ? createSourceRef(ref.resource_type, ref.resource_id, { ...ref, representation: defaultForm })\n : ref;\n}\n\nfunction cardById(state: SourceSetState, id: string): SourceCardModel | undefined {\n return state.cards.find((c) => c.id === id);\n}\n\nfunction replaceCard(\n state: SourceSetState,\n id: string,\n patch: (card: SourceCardModel) => SourceCardModel,\n): SourceSetState {\n let changed = false;\n const cards = state.cards.map((c) => {\n if (c.id !== id) return c;\n const next = patch(c);\n if (next !== c) changed = true;\n return next;\n });\n return changed ? { ...state, cards } : state;\n}\n\n// ── Reducers ────────────────────────────────────────────────────────────────\n\n/** Add a Source that is already a pointer (a stored record, a landed Source). */\nexport function addReadyCard(\n state: SourceSetState,\n id: string,\n draft: SourceDraft,\n options: { defaultForm?: string | undefined } = {},\n): SourceSetState {\n const ref = draft.ref ? withDefaultForm(draft.ref, options.defaultForm) : null;\n return {\n ...state,\n cards: [...state.cards, { id, draft: { ...draft, ref }, status: \"ready\", error: null, manifest: null }],\n };\n}\n\n/** Add a Source that is still landing; finish it with `settleCard` or `failCard`. */\nexport function addPendingCard(\n state: SourceSetState,\n id: string,\n draft: Omit<SourceDraft, \"ref\">,\n): SourceSetState {\n return {\n ...state,\n cards: [...state.cards, { id, draft: { ...draft, ref: null }, status: \"resolving\", error: null, manifest: null }],\n };\n}\n\n/**\n * A landing answered. The door dedupes by content: landing the same thing\n * twice returns the Source already picked — keep ONE card and say so on it.\n */\nexport function settleCard(\n state: SourceSetState,\n id: string,\n patch: Partial<SourceDraft> & { ref: SourceRef },\n options: { defaultForm?: string | undefined } = {},\n): SourceSetState {\n const card = cardById(state, id);\n if (!card) return state; // removed while it was landing — nothing to finish\n const twin = state.cards.find((c) => c.id !== id && c.draft.ref && sameSourceRef(c.draft.ref, patch.ref));\n if (twin) {\n const without = { ...state, cards: state.cards.filter((c) => c.id !== id) };\n if (twin.draft.notes?.includes(SAME_SOURCE_AGAIN)) return without;\n return replaceCard(without, twin.id, (c) => ({\n ...c,\n draft: { ...c.draft, notes: [...(c.draft.notes ?? []), SAME_SOURCE_AGAIN] },\n }));\n }\n return replaceCard(state, id, (c) => ({\n ...c,\n // Landed: the kept input has done its job and leaves the draft.\n draft: { ...c.draft, ...patch, input: undefined, ref: withDefaultForm(patch.ref, options.defaultForm) },\n status: \"ready\",\n error: null,\n }));\n}\n\n/**\n * A card that failed has ONE state — failed. Its last measurement goes, so it\n * can never also say \"Still being read\" (verify-3: a stored PDF showed both).\n */\nexport function failCard(state: SourceSetState, id: string, sentence: string): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, status: \"error\", error: sentence, manifest: null }));\n}\n\n/** Back to landing (after a reload or a failure). */\nexport function restartCard(state: SourceSetState, id: string): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, status: \"resolving\", error: null }));\n}\n\n/** Change what a card says or keeps (label, input, fileId, notes, processedDocumentId). */\nexport function updateCardDraft(\n state: SourceSetState,\n id: string,\n patch: Partial<Omit<SourceDraft, \"ref\">>,\n): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, draft: { ...c.draft, ...patch } }));\n}\n\nexport function removeCard(state: SourceSetState, id: string): SourceSetState {\n if (!cardById(state, id)) return state;\n return { ...state, cards: state.cards.filter((c) => c.id !== id) };\n}\n\n/** Change the pointer's choices (form, parts, cap, delivery). */\nexport function updateCardRef(state: SourceSetState, id: string, options: SourceRefOptions): SourceSetState {\n return replaceCard(state, id, (c) => {\n if (!c.draft.ref) return c;\n const ref = createSourceRef(c.draft.ref.resource_type, c.draft.ref.resource_id, { ...c.draft.ref, ...options });\n return rememberPickedParts({ ...c, draft: { ...c.draft, ref } });\n });\n}\n\n/**\n * Remember where the picked parts sit (label + pages) from the card's current\n * measurement, so a pick survives the Source being re-split (raw pages → clean\n * parts). No parts picked = nothing remembered.\n */\nexport function rememberPickedParts(card: SourceCardModel): SourceCardModel {\n const ids = card.draft.ref?.include_segments ?? [];\n if (ids.length === 0) {\n return card.draft.pickedParts === undefined ? card : { ...card, draft: { ...card.draft, pickedParts: undefined } };\n }\n const segments = card.manifest?.segments ?? [];\n const known = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));\n const picked: SourcePickedPart[] = [];\n for (const id of ids) {\n const segment = segments.find((s) => s.id === id);\n if (segment) {\n const pages = partPages(segment);\n picked.push({ id, label: segment.label, ...(pages ? { pages } : {}) });\n } else {\n const before = known.get(id);\n if (before) picked.push(before);\n }\n }\n return { ...card, draft: { ...card.draft, pickedParts: picked.length ? picked : undefined } };\n}\n\nfunction withNote(notes: readonly string[] | undefined, note: string, drop: readonly string[] = []): string[] {\n const kept = (notes ?? []).filter((n) => n !== note && !drop.includes(n));\n return [...kept, note];\n}\n\n/**\n * A fresh measurement listed NEW parts (the clean version landed, so the raw\n * pages the person picked no longer exist by id). Carry the pick over by page:\n * every new part that covers a page the old pick covered goes in. When the old\n * pick's pages are unknown, the pick is cleared and the card says so — never\n * \"0 characters · 4 of 21 parts\" with nothing ticked (verify-3, 11d/11e).\n */\nexport function carryPickedParts(card: SourceCardModel, entry: SourceManifestEntry): SourceCardModel {\n const ref = card.draft.ref;\n const picked = ref?.include_segments ?? [];\n const segments = entry.segments ?? [];\n if (!ref || picked.length === 0 || segments.length === 0) return card;\n const ids = new Set(segments.map((s) => s.id));\n const stale = picked.filter((id) => !ids.has(id));\n if (stale.length === 0) return card;\n const remembered = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));\n const oldSegments = card.manifest?.segments ?? [];\n const spans: Array<[number, number]> = [];\n let unknown = 0;\n for (const id of stale) {\n const old = oldSegments.find((s) => s.id === id);\n const pages = remembered.get(id)?.pages ?? (old ? partPages(old) : null);\n if (pages) spans.push(pages);\n else unknown += 1;\n }\n const keep = new Set(picked.filter((id) => ids.has(id)));\n for (const segment of segments) {\n const pages = partPages(segment);\n if (pages && spans.some(([from, to]) => pages[0] <= to && pages[1] >= from)) keep.add(segment.id);\n }\n const nextIds = segments.filter((s) => keep.has(s.id)).map((s) => s.id);\n const matched = unknown === 0 && nextIds.length > 0;\n const nextRef = createSourceRef(ref.resource_type, ref.resource_id, {\n ...ref,\n include_segments: matched ? nextIds : undefined,\n });\n const note = matched ? PARTS_MATCHED_BY_PAGE : PARTS_NOT_MATCHED;\n const other = matched ? PARTS_NOT_MATCHED : PARTS_MATCHED_BY_PAGE;\n return rememberPickedParts({\n ...card,\n manifest: entry,\n draft: { ...card.draft, ref: nextRef, notes: withNote(card.draft.notes, note, [other]) },\n });\n}\n\nexport function setCardWaitForClean(state: SourceSetState, id: string, wait: boolean): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, draft: { ...c.draft, waitForClean: wait } }));\n}\n\nexport function setSourceTopic(state: SourceSetState, topic: string): SourceSetState {\n return state.topic === topic ? state : { ...state, topic };\n}\n\n/** Apply a set the review returned (forms, parts, caps, delivery) — and its topic. */\nexport function applyReviewedSourceSet(state: SourceSetState, set: SourceSet): SourceSetState {\n let next = state;\n for (const card of state.cards) {\n const ref = card.draft.ref;\n if (!ref) continue;\n const match = set.sources.find((r) => sameSourceRef(r, ref));\n if (!match) continue;\n next = replaceCard(next, card.id, (c) => rememberPickedParts({ ...c, draft: { ...c.draft, ref: match } }));\n }\n return set.topic !== undefined ? setSourceTopic(next, set.topic) : next;\n}\n\n/** The server measured the ready Sources: each ready card takes its entry. */\nexport function applyManifest(state: SourceSetState, manifest: SourceManifest): SourceSetState {\n let next = state;\n for (const card of state.cards) {\n const ref = card.draft.ref;\n if (!ref || card.status !== \"ready\") continue;\n const entry = manifest.sources.find((e) => sameSourceRef(e.ref, ref));\n if (!entry) continue;\n next = replaceCard(next, card.id, (c) => {\n const carried = carryPickedParts(c, entry);\n if (carried !== c) return carried;\n const measured = { ...c, manifest: entry };\n // Parts picked before their pages were known are remembered now.\n return c.draft.ref?.include_segments?.length && !c.draft.pickedParts ? rememberPickedParts(measured) : measured;\n });\n }\n return next;\n}\n\n/**\n * Only what the host can use (V2-F #1): a Source set to a delivery this surface\n * cannot use (picked elsewhere, restored from a draft, handed in by a link) is\n * switched back, and its card says so. Never a choice that cannot work.\n */\nexport function fitCardDeliveries(\n state: SourceSetState,\n deliveries: readonly SourceDelivery[] | undefined,\n): SourceSetState {\n let next = state;\n for (const card of state.cards) {\n const fit = fitDelivery(card.draft.ref, deliveries);\n if (!fit) continue;\n next = updateCardRef(next, card.id, fit.patch);\n const note = deliverySwitchedNote(fit.to);\n if (!card.draft.notes?.includes(note))\n next = updateCardDraft(next, card.id, { notes: [...(card.draft.notes ?? []), note] });\n }\n return next;\n}\n\n// ── Persistence (a draft store keeps this for a reload) ─────────────────────\n\n/** Read whatever a draft store handed back; anything malformed is dropped. */\nexport function readPersistedSourceInput(data: unknown): PersistedSourceInput {\n const record = data && typeof data === \"object\" ? (data as Record<string, unknown>) : undefined;\n const sources = Array.isArray(record?.sources)\n ? (record.sources as PersistedSourceCard[]).filter(\n (c) => !!c && typeof c.id === \"string\" && isSourceDraft(c.draft),\n )\n : [];\n return { sources, topic: typeof record?.topic === \"string\" ? record.topic : \"\" };\n}\n\nexport function toPersistedSourceInput(state: SourceSetState): PersistedSourceInput {\n return {\n sources: state.cards.map((c) => ({ id: c.id, draft: c.draft, status: c.status, error: c.error })),\n topic: state.topic,\n };\n}\n\n/**\n * The cards a reload brings back. A card cut off mid-landing becomes an error\n * the input resolves (it re-lands the kept input, or asks for the file again)\n * — never a spinner forever. A landing held for an organization lost its hold\n * with the page: it is picked up again like one cut off mid-landing.\n */\nexport function restoredCards(persisted: PersistedSourceInput): SourceCardModel[] {\n return persisted.sources.map((card) => {\n const reloaded = reloadedCard(\n card.draft,\n card.status === \"error\" && card.error === WAITING_FOR_ORGANIZATION ? \"resolving\" : card.status,\n );\n return {\n id: card.id,\n draft: card.draft,\n status: reloaded ? \"error\" : card.status,\n error: reloaded ? reloaded.sentence : (card.error ?? null),\n manifest: null,\n };\n });\n}\n\n// ── Selectors ───────────────────────────────────────────────────────────────\n\nexport function readySourceRefs(state: SourceSetState): SourceRef[] {\n return state.cards.flatMap((c) => (c.status === \"ready\" && c.draft.ref ? [c.draft.ref] : []));\n}\n\nexport function hasSourceRef(state: SourceSetState, resourceType: string, resourceId: string): boolean {\n return state.cards.some(\n (c) => c.draft.ref?.resource_type === resourceType && c.draft.ref.resource_id === resourceId,\n );\n}\n\n/** The frozen v1 payload, built from the ready Sources. */\nexport function selectSourceSet(\n state: SourceSetState,\n options: { targetModelId?: string | undefined } = {},\n): SourceSet {\n const topic = state.topic.trim();\n return createSourceSet(readySourceRefs(state), {\n topic: topic || undefined,\n grounding: \"whole\",\n target_model_id: options.targetModelId,\n });\n}\n\n/**\n * THE one size rule (the contract's `totalChars`): the chosen form, or the\n * picked parts, capped — measured against each card's CURRENT pointer.\n */\nexport function selectTotalChars(state: SourceSetState): number {\n const measured: SourceManifestEntry[] = state.cards.flatMap((c) =>\n c.status === \"ready\" && c.manifest && c.draft.ref ? [{ ...c.manifest, ref: c.draft.ref }] : [],\n );\n if (!measured.length) return 0;\n return sumChars({\n __kind: \"source_manifest\",\n sources: measured,\n total_chars: 0,\n estimated_tokens: 0,\n model_context_tokens: null,\n });\n}\n\n/**\n * THE one size of one Source (verify-3: one Source read 109k, 115k, 108k and\n * 106k on four screens): the contract's rule — the chosen form, or the picked\n * parts, capped by `max_chars` — measured against the card's CURRENT pointer.\n * The card, the header total (`selectTotalChars`) and the review (`SourcePlanEntry.chars`)\n * all read this. Null when it is not measured or cannot go in.\n */\nexport function sourceEntryChars(entry: SourceManifestEntry, ref: SourceRef): number | null {\n if (entry.state !== \"ready\" && entry.state !== \"processing\") return null;\n return sumChars({\n __kind: \"source_manifest\",\n sources: [{ ...entry, ref }],\n total_chars: 0,\n estimated_tokens: 0,\n model_context_tokens: null,\n });\n}\n\nexport function sourceCardChars(card: Pick<SourceCardModel, \"draft\" | \"manifest\">): number | null {\n return card.manifest && card.draft.ref ? sourceEntryChars(card.manifest, card.draft.ref) : null;\n}\n\n/**\n * THE one state of one Source card, derived once: its own lifecycle wins\n * (adding, waiting for an organization, failed); only a card that landed takes\n * the server's measured state. Never two states at once.\n */\nexport type SourceCardState =\n | \"adding\"\n | \"waiting_for_organization\"\n | \"failed\"\n | \"unmeasured\"\n | SourceManifestEntry[\"state\"];\n\nexport function sourceCardState(card: Pick<SourceCardModel, \"status\" | \"error\" | \"manifest\">): SourceCardState {\n if (card.status === \"pending\" || card.status === \"resolving\") return \"adding\";\n if (card.status === \"error\") return card.error === WAITING_FOR_ORGANIZATION ? \"waiting_for_organization\" : \"failed\";\n return card.manifest?.state ?? \"unmeasured\";\n}\n\n/** The server's measured state to show on a card — only for a card that landed (null otherwise). */\nexport function sourceCardMeasuredState(\n card: Pick<SourceCardModel, \"status\" | \"error\" | \"manifest\">,\n): SourceManifestEntry[\"state\"] | null {\n return card.status === \"ready\" ? (card.manifest?.state ?? null) : null;\n}\n\n/** Every Source finished landing (nothing pending) and none failed. */\nexport function selectSettled(state: SourceSetState): boolean {\n return state.cards.every((c) => c.status === \"ready\");\n}\n\n/** How many more Sources fit under the host's max (Infinity when there is none). */\nexport function sourceRoomLeft(state: SourceSetState, max: number | undefined): number {\n return max === undefined ? Number.POSITIVE_INFINITY : Math.max(0, max - state.cards.length);\n}\n\n/**\n * Every generator names a Source the way the person saw it on its card — the\n * file name, the name they gave pasted text — never the stored document's own\n * title (V2-F #5). The server's label stays only for a Source the input does\n * not hold.\n */\nexport function withDisplayNames(\n resolved: ResolvedSourceSet,\n cards: readonly Pick<SourceCardModel, \"draft\">[],\n): ResolvedSourceSet {\n const names = new Map<string, string>();\n for (const c of cards) {\n const label = c.draft.label?.trim();\n if (c.draft.ref && label) names.set(sourceKey(c.draft.ref), label);\n }\n return {\n ...resolved,\n sources: resolved.sources.map((s) => {\n const name = names.get(sourceKey(s.ref));\n return name ? { ...s, label: name } : s;\n }),\n };\n}\n","/**\n * The Source-set controller — the imperative face of the state machine, with\n * every outside dependency injected through one adapter:\n *\n * - `store` where the cards live (a Redux slice, a Zustand store, the\n * in-memory store below — the host's choice);\n * - `persistence` the draft store a reload reads back (optional);\n * - `client` the Source doors (`createSourcesClient(transport)`);\n * - `config` the host's choices: default form, organization, the\n * deliveries it can use, the most Sources it takes.\n *\n * Every screen (the Studio grid, a compact strip, chat's \"+\", the review)\n * drives the SAME controller; `@ai-matrx/agents/sources/react` binds it to\n * React with `useSourceSet(adapter)`.\n */\n\nimport {\n createSourceSet,\n type ResolvedSourceSet,\n type SourceManifest,\n type SourceRef,\n type SourceRefOptions,\n type SourceSet,\n} from \"../index\";\nimport type { SourcesClient } from \"./client\";\nimport type { SourceDelivery } from \"./delivery\";\nimport {\n addPendingCard,\n addReadyCard,\n applyManifest,\n applyReviewedSourceSet,\n EMPTY_SOURCE_SET_STATE,\n failCard,\n fitCardDeliveries,\n hasSourceRef,\n readPersistedSourceInput,\n readySourceRefs,\n removeCard,\n restartCard,\n restoredCards,\n selectSettled,\n selectSourceSet,\n selectTotalChars,\n setCardWaitForClean,\n setSourceTopic,\n settleCard,\n sourceRoomLeft,\n toPersistedSourceInput,\n updateCardDraft,\n updateCardRef,\n withDisplayNames,\n} from \"./state\";\nimport type { PersistedSourceInput, SourceCardModel, SourceDraft, SourceSetState } from \"./types\";\n\n/** Where the cards live. `getState` must return the SAME object until something changes. */\nexport interface SourceSetStore {\n getState(): SourceSetState;\n setState(next: SourceSetState): void;\n subscribe(listener: () => void): () => void;\n /** Called once when a screen mounts (a store that registers entries lazily). */\n init?: (() => void) | undefined;\n}\n\n/** The draft store a reload reads back. `load` returns the raw saved value (stable until it changes). */\nexport interface SourceDraftStorage {\n load(): unknown;\n save(value: PersistedSourceInput): void;\n subscribe?: ((listener: () => void) => () => void) | undefined;\n}\n\nexport interface SourceSetConfig {\n /** The form each new Source starts on (\"clean\" | \"raw\"). Omitted = the server's choice. */\n defaultForm?: string | undefined;\n /** The organization named on the door calls (they answer without one too). */\n organizationId?: string | null | undefined;\n /** How the AI may get the Sources on this surface. Omitted = both. */\n deliveries?: readonly SourceDelivery[] | undefined;\n /** Most Sources the person may pick. Omitted = no limit. */\n max?: number | undefined;\n}\n\nexport interface SourceSetAdapter {\n store: SourceSetStore;\n persistence?: SourceDraftStorage | undefined;\n /** Needed for `manifest()` and `resolve()`. */\n client?: SourcesClient | undefined;\n config?: SourceSetConfig | undefined;\n /** A new card's id (default: a random UUID). */\n createId?: (() => string) | undefined;\n /** A failed call as one sentence with its remedy (default: the error's message). */\n describeError?: ((error: unknown) => string) | undefined;\n}\n\n/** The measurement's own state (not persisted, not shared across controllers). */\nexport interface SourceSetMeta {\n measuring: boolean;\n /** Why the measurement failed, with its remedy. */\n manifestError: string | null;\n}\n\n/** The mutations every intake and screen drives. */\nexport interface SourceSetActions {\n /** Add a Source that is already a pointer (a stored record, a landed Source). */\n addReady(draft: SourceDraft): string;\n /** Add a Source that is still landing; finish it with `settle` or `fail`. */\n addPending(draft: Omit<SourceDraft, \"ref\">): string;\n settle(id: string, patch: Partial<SourceDraft> & { ref: SourceRef }): void;\n fail(id: string, sentence: string): void;\n /** Back to landing. False when the card is gone (removed) — nothing to land. */\n restart(id: string): boolean;\n /** Change what a card that is still landing says or keeps (label, input, fileId, notes). */\n updateDraft(id: string, patch: Partial<Omit<SourceDraft, \"ref\">>): void;\n remove(id: string): void;\n /** Change the pointer's choices (form, parts, cap, delivery). */\n updateRef(id: string, options: SourceRefOptions): void;\n setWaitForClean(id: string, wait: boolean): void;\n setTopic(topic: string): void;\n /** True when this pointer is already picked. */\n hasRef(resourceType: string, resourceId: string): boolean;\n /** How many Sources are picked RIGHT NOW (read from the store, never a stale render). */\n liveCount(): number;\n /** POST /sources/manifest for the ready Sources; cards update with it. */\n manifest(): Promise<SourceManifest | null>;\n}\n\nexport interface SourceSetController extends SourceSetActions {\n getState(): SourceSetState;\n subscribe(listener: () => void): () => void;\n getMeta(): SourceSetMeta;\n subscribeMeta(listener: () => void): () => void;\n /** Replace the host's choices (called on every render by a React binding). */\n configure(config: SourceSetConfig): void;\n readonly config: SourceSetConfig;\n /** Bring back a saved draft once — only into an empty input. True when it restored. */\n restore(saved: unknown): boolean;\n /** The frozen v1 payload, built from the ready Sources. */\n toSourceSet(options?: { targetModelId?: string | undefined }): SourceSet;\n /** Apply a set the review returned (forms, parts, caps, delivery). */\n applySourceSet(set: SourceSet): void;\n /** POST /sources/resolve — the grounded text for a generator, named as the cards name them. */\n resolve(options?: { targetModelId?: string | undefined }): Promise<ResolvedSourceSet>;\n /** Switch back any Source set to a delivery the host cannot use (with a note). */\n fitDeliveries(deliveries?: readonly SourceDelivery[]): void;\n /** How many more Sources fit under the host's max. */\n roomLeft(): number;\n totalChars(): number;\n settled(): boolean;\n}\n\nfunction randomId(): string {\n const cryptoApi = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();\n return `src-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** An in-memory store — for clients without their own, and for tests. */\nexport function createMemorySourceSetStore(initial: SourceSetState = EMPTY_SOURCE_SET_STATE): SourceSetStore {\n let state = initial;\n const listeners = new Set<() => void>();\n return {\n getState: () => state,\n setState(next) {\n if (next === state) return;\n state = next;\n for (const listener of [...listeners]) listener();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\n/** An in-memory draft store (a stand-in for device storage in tests and previews). */\nexport function createMemorySourceDraftStorage(initial: unknown = undefined): SourceDraftStorage & {\n current(): unknown;\n} {\n let saved: unknown = initial;\n const listeners = new Set<() => void>();\n return {\n load: () => saved,\n save(value) {\n saved = value;\n for (const listener of [...listeners]) listener();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n current: () => saved,\n };\n}\n\nexport function createSourceSetController(adapter: SourceSetAdapter): SourceSetController {\n const { store, persistence } = adapter;\n let config: SourceSetConfig = { ...(adapter.config ?? {}) };\n const createId = adapter.createId ?? randomId;\n const describe = adapter.describeError ?? errorText;\n let meta: SourceSetMeta = { measuring: false, manifestError: null };\n const metaListeners = new Set<() => void>();\n let hydrated = false;\n /** The newest measurement wins: an older answer never overwrites a newer one. */\n let measurement: AbortController | null = null;\n\n const setMeta = (patch: Partial<SourceSetMeta>) => {\n const next = { ...meta, ...patch };\n if (next.measuring === meta.measuring && next.manifestError === meta.manifestError) return;\n meta = next;\n for (const listener of [...metaListeners]) listener();\n };\n\n /** Apply a reducer's result and write the draft (explicit persistence). */\n const commit = (next: SourceSetState) => {\n hydrated = true;\n if (next !== store.getState()) store.setState(next);\n persistence?.save(toPersistedSourceInput(store.getState()));\n };\n\n const has = (id: string) => store.getState().cards.some((c) => c.id === id);\n\n const controller: SourceSetController = {\n getState: () => store.getState(),\n subscribe: (listener) => store.subscribe(listener),\n getMeta: () => meta,\n subscribeMeta(listener) {\n metaListeners.add(listener);\n return () => metaListeners.delete(listener);\n },\n configure(next) {\n config = { ...next };\n },\n get config() {\n return config;\n },\n\n restore(saved) {\n if (hydrated) return false;\n const live = store.getState();\n if (live.cards.length > 0) {\n hydrated = true;\n return false;\n }\n const persisted = readPersistedSourceInput(saved);\n if (persisted.sources.length === 0) return false;\n hydrated = true;\n store.setState({ cards: restoredCards(persisted), topic: live.topic || persisted.topic });\n return true;\n },\n\n addReady(draft) {\n const id = createId();\n commit(addReadyCard(store.getState(), id, draft, { defaultForm: config.defaultForm }));\n return id;\n },\n addPending(draft) {\n const id = createId();\n commit(addPendingCard(store.getState(), id, draft));\n return id;\n },\n settle(id, patch) {\n if (!has(id)) return;\n commit(settleCard(store.getState(), id, patch, { defaultForm: config.defaultForm }));\n },\n fail(id, sentence) {\n if (!has(id)) return;\n commit(failCard(store.getState(), id, sentence));\n },\n restart(id) {\n if (!has(id)) return false;\n commit(restartCard(store.getState(), id));\n return true;\n },\n updateDraft(id, patch) {\n if (!has(id)) return;\n commit(updateCardDraft(store.getState(), id, patch));\n },\n remove(id) {\n commit(removeCard(store.getState(), id));\n },\n updateRef(id, options) {\n if (!store.getState().cards.find((c) => c.id === id)?.draft.ref) return;\n commit(updateCardRef(store.getState(), id, options));\n },\n setWaitForClean(id, wait) {\n if (!has(id)) return;\n commit(setCardWaitForClean(store.getState(), id, wait));\n },\n setTopic(topic) {\n commit(setSourceTopic(store.getState(), topic));\n },\n hasRef: (resourceType, resourceId) => hasSourceRef(store.getState(), resourceType, resourceId),\n liveCount: () => store.getState().cards.length,\n\n toSourceSet: (options = {}) => selectSourceSet(store.getState(), options),\n applySourceSet(set) {\n commit(applyReviewedSourceSet(store.getState(), set));\n },\n\n async manifest() {\n const refs = readySourceRefs(store.getState());\n if (refs.length === 0) {\n setMeta({ manifestError: null });\n return null;\n }\n if (!adapter.client) throw new Error(\"createSourceSetController: manifest() needs a client in the adapter\");\n measurement?.abort();\n const controllerForThis = new AbortController();\n measurement = controllerForThis;\n setMeta({ measuring: true });\n try {\n const result = await adapter.client.manifest(createSourceSet(refs), {\n organizationId: config.organizationId ?? undefined,\n signal: controllerForThis.signal,\n });\n if (measurement !== controllerForThis) return null;\n const next = applyManifest(store.getState(), result);\n if (next !== store.getState()) store.setState(next);\n setMeta({ manifestError: null });\n return result;\n } catch (err) {\n // A superseded measurement was cancelled on purpose — not a failure.\n if (measurement !== controllerForThis) return null;\n setMeta({\n manifestError: `Sizes and parts could not be read: ${describe(err)} Your picks are kept — try again.`,\n });\n return null;\n } finally {\n if (measurement === controllerForThis) setMeta({ measuring: false });\n }\n },\n\n async resolve(options = {}) {\n if (!adapter.client) throw new Error(\"createSourceSetController: resolve() needs a client in the adapter\");\n const resolved = await adapter.client.resolve(controller.toSourceSet(options), {\n organizationId: config.organizationId ?? undefined,\n });\n return withDisplayNames(resolved, store.getState().cards as SourceCardModel[]);\n },\n\n fitDeliveries(deliveries = config.deliveries) {\n const next = fitCardDeliveries(store.getState(), deliveries);\n if (next !== store.getState()) commit(next);\n },\n roomLeft: () => sourceRoomLeft(store.getState(), config.max),\n totalChars: () => selectTotalChars(store.getState()),\n settled: () => selectSettled(store.getState()),\n };\n return controller;\n}\n","/**\n * Source intake — every way NEW material becomes a Source, through the doors\n * that already exist on the server (DESIGN.md amendment A3). Each call adds a\n * card at once (so the person sees it working), then settles it to a pointer\n * or fails it with a sentence and a remedy. Nothing is ever sent onward as a\n * blob.\n *\n * pasted text → `POST /sources/land`, kept.\n * a web page → the host's scraper lands it (`addScrapedPage`), or a link\n * typed before a reload is scraped again (`addWebPage`);\n * `POST /sources/{id}/keep` files it against the thing being made.\n * a file/image → the host's uploader hands over file ids (`addUploaded`); the\n * file is filed against `attachTo` in the direction the\n * association registry declares, and its Source is kept once\n * reading makes one (`fileLanded`, driven by the recovery).\n * existing → a registry item (`addExisting`).\n * YouTube/audio → the transcript comes from the host's readers and lands\n * through `POST /sources/land`.\n *\n * Never lose input: every landing keeps what the person handed over in the\n * draft (`SourceDraft.input` — text, link, uploaded recording; never bytes)\n * until it settles, so `resume` can land it again after a reload, a failure,\n * or once an organization is chosen (the recovery replays every card waiting\n * for one — from state, never an in-memory queue). Landing twice is safe: the\n * door dedupes by (organization, identity, content hash).\n *\n * Every outside dependency is INJECTED (`SourceIntakeDeps`): the doors, the\n * organization gate, the signed-in person, the failure wording.\n */\n\nimport { isAssociationTargetType, isRegisteredPair } from \"@ai-matrx/associations\";\nimport { createSourceRef } from \"../index\";\nimport type { SourceSetActions } from \"./controller\";\nimport {\n KEEP_WAITING_FOR_ORGANIZATION,\n NOT_KEPT_FOR_RELOAD,\n WAITING_FOR_ORGANIZATION,\n resumableInput,\n} from \"./interrupted\";\nimport { draftKindForToken } from \"./state\";\nimport type { SourceAttachTo, SourceCardModel, SourceIntakeInput, SourceKindId } from \"./types\";\n\nconst TRANSCRIPT_NAME_MAX = 120;\n\n/** A door's notice: a sentence, and sometimes a remedy code (\"save_it…\"). */\nexport interface SourceLandingNotice {\n message: string;\n remedy?: string | null | undefined;\n}\n\n/** The target a door files a Source against (`attach_to`). */\nexport interface SourceAttachTarget {\n entity_type: string;\n entity_id: string;\n label: string | null;\n signal: boolean;\n}\n\n/** The part of a landing body the intake reads or sets — the rest is the host's door shape. */\nexport interface SourceLandingBodyBase {\n name: string;\n canonical_identity?: string | null | undefined;\n provenance?: Record<string, unknown> | null | undefined;\n}\n\n/** A landed (or kept) Source's answer. */\nexport interface SourceLandingAnswer {\n processed_document_id: string;\n notices?: SourceLandingNotice[] | null | undefined;\n}\n\n/** What the host's web reader returns for a link. Null = the page could not be read. */\nexport interface ScrapedSourcePage {\n processedDocumentId: string | null | undefined;\n sourceNotices: SourceLandingNotice[];\n pageTitle?: string | null | undefined;\n}\n\n/** What the host's YouTube reader returns. `source` = the server landed a timed transcript Source. */\nexport interface YouTubeTranscriptResult {\n text: string | null | undefined;\n note?: string | null | undefined;\n source?: { processed_document_id: string; title?: string | null | undefined } | null | undefined;\n}\n\n/** One file the host's uploader already uploaded. */\nexport interface UploadedSourceFile {\n fileId: string;\n name: string;\n}\n\n/** The association write (the host's one chokepoint). */\nexport interface SourceAssociationEdge {\n sourceType: string;\n sourceId: string;\n targetType: string;\n targetId: string;\n orgId: string;\n}\n\nexport type SourceAssociationResult = { ok: true } | { ok: false; error: { message: string } };\n\nexport interface SourceIntakeDoors<Body extends SourceLandingBodyBase = SourceLandingBodyBase> {\n /** `POST /sources/land` with the body as given (keep + attach_to set by the intake). */\n land(body: Body & { keep: true; attach_to: SourceAttachTarget[] }): Promise<SourceLandingAnswer>;\n /** `POST /sources/{id}/keep`, filed against the targets. */\n keep(\n processedDocumentId: string,\n options: { attachTo: SourceAttachTarget[]; organizationId: string },\n ): Promise<{ notices?: SourceLandingNotice[] | null | undefined }>;\n /** Build the landing body for text the person handed over. */\n buildTextLanding(input: {\n text: string;\n name?: string | undefined;\n organizationId: string;\n userId: string;\n }): Promise<Body>;\n /** Read a web page (the scraper lands it). Null = it could not be read. */\n scrapeUrl(url: string): Promise<ScrapedSourcePage | null>;\n /** Read a YouTube video's transcript. */\n fetchYouTubeTranscript(url: string): Promise<YouTubeTranscriptResult>;\n /** Write out a recording that is already stored. */\n transcribeFile(input: { fileId: string; organizationId: string }): Promise<{ text?: string | null | undefined }>;\n /** File one edge through the host's association chokepoint. */\n associate(edge: SourceAssociationEdge): Promise<SourceAssociationResult>;\n}\n\nexport interface SourceIntakeDeps<Body extends SourceLandingBodyBase = SourceLandingBodyBase> {\n doors: SourceIntakeDoors<Body>;\n /** The organization to land in — asks the person when none is chosen (the host's gate). */\n ensureOrganization(): Promise<string>;\n /** Run a landing the person asked for so the gate can carry the click intent. Default: run it. */\n holdIntent?: (<T>(run: () => Promise<T>) => Promise<T | undefined>) | undefined;\n /** True when a landing stopped only because no organization is chosen yet. */\n waitsForOrganization(error: unknown): boolean;\n /** A failed landing as one sentence with its remedy. */\n failureSentence(error: unknown): string;\n /** The signed-in person (null while sign-in is still loading). */\n userId(): string | null | undefined;\n /** The YouTube video id in a link, or null. */\n youtubeId(url: string): string | null | undefined;\n /** The largest pasted text kept in the draft for a reload (null = unknown — nothing kept). */\n maxKeptChars(): number | null;\n /** The thing being made — new Sources are filed against it and kept. */\n attachTo?: SourceAttachTo | undefined;\n}\n\nexport interface SourceIntake {\n addPastedText(text: string, name?: string): Promise<void>;\n addWebPage(url: string): Promise<void>;\n /**\n * A page the host's web picker already read (and the scraper landed); null id\n * = land its text instead. `pendingId` = the card `beginWebPage` made when the\n * read started — it is settled instead of a new card being added.\n */\n addScrapedPage(\n page: { url: string; title: string; text: string; processedDocumentId: string | null },\n pendingId?: string | null,\n ): Promise<void>;\n /**\n * The host's web picker STARTED reading a link: a card with the link kept\n * appears at once, so a reload mid-read brings it back and lands it (verify-3\n * 12a/12b: a reload while a page was read lost it, link and all). Finish it\n * with `addScrapedPage(page, id)`; if the person drops the preview, remove it;\n * if the picker goes away mid-read, `resume(card)` lands it through the web door.\n */\n beginWebPage(url: string): string;\n /** Files the host's uploader already uploaded. */\n addUploaded(files: readonly UploadedSourceFile[], kind: SourceKindId): Promise<void>;\n /**\n * A recording made in place (the Voice Pad) that is already written out: it\n * lands as text, but it IS a recording — its card and review say \"Recording\",\n * never \"Pasted text\" — and it keeps its name (\"Recording 3:41 PM\").\n */\n addRecordedText(text: string, name?: string): Promise<void>;\n /** A recording already uploaded — written out, then landed. */\n addUploadedRecording(file: UploadedSourceFile): Promise<void>;\n /** Something the person already has (Use existing / search). Returns false when already picked. */\n addExisting(item: { token: string; id: string; title: string }): boolean;\n addYouTube(url: string): Promise<void>;\n /** Land a card's kept input again (after a reload or a failure). False when nothing was kept. */\n resume(card: SourceCardModel): boolean;\n /** The person chose the file again (uploaded) for a card whose upload was cut off. */\n retryFile(card: SourceCardModel, file: UploadedSourceFile): Promise<void>;\n /** Reading an uploaded file made its Source: keep it and file it against `attachTo`. */\n fileLanded(card: SourceCardModel, processedDocumentId: string): Promise<void>;\n}\n\nexport function sourceAttachTargets(attachTo: SourceAttachTo | undefined): SourceAttachTarget[] {\n return attachTo\n ? [\n {\n entity_type: attachTo.entityType,\n entity_id: attachTo.entityId,\n // The EDGE's label, which the registry names (a deck's Source is its\n // \"source\", a scope's is \"about\") — never the target's display name,\n // which the door refused as an unknown label (USI-3e).\n label: null,\n signal: true,\n },\n ]\n : [];\n}\n\nfunction hostOf(url: string): string {\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n } catch {\n return url;\n }\n}\n\n/** A notice that asks the person to save (keep) the Source — moot once it is kept. */\nfunction isSaveItNotice(remedy: string | null | undefined): boolean {\n return typeof remedy === \"string\" && remedy.startsWith(\"save_it\");\n}\n\nfunction landedNotes(notices: readonly SourceLandingNotice[] | null | undefined): string[] {\n return (notices ?? []).map((n) => n.message).filter(Boolean);\n}\n\n/**\n * Which way a file ↔ `targetType` edge is registered — read from the package's\n * generated association registry (`@ai-matrx/associations`) — or null when it\n * is not registered.\n */\nexport function registeredFileEdge(targetType: string): \"file_to_target\" | \"target_to_file\" | null {\n if (isRegisteredPair(\"file\", targetType)) return \"file_to_target\";\n if (isRegisteredPair(targetType, \"file\")) return \"target_to_file\";\n return null;\n}\n\nexport function createSourceIntake<Body extends SourceLandingBodyBase>(\n set: SourceSetActions,\n deps: SourceIntakeDeps<Body>,\n): SourceIntake {\n const { doors } = deps;\n const attachTo = sourceAttachTargets(deps.attachTo);\n const hold = <T>(run: () => Promise<T>): Promise<T | undefined> =>\n deps.holdIntent ? deps.holdIntent(run) : run();\n const notFiledSuffix = attachTo.length ? \" or filed with what you are making\" : \"\";\n\n /**\n * Fail the card — or, when only the organization is missing, say it is\n * waiting. The card's kept input is its replay: the recovery lands it again\n * the moment an organization is set (state, not a queue).\n */\n const failOrHold = (id: string, err: unknown) => {\n set.fail(id, deps.waitsForOrganization(err) ? WAITING_FOR_ORGANIZATION : deps.failureSentence(err));\n };\n\n const needUser = (): string => {\n const userId = deps.userId();\n if (!userId) throw new Error(\"Your sign-in is still loading, so nothing was added. Try again in a moment.\");\n return userId;\n };\n\n /** Land text through the door as a kept Source; returns the settle patch. */\n const landText = async (body: Body): Promise<{ id: string; notes: string[] }> => {\n const landed = await doors.land({ ...body, keep: true, attach_to: attachTo });\n return { id: landed.processed_document_id, notes: landedNotes(landed.notices) };\n };\n\n const landPaste = async (id: string, trimmed: string, name?: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const body = await doors.buildTextLanding({ text: trimmed, name, organizationId, userId: needUser() });\n const landed = await landText(body);\n set.settle(id, {\n label: body.name,\n ref: createSourceRef(\"processed_document\", landed.id),\n processedDocumentId: landed.id,\n notes: landed.notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n const landWebPage = async (id: string, url: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const result = await doors.scrapeUrl(url);\n if (!result) {\n set.fail(\n id,\n \"That page could not be read — it may need a sign-in or block robots. Try another link, or copy the text and use Paste text.\",\n );\n return;\n }\n if (!result.processedDocumentId) {\n set.fail(\n id,\n result.sourceNotices[0]?.message ??\n \"The page was read but did not become a Source, and the server did not say why. Try again.\",\n );\n return;\n }\n // A Source picked for real work is kept (A3): its clean → segment →\n // embed is queued, and it is filed against the thing being made. Once\n // kept, the capture's \"not saved — save it\" notices are no longer true;\n // the keep's own notices replace them.\n let notes: string[];\n try {\n const kept = await doors.keep(result.processedDocumentId, { attachTo, organizationId });\n notes = [\n ...landedNotes(result.sourceNotices.filter((n) => !isSaveItNotice(n.remedy))),\n ...landedNotes(kept.notices),\n ];\n } catch (err) {\n notes = [\n ...landedNotes(result.sourceNotices),\n `It is in your Sources, but it could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`,\n ];\n }\n set.settle(id, {\n label: result.pageTitle || hostOf(url),\n ref: createSourceRef(\"processed_document\", result.processedDocumentId),\n processedDocumentId: result.processedDocumentId,\n notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n const landYouTube = async (id: string, url: string, videoId: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const { text, note, source } = await doors.fetchYouTubeTranscript(url);\n if (!text) {\n set.fail(\n id,\n note ??\n \"That video has no speech we could write out (no captions and no clear voice). Try another video, or paste a transcript.\",\n );\n return;\n }\n if (source) {\n // The server landed the timed transcript through the door: the card IS\n // that transcript Source, and \"Choose parts\" lists its timed segments.\n const label = `YouTube — ${source.title || videoId}`.slice(0, TRANSCRIPT_NAME_MAX);\n let notes: string[] = [];\n try {\n const kept = await doors.keep(source.processed_document_id, { attachTo, organizationId });\n notes = landedNotes(kept.notices);\n } catch (err) {\n notes = [\n `It was read, but its Source could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`,\n ];\n }\n set.settle(id, {\n label,\n ref: createSourceRef(\"processed_document\", source.processed_document_id),\n processedDocumentId: source.processed_document_id,\n notes,\n });\n return;\n }\n const name = `YouTube — ${text.split(/\\s+/).slice(0, 10).join(\" \")}…`.slice(0, TRANSCRIPT_NAME_MAX);\n const body = await doors.buildTextLanding({ text, name, organizationId, userId: needUser() });\n const landed = await landText({\n ...body,\n // Identity is the video, so the same video twice is one Source.\n canonical_identity: `youtube:${videoId}`,\n provenance: { ...(body.provenance ?? {}), origin_client: \"youtube\", capture_method: \"captions\", final_url: url },\n });\n set.settle(id, {\n label: name,\n ref: createSourceRef(\"processed_document\", landed.id),\n processedDocumentId: landed.id,\n // Untimed: say why it has no parts to choose (the server's own sentence).\n notes: note ? [...landed.notes, note] : landed.notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n /**\n * File the uploaded file against the thing being made — the ONE associations\n * chokepoint, in the direction the registry declares (`fc_set → file`, but\n * `file → task`); writing it backwards is refused (USI-3e). Returns a note\n * when it could not be filed; the upload itself stands.\n */\n const fileAgainstTarget = async (fileId: string, organizationId: string): Promise<string | null> => {\n const target = deps.attachTo;\n if (!target) return null;\n const what = target.label ? `\"${target.label}\"` : \"what you are making\";\n const direction = registeredFileEdge(target.entityType);\n const cannot = `It was uploaded, but a file cannot be filed with ${what} (a ${target.entityType.replace(/_/g, \" \")}), so it is not listed there.`;\n if (!direction) return cannot;\n if (direction === \"file_to_target\" && !isAssociationTargetType(target.entityType)) return cannot;\n const linked = await doors.associate(\n direction === \"file_to_target\"\n ? {\n sourceType: \"file\",\n sourceId: fileId,\n targetType: target.entityType,\n targetId: target.entityId,\n orgId: organizationId,\n }\n : {\n sourceType: target.entityType,\n sourceId: target.entityId,\n targetType: \"file\",\n targetId: fileId,\n orgId: organizationId,\n },\n );\n return linked.ok ? null : `It was uploaded, but it could not be filed with ${what}: ${linked.error.message}`;\n };\n\n const fileNotes = async (fileId: string): Promise<string[]> => {\n try {\n const organizationId = await deps.ensureOrganization();\n const filed = await fileAgainstTarget(fileId, organizationId);\n return filed ? [filed] : [];\n } catch (err) {\n return deps.waitsForOrganization(err)\n ? []\n : [`It was uploaded, but it could not be filed: ${deps.failureSentence(err)}`];\n }\n };\n\n const transcribeRecording = async (id: string, fileId: string, fileName: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const transcription = await doors.transcribeFile({ fileId, organizationId });\n const text = (transcription.text ?? \"\").trim();\n if (text.length < 8) {\n set.fail(\n id,\n \"We couldn't hear enough speech in that recording to write it out. Try a recording with a clear voice.\",\n );\n return;\n }\n const name = `Recording — ${fileName}`.slice(0, TRANSCRIPT_NAME_MAX);\n const body = await doors.buildTextLanding({ text, name, organizationId, userId: needUser() });\n const landed = await landText({\n ...body,\n canonical_identity: `audio-transcript:${fileId}`,\n provenance: { ...(body.provenance ?? {}), origin_client: \"transcription\", capture_method: \"speech\" },\n });\n set.settle(id, {\n label: name,\n ref: createSourceRef(\"processed_document\", landed.id),\n processedDocumentId: landed.id,\n fileId,\n notes: landed.notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n const intake: SourceIntake = {\n async addPastedText(text, name) {\n const trimmed = text.trim();\n if (!trimmed) return;\n const max = deps.maxKeptChars();\n const kept = max !== null && trimmed.length <= max;\n const id = set.addPending({\n kind: \"paste\",\n label: name?.trim() || \"Pasted text\",\n input: kept ? { text: trimmed, name } : undefined,\n notes: kept ? undefined : [NOT_KEPT_FOR_RELOAD],\n });\n await hold(() => landPaste(id, trimmed, name));\n },\n\n async addRecordedText(text, name) {\n const trimmed = text.trim();\n if (!trimmed) return;\n const max = deps.maxKeptChars();\n const kept = max !== null && trimmed.length <= max;\n const id = set.addPending({\n kind: \"audio\",\n label: name?.trim() || \"Recording\",\n origin: \"Recording\",\n input: kept ? { text: trimmed, name } : undefined,\n notes: kept ? undefined : [NOT_KEPT_FOR_RELOAD],\n });\n await hold(() => landPaste(id, trimmed, name));\n },\n\n async addWebPage(raw) {\n const url = /^https?:\\/\\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;\n const id = set.addPending({ kind: \"web\", label: hostOf(url), origin: url, input: { url } });\n await hold(() => landWebPage(id, url));\n },\n\n beginWebPage(raw) {\n const url = /^https?:\\/\\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;\n return set.addPending({ kind: \"web\", label: hostOf(url), origin: url, input: { url } });\n },\n\n async addScrapedPage(page, pendingId) {\n const label = page.title || hostOf(page.url);\n const cardFor = () => {\n if (pendingId && set.restart(pendingId)) {\n set.updateDraft(pendingId, { label, origin: page.url, input: { url: page.url } });\n return pendingId;\n }\n return set.addPending({ kind: \"web\", label, origin: page.url, input: { url: page.url } });\n };\n if (!page.processedDocumentId) {\n // The scrape did not land a Source (or the person edited the text): land what they confirmed.\n const id = cardFor();\n await hold(() => landPaste(id, page.text, label));\n return;\n }\n const pdId = page.processedDocumentId;\n const id = cardFor();\n await hold(async () => {\n let notes: string[] = [];\n try {\n const organizationId = await deps.ensureOrganization();\n const kept = await doors.keep(pdId, { attachTo, organizationId });\n notes = landedNotes(kept.notices);\n } catch (err) {\n notes = deps.waitsForOrganization(err)\n ? [KEEP_WAITING_FOR_ORGANIZATION]\n : [`It is in your Sources, but it could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`];\n }\n set.settle(id, {\n label,\n ref: createSourceRef(\"processed_document\", pdId),\n processedDocumentId: pdId,\n notes,\n });\n });\n },\n\n async addUploaded(files, kind) {\n for (const file of files) {\n if (set.hasRef(\"file\", file.fileId)) continue;\n const id = set.addPending({ kind, label: file.name, origin: \"Uploaded file\", fileId: file.fileId });\n const notes = await fileNotes(file.fileId);\n // The Source itself is kept and filed by the recovery from the server's state.\n set.settle(id, { label: file.name, ref: createSourceRef(\"file\", file.fileId), fileId: file.fileId, notes });\n }\n },\n\n async addUploadedRecording(file) {\n const id = set.addPending({\n kind: \"audio\",\n label: file.name,\n origin: \"Recording\",\n fileId: file.fileId,\n input: { fileId: file.fileId },\n });\n await hold(() => transcribeRecording(id, file.fileId, file.name));\n },\n\n addExisting(item) {\n if (set.hasRef(item.token, item.id)) return false;\n set.addReady({\n kind: draftKindForToken(item.token),\n label: item.title,\n ref: createSourceRef(item.token, item.id),\n fileId: item.token === \"file\" ? item.id : undefined,\n processedDocumentId: item.token === \"processed_document\" ? item.id : undefined,\n });\n return true;\n },\n\n async addYouTube(raw) {\n const url = raw.trim();\n const videoId = deps.youtubeId(url);\n if (!videoId) return;\n const id = set.addPending({ kind: \"youtube\", label: \"YouTube video\", origin: url, input: { url } });\n await hold(() => landYouTube(id, url, videoId));\n },\n\n resume(card) {\n const input: SourceIntakeInput | null = resumableInput(card.draft);\n if (!input) return false;\n set.restart(card.id);\n switch (card.draft.kind) {\n case \"paste\":\n void landPaste(card.id, (input.text ?? \"\").trim(), input.name);\n return true;\n case \"web\":\n void landWebPage(card.id, input.url ?? \"\");\n return true;\n case \"youtube\": {\n const videoId = deps.youtubeId(input.url ?? \"\");\n if (!videoId) {\n set.fail(card.id, \"That link is not a YouTube video any more. Remove it and paste the link again.\");\n return true;\n }\n void landYouTube(card.id, input.url ?? \"\", videoId);\n return true;\n }\n case \"audio\":\n if (input.fileId) void transcribeRecording(card.id, input.fileId, card.draft.label);\n else void landPaste(card.id, (input.text ?? \"\").trim(), input.name);\n return true;\n default:\n return false;\n }\n },\n\n async retryFile(card, file) {\n set.restart(card.id);\n set.updateDraft(card.id, { label: file.name, fileId: file.fileId });\n if (card.draft.kind === \"audio\") {\n set.updateDraft(card.id, { input: { fileId: file.fileId } });\n await hold(() => transcribeRecording(card.id, file.fileId, file.name));\n return;\n }\n const notes = await fileNotes(file.fileId);\n set.settle(card.id, { label: file.name, ref: createSourceRef(\"file\", file.fileId), fileId: file.fileId, notes });\n },\n\n async fileLanded(card, processedDocumentId) {\n // Every card opens its Source from now on (and a held keep's waiting note goes).\n const notes = (card.draft.notes ?? []).filter((n) => n !== KEEP_WAITING_FOR_ORGANIZATION);\n set.updateDraft(card.id, { processedDocumentId, notes });\n try {\n const organizationId = await deps.ensureOrganization();\n await doors.keep(processedDocumentId, { attachTo, organizationId });\n } catch (err) {\n if (deps.waitsForOrganization(err)) {\n // Kept again by the recovery once an organization is set.\n set.updateDraft(card.id, { processedDocumentId, notes: [...notes, KEEP_WAITING_FOR_ORGANIZATION] });\n return;\n }\n set.updateDraft(card.id, {\n processedDocumentId,\n notes: [\n ...notes,\n `It was read, but its Source could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`,\n ],\n });\n }\n },\n };\n return intake;\n}\n","/**\n * Recovery — the UI-free half of \"never lose input\" (USI-3b), as decisions and\n * one step function. A React binding (`@ai-matrx/agents/sources/react`\n * `useSourceRecovery`) schedules them; any other client can call them itself.\n *\n * 1. A Source a reload cut off while it was landing, whose input the draft\n * kept (`interrupted.ts`), is handed back to the door once — the door\n * dedupes by content hash, so a second landing reuses the same Source.\n * 2. A landing that waited for an organization is landed again the moment one\n * is set — from the card's kept input, or, for a read Source whose keep\n * waited, by keeping it again. State, never an in-memory queue.\n * 3. A stored file's Source (new upload, reused copy, or picked file) is read\n * from the SERVER's state (`fileSource.ts`): kept and filed once it exists,\n * the one run started only when nothing is reading it, re-attached after a\n * reload — never a duplicate run.\n *\n * The once-per-card guards live on `globalThis` (one registry however many\n * loader graphs import this module), so two inputs on one surface, or a\n * re-mount, never land the same card twice.\n */\n\nimport type { SourceSetActions } from \"./controller\";\nimport {\n fileCardHeldForOrganization,\n isWaitingFileCard,\n nextFileStep,\n type FileSourceStatus,\n} from \"./fileSource\";\nimport type { SourceIntake } from \"./intake\";\nimport { KEEP_WAITING_FOR_ORGANIZATION, RELOADED_RESUMING, WAITING_FOR_ORGANIZATION } from \"./interrupted\";\nimport type { SourceCardModel } from \"./types\";\n\ninterface RecoveryGuards {\n resumedCards: Set<string>;\n keptFileSources: Set<string>;\n startedFileRuns: Set<string>;\n}\n\n// Module-level state is banned in our packages (dual ESM/CJS graphs would\n// split it): the guards live on globalThis under one registered symbol.\nconst GUARDS = Symbol.for(\"ai-matrx.agents.sources.recovery-guards\");\n\nexport function sourceRecoveryGuards(): RecoveryGuards {\n const slot = globalThis as unknown as Record<symbol, RecoveryGuards | undefined>;\n let guards = slot[GUARDS];\n if (!guards) {\n guards = { resumedCards: new Set(), keptFileSources: new Set(), startedFileRuns: new Set() };\n slot[GUARDS] = guards;\n }\n return guards;\n}\n\n/** Cards a reload cut off whose kept input lands again now. */\nexport function cardsToResume(cards: readonly SourceCardModel[]): SourceCardModel[] {\n return cards.filter((c) => c.status === \"error\" && c.error === RELOADED_RESUMING);\n}\n\n/** Resume each cut-off card once (per card id, across every input). */\nexport function resumeInterrupted(cards: readonly SourceCardModel[], intake: Pick<SourceIntake, \"resume\">): void {\n const { resumedCards } = sourceRecoveryGuards();\n for (const card of cardsToResume(cards)) {\n if (resumedCards.has(card.id)) continue;\n resumedCards.add(card.id);\n intake.resume(card);\n }\n}\n\n/** Cards that waited for an organization (a landing, or a read Source's keep). */\nexport function cardsWaitingForOrganization(cards: readonly SourceCardModel[]): SourceCardModel[] {\n return cards.filter(\n (s) =>\n (s.status === \"error\" && s.error === WAITING_FOR_ORGANIZATION) ||\n (!!s.draft.processedDocumentId && !!s.draft.notes?.includes(KEEP_WAITING_FOR_ORGANIZATION)),\n );\n}\n\n/** An organization is known now: land or keep every card that waited for one. */\nexport function continueAfterOrganization(\n cards: readonly SourceCardModel[],\n intake: Pick<SourceIntake, \"resume\" | \"fileLanded\">,\n): void {\n for (const card of cards) {\n if (card.status === \"error\" && card.error === WAITING_FOR_ORGANIZATION) {\n intake.resume(card);\n } else if (card.draft.processedDocumentId && card.draft.notes?.includes(KEEP_WAITING_FOR_ORGANIZATION)) {\n void intake.fileLanded(card, card.draft.processedDocumentId);\n }\n }\n}\n\n/** The host's processing runner, as far as the recovery needs it. */\nexport interface SourceFileRunner {\n jobs: ReadonlyArray<{ cldFileId?: string | null | undefined; status: string; processedDocumentId?: string | null | undefined }>;\n runForCldFile(fileId: string, label: string, reason: string): Promise<unknown>;\n}\n\nexport interface FileRecoveryDeps {\n /** The organization the person picked (null = none yet). */\n organizationId: string | null | undefined;\n /** The server's `/files/{id}/rag-status` read. */\n readFileState(fileId: string, signal?: AbortSignal): Promise<FileSourceStatus>;\n /** The host's lookup of a file's own organization (omitted = unknown). */\n fileOrganizationId?: ((fileId: string) => string | null | undefined) | undefined;\n}\n\n/** A file card the recovery may ask about now (waiting, and not held for an organization). */\nexport function isAskableFileCard(card: SourceCardModel, deps: Pick<FileRecoveryDeps, \"organizationId\" | \"fileOrganizationId\">): boolean {\n return isWaitingFileCard(card) && !fileCardHeldForOrganization(card, deps.organizationId, deps.fileOrganizationId);\n}\n\n/**\n * One look at every askable file card: a Source → keep and file it; a live run\n * → look again; nothing reading it → start the one run (once); unreadable →\n * say so. Returns true while any card still waits (look again later).\n */\nexport async function lookAtFileCards(\n cards: readonly SourceCardModel[],\n ctx: {\n set: Pick<SourceSetActions, \"fail\" | \"manifest\">;\n intake: Pick<SourceIntake, \"fileLanded\">;\n runner: SourceFileRunner;\n signal: AbortSignal;\n } & FileRecoveryDeps,\n): Promise<boolean> {\n const { keptFileSources, startedFileRuns } = sourceRecoveryGuards();\n let anyWaiting = false;\n for (const card of cards.filter((c) => isAskableFileCard(c, ctx))) {\n const fileId = card.draft.fileId as string;\n const guard = `${card.id}:${fileId}`;\n if (keptFileSources.has(guard)) continue;\n let status: FileSourceStatus | null = null;\n try {\n status = await ctx.readFileState(fileId, ctx.signal);\n } catch {\n // A missed read is not an answer — look again next round.\n if (ctx.signal.aborted) return false;\n anyWaiting = true;\n continue;\n }\n if (ctx.signal.aborted) return false;\n const localJob = ctx.runner.jobs.find((j) => j.cldFileId === fileId) ?? null;\n const step = nextFileStep(status, {\n started: startedFileRuns.has(guard),\n localRunning: localJob?.status === \"running\",\n });\n const localPdId = localJob?.processedDocumentId ?? null;\n if (step.do === \"keep\" || localPdId) {\n keptFileSources.add(guard);\n const pdId = step.do === \"keep\" ? step.processedDocumentId : (localPdId as string);\n await ctx.intake.fileLanded(card, pdId);\n // The pointer did not change, so nothing else re-measures: ask once now.\n void ctx.set.manifest();\n } else if (step.do === \"start\") {\n startedFileRuns.add(guard);\n anyWaiting = true;\n void ctx.runner.runForCldFile(fileId, card.draft.label, \"Reading it into a Source\").catch(() => undefined);\n } else if (step.do === \"unreadable\") {\n keptFileSources.add(guard);\n ctx.set.fail(card.id, step.reason);\n } else {\n anyWaiting = true;\n }\n }\n return anyWaiting;\n}\n"],"mappings":"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","names":["id"]}
|
|
1
|
+
{"version":3,"sources":["../../../sources/react/index.ts","../../../sources/index.ts","../../../sources/runtime/delivery.ts","../../../sources/runtime/partsSearch.ts","../../../sources/runtime/interrupted.ts","../../../sources/runtime/fileSource.ts","../../../sources/runtime/state.ts","../../../sources/runtime/controller.ts","../../../sources/runtime/intake.ts","../../../sources/runtime/recovery.ts"],"sourcesContent":["/**\n * `@ai-matrx/agents/sources/react` — thin React hooks over the Source runtime\n * (`@ai-matrx/agents/sources/runtime`). No logic lives here that a non-React\n * client could not reach through the runtime itself: the hooks subscribe,\n * schedule, and hand back the same controller.\n *\n * const set = useSourceSet(adapter, { persistenceReady });\n * const intake = useSourceIntake(set, deps);\n * useSourceRecovery(set, intake, runner, { organizationId, readFileState });\n * const search = useSourcePartsSearch(client, ref, query);\n *\n * A host binds the adapter to its own store once (memoized per surface) —\n * the web app binds Redux; another client binds its own.\n */\n\nimport { useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { createSourceRef, type ResolvedSourceSet, type SourceRef, type SourceSet } from \"../index\";\nimport {\n cardsToResume,\n cardsWaitingForOrganization,\n continueAfterOrganization,\n createSourceIntake,\n createSourceSetController,\n fileSourcePollDelayMs,\n isAskableFileCard,\n isWordQuery,\n lookAtFileCards,\n readPersistedSourceInput,\n resumeInterrupted,\n type FileRecoveryDeps,\n type PartMatchIds,\n type SourceCardModel,\n type SourceDelivery,\n type SourceIntake,\n type SourceIntakeDeps,\n type SourceLandingBodyBase,\n type SourceSetActions,\n type SourceSetAdapter,\n type SourceSetConfig,\n type SourceSetController,\n type SourceFileRunner,\n type SourcesClient,\n} from \"../runtime/index\";\n\nconst noSubscribe = () => () => {};\n\n/**\n * The latest value of a callback, read inside effects without re-running them\n * (React 18 has no `useEffectEvent`; the peer range starts at 18). The ref is\n * refreshed by an effect declared BEFORE the effects that read it, so they\n * always see this render's closure.\n */\nfunction useLatest<T>(value: T): { readonly current: T } {\n const ref = useRef(value);\n useEffect(() => {\n ref.current = value;\n });\n return ref;\n}\nconst noSaved = () => undefined;\n\nexport interface UseSourceSetOptions {\n /**\n * The draft store has been read back (a device store loads a moment after\n * the page). While false, \"nothing picked\" is not known — `restoring` stays\n * true. Default true.\n */\n persistenceReady?: boolean | undefined;\n /** The host's choices, re-read on every render. Default: the adapter's config. */\n config?: SourceSetConfig | undefined;\n}\n\nexport interface UseSourceSetResult extends SourceSetActions {\n /** Every picked Source, in the order picked. */\n sources: SourceCardModel[];\n topic: string;\n /** The frozen v1 payload, built from the ready Sources. */\n toSourceSet: (options?: { targetModelId?: string | undefined }) => SourceSet;\n /** Apply a set the review page returned (forms, parts, caps, delivery). */\n applySourceSet: (set: SourceSet, options?: { reviewed?: SourceSet | undefined }) => void;\n /** POST /sources/resolve — the grounded text for a generator. */\n resolve: (options?: { targetModelId?: string | undefined }) => Promise<ResolvedSourceSet>;\n /** Switch back any Source set to a delivery the host cannot use (with a note). */\n fitDeliveries: (deliveries?: readonly SourceDelivery[]) => void;\n /** How many more Sources fit under the host's max. */\n roomLeft: () => number;\n /** Characters that will go in (the server's measurement; 0 until measured). */\n totalChars: number;\n measuring: boolean;\n /** Why the measurement failed, with its remedy. */\n manifestError: string | null;\n /** Every Source finished landing (nothing pending) and none failed. */\n settled: boolean;\n /** The saved draft is not read back yet — show a loading state, never an empty one. */\n restoring: boolean;\n /** The controller itself, for non-React code on the same surface. */\n controller: SourceSetController;\n}\n\n/**\n * THE hook for one Source input. `adapter` must be stable for a surface\n * (memoize it); a new adapter builds a new controller.\n */\nexport function useSourceSet(adapter: SourceSetAdapter, options: UseSourceSetOptions = {}): UseSourceSetResult {\n const controller = useMemo(() => createSourceSetController(adapter), [adapter]);\n controller.configure(options.config ?? adapter.config ?? {});\n const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);\n const meta = useSyncExternalStore(controller.subscribeMeta, controller.getMeta, controller.getMeta);\n const persistence = adapter.persistence;\n const saved = useSyncExternalStore(\n persistence?.subscribe ?? noSubscribe,\n persistence ? persistence.load : noSaved,\n persistence ? persistence.load : noSaved,\n );\n\n useEffect(() => {\n adapter.store.init?.();\n }, [adapter]);\n\n // Restore the saved draft once, the moment it is read back.\n useEffect(() => {\n controller.restore(saved);\n }, [controller, saved]);\n\n const savedCount = readPersistedSourceInput(saved).sources.length;\n const ready = options.persistenceReady ?? true;\n\n return {\n controller,\n sources: state.cards as SourceCardModel[],\n topic: state.topic,\n addReady: controller.addReady,\n addPending: controller.addPending,\n settle: controller.settle,\n fail: controller.fail,\n restart: controller.restart,\n updateDraft: controller.updateDraft,\n remove: controller.remove,\n updateRef: controller.updateRef,\n setWaitForClean: controller.setWaitForClean,\n setTopic: controller.setTopic,\n hasRef: controller.hasRef,\n liveCount: controller.liveCount,\n manifest: controller.manifest,\n toSourceSet: controller.toSourceSet,\n applySourceSet: controller.applySourceSet,\n resolve: controller.resolve,\n fitDeliveries: controller.fitDeliveries,\n roomLeft: controller.roomLeft,\n totalChars: controller.totalChars(),\n measuring: meta.measuring,\n manifestError: meta.manifestError,\n settled: controller.settled(),\n // Not read back yet, or read back but the restore has not landed in the\n // store (one render between the two) — both would draw a false \"empty\".\n restoring: !ready || (savedCount > 0 && state.cards.length === 0),\n };\n}\n\n/** Every landing door, over the set. Rebuilt each render (closures only — nothing to keep). */\nexport function useSourceIntake<Body extends SourceLandingBodyBase>(\n set: SourceSetActions,\n deps: SourceIntakeDeps<Body>,\n): SourceIntake {\n return createSourceIntake(set, deps);\n}\n\nexport interface UseSourceRecoveryOptions extends FileRecoveryDeps {}\n\n/**\n * Never lose input, and follow stored files' Sources — call once per screen\n * that sits on `useSourceSet` + `useSourceIntake`.\n */\nexport function useSourceRecovery(\n set: Pick<UseSourceSetResult, \"sources\" | \"fail\" | \"manifest\">,\n intake: Pick<SourceIntake, \"resume\" | \"fileLanded\">,\n runner: SourceFileRunner,\n options: UseSourceRecoveryOptions,\n): void {\n // ── Never lose input: land again what a reload cut off ─────────────────────\n const resumeKey = cardsToResume(set.sources)\n .map((s) => s.id)\n .join(\",\");\n const latest = useLatest({ set, intake, runner, options });\n useEffect(() => {\n if (resumeKey) resumeInterrupted(latest.current.set.sources, latest.current.intake);\n }, [resumeKey, latest]);\n\n // ── Waited for an organization: go on the moment one is set ─────────────────\n const waitingForOrgKey = options.organizationId\n ? cardsWaitingForOrganization(set.sources)\n .map((s) => s.id)\n .join(\",\")\n : \"\";\n useEffect(() => {\n if (waitingForOrgKey) continueAfterOrganization(latest.current.set.sources, latest.current.intake);\n }, [waitingForOrgKey, latest]);\n\n // ── A stored file's Source: read the SERVER's state, never this tab's memory.\n // Held for an organization (V2-F #3): no organization known = nothing asked.\n // Picking one changes the key, so the look starts by itself.\n const waitingKey = set.sources\n .filter((c) => isAskableFileCard(c, options))\n .map((c) => `${c.id}:${c.draft.fileId}`)\n .join(\",\");\n useEffect(() => {\n if (!waitingKey) return undefined;\n const ac = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n const look = (round: number) => {\n timer = setTimeout(async () => {\n const now = latest.current;\n const again = await lookAtFileCards(now.set.sources, {\n set: now.set,\n intake: now.intake,\n runner: now.runner,\n signal: ac.signal,\n ...now.options,\n });\n if (again && !ac.signal.aborted) look(round + 1);\n }, fileSourcePollDelayMs(round));\n };\n look(0);\n return () => {\n ac.abort();\n if (timer) clearTimeout(timer);\n };\n }, [waitingKey, latest]);\n}\n\n/** How long typing must pause before the server is asked. */\nconst SEARCH_DEBOUNCE_MS = 250;\n\nconst COULD_NOT_SEARCH =\n \"Only part titles and opening words are searched — the full text could not be searched just now.\";\n\nexport interface SourcePartsSearchState {\n /** Ids of the parts whose text holds every word (undefined until answered). */\n matches: PartMatchIds | undefined;\n /** The server is being asked about the current words (\"Searching inside the text…\"). */\n reading: boolean;\n /** Said under the search when the text could not be searched (titles and previews still match). */\n error: string | null;\n /** More parts matched than the server returns; the list shown is the first of them. */\n truncated: boolean;\n}\n\n/**\n * Which of one Source's parts hold every word a person typed, answered by the\n * server (`POST /sources/parts/search` — ids only; the whole text never comes\n * to the client). Asked only for words (never a page or a range), after the\n * person pauses typing.\n */\nexport function useSourcePartsSearch(\n client: Pick<SourcesClient, \"searchParts\">,\n ref: SourceRef | null,\n query: string,\n): SourcePartsSearchState {\n const [state, setState] = useState<{\n key: string;\n matches?: PartMatchIds;\n truncated?: boolean;\n error?: string;\n } | null>(null);\n const resourceType = ref?.resource_type ?? \"\";\n const resourceId = ref?.resource_id ?? \"\";\n const representation = ref?.representation ?? undefined;\n const words = isWordQuery(query) ? query.trim().toLowerCase().split(/\\s+/).join(\" \") : \"\";\n const key = resourceId && words ? `${resourceType}:${resourceId}:${representation ?? \"\"}:${words}` : null;\n const latestClient = useLatest(client);\n\n useEffect(() => {\n if (!key) return undefined;\n // The whole Source in the chosen form: the person's picked parts never narrow a search.\n const whole = createSourceRef(resourceType, resourceId, { representation });\n const controller = new AbortController();\n const timer = setTimeout(() => {\n latestClient.current\n .searchParts(whole, words, { signal: controller.signal })\n .then((found) => {\n if (controller.signal.aborted) return;\n if (found.unavailable) {\n setState({\n key,\n error: `Only part titles and opening words are searched — ${\n found.detail ?? \"the full text could not be searched.\"\n }`,\n });\n return;\n }\n setState({ key, matches: new Set(found.segment_ids ?? []), truncated: !!found.truncated });\n })\n .catch(() => {\n if (!controller.signal.aborted) setState({ key, error: COULD_NOT_SEARCH });\n });\n }, SEARCH_DEBOUNCE_MS);\n return () => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [key, resourceType, resourceId, representation, words, latestClient]);\n\n const mine = key && state && state.key === key ? state : null;\n return {\n matches: mine?.matches,\n reading: !!key && !mine,\n error: mine?.error ?? null,\n truncated: mine?.truncated ?? false,\n };\n}\n","/**\n * `@ai-matrx/agents/sources` — THE ONE SOURCE PAYLOAD (contract v1, frozen 2026-09-27).\n *\n * Every request that is built from a person's Sources carries them as a\n * `SourceSet`: a list of `SourceRef` pointers (never blobs) plus how the model\n * should be grounded in them. The server answers with a `SourceManifest`\n * (sizes and states, never bodies — POST /sources/manifest) or a\n * `ResolvedSourceSet` (grounded text for generators — POST /sources/resolve).\n *\n * Contract of record: common-docs `projects/unified-source-input/DESIGN.md`\n * § \"Contract v1 — FROZEN\". A shape change here is an AMENDMENT there first,\n * with its Pydantic twin beside aidream's `parse_resource_reference`.\n *\n * `SourceRef` IS the existing `resource_ref` pointer already on the wire\n * (aidream `services/conversation_context/resource_context.py`), extended with\n * optional fields only — never coin a second pointer type.\n *\n * Pure module: no React, no I/O, no \"use client\".\n */\n\nexport const RESOURCE_REF_KIND = \"resource_ref\" as const;\nexport const SOURCE_SET_KIND = \"source_set\" as const;\nexport const SOURCE_MANIFEST_KIND = \"source_manifest\" as const;\nexport const RESOLVED_SOURCE_SET_KIND = \"resolved_source_set\" as const;\n\n/** The wire version every `SourceSet` carries. */\nexport const SOURCE_SET_VERSION = 1 as const;\n\n/** A bounded preview of one representation promoted into the prompt. */\nexport interface ResourcePromotion {\n representation: string;\n max_chars?: number;\n}\n\nexport type SourceDelivery = \"direct\" | \"context\";\nexport type SourceGrounding = \"whole\" | \"selected\" | \"retrieve\";\n\n/** The pointer — the existing `resource_ref` envelope, extended (all new fields optional). */\nexport interface SourceRef {\n __kind: typeof RESOURCE_REF_KIND;\n /** Server resource token: \"file\" (A2; \"cld_file\" is a server alias) | \"processed_document\" | \"note\" | \"fc_set\" | … */\n resource_type: string;\n resource_id: string;\n /** \"clean\" | \"raw\" | \"pdf\" | a family representation key. Omitted = server's Clean → Raw → original fallback. */\n representation?: string;\n /** Hand-picked Segment ids (rag.kg_chunks ids or \"<resource_id>:<n>\"). */\n include_segments?: string[];\n /** Include the text (default \"direct\") | the AI fetches it on demand (\"context\"). */\n delivery?: SourceDelivery;\n /** Per-Source cap chosen on the review page. */\n max_chars?: number;\n promote?: ResourcePromotion | ResourcePromotion[];\n exclude?: string[];\n}\n\nexport interface SourceSet {\n __kind: typeof SOURCE_SET_KIND;\n version: typeof SOURCE_SET_VERSION;\n sources: SourceRef[];\n /** Only for \"Just a topic\". */\n topic?: string;\n /** Default \"whole\". */\n grounding?: SourceGrounding;\n /** Required in spirit when grounding = \"retrieve\". */\n retrieve_query?: string;\n /** The model whose context window sets the budget. */\n target_model_id?: string;\n}\n\nexport type SourceState = \"ready\" | \"processing\" | \"failed\" | \"unavailable\";\n\nexport interface SourceManifestForm {\n form: string;\n label: string;\n chars: number;\n available: boolean;\n}\n\nexport interface SourceManifestSegment {\n id: string;\n /** \"Page 7\", \"Pages 22–24\" (a part spanning pages), \"0:04–2:31\", a heading path, \"Part 3\". */\n label: string;\n page?: number;\n chars: number;\n /**\n * Amendment A5: the part's opening words (about 160 characters, whitespace\n * collapsed) — never its body. Lets a person see what a part says and find\n * a part by its words.\n */\n preview?: string;\n}\n\nexport interface SourceManifestEntry {\n ref: SourceRef;\n label: string;\n resource_type: string;\n state: SourceState;\n state_detail?: string;\n forms: SourceManifestForm[];\n default_form: string;\n segments?: SourceManifestSegment[];\n}\n\n/** POST /sources/manifest { source_set } → sizes and states, never bodies. */\nexport interface SourceManifest {\n __kind: typeof SOURCE_MANIFEST_KIND;\n sources: SourceManifestEntry[];\n total_chars: number;\n estimated_tokens: number;\n /** null = unknown model; the UI says so. */\n model_context_tokens: number | null;\n}\n\nexport interface ResolvedSourceSegment {\n id: string;\n page?: number;\n chars: number;\n}\n\nexport interface ResolvedSource {\n ref: SourceRef;\n label: string;\n form_used: string;\n /** Grounded: \"### Chunk <id> (page N)\" blocks; never re-chunked. */\n text: string;\n segments: ResolvedSourceSegment[];\n file_id?: string;\n processed_document_id?: string;\n /** \"processing\" = the raw fallback was used. */\n state: \"ready\" | \"processing\";\n truncated: boolean;\n /** Every stand-in announces itself. */\n notes: string[];\n}\n\n/** A1 (2026-09-27): \"not_ready\" = a file not yet read. */\nexport type DroppedSourceReason =\n | \"no_access\"\n | \"missing\"\n | \"failed\"\n | \"over_budget\"\n | \"not_ready\";\n\nexport interface DroppedSource {\n ref: SourceRef;\n reason: DroppedSourceReason;\n /** A1: what happened and what to do. */\n detail?: string;\n}\n\n/** POST /sources/resolve { source_set } → grounded text for generators. */\nexport interface ResolvedSourceSet {\n __kind: typeof RESOLVED_SOURCE_SET_KIND;\n sources: ResolvedSource[];\n dropped: DroppedSource[];\n total_chars: number;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers\n// ---------------------------------------------------------------------------\n\n/** Builder options. `undefined` is accepted everywhere so callers can forward an existing ref's optional fields. */\nexport interface SourceRefOptions {\n representation?: string | undefined;\n include_segments?: readonly string[] | undefined;\n delivery?: SourceDelivery | undefined;\n max_chars?: number | undefined;\n promote?: ResourcePromotion | ResourcePromotion[] | undefined;\n exclude?: readonly string[] | undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Build one pointer. Empty optional fields are omitted (so the wire stays\n * minimal and equal pointers serialise equally); `exclude` is trimmed,\n * lower-cased and de-duplicated exactly as the server normalises it;\n * `include_segments` is de-duplicated in order. Throws on an empty type or id —\n * a pointer to nothing is never built silently.\n */\nexport function createSourceRef(\n resourceType: string,\n resourceId: string,\n options: SourceRefOptions = {},\n): SourceRef {\n const resource_type = resourceType.trim();\n const resource_id = resourceId.trim();\n if (!resource_type) throw new Error(\"createSourceRef: resource_type is required\");\n if (!resource_id) throw new Error(\"createSourceRef: resource_id is required\");\n if (\n options.max_chars !== undefined &&\n (!Number.isInteger(options.max_chars) || options.max_chars <= 0)\n ) {\n throw new Error(\"createSourceRef: max_chars must be a positive integer\");\n }\n const exclude = Array.from(\n new Set(\n (options.exclude ?? [])\n .map((value) => value.trim().toLowerCase())\n .filter(Boolean),\n ),\n );\n const include_segments = Array.from(\n new Set((options.include_segments ?? []).map((id) => id.trim()).filter(Boolean)),\n );\n return {\n __kind: RESOURCE_REF_KIND,\n resource_type,\n resource_id,\n ...(options.representation ? { representation: options.representation } : {}),\n ...(include_segments.length ? { include_segments } : {}),\n ...(options.delivery ? { delivery: options.delivery } : {}),\n ...(options.max_chars !== undefined ? { max_chars: options.max_chars } : {}),\n ...(options.promote ? { promote: options.promote } : {}),\n ...(exclude.length ? { exclude } : {}),\n };\n}\n\nexport function isSourceRef(value: unknown): value is SourceRef {\n return (\n isRecord(value) &&\n value.__kind === RESOURCE_REF_KIND &&\n typeof value.resource_type === \"string\" &&\n value.resource_type.length > 0 &&\n typeof value.resource_id === \"string\" &&\n value.resource_id.length > 0\n );\n}\n\nexport interface SourceSetOptions {\n topic?: string | undefined;\n grounding?: SourceGrounding | undefined;\n retrieve_query?: string | undefined;\n target_model_id?: string | undefined;\n}\n\n/**\n * Build one envelope. Duplicate pointers (same type + id + representation) are\n * collapsed, keeping the first. `grounding: \"retrieve\"` without a query and\n * `grounding: \"selected\"` with no Source carrying `include_segments` throw —\n * both would otherwise resolve to something the person never asked for.\n */\nexport function createSourceSet(\n sources: readonly SourceRef[],\n options: SourceSetOptions = {},\n): SourceSet {\n const seen = new Set<string>();\n const unique: SourceRef[] = [];\n for (const ref of sources) {\n if (!isSourceRef(ref)) throw new Error(\"createSourceSet: every source must be a resource_ref\");\n const key = `${ref.resource_type}\\u0000${ref.resource_id}\\u0000${ref.representation ?? \"\"}`;\n if (seen.has(key)) continue;\n seen.add(key);\n unique.push(ref);\n }\n const topic = options.topic?.trim();\n const retrieve_query = options.retrieve_query?.trim();\n if (options.grounding === \"retrieve\" && !retrieve_query) {\n throw new Error('createSourceSet: grounding \"retrieve\" needs a retrieve_query');\n }\n if (\n options.grounding === \"selected\" &&\n !unique.some((ref) => (ref.include_segments?.length ?? 0) > 0)\n ) {\n throw new Error('createSourceSet: grounding \"selected\" needs at least one Source with include_segments');\n }\n return {\n __kind: SOURCE_SET_KIND,\n version: SOURCE_SET_VERSION,\n sources: unique,\n ...(topic ? { topic } : {}),\n ...(options.grounding ? { grounding: options.grounding } : {}),\n ...(retrieve_query ? { retrieve_query } : {}),\n ...(options.target_model_id ? { target_model_id: options.target_model_id } : {}),\n };\n}\n\n/** Structural guard for a wire value claiming to be a v1 `SourceSet`. */\nexport function isSourceSet(value: unknown): value is SourceSet {\n return (\n isRecord(value) &&\n value.__kind === SOURCE_SET_KIND &&\n value.version === SOURCE_SET_VERSION &&\n Array.isArray(value.sources) &&\n value.sources.every(isSourceRef)\n );\n}\n\nfunction manifestEntryChars(entry: SourceManifestEntry): number {\n const selected = entry.ref.include_segments;\n let chars: number;\n if (selected?.length && entry.segments?.length) {\n const wanted = new Set(selected);\n chars = entry.segments\n .filter((segment) => wanted.has(segment.id))\n .reduce((sum, segment) => sum + segment.chars, 0);\n } else {\n const formKey = entry.ref.representation ?? entry.default_form;\n const form =\n entry.forms.find((candidate) => candidate.form === formKey) ??\n entry.forms.find((candidate) => candidate.form === entry.default_form);\n chars = form?.chars ?? 0;\n }\n return entry.ref.max_chars !== undefined ? Math.min(chars, entry.ref.max_chars) : chars;\n}\n\n/**\n * Characters that will actually go in, computed from the Sources themselves\n * (never trusting a stale `total_chars`):\n * - `ResolvedSourceSet`: the sum of every resolved text's length.\n * - `SourceManifest`: per Source, the chosen form's size (the ref's\n * `representation`, else `default_form`), or the picked Segments' sizes when\n * `include_segments` is set, capped by the ref's `max_chars`. Sources whose\n * state is \"failed\" or \"unavailable\" contribute nothing — they cannot go in.\n */\nexport function totalChars(value: SourceManifest | ResolvedSourceSet): number {\n if (value.__kind === RESOLVED_SOURCE_SET_KIND) {\n return value.sources.reduce((sum, source) => sum + source.text.length, 0);\n }\n return value.sources\n .filter((entry) => entry.state === \"ready\" || entry.state === \"processing\")\n .reduce((sum, entry) => sum + manifestEntryChars(entry), 0);\n}\n","/**\n * How the AI gets a Source — THE one source of truth for delivery.\n *\n * The frozen contract (`SourceRef.delivery`, `@ai-matrx/agents/sources`) has\n * two values and a default: absent / \"direct\" = the text is handed to the AI\n * with the request; \"context\" = nothing is sent up front and the AI opens the\n * Source while it works. The server (aidream `source_resolution.py`) reads\n * exactly this field and nothing else — `promote` / `exclude` are NOT read on\n * the Source path.\n *\n * Every screen that shows or changes delivery (the Source card, \"Review what\n * goes in\", the planner) reads it through `sourceDelivery` and says it with\n * `DELIVERY_WORDS`, so a card can never say one thing while the review and the\n * request say another (V1-A: the card said \"Nothing is copied in\" — chat's\n * attachment editor's wording — while the review said \"Include the text\" and\n * the request carried the text).\n */\n\nimport type { SourceDelivery, SourceRef, SourceRefOptions } from \"../index\";\n\nexport type { SourceDelivery };\n\n/** The delivery a pointer asks for — absent means the contract default, \"direct\". */\nexport function sourceDelivery(ref: Pick<SourceRef, \"delivery\"> | null | undefined): SourceDelivery {\n return ref?.delivery === \"context\" ? \"context\" : \"direct\";\n}\n\n/**\n * The patch that sets a delivery. \"direct\" is the default, so it clears the\n * field (the wire stays minimal, exactly as the review has always written it).\n * Looking a Source up sends no text, so parts and a size limit no longer apply.\n */\nexport function deliveryPatch(\n delivery: SourceDelivery,\n): Pick<SourceRefOptions, \"delivery\" | \"include_segments\" | \"max_chars\"> {\n return delivery === \"context\"\n ? { delivery: \"context\", include_segments: undefined, max_chars: undefined }\n : { delivery: undefined };\n}\n\nexport interface DeliveryWords {\n /** The choice's name on a control. */\n label: string;\n /** Two or three words under the control: what happens (copy law R9). */\n hint: string;\n /** The short phrase a summary line uses. */\n summary: string;\n}\n\nexport const DELIVERY_WORDS: Record<SourceDelivery, DeliveryWords> = {\n direct: {\n label: \"Include the text\",\n hint: \"Sent in full\",\n summary: \"Text included\",\n },\n context: {\n label: \"Let the AI look it up\",\n hint: \"Read as needed\",\n summary: \"Looked up when needed\",\n },\n};\n\n/** The choices, in the order every control shows them. */\nexport const DELIVERY_CHOICES: ReadonlyArray<{ value: SourceDelivery } & DeliveryWords> = (\n [\"direct\", \"context\"] as const\n).map((value) => ({ value, ...DELIVERY_WORDS[value] }));\n\n/**\n * What a HOST can use. Not every host can take every delivery: a generator\n * that needs the text up front (flashcards' segmented generator reads the\n * resolved text and nothing else) gets NOTHING from a Source set to \"look it\n * up\" — V2 verifier shots 06/26: the request went out with `delivery:\n * \"context\"` and the page said \"None of the Sources had any text\", which was\n * false. So a host declares the deliveries it can use (`SourceInputProps.\n * deliveries`); the card and the review offer only those, and a Source already\n * set to something the host cannot use is switched back — with a note on it.\n * Omitted = both (a host whose AI can open Sources while it works).\n */\nexport function allowedDeliveries(\n deliveries: readonly SourceDelivery[] | undefined,\n): readonly SourceDelivery[] {\n const allowed = ([\"direct\", \"context\"] as const).filter((d) => !deliveries || deliveries.includes(d));\n // A host that lists nothing it can use still gets the contract default.\n return allowed.length > 0 ? allowed : [\"direct\"];\n}\n\n/** The choices one host offers, in the order every control shows them. */\nexport function deliveryChoicesFor(\n deliveries: readonly SourceDelivery[] | undefined,\n): ReadonlyArray<{ value: SourceDelivery } & DeliveryWords> {\n const allowed = allowedDeliveries(deliveries);\n return DELIVERY_CHOICES.filter((c) => allowed.includes(c.value));\n}\n\n/** The sentence a switched-back Source carries — every intervention announces itself. */\nexport function deliverySwitchedNote(to: SourceDelivery): string {\n return to === \"direct\"\n ? `This Source was set to \"${DELIVERY_WORDS.context.label}\", which this page cannot use — it needs the text up front — so it was switched back to \"${DELIVERY_WORDS.direct.label}\".`\n : `This Source was set to \"${DELIVERY_WORDS.direct.label}\", which this page cannot use, so it was switched to \"${DELIVERY_WORDS.context.label}\".`;\n}\n\n/**\n * Fit a pointer to what the host can use. Returns the patch to apply (null\n * when it already fits) and the delivery it lands on.\n */\nexport function fitDelivery(\n ref: Pick<SourceRef, \"delivery\"> | null | undefined,\n deliveries: readonly SourceDelivery[] | undefined,\n): { patch: ReturnType<typeof deliveryPatch>; to: SourceDelivery } | null {\n if (!ref) return null;\n const allowed = allowedDeliveries(deliveries);\n const current = sourceDelivery(ref);\n if (allowed.includes(current)) return null;\n const to = allowed[0]!;\n return { patch: deliveryPatch(to), to };\n}\n","/**\n * Finding a part of a Source — THE one matcher, used by the Source card's\n * \"Choose parts\" and by \"Review what goes in\".\n *\n * A query is one of:\n * - a page number (\"12\") — the part that covers that page;\n * - a page range (\"3-10\", \"3–10\", \"3 to 10\") — every part inside it;\n * - words — every word must appear in the part's label or its preview (the\n * opening words the manifest carries, contract amendment A5), matched here;\n * or the part is one the server found holding every word in its full text\n * (`POST /sources/parts/search`, via `useSourcePartsSearch`).\n *\n * A part spanning several pages (\"Pages 22–24\") covers each of them: the\n * manifest's numeric `page` is its first page and the label names the span.\n *\n * V1-A: the search promised \"words\" but matched only labels, so\n * \"photosynthesis\" found nothing in a biology course.\n */\n\nimport type { SourceManifestSegment } from \"../index\";\n\n/** A manifest part, with the A5 preview (optional on the wire). */\nexport type SourcePart = SourceManifestSegment & { preview?: string };\n\n/** The ids of parts the server found holding every word (`useSourcePartsSearch`). */\nexport type PartMatchIds = ReadonlySet<string>;\n\nconst RANGE_RE = /^(\\d+)\\s*(?:-|–|—|to)\\s*(\\d+)$/;\nconst SPAN_RE = /(\\d+)\\s*[–—-]\\s*(\\d+)/;\n\n/** The pages a part covers: its label's span (\"Pages 22–24\") or its one page. */\nexport function partPages(part: SourcePart): [number, number] | null {\n if (part.page === undefined || part.page === null) return null;\n const span = /^pages?\\s/i.test(part.label) ? SPAN_RE.exec(part.label) : null;\n if (span) return [Number(span[1]), Number(span[2])];\n return [part.page, part.page];\n}\n\n/** True when a query is words (not a page or a range) — only then is the text searched. */\nexport function isWordQuery(query: string): boolean {\n const q = query.trim().toLowerCase();\n return q.length > 0 && !/^\\d+$/.test(q) && !RANGE_RE.test(q);\n}\n\nfunction normalise(text: string): string {\n return text.toLowerCase().replace(/\\s+/g, \" \");\n}\n\nexport function matchesPart(part: SourcePart, query: string, serverMatches?: PartMatchIds): boolean {\n const q = query.trim().toLowerCase();\n if (!q) return true;\n const pages = partPages(part);\n const range = RANGE_RE.exec(q);\n if (range && pages) {\n const from = Math.min(Number(range[1]), Number(range[2]));\n const to = Math.max(Number(range[1]), Number(range[2]));\n return pages[0] <= to && pages[1] >= from;\n }\n if (/^\\d+$/.test(q) && pages) {\n const n = Number(q);\n return pages[0] <= n && n <= pages[1];\n }\n if (part.id.toLowerCase() === q) return true;\n if (serverMatches?.has(part.id)) return true;\n const haystack = normalise([part.label, part.preview ?? \"\"].join(\" \"));\n return q\n .split(/\\s+/)\n .filter(Boolean)\n .every((word) => haystack.includes(word));\n}\n\n/** The parts a query shows, in the Source's own order. */\nexport function findParts<T extends SourcePart>(\n parts: readonly T[],\n query: string,\n serverMatches?: PartMatchIds,\n): T[] {\n return parts.filter((p) => matchesPart(p, query, serverMatches));\n}\n","/**\n * What a Source that was still landing becomes when the page reloads.\n *\n * Never lose input (table stakes): the pasted text, the link, or an\n * already-uploaded recording is kept in the draft (`SourceDraft.input`), so\n * the input picks it up again by itself — the landing door dedupes by content\n * hash, so landing it a second time reuses the same Source, never a copy.\n * A file that was mid-upload cannot come back (its bytes lived only in the\n * browser tab); the card says so honestly and keeps the file's name so the\n * person can choose it again in one click.\n */\n\nimport type { SourceDraft, SourceIntakeInput } from \"./types\";\n\n/** Shown while a kept input is being landed again after a reload. */\nexport const RELOADED_RESUMING =\n \"The page reloaded while this was being added — picking it up again.\";\n\n/** A kept input exists but has not been re-landed (it will be, or the person can press Try again). */\nexport const RELOADED_WHILE_ADDING =\n \"This was still being added when the page reloaded, so it did not finish. Add it again.\";\n\n/** The kinds whose landing can be repeated from what the draft kept. */\nexport function resumableInput(draft: SourceDraft): SourceIntakeInput | null {\n const input = draft.input;\n if (!input) return null;\n switch (draft.kind) {\n case \"paste\":\n return input.text?.trim() ? input : null;\n case \"web\":\n case \"youtube\":\n return input.url?.trim() ? input : null;\n case \"audio\":\n // An uploaded recording re-transcribes from its file; one recorded in\n // place (the Voice Pad) is already text and lands again from it.\n return input.fileId || input.text?.trim() ? input : null;\n default:\n return null;\n }\n}\n\n/** The sentence for a file whose upload the reload cut off. */\nexport function uploadCutOffSentence(draft: SourceDraft): string {\n return `\"${draft.label}\" was still uploading when the page reloaded, so it did not arrive. Choose it again to add it.`;\n}\n\nexport interface ReloadedCard {\n /** \"resume\" = land the kept input again now; \"reoffer\" = the person must re-choose a file. */\n action: \"resume\" | \"reoffer\" | \"lost\";\n sentence: string;\n}\n\n/**\n * The one decision: a card that was `pending`/`resolving` when the page\n * unloaded. Cards in any other state are restored unchanged (returns null).\n */\nexport function reloadedCard(\n draft: SourceDraft,\n status: \"pending\" | \"resolving\" | \"ready\" | \"error\",\n): ReloadedCard | null {\n if (status !== \"pending\" && status !== \"resolving\") return null;\n if (resumableInput(draft)) return { action: \"resume\", sentence: RELOADED_RESUMING };\n if (draft.kind === \"upload\" || draft.kind === \"image\" || draft.kind === \"audio\")\n return { action: \"reoffer\", sentence: uploadCutOffSentence(draft) };\n return { action: \"lost\", sentence: RELOADED_WHILE_ADDING };\n}\n\n/**\n * The knob for the largest pasted text kept in the device draft (it would\n * crowd the draft store). Read by the intake; while unread nothing is kept and\n * the card says so.\n */\nexport const MAX_KEPT_TEXT_KNOB = { feature: \"sources\", key: \"max_kept_draft_chars\" } as const;\n\n/** Said on a pasted card whose text is too large (or the limit unreadable) to keep for a reload. */\nexport const NOT_KEPT_FOR_RELOAD =\n \"Too large to restore if the page reloads before it is added.\";\n\n/**\n * A landing stopped only because no organization is chosen yet. The card\n * waits; the moment one is set the intake lands every waiting card again from\n * what its draft kept (state, never an in-memory queue — it survives a reload).\n */\nexport const WAITING_FOR_ORGANIZATION =\n \"Waiting for an organization — choose one and this continues by itself.\";\n\n/** A read Source whose keep waits for an organization; kept again once one is set. */\nexport const KEEP_WAITING_FOR_ORGANIZATION =\n \"Read. Waiting for an organization to keep it — choose one and it is kept by itself.\";\n","/**\n * fileSource — how a stored file on a Source card becomes its Source, decided\n * from the SERVER's state alone (USI-3e). Pure: the one read\n * (`/files/{id}/rag-status`) and the file's own organization are INJECTED by\n * the host (`SourceFileState` below), never imported.\n *\n * The server owns reading a file: every upload's finalize already starts the\n * one processing run (the file adapters → a `processed_documents` row), and\n * `/files/{id}/rag-status` merges that run's lifecycle row with the Source it\n * made. So a card never starts its own run while one is live, a reload simply\n * reads the state again (re-attach, never a second job), and a file someone\n * already had (\"use the one you already have\", or picked from Files) is kept\n * the moment its existing Source is seen.\n */\n\nimport type { SourceCardModel } from \"./types\";\n\n/** The part of the server's `/files/{id}/rag-status` answer the decision reads. */\nexport interface FileSourceStatus {\n state: string;\n processed_document_id?: string | null | undefined;\n error?: { message?: string | null | undefined; [detail: string]: unknown } | null | undefined;\n}\n\nexport type FileSourceStep =\n /** The Source exists: keep it and file it against the thing being made. */\n | { do: \"keep\"; processedDocumentId: string }\n /** A run is reading it now (server-side or this tab's own). Look again soon. */\n | { do: \"wait\" }\n /** Nothing is reading it and it has no Source yet: start the one run. */\n | { do: \"start\" }\n /** It cannot become a Source; say why, and stop looking. */\n | { do: \"unreadable\"; reason: string };\n\nexport interface FileSourceContext {\n /** This card already started a run in this page's life. */\n started: boolean;\n /** This tab's processing runner has a live run for the file. */\n localRunning: boolean;\n}\n\nconst UNREADABLE = \"Can't read this file — add a PDF, Word or text copy.\";\n\n/** The one decision. `status` is the server's `/files/{id}/rag-status` answer. */\nexport function nextFileStep(\n status: FileSourceStatus | null,\n ctx: FileSourceContext,\n): FileSourceStep {\n const pdId = status?.processed_document_id ?? null;\n if (pdId) return { do: \"keep\", processedDocumentId: pdId };\n if (ctx.localRunning || status?.state === \"running\") return { do: \"wait\" };\n if (status?.state === \"failed\")\n return {\n do: \"unreadable\",\n reason: status.error?.message\n ? `Can't read this file: ${status.error.message}. Add it again.`\n : UNREADABLE,\n };\n if (!ctx.started) return { do: \"start\" };\n return { do: \"unreadable\", reason: UNREADABLE };\n}\n\n/** How long to wait before looking again: quick at first, then spaced out. */\nexport function fileSourcePollDelayMs(round: number): number {\n if (round < 5) return 3_000;\n if (round < 20) return 6_000;\n return 15_000;\n}\n\n/** A stored file on a card whose Source is not known yet — the recovery reads its state. */\nexport function isWaitingFileCard(card: SourceCardModel): boolean {\n return (\n card.status === \"ready\" &&\n card.draft.ref?.resource_type === \"file\" &&\n !!card.draft.fileId &&\n !card.draft.processedDocumentId\n );\n}\n\n/**\n * True while a waiting file card cannot be asked about yet: `/files/{id}/\n * rag-status` answers only with an organization (the file's own, when the\n * host knows it, or the one the person picked). Without one every read was a\n * refused 400 — every ~3 s, piling up as page errors (V2-F #3). So the card\n * is HELD: it says it is waiting for an organization, offers the one picker,\n * and nothing is asked until one is known.\n *\n * `fileOrganizationId` is the host's lookup of a file's own organization\n * (omitted = the host does not know it).\n */\nexport function fileCardHeldForOrganization(\n card: SourceCardModel,\n activeOrganizationId: string | null | undefined,\n fileOrganizationId?: (fileId: string) => string | null | undefined,\n): boolean {\n if (!isWaitingFileCard(card)) return false;\n if (activeOrganizationId) return false;\n return !fileOrganizationId?.(card.draft.fileId as string);\n}\n","/**\n * The source-list state machine — pure reducers and selectors over\n * `SourceSetState`. Every function returns a NEW state (or the same one when\n * nothing changed) and never touches a store, a network or a clock; the\n * controller (`controller.ts`) applies them through the host's store adapter.\n *\n * The rules here are the ones the web app's Source input has always kept:\n * - landing the same Source twice keeps ONE card and says so on it;\n * - a settled card drops the input it kept for a reload;\n * - a card cut off mid-landing by a reload is restored as an error the\n * input resolves (`interrupted.ts`), never a spinner forever;\n * - a new Source starts on the host's default form.\n */\n\nimport {\n createSourceRef,\n createSourceSet,\n totalChars as sumChars,\n type ResolvedSourceSet,\n type SourceManifest,\n type SourceManifestEntry,\n type SourceRef,\n type SourceRefOptions,\n type SourceSet,\n} from \"../index\";\nimport { deliverySwitchedNote, fitDelivery, type SourceDelivery } from \"./delivery\";\nimport { reloadedCard, WAITING_FOR_ORGANIZATION } from \"./interrupted\";\nimport { partPages } from \"./partsSearch\";\nimport type {\n PersistedSourceCard,\n PersistedSourceInput,\n SourceCardModel,\n SourceDraft,\n SourcePickedPart,\n SourceSetState,\n} from \"./types\";\n\nexport const EMPTY_SOURCE_SET_STATE: SourceSetState = Object.freeze({ cards: Object.freeze([]), topic: \"\" }) as SourceSetState;\n\n/** Said when a Source's parts were re-read (the clean version landed) and the pick was carried over by page. */\nexport const PARTS_MATCHED_BY_PAGE = \"The clean version is ready — your parts were matched to it by page.\";\n\n/** Said when a pick could not be carried over to the Source's new parts: the whole Source goes in until parts are chosen again. */\nexport const PARTS_NOT_MATCHED =\n \"The clean version is ready, but your parts could not be matched to it — choose parts again. Until then the whole Source goes in.\";\n\n/** Said on the one card kept when the same Source lands twice. */\nexport const SAME_SOURCE_AGAIN = \"You added this again — it is the same Source, so it is listed once.\";\n\nexport function isSourceDraft(value: unknown): value is SourceDraft {\n return (\n !!value &&\n typeof value === \"object\" &&\n typeof (value as SourceDraft).kind === \"string\" &&\n typeof (value as SourceDraft).label === \"string\"\n );\n}\n\nexport function sameSourceRef(\n a: Pick<SourceRef, \"resource_type\" | \"resource_id\">,\n b: Pick<SourceRef, \"resource_type\" | \"resource_id\">,\n): boolean {\n return a.resource_type === b.resource_type && a.resource_id === b.resource_id;\n}\n\n/** \"<resource_type>:<resource_id>\" — how a Source is keyed across screens. */\nexport function sourceKey(ref: { resource_type: string; resource_id: string }): string {\n return `${ref.resource_type}:${ref.resource_id}`;\n}\n\n/** The draft kind a registry token is picked as. */\nexport function draftKindForToken(token: string): SourceDraft[\"kind\"] {\n if (token === \"file\") return \"files\";\n if (token === \"note\") return \"notes\";\n if (token === \"processed_document\") return \"your_sources\";\n return \"records\";\n}\n\n/** A new pointer starts on the host's default form (never over one already chosen). */\nexport function withDefaultForm(ref: SourceRef, defaultForm: string | undefined): SourceRef {\n return defaultForm && !ref.representation\n ? createSourceRef(ref.resource_type, ref.resource_id, { ...ref, representation: defaultForm })\n : ref;\n}\n\nfunction cardById(state: SourceSetState, id: string): SourceCardModel | undefined {\n return state.cards.find((c) => c.id === id);\n}\n\nfunction replaceCard(\n state: SourceSetState,\n id: string,\n patch: (card: SourceCardModel) => SourceCardModel,\n): SourceSetState {\n let changed = false;\n const cards = state.cards.map((c) => {\n if (c.id !== id) return c;\n const next = patch(c);\n if (next !== c) changed = true;\n return next;\n });\n return changed ? { ...state, cards } : state;\n}\n\n// ── Reducers ────────────────────────────────────────────────────────────────\n\n/** Add a Source that is already a pointer (a stored record, a landed Source). */\nexport function addReadyCard(\n state: SourceSetState,\n id: string,\n draft: SourceDraft,\n options: { defaultForm?: string | undefined } = {},\n): SourceSetState {\n const ref = draft.ref ? withDefaultForm(draft.ref, options.defaultForm) : null;\n return {\n ...state,\n cards: [...state.cards, { id, draft: { ...draft, ref }, status: \"ready\", error: null, manifest: null }],\n };\n}\n\n/** Add a Source that is still landing; finish it with `settleCard` or `failCard`. */\nexport function addPendingCard(\n state: SourceSetState,\n id: string,\n draft: Omit<SourceDraft, \"ref\">,\n): SourceSetState {\n return {\n ...state,\n cards: [...state.cards, { id, draft: { ...draft, ref: null }, status: \"resolving\", error: null, manifest: null }],\n };\n}\n\n/**\n * A landing answered. The door dedupes by content: landing the same thing\n * twice returns the Source already picked — keep ONE card and say so on it.\n */\nexport function settleCard(\n state: SourceSetState,\n id: string,\n patch: Partial<SourceDraft> & { ref: SourceRef },\n options: { defaultForm?: string | undefined } = {},\n): SourceSetState {\n const card = cardById(state, id);\n if (!card) return state; // removed while it was landing — nothing to finish\n const twin = state.cards.find((c) => c.id !== id && c.draft.ref && sameSourceRef(c.draft.ref, patch.ref));\n if (twin) {\n const without = { ...state, cards: state.cards.filter((c) => c.id !== id) };\n if (twin.draft.notes?.includes(SAME_SOURCE_AGAIN)) return without;\n return replaceCard(without, twin.id, (c) => ({\n ...c,\n draft: { ...c.draft, notes: [...(c.draft.notes ?? []), SAME_SOURCE_AGAIN] },\n }));\n }\n return replaceCard(state, id, (c) => ({\n ...c,\n // Landed: the kept input has done its job and leaves the draft.\n draft: { ...c.draft, ...patch, input: undefined, ref: withDefaultForm(patch.ref, options.defaultForm) },\n status: \"ready\",\n error: null,\n }));\n}\n\n/**\n * A card that failed has ONE state — failed. Its last measurement goes, so it\n * can never also say \"Still being read\" (verify-3: a stored PDF showed both).\n */\nexport function failCard(state: SourceSetState, id: string, sentence: string): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, status: \"error\", error: sentence, manifest: null }));\n}\n\n/** Back to landing (after a reload or a failure). */\nexport function restartCard(state: SourceSetState, id: string): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, status: \"resolving\", error: null }));\n}\n\n/** Change what a card says or keeps (label, input, fileId, notes, processedDocumentId). */\nexport function updateCardDraft(\n state: SourceSetState,\n id: string,\n patch: Partial<Omit<SourceDraft, \"ref\">>,\n): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, draft: { ...c.draft, ...patch } }));\n}\n\nexport function removeCard(state: SourceSetState, id: string): SourceSetState {\n if (!cardById(state, id)) return state;\n return { ...state, cards: state.cards.filter((c) => c.id !== id) };\n}\n\n/** Change the pointer's choices (form, parts, cap, delivery). */\nexport function updateCardRef(state: SourceSetState, id: string, options: SourceRefOptions): SourceSetState {\n return replaceCard(state, id, (c) => {\n if (!c.draft.ref) return c;\n const ref = createSourceRef(c.draft.ref.resource_type, c.draft.ref.resource_id, { ...c.draft.ref, ...options });\n return rememberPickedParts({ ...c, draft: { ...c.draft, ref } });\n });\n}\n\n/**\n * Remember where the picked parts sit (label + pages) from the card's current\n * measurement, so a pick survives the Source being re-split (raw pages → clean\n * parts). No parts picked = nothing remembered.\n */\nexport function rememberPickedParts(card: SourceCardModel): SourceCardModel {\n const ids = card.draft.ref?.include_segments ?? [];\n if (ids.length === 0) {\n return card.draft.pickedParts === undefined ? card : { ...card, draft: { ...card.draft, pickedParts: undefined } };\n }\n const segments = card.manifest?.segments ?? [];\n const known = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));\n const picked: SourcePickedPart[] = [];\n for (const id of ids) {\n const segment = segments.find((s) => s.id === id);\n if (segment) {\n const pages = partPages(segment);\n picked.push({ id, label: segment.label, ...(pages ? { pages } : {}) });\n } else {\n const before = known.get(id);\n if (before) picked.push(before);\n }\n }\n return { ...card, draft: { ...card.draft, pickedParts: picked.length ? picked : undefined } };\n}\n\nfunction withNote(notes: readonly string[] | undefined, note: string, drop: readonly string[] = []): string[] {\n const kept = (notes ?? []).filter((n) => n !== note && !drop.includes(n));\n return [...kept, note];\n}\n\n/**\n * A fresh measurement listed NEW parts (the clean version landed, so the raw\n * pages the person picked no longer exist by id). Carry the pick over by page:\n * every new part that covers a page the old pick covered goes in. When the old\n * pick's pages are unknown, the pick is cleared and the card says so — never\n * \"0 characters · 4 of 21 parts\" with nothing ticked (verify-3, 11d/11e).\n */\nexport function carryPickedParts(card: SourceCardModel, entry: SourceManifestEntry): SourceCardModel {\n const ref = card.draft.ref;\n const picked = ref?.include_segments ?? [];\n const segments = entry.segments ?? [];\n if (!ref || picked.length === 0 || segments.length === 0) return card;\n const ids = new Set(segments.map((s) => s.id));\n const stale = picked.filter((id) => !ids.has(id));\n if (stale.length === 0) return card;\n const remembered = new Map((card.draft.pickedParts ?? []).map((p) => [p.id, p]));\n const oldSegments = card.manifest?.segments ?? [];\n const spans: Array<[number, number]> = [];\n let unknown = 0;\n for (const id of stale) {\n const old = oldSegments.find((s) => s.id === id);\n const pages = remembered.get(id)?.pages ?? (old ? partPages(old) : null);\n if (pages) spans.push(pages);\n else unknown += 1;\n }\n const keep = new Set(picked.filter((id) => ids.has(id)));\n for (const segment of segments) {\n const pages = partPages(segment);\n if (pages && spans.some(([from, to]) => pages[0] <= to && pages[1] >= from)) keep.add(segment.id);\n }\n const nextIds = segments.filter((s) => keep.has(s.id)).map((s) => s.id);\n const matched = unknown === 0 && nextIds.length > 0;\n const nextRef = createSourceRef(ref.resource_type, ref.resource_id, {\n ...ref,\n include_segments: matched ? nextIds : undefined,\n });\n const note = matched ? PARTS_MATCHED_BY_PAGE : PARTS_NOT_MATCHED;\n const other = matched ? PARTS_NOT_MATCHED : PARTS_MATCHED_BY_PAGE;\n return rememberPickedParts({\n ...card,\n manifest: entry,\n draft: { ...card.draft, ref: nextRef, notes: withNote(card.draft.notes, note, [other]) },\n });\n}\n\nexport function setCardWaitForClean(state: SourceSetState, id: string, wait: boolean): SourceSetState {\n return replaceCard(state, id, (c) => ({ ...c, draft: { ...c.draft, waitForClean: wait } }));\n}\n\nexport function setSourceTopic(state: SourceSetState, topic: string): SourceSetState {\n return state.topic === topic ? state : { ...state, topic };\n}\n\n/**\n * What the person removed in \"Review what goes in\": the Sources that went INTO\n * the review (`reviewed`) and did not come back in its answer — keyed by\n * `sourceKey`. A Source that landed while the review was open is never in\n * `reviewed`, so it is never removed by it (verify-4 V4-F #3).\n */\nexport function removedInReview(reviewed: SourceSet, answer: SourceSet): Set<string> {\n const kept = new Set(answer.sources.map(sourceKey));\n return new Set(reviewed.sources.map(sourceKey).filter((k) => !kept.has(k)));\n}\n\n/**\n * Apply a set the review returned (forms, parts, caps, delivery) — and its\n * topic. Pass `reviewed` (the set that was sent INTO the review) and every\n * Source removed there leaves the list, bound by its own card id.\n */\nexport function applyReviewedSourceSet(state: SourceSetState, set: SourceSet, reviewed?: SourceSet): SourceSetState {\n let next = state;\n if (reviewed) {\n const removed = removedInReview(reviewed, set);\n for (const card of state.cards) {\n if (card.draft.ref && removed.has(sourceKey(card.draft.ref))) next = removeCard(next, card.id);\n }\n }\n for (const card of next.cards) {\n const ref = card.draft.ref;\n if (!ref) continue;\n const match = set.sources.find((r) => sameSourceRef(r, ref));\n if (!match) continue;\n next = replaceCard(next, card.id, (c) => rememberPickedParts({ ...c, draft: { ...c.draft, ref: match } }));\n }\n return set.topic !== undefined ? setSourceTopic(next, set.topic) : next;\n}\n\n/** The server measured the ready Sources: each ready card takes its entry. */\nexport function applyManifest(state: SourceSetState, manifest: SourceManifest): SourceSetState {\n let next = state;\n for (const card of state.cards) {\n const ref = card.draft.ref;\n if (!ref || card.status !== \"ready\") continue;\n const entry = manifest.sources.find((e) => sameSourceRef(e.ref, ref));\n if (!entry) continue;\n next = replaceCard(next, card.id, (c) => {\n const carried = carryPickedParts(c, entry);\n if (carried !== c) return carried;\n const measured = { ...c, manifest: entry };\n // Parts picked before their pages were known are remembered now.\n return c.draft.ref?.include_segments?.length && !c.draft.pickedParts ? rememberPickedParts(measured) : measured;\n });\n }\n return next;\n}\n\n/**\n * Only what the host can use (V2-F #1): a Source set to a delivery this surface\n * cannot use (picked elsewhere, restored from a draft, handed in by a link) is\n * switched back, and its card says so. Never a choice that cannot work.\n */\nexport function fitCardDeliveries(\n state: SourceSetState,\n deliveries: readonly SourceDelivery[] | undefined,\n): SourceSetState {\n let next = state;\n for (const card of state.cards) {\n const fit = fitDelivery(card.draft.ref, deliveries);\n if (!fit) continue;\n next = updateCardRef(next, card.id, fit.patch);\n const note = deliverySwitchedNote(fit.to);\n if (!card.draft.notes?.includes(note))\n next = updateCardDraft(next, card.id, { notes: [...(card.draft.notes ?? []), note] });\n }\n return next;\n}\n\n// ── Persistence (a draft store keeps this for a reload) ─────────────────────\n\n/** Read whatever a draft store handed back; anything malformed is dropped. */\nexport function readPersistedSourceInput(data: unknown): PersistedSourceInput {\n const record = data && typeof data === \"object\" ? (data as Record<string, unknown>) : undefined;\n const sources = Array.isArray(record?.sources)\n ? (record.sources as PersistedSourceCard[]).filter(\n (c) => !!c && typeof c.id === \"string\" && isSourceDraft(c.draft),\n )\n : [];\n return { sources, topic: typeof record?.topic === \"string\" ? record.topic : \"\" };\n}\n\nexport function toPersistedSourceInput(state: SourceSetState): PersistedSourceInput {\n return {\n sources: state.cards.map((c) => ({ id: c.id, draft: c.draft, status: c.status, error: c.error })),\n topic: state.topic,\n };\n}\n\n/**\n * The cards a reload brings back. A card cut off mid-landing becomes an error\n * the input resolves (it re-lands the kept input, or asks for the file again)\n * — never a spinner forever. A landing held for an organization lost its hold\n * with the page: it is picked up again like one cut off mid-landing.\n */\nexport function restoredCards(persisted: PersistedSourceInput): SourceCardModel[] {\n return persisted.sources.map((card) => {\n const reloaded = reloadedCard(\n card.draft,\n card.status === \"error\" && card.error === WAITING_FOR_ORGANIZATION ? \"resolving\" : card.status,\n );\n return {\n id: card.id,\n draft: card.draft,\n status: reloaded ? \"error\" : card.status,\n error: reloaded ? reloaded.sentence : (card.error ?? null),\n manifest: null,\n };\n });\n}\n\n// ── Selectors ───────────────────────────────────────────────────────────────\n\nexport function readySourceRefs(state: SourceSetState): SourceRef[] {\n return state.cards.flatMap((c) => (c.status === \"ready\" && c.draft.ref ? [c.draft.ref] : []));\n}\n\nexport function hasSourceRef(state: SourceSetState, resourceType: string, resourceId: string): boolean {\n return state.cards.some(\n (c) => c.draft.ref?.resource_type === resourceType && c.draft.ref.resource_id === resourceId,\n );\n}\n\n/** The frozen v1 payload, built from the ready Sources. */\nexport function selectSourceSet(\n state: SourceSetState,\n options: { targetModelId?: string | undefined } = {},\n): SourceSet {\n const topic = state.topic.trim();\n return createSourceSet(readySourceRefs(state), {\n topic: topic || undefined,\n grounding: \"whole\",\n target_model_id: options.targetModelId,\n });\n}\n\n/**\n * THE one size rule (the contract's `totalChars`): the chosen form, or the\n * picked parts, capped — measured against each card's CURRENT pointer.\n */\nexport function selectTotalChars(state: SourceSetState): number {\n const measured: SourceManifestEntry[] = state.cards.flatMap((c) =>\n c.status === \"ready\" && c.manifest && c.draft.ref ? [{ ...c.manifest, ref: c.draft.ref }] : [],\n );\n if (!measured.length) return 0;\n return sumChars({\n __kind: \"source_manifest\",\n sources: measured,\n total_chars: 0,\n estimated_tokens: 0,\n model_context_tokens: null,\n });\n}\n\n/**\n * THE one size of one Source (verify-3: one Source read 109k, 115k, 108k and\n * 106k on four screens): the contract's rule — the chosen form, or the picked\n * parts, capped by `max_chars` — measured against the card's CURRENT pointer.\n * The card, the header total (`selectTotalChars`) and the review (`SourcePlanEntry.chars`)\n * all read this. Null when it is not measured or cannot go in.\n */\nexport function sourceEntryChars(entry: SourceManifestEntry, ref: SourceRef): number | null {\n if (entry.state !== \"ready\" && entry.state !== \"processing\") return null;\n return sumChars({\n __kind: \"source_manifest\",\n sources: [{ ...entry, ref }],\n total_chars: 0,\n estimated_tokens: 0,\n model_context_tokens: null,\n });\n}\n\nexport function sourceCardChars(card: Pick<SourceCardModel, \"draft\" | \"manifest\">): number | null {\n return card.manifest && card.draft.ref ? sourceEntryChars(card.manifest, card.draft.ref) : null;\n}\n\n/**\n * THE one state of one Source card, derived once: its own lifecycle wins\n * (adding, waiting for an organization, failed); only a card that landed takes\n * the server's measured state. Never two states at once.\n */\nexport type SourceCardState =\n | \"adding\"\n | \"waiting_for_organization\"\n | \"failed\"\n | \"unmeasured\"\n | SourceManifestEntry[\"state\"];\n\nexport function sourceCardState(card: Pick<SourceCardModel, \"status\" | \"error\" | \"manifest\">): SourceCardState {\n if (card.status === \"pending\" || card.status === \"resolving\") return \"adding\";\n if (card.status === \"error\") return card.error === WAITING_FOR_ORGANIZATION ? \"waiting_for_organization\" : \"failed\";\n return card.manifest?.state ?? \"unmeasured\";\n}\n\n/** The server's measured state to show on a card — only for a card that landed (null otherwise). */\nexport function sourceCardMeasuredState(\n card: Pick<SourceCardModel, \"status\" | \"error\" | \"manifest\">,\n): SourceManifestEntry[\"state\"] | null {\n return card.status === \"ready\" ? (card.manifest?.state ?? null) : null;\n}\n\n/** Every Source finished landing (nothing pending) and none failed. */\nexport function selectSettled(state: SourceSetState): boolean {\n return state.cards.every((c) => c.status === \"ready\");\n}\n\n/** How many more Sources fit under the host's max (Infinity when there is none). */\nexport function sourceRoomLeft(state: SourceSetState, max: number | undefined): number {\n return max === undefined ? Number.POSITIVE_INFINITY : Math.max(0, max - state.cards.length);\n}\n\n/**\n * Every generator names a Source the way the person saw it on its card — the\n * file name, the name they gave pasted text — never the stored document's own\n * title (V2-F #5). The server's label stays only for a Source the input does\n * not hold.\n */\nexport function withDisplayNames(\n resolved: ResolvedSourceSet,\n cards: readonly Pick<SourceCardModel, \"draft\">[],\n): ResolvedSourceSet {\n const names = new Map<string, string>();\n for (const c of cards) {\n const label = c.draft.label?.trim();\n if (c.draft.ref && label) names.set(sourceKey(c.draft.ref), label);\n }\n return {\n ...resolved,\n sources: resolved.sources.map((s) => {\n const name = names.get(sourceKey(s.ref));\n return name ? { ...s, label: name } : s;\n }),\n };\n}\n","/**\n * The Source-set controller — the imperative face of the state machine, with\n * every outside dependency injected through one adapter:\n *\n * - `store` where the cards live (a Redux slice, a Zustand store, the\n * in-memory store below — the host's choice);\n * - `persistence` the draft store a reload reads back (optional);\n * - `client` the Source doors (`createSourcesClient(transport)`);\n * - `config` the host's choices: default form, organization, the\n * deliveries it can use, the most Sources it takes.\n *\n * Every screen (the Studio grid, a compact strip, chat's \"+\", the review)\n * drives the SAME controller; `@ai-matrx/agents/sources/react` binds it to\n * React with `useSourceSet(adapter)`.\n */\n\nimport {\n createSourceSet,\n type ResolvedSourceSet,\n type SourceManifest,\n type SourceRef,\n type SourceRefOptions,\n type SourceSet,\n} from \"../index\";\nimport type { SourcesClient } from \"./client\";\nimport type { SourceDelivery } from \"./delivery\";\nimport {\n addPendingCard,\n addReadyCard,\n applyManifest,\n applyReviewedSourceSet,\n EMPTY_SOURCE_SET_STATE,\n failCard,\n fitCardDeliveries,\n hasSourceRef,\n readPersistedSourceInput,\n readySourceRefs,\n removeCard,\n restartCard,\n restoredCards,\n selectSettled,\n selectSourceSet,\n selectTotalChars,\n setCardWaitForClean,\n setSourceTopic,\n settleCard,\n sourceRoomLeft,\n toPersistedSourceInput,\n updateCardDraft,\n updateCardRef,\n withDisplayNames,\n} from \"./state\";\nimport type { PersistedSourceInput, SourceCardModel, SourceDraft, SourceSetState } from \"./types\";\n\n/** Where the cards live. `getState` must return the SAME object until something changes. */\nexport interface SourceSetStore {\n getState(): SourceSetState;\n setState(next: SourceSetState): void;\n subscribe(listener: () => void): () => void;\n /** Called once when a screen mounts (a store that registers entries lazily). */\n init?: (() => void) | undefined;\n}\n\n/** The draft store a reload reads back. `load` returns the raw saved value (stable until it changes). */\nexport interface SourceDraftStorage {\n load(): unknown;\n save(value: PersistedSourceInput): void;\n subscribe?: ((listener: () => void) => () => void) | undefined;\n}\n\nexport interface SourceSetConfig {\n /** The form each new Source starts on (\"clean\" | \"raw\"). Omitted = the server's choice. */\n defaultForm?: string | undefined;\n /** The organization named on the door calls (they answer without one too). */\n organizationId?: string | null | undefined;\n /** How the AI may get the Sources on this surface. Omitted = both. */\n deliveries?: readonly SourceDelivery[] | undefined;\n /** Most Sources the person may pick. Omitted = no limit. */\n max?: number | undefined;\n}\n\nexport interface SourceSetAdapter {\n store: SourceSetStore;\n persistence?: SourceDraftStorage | undefined;\n /** Needed for `manifest()` and `resolve()`. */\n client?: SourcesClient | undefined;\n config?: SourceSetConfig | undefined;\n /** A new card's id (default: a random UUID). */\n createId?: (() => string) | undefined;\n /** A failed call as one sentence with its remedy (default: the error's message). */\n describeError?: ((error: unknown) => string) | undefined;\n}\n\n/** The measurement's own state (not persisted, not shared across controllers). */\nexport interface SourceSetMeta {\n measuring: boolean;\n /** Why the measurement failed, with its remedy. */\n manifestError: string | null;\n}\n\n/** The mutations every intake and screen drives. */\nexport interface SourceSetActions {\n /** Add a Source that is already a pointer (a stored record, a landed Source). */\n addReady(draft: SourceDraft): string;\n /** Add a Source that is still landing; finish it with `settle` or `fail`. */\n addPending(draft: Omit<SourceDraft, \"ref\">): string;\n settle(id: string, patch: Partial<SourceDraft> & { ref: SourceRef }): void;\n fail(id: string, sentence: string): void;\n /** Back to landing. False when the card is gone (removed) — nothing to land. */\n restart(id: string): boolean;\n /** Change what a card that is still landing says or keeps (label, input, fileId, notes). */\n updateDraft(id: string, patch: Partial<Omit<SourceDraft, \"ref\">>): void;\n remove(id: string): void;\n /** Change the pointer's choices (form, parts, cap, delivery). */\n updateRef(id: string, options: SourceRefOptions): void;\n setWaitForClean(id: string, wait: boolean): void;\n setTopic(topic: string): void;\n /** True when this pointer is already picked. */\n hasRef(resourceType: string, resourceId: string): boolean;\n /** How many Sources are picked RIGHT NOW (read from the store, never a stale render). */\n liveCount(): number;\n /** POST /sources/manifest for the ready Sources; cards update with it. */\n manifest(): Promise<SourceManifest | null>;\n}\n\nexport interface SourceSetController extends SourceSetActions {\n getState(): SourceSetState;\n subscribe(listener: () => void): () => void;\n getMeta(): SourceSetMeta;\n subscribeMeta(listener: () => void): () => void;\n /** Replace the host's choices (called on every render by a React binding). */\n configure(config: SourceSetConfig): void;\n readonly config: SourceSetConfig;\n /** Bring back a saved draft once — only into an empty input. True when it restored. */\n restore(saved: unknown): boolean;\n /** The frozen v1 payload, built from the ready Sources. */\n toSourceSet(options?: { targetModelId?: string | undefined }): SourceSet;\n /**\n * Apply a set the review returned (forms, parts, caps, delivery). Pass\n * `reviewed` — the set sent INTO the review — and every Source removed there\n * leaves the list too (only those; one that landed meanwhile stays).\n */\n applySourceSet(set: SourceSet, options?: { reviewed?: SourceSet | undefined }): void;\n /** POST /sources/resolve — the grounded text for a generator, named as the cards name them. */\n resolve(options?: { targetModelId?: string | undefined }): Promise<ResolvedSourceSet>;\n /** Switch back any Source set to a delivery the host cannot use (with a note). */\n fitDeliveries(deliveries?: readonly SourceDelivery[]): void;\n /** How many more Sources fit under the host's max. */\n roomLeft(): number;\n totalChars(): number;\n settled(): boolean;\n}\n\nfunction randomId(): string {\n const cryptoApi = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;\n if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();\n return `src-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** An in-memory store — for clients without their own, and for tests. */\nexport function createMemorySourceSetStore(initial: SourceSetState = EMPTY_SOURCE_SET_STATE): SourceSetStore {\n let state = initial;\n const listeners = new Set<() => void>();\n return {\n getState: () => state,\n setState(next) {\n if (next === state) return;\n state = next;\n for (const listener of [...listeners]) listener();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\n/** An in-memory draft store (a stand-in for device storage in tests and previews). */\nexport function createMemorySourceDraftStorage(initial: unknown = undefined): SourceDraftStorage & {\n current(): unknown;\n} {\n let saved: unknown = initial;\n const listeners = new Set<() => void>();\n return {\n load: () => saved,\n save(value) {\n saved = value;\n for (const listener of [...listeners]) listener();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n current: () => saved,\n };\n}\n\nexport function createSourceSetController(adapter: SourceSetAdapter): SourceSetController {\n const { store, persistence } = adapter;\n let config: SourceSetConfig = { ...(adapter.config ?? {}) };\n const createId = adapter.createId ?? randomId;\n const describe = adapter.describeError ?? errorText;\n let meta: SourceSetMeta = { measuring: false, manifestError: null };\n const metaListeners = new Set<() => void>();\n let hydrated = false;\n /** The newest measurement wins: an older answer never overwrites a newer one. */\n let measurement: AbortController | null = null;\n\n const setMeta = (patch: Partial<SourceSetMeta>) => {\n const next = { ...meta, ...patch };\n if (next.measuring === meta.measuring && next.manifestError === meta.manifestError) return;\n meta = next;\n for (const listener of [...metaListeners]) listener();\n };\n\n /** Apply a reducer's result and write the draft (explicit persistence). */\n const commit = (next: SourceSetState) => {\n hydrated = true;\n if (next !== store.getState()) store.setState(next);\n persistence?.save(toPersistedSourceInput(store.getState()));\n };\n\n const has = (id: string) => store.getState().cards.some((c) => c.id === id);\n\n const controller: SourceSetController = {\n getState: () => store.getState(),\n subscribe: (listener) => store.subscribe(listener),\n getMeta: () => meta,\n subscribeMeta(listener) {\n metaListeners.add(listener);\n return () => metaListeners.delete(listener);\n },\n configure(next) {\n config = { ...next };\n },\n get config() {\n return config;\n },\n\n restore(saved) {\n if (hydrated) return false;\n const live = store.getState();\n if (live.cards.length > 0) {\n hydrated = true;\n return false;\n }\n const persisted = readPersistedSourceInput(saved);\n if (persisted.sources.length === 0) return false;\n hydrated = true;\n store.setState({ cards: restoredCards(persisted), topic: live.topic || persisted.topic });\n return true;\n },\n\n addReady(draft) {\n const id = createId();\n commit(addReadyCard(store.getState(), id, draft, { defaultForm: config.defaultForm }));\n return id;\n },\n addPending(draft) {\n const id = createId();\n commit(addPendingCard(store.getState(), id, draft));\n return id;\n },\n settle(id, patch) {\n if (!has(id)) return;\n commit(settleCard(store.getState(), id, patch, { defaultForm: config.defaultForm }));\n },\n fail(id, sentence) {\n if (!has(id)) return;\n commit(failCard(store.getState(), id, sentence));\n },\n restart(id) {\n if (!has(id)) return false;\n commit(restartCard(store.getState(), id));\n return true;\n },\n updateDraft(id, patch) {\n if (!has(id)) return;\n commit(updateCardDraft(store.getState(), id, patch));\n },\n remove(id) {\n commit(removeCard(store.getState(), id));\n },\n updateRef(id, options) {\n if (!store.getState().cards.find((c) => c.id === id)?.draft.ref) return;\n commit(updateCardRef(store.getState(), id, options));\n },\n setWaitForClean(id, wait) {\n if (!has(id)) return;\n commit(setCardWaitForClean(store.getState(), id, wait));\n },\n setTopic(topic) {\n commit(setSourceTopic(store.getState(), topic));\n },\n hasRef: (resourceType, resourceId) => hasSourceRef(store.getState(), resourceType, resourceId),\n liveCount: () => store.getState().cards.length,\n\n toSourceSet: (options = {}) => selectSourceSet(store.getState(), options),\n applySourceSet(set, options = {}) {\n commit(applyReviewedSourceSet(store.getState(), set, options.reviewed));\n },\n\n async manifest() {\n const refs = readySourceRefs(store.getState());\n if (refs.length === 0) {\n setMeta({ manifestError: null });\n return null;\n }\n if (!adapter.client) throw new Error(\"createSourceSetController: manifest() needs a client in the adapter\");\n measurement?.abort();\n const controllerForThis = new AbortController();\n measurement = controllerForThis;\n setMeta({ measuring: true });\n try {\n const result = await adapter.client.manifest(createSourceSet(refs), {\n organizationId: config.organizationId ?? undefined,\n signal: controllerForThis.signal,\n });\n if (measurement !== controllerForThis) return null;\n const next = applyManifest(store.getState(), result);\n if (next !== store.getState()) store.setState(next);\n setMeta({ manifestError: null });\n return result;\n } catch (err) {\n // A superseded measurement was cancelled on purpose — not a failure.\n if (measurement !== controllerForThis) return null;\n setMeta({\n manifestError: `Sizes and parts could not be read: ${describe(err)} Your picks are kept — try again.`,\n });\n return null;\n } finally {\n if (measurement === controllerForThis) setMeta({ measuring: false });\n }\n },\n\n async resolve(options = {}) {\n if (!adapter.client) throw new Error(\"createSourceSetController: resolve() needs a client in the adapter\");\n const resolved = await adapter.client.resolve(controller.toSourceSet(options), {\n organizationId: config.organizationId ?? undefined,\n });\n return withDisplayNames(resolved, store.getState().cards as SourceCardModel[]);\n },\n\n fitDeliveries(deliveries = config.deliveries) {\n const next = fitCardDeliveries(store.getState(), deliveries);\n if (next !== store.getState()) commit(next);\n },\n roomLeft: () => sourceRoomLeft(store.getState(), config.max),\n totalChars: () => selectTotalChars(store.getState()),\n settled: () => selectSettled(store.getState()),\n };\n return controller;\n}\n","/**\n * Source intake — every way NEW material becomes a Source, through the doors\n * that already exist on the server (DESIGN.md amendment A3). Each call adds a\n * card at once (so the person sees it working), then settles it to a pointer\n * or fails it with a sentence and a remedy. Nothing is ever sent onward as a\n * blob.\n *\n * pasted text → `POST /sources/land`, kept.\n * a web page → the host's scraper lands it (`addScrapedPage`), or a link\n * typed before a reload is scraped again (`addWebPage`);\n * `POST /sources/{id}/keep` files it against the thing being made.\n * a file/image → the host's uploader hands over file ids (`addUploaded`); the\n * file is filed against `attachTo` in the direction the\n * association registry declares, and its Source is kept once\n * reading makes one (`fileLanded`, driven by the recovery).\n * existing → a registry item (`addExisting`).\n * YouTube/audio → the transcript comes from the host's readers and lands\n * through `POST /sources/land`.\n *\n * Never lose input: every landing keeps what the person handed over in the\n * draft (`SourceDraft.input` — text, link, uploaded recording; never bytes)\n * until it settles, so `resume` can land it again after a reload, a failure,\n * or once an organization is chosen (the recovery replays every card waiting\n * for one — from state, never an in-memory queue). Landing twice is safe: the\n * door dedupes by (organization, identity, content hash).\n *\n * Every outside dependency is INJECTED (`SourceIntakeDeps`): the doors, the\n * organization gate, the signed-in person, the failure wording.\n */\n\nimport { isAssociationTargetType, isRegisteredPair } from \"@ai-matrx/associations\";\nimport { createSourceRef } from \"../index\";\nimport type { SourceSetActions } from \"./controller\";\nimport {\n KEEP_WAITING_FOR_ORGANIZATION,\n NOT_KEPT_FOR_RELOAD,\n WAITING_FOR_ORGANIZATION,\n resumableInput,\n} from \"./interrupted\";\nimport { draftKindForToken } from \"./state\";\nimport type { SourceAttachTo, SourceCardModel, SourceIntakeInput, SourceKindId } from \"./types\";\n\nconst TRANSCRIPT_NAME_MAX = 120;\n\n/** A door's notice: a sentence, and sometimes a remedy code (\"save_it…\"). */\nexport interface SourceLandingNotice {\n message: string;\n remedy?: string | null | undefined;\n}\n\n/** The target a door files a Source against (`attach_to`). */\nexport interface SourceAttachTarget {\n entity_type: string;\n entity_id: string;\n label: string | null;\n signal: boolean;\n}\n\n/** The part of a landing body the intake reads or sets — the rest is the host's door shape. */\nexport interface SourceLandingBodyBase {\n name: string;\n canonical_identity?: string | null | undefined;\n provenance?: Record<string, unknown> | null | undefined;\n}\n\n/** A landed (or kept) Source's answer. */\nexport interface SourceLandingAnswer {\n processed_document_id: string;\n notices?: SourceLandingNotice[] | null | undefined;\n}\n\n/** What the host's web reader returns for a link. Null = the page could not be read. */\nexport interface ScrapedSourcePage {\n processedDocumentId: string | null | undefined;\n sourceNotices: SourceLandingNotice[];\n pageTitle?: string | null | undefined;\n}\n\n/** What the host's YouTube reader returns. `source` = the server landed a timed transcript Source. */\nexport interface YouTubeTranscriptResult {\n text: string | null | undefined;\n note?: string | null | undefined;\n source?: { processed_document_id: string; title?: string | null | undefined } | null | undefined;\n}\n\n/** One file the host's uploader already uploaded. */\nexport interface UploadedSourceFile {\n fileId: string;\n name: string;\n}\n\n/** The association write (the host's one chokepoint). */\nexport interface SourceAssociationEdge {\n sourceType: string;\n sourceId: string;\n targetType: string;\n targetId: string;\n orgId: string;\n}\n\nexport type SourceAssociationResult = { ok: true } | { ok: false; error: { message: string } };\n\nexport interface SourceIntakeDoors<Body extends SourceLandingBodyBase = SourceLandingBodyBase> {\n /** `POST /sources/land` with the body as given (keep + attach_to set by the intake). */\n land(body: Body & { keep: true; attach_to: SourceAttachTarget[] }): Promise<SourceLandingAnswer>;\n /** `POST /sources/{id}/keep`, filed against the targets. */\n keep(\n processedDocumentId: string,\n options: { attachTo: SourceAttachTarget[]; organizationId: string },\n ): Promise<{ notices?: SourceLandingNotice[] | null | undefined }>;\n /** Build the landing body for text the person handed over. */\n buildTextLanding(input: {\n text: string;\n name?: string | undefined;\n organizationId: string;\n userId: string;\n }): Promise<Body>;\n /** Read a web page (the scraper lands it). Null = it could not be read. */\n scrapeUrl(url: string): Promise<ScrapedSourcePage | null>;\n /** Read a YouTube video's transcript. */\n fetchYouTubeTranscript(url: string): Promise<YouTubeTranscriptResult>;\n /** Write out a recording that is already stored. */\n transcribeFile(input: { fileId: string; organizationId: string }): Promise<{ text?: string | null | undefined }>;\n /** File one edge through the host's association chokepoint. */\n associate(edge: SourceAssociationEdge): Promise<SourceAssociationResult>;\n}\n\nexport interface SourceIntakeDeps<Body extends SourceLandingBodyBase = SourceLandingBodyBase> {\n doors: SourceIntakeDoors<Body>;\n /** The organization to land in — asks the person when none is chosen (the host's gate). */\n ensureOrganization(): Promise<string>;\n /** Run a landing the person asked for so the gate can carry the click intent. Default: run it. */\n holdIntent?: (<T>(run: () => Promise<T>) => Promise<T | undefined>) | undefined;\n /** True when a landing stopped only because no organization is chosen yet. */\n waitsForOrganization(error: unknown): boolean;\n /** A failed landing as one sentence with its remedy. */\n failureSentence(error: unknown): string;\n /** The signed-in person (null while sign-in is still loading). */\n userId(): string | null | undefined;\n /** The YouTube video id in a link, or null. */\n youtubeId(url: string): string | null | undefined;\n /** The largest pasted text kept in the draft for a reload (null = unknown — nothing kept). */\n maxKeptChars(): number | null;\n /** The thing being made — new Sources are filed against it and kept. */\n attachTo?: SourceAttachTo | undefined;\n}\n\nexport interface SourceIntake {\n addPastedText(text: string, name?: string): Promise<void>;\n addWebPage(url: string): Promise<void>;\n /**\n * A page the host's web picker already read (and the scraper landed); null id\n * = land its text instead. `pendingId` = the card `beginWebPage` made when the\n * read started — it is settled instead of a new card being added.\n */\n addScrapedPage(\n page: { url: string; title: string; text: string; processedDocumentId: string | null },\n pendingId?: string | null,\n ): Promise<void>;\n /**\n * The host's web picker STARTED reading a link: a card with the link kept\n * appears at once, so a reload mid-read brings it back and lands it (verify-3\n * 12a/12b: a reload while a page was read lost it, link and all). Finish it\n * with `addScrapedPage(page, id)`; if the person drops the preview, remove it;\n * if the picker goes away mid-read, `resume(card)` lands it through the web door.\n */\n beginWebPage(url: string): string;\n /** Files the host's uploader already uploaded. */\n addUploaded(files: readonly UploadedSourceFile[], kind: SourceKindId): Promise<void>;\n /**\n * A recording made in place (the Voice Pad) that is already written out: it\n * lands as text, but it IS a recording — its card and review say \"Recording\",\n * never \"Pasted text\" — and it keeps its name (\"Recording 3:41 PM\").\n */\n addRecordedText(text: string, name?: string): Promise<void>;\n /** A recording already uploaded — written out, then landed. */\n addUploadedRecording(file: UploadedSourceFile): Promise<void>;\n /** Something the person already has (Use existing / search). Returns false when already picked. */\n addExisting(item: { token: string; id: string; title: string }): boolean;\n addYouTube(url: string): Promise<void>;\n /** Land a card's kept input again (after a reload or a failure). False when nothing was kept. */\n resume(card: SourceCardModel): boolean;\n /** The person chose the file again (uploaded) for a card whose upload was cut off. */\n retryFile(card: SourceCardModel, file: UploadedSourceFile): Promise<void>;\n /** Reading an uploaded file made its Source: keep it and file it against `attachTo`. */\n fileLanded(card: SourceCardModel, processedDocumentId: string): Promise<void>;\n}\n\nexport function sourceAttachTargets(attachTo: SourceAttachTo | undefined): SourceAttachTarget[] {\n return attachTo\n ? [\n {\n entity_type: attachTo.entityType,\n entity_id: attachTo.entityId,\n // The EDGE's label, which the registry names (a deck's Source is its\n // \"source\", a scope's is \"about\") — never the target's display name,\n // which the door refused as an unknown label (USI-3e).\n label: null,\n signal: true,\n },\n ]\n : [];\n}\n\nfunction hostOf(url: string): string {\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n } catch {\n return url;\n }\n}\n\n/** A notice that asks the person to save (keep) the Source — moot once it is kept. */\nfunction isSaveItNotice(remedy: string | null | undefined): boolean {\n return typeof remedy === \"string\" && remedy.startsWith(\"save_it\");\n}\n\nfunction landedNotes(notices: readonly SourceLandingNotice[] | null | undefined): string[] {\n return (notices ?? []).map((n) => n.message).filter(Boolean);\n}\n\n/**\n * Which way a file ↔ `targetType` edge is registered — read from the package's\n * generated association registry (`@ai-matrx/associations`) — or null when it\n * is not registered.\n */\nexport function registeredFileEdge(targetType: string): \"file_to_target\" | \"target_to_file\" | null {\n if (isRegisteredPair(\"file\", targetType)) return \"file_to_target\";\n if (isRegisteredPair(targetType, \"file\")) return \"target_to_file\";\n return null;\n}\n\nexport function createSourceIntake<Body extends SourceLandingBodyBase>(\n set: SourceSetActions,\n deps: SourceIntakeDeps<Body>,\n): SourceIntake {\n const { doors } = deps;\n const attachTo = sourceAttachTargets(deps.attachTo);\n const hold = <T>(run: () => Promise<T>): Promise<T | undefined> =>\n deps.holdIntent ? deps.holdIntent(run) : run();\n const notFiledSuffix = attachTo.length ? \" or filed with what you are making\" : \"\";\n\n /**\n * Fail the card — or, when only the organization is missing, say it is\n * waiting. The card's kept input is its replay: the recovery lands it again\n * the moment an organization is set (state, not a queue).\n */\n const failOrHold = (id: string, err: unknown) => {\n set.fail(id, deps.waitsForOrganization(err) ? WAITING_FOR_ORGANIZATION : deps.failureSentence(err));\n };\n\n const needUser = (): string => {\n const userId = deps.userId();\n if (!userId) throw new Error(\"Your sign-in is still loading, so nothing was added. Try again in a moment.\");\n return userId;\n };\n\n /** Land text through the door as a kept Source; returns the settle patch. */\n const landText = async (body: Body): Promise<{ id: string; notes: string[] }> => {\n const landed = await doors.land({ ...body, keep: true, attach_to: attachTo });\n return { id: landed.processed_document_id, notes: landedNotes(landed.notices) };\n };\n\n const landPaste = async (id: string, trimmed: string, name?: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const body = await doors.buildTextLanding({ text: trimmed, name, organizationId, userId: needUser() });\n const landed = await landText(body);\n set.settle(id, {\n label: body.name,\n ref: createSourceRef(\"processed_document\", landed.id),\n processedDocumentId: landed.id,\n notes: landed.notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n const landWebPage = async (id: string, url: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const result = await doors.scrapeUrl(url);\n if (!result) {\n set.fail(\n id,\n \"That page could not be read — it may need a sign-in or block robots. Try another link, or copy the text and use Paste text.\",\n );\n return;\n }\n if (!result.processedDocumentId) {\n set.fail(\n id,\n result.sourceNotices[0]?.message ??\n \"The page was read but did not become a Source, and the server did not say why. Try again.\",\n );\n return;\n }\n // A Source picked for real work is kept (A3): its clean → segment →\n // embed is queued, and it is filed against the thing being made. Once\n // kept, the capture's \"not saved — save it\" notices are no longer true;\n // the keep's own notices replace them.\n let notes: string[];\n try {\n const kept = await doors.keep(result.processedDocumentId, { attachTo, organizationId });\n notes = [\n ...landedNotes(result.sourceNotices.filter((n) => !isSaveItNotice(n.remedy))),\n ...landedNotes(kept.notices),\n ];\n } catch (err) {\n notes = [\n ...landedNotes(result.sourceNotices),\n `It is in your Sources, but it could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`,\n ];\n }\n set.settle(id, {\n label: result.pageTitle || hostOf(url),\n ref: createSourceRef(\"processed_document\", result.processedDocumentId),\n processedDocumentId: result.processedDocumentId,\n notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n const landYouTube = async (id: string, url: string, videoId: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const { text, note, source } = await doors.fetchYouTubeTranscript(url);\n if (!text) {\n set.fail(\n id,\n note ??\n \"That video has no speech we could write out (no captions and no clear voice). Try another video, or paste a transcript.\",\n );\n return;\n }\n if (source) {\n // The server landed the timed transcript through the door: the card IS\n // that transcript Source, and \"Choose parts\" lists its timed segments.\n const label = `YouTube — ${source.title || videoId}`.slice(0, TRANSCRIPT_NAME_MAX);\n let notes: string[] = [];\n try {\n const kept = await doors.keep(source.processed_document_id, { attachTo, organizationId });\n notes = landedNotes(kept.notices);\n } catch (err) {\n notes = [\n `It was read, but its Source could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`,\n ];\n }\n set.settle(id, {\n label,\n ref: createSourceRef(\"processed_document\", source.processed_document_id),\n processedDocumentId: source.processed_document_id,\n notes,\n });\n return;\n }\n const name = `YouTube — ${text.split(/\\s+/).slice(0, 10).join(\" \")}…`.slice(0, TRANSCRIPT_NAME_MAX);\n const body = await doors.buildTextLanding({ text, name, organizationId, userId: needUser() });\n const landed = await landText({\n ...body,\n // Identity is the video, so the same video twice is one Source.\n canonical_identity: `youtube:${videoId}`,\n provenance: { ...(body.provenance ?? {}), origin_client: \"youtube\", capture_method: \"captions\", final_url: url },\n });\n set.settle(id, {\n label: name,\n ref: createSourceRef(\"processed_document\", landed.id),\n processedDocumentId: landed.id,\n // Untimed: say why it has no parts to choose (the server's own sentence).\n notes: note ? [...landed.notes, note] : landed.notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n /**\n * File the uploaded file against the thing being made — the ONE associations\n * chokepoint, in the direction the registry declares (`fc_set → file`, but\n * `file → task`); writing it backwards is refused (USI-3e). Returns a note\n * when it could not be filed; the upload itself stands.\n */\n const fileAgainstTarget = async (fileId: string, organizationId: string): Promise<string | null> => {\n const target = deps.attachTo;\n if (!target) return null;\n const what = target.label ? `\"${target.label}\"` : \"what you are making\";\n const direction = registeredFileEdge(target.entityType);\n const cannot = `It was uploaded, but a file cannot be filed with ${what} (a ${target.entityType.replace(/_/g, \" \")}), so it is not listed there.`;\n if (!direction) return cannot;\n if (direction === \"file_to_target\" && !isAssociationTargetType(target.entityType)) return cannot;\n const linked = await doors.associate(\n direction === \"file_to_target\"\n ? {\n sourceType: \"file\",\n sourceId: fileId,\n targetType: target.entityType,\n targetId: target.entityId,\n orgId: organizationId,\n }\n : {\n sourceType: target.entityType,\n sourceId: target.entityId,\n targetType: \"file\",\n targetId: fileId,\n orgId: organizationId,\n },\n );\n return linked.ok ? null : `It was uploaded, but it could not be filed with ${what}: ${linked.error.message}`;\n };\n\n const fileNotes = async (fileId: string): Promise<string[]> => {\n try {\n const organizationId = await deps.ensureOrganization();\n const filed = await fileAgainstTarget(fileId, organizationId);\n return filed ? [filed] : [];\n } catch (err) {\n return deps.waitsForOrganization(err)\n ? []\n : [`It was uploaded, but it could not be filed: ${deps.failureSentence(err)}`];\n }\n };\n\n const transcribeRecording = async (id: string, fileId: string, fileName: string) => {\n try {\n const organizationId = await deps.ensureOrganization();\n const transcription = await doors.transcribeFile({ fileId, organizationId });\n const text = (transcription.text ?? \"\").trim();\n if (text.length < 8) {\n set.fail(\n id,\n \"We couldn't hear enough speech in that recording to write it out. Try a recording with a clear voice.\",\n );\n return;\n }\n const name = `Recording — ${fileName}`.slice(0, TRANSCRIPT_NAME_MAX);\n const body = await doors.buildTextLanding({ text, name, organizationId, userId: needUser() });\n const landed = await landText({\n ...body,\n canonical_identity: `audio-transcript:${fileId}`,\n provenance: { ...(body.provenance ?? {}), origin_client: \"transcription\", capture_method: \"speech\" },\n });\n set.settle(id, {\n label: name,\n ref: createSourceRef(\"processed_document\", landed.id),\n processedDocumentId: landed.id,\n fileId,\n notes: landed.notes,\n });\n } catch (err) {\n failOrHold(id, err);\n }\n };\n\n const intake: SourceIntake = {\n async addPastedText(text, name) {\n const trimmed = text.trim();\n if (!trimmed) return;\n const max = deps.maxKeptChars();\n const kept = max !== null && trimmed.length <= max;\n const id = set.addPending({\n kind: \"paste\",\n label: name?.trim() || \"Pasted text\",\n input: kept ? { text: trimmed, name } : undefined,\n notes: kept ? undefined : [NOT_KEPT_FOR_RELOAD],\n });\n await hold(() => landPaste(id, trimmed, name));\n },\n\n async addRecordedText(text, name) {\n const trimmed = text.trim();\n if (!trimmed) return;\n const max = deps.maxKeptChars();\n const kept = max !== null && trimmed.length <= max;\n const id = set.addPending({\n kind: \"audio\",\n label: name?.trim() || \"Recording\",\n origin: \"Recording\",\n input: kept ? { text: trimmed, name } : undefined,\n notes: kept ? undefined : [NOT_KEPT_FOR_RELOAD],\n });\n await hold(() => landPaste(id, trimmed, name));\n },\n\n async addWebPage(raw) {\n const url = /^https?:\\/\\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;\n const id = set.addPending({ kind: \"web\", label: hostOf(url), origin: url, input: { url } });\n await hold(() => landWebPage(id, url));\n },\n\n beginWebPage(raw) {\n const url = /^https?:\\/\\//i.test(raw.trim()) ? raw.trim() : `https://${raw.trim()}`;\n return set.addPending({ kind: \"web\", label: hostOf(url), origin: url, input: { url } });\n },\n\n async addScrapedPage(page, pendingId) {\n const label = page.title || hostOf(page.url);\n const cardFor = () => {\n if (pendingId && set.restart(pendingId)) {\n set.updateDraft(pendingId, { label, origin: page.url, input: { url: page.url } });\n return pendingId;\n }\n return set.addPending({ kind: \"web\", label, origin: page.url, input: { url: page.url } });\n };\n if (!page.processedDocumentId) {\n // The scrape did not land a Source (or the person edited the text): land what they confirmed.\n const id = cardFor();\n await hold(() => landPaste(id, page.text, label));\n return;\n }\n const pdId = page.processedDocumentId;\n const id = cardFor();\n await hold(async () => {\n let notes: string[] = [];\n try {\n const organizationId = await deps.ensureOrganization();\n const kept = await doors.keep(pdId, { attachTo, organizationId });\n notes = landedNotes(kept.notices);\n } catch (err) {\n notes = deps.waitsForOrganization(err)\n ? [KEEP_WAITING_FOR_ORGANIZATION]\n : [`It is in your Sources, but it could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`];\n }\n set.settle(id, {\n label,\n ref: createSourceRef(\"processed_document\", pdId),\n processedDocumentId: pdId,\n notes,\n });\n });\n },\n\n async addUploaded(files, kind) {\n for (const file of files) {\n if (set.hasRef(\"file\", file.fileId)) continue;\n const id = set.addPending({ kind, label: file.name, origin: \"Uploaded file\", fileId: file.fileId });\n const notes = await fileNotes(file.fileId);\n // The Source itself is kept and filed by the recovery from the server's state.\n set.settle(id, { label: file.name, ref: createSourceRef(\"file\", file.fileId), fileId: file.fileId, notes });\n }\n },\n\n async addUploadedRecording(file) {\n const id = set.addPending({\n kind: \"audio\",\n label: file.name,\n origin: \"Recording\",\n fileId: file.fileId,\n input: { fileId: file.fileId },\n });\n await hold(() => transcribeRecording(id, file.fileId, file.name));\n },\n\n addExisting(item) {\n if (set.hasRef(item.token, item.id)) return false;\n set.addReady({\n kind: draftKindForToken(item.token),\n label: item.title,\n ref: createSourceRef(item.token, item.id),\n fileId: item.token === \"file\" ? item.id : undefined,\n processedDocumentId: item.token === \"processed_document\" ? item.id : undefined,\n });\n return true;\n },\n\n async addYouTube(raw) {\n const url = raw.trim();\n const videoId = deps.youtubeId(url);\n if (!videoId) return;\n const id = set.addPending({ kind: \"youtube\", label: \"YouTube video\", origin: url, input: { url } });\n await hold(() => landYouTube(id, url, videoId));\n },\n\n resume(card) {\n const input: SourceIntakeInput | null = resumableInput(card.draft);\n if (!input) return false;\n set.restart(card.id);\n switch (card.draft.kind) {\n case \"paste\":\n void landPaste(card.id, (input.text ?? \"\").trim(), input.name);\n return true;\n case \"web\":\n void landWebPage(card.id, input.url ?? \"\");\n return true;\n case \"youtube\": {\n const videoId = deps.youtubeId(input.url ?? \"\");\n if (!videoId) {\n set.fail(card.id, \"That link is not a YouTube video any more. Remove it and paste the link again.\");\n return true;\n }\n void landYouTube(card.id, input.url ?? \"\", videoId);\n return true;\n }\n case \"audio\":\n if (input.fileId) void transcribeRecording(card.id, input.fileId, card.draft.label);\n else void landPaste(card.id, (input.text ?? \"\").trim(), input.name);\n return true;\n default:\n return false;\n }\n },\n\n async retryFile(card, file) {\n set.restart(card.id);\n set.updateDraft(card.id, { label: file.name, fileId: file.fileId });\n if (card.draft.kind === \"audio\") {\n set.updateDraft(card.id, { input: { fileId: file.fileId } });\n await hold(() => transcribeRecording(card.id, file.fileId, file.name));\n return;\n }\n const notes = await fileNotes(file.fileId);\n set.settle(card.id, { label: file.name, ref: createSourceRef(\"file\", file.fileId), fileId: file.fileId, notes });\n },\n\n async fileLanded(card, processedDocumentId) {\n // Every card opens its Source from now on (and a held keep's waiting note goes).\n const notes = (card.draft.notes ?? []).filter((n) => n !== KEEP_WAITING_FOR_ORGANIZATION);\n set.updateDraft(card.id, { processedDocumentId, notes });\n try {\n const organizationId = await deps.ensureOrganization();\n await doors.keep(processedDocumentId, { attachTo, organizationId });\n } catch (err) {\n if (deps.waitsForOrganization(err)) {\n // Kept again by the recovery once an organization is set.\n set.updateDraft(card.id, { processedDocumentId, notes: [...notes, KEEP_WAITING_FOR_ORGANIZATION] });\n return;\n }\n set.updateDraft(card.id, {\n processedDocumentId,\n notes: [\n ...notes,\n `It was read, but its Source could not be kept for reuse${notFiledSuffix}: ${deps.failureSentence(err)}`,\n ],\n });\n }\n },\n };\n return intake;\n}\n","/**\n * Recovery — the UI-free half of \"never lose input\" (USI-3b), as decisions and\n * one step function. A React binding (`@ai-matrx/agents/sources/react`\n * `useSourceRecovery`) schedules them; any other client can call them itself.\n *\n * 1. A Source a reload cut off while it was landing, whose input the draft\n * kept (`interrupted.ts`), is handed back to the door once — the door\n * dedupes by content hash, so a second landing reuses the same Source.\n * 2. A landing that waited for an organization is landed again the moment one\n * is set — from the card's kept input, or, for a read Source whose keep\n * waited, by keeping it again. State, never an in-memory queue.\n * 3. A stored file's Source (new upload, reused copy, or picked file) is read\n * from the SERVER's state (`fileSource.ts`): kept and filed once it exists,\n * the one run started only when nothing is reading it, re-attached after a\n * reload — never a duplicate run.\n *\n * The once-per-card guards live on `globalThis` (one registry however many\n * loader graphs import this module), so two inputs on one surface, or a\n * re-mount, never land the same card twice.\n */\n\nimport type { SourceSetActions } from \"./controller\";\nimport {\n fileCardHeldForOrganization,\n isWaitingFileCard,\n nextFileStep,\n type FileSourceStatus,\n} from \"./fileSource\";\nimport type { SourceIntake } from \"./intake\";\nimport { KEEP_WAITING_FOR_ORGANIZATION, RELOADED_RESUMING, WAITING_FOR_ORGANIZATION } from \"./interrupted\";\nimport type { SourceCardModel } from \"./types\";\n\ninterface RecoveryGuards {\n resumedCards: Set<string>;\n keptFileSources: Set<string>;\n startedFileRuns: Set<string>;\n}\n\n// Module-level state is banned in our packages (dual ESM/CJS graphs would\n// split it): the guards live on globalThis under one registered symbol.\nconst GUARDS = Symbol.for(\"ai-matrx.agents.sources.recovery-guards\");\n\nexport function sourceRecoveryGuards(): RecoveryGuards {\n const slot = globalThis as unknown as Record<symbol, RecoveryGuards | undefined>;\n let guards = slot[GUARDS];\n if (!guards) {\n guards = { resumedCards: new Set(), keptFileSources: new Set(), startedFileRuns: new Set() };\n slot[GUARDS] = guards;\n }\n return guards;\n}\n\n/** Cards a reload cut off whose kept input lands again now. */\nexport function cardsToResume(cards: readonly SourceCardModel[]): SourceCardModel[] {\n return cards.filter((c) => c.status === \"error\" && c.error === RELOADED_RESUMING);\n}\n\n/** Resume each cut-off card once (per card id, across every input). */\nexport function resumeInterrupted(cards: readonly SourceCardModel[], intake: Pick<SourceIntake, \"resume\">): void {\n const { resumedCards } = sourceRecoveryGuards();\n for (const card of cardsToResume(cards)) {\n if (resumedCards.has(card.id)) continue;\n resumedCards.add(card.id);\n intake.resume(card);\n }\n}\n\n/** Cards that waited for an organization (a landing, or a read Source's keep). */\nexport function cardsWaitingForOrganization(cards: readonly SourceCardModel[]): SourceCardModel[] {\n return cards.filter(\n (s) =>\n (s.status === \"error\" && s.error === WAITING_FOR_ORGANIZATION) ||\n (!!s.draft.processedDocumentId && !!s.draft.notes?.includes(KEEP_WAITING_FOR_ORGANIZATION)),\n );\n}\n\n/** An organization is known now: land or keep every card that waited for one. */\nexport function continueAfterOrganization(\n cards: readonly SourceCardModel[],\n intake: Pick<SourceIntake, \"resume\" | \"fileLanded\">,\n): void {\n for (const card of cards) {\n if (card.status === \"error\" && card.error === WAITING_FOR_ORGANIZATION) {\n intake.resume(card);\n } else if (card.draft.processedDocumentId && card.draft.notes?.includes(KEEP_WAITING_FOR_ORGANIZATION)) {\n void intake.fileLanded(card, card.draft.processedDocumentId);\n }\n }\n}\n\n/** The host's processing runner, as far as the recovery needs it. */\nexport interface SourceFileRunner {\n jobs: ReadonlyArray<{ cldFileId?: string | null | undefined; status: string; processedDocumentId?: string | null | undefined }>;\n runForCldFile(fileId: string, label: string, reason: string): Promise<unknown>;\n}\n\nexport interface FileRecoveryDeps {\n /** The organization the person picked (null = none yet). */\n organizationId: string | null | undefined;\n /** The server's `/files/{id}/rag-status` read. */\n readFileState(fileId: string, signal?: AbortSignal): Promise<FileSourceStatus>;\n /** The host's lookup of a file's own organization (omitted = unknown). */\n fileOrganizationId?: ((fileId: string) => string | null | undefined) | undefined;\n}\n\n/** A file card the recovery may ask about now (waiting, and not held for an organization). */\nexport function isAskableFileCard(card: SourceCardModel, deps: Pick<FileRecoveryDeps, \"organizationId\" | \"fileOrganizationId\">): boolean {\n return isWaitingFileCard(card) && !fileCardHeldForOrganization(card, deps.organizationId, deps.fileOrganizationId);\n}\n\n/**\n * One look at every askable file card: a Source → keep and file it; a live run\n * → look again; nothing reading it → start the one run (once); unreadable →\n * say so. Returns true while any card still waits (look again later).\n */\nexport async function lookAtFileCards(\n cards: readonly SourceCardModel[],\n ctx: {\n set: Pick<SourceSetActions, \"fail\" | \"manifest\">;\n intake: Pick<SourceIntake, \"fileLanded\">;\n runner: SourceFileRunner;\n signal: AbortSignal;\n } & FileRecoveryDeps,\n): Promise<boolean> {\n const { keptFileSources, startedFileRuns } = sourceRecoveryGuards();\n let anyWaiting = false;\n for (const card of cards.filter((c) => isAskableFileCard(c, ctx))) {\n const fileId = card.draft.fileId as string;\n const guard = `${card.id}:${fileId}`;\n if (keptFileSources.has(guard)) continue;\n let status: FileSourceStatus | null = null;\n try {\n status = await ctx.readFileState(fileId, ctx.signal);\n } catch {\n // A missed read is not an answer — look again next round.\n if (ctx.signal.aborted) return false;\n anyWaiting = true;\n continue;\n }\n if (ctx.signal.aborted) return false;\n const localJob = ctx.runner.jobs.find((j) => j.cldFileId === fileId) ?? null;\n const step = nextFileStep(status, {\n started: startedFileRuns.has(guard),\n localRunning: localJob?.status === \"running\",\n });\n const localPdId = localJob?.processedDocumentId ?? null;\n if (step.do === \"keep\" || localPdId) {\n keptFileSources.add(guard);\n const pdId = step.do === \"keep\" ? step.processedDocumentId : (localPdId as string);\n await ctx.intake.fileLanded(card, pdId);\n // The pointer did not change, so nothing else re-measures: ask once now.\n void ctx.set.manifest();\n } else if (step.do === \"start\") {\n startedFileRuns.add(guard);\n anyWaiting = true;\n void ctx.runner.runForCldFile(fileId, card.draft.label, \"Reading it into a Source\").catch(() => undefined);\n } else if (step.do === \"unreadable\") {\n keptFileSources.add(guard);\n ctx.set.fail(card.id, step.reason);\n } else {\n anyWaiting = true;\n }\n }\n return anyWaiting;\n}\n"],"mappings":"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","names":["id"]}
|