tina4-nodejs 3.13.112 → 3.13.113
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/CLAUDE.md +2 -2
- package/package.json +1 -1
- package/packages/cli/dist/bin.js +533 -48
- package/packages/core/dist/index.js +536 -48
- package/packages/core/src/aiClient.ts +368 -48
- package/packages/core/src/api.ts +269 -0
- package/packages/core/src/index.ts +3 -3
- package/packages/orm/dist/index.js +533 -48
- package/types/core/src/aiClient.d.ts +74 -5
- package/types/core/src/api.d.ts +102 -0
- package/types/core/src/index.d.ts +3 -3
|
@@ -21,10 +21,52 @@ export interface ChatResponse {
|
|
|
21
21
|
finishReason: string | null;
|
|
22
22
|
raw: Record<string, unknown>;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* A multimodal content part. `text` carries plain UTF-8 prose; `image`
|
|
26
|
+
* carries a `data:<media_type>;base64,<payload>` URI or an https:// URL
|
|
27
|
+
* (the client translates to each provider's shape). ADR-0060.
|
|
28
|
+
*/
|
|
29
|
+
export type ContentPart = {
|
|
30
|
+
type: "text";
|
|
31
|
+
text: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: "image";
|
|
34
|
+
source: string;
|
|
35
|
+
};
|
|
36
|
+
/** The value a caller may pass for `message.content`. ADR-0060. */
|
|
37
|
+
export type AiMessageContent = string | ContentPart[];
|
|
24
38
|
export interface AiMessage {
|
|
25
39
|
role: "system" | "user" | "assistant";
|
|
26
|
-
content:
|
|
40
|
+
content: AiMessageContent;
|
|
27
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* One event yielded by `Ai.chat(stream: true)`. The four variants
|
|
44
|
+
* discriminated by `type`. Text deltas arrive per chunk (typewriter UX);
|
|
45
|
+
* `tool_call` fires once per call, aggregated from provider fragments;
|
|
46
|
+
* `done` fires exactly once after all deltas; `error` replaces `done` on
|
|
47
|
+
* mid-stream failure. ADR-0060.
|
|
48
|
+
*/
|
|
49
|
+
export type AiEvent = {
|
|
50
|
+
type: "text_delta";
|
|
51
|
+
text: string;
|
|
52
|
+
} | {
|
|
53
|
+
type: "tool_call";
|
|
54
|
+
id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
args: Record<string, unknown>;
|
|
57
|
+
} | {
|
|
58
|
+
type: "done";
|
|
59
|
+
finishReason: string;
|
|
60
|
+
usage?: {
|
|
61
|
+
promptTokens: number;
|
|
62
|
+
completionTokens: number;
|
|
63
|
+
totalTokens: number;
|
|
64
|
+
};
|
|
65
|
+
} | {
|
|
66
|
+
type: "error";
|
|
67
|
+
message: string;
|
|
68
|
+
code?: string;
|
|
69
|
+
};
|
|
28
70
|
export interface AiChatOptions {
|
|
29
71
|
model?: string;
|
|
30
72
|
temperature?: number;
|
|
@@ -41,26 +83,53 @@ export interface AiEmbedOptions {
|
|
|
41
83
|
export declare class Ai {
|
|
42
84
|
static chat(messages: AiMessage[], options: AiChatOptions & {
|
|
43
85
|
stream: true;
|
|
44
|
-
}): AsyncGenerator<
|
|
86
|
+
}): AsyncGenerator<AiEvent>;
|
|
45
87
|
static chat(messages: AiMessage[], options?: AiChatOptions & {
|
|
46
88
|
stream?: false;
|
|
47
89
|
}): Promise<ChatResponse>;
|
|
48
90
|
static complete(prompt: string, options?: Omit<AiChatOptions, "stream">): Promise<string>;
|
|
49
91
|
static embed(textOrTexts: string | string[], options?: AiEmbedOptions): Promise<number[] | number[][]>;
|
|
92
|
+
/**
|
|
93
|
+
* Validate role + content shape. Content may be a string OR a non-empty
|
|
94
|
+
* list of {type:'text'|'image', ...} parts (ADR-0060). Malformed parts
|
|
95
|
+
* fail fast with AiConfigError, never reaching the wire.
|
|
96
|
+
*/
|
|
50
97
|
private static validateMessages;
|
|
98
|
+
private static validateContent;
|
|
51
99
|
private static number;
|
|
52
100
|
private static config;
|
|
53
101
|
private static endpoint;
|
|
54
102
|
private static headers;
|
|
103
|
+
/**
|
|
104
|
+
* Build the provider-specific request body from a Tina4-shaped message
|
|
105
|
+
* list. Multimodal parts are translated per provider (ADR-0060):
|
|
106
|
+
* - OpenAI/local: {type:'image_url', image_url:{url}}
|
|
107
|
+
* - Anthropic: {type:'image', source:{type:'base64'|'url', ...}}
|
|
108
|
+
* String content is preserved verbatim in the OpenAI/local shape and
|
|
109
|
+
* likewise for Anthropic (both accept a bare string).
|
|
110
|
+
*/
|
|
55
111
|
private static chatBody;
|
|
112
|
+
/**
|
|
113
|
+
* Translate one message content value into the provider's on-wire shape.
|
|
114
|
+
* A plain string is passed through (both providers accept a string
|
|
115
|
+
* content). A parts array becomes provider-native content blocks.
|
|
116
|
+
*/
|
|
117
|
+
private static translateContent;
|
|
118
|
+
private static parseDataUri;
|
|
119
|
+
private static contentToPlainText;
|
|
56
120
|
private static open;
|
|
57
121
|
private static readBody;
|
|
58
122
|
private static retryDelay;
|
|
59
123
|
private static requestJson;
|
|
60
124
|
private static normalizeChat;
|
|
61
125
|
private static chatResponse;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Stream the response through the shared {@link parseSseStream} framer
|
|
128
|
+
* (ADR-0060 rule 5). Translates each SSE data payload into 0..N
|
|
129
|
+
* {@link AiEvent}s: text_delta per chunk, tool_call aggregated per
|
|
130
|
+
* index / block, exactly one done (or error) at the end.
|
|
131
|
+
*/
|
|
65
132
|
private static streamRequest;
|
|
133
|
+
private static responseChunks;
|
|
134
|
+
private static streamError;
|
|
66
135
|
}
|
package/types/core/src/api.d.ts
CHANGED
|
@@ -4,6 +4,38 @@ export interface ApiResult {
|
|
|
4
4
|
headers: Record<string, string>;
|
|
5
5
|
error: string | null;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Options for the streaming primitives ({@link Api.streamBytes},
|
|
9
|
+
* {@link Api.streamLines}, {@link Api.streamSse}). All fields optional.
|
|
10
|
+
* `timeout` bounds the WHOLE stream (headers + body), matching
|
|
11
|
+
* `TINA4_API_TIMEOUT`; `connectTimeout` bounds only the connection +
|
|
12
|
+
* headers-arrival phase, matching `TINA4_API_CONNECT_TIMEOUT`.
|
|
13
|
+
*/
|
|
14
|
+
export interface StreamOptions {
|
|
15
|
+
method?: string;
|
|
16
|
+
body?: unknown;
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
contentType?: string;
|
|
19
|
+
timeout?: number;
|
|
20
|
+
connectTimeout?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* One SSE event yielded by {@link Api.streamSse}. `data` is always present
|
|
24
|
+
* (multi-line `data:` fields are concatenated with `\n`). `event`, `id`,
|
|
25
|
+
* `retry` are set only when the corresponding SSE field appeared. `retry`
|
|
26
|
+
* is a number (milliseconds) per the SSE spec.
|
|
27
|
+
*/
|
|
28
|
+
export interface SseEvent {
|
|
29
|
+
data: string;
|
|
30
|
+
event?: string;
|
|
31
|
+
id?: string;
|
|
32
|
+
retry?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Raised by the streaming primitives on a non-2xx status. */
|
|
35
|
+
export declare class ApiStreamError extends Error {
|
|
36
|
+
readonly status: number | null;
|
|
37
|
+
constructor(message: string, status?: number | null);
|
|
38
|
+
}
|
|
7
39
|
/**
|
|
8
40
|
* Result of {@link Api.download}. There is no `body` field — the response
|
|
9
41
|
* body went to disk. `path` is the destination on success and `null` on any
|
|
@@ -90,6 +122,28 @@ export interface ApiOptions {
|
|
|
90
122
|
*/
|
|
91
123
|
cookies?: boolean;
|
|
92
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Split an async byte iterable into UTF-8 lines. Handles LF and CRLF; a
|
|
127
|
+
* multibyte codepoint that lands across a chunk boundary buffers across the
|
|
128
|
+
* split (TextDecoder({stream: true})). A trailing line without a terminator
|
|
129
|
+
* yields on EOF.
|
|
130
|
+
*
|
|
131
|
+
* Exported so {@link Api} instance methods AND `Ai.chat` streaming share
|
|
132
|
+
* one framer — ADR-0060's "no duplicate framing code" rule.
|
|
133
|
+
*/
|
|
134
|
+
export declare function parseLineStream(chunks: AsyncIterable<Uint8Array>): AsyncGenerator<string>;
|
|
135
|
+
/**
|
|
136
|
+
* Parse SSE (Server-Sent Events) framing from a line iterable. Yields
|
|
137
|
+
* one {@link SseEvent} per event boundary (blank line) or on EOF for a
|
|
138
|
+
* final trailing event. `:` comment lines are ignored. Fields are
|
|
139
|
+
* `data` (multi-line concatenated with `\n`), `event`, `id`, `retry`.
|
|
140
|
+
*
|
|
141
|
+
* Follows the WHATWG SSE parsing algorithm closely enough for every LLM
|
|
142
|
+
* provider (OpenAI, Anthropic, local): one leading space after the colon
|
|
143
|
+
* is stripped, unknown fields are ignored, malformed `retry:` values are
|
|
144
|
+
* ignored.
|
|
145
|
+
*/
|
|
146
|
+
export declare function parseSseStream(lines: AsyncIterable<string>): AsyncGenerator<SseEvent>;
|
|
93
147
|
export declare class Api {
|
|
94
148
|
private baseUrl;
|
|
95
149
|
private headers;
|
|
@@ -209,6 +263,54 @@ export declare class Api {
|
|
|
209
263
|
* not written on error.
|
|
210
264
|
*/
|
|
211
265
|
download(path: string, destPath: string, params?: Record<string, string>): Promise<DownloadResult>;
|
|
266
|
+
/**
|
|
267
|
+
* Stream a response body as raw bytes. Yields the chunks the transport
|
|
268
|
+
* delivers, in order, never buffered whole. Ends cleanly on EOF and
|
|
269
|
+
* throws on a transport failure or a non-2xx status (body drained
|
|
270
|
+
* first). No JSON decoding, no line splitting, no framing —
|
|
271
|
+
* {@link streamLines} and {@link streamSse} build on this primitive.
|
|
272
|
+
*
|
|
273
|
+
* Closing the iterator before EOF (a `break` out of a `for await`)
|
|
274
|
+
* destroys the underlying socket, so a caller who takes only the
|
|
275
|
+
* first few chunks never leaks the connection.
|
|
276
|
+
*
|
|
277
|
+
* `opts.timeout` bounds the whole stream duration (default
|
|
278
|
+
* `TINA4_API_TIMEOUT` or the client `timeout`); `opts.connectTimeout`
|
|
279
|
+
* bounds just the connect + headers phase (default
|
|
280
|
+
* `TINA4_API_CONNECT_TIMEOUT` or 10s).
|
|
281
|
+
*/
|
|
282
|
+
streamBytes(path: string, opts?: StreamOptions): AsyncGenerator<Uint8Array>;
|
|
283
|
+
/**
|
|
284
|
+
* Stream the response body as UTF-8 lines. Splits on LF or CRLF;
|
|
285
|
+
* buffers a multibyte codepoint that lands across a chunk boundary;
|
|
286
|
+
* yields a trailing line without a terminator on EOF. Built on
|
|
287
|
+
* {@link streamBytes} plus the shared {@link parseLineStream}.
|
|
288
|
+
*/
|
|
289
|
+
streamLines(path: string, opts?: StreamOptions): AsyncGenerator<string>;
|
|
290
|
+
/**
|
|
291
|
+
* Stream the response as SSE (Server-Sent Events). Yields one
|
|
292
|
+
* {@link SseEvent} per event boundary (blank line) or on EOF for a
|
|
293
|
+
* trailing event. `data:[DONE]` is delivered as an ordinary event
|
|
294
|
+
* with `data === "[DONE]"` and the iterator ends on the next EOF.
|
|
295
|
+
* Built on {@link streamLines} plus the shared {@link parseSseStream}.
|
|
296
|
+
*/
|
|
297
|
+
streamSse(path: string, opts?: StreamOptions): AsyncGenerator<SseEvent>;
|
|
298
|
+
/**
|
|
299
|
+
* Resolve a stream duration from (in order): explicit `opts` field,
|
|
300
|
+
* the named env var, then the fallback. Zero disables. A non-numeric
|
|
301
|
+
* or negative env value warns via a fallback rather than throwing —
|
|
302
|
+
* a bad env var must not brick every streaming call.
|
|
303
|
+
*/
|
|
304
|
+
private streamSeconds;
|
|
305
|
+
/**
|
|
306
|
+
* Open a streaming HTTP request. Returns the raw
|
|
307
|
+
* {@link http.IncomingMessage} once headers arrive. Redirects are NOT
|
|
308
|
+
* followed on streams (a caller who needs a redirect should do a
|
|
309
|
+
* regular GET first). Connect phase is bounded by `connectSec`;
|
|
310
|
+
* body-phase timeout is applied by the caller (streamBytes) via
|
|
311
|
+
* `res.destroy()`.
|
|
312
|
+
*/
|
|
313
|
+
private openStreamRequest;
|
|
212
314
|
private buildUrl;
|
|
213
315
|
/**
|
|
214
316
|
* Build the request headers (default User-Agent + auth + cookie jar +
|
|
@@ -39,8 +39,8 @@ export { ServiceRunner, Tina4Service, matchCronField, matchesCron } from "./serv
|
|
|
39
39
|
export type { ServiceOptions, ServiceContext, ServiceHandler, ServiceInfo } from "./service.js";
|
|
40
40
|
export { responseCache, clearCache, cacheStats, cacheGet, cacheSet, cacheDelete, cacheClear, cacheBackendStats, sweep, createBackend, _resetBackend } from "./cache.js";
|
|
41
41
|
export type { ResponseCacheConfig, CacheBackend } from "./cache.js";
|
|
42
|
-
export { Api } from "./api.js";
|
|
43
|
-
export type { ApiResult, ApiOptions, ApiTransport, DownloadResult, UploadOptions } from "./api.js";
|
|
42
|
+
export { Api, ApiStreamError, parseLineStream, parseSseStream } from "./api.js";
|
|
43
|
+
export type { ApiResult, ApiOptions, ApiTransport, DownloadResult, UploadOptions, StreamOptions, SseEvent } from "./api.js";
|
|
44
44
|
export { Context, defaultContext, existingContext, fts5Supported, _sharedContexts } from "./context/index.js";
|
|
45
45
|
export type { SearchHit } from "./context/index.js";
|
|
46
46
|
export { Events } from "./events.js";
|
|
@@ -58,7 +58,7 @@ export type { AiTool } from "./ai.js";
|
|
|
58
58
|
export { Sso, SSO, SsoError } from "./sso.js";
|
|
59
59
|
export type { SsoOptions } from "./sso.js";
|
|
60
60
|
export { Ai, AiError, AiConfigError, AiHTTPError, AiTimeoutError, AiParseError } from "./aiClient.js";
|
|
61
|
-
export type { ChatResponse, AiMessage, AiChatOptions, AiEmbedOptions } from "./aiClient.js";
|
|
61
|
+
export type { ChatResponse, AiMessage, AiChatOptions, AiEmbedOptions, AiEvent, ContentPart, AiMessageContent } from "./aiClient.js";
|
|
62
62
|
export type { ImapMessage, ImapFullMessage, ImapAttachment } from "./messenger.js";
|
|
63
63
|
export { LiteBackend } from "./queueBackends/liteBackend.js";
|
|
64
64
|
export { RabbitMQBackend, parseAmqpUrl } from "./queueBackends/rabbitmqBackend.js";
|