@mindstudio-ai/agent 0.1.139 → 0.1.140

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/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 —
@@ -2818,9 +2833,14 @@ interface DictionaryReport {
2818
2833
  names: number;
2819
2834
  /** Names more than one id claims: a passage naming one is tagged with every claimant. */
2820
2835
  ambiguousNames: number;
2821
- /** The names (as matched: folded, separators dropped) the most ids claim. */
2836
+ /**
2837
+ * The names the most ids claim: `name` as you pushed it (one of them, when
2838
+ * several fold alike), `key` as the linker matches it (folded, separators
2839
+ * dropped), and how many ids claim it.
2840
+ */
2822
2841
  mostClaimed: {
2823
2842
  key: string;
2843
+ name?: string;
2824
2844
  ids: number;
2825
2845
  }[];
2826
2846
  /**
@@ -2959,7 +2979,8 @@ declare class DataSource {
2959
2979
  * it is who or what was written about then. No filter covers the corpus.
2960
2980
  * `chunks` is how many matching passages carry each id, not documents: a
2961
2981
  * long document's passages each count. Approximate counts, ordered most
2962
- * first; `limit` defaults to 20, at most 100.
2982
+ * first; `limit` defaults to 20, at most 1,000. One document's entities:
2983
+ * `{ filter: { documentIds: [id] } }`.
2963
2984
  *
2964
2985
  * Shares the search rate limit (300/minute per app), and shows the same
2965
2986
  * `index_warming` / `index_building` as search while a corpus loads.
@@ -3075,6 +3096,38 @@ declare class DataSource {
3075
3096
  limit?: number;
3076
3097
  order?: 'oldest' | 'newest';
3077
3098
  }): Promise<DataSourceDocumentPage>;
3099
+ /**
3100
+ * One page of the passages matching a filter, unranked: every page that
3101
+ * mentions an asset (`{ entities: ['P-1004A'] }`), every passage holding a
3102
+ * phrase, every chunk of some documents. Where {@link search} ranks and
3103
+ * stops at its top results and {@link count} gives a number, this lists
3104
+ * them all. Passages come document by document, each document's in order;
3105
+ * pass `nextCursor` back for the next page, which is null after the last.
3106
+ * `limit` defaults to 50, at most 200.
3107
+ *
3108
+ * Shares the search rate limit (300/minute per app), and shows the same
3109
+ * `index_warming` / `index_building` as search while a corpus loads.
3110
+ */
3111
+ passages(options?: {
3112
+ filter?: SearchFilter;
3113
+ cursor?: string | null;
3114
+ limit?: number;
3115
+ }): Promise<DataSourcePassagePage>;
3116
+ /**
3117
+ * Every passage matching a filter, a page at a time behind the scenes: the
3118
+ * walk over {@link passages}. Each page counts against the search rate
3119
+ * limit, so a large walk belongs in a background task.
3120
+ *
3121
+ * ```ts
3122
+ * for await (const passage of Manuals.allPassages({ entities: ['P-1004A'] })) {
3123
+ * mentions.push({ asset: 'P-1004A', ...passage.citation });
3124
+ * }
3125
+ * ```
3126
+ */
3127
+ allPassages(filter?: SearchFilter, options?: {
3128
+ /** Passages per page, at most 200 (the default). */
3129
+ pageSize?: number;
3130
+ }): AsyncGenerator<DataSourcePassage, void, undefined>;
3078
3131
  /**
3079
3132
  * Every document in the corpus, oldest first, a page at a time behind the
3080
3133
  * scenes. This is how an app builds its own view of a large corpus (a
@@ -11816,7 +11869,12 @@ declare function defineMapper(source: {
11816
11869
  * what named the document.
11817
11870
  * - `cleared(sourceId)` — the whole source was deleted, once, so the app can
11818
11871
  * drop that source's rows in one statement. Optional.
11819
- * A throw fails that delivery; the platform retries it.
11872
+ * - `relinked(document)` — a document already read was re-tagged by a new
11873
+ * dictionary: its passages carry different entities, its text is the same.
11874
+ * For rows derived from the tags. Optional.
11875
+ * A throw fails that delivery; the platform retries it. `document.bytes()`
11876
+ * reads the file the document came from, for a reader that needs the drawing
11877
+ * itself rather than its text.
11820
11878
  *
11821
11879
  * A reader runs against the app's LIVE release (or the dev session under
11822
11880
  * `reader test --dev`), never a pinned one: app databases are per release, so
@@ -11844,26 +11902,47 @@ interface ReaderDocument {
11844
11902
  pageCount: number | null;
11845
11903
  chunkCount: number | null;
11846
11904
  createdAt: string;
11905
+ /**
11906
+ * A short-lived link to the file the document came from: the uploaded
11907
+ * file, or on a mapped source the raw object the mapper read. Valid for the
11908
+ * delivery; null when the file is no longer kept.
11909
+ */
11910
+ url: string | null;
11847
11911
  /**
11848
11912
  * The document's passages as indexed: text, page, heading path, and each
11849
11913
  * passage's entities (its document's asserted ones and those its text
11850
11914
  * names from the source's dictionary). Read once, then held.
11851
11915
  */
11852
11916
  chunks(): Promise<DataSourceChunk[]>;
11917
+ /** The bytes behind {@link url}: a drawing's image, a PDF's pages. Read once, then held. */
11918
+ bytes(): Promise<Uint8Array>;
11853
11919
  }
11854
11920
  type MaybePromise<T> = T | Promise<T>;
11855
11921
  interface ReaderConfig {
11856
11922
  read: (document: ReaderDocument) => MaybePromise<void>;
11857
11923
  removed: (documentId: string) => MaybePromise<void>;
11858
11924
  cleared?: (sourceId: string) => MaybePromise<void>;
11925
+ /**
11926
+ * A document already read was re-tagged: the source's dictionary changed,
11927
+ * and its passages' entities with it. The document arrives as `read` gets
11928
+ * it, chunks and all, carrying the new entities, so rows derived from the
11929
+ * tags (links from assets to documents) can follow. Nothing about the text
11930
+ * changed, so this is no reason to extract again. Optional: without it a
11931
+ * relink delivers nothing.
11932
+ */
11933
+ relinked?: (document: ReaderDocument) => MaybePromise<void>;
11859
11934
  }
11860
- /** One delivery as the platform hands it to the executor. */
11861
- type ReadDelivery = {
11862
- kind: 'read';
11863
- document: Omit<ReaderDocument, 'chunks'>;
11935
+ type DocumentDelivery = {
11936
+ document: Omit<ReaderDocument, 'chunks' | 'bytes'>;
11864
11937
  /** The passages, when the platform carried them inline. */
11865
11938
  chunks?: DataSourceChunk[];
11866
- } | {
11939
+ };
11940
+ /** One delivery as the platform hands it to the executor. */
11941
+ type ReadDelivery = ({
11942
+ kind: 'read';
11943
+ } & DocumentDelivery) | ({
11944
+ kind: 'relinked';
11945
+ } & DocumentDelivery) | {
11867
11946
  kind: 'removed';
11868
11947
  documentId: string;
11869
11948
  } | {
@@ -11894,6 +11973,10 @@ interface ReadRunRecord {
11894
11973
  v: 1;
11895
11974
  source: string;
11896
11975
  outcomes: ReadRunResult[];
11976
+ /** The optional hooks this reader defines, so the platform sends only what one handles. */
11977
+ hooks: {
11978
+ relinked: boolean;
11979
+ };
11897
11980
  startedAt: number;
11898
11981
  durationMs: number;
11899
11982
  }
package/dist/index.js CHANGED
@@ -3261,7 +3261,8 @@ var DataSource = class {
3261
3261
  * it is who or what was written about then. No filter covers the corpus.
3262
3262
  * `chunks` is how many matching passages carry each id, not documents: a
3263
3263
  * long document's passages each count. Approximate counts, ordered most
3264
- * first; `limit` defaults to 20, at most 100.
3264
+ * first; `limit` defaults to 20, at most 1,000. One document's entities:
3265
+ * `{ filter: { documentIds: [id] } }`.
3265
3266
  *
3266
3267
  * Shares the search rate limit (300/minute per app), and shows the same
3267
3268
  * `index_warming` / `index_building` as search while a corpus loads.
@@ -3452,6 +3453,59 @@ var DataSource = class {
3452
3453
  });
3453
3454
  return { documents: documents2 ?? [], nextCursor: nextCursor ?? null };
3454
3455
  }
3456
+ /**
3457
+ * One page of the passages matching a filter, unranked: every page that
3458
+ * mentions an asset (`{ entities: ['P-1004A'] }`), every passage holding a
3459
+ * phrase, every chunk of some documents. Where {@link search} ranks and
3460
+ * stops at its top results and {@link count} gives a number, this lists
3461
+ * them all. Passages come document by document, each document's in order;
3462
+ * pass `nextCursor` back for the next page, which is null after the last.
3463
+ * `limit` defaults to 50, at most 200.
3464
+ *
3465
+ * Shares the search rate limit (300/minute per app), and shows the same
3466
+ * `index_warming` / `index_building` as search while a corpus loads.
3467
+ */
3468
+ async passages(options) {
3469
+ const { passages, nextCursor, latencyMs } = await this._call("passages", {
3470
+ slug: this._slug,
3471
+ ...options?.filter !== void 0 ? { filter: options.filter } : {},
3472
+ ...options?.cursor ? { cursor: options.cursor } : {},
3473
+ ...options?.limit !== void 0 ? { limit: options.limit } : {}
3474
+ });
3475
+ return {
3476
+ passages: passages ?? [],
3477
+ nextCursor: nextCursor ?? null,
3478
+ latencyMs: latencyMs ?? 0
3479
+ };
3480
+ }
3481
+ /**
3482
+ * Every passage matching a filter, a page at a time behind the scenes: the
3483
+ * walk over {@link passages}. Each page counts against the search rate
3484
+ * limit, so a large walk belongs in a background task.
3485
+ *
3486
+ * ```ts
3487
+ * for await (const passage of Manuals.allPassages({ entities: ['P-1004A'] })) {
3488
+ * mentions.push({ asset: 'P-1004A', ...passage.citation });
3489
+ * }
3490
+ * ```
3491
+ */
3492
+ async *allPassages(filter, options) {
3493
+ let cursor = null;
3494
+ while (true) {
3495
+ const page = await this.passages({
3496
+ ...filter !== void 0 ? { filter } : {},
3497
+ cursor,
3498
+ limit: options?.pageSize ?? 200
3499
+ });
3500
+ for (const passage of page.passages) {
3501
+ yield passage;
3502
+ }
3503
+ if (!page.nextCursor || page.passages.length === 0) {
3504
+ return;
3505
+ }
3506
+ cursor = page.nextCursor;
3507
+ }
3508
+ }
3455
3509
  /**
3456
3510
  * Every document in the corpus, oldest first, a page at a time behind the
3457
3511
  * scenes. This is how an app builds its own view of a large corpus (a
@@ -8519,6 +8573,7 @@ function errorInfo3(e) {
8519
8573
  function refOf(delivery) {
8520
8574
  switch (delivery.kind) {
8521
8575
  case "read":
8576
+ case "relinked":
8522
8577
  return delivery.document.id;
8523
8578
  case "removed":
8524
8579
  return delivery.documentId;
@@ -8549,6 +8604,8 @@ async function withTimeout2(work, timeoutMs, ref) {
8549
8604
  function defineReader(source, config) {
8550
8605
  const documentFor = (delivery) => {
8551
8606
  let cached = delivery.chunks ? Promise.resolve(delivery.chunks) : null;
8607
+ let bytes = null;
8608
+ const { url } = delivery.document;
8552
8609
  return {
8553
8610
  ...delivery.document,
8554
8611
  chunks: () => {
@@ -8556,6 +8613,25 @@ function defineReader(source, config) {
8556
8613
  cached = source.chunks(delivery.document.id);
8557
8614
  }
8558
8615
  return cached;
8616
+ },
8617
+ bytes: () => {
8618
+ if (!bytes) {
8619
+ bytes = (async () => {
8620
+ if (!url) {
8621
+ throw new Error(
8622
+ `The file behind document ${delivery.document.id} is no longer kept.`
8623
+ );
8624
+ }
8625
+ const response = await fetch(url);
8626
+ if (!response.ok) {
8627
+ throw new Error(
8628
+ `Could not read the file behind document ${delivery.document.id}: HTTP ${response.status}`
8629
+ );
8630
+ }
8631
+ return new Uint8Array(await response.arrayBuffer());
8632
+ })();
8633
+ }
8634
+ return bytes;
8559
8635
  }
8560
8636
  };
8561
8637
  };
@@ -8564,6 +8640,9 @@ function defineReader(source, config) {
8564
8640
  case "read":
8565
8641
  await config.read(documentFor(delivery));
8566
8642
  return;
8643
+ case "relinked":
8644
+ await config.relinked?.(documentFor(delivery));
8645
+ return;
8567
8646
  case "removed":
8568
8647
  await config.removed(delivery.documentId);
8569
8648
  return;
@@ -8618,6 +8697,7 @@ function defineReader(source, config) {
8618
8697
  v: 1,
8619
8698
  source: source.name,
8620
8699
  outcomes,
8700
+ hooks: { relinked: typeof config.relinked === "function" },
8621
8701
  startedAt,
8622
8702
  durationMs: Date.now() - startedAt
8623
8703
  };