nexus-ai-pro 2.20.2 → 2.22.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 +93 -0
- package/CHANGELOG.md +208 -1
- package/README.md +11 -6
- package/SECURITY.md +16 -2
- package/dist/adapter-kit/gather.d.ts +76 -0
- package/dist/adapter-kit/gather.js +147 -0
- package/dist/adapter-kit/index.d.ts +1 -0
- package/dist/adapter-kit/index.js +1 -0
- package/dist/adapter-kit/record.d.ts +3 -1
- package/dist/adapter-kit/record.js +20 -5
- package/dist/agent/openapi.d.ts +94 -8
- package/dist/agent/openapi.js +528 -32
- package/dist/cli/adapters.d.ts +4 -3
- package/dist/cli/adapters.js +71 -2
- package/dist/cli/doctor.js +3 -0
- package/dist/cli.js +3 -1
- package/dist/core/config-builder.d.ts +1 -0
- package/dist/core/config-builder.js +1 -0
- package/dist/core/defaults.d.ts +34 -0
- package/dist/core/defaults.js +39 -0
- package/dist/core/secure-stream.js +4 -1
- package/dist/decisions/completion.d.ts +10 -7
- package/dist/decisions/completion.js +82 -8
- package/dist/decisions/core.d.ts +88 -43
- package/dist/decisions/core.js +115 -28
- package/dist/decisions/errors.d.ts +25 -0
- package/dist/decisions/errors.js +12 -0
- package/dist/decisions/index.d.ts +6 -5
- package/dist/decisions/index.js +2 -1
- package/dist/decisions/integrations.d.ts +14 -5
- package/dist/decisions/integrations.js +16 -1
- package/dist/decisions/mock.d.ts +5 -3
- package/dist/decisions/mock.js +4 -1
- package/dist/decisions/pictures.d.ts +43 -0
- package/dist/decisions/pictures.js +103 -0
- package/dist/decisions/typesafe.d.ts +33 -5
- package/dist/decisions/typesafe.js +121 -8
- package/dist/doctor/index.d.ts +6 -9
- package/dist/doctor/index.js +41 -0
- package/dist/embeddings/adapters.d.ts +1 -1
- package/dist/embeddings/adapters.js +3 -3
- package/dist/embeddings/batch-google.d.ts +27 -8
- package/dist/embeddings/batch-google.js +112 -36
- package/dist/embeddings/batch-mock.js +1 -1
- package/dist/embeddings/batch.js +10 -4
- package/dist/embeddings/engine.js +14 -13
- package/dist/embeddings/index.d.ts +1 -1
- package/dist/embeddings/inputs.d.ts +26 -3
- package/dist/embeddings/inputs.js +84 -5
- package/dist/embeddings/mock.js +1 -1
- package/dist/embeddings/models.js +39 -4
- package/dist/loaders/csv.d.ts +23 -1
- package/dist/loaders/csv.js +125 -72
- package/dist/loaders/index.d.ts +7 -2
- package/dist/loaders/input.d.ts +6 -0
- package/dist/loaders/input.js +42 -1
- package/dist/loaders/json.d.ts +14 -3
- package/dist/loaders/json.js +171 -20
- package/dist/loaders/web.d.ts +55 -0
- package/dist/loaders/web.js +20 -1
- package/dist/mcp/client.d.ts +54 -5
- package/dist/mcp/client.js +171 -20
- package/dist/mcp/http.d.ts +45 -0
- package/dist/mcp/http.js +233 -0
- package/dist/mcp/index.d.ts +4 -2
- package/dist/mcp/index.js +3 -1
- package/dist/mcp/protocol.d.ts +107 -0
- package/dist/mcp/sampling.d.ts +41 -0
- package/dist/mcp/sampling.js +52 -0
- package/dist/mcp/server.d.ts +96 -14
- package/dist/mcp/server.js +274 -59
- package/dist/models/data.js +20 -1
- package/dist/operations/adapters.d.ts +1 -0
- package/dist/operations/adapters.js +3 -1
- package/dist/protocols/a2a-grpc.js +10 -3
- package/dist/protocols/a2a-signing.d.ts +65 -0
- package/dist/protocols/a2a-signing.js +133 -0
- package/dist/protocols/a2a.d.ts +14 -0
- package/dist/protocols/a2a.js +60 -5
- package/dist/providers/cohere.js +16 -2
- package/dist/providers/google.js +7 -1
- package/dist/providers/ollama.d.ts +1 -1
- package/dist/providers/ollama.js +35 -27
- package/dist/providers/openai.js +19 -2
- package/dist/rag/pinecone.d.ts +63 -2
- package/dist/rag/pinecone.js +80 -0
- package/dist/realtime/conversation.js +18 -0
- package/dist/realtime/gemini-live.transport.d.ts +28 -3
- package/dist/realtime/gemini-live.transport.js +170 -32
- package/dist/realtime/session.d.ts +2 -0
- package/dist/realtime/session.js +19 -4
- package/dist/realtime/types.d.ts +35 -3
- package/dist/security/output-guard.js +4 -1
- package/dist/server/auth.d.ts +263 -2
- package/dist/server/auth.js +432 -5
- package/dist/server/deployments.d.ts +3 -2
- package/dist/server/deployments.js +6 -1
- package/dist/telephony/index.d.ts +1 -1
- package/dist/telephony/manager.d.ts +8 -1
- package/dist/telephony/manager.js +13 -0
- package/dist/telephony/providers/telnyx.d.ts +18 -5
- package/dist/telephony/providers/telnyx.js +44 -7
- package/dist/telephony/providers/twilio.d.ts +3 -1
- package/dist/telephony/providers/twilio.js +16 -0
- package/dist/tracing/stores.d.ts +2 -0
- package/dist/tracing/stores.js +1 -0
- package/dist/tracing/tracer.d.ts +5 -2
- package/dist/tracing/tracer.js +6 -3
- package/dist/types/embeddings.d.ts +47 -5
- package/dist/types/messages.d.ts +7 -0
- package/dist/types/principal.d.ts +1 -1
- package/dist/types/response.d.ts +5 -0
- package/dist/types/telephony.d.ts +38 -0
- package/dist/types/tracing.d.ts +6 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/voice/providers/google.d.ts +44 -0
- package/dist/voice/providers/google.js +215 -0
- package/dist-cjs/adapter-kit/gather.d.ts +76 -0
- package/dist-cjs/adapter-kit/gather.js +152 -0
- package/dist-cjs/adapter-kit/index.d.ts +1 -0
- package/dist-cjs/adapter-kit/index.js +4 -1
- package/dist-cjs/adapter-kit/record.d.ts +3 -1
- package/dist-cjs/adapter-kit/record.js +20 -5
- package/dist-cjs/agent/openapi.d.ts +94 -8
- package/dist-cjs/agent/openapi.js +530 -32
- package/dist-cjs/cli/adapters.d.ts +4 -3
- package/dist-cjs/cli/adapters.js +70 -1
- package/dist-cjs/cli/doctor.js +3 -0
- package/dist-cjs/core/config-builder.d.ts +1 -0
- package/dist-cjs/core/config-builder.js +5 -1
- package/dist-cjs/core/defaults.d.ts +34 -0
- package/dist-cjs/core/defaults.js +44 -0
- package/dist-cjs/core/secure-stream.js +4 -1
- package/dist-cjs/decisions/completion.d.ts +10 -7
- package/dist-cjs/decisions/completion.js +81 -7
- package/dist-cjs/decisions/core.d.ts +88 -43
- package/dist-cjs/decisions/core.js +134 -46
- package/dist-cjs/decisions/errors.d.ts +25 -0
- package/dist-cjs/decisions/errors.js +16 -0
- package/dist-cjs/decisions/index.d.ts +6 -5
- package/dist-cjs/decisions/index.js +5 -1
- package/dist-cjs/decisions/integrations.d.ts +14 -5
- package/dist-cjs/decisions/integrations.js +16 -1
- package/dist-cjs/decisions/mock.d.ts +5 -3
- package/dist-cjs/decisions/mock.js +4 -1
- package/dist-cjs/decisions/pictures.d.ts +43 -0
- package/dist-cjs/decisions/pictures.js +109 -0
- package/dist-cjs/decisions/typesafe.d.ts +33 -5
- package/dist-cjs/decisions/typesafe.js +126 -13
- package/dist-cjs/doctor/index.d.ts +6 -9
- package/dist-cjs/doctor/index.js +41 -0
- package/dist-cjs/embeddings/adapters.d.ts +1 -1
- package/dist-cjs/embeddings/adapters.js +3 -3
- package/dist-cjs/embeddings/batch-google.d.ts +27 -8
- package/dist-cjs/embeddings/batch-google.js +112 -36
- package/dist-cjs/embeddings/batch-mock.js +1 -1
- package/dist-cjs/embeddings/batch.js +9 -3
- package/dist-cjs/embeddings/engine.js +13 -12
- package/dist-cjs/embeddings/index.d.ts +1 -1
- package/dist-cjs/embeddings/inputs.d.ts +26 -3
- package/dist-cjs/embeddings/inputs.js +89 -5
- package/dist-cjs/embeddings/mock.js +1 -1
- package/dist-cjs/embeddings/models.js +39 -4
- package/dist-cjs/loaders/csv.d.ts +23 -1
- package/dist-cjs/loaders/csv.js +126 -71
- package/dist-cjs/loaders/index.d.ts +7 -2
- package/dist-cjs/loaders/input.d.ts +6 -0
- package/dist-cjs/loaders/input.js +43 -1
- package/dist-cjs/loaders/json.d.ts +14 -3
- package/dist-cjs/loaders/json.js +170 -19
- package/dist-cjs/loaders/web.d.ts +55 -0
- package/dist-cjs/loaders/web.js +21 -1
- package/dist-cjs/mcp/client.d.ts +54 -5
- package/dist-cjs/mcp/client.js +171 -20
- package/dist-cjs/mcp/http.d.ts +45 -0
- package/dist-cjs/mcp/http.js +236 -0
- package/dist-cjs/mcp/index.d.ts +4 -2
- package/dist-cjs/mcp/index.js +5 -1
- package/dist-cjs/mcp/protocol.d.ts +107 -0
- package/dist-cjs/mcp/sampling.d.ts +41 -0
- package/dist-cjs/mcp/sampling.js +55 -0
- package/dist-cjs/mcp/server.d.ts +96 -14
- package/dist-cjs/mcp/server.js +273 -58
- package/dist-cjs/models/data.js +20 -1
- package/dist-cjs/operations/adapters.d.ts +1 -0
- package/dist-cjs/operations/adapters.js +3 -1
- package/dist-cjs/protocols/a2a-grpc.js +10 -3
- package/dist-cjs/protocols/a2a-signing.d.ts +65 -0
- package/dist-cjs/protocols/a2a-signing.js +140 -0
- package/dist-cjs/protocols/a2a.d.ts +14 -0
- package/dist-cjs/protocols/a2a.js +65 -6
- package/dist-cjs/providers/cohere.js +16 -2
- package/dist-cjs/providers/google.js +7 -1
- package/dist-cjs/providers/ollama.d.ts +1 -1
- package/dist-cjs/providers/ollama.js +35 -27
- package/dist-cjs/providers/openai.js +19 -2
- package/dist-cjs/rag/pinecone.d.ts +63 -2
- package/dist-cjs/rag/pinecone.js +81 -0
- package/dist-cjs/realtime/conversation.js +18 -0
- package/dist-cjs/realtime/gemini-live.transport.d.ts +28 -3
- package/dist-cjs/realtime/gemini-live.transport.js +170 -32
- package/dist-cjs/realtime/session.d.ts +2 -0
- package/dist-cjs/realtime/session.js +19 -4
- package/dist-cjs/realtime/types.d.ts +35 -3
- package/dist-cjs/security/output-guard.js +4 -1
- package/dist-cjs/server/auth.d.ts +263 -2
- package/dist-cjs/server/auth.js +437 -5
- package/dist-cjs/server/deployments.d.ts +3 -2
- package/dist-cjs/server/deployments.js +6 -1
- package/dist-cjs/telephony/index.d.ts +1 -1
- package/dist-cjs/telephony/manager.d.ts +8 -1
- package/dist-cjs/telephony/manager.js +13 -0
- package/dist-cjs/telephony/providers/telnyx.d.ts +18 -5
- package/dist-cjs/telephony/providers/telnyx.js +44 -7
- package/dist-cjs/telephony/providers/twilio.d.ts +3 -1
- package/dist-cjs/telephony/providers/twilio.js +16 -0
- package/dist-cjs/tracing/stores.d.ts +2 -0
- package/dist-cjs/tracing/stores.js +1 -0
- package/dist-cjs/tracing/tracer.d.ts +5 -2
- package/dist-cjs/tracing/tracer.js +6 -3
- package/dist-cjs/types/embeddings.d.ts +47 -5
- package/dist-cjs/types/messages.d.ts +7 -0
- package/dist-cjs/types/principal.d.ts +1 -1
- package/dist-cjs/types/response.d.ts +5 -0
- package/dist-cjs/types/telephony.d.ts +38 -0
- package/dist-cjs/types/tracing.d.ts +6 -0
- package/dist-cjs/version.d.ts +1 -1
- package/dist-cjs/version.js +1 -1
- package/dist-cjs/voice/providers/google.d.ts +44 -0
- package/dist-cjs/voice/providers/google.js +252 -0
- package/llms.txt +1 -1
- package/package.json +17 -1
|
@@ -60,13 +60,18 @@ export const KNOWN_EMBEDDING_MODELS = {
|
|
|
60
60
|
maxBatchSize: 100,
|
|
61
61
|
costPer1kInput: 0.0002,
|
|
62
62
|
costPerImage: 0.00012,
|
|
63
|
+
costPerAudioSecond: 0.00016,
|
|
64
|
+
costPerVideoFrame: 0.00079,
|
|
65
|
+
videoFrames: { perSecond: 1, max: 32 },
|
|
66
|
+
maxAudioSeconds: 180,
|
|
67
|
+
maxVideoSeconds: 120,
|
|
63
68
|
normalized: true,
|
|
64
69
|
inputTypes: ['document', 'query', 'classification', 'clustering'],
|
|
65
|
-
inputModalities: ['text', 'image', 'audio', 'document'],
|
|
70
|
+
inputModalities: ['text', 'image', 'audio', 'video', 'document'],
|
|
66
71
|
status: 'stable',
|
|
67
|
-
verifiedAt: '2026-10-
|
|
68
|
-
source: 'https://ai.google.dev/gemini-api/docs/
|
|
69
|
-
notes: 'One vector for text, images (up to 6), audio (up to 180 s), and a PDF (up to 6 pages) together. Reads its task from a text prefix, not a task type. Audio
|
|
72
|
+
verifiedAt: '2026-10-28',
|
|
73
|
+
source: 'https://ai.google.dev/gemini-api/docs/pricing',
|
|
74
|
+
notes: 'One vector for text, images (up to 6, PNG or JPEG), audio (up to 180 s, MP3 or WAV), video (up to 120 s, MP4 or MOV, its sound not heard), and a PDF (up to 6 pages) together. Reads its task from a text prefix, not a task type. Audio is billed by the second, video by the frame it takes: one a second, at most 32.',
|
|
70
75
|
}),
|
|
71
76
|
'text-embedding-004': embeddingModel({
|
|
72
77
|
provider: 'google',
|
|
@@ -93,6 +98,36 @@ export const KNOWN_EMBEDDING_MODELS = {
|
|
|
93
98
|
status: 'stable',
|
|
94
99
|
notes: 'Takes images, and text with images, as data URIs: JPEG, PNG, WebP, or GIF, 20 MB a request in total.',
|
|
95
100
|
}),
|
|
101
|
+
'embed-v5.0-pro': embeddingModel({
|
|
102
|
+
provider: 'cohere',
|
|
103
|
+
family: 'embed-v5',
|
|
104
|
+
dimensions: 2048,
|
|
105
|
+
supportedDimensions: [256, 512, 768, 1024, 1536, 2048],
|
|
106
|
+
maxInputTokens: 128000,
|
|
107
|
+
maxBatchSize: 96,
|
|
108
|
+
costPer1kInput: 0,
|
|
109
|
+
inputTypes: ['document', 'query', 'classification', 'clustering'],
|
|
110
|
+
inputModalities: ['text', 'image'],
|
|
111
|
+
status: 'stable',
|
|
112
|
+
verifiedAt: '2026-10-29',
|
|
113
|
+
source: 'https://docs.cohere.com/docs/cohere-embed',
|
|
114
|
+
notes: 'The quality model, for indexing. Shares one vector space with embed-v5.0-fast, so a corpus indexed with Pro is searched with Fast. Cohere publishes no per-token price for it, so its cost reads as zero: give one through embeddings.models.registry.',
|
|
115
|
+
}),
|
|
116
|
+
'embed-v5.0-fast': embeddingModel({
|
|
117
|
+
provider: 'cohere',
|
|
118
|
+
family: 'embed-v5',
|
|
119
|
+
dimensions: 2048,
|
|
120
|
+
supportedDimensions: [256, 512, 768, 1024, 1536, 2048],
|
|
121
|
+
maxInputTokens: 128000,
|
|
122
|
+
maxBatchSize: 96,
|
|
123
|
+
costPer1kInput: 0,
|
|
124
|
+
inputTypes: ['document', 'query', 'classification', 'clustering'],
|
|
125
|
+
inputModalities: ['text', 'image'],
|
|
126
|
+
status: 'stable',
|
|
127
|
+
verifiedAt: '2026-10-29',
|
|
128
|
+
source: 'https://docs.cohere.com/docs/cohere-embed',
|
|
129
|
+
notes: 'The fast model, for queries and agent loops. Shares one vector space with embed-v5.0-pro, so a corpus indexed with Pro is searched with Fast. Cohere publishes no per-token price for it, so its cost reads as zero: give one through embeddings.models.registry.',
|
|
130
|
+
}),
|
|
96
131
|
'embed-english-v3.0': embeddingModel({
|
|
97
132
|
provider: 'cohere',
|
|
98
133
|
family: 'embed-v3',
|
package/dist/loaders/csv.d.ts
CHANGED
|
@@ -5,6 +5,27 @@ export interface CsvParseOptions {
|
|
|
5
5
|
/** The field separator. Defaults to a comma; use `'\t'` for TSV. */
|
|
6
6
|
delimiter?: string;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* CSV parsed as it arrives: `push()` takes the next piece of text, of any length, and returns the rows
|
|
10
|
+
* it completed; `end()` returns the last. A quote, or a CRLF, split between two pieces is read as one.
|
|
11
|
+
* `parseCsv()` is this, given the whole text at once.
|
|
12
|
+
*/
|
|
13
|
+
export declare class CsvRowParser {
|
|
14
|
+
private readonly delimiter;
|
|
15
|
+
private row;
|
|
16
|
+
private field;
|
|
17
|
+
private quoted;
|
|
18
|
+
/** A quote inside a quoted field, waiting for the next character: a second quote, or the field's end. */
|
|
19
|
+
private quote;
|
|
20
|
+
/** A carriage return that ended a row, whose line feed, if one follows, belongs to it. */
|
|
21
|
+
private carriage;
|
|
22
|
+
private started;
|
|
23
|
+
constructor(options?: CsvParseOptions);
|
|
24
|
+
/** Reads the next piece of text, and returns the rows it completed. */
|
|
25
|
+
push(text: string): string[][];
|
|
26
|
+
/** Ends the text, and returns its last row, unless it ended with a line break. */
|
|
27
|
+
end(): string[][];
|
|
28
|
+
}
|
|
8
29
|
/**
|
|
9
30
|
* Parses CSV into rows of fields, following RFC 4180: quoted fields may hold the delimiter, line
|
|
10
31
|
* breaks, and doubled quotes; lines may end in CRLF or LF; and a trailing line break adds no row.
|
|
@@ -24,6 +45,7 @@ export interface CsvLoaderOptions extends FileLoaderOptions, CsvParseOptions {
|
|
|
24
45
|
}
|
|
25
46
|
/**
|
|
26
47
|
* CSV files, one document per row. The first row names the columns. Each row's text lists its columns
|
|
27
|
-
* by name, so a model reading a chunk knows what each value is.
|
|
48
|
+
* by name, so a model reading a chunk knows what each value is. Rows are read as the file arrives, so
|
|
49
|
+
* a file larger than memory streams through.
|
|
28
50
|
*/
|
|
29
51
|
export declare function loadCsv(inputs: FileInput | Iterable<FileInput>, options?: CsvLoaderOptions): AsyncGenerator<DocumentSource>;
|
package/dist/loaders/csv.js
CHANGED
|
@@ -1,87 +1,140 @@
|
|
|
1
|
-
import { inputsOf,
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { inputsOf, sourceOf, textChunks } from './input.js';
|
|
2
|
+
export class CsvRowParser {
|
|
3
|
+
delimiter;
|
|
4
|
+
row = [];
|
|
5
|
+
field = '';
|
|
6
|
+
quoted = false;
|
|
7
|
+
quote = false;
|
|
8
|
+
carriage = false;
|
|
9
|
+
started = false;
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
const delimiter = options.delimiter ?? ',';
|
|
12
|
+
if (delimiter.length !== 1 || delimiter === '"' || delimiter === '\n' || delimiter === '\r') {
|
|
13
|
+
throw new RangeError('delimiter must be one character other than a quote or a line break');
|
|
14
|
+
}
|
|
15
|
+
this.delimiter = delimiter;
|
|
6
16
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
push(text) {
|
|
18
|
+
const rows = [];
|
|
19
|
+
let index = 0;
|
|
20
|
+
if (!this.started && text.length > 0) {
|
|
21
|
+
this.started = true;
|
|
22
|
+
if (text.charCodeAt(0) === 0xfeff)
|
|
23
|
+
index = 1;
|
|
24
|
+
}
|
|
25
|
+
for (; index < text.length; index++) {
|
|
26
|
+
const char = text[index];
|
|
27
|
+
if (this.carriage) {
|
|
28
|
+
this.carriage = false;
|
|
29
|
+
if (char === '\n')
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (this.quote) {
|
|
33
|
+
this.quote = false;
|
|
34
|
+
if (char === '"') {
|
|
35
|
+
this.field += '"';
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
this.quoted = false;
|
|
39
|
+
}
|
|
40
|
+
if (this.quoted) {
|
|
41
|
+
if (char === '"')
|
|
42
|
+
this.quote = true;
|
|
43
|
+
else
|
|
44
|
+
this.field += char;
|
|
45
|
+
}
|
|
46
|
+
else if (char === '"' && this.field === '')
|
|
47
|
+
this.quoted = true;
|
|
48
|
+
else if (char === this.delimiter) {
|
|
49
|
+
this.row.push(this.field);
|
|
50
|
+
this.field = '';
|
|
51
|
+
}
|
|
52
|
+
else if (char === '\n' || char === '\r') {
|
|
53
|
+
this.carriage = char === '\r';
|
|
54
|
+
this.row.push(this.field);
|
|
55
|
+
rows.push(this.row);
|
|
56
|
+
this.row = [];
|
|
57
|
+
this.field = '';
|
|
20
58
|
}
|
|
21
59
|
else
|
|
22
|
-
|
|
60
|
+
this.field += char;
|
|
23
61
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
62
|
+
return rows;
|
|
63
|
+
}
|
|
64
|
+
end() {
|
|
65
|
+
if (this.quote) {
|
|
66
|
+
this.quote = false;
|
|
67
|
+
this.quoted = false;
|
|
29
68
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
row
|
|
36
|
-
field = '';
|
|
69
|
+
if (this.quoted)
|
|
70
|
+
throw new SyntaxError('The CSV ends inside a quoted field');
|
|
71
|
+
const rows = [];
|
|
72
|
+
if (this.field !== '' || this.row.length > 0) {
|
|
73
|
+
this.row.push(this.field);
|
|
74
|
+
rows.push(this.row);
|
|
37
75
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (quoted)
|
|
42
|
-
throw new SyntaxError('The CSV ends inside a quoted field');
|
|
43
|
-
if (field !== '' || row.length > 0) {
|
|
44
|
-
row.push(field);
|
|
45
|
-
rows.push(row);
|
|
76
|
+
this.row = [];
|
|
77
|
+
this.field = '';
|
|
78
|
+
return rows;
|
|
46
79
|
}
|
|
47
|
-
|
|
80
|
+
}
|
|
81
|
+
export function parseCsv(text, options = {}) {
|
|
82
|
+
const parser = new CsvRowParser(options);
|
|
83
|
+
return [...parser.push(text), ...parser.end()];
|
|
48
84
|
}
|
|
49
85
|
export async function* loadCsv(inputs, options = {}) {
|
|
50
86
|
for (const input of inputsOf(inputs)) {
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
throw new RangeError(`${source} has no column "${name}"`);
|
|
59
|
-
return index;
|
|
87
|
+
const source = sourceOf(input);
|
|
88
|
+
const parser = new CsvRowParser(options);
|
|
89
|
+
let reader;
|
|
90
|
+
const rows = async function* () {
|
|
91
|
+
for await (const chunk of textChunks(input))
|
|
92
|
+
yield* parser.push(chunk);
|
|
93
|
+
yield* parser.end();
|
|
60
94
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
? options.textColumns.map(column)
|
|
65
|
-
: header
|
|
66
|
-
.map((_, index) => index)
|
|
67
|
-
.filter((index) => index !== idIndex && !metadataIndexes.some(([, metadata]) => metadata === index));
|
|
68
|
-
for (const [rowIndex, fields] of rows.entries()) {
|
|
69
|
-
if (fields.length === 1 && fields[0] === '')
|
|
95
|
+
for await (const fields of rows()) {
|
|
96
|
+
if (!reader) {
|
|
97
|
+
reader = rowReader(source, fields, options);
|
|
70
98
|
continue;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
.map((index) => `${header[index]}: ${fields[index] ?? ''}`)
|
|
76
|
-
.filter((line) => !line.endsWith(': '))
|
|
77
|
-
.join('\n'),
|
|
78
|
-
source,
|
|
79
|
-
metadata: {
|
|
80
|
-
...options.metadata,
|
|
81
|
-
...Object.fromEntries(metadataIndexes.map(([name, index]) => [name, fields[index] ?? ''])),
|
|
82
|
-
row: rowIndex + 1,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
99
|
+
}
|
|
100
|
+
const document = reader(fields);
|
|
101
|
+
if (document)
|
|
102
|
+
yield document;
|
|
85
103
|
}
|
|
86
104
|
}
|
|
87
105
|
}
|
|
106
|
+
function rowReader(source, header, options) {
|
|
107
|
+
const column = (name) => {
|
|
108
|
+
const index = header.indexOf(name);
|
|
109
|
+
if (index < 0)
|
|
110
|
+
throw new RangeError(`${source} has no column "${name}"`);
|
|
111
|
+
return index;
|
|
112
|
+
};
|
|
113
|
+
const idIndex = options.idColumn === undefined ? -1 : column(options.idColumn);
|
|
114
|
+
const metadataIndexes = (options.metadataColumns ?? []).map((name) => [name, column(name)]);
|
|
115
|
+
const textIndexes = options.textColumns
|
|
116
|
+
? options.textColumns.map(column)
|
|
117
|
+
: header
|
|
118
|
+
.map((_, index) => index)
|
|
119
|
+
.filter((index) => index !== idIndex && !metadataIndexes.some(([, metadata]) => metadata === index));
|
|
120
|
+
let rowIndex = 0;
|
|
121
|
+
return (fields) => {
|
|
122
|
+
rowIndex += 1;
|
|
123
|
+
if (fields.length === 1 && fields[0] === '')
|
|
124
|
+
return undefined;
|
|
125
|
+
const key = idIndex >= 0 ? fields[idIndex] : String(rowIndex);
|
|
126
|
+
return {
|
|
127
|
+
id: `${source}#${key}`,
|
|
128
|
+
text: textIndexes
|
|
129
|
+
.map((index) => `${header[index]}: ${fields[index] ?? ''}`)
|
|
130
|
+
.filter((line) => !line.endsWith(': '))
|
|
131
|
+
.join('\n'),
|
|
132
|
+
source,
|
|
133
|
+
metadata: {
|
|
134
|
+
...options.metadata,
|
|
135
|
+
...Object.fromEntries(metadataIndexes.map(([name, index]) => [name, fields[index] ?? ''])),
|
|
136
|
+
row: rowIndex,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
}
|
package/dist/loaders/index.d.ts
CHANGED
|
@@ -7,12 +7,17 @@ export type { DocumentSource } from '../rag/ingestion.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export type DocumentLoader = AsyncIterable<DocumentSource> | Iterable<DocumentSource>;
|
|
9
9
|
/**
|
|
10
|
-
* A file to load: a path, a `file:` URL,
|
|
11
|
-
*
|
|
10
|
+
* A file to load: a path, a `file:` URL, content already in memory with a name for it, or a stream of
|
|
11
|
+
* it, such as a response's body or an object store's download. In-memory content is how a loader reads
|
|
12
|
+
* an upload, a database blob, or a file on a runtime without a disk; a stream, how the CSV and JSON
|
|
13
|
+
* loaders read a file larger than memory, as it arrives.
|
|
12
14
|
*/
|
|
13
15
|
export type FileInput = string | URL | {
|
|
14
16
|
source: string;
|
|
15
17
|
content: string | Uint8Array;
|
|
18
|
+
} | {
|
|
19
|
+
source: string;
|
|
20
|
+
stream: AsyncIterable<Uint8Array | string> | Iterable<Uint8Array | string>;
|
|
16
21
|
};
|
|
17
22
|
/** Reads every document from one or more loaders, in order, into an array. */
|
|
18
23
|
export declare function collectDocuments(...loaders: DocumentLoader[]): Promise<DocumentSource[]>;
|
package/dist/loaders/input.d.ts
CHANGED
|
@@ -18,3 +18,9 @@ export declare function readText(input: FileInput): Promise<{
|
|
|
18
18
|
source: string;
|
|
19
19
|
text: string;
|
|
20
20
|
}>;
|
|
21
|
+
/**
|
|
22
|
+
* An input's text a piece at a time, so a large file is never held whole: a path or file URL read from
|
|
23
|
+
* disk in chunks of 64 KiB, a stream as it arrives, and content in memory as it is. A character split
|
|
24
|
+
* between two chunks is decoded whole, and a byte-order mark is dropped.
|
|
25
|
+
*/
|
|
26
|
+
export declare function textChunks(input: FileInput): AsyncGenerator<string>;
|
package/dist/loaders/input.js
CHANGED
|
@@ -14,6 +14,19 @@ export function sourceOf(input) {
|
|
|
14
14
|
}
|
|
15
15
|
export async function readInput(input) {
|
|
16
16
|
if (typeof input === 'object' && !(input instanceof URL)) {
|
|
17
|
+
if ('stream' in input) {
|
|
18
|
+
const pieces = [];
|
|
19
|
+
for await (const piece of input.stream) {
|
|
20
|
+
pieces.push(typeof piece === 'string' ? new TextEncoder().encode(piece) : piece);
|
|
21
|
+
}
|
|
22
|
+
const bytes = new Uint8Array(pieces.reduce((total, piece) => total + piece.byteLength, 0));
|
|
23
|
+
let offset = 0;
|
|
24
|
+
for (const piece of pieces) {
|
|
25
|
+
bytes.set(piece, offset);
|
|
26
|
+
offset += piece.byteLength;
|
|
27
|
+
}
|
|
28
|
+
return { source: input.source, bytes };
|
|
29
|
+
}
|
|
17
30
|
const bytes = typeof input.content === 'string' ? new TextEncoder().encode(input.content) : input.content;
|
|
18
31
|
return { source: input.source, bytes };
|
|
19
32
|
}
|
|
@@ -21,12 +34,40 @@ export async function readInput(input) {
|
|
|
21
34
|
return { source: sourceOf(input), bytes: new Uint8Array(await readFile(input)) };
|
|
22
35
|
}
|
|
23
36
|
export async function readText(input) {
|
|
24
|
-
if (typeof input === 'object' && !(input instanceof URL) && typeof input.content === 'string') {
|
|
37
|
+
if (typeof input === 'object' && !(input instanceof URL) && 'content' in input && typeof input.content === 'string') {
|
|
25
38
|
return { source: input.source, text: stripBom(input.content) };
|
|
26
39
|
}
|
|
27
40
|
const { source, bytes } = await readInput(input);
|
|
28
41
|
return { source, text: stripBom(new TextDecoder().decode(bytes)) };
|
|
29
42
|
}
|
|
43
|
+
export async function* textChunks(input) {
|
|
44
|
+
const decoder = new TextDecoder();
|
|
45
|
+
let first = true;
|
|
46
|
+
for await (const piece of piecesOf(input)) {
|
|
47
|
+
let text = typeof piece === 'string' ? piece : decoder.decode(piece, { stream: true });
|
|
48
|
+
if (first && text) {
|
|
49
|
+
first = false;
|
|
50
|
+
text = stripBom(text);
|
|
51
|
+
}
|
|
52
|
+
if (text)
|
|
53
|
+
yield text;
|
|
54
|
+
}
|
|
55
|
+
const rest = decoder.decode();
|
|
56
|
+
if (rest)
|
|
57
|
+
yield rest;
|
|
58
|
+
}
|
|
59
|
+
async function* piecesOf(input) {
|
|
60
|
+
if (typeof input === 'object' && !(input instanceof URL)) {
|
|
61
|
+
if ('stream' in input)
|
|
62
|
+
yield* input.stream;
|
|
63
|
+
else
|
|
64
|
+
yield input.content;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const { createReadStream } = await import('node:fs');
|
|
68
|
+
for await (const chunk of createReadStream(input, { highWaterMark: 64 * 1024 }))
|
|
69
|
+
yield chunk;
|
|
70
|
+
}
|
|
30
71
|
function stripBom(text) {
|
|
31
72
|
return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
|
|
32
73
|
}
|
package/dist/loaders/json.d.ts
CHANGED
|
@@ -3,10 +3,17 @@ import type { FileLoaderOptions } from './text.js';
|
|
|
3
3
|
/** Options for `loadJson()`. */
|
|
4
4
|
export interface JsonLoaderOptions extends FileLoaderOptions {
|
|
5
5
|
/**
|
|
6
|
-
* Picks the records out of the parsed file. Defaults to the items of
|
|
7
|
-
* value itself as
|
|
6
|
+
* Picks the records out of the parsed file, which is then read whole. Defaults to the items of the
|
|
7
|
+
* array at `recordsAt`, or of a top-level array, read as the file arrives; or else the value itself as
|
|
8
|
+
* one record.
|
|
8
9
|
*/
|
|
9
10
|
records?: (value: unknown) => Iterable<unknown>;
|
|
11
|
+
/**
|
|
12
|
+
* Where the array of records is: object keys from the top, dotted, such as `data.items`. Its items
|
|
13
|
+
* are read one at a time as the file arrives, so a file larger than memory streams through. A file
|
|
14
|
+
* with no array there is refused.
|
|
15
|
+
*/
|
|
16
|
+
recordsAt?: string;
|
|
10
17
|
/**
|
|
11
18
|
* A record's text: a field, by dotted path such as `body.text`, or a function. Defaults to a string
|
|
12
19
|
* record itself, or else the record as indented JSON.
|
|
@@ -22,5 +29,9 @@ export interface JsonLoaderOptions extends FileLoaderOptions {
|
|
|
22
29
|
*/
|
|
23
30
|
lines?: boolean;
|
|
24
31
|
}
|
|
25
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* JSON and JSON Lines files, one document per record. A JSON Lines file, and the array of records in a
|
|
34
|
+
* JSON one, are read as the file arrives, a record at a time, so a file larger than memory streams
|
|
35
|
+
* through; a `records` function reads the file whole.
|
|
36
|
+
*/
|
|
26
37
|
export declare function loadJson(inputs: FileInput | Iterable<FileInput>, options?: JsonLoaderOptions): AsyncGenerator<DocumentSource>;
|
package/dist/loaders/json.js
CHANGED
|
@@ -1,28 +1,15 @@
|
|
|
1
|
-
import { inputsOf, readText } from './input.js';
|
|
1
|
+
import { inputsOf, readText, sourceOf, textChunks } from './input.js';
|
|
2
2
|
export async function* loadJson(inputs, options = {}) {
|
|
3
3
|
for (const input of inputsOf(inputs)) {
|
|
4
|
-
const
|
|
4
|
+
const source = sourceOf(input);
|
|
5
5
|
const lines = options.lines ?? /\.(jsonl|ndjson)$/i.test(source);
|
|
6
|
-
const parsed = lines
|
|
7
|
-
? text
|
|
8
|
-
.split(/\r?\n/)
|
|
9
|
-
.filter((line) => line.trim())
|
|
10
|
-
.map((line, index) => {
|
|
11
|
-
try {
|
|
12
|
-
return JSON.parse(line);
|
|
13
|
-
}
|
|
14
|
-
catch (error) {
|
|
15
|
-
throw new SyntaxError(`${source} line ${index + 1}: ${error.message}`);
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
: JSON.parse(text);
|
|
19
|
-
const records = options.records ? options.records(parsed) : Array.isArray(parsed) ? parsed : [parsed];
|
|
20
6
|
let index = 0;
|
|
21
|
-
|
|
7
|
+
const documentOf = (record) => {
|
|
22
8
|
const key = typeof options.id === 'function' ? options.id(record, index) : pick(record, options.id);
|
|
23
9
|
const value = typeof options.text === 'function' ? options.text(record) : pick(record, options.text, record);
|
|
24
|
-
|
|
25
|
-
|
|
10
|
+
index++;
|
|
11
|
+
return {
|
|
12
|
+
id: `${source}#${key === undefined || key === null ? index : String(key)}`,
|
|
26
13
|
text: typeof value === 'string' ? value : JSON.stringify(value, null, 2),
|
|
27
14
|
source,
|
|
28
15
|
metadata: {
|
|
@@ -32,8 +19,172 @@ export async function* loadJson(inputs, options = {}) {
|
|
|
32
19
|
: Object.fromEntries((options.metadataFields ?? []).map((field) => [field, pick(record, field)]))),
|
|
33
20
|
},
|
|
34
21
|
};
|
|
35
|
-
|
|
22
|
+
};
|
|
23
|
+
if (options.records) {
|
|
24
|
+
const { text } = await readText(input);
|
|
25
|
+
const values = [];
|
|
26
|
+
if (lines)
|
|
27
|
+
for await (const value of jsonLines([text], source))
|
|
28
|
+
values.push(value);
|
|
29
|
+
const parsed = lines ? values : JSON.parse(text);
|
|
30
|
+
for (const record of options.records(parsed))
|
|
31
|
+
yield documentOf(record);
|
|
32
|
+
}
|
|
33
|
+
else if (lines) {
|
|
34
|
+
for await (const record of jsonLines(textChunks(input), source))
|
|
35
|
+
yield documentOf(record);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const scanner = new JsonRecordScanner(options.recordsAt?.split('.') ?? []);
|
|
39
|
+
for await (const chunk of textChunks(input)) {
|
|
40
|
+
for (const record of scanner.push(chunk))
|
|
41
|
+
yield documentOf(record);
|
|
42
|
+
if (scanner.finished)
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
for (const record of scanner.end(source))
|
|
46
|
+
yield documentOf(record);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function* jsonLines(chunks, source) {
|
|
51
|
+
let rest = '';
|
|
52
|
+
let number = 0;
|
|
53
|
+
const parse = (line) => {
|
|
54
|
+
number += 1;
|
|
55
|
+
if (!line.trim())
|
|
56
|
+
return undefined;
|
|
57
|
+
try {
|
|
58
|
+
return { value: JSON.parse(line) };
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new SyntaxError(`${source} line ${number}: ${error.message}`);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
for await (const chunk of chunks) {
|
|
65
|
+
const pieces = (rest + chunk).split('\n');
|
|
66
|
+
rest = pieces.pop() ?? '';
|
|
67
|
+
for (const line of pieces) {
|
|
68
|
+
const parsed = parse(line);
|
|
69
|
+
if (parsed)
|
|
70
|
+
yield parsed.value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const last = parse(rest);
|
|
74
|
+
if (last)
|
|
75
|
+
yield last.value;
|
|
76
|
+
}
|
|
77
|
+
class JsonRecordScanner {
|
|
78
|
+
path;
|
|
79
|
+
stack = [];
|
|
80
|
+
inString = false;
|
|
81
|
+
escaped = false;
|
|
82
|
+
keyText;
|
|
83
|
+
target = -1;
|
|
84
|
+
found = false;
|
|
85
|
+
done = false;
|
|
86
|
+
record;
|
|
87
|
+
whole;
|
|
88
|
+
started = false;
|
|
89
|
+
explicit;
|
|
90
|
+
constructor(path = []) {
|
|
91
|
+
this.path = path;
|
|
92
|
+
this.explicit = path.length > 0;
|
|
93
|
+
}
|
|
94
|
+
get finished() {
|
|
95
|
+
return this.done;
|
|
96
|
+
}
|
|
97
|
+
push(text) {
|
|
98
|
+
const records = [];
|
|
99
|
+
if (this.whole) {
|
|
100
|
+
this.whole.push(text);
|
|
101
|
+
return records;
|
|
36
102
|
}
|
|
103
|
+
let from = this.record ? 0 : -1;
|
|
104
|
+
for (let index = 0; index < text.length; index++) {
|
|
105
|
+
const char = text[index];
|
|
106
|
+
if (!this.started) {
|
|
107
|
+
if (/\s/.test(char))
|
|
108
|
+
continue;
|
|
109
|
+
this.started = true;
|
|
110
|
+
if (char !== '[' && !this.explicit) {
|
|
111
|
+
this.whole = [text.slice(index)];
|
|
112
|
+
return records;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (this.inString) {
|
|
116
|
+
if (this.keyText)
|
|
117
|
+
this.keyText.push(char);
|
|
118
|
+
if (this.escaped)
|
|
119
|
+
this.escaped = false;
|
|
120
|
+
else if (char === '\\')
|
|
121
|
+
this.escaped = true;
|
|
122
|
+
else if (char === '"') {
|
|
123
|
+
this.inString = false;
|
|
124
|
+
if (this.keyText) {
|
|
125
|
+
const frame = this.stack.at(-1);
|
|
126
|
+
frame.key = JSON.parse(`"${this.keyText.slice(0, -1).join('')}"`);
|
|
127
|
+
frame.expectKey = false;
|
|
128
|
+
this.keyText = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const atTarget = this.target >= 0 && this.stack.length === this.target;
|
|
134
|
+
if (atTarget && (char === ',' || char === ']')) {
|
|
135
|
+
if (this.record) {
|
|
136
|
+
this.record.push(text.slice(from, index));
|
|
137
|
+
records.push(JSON.parse(this.record.join('')));
|
|
138
|
+
this.record = undefined;
|
|
139
|
+
}
|
|
140
|
+
if (char === ']') {
|
|
141
|
+
this.done = true;
|
|
142
|
+
return records;
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (atTarget && !this.record && !/\s/.test(char)) {
|
|
147
|
+
this.record = [];
|
|
148
|
+
from = index;
|
|
149
|
+
}
|
|
150
|
+
const frame = this.stack.at(-1);
|
|
151
|
+
if (char === '"') {
|
|
152
|
+
this.inString = true;
|
|
153
|
+
if (frame?.kind === 'object' && frame.expectKey && !this.record)
|
|
154
|
+
this.keyText = [];
|
|
155
|
+
}
|
|
156
|
+
else if (char === '{' || char === '[') {
|
|
157
|
+
const opened = char === '{' ? { kind: 'object', expectKey: true } : { kind: 'array' };
|
|
158
|
+
if (char === '[' && this.at(this.path)) {
|
|
159
|
+
this.found = true;
|
|
160
|
+
this.target = this.stack.length + 1;
|
|
161
|
+
}
|
|
162
|
+
this.stack.push(opened);
|
|
163
|
+
}
|
|
164
|
+
else if (char === '}' || char === ']') {
|
|
165
|
+
this.stack.pop();
|
|
166
|
+
}
|
|
167
|
+
else if (char === ',' && frame?.kind === 'object')
|
|
168
|
+
frame.expectKey = true;
|
|
169
|
+
}
|
|
170
|
+
if (this.record)
|
|
171
|
+
this.record.push(text.slice(Math.max(from, 0)));
|
|
172
|
+
return records;
|
|
173
|
+
}
|
|
174
|
+
end(source) {
|
|
175
|
+
if (this.whole)
|
|
176
|
+
return [JSON.parse(this.whole.join(''))];
|
|
177
|
+
if (!this.found) {
|
|
178
|
+
throw new SyntaxError(this.explicit ? `${source} has no array at "${this.path.join('.')}"` : `${source} holds no JSON value`);
|
|
179
|
+
}
|
|
180
|
+
if (!this.done)
|
|
181
|
+
throw new SyntaxError(`${source} ends inside its array of records`);
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
at(path) {
|
|
185
|
+
if (this.stack.length !== path.length)
|
|
186
|
+
return false;
|
|
187
|
+
return this.stack.every((frame, depth) => frame.key === path[depth]);
|
|
37
188
|
}
|
|
38
189
|
}
|
|
39
190
|
function pick(record, path, fallback) {
|