nexus-ai-pro 2.8.0 → 2.9.0
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/API_STABILITY.md +34 -0
- package/CHANGELOG.md +109 -1
- package/README.md +15 -4
- package/dist/batch/poll.d.ts +8 -4
- package/dist/batch/poll.js +2 -1
- package/dist/deep-agent/helpers.d.ts +4 -0
- package/dist/deep-agent/helpers.js +56 -4
- package/dist/evaluate/online.d.ts +5 -0
- package/dist/evaluate/online.js +74 -5
- package/dist/lifecycle/budget.d.ts +60 -3
- package/dist/lifecycle/budget.js +147 -3
- package/dist/lifecycle/index.d.ts +2 -2
- package/dist/lifecycle/reservations.d.ts +46 -0
- package/dist/lifecycle/reservations.js +67 -0
- package/dist/media/rag.d.ts +76 -1
- package/dist/media/rag.js +195 -53
- package/dist/postgres/tenancy.d.ts +26 -1
- package/dist/postgres/tenancy.js +116 -1
- package/dist/postgres/traces.d.ts +2 -1
- package/dist/postgres/traces.js +13 -1
- package/dist/server/tenancy.d.ts +33 -2
- package/dist/server/tenancy.js +162 -0
- package/dist/tracing/index.d.ts +2 -2
- package/dist/tracing/index.js +1 -1
- package/dist/tracing/query.d.ts +5 -1
- package/dist/tracing/query.js +14 -1
- package/dist/tracing/stores.d.ts +2 -2
- package/dist/tracing/stores.js +2 -2
- package/dist/types/lifecycle.d.ts +92 -1
- package/dist/types/tracing.d.ts +20 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/video/errors.d.ts +37 -0
- package/dist/video/errors.js +22 -0
- package/dist/video/google.d.ts +52 -0
- package/dist/video/google.js +248 -0
- package/dist/video/index.d.ts +426 -0
- package/dist/video/index.js +666 -0
- package/dist/video/mock.d.ts +62 -0
- package/dist/video/mock.js +97 -0
- package/dist/video/runway.d.ts +47 -0
- package/dist/video/runway.js +241 -0
- package/dist-cjs/batch/poll.d.ts +8 -4
- package/dist-cjs/batch/poll.js +2 -1
- package/dist-cjs/deep-agent/helpers.d.ts +4 -0
- package/dist-cjs/deep-agent/helpers.js +56 -4
- package/dist-cjs/evaluate/online.d.ts +5 -0
- package/dist-cjs/evaluate/online.js +74 -5
- package/dist-cjs/lifecycle/budget.d.ts +60 -3
- package/dist-cjs/lifecycle/budget.js +147 -3
- package/dist-cjs/lifecycle/index.d.ts +2 -2
- package/dist-cjs/lifecycle/reservations.d.ts +46 -0
- package/dist-cjs/lifecycle/reservations.js +71 -0
- package/dist-cjs/media/rag.d.ts +76 -1
- package/dist-cjs/media/rag.js +195 -53
- package/dist-cjs/postgres/tenancy.d.ts +26 -1
- package/dist-cjs/postgres/tenancy.js +115 -0
- package/dist-cjs/postgres/traces.d.ts +2 -1
- package/dist-cjs/postgres/traces.js +13 -1
- package/dist-cjs/server/tenancy.d.ts +33 -2
- package/dist-cjs/server/tenancy.js +162 -0
- package/dist-cjs/tracing/index.d.ts +2 -2
- package/dist-cjs/tracing/index.js +3 -1
- package/dist-cjs/tracing/query.d.ts +5 -1
- package/dist-cjs/tracing/query.js +16 -1
- package/dist-cjs/tracing/stores.d.ts +2 -2
- package/dist-cjs/tracing/stores.js +3 -1
- package/dist-cjs/types/lifecycle.d.ts +92 -1
- package/dist-cjs/types/tracing.d.ts +20 -1
- package/dist-cjs/version.d.ts +1 -1
- package/dist-cjs/version.js +1 -1
- package/dist-cjs/video/errors.d.ts +37 -0
- package/dist-cjs/video/errors.js +27 -0
- package/dist-cjs/video/google.d.ts +52 -0
- package/dist-cjs/video/google.js +252 -0
- package/dist-cjs/video/index.d.ts +426 -0
- package/dist-cjs/video/index.js +708 -0
- package/dist-cjs/video/mock.d.ts +62 -0
- package/dist-cjs/video/mock.js +101 -0
- package/dist-cjs/video/runway.d.ts +47 -0
- package/dist-cjs/video/runway.js +245 -0
- package/llms.txt +2 -1
- package/package.json +54 -1
package/dist/lifecycle/budget.js
CHANGED
|
@@ -1,12 +1,47 @@
|
|
|
1
1
|
import { BudgetExceededError } from '../core/lifecycle.js';
|
|
2
|
+
import { randomHex } from '../utils/ids.js';
|
|
2
3
|
import { periodEnd, periodStart } from '../utils/periods.js';
|
|
4
|
+
import { MemoryReservationBook } from './reservations.js';
|
|
5
|
+
const DEFAULT_LEASE_MS = 10 * 60 * 1000;
|
|
6
|
+
const FROM = {
|
|
7
|
+
settled: ['reserved', 'uncertain', 'expired'],
|
|
8
|
+
released: ['reserved', 'uncertain'],
|
|
9
|
+
recovered: ['reserved'],
|
|
10
|
+
};
|
|
3
11
|
export function budgetLedger(options) {
|
|
4
12
|
const now = options.now ?? (() => new Date());
|
|
5
13
|
const period = options.period ?? 'month';
|
|
6
14
|
const store = options.store ?? new MemoryBudgetUsage(() => now().getTime());
|
|
15
|
+
const records = recordsOf(store);
|
|
16
|
+
const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;
|
|
17
|
+
if (!(Number.isFinite(leaseMs) && leaseMs > 0))
|
|
18
|
+
throw new RangeError('leaseMs must be a positive number');
|
|
19
|
+
const uncertain = options.uncertain ?? 'charge';
|
|
7
20
|
const windows = new WeakMap();
|
|
8
21
|
const storeKeyOf = (key, at) => `budget:${encodeURIComponent(key)}:${periodStart(period, at)}`;
|
|
9
22
|
const limitOf = async (key) => (typeof options.limit === 'function' ? options.limit(key) : options.limit);
|
|
23
|
+
const apply = async (record, outcome) => {
|
|
24
|
+
if (!records)
|
|
25
|
+
return false;
|
|
26
|
+
const at = now().getTime();
|
|
27
|
+
switch (outcome.kind) {
|
|
28
|
+
case 'running':
|
|
29
|
+
return records.renew(record.id, at + leaseMs);
|
|
30
|
+
case 'finished': {
|
|
31
|
+
const cost = Math.max(0, outcome.cost);
|
|
32
|
+
return records.settle(record.id, { status: 'settled', charged: cost, actual: cost, from: FROM.settled, at });
|
|
33
|
+
}
|
|
34
|
+
case 'never-started':
|
|
35
|
+
return records.settle(record.id, { status: 'expired', charged: 0, from: FROM.recovered, at });
|
|
36
|
+
case 'unknown':
|
|
37
|
+
return records.settle(record.id, {
|
|
38
|
+
status: 'uncertain',
|
|
39
|
+
charged: uncertain === 'charge' ? record.amount : 0,
|
|
40
|
+
from: FROM.recovered,
|
|
41
|
+
at,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
10
45
|
return {
|
|
11
46
|
async reserve(operation, estimate) {
|
|
12
47
|
const key = options.key ? options.key(operation) : (operation.tenantId ?? 'default');
|
|
@@ -19,17 +54,48 @@ export function budgetLedger(options) {
|
|
|
19
54
|
const storeKey = storeKeyOf(key, at);
|
|
20
55
|
const resetAt = periodEnd(period, at);
|
|
21
56
|
const amount = Math.max(0, estimate);
|
|
22
|
-
const
|
|
57
|
+
const id = records ? `rsv_${randomHex(12)}` : undefined;
|
|
58
|
+
const total = records
|
|
59
|
+
? await records.hold({
|
|
60
|
+
id: id,
|
|
61
|
+
key,
|
|
62
|
+
storeKey,
|
|
63
|
+
resetAt,
|
|
64
|
+
amount,
|
|
65
|
+
charged: amount,
|
|
66
|
+
operationId: operation.requestId,
|
|
67
|
+
family: operation.family,
|
|
68
|
+
operation: operation.operation,
|
|
69
|
+
status: 'reserved',
|
|
70
|
+
leasedUntil: at.getTime() + leaseMs,
|
|
71
|
+
createdAt: at.getTime(),
|
|
72
|
+
})
|
|
73
|
+
: await store.add(storeKey, amount, resetAt);
|
|
23
74
|
const before = total - amount;
|
|
24
75
|
if (total > limit || before >= limit) {
|
|
25
|
-
|
|
76
|
+
if (records) {
|
|
77
|
+
await records.settle(id, { status: 'released', charged: 0, from: FROM.released, at: at.getTime() });
|
|
78
|
+
}
|
|
79
|
+
else
|
|
80
|
+
await store.add(storeKey, -amount, resetAt);
|
|
26
81
|
throw new BudgetExceededError(key, amount, limit - before);
|
|
27
82
|
}
|
|
28
|
-
const reservation = { key, amount };
|
|
83
|
+
const reservation = { key, amount, ...(id ? { id } : {}) };
|
|
29
84
|
windows.set(reservation, { storeKey, resetAt });
|
|
30
85
|
return reservation;
|
|
31
86
|
},
|
|
32
87
|
async reconcile(reservation, actual) {
|
|
88
|
+
if (reservation.id && records) {
|
|
89
|
+
const cost = Math.max(0, actual);
|
|
90
|
+
await records.settle(reservation.id, {
|
|
91
|
+
status: 'settled',
|
|
92
|
+
charged: cost,
|
|
93
|
+
actual: cost,
|
|
94
|
+
from: FROM.settled,
|
|
95
|
+
at: now().getTime(),
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
33
99
|
const window = windows.get(reservation);
|
|
34
100
|
if (!window)
|
|
35
101
|
return;
|
|
@@ -39,6 +105,15 @@ export function budgetLedger(options) {
|
|
|
39
105
|
await store.add(window.storeKey, delta, window.resetAt);
|
|
40
106
|
},
|
|
41
107
|
async release(reservation) {
|
|
108
|
+
if (reservation.id && records) {
|
|
109
|
+
await records.settle(reservation.id, {
|
|
110
|
+
status: 'released',
|
|
111
|
+
charged: 0,
|
|
112
|
+
from: FROM.released,
|
|
113
|
+
at: now().getTime(),
|
|
114
|
+
});
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
42
117
|
const window = windows.get(reservation);
|
|
43
118
|
if (!window)
|
|
44
119
|
return;
|
|
@@ -49,13 +124,67 @@ export function budgetLedger(options) {
|
|
|
49
124
|
async spent(key) {
|
|
50
125
|
return store.total(storeKeyOf(key, now()));
|
|
51
126
|
},
|
|
127
|
+
async reservation(id) {
|
|
128
|
+
return records ? records.reservation(id) : undefined;
|
|
129
|
+
},
|
|
130
|
+
async renew(reservation) {
|
|
131
|
+
if (reservation.id && records)
|
|
132
|
+
await records.renew(reservation.id, now().getTime() + leaseMs);
|
|
133
|
+
},
|
|
134
|
+
async settle(id, outcome) {
|
|
135
|
+
const record = records ? await records.reservation(id) : undefined;
|
|
136
|
+
return record ? apply(record, outcome) : false;
|
|
137
|
+
},
|
|
138
|
+
async recover(resolve, recoverOptions = {}) {
|
|
139
|
+
const report = { settled: 0, expired: 0, uncertain: 0, renewed: 0, skipped: 0 };
|
|
140
|
+
if (!records)
|
|
141
|
+
return report;
|
|
142
|
+
const lapsed = await records.lapsed(now().getTime(), recoverOptions.limit ?? 100, recoverOptions.operation);
|
|
143
|
+
for (const record of lapsed) {
|
|
144
|
+
const outcome = await resolve(record);
|
|
145
|
+
if (!outcome) {
|
|
146
|
+
report.skipped += 1;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (!(await apply(record, outcome)))
|
|
150
|
+
continue;
|
|
151
|
+
if (outcome.kind === 'finished')
|
|
152
|
+
report.settled += 1;
|
|
153
|
+
else if (outcome.kind === 'never-started')
|
|
154
|
+
report.expired += 1;
|
|
155
|
+
else if (outcome.kind === 'unknown')
|
|
156
|
+
report.uncertain += 1;
|
|
157
|
+
else
|
|
158
|
+
report.renewed += 1;
|
|
159
|
+
}
|
|
160
|
+
return report;
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function recordsOf(store) {
|
|
165
|
+
const names = ['hold', 'settle', 'renew', 'lapsed', 'reservation'];
|
|
166
|
+
const present = names.filter((name) => typeof store[name] === 'function');
|
|
167
|
+
if (present.length === 0)
|
|
168
|
+
return undefined;
|
|
169
|
+
if (present.length < names.length) {
|
|
170
|
+
const missing = names.filter((name) => !present.includes(name));
|
|
171
|
+
throw new TypeError(`A budget store that records reservations implements all five methods; missing ${missing.join(', ')}`);
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
hold: (record) => store.hold.call(store, record),
|
|
175
|
+
settle: (id, change) => store.settle.call(store, id, change),
|
|
176
|
+
renew: (id, leasedUntil) => store.renew.call(store, id, leasedUntil),
|
|
177
|
+
lapsed: (at, limit, operation) => store.lapsed.call(store, at, limit, operation),
|
|
178
|
+
reservation: (id) => store.reservation.call(store, id),
|
|
52
179
|
};
|
|
53
180
|
}
|
|
54
181
|
export class MemoryBudgetUsage {
|
|
55
182
|
now;
|
|
56
183
|
totals = new Map();
|
|
184
|
+
book;
|
|
57
185
|
constructor(now = () => Date.now()) {
|
|
58
186
|
this.now = now;
|
|
187
|
+
this.book = new MemoryReservationBook((key, amount, resetAt) => this.add(key, amount, resetAt), now);
|
|
59
188
|
}
|
|
60
189
|
add(key, amount, resetAt) {
|
|
61
190
|
const current = this.totals.get(key);
|
|
@@ -67,4 +196,19 @@ export class MemoryBudgetUsage {
|
|
|
67
196
|
const current = this.totals.get(key);
|
|
68
197
|
return current && current.resetAt > this.now() ? current.value : 0;
|
|
69
198
|
}
|
|
199
|
+
hold(record) {
|
|
200
|
+
return this.book.hold(record);
|
|
201
|
+
}
|
|
202
|
+
settle(id, change) {
|
|
203
|
+
return this.book.settle(id, change);
|
|
204
|
+
}
|
|
205
|
+
renew(id, leasedUntil) {
|
|
206
|
+
return this.book.renew(id, leasedUntil);
|
|
207
|
+
}
|
|
208
|
+
lapsed(now, limit, operation) {
|
|
209
|
+
return this.book.lapsed(now, limit, operation);
|
|
210
|
+
}
|
|
211
|
+
reservation(id) {
|
|
212
|
+
return this.book.get(id);
|
|
213
|
+
}
|
|
70
214
|
}
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* building that budget, and for code that runs operations of its own through `ai.lifecycle`.
|
|
5
5
|
*/
|
|
6
6
|
export { BudgetExceededError, LIFECYCLE_STAGES, type LifecycleRuntime, OperationDeniedError, OperationLifecycle, type OperationPlan, } from '../core/lifecycle.js';
|
|
7
|
-
export { type BudgetLedgerOptions, type BudgetLedgerWithReport, type BudgetUsageStore, budgetLedger, MemoryBudgetUsage, } from './budget.js';
|
|
8
|
-
export type { BudgetLedger, BudgetPeriod, BudgetReservation, LifecycleConfig, LifecycleHooks, LifecycleStage, OperationDescriptor, OperationFamily, OperationLifecycleLike, OperationOutcome, OperationResultInfo, OperationStartOptions, OperationTicket, ProviderCallContext, } from '../types/lifecycle.js';
|
|
7
|
+
export { type BudgetLedgerOptions, type BudgetLedgerWithReport, type BudgetReservationChange, type BudgetUsageStore, budgetLedger, MemoryBudgetUsage, } from './budget.js';
|
|
8
|
+
export type { BudgetLedger, BudgetPeriod, BudgetRecoverOptions, BudgetRecoveryReport, BudgetReservation, BudgetReservationOutcome, BudgetReservationRecord, BudgetReservationStatus, LifecycleConfig, LifecycleHooks, LifecycleStage, OperationDescriptor, OperationFamily, OperationLifecycleLike, OperationOutcome, OperationResultInfo, OperationStartOptions, OperationTicket, ProviderCallContext, } from '../types/lifecycle.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { BudgetReservationRecord, BudgetReservationStatus } from '../types/lifecycle.js';
|
|
2
|
+
/**
|
|
3
|
+
* A change to one recorded reservation: where it moves, what it charges once there, and the
|
|
4
|
+
* statuses it may move from. A store applies the status and the difference in what it charges to its
|
|
5
|
+
* total together, or not at all.
|
|
6
|
+
*/
|
|
7
|
+
export interface BudgetReservationChange {
|
|
8
|
+
/** Where it moves. */
|
|
9
|
+
status: Exclude<BudgetReservationStatus, 'reserved'>;
|
|
10
|
+
/** What it adds to its total once moved. */
|
|
11
|
+
charged: number;
|
|
12
|
+
/** The statuses it may move from. From any other, the change is refused. */
|
|
13
|
+
from: readonly BudgetReservationStatus[];
|
|
14
|
+
/** When, epoch milliseconds. */
|
|
15
|
+
at: number;
|
|
16
|
+
/** What its operation cost, when settled. */
|
|
17
|
+
actual?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Reservations in process memory, beside the totals of the store that holds them: what
|
|
21
|
+
* `MemoryBudgetUsage` and `MemoryTenantUsage` keep them in. Each change and its total move together,
|
|
22
|
+
* since nothing runs between them on one thread.
|
|
23
|
+
*/
|
|
24
|
+
export declare class MemoryReservationBook {
|
|
25
|
+
private readonly add;
|
|
26
|
+
private readonly now;
|
|
27
|
+
private readonly records;
|
|
28
|
+
private prunedAt;
|
|
29
|
+
constructor(add: (key: string, amount: number, resetAt: number) => number, now: () => number);
|
|
30
|
+
/** Records a reservation and adds what it charges to its total. */
|
|
31
|
+
hold(record: BudgetReservationRecord): number;
|
|
32
|
+
/** Moves a reservation, and its total by what it charges differently, if it stands where `from` allows. */
|
|
33
|
+
settle(id: string, change: BudgetReservationChange): boolean;
|
|
34
|
+
/** Extends a reserved reservation's lease. */
|
|
35
|
+
renew(id: string, leasedUntil: number): boolean;
|
|
36
|
+
/** Reserved reservations whose lease lapsed by `now`, soonest lapsed first. */
|
|
37
|
+
lapsed(now: number, limit: number, operation?: string): BudgetReservationRecord[];
|
|
38
|
+
/** One reservation. */
|
|
39
|
+
get(id: string): BudgetReservationRecord | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Forgets what no report can change any more, at most once a minute: anything whose period has
|
|
42
|
+
* ended, and a settled, released, or expired reservation after an hour. An uncertain one is kept
|
|
43
|
+
* for its period, until its operation says what it cost.
|
|
44
|
+
*/
|
|
45
|
+
private prune;
|
|
46
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const SETTLED_RETENTION_MS = 60 * 60 * 1000;
|
|
2
|
+
export class MemoryReservationBook {
|
|
3
|
+
add;
|
|
4
|
+
now;
|
|
5
|
+
records = new Map();
|
|
6
|
+
prunedAt = 0;
|
|
7
|
+
constructor(add, now) {
|
|
8
|
+
this.add = add;
|
|
9
|
+
this.now = now;
|
|
10
|
+
}
|
|
11
|
+
hold(record) {
|
|
12
|
+
this.prune();
|
|
13
|
+
if (this.records.has(record.id))
|
|
14
|
+
throw new Error(`Budget reservation "${record.id}" already exists`);
|
|
15
|
+
this.records.set(record.id, { ...record });
|
|
16
|
+
return this.add(record.storeKey, record.charged, record.resetAt);
|
|
17
|
+
}
|
|
18
|
+
settle(id, change) {
|
|
19
|
+
const record = this.records.get(id);
|
|
20
|
+
if (!record || !change.from.includes(record.status))
|
|
21
|
+
return false;
|
|
22
|
+
const delta = change.charged - record.charged;
|
|
23
|
+
record.status = change.status;
|
|
24
|
+
record.charged = change.charged;
|
|
25
|
+
record.settledAt = change.at;
|
|
26
|
+
if (change.actual !== undefined)
|
|
27
|
+
record.actual = change.actual;
|
|
28
|
+
if (delta !== 0 && record.resetAt > change.at)
|
|
29
|
+
this.add(record.storeKey, delta, record.resetAt);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
renew(id, leasedUntil) {
|
|
33
|
+
const record = this.records.get(id);
|
|
34
|
+
if (record?.status !== 'reserved')
|
|
35
|
+
return false;
|
|
36
|
+
record.leasedUntil = leasedUntil;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
lapsed(now, limit, operation) {
|
|
40
|
+
const lapsed = [];
|
|
41
|
+
for (const record of this.records.values()) {
|
|
42
|
+
if (record.status !== 'reserved' || record.leasedUntil > now)
|
|
43
|
+
continue;
|
|
44
|
+
if (operation !== undefined && record.operation !== operation)
|
|
45
|
+
continue;
|
|
46
|
+
lapsed.push({ ...record });
|
|
47
|
+
}
|
|
48
|
+
return lapsed.sort((a, b) => a.leasedUntil - b.leasedUntil).slice(0, limit);
|
|
49
|
+
}
|
|
50
|
+
get(id) {
|
|
51
|
+
const record = this.records.get(id);
|
|
52
|
+
return record ? { ...record } : undefined;
|
|
53
|
+
}
|
|
54
|
+
prune() {
|
|
55
|
+
const now = this.now();
|
|
56
|
+
if (now - this.prunedAt < 60_000)
|
|
57
|
+
return;
|
|
58
|
+
this.prunedAt = now;
|
|
59
|
+
for (const [id, record] of this.records) {
|
|
60
|
+
if (record.status === 'reserved')
|
|
61
|
+
continue;
|
|
62
|
+
const settledLongAgo = record.status !== 'uncertain' && (record.settledAt ?? 0) + SETTLED_RETENTION_MS <= now;
|
|
63
|
+
if (record.resetAt <= now || settledLongAgo)
|
|
64
|
+
this.records.delete(id);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/media/rag.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { VectorStore } from '../hallucination/retrieval.js';
|
|
6
6
|
import type { AssetStore } from '../images/asset-support.js';
|
|
7
7
|
import type { EmbeddingRequest, EmbeddingResponse } from '../types/embeddings.js';
|
|
8
|
+
import type { Store } from '../types/store.js';
|
|
8
9
|
import { type MediaAnswer, type MediaInput, type MediaKind, type MediaManager } from './index.js';
|
|
9
10
|
/** Anything that embeds, such as an `EmbeddingManager` or a client's `embeddings`. */
|
|
10
11
|
export interface MediaEmbeddingSource {
|
|
@@ -64,11 +65,68 @@ export interface MediaIndexOptions {
|
|
|
64
65
|
};
|
|
65
66
|
/** The longest chunk of page text, in characters; a longer page is split at paragraphs. Defaults to 4,000. */
|
|
66
67
|
maxChunkChars?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Where the index remembers what it holds: any `Store`, so it lives in memory, Redis, Postgres, or
|
|
70
|
+
* SQLite. With one, `add()` skips a medium whose content and options are unchanged and replaces
|
|
71
|
+
* exactly the chunks of one that changed, and `delete()`, `reindex()`, `describe()`, and `list()`
|
|
72
|
+
* work by a medium's id. A store with an item limit must hold every medium.
|
|
73
|
+
*/
|
|
74
|
+
manifest?: Store;
|
|
75
|
+
/** Names the index. Its manifest is kept under this name, so two indexes never share one. Defaults to `media`. */
|
|
76
|
+
name?: string;
|
|
77
|
+
}
|
|
78
|
+
/** Who produced a medium's text or caption. */
|
|
79
|
+
export interface MediaIndexReader {
|
|
80
|
+
/** The provider that answered. */
|
|
81
|
+
provider: string;
|
|
82
|
+
/** The model it used. */
|
|
83
|
+
model: string;
|
|
84
|
+
}
|
|
85
|
+
/** What the manifest records for one medium. */
|
|
86
|
+
export interface MediaIndexEntry {
|
|
87
|
+
/** The medium's id. */
|
|
88
|
+
id: string;
|
|
89
|
+
/**
|
|
90
|
+
* A hash of the medium's content, source, metadata, and how it was indexed: the medium's version.
|
|
91
|
+
* Adding it again with the same hash writes nothing.
|
|
92
|
+
*/
|
|
93
|
+
hash: string;
|
|
94
|
+
/** Where it came from. */
|
|
95
|
+
source?: string;
|
|
96
|
+
/** Its metadata. */
|
|
97
|
+
metadata?: Record<string, string | number | boolean>;
|
|
98
|
+
/** Where the medium is kept: its URL, or its asset. */
|
|
99
|
+
reference: MediaReference;
|
|
100
|
+
/** The pages that were read. */
|
|
101
|
+
pages: number;
|
|
102
|
+
/** Every chunk's id in the vector store. */
|
|
103
|
+
chunkIds: string[];
|
|
104
|
+
/** The embedding model, when one was named. */
|
|
105
|
+
model?: string;
|
|
106
|
+
/** Who read its pages, when they were read. */
|
|
107
|
+
reader?: MediaIndexReader;
|
|
108
|
+
/** Who described it, when it was described. */
|
|
109
|
+
describer?: MediaIndexReader;
|
|
110
|
+
/** ISO-8601 time it was first indexed. */
|
|
111
|
+
createdAt: string;
|
|
112
|
+
/** ISO-8601 time it was last indexed. */
|
|
113
|
+
updatedAt: string;
|
|
114
|
+
/**
|
|
115
|
+
* A change that began and has not finished, as a crash leaves it: its version, its chunks, and the
|
|
116
|
+
* asset it stored. The next `add()`, `reindex()`, or `delete()` of the medium finishes or undoes it.
|
|
117
|
+
*/
|
|
118
|
+
pending?: {
|
|
119
|
+
hash: string;
|
|
120
|
+
chunkIds: string[];
|
|
121
|
+
assetId?: string;
|
|
122
|
+
};
|
|
67
123
|
}
|
|
68
124
|
/** What `add()` indexed. */
|
|
69
125
|
export interface MediaIndexReport {
|
|
70
126
|
/** Media indexed. */
|
|
71
127
|
media: number;
|
|
128
|
+
/** Media the manifest already held at the same version, which were not indexed again. */
|
|
129
|
+
unchanged: number;
|
|
72
130
|
/** Chunks of page text. */
|
|
73
131
|
pages: number;
|
|
74
132
|
/** Captions. */
|
|
@@ -106,8 +164,25 @@ export interface MediaSearchOptions {
|
|
|
106
164
|
}
|
|
107
165
|
/** An index of media in a vector store. */
|
|
108
166
|
export interface MediaIndex {
|
|
109
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* Reads, describes, and embeds each medium, and writes its chunks. Adding an id again replaces it;
|
|
169
|
+
* with a manifest, only when its content, source, metadata, or the index's options changed.
|
|
170
|
+
*/
|
|
110
171
|
add(documents: readonly MediaDocument[]): Promise<MediaIndexReport>;
|
|
172
|
+
/** Removes media by id: their chunks, their stored assets, and their manifest entries. Needs a manifest. */
|
|
173
|
+
delete(ids: readonly string[]): Promise<number>;
|
|
174
|
+
/**
|
|
175
|
+
* Indexes media again by id, from where the manifest says each is kept, even when unchanged: after a
|
|
176
|
+
* new embedding model or a better reader. Needs a manifest.
|
|
177
|
+
*/
|
|
178
|
+
reindex(ids: readonly string[]): Promise<MediaIndexReport>;
|
|
179
|
+
/** What the manifest records for a medium, or `undefined`. Needs a manifest. */
|
|
180
|
+
describe(id: string): Promise<MediaIndexEntry | undefined>;
|
|
181
|
+
/** The manifest's entries, newest first, a page at a time. Needs a manifest. */
|
|
182
|
+
list(options?: {
|
|
183
|
+
limit?: number;
|
|
184
|
+
offset?: number;
|
|
185
|
+
}): Promise<MediaIndexEntry[]>;
|
|
111
186
|
/** The media a question is about, each once, at its best chunk. */
|
|
112
187
|
search(query: string, options?: MediaSearchOptions): Promise<MediaHit[]>;
|
|
113
188
|
/** The medium behind a hit, to hand a model; `undefined` when its asset is gone. */
|