@mindstudio-ai/agent 0.1.139 → 0.1.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +216 -424
- package/dist/index.d.ts +194 -23
- package/dist/index.js +352 -411
- package/dist/index.js.map +1 -1
- package/dist/postinstall.js +216 -424
- package/llms.txt +5 -5
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2332,6 +2332,21 @@ interface SearchExplain {
|
|
|
2332
2332
|
lexical: BranchPosition | null;
|
|
2333
2333
|
matchedVia: 'dense' | 'lexical' | 'both';
|
|
2334
2334
|
}
|
|
2335
|
+
/** One passage of a listing ({@link DataSource.passages}): a search hit without the ranking. */
|
|
2336
|
+
interface DataSourcePassage {
|
|
2337
|
+
/** The chunk, prefixed with its heading path for context. */
|
|
2338
|
+
text: string;
|
|
2339
|
+
/** The ids the passage carries: its document's, and those its text names from the dictionary. */
|
|
2340
|
+
entities: string[];
|
|
2341
|
+
citation: Citation;
|
|
2342
|
+
}
|
|
2343
|
+
/** A page of {@link DataSource.passages}. */
|
|
2344
|
+
interface DataSourcePassagePage {
|
|
2345
|
+
passages: DataSourcePassage[];
|
|
2346
|
+
/** Pass back for the next page; null after the last. */
|
|
2347
|
+
nextCursor: string | null;
|
|
2348
|
+
latencyMs: number;
|
|
2349
|
+
}
|
|
2335
2350
|
interface SearchHit {
|
|
2336
2351
|
/**
|
|
2337
2352
|
* Relevance of this hit. Comparable within a response, not across them —
|
|
@@ -2528,6 +2543,14 @@ interface AddOptions {
|
|
|
2528
2543
|
* supplying them replaces the whole set, and `[]` clears it.
|
|
2529
2544
|
*/
|
|
2530
2545
|
entities?: string[];
|
|
2546
|
+
/**
|
|
2547
|
+
* On a mapped source, the budget in dollars of the job that takes an
|
|
2548
|
+
* object's documents past the first thousand ({@link AddResult.job}): it
|
|
2549
|
+
* pauses there, and a plan projected over it waits for an approval rather
|
|
2550
|
+
* than starting. Without one the job runs within its plan's projection,
|
|
2551
|
+
* with headroom.
|
|
2552
|
+
*/
|
|
2553
|
+
budgetDollars?: number;
|
|
2531
2554
|
}
|
|
2532
2555
|
/** What {@link DataSource.add} returns. */
|
|
2533
2556
|
interface AddResult {
|
|
@@ -2536,8 +2559,14 @@ interface AddResult {
|
|
|
2536
2559
|
* mapper answered `deletes` — nothing was added.
|
|
2537
2560
|
*/
|
|
2538
2561
|
document: DataSourceDocument | null;
|
|
2539
|
-
/**
|
|
2562
|
+
/**
|
|
2563
|
+
* Every document the bytes became, or the first thousand of an object that
|
|
2564
|
+
* maps to more ({@link job} takes the rest). One entry on an unmapped
|
|
2565
|
+
* source.
|
|
2566
|
+
*/
|
|
2540
2567
|
documents: DataSourceDocument[];
|
|
2568
|
+
/** How many documents the bytes map to in all: `documents.length` unless {@link job} is set. */
|
|
2569
|
+
documentCount: number;
|
|
2541
2570
|
/** Whether any of them was queued for a build (the rest were already current). */
|
|
2542
2571
|
queued: boolean;
|
|
2543
2572
|
/**
|
|
@@ -2547,6 +2576,28 @@ interface AddResult {
|
|
|
2547
2576
|
outcome: 'unmapped' | 'documents' | 'passthrough' | 'deletes';
|
|
2548
2577
|
/** Documents removed or superseded as a result — a `deletes` outcome, a `replaces`. */
|
|
2549
2578
|
removed: number;
|
|
2579
|
+
/**
|
|
2580
|
+
* The documents the mapper produced that failed validation and were not
|
|
2581
|
+
* registered, by their index in its output (`document: 1234` is the
|
|
2582
|
+
* 1,235th it returned or yielded), with why; null when every one passed.
|
|
2583
|
+
* The rest are registered. `add()` throws `mapper_error` only when none
|
|
2584
|
+
* passed.
|
|
2585
|
+
*/
|
|
2586
|
+
invalid: {
|
|
2587
|
+
count: number;
|
|
2588
|
+
examples: {
|
|
2589
|
+
document: number;
|
|
2590
|
+
reason: string;
|
|
2591
|
+
}[];
|
|
2592
|
+
} | null;
|
|
2593
|
+
/**
|
|
2594
|
+
* The job registering and building the rest of an object that maps to more
|
|
2595
|
+
* than a thousand documents; null otherwise. It plans and starts on its own
|
|
2596
|
+
* (within {@link AddOptions.budgetDollars}); follow it with
|
|
2597
|
+
* {@link DataSource.job}. What the object supersedes or retires goes when
|
|
2598
|
+
* the job finishes, once every one of its documents is searchable.
|
|
2599
|
+
*/
|
|
2600
|
+
job: DataSourceJob | null;
|
|
2550
2601
|
}
|
|
2551
2602
|
interface DataSourceDocument {
|
|
2552
2603
|
id: string;
|
|
@@ -2705,8 +2756,9 @@ interface DataSourceJobPlan {
|
|
|
2705
2756
|
}
|
|
2706
2757
|
/**
|
|
2707
2758
|
* A bulk ingestion job — a sync, a corpus load started from the CLI, a remap
|
|
2708
|
-
* of a mapped source's raw copies, a replay of an earlier job's quarantine,
|
|
2709
|
-
*
|
|
2759
|
+
* of a mapped source's raw copies, a replay of an earlier job's quarantine, a
|
|
2760
|
+
* reread of the source's documents by its reader, or the rest of one large
|
|
2761
|
+
* object an {@link DataSource.add} took.
|
|
2710
2762
|
*/
|
|
2711
2763
|
interface DataSourceJob {
|
|
2712
2764
|
id: string;
|
|
@@ -2735,6 +2787,9 @@ interface DataSourceJob {
|
|
|
2735
2787
|
} | {
|
|
2736
2788
|
type: 'reread';
|
|
2737
2789
|
unread: boolean;
|
|
2790
|
+
} | {
|
|
2791
|
+
type: 'object';
|
|
2792
|
+
ref: string;
|
|
2738
2793
|
};
|
|
2739
2794
|
/**
|
|
2740
2795
|
* Objects the mapper skipped or failed on, and documents the reader failed
|
|
@@ -2818,9 +2873,14 @@ interface DictionaryReport {
|
|
|
2818
2873
|
names: number;
|
|
2819
2874
|
/** Names more than one id claims: a passage naming one is tagged with every claimant. */
|
|
2820
2875
|
ambiguousNames: number;
|
|
2821
|
-
/**
|
|
2876
|
+
/**
|
|
2877
|
+
* The names the most ids claim: `name` as you pushed it (one of them, when
|
|
2878
|
+
* several fold alike), `key` as the linker matches it (folded, separators
|
|
2879
|
+
* dropped), and how many ids claim it.
|
|
2880
|
+
*/
|
|
2822
2881
|
mostClaimed: {
|
|
2823
2882
|
key: string;
|
|
2883
|
+
name?: string;
|
|
2824
2884
|
ids: number;
|
|
2825
2885
|
}[];
|
|
2826
2886
|
/**
|
|
@@ -2959,7 +3019,8 @@ declare class DataSource {
|
|
|
2959
3019
|
* it is who or what was written about then. No filter covers the corpus.
|
|
2960
3020
|
* `chunks` is how many matching passages carry each id, not documents: a
|
|
2961
3021
|
* long document's passages each count. Approximate counts, ordered most
|
|
2962
|
-
* first; `limit` defaults to 20, at most
|
|
3022
|
+
* first; `limit` defaults to 20, at most 1,000. One document's entities:
|
|
3023
|
+
* `{ filter: { documentIds: [id] } }`.
|
|
2963
3024
|
*
|
|
2964
3025
|
* Shares the search rate limit (300/minute per app), and shows the same
|
|
2965
3026
|
* `index_warming` / `index_building` as search while a corpus loads.
|
|
@@ -3049,7 +3110,15 @@ declare class DataSource {
|
|
|
3049
3110
|
* as the new one is registered, before its build lands; a search in that
|
|
3050
3111
|
* window sees neither. **Throws `mapper_skipped`** (HTTP 422) when the
|
|
3051
3112
|
* mapper skipped the object — a specific thing it refused, which the caller
|
|
3052
|
-
* should see — and `mapper_error` when the mapper threw
|
|
3113
|
+
* should see — and `mapper_error` when the mapper threw, or when none of
|
|
3114
|
+
* its documents passed validation. A document that fails is left out and
|
|
3115
|
+
* reported in {@link AddResult.invalid}; the rest are registered.
|
|
3116
|
+
*
|
|
3117
|
+
* An object that maps to more than a thousand documents (a large export,
|
|
3118
|
+
* streamed out of the mapper as it parses) registers its first thousand
|
|
3119
|
+
* here and returns {@link AddResult.job}, a job that registers and builds
|
|
3120
|
+
* the rest; `documentCount` says how many there are in all. Another job on
|
|
3121
|
+
* the source refuses it with `data_source_busy`.
|
|
3053
3122
|
*/
|
|
3054
3123
|
add(content: Buffer | Uint8Array | string, options: AddOptions): Promise<AddResult>;
|
|
3055
3124
|
/**
|
|
@@ -3075,6 +3144,38 @@ declare class DataSource {
|
|
|
3075
3144
|
limit?: number;
|
|
3076
3145
|
order?: 'oldest' | 'newest';
|
|
3077
3146
|
}): Promise<DataSourceDocumentPage>;
|
|
3147
|
+
/**
|
|
3148
|
+
* One page of the passages matching a filter, unranked: every page that
|
|
3149
|
+
* mentions an asset (`{ entities: ['P-1004A'] }`), every passage holding a
|
|
3150
|
+
* phrase, every chunk of some documents. Where {@link search} ranks and
|
|
3151
|
+
* stops at its top results and {@link count} gives a number, this lists
|
|
3152
|
+
* them all. Passages come document by document, each document's in order;
|
|
3153
|
+
* pass `nextCursor` back for the next page, which is null after the last.
|
|
3154
|
+
* `limit` defaults to 50, at most 200.
|
|
3155
|
+
*
|
|
3156
|
+
* Shares the search rate limit (300/minute per app), and shows the same
|
|
3157
|
+
* `index_warming` / `index_building` as search while a corpus loads.
|
|
3158
|
+
*/
|
|
3159
|
+
passages(options?: {
|
|
3160
|
+
filter?: SearchFilter;
|
|
3161
|
+
cursor?: string | null;
|
|
3162
|
+
limit?: number;
|
|
3163
|
+
}): Promise<DataSourcePassagePage>;
|
|
3164
|
+
/**
|
|
3165
|
+
* Every passage matching a filter, a page at a time behind the scenes: the
|
|
3166
|
+
* walk over {@link passages}. Each page counts against the search rate
|
|
3167
|
+
* limit, so a large walk belongs in a background task.
|
|
3168
|
+
*
|
|
3169
|
+
* ```ts
|
|
3170
|
+
* for await (const passage of Manuals.allPassages({ entities: ['P-1004A'] })) {
|
|
3171
|
+
* mentions.push({ asset: 'P-1004A', ...passage.citation });
|
|
3172
|
+
* }
|
|
3173
|
+
* ```
|
|
3174
|
+
*/
|
|
3175
|
+
allPassages(filter?: SearchFilter, options?: {
|
|
3176
|
+
/** Passages per page, at most 200 (the default). */
|
|
3177
|
+
pageSize?: number;
|
|
3178
|
+
}): AsyncGenerator<DataSourcePassage, void, undefined>;
|
|
3078
3179
|
/**
|
|
3079
3180
|
* Every document in the corpus, oldest first, a page at a time behind the
|
|
3080
3181
|
* scenes. This is how an app builds its own view of a large corpus (a
|
|
@@ -3168,6 +3269,17 @@ declare class DataSource {
|
|
|
3168
3269
|
* document has been added.
|
|
3169
3270
|
*/
|
|
3170
3271
|
ensure(name?: string): Promise<void>;
|
|
3272
|
+
/**
|
|
3273
|
+
* @internal A mapper frame's grant to store the next part of its spill: how
|
|
3274
|
+
* `defineMapper`'s executor hands the platform an object's documents a part
|
|
3275
|
+
* at a time once they outgrow the frame's record. Only a mapper frame's
|
|
3276
|
+
* token is granted one.
|
|
3277
|
+
*/
|
|
3278
|
+
_mapSpillGrant(spillId: string): Promise<{
|
|
3279
|
+
part: number;
|
|
3280
|
+
uploadUrl: string;
|
|
3281
|
+
uploadFields: Record<string, string>;
|
|
3282
|
+
}>;
|
|
3171
3283
|
/**
|
|
3172
3284
|
* @internal Content hash of some bytes, matching what the server computes.
|
|
3173
3285
|
* Exposed for callers that want to check whether they already added a file.
|
|
@@ -11606,7 +11718,9 @@ declare function runWithContext<T>(ctx: RequestContext, fn: () => T | Promise<T>
|
|
|
11606
11718
|
* - `documents([...])` — the object becomes these documents (an array is
|
|
11607
11719
|
* one object → many). Each is `{ externalId, title, markdown, metadata?,
|
|
11608
11720
|
* entities?, replaces? }`; `externalId` is the identity the platform
|
|
11609
|
-
* replaces by.
|
|
11721
|
+
* replaces by. Any number: pass a generator (sync or async) to stream an
|
|
11722
|
+
* export of a million rows without holding it. A document that fails
|
|
11723
|
+
* validation is left out and named; the rest of the object goes in.
|
|
11610
11724
|
* - `passthrough({ metadata?, entities? })` — ingest the raw object itself through
|
|
11611
11725
|
* built-in extraction, as an unmapped source would. What lets a mapped
|
|
11612
11726
|
* source still accept a PDF.
|
|
@@ -11619,10 +11733,14 @@ declare function runWithContext<T>(ctx: RequestContext, fn: () => T | Promise<T>
|
|
|
11619
11733
|
* `defineMapper` returns a CALLABLE — the executor — with the config attached
|
|
11620
11734
|
* (the same pattern as `defineJewel`). The platform runs it as an ordinary
|
|
11621
11735
|
* execution frame: one call maps a slice of objects and returns their
|
|
11622
|
-
* outcomes
|
|
11736
|
+
* outcomes, and stores the documents its objects produce as it goes, a part
|
|
11737
|
+
* of up to a thousand at a time, so a frame's memory holds one part
|
|
11738
|
+
* whatever its objects become. Everything a method can do, a mapper can do — call models via
|
|
11623
11739
|
* `runTask`, `fetch` an external API, read the app's tables — and every call
|
|
11624
11740
|
* is spend per object. The mapper's `map` runs under a per-object timeout
|
|
11625
|
-
* (declared in `mindstudio.json`, default 30 s)
|
|
11741
|
+
* (declared in `mindstudio.json`, default 30 s), which also bounds the wait
|
|
11742
|
+
* for each next document a generator yields; a whole object has the frame's
|
|
11743
|
+
* twenty minutes. The executor never throws.
|
|
11626
11744
|
*
|
|
11627
11745
|
* On a job, mapping is its own stage: the mapper turns each object into
|
|
11628
11746
|
* documents, and the platform ingests those documents in parallel batches of
|
|
@@ -11677,9 +11795,11 @@ interface MappedDocument {
|
|
|
11677
11795
|
/** External ids this document replaces (a writethru's original id). */
|
|
11678
11796
|
replaces?: string | string[];
|
|
11679
11797
|
}
|
|
11798
|
+
/** What `documents()` takes: one document, an array, or any iterable or async iterable. */
|
|
11799
|
+
type MappedDocuments = MappedDocument | Iterable<MappedDocument> | AsyncIterable<MappedDocument>;
|
|
11680
11800
|
type MapOutcome = {
|
|
11681
11801
|
kind: 'documents';
|
|
11682
|
-
documents: MappedDocument
|
|
11802
|
+
documents: Iterable<MappedDocument> | AsyncIterable<MappedDocument>;
|
|
11683
11803
|
} | {
|
|
11684
11804
|
kind: 'passthrough';
|
|
11685
11805
|
metadata?: DocumentMetadata;
|
|
@@ -11704,15 +11824,13 @@ interface MapRunObject {
|
|
|
11704
11824
|
etag: string | null;
|
|
11705
11825
|
lastModified: string | null;
|
|
11706
11826
|
metadata: DocumentMetadata | null;
|
|
11707
|
-
|
|
11708
|
-
entities?: string[] | null;
|
|
11827
|
+
entities: string[] | null;
|
|
11709
11828
|
/** Short-lived read URL for the object's bytes. */
|
|
11710
11829
|
url: string;
|
|
11711
11830
|
/**
|
|
11712
11831
|
* The object's bytes, base64, when the platform already held them (it
|
|
11713
11832
|
* hashes and lands every object before mapping, and small objects ride
|
|
11714
|
-
* along). Present, it is the bytes; `url` is the fallback for large objects
|
|
11715
|
-
* and for frames from a platform that predates it.
|
|
11833
|
+
* along). Present, it is the bytes; `url` is the fallback for large objects.
|
|
11716
11834
|
*/
|
|
11717
11835
|
content?: string;
|
|
11718
11836
|
}
|
|
@@ -11723,8 +11841,26 @@ interface MapRunParams {
|
|
|
11723
11841
|
timeoutMs?: number;
|
|
11724
11842
|
/** Objects mapped at once inside the frame. */
|
|
11725
11843
|
concurrency?: number;
|
|
11844
|
+
/** Where the frame's documents are stored, a part at a time. */
|
|
11845
|
+
spill?: {
|
|
11846
|
+
id: string;
|
|
11847
|
+
};
|
|
11848
|
+
}
|
|
11849
|
+
/**
|
|
11850
|
+
* One stored part of a frame's documents: gzipped NDJSON, a line `{ o, i, d }`
|
|
11851
|
+
* per document (the object's index in the frame, the document's index in
|
|
11852
|
+
* that object's output, the document).
|
|
11853
|
+
*/
|
|
11854
|
+
interface MapRunPart {
|
|
11855
|
+
part: number;
|
|
11856
|
+
count: number;
|
|
11726
11857
|
}
|
|
11727
|
-
type MapRunOutcome =
|
|
11858
|
+
type MapRunOutcome = {
|
|
11859
|
+
kind: 'documents';
|
|
11860
|
+
count: number;
|
|
11861
|
+
} | Exclude<MapOutcome, {
|
|
11862
|
+
kind: 'documents';
|
|
11863
|
+
}> | {
|
|
11728
11864
|
kind: 'error';
|
|
11729
11865
|
error: {
|
|
11730
11866
|
message: string;
|
|
@@ -11741,6 +11877,8 @@ interface MapRunRecord {
|
|
|
11741
11877
|
v: 1;
|
|
11742
11878
|
source: string;
|
|
11743
11879
|
outcomes: MapRunResult[];
|
|
11880
|
+
/** Every document the frame's objects produced, in the order stored. */
|
|
11881
|
+
parts: MapRunPart[];
|
|
11744
11882
|
startedAt: number;
|
|
11745
11883
|
durationMs: number;
|
|
11746
11884
|
}
|
|
@@ -11752,8 +11890,11 @@ interface Mapper {
|
|
|
11752
11890
|
readonly source: string;
|
|
11753
11891
|
readonly config: MapperConfig;
|
|
11754
11892
|
}
|
|
11755
|
-
/**
|
|
11756
|
-
|
|
11893
|
+
/**
|
|
11894
|
+
* The object becomes these documents: one passed bare, an array, or a
|
|
11895
|
+
* generator that yields them, which streams an export of any size.
|
|
11896
|
+
*/
|
|
11897
|
+
declare function documents(list: MappedDocuments): MapOutcome;
|
|
11757
11898
|
/**
|
|
11758
11899
|
* Ingest the raw object itself through built-in extraction. `metadata` and
|
|
11759
11900
|
* `entities`, when given, replace what the origin supplied.
|
|
@@ -11816,7 +11957,12 @@ declare function defineMapper(source: {
|
|
|
11816
11957
|
* what named the document.
|
|
11817
11958
|
* - `cleared(sourceId)` — the whole source was deleted, once, so the app can
|
|
11818
11959
|
* drop that source's rows in one statement. Optional.
|
|
11819
|
-
*
|
|
11960
|
+
* - `relinked(document)` — a document already read was re-tagged by a new
|
|
11961
|
+
* dictionary: its passages carry different entities, its text is the same.
|
|
11962
|
+
* For rows derived from the tags. Optional.
|
|
11963
|
+
* A throw fails that delivery; the platform retries it. `document.bytes()`
|
|
11964
|
+
* reads the file the document came from, for a reader that needs the drawing
|
|
11965
|
+
* itself rather than its text.
|
|
11820
11966
|
*
|
|
11821
11967
|
* A reader runs against the app's LIVE release (or the dev session under
|
|
11822
11968
|
* `reader test --dev`), never a pinned one: app databases are per release, so
|
|
@@ -11844,26 +11990,47 @@ interface ReaderDocument {
|
|
|
11844
11990
|
pageCount: number | null;
|
|
11845
11991
|
chunkCount: number | null;
|
|
11846
11992
|
createdAt: string;
|
|
11993
|
+
/**
|
|
11994
|
+
* A short-lived link to the file the document came from: the uploaded
|
|
11995
|
+
* file, or on a mapped source the raw object the mapper read. Valid for the
|
|
11996
|
+
* delivery; null when the file is no longer kept.
|
|
11997
|
+
*/
|
|
11998
|
+
url: string | null;
|
|
11847
11999
|
/**
|
|
11848
12000
|
* The document's passages as indexed: text, page, heading path, and each
|
|
11849
12001
|
* passage's entities (its document's asserted ones and those its text
|
|
11850
12002
|
* names from the source's dictionary). Read once, then held.
|
|
11851
12003
|
*/
|
|
11852
12004
|
chunks(): Promise<DataSourceChunk[]>;
|
|
12005
|
+
/** The bytes behind {@link url}: a drawing's image, a PDF's pages. Read once, then held. */
|
|
12006
|
+
bytes(): Promise<Uint8Array>;
|
|
11853
12007
|
}
|
|
11854
12008
|
type MaybePromise<T> = T | Promise<T>;
|
|
11855
12009
|
interface ReaderConfig {
|
|
11856
12010
|
read: (document: ReaderDocument) => MaybePromise<void>;
|
|
11857
12011
|
removed: (documentId: string) => MaybePromise<void>;
|
|
11858
12012
|
cleared?: (sourceId: string) => MaybePromise<void>;
|
|
12013
|
+
/**
|
|
12014
|
+
* A document already read was re-tagged: the source's dictionary changed,
|
|
12015
|
+
* and its passages' entities with it. The document arrives as `read` gets
|
|
12016
|
+
* it, chunks and all, carrying the new entities, so rows derived from the
|
|
12017
|
+
* tags (links from assets to documents) can follow. Nothing about the text
|
|
12018
|
+
* changed, so this is no reason to extract again. Optional: without it a
|
|
12019
|
+
* relink delivers nothing.
|
|
12020
|
+
*/
|
|
12021
|
+
relinked?: (document: ReaderDocument) => MaybePromise<void>;
|
|
11859
12022
|
}
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
kind: 'read';
|
|
11863
|
-
document: Omit<ReaderDocument, 'chunks'>;
|
|
12023
|
+
type DocumentDelivery = {
|
|
12024
|
+
document: Omit<ReaderDocument, 'chunks' | 'bytes'>;
|
|
11864
12025
|
/** The passages, when the platform carried them inline. */
|
|
11865
12026
|
chunks?: DataSourceChunk[];
|
|
11866
|
-
}
|
|
12027
|
+
};
|
|
12028
|
+
/** One delivery as the platform hands it to the executor. */
|
|
12029
|
+
type ReadDelivery = ({
|
|
12030
|
+
kind: 'read';
|
|
12031
|
+
} & DocumentDelivery) | ({
|
|
12032
|
+
kind: 'relinked';
|
|
12033
|
+
} & DocumentDelivery) | {
|
|
11867
12034
|
kind: 'removed';
|
|
11868
12035
|
documentId: string;
|
|
11869
12036
|
} | {
|
|
@@ -11894,6 +12061,10 @@ interface ReadRunRecord {
|
|
|
11894
12061
|
v: 1;
|
|
11895
12062
|
source: string;
|
|
11896
12063
|
outcomes: ReadRunResult[];
|
|
12064
|
+
/** The optional hooks this reader defines, so the platform sends only what one handles. */
|
|
12065
|
+
hooks: {
|
|
12066
|
+
relinked: boolean;
|
|
12067
|
+
};
|
|
11897
12068
|
startedAt: number;
|
|
11898
12069
|
durationMs: number;
|
|
11899
12070
|
}
|