@mindstudio-ai/agent 0.1.138 → 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/cli.js +197 -10
- package/dist/index.d.ts +438 -17
- package/dist/index.js +326 -1
- package/dist/index.js.map +1 -1
- package/dist/postinstall.js +197 -10
- package/llms.txt +18 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3131,6 +3131,8 @@ function createFiles(call) {
|
|
|
3131
3131
|
|
|
3132
3132
|
// src/datasources/source.ts
|
|
3133
3133
|
import { createHash as createHash2 } from "crypto";
|
|
3134
|
+
var DICTIONARY_PAGE_ENTRIES = 1e4;
|
|
3135
|
+
var DICTIONARY_PAGE_BYTES = 4e6;
|
|
3134
3136
|
var REMOVE_WHERE_MAX_PAGES = 100;
|
|
3135
3137
|
var DataSource = class {
|
|
3136
3138
|
constructor(_slug, _call) {
|
|
@@ -3251,6 +3253,121 @@ var DataSource = class {
|
|
|
3251
3253
|
});
|
|
3252
3254
|
return { chunks: chunks ?? 0, latencyMs: latencyMs ?? 0 };
|
|
3253
3255
|
}
|
|
3256
|
+
/**
|
|
3257
|
+
* Which entities the passages matching a filter are about, most first.
|
|
3258
|
+
*
|
|
3259
|
+
* Filter on one entity (`{ entities: ['P-101A'] }`) and the answer is what
|
|
3260
|
+
* appears beside it: a co-mention graph for free. Filter on a date range and
|
|
3261
|
+
* it is who or what was written about then. No filter covers the corpus.
|
|
3262
|
+
* `chunks` is how many matching passages carry each id, not documents: a
|
|
3263
|
+
* long document's passages each count. Approximate counts, ordered most
|
|
3264
|
+
* first; `limit` defaults to 20, at most 1,000. One document's entities:
|
|
3265
|
+
* `{ filter: { documentIds: [id] } }`.
|
|
3266
|
+
*
|
|
3267
|
+
* Shares the search rate limit (300/minute per app), and shows the same
|
|
3268
|
+
* `index_warming` / `index_building` as search while a corpus loads.
|
|
3269
|
+
*/
|
|
3270
|
+
async entities(options) {
|
|
3271
|
+
const { entities, latencyMs } = await this._call("entities", {
|
|
3272
|
+
slug: this._slug,
|
|
3273
|
+
...options?.filter !== void 0 ? { filter: options.filter } : {},
|
|
3274
|
+
...options?.limit !== void 0 ? { limit: options.limit } : {}
|
|
3275
|
+
});
|
|
3276
|
+
return { entities: entities ?? [], latencyMs: latencyMs ?? 0 };
|
|
3277
|
+
}
|
|
3278
|
+
/**
|
|
3279
|
+
* Push this source's dictionary: every entity id you have and the names it
|
|
3280
|
+
* goes by, replacing the dictionary it had. From then on every passage is
|
|
3281
|
+
* tagged with the ids whose names its text mentions, beside the ones its
|
|
3282
|
+
* document asserts, so `filter.entities` and {@link entities} find a tag
|
|
3283
|
+
* wherever it's written. Passages indexed before are re-tagged in the
|
|
3284
|
+
* background (a relink; see {@link dictionary}), and nothing is
|
|
3285
|
+
* re-embedded.
|
|
3286
|
+
*
|
|
3287
|
+
* Push it whole after each load of the tables it comes from: an unchanged
|
|
3288
|
+
* dictionary commits nothing (`unchanged: true`). Takes an array or any
|
|
3289
|
+
* (async) iterable, and sends it in pages, so a register of a quarter of a
|
|
3290
|
+
* million entries is fine. A repeated id merges its names.
|
|
3291
|
+
*/
|
|
3292
|
+
async pushDictionary(entries, options) {
|
|
3293
|
+
const { stageId, pageMaxEntries } = await this._call("dictionary/stage", {
|
|
3294
|
+
slug: this._slug,
|
|
3295
|
+
...options?.linkerVersion !== void 0 ? { linkerVersion: options.linkerVersion } : {}
|
|
3296
|
+
});
|
|
3297
|
+
const perPage = Math.min(
|
|
3298
|
+
DICTIONARY_PAGE_ENTRIES,
|
|
3299
|
+
Number(pageMaxEntries) || DICTIONARY_PAGE_ENTRIES
|
|
3300
|
+
);
|
|
3301
|
+
let pages = 0;
|
|
3302
|
+
let page = [];
|
|
3303
|
+
let bytes = 0;
|
|
3304
|
+
const send = async () => {
|
|
3305
|
+
if (page.length === 0) {
|
|
3306
|
+
return;
|
|
3307
|
+
}
|
|
3308
|
+
await this._call("dictionary/page", {
|
|
3309
|
+
slug: this._slug,
|
|
3310
|
+
stageId,
|
|
3311
|
+
page: pages,
|
|
3312
|
+
entries: page
|
|
3313
|
+
});
|
|
3314
|
+
pages += 1;
|
|
3315
|
+
page = [];
|
|
3316
|
+
bytes = 0;
|
|
3317
|
+
};
|
|
3318
|
+
for await (const entry of entries) {
|
|
3319
|
+
const size = JSON.stringify(entry).length;
|
|
3320
|
+
if (page.length >= perPage || bytes + size > DICTIONARY_PAGE_BYTES) {
|
|
3321
|
+
await send();
|
|
3322
|
+
}
|
|
3323
|
+
page.push(entry);
|
|
3324
|
+
bytes += size;
|
|
3325
|
+
}
|
|
3326
|
+
await send();
|
|
3327
|
+
if (pages === 0) {
|
|
3328
|
+
throw new Error(
|
|
3329
|
+
"pushDictionary needs at least one entry. To clear what a dictionary tags, push its entries with the names you mean."
|
|
3330
|
+
);
|
|
3331
|
+
}
|
|
3332
|
+
return this._call("dictionary/commit", {
|
|
3333
|
+
slug: this._slug,
|
|
3334
|
+
stageId,
|
|
3335
|
+
pages
|
|
3336
|
+
});
|
|
3337
|
+
}
|
|
3338
|
+
/**
|
|
3339
|
+
* The source's current dictionary, or null when none was pushed, and the
|
|
3340
|
+
* relink re-tagging its passages while one runs.
|
|
3341
|
+
*/
|
|
3342
|
+
async dictionary() {
|
|
3343
|
+
const { dictionary, relink } = await this._call("dictionary", {
|
|
3344
|
+
slug: this._slug
|
|
3345
|
+
});
|
|
3346
|
+
return {
|
|
3347
|
+
dictionary: dictionary ?? null,
|
|
3348
|
+
relink: relink ? {
|
|
3349
|
+
version: relink.version,
|
|
3350
|
+
lap: relink.lap,
|
|
3351
|
+
walked: relink.walked,
|
|
3352
|
+
total: relink.total,
|
|
3353
|
+
waiting: relink.waiting ?? null,
|
|
3354
|
+
error: relink.error ?? null
|
|
3355
|
+
} : null
|
|
3356
|
+
};
|
|
3357
|
+
}
|
|
3358
|
+
/**
|
|
3359
|
+
* What the current dictionary finds in a piece of text: each mention, in
|
|
3360
|
+
* order, with the ids it tags. How to check a dictionary before relying on
|
|
3361
|
+
* it. `version` is null when the source has none. Shares the search rate
|
|
3362
|
+
* limit.
|
|
3363
|
+
*/
|
|
3364
|
+
async link(text) {
|
|
3365
|
+
const { version, mentions } = await this._call("link", {
|
|
3366
|
+
slug: this._slug,
|
|
3367
|
+
text
|
|
3368
|
+
});
|
|
3369
|
+
return { version: version ?? null, mentions: mentions ?? [] };
|
|
3370
|
+
}
|
|
3254
3371
|
/**
|
|
3255
3372
|
* Every chunk of one document, exactly as it was indexed.
|
|
3256
3373
|
*
|
|
@@ -3302,6 +3419,7 @@ var DataSource = class {
|
|
|
3302
3419
|
filename: options.filename,
|
|
3303
3420
|
...options.contentType ? { contentType: options.contentType } : {},
|
|
3304
3421
|
...options.metadata !== void 0 ? { metadata: options.metadata } : {},
|
|
3422
|
+
...options.entities !== void 0 ? { entities: options.entities } : {},
|
|
3305
3423
|
body: bytes.toString("base64")
|
|
3306
3424
|
});
|
|
3307
3425
|
}
|
|
@@ -3335,6 +3453,59 @@ var DataSource = class {
|
|
|
3335
3453
|
});
|
|
3336
3454
|
return { documents: documents2 ?? [], nextCursor: nextCursor ?? null };
|
|
3337
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
|
+
}
|
|
3338
3509
|
/**
|
|
3339
3510
|
* Every document in the corpus, oldest first, a page at a time behind the
|
|
3340
3511
|
* scenes. This is how an app builds its own view of a large corpus (a
|
|
@@ -8252,7 +8423,11 @@ function documents(list) {
|
|
|
8252
8423
|
return { kind: "documents", documents: Array.isArray(list) ? list : [list] };
|
|
8253
8424
|
}
|
|
8254
8425
|
function passthrough(options) {
|
|
8255
|
-
return
|
|
8426
|
+
return {
|
|
8427
|
+
kind: "passthrough",
|
|
8428
|
+
...options?.metadata !== void 0 ? { metadata: options.metadata } : {},
|
|
8429
|
+
...options?.entities !== void 0 ? { entities: options.entities } : {}
|
|
8430
|
+
};
|
|
8256
8431
|
}
|
|
8257
8432
|
function skip(reason) {
|
|
8258
8433
|
return { kind: "skip", reason };
|
|
@@ -8296,6 +8471,7 @@ function objectFor(input) {
|
|
|
8296
8471
|
etag: input.etag,
|
|
8297
8472
|
lastModified: input.lastModified,
|
|
8298
8473
|
metadata: input.metadata,
|
|
8474
|
+
entities: input.entities ?? null,
|
|
8299
8475
|
bytes,
|
|
8300
8476
|
text: async () => new TextDecoder("utf-8").decode(await bytes()),
|
|
8301
8477
|
json: async () => JSON.parse(new TextDecoder("utf-8").decode(await bytes()))
|
|
@@ -8385,6 +8561,154 @@ function defineMapper(source, config) {
|
|
|
8385
8561
|
});
|
|
8386
8562
|
}
|
|
8387
8563
|
|
|
8564
|
+
// src/reader/index.ts
|
|
8565
|
+
var DEFAULT_TIMEOUT_MS2 = 6e4;
|
|
8566
|
+
var DEFAULT_CONCURRENCY3 = 4;
|
|
8567
|
+
function errorInfo3(e) {
|
|
8568
|
+
if (e instanceof Error) {
|
|
8569
|
+
return { message: e.message, stack: e.stack };
|
|
8570
|
+
}
|
|
8571
|
+
return { message: String(e) };
|
|
8572
|
+
}
|
|
8573
|
+
function refOf(delivery) {
|
|
8574
|
+
switch (delivery.kind) {
|
|
8575
|
+
case "read":
|
|
8576
|
+
case "relinked":
|
|
8577
|
+
return delivery.document.id;
|
|
8578
|
+
case "removed":
|
|
8579
|
+
return delivery.documentId;
|
|
8580
|
+
case "cleared":
|
|
8581
|
+
return delivery.sourceId;
|
|
8582
|
+
}
|
|
8583
|
+
}
|
|
8584
|
+
async function withTimeout2(work, timeoutMs, ref) {
|
|
8585
|
+
let timer;
|
|
8586
|
+
try {
|
|
8587
|
+
return await Promise.race([
|
|
8588
|
+
work,
|
|
8589
|
+
new Promise((_, reject) => {
|
|
8590
|
+
timer = setTimeout(
|
|
8591
|
+
() => reject(
|
|
8592
|
+
new Error(`reader timed out after ${timeoutMs}ms on ${ref}`)
|
|
8593
|
+
),
|
|
8594
|
+
timeoutMs
|
|
8595
|
+
);
|
|
8596
|
+
})
|
|
8597
|
+
]);
|
|
8598
|
+
} finally {
|
|
8599
|
+
if (timer) {
|
|
8600
|
+
clearTimeout(timer);
|
|
8601
|
+
}
|
|
8602
|
+
}
|
|
8603
|
+
}
|
|
8604
|
+
function defineReader(source, config) {
|
|
8605
|
+
const documentFor = (delivery) => {
|
|
8606
|
+
let cached = delivery.chunks ? Promise.resolve(delivery.chunks) : null;
|
|
8607
|
+
let bytes = null;
|
|
8608
|
+
const { url } = delivery.document;
|
|
8609
|
+
return {
|
|
8610
|
+
...delivery.document,
|
|
8611
|
+
chunks: () => {
|
|
8612
|
+
if (!cached) {
|
|
8613
|
+
cached = source.chunks(delivery.document.id);
|
|
8614
|
+
}
|
|
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;
|
|
8635
|
+
}
|
|
8636
|
+
};
|
|
8637
|
+
};
|
|
8638
|
+
const deliver2 = async (delivery) => {
|
|
8639
|
+
switch (delivery.kind) {
|
|
8640
|
+
case "read":
|
|
8641
|
+
await config.read(documentFor(delivery));
|
|
8642
|
+
return;
|
|
8643
|
+
case "relinked":
|
|
8644
|
+
await config.relinked?.(documentFor(delivery));
|
|
8645
|
+
return;
|
|
8646
|
+
case "removed":
|
|
8647
|
+
await config.removed(delivery.documentId);
|
|
8648
|
+
return;
|
|
8649
|
+
case "cleared":
|
|
8650
|
+
await config.cleared?.(delivery.sourceId);
|
|
8651
|
+
return;
|
|
8652
|
+
}
|
|
8653
|
+
};
|
|
8654
|
+
const run = async (params) => {
|
|
8655
|
+
const startedAt = Date.now();
|
|
8656
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
8657
|
+
const concurrency = Math.max(1, params.concurrency ?? DEFAULT_CONCURRENCY3);
|
|
8658
|
+
const deliveries = Array.isArray(params.deliveries) ? params.deliveries : [];
|
|
8659
|
+
const outcomes = new Array(deliveries.length);
|
|
8660
|
+
let next = 0;
|
|
8661
|
+
const worker = async () => {
|
|
8662
|
+
while (true) {
|
|
8663
|
+
const index = next++;
|
|
8664
|
+
if (index >= deliveries.length) {
|
|
8665
|
+
return;
|
|
8666
|
+
}
|
|
8667
|
+
const delivery = deliveries[index];
|
|
8668
|
+
const ref = refOf(delivery);
|
|
8669
|
+
const t = Date.now();
|
|
8670
|
+
try {
|
|
8671
|
+
await withTimeout2(
|
|
8672
|
+
Promise.resolve().then(() => deliver2(delivery)),
|
|
8673
|
+
timeoutMs,
|
|
8674
|
+
ref
|
|
8675
|
+
);
|
|
8676
|
+
outcomes[index] = {
|
|
8677
|
+
ref,
|
|
8678
|
+
kind: delivery.kind,
|
|
8679
|
+
ok: true,
|
|
8680
|
+
durationMs: Date.now() - t
|
|
8681
|
+
};
|
|
8682
|
+
} catch (e) {
|
|
8683
|
+
outcomes[index] = {
|
|
8684
|
+
ref,
|
|
8685
|
+
kind: delivery.kind,
|
|
8686
|
+
ok: false,
|
|
8687
|
+
error: errorInfo3(e),
|
|
8688
|
+
durationMs: Date.now() - t
|
|
8689
|
+
};
|
|
8690
|
+
}
|
|
8691
|
+
}
|
|
8692
|
+
};
|
|
8693
|
+
await Promise.all(
|
|
8694
|
+
Array.from({ length: Math.min(concurrency, deliveries.length) }, worker)
|
|
8695
|
+
);
|
|
8696
|
+
return {
|
|
8697
|
+
v: 1,
|
|
8698
|
+
source: source.name,
|
|
8699
|
+
outcomes,
|
|
8700
|
+
hooks: { relinked: typeof config.relinked === "function" },
|
|
8701
|
+
startedAt,
|
|
8702
|
+
durationMs: Date.now() - startedAt
|
|
8703
|
+
};
|
|
8704
|
+
};
|
|
8705
|
+
return Object.assign(run, {
|
|
8706
|
+
kind: "reader",
|
|
8707
|
+
source: source.name,
|
|
8708
|
+
config
|
|
8709
|
+
});
|
|
8710
|
+
}
|
|
8711
|
+
|
|
8388
8712
|
// src/generated/snippets.ts
|
|
8389
8713
|
var monacoSnippets = {
|
|
8390
8714
|
"activeCampaignAddNote": { fields: [["contactId", "string"], ["note", "string"]], outputKeys: [] },
|
|
@@ -8645,6 +8969,7 @@ export {
|
|
|
8645
8969
|
index_default as default,
|
|
8646
8970
|
defineJewel,
|
|
8647
8971
|
defineMapper,
|
|
8972
|
+
defineReader,
|
|
8648
8973
|
deletes,
|
|
8649
8974
|
documents,
|
|
8650
8975
|
email,
|