tina4-nodejs 3.13.113 → 3.13.115
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 +173 -17
- package/packages/core/dist/index.js +173 -17
- package/packages/core/src/aiClient.ts +218 -17
- package/packages/core/src/index.ts +1 -1
- package/packages/core/src/server.ts +34 -9
- package/packages/orm/dist/index.js +173 -17
- package/types/core/src/aiClient.d.ts +91 -7
- package/types/core/src/index.d.ts +1 -1
- package/types/core/src/server.d.ts +23 -1
|
@@ -24,7 +24,10 @@ export interface ChatResponse {
|
|
|
24
24
|
/**
|
|
25
25
|
* A multimodal content part. `text` carries plain UTF-8 prose; `image`
|
|
26
26
|
* carries a `data:<media_type>;base64,<payload>` URI or an https:// URL
|
|
27
|
-
* (the client translates to each provider's shape
|
|
27
|
+
* (the client translates to each provider's shape, ADR-0060). `tool_result`
|
|
28
|
+
* carries the Anthropic-style return of a locally-executed tool call
|
|
29
|
+
* (ADR-0061); the client translates it to OpenAI's `{role: "tool", ...}`
|
|
30
|
+
* turn on non-Anthropic providers.
|
|
28
31
|
*/
|
|
29
32
|
export type ContentPart = {
|
|
30
33
|
type: "text";
|
|
@@ -32,13 +35,50 @@ export type ContentPart = {
|
|
|
32
35
|
} | {
|
|
33
36
|
type: "image";
|
|
34
37
|
source: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: "tool_result";
|
|
40
|
+
tool_use_id: string;
|
|
41
|
+
content: string;
|
|
35
42
|
};
|
|
36
43
|
/** The value a caller may pass for `message.content`. ADR-0060. */
|
|
37
44
|
export type AiMessageContent = string | ContentPart[];
|
|
38
|
-
|
|
45
|
+
/**
|
|
46
|
+
* One conversation turn. The three "chat" roles carry a string OR a
|
|
47
|
+
* content-parts array (ADR-0060). The `tool` role is the OpenAI-style
|
|
48
|
+
* return of a tool call (ADR-0061); the client translates it to the
|
|
49
|
+
* Anthropic user-turn form when the current provider is Anthropic.
|
|
50
|
+
*/
|
|
51
|
+
export type AiMessage = {
|
|
39
52
|
role: "system" | "user" | "assistant";
|
|
40
53
|
content: AiMessageContent;
|
|
54
|
+
} | {
|
|
55
|
+
role: "tool";
|
|
56
|
+
tool_call_id: string;
|
|
57
|
+
content: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* A tool declaration the model may call (named `AiToolDeclaration` to
|
|
61
|
+
* stay out of the way of {@link ./ai.ts}'s existing `AiTool` interface
|
|
62
|
+
* for AI-coding-tool context installation). `parameters` is a JSON
|
|
63
|
+
* Schema object; it is passed to the provider unchanged (ADR-0061
|
|
64
|
+
* `parameters-passthrough`).
|
|
65
|
+
*/
|
|
66
|
+
export interface AiToolDeclaration {
|
|
67
|
+
name: string;
|
|
68
|
+
description: string;
|
|
69
|
+
parameters: Record<string, unknown>;
|
|
41
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* How the model picks a tool. Four Tina4 values that span the useful cases
|
|
73
|
+
* across providers (ADR-0061 wire-translation table):
|
|
74
|
+
* 'auto' — model may call any tool or answer with text
|
|
75
|
+
* 'none' — model must not call a tool (Anthropic omits `tools`)
|
|
76
|
+
* 'required' — model must call some tool
|
|
77
|
+
* {name: 'x'} — model must call tool 'x'
|
|
78
|
+
*/
|
|
79
|
+
export type AiToolChoice = "auto" | "none" | "required" | {
|
|
80
|
+
name: string;
|
|
81
|
+
};
|
|
42
82
|
/**
|
|
43
83
|
* One event yielded by `Ai.chat(stream: true)`. The four variants
|
|
44
84
|
* discriminated by `type`. Text deltas arrive per chunk (typewriter UX);
|
|
@@ -74,6 +114,14 @@ export interface AiChatOptions {
|
|
|
74
114
|
stream?: boolean;
|
|
75
115
|
timeout?: number;
|
|
76
116
|
provider?: "local" | "openai" | "anthropic";
|
|
117
|
+
/** Tools the model may call. ADR-0061 — translated per provider. */
|
|
118
|
+
tools?: AiToolDeclaration[];
|
|
119
|
+
/**
|
|
120
|
+
* How the model picks a tool. ADR-0061 — translated per provider. If
|
|
121
|
+
* `'none'` on Anthropic (which has no "none" mode), `tools` is omitted
|
|
122
|
+
* from the outbound body entirely.
|
|
123
|
+
*/
|
|
124
|
+
toolChoice?: AiToolChoice;
|
|
77
125
|
}
|
|
78
126
|
export interface AiEmbedOptions {
|
|
79
127
|
model?: string;
|
|
@@ -91,24 +139,60 @@ export declare class Ai {
|
|
|
91
139
|
static embed(textOrTexts: string | string[], options?: AiEmbedOptions): Promise<number[] | number[][]>;
|
|
92
140
|
/**
|
|
93
141
|
* Validate role + content shape. Content may be a string OR a non-empty
|
|
94
|
-
* list of {type:'text'|'image', ...} parts (ADR-0060
|
|
95
|
-
*
|
|
142
|
+
* list of {type:'text'|'image'|'tool_result', ...} parts (ADR-0060 +
|
|
143
|
+
* ADR-0061). The `tool` role is the OpenAI-style tool-result turn
|
|
144
|
+
* (ADR-0061). Malformed parts fail fast with AiConfigError, never
|
|
145
|
+
* reaching the wire.
|
|
96
146
|
*/
|
|
97
147
|
private static validateMessages;
|
|
98
148
|
private static validateContent;
|
|
149
|
+
/**
|
|
150
|
+
* Validate the outbound tool declarations (ADR-0061). Each tool needs a
|
|
151
|
+
* non-empty `name`, a string `description`, and a JSON-Schema-shaped
|
|
152
|
+
* `parameters` object. Malformed tools fail fast with AiConfigError,
|
|
153
|
+
* never reaching the wire.
|
|
154
|
+
*/
|
|
155
|
+
private static validateTools;
|
|
156
|
+
/**
|
|
157
|
+
* Validate the outbound tool_choice value (ADR-0061). The four accepted
|
|
158
|
+
* shapes are 'auto', 'none', 'required', and {name: 'x'}.
|
|
159
|
+
*/
|
|
160
|
+
private static validateToolChoice;
|
|
99
161
|
private static number;
|
|
100
162
|
private static config;
|
|
101
163
|
private static endpoint;
|
|
102
164
|
private static headers;
|
|
103
165
|
/**
|
|
104
166
|
* Build the provider-specific request body from a Tina4-shaped message
|
|
105
|
-
* list
|
|
106
|
-
*
|
|
107
|
-
*
|
|
167
|
+
* list plus optional tool declarations (ADR-0060 + ADR-0061).
|
|
168
|
+
*
|
|
169
|
+
* Content parts translate per provider:
|
|
170
|
+
* - OpenAI/local: image → {type:'image_url', image_url:{url}}
|
|
171
|
+
* - Anthropic: image → {type:'image', source:{type:'base64'|'url', ...}}
|
|
108
172
|
* String content is preserved verbatim in the OpenAI/local shape and
|
|
109
173
|
* likewise for Anthropic (both accept a bare string).
|
|
174
|
+
*
|
|
175
|
+
* Tool-result turns are normalised to the current provider's expected
|
|
176
|
+
* shape (either the OpenAI `{role:"tool", tool_call_id, content}` turn or
|
|
177
|
+
* the Anthropic `{role:"user", content:[{type:"tool_result", ...}]}`
|
|
178
|
+
* turn), so an agent-loop written against Tina4 never has to fork on
|
|
179
|
+
* TINA4_AI_PROVIDER (ADR-0061 wire translation).
|
|
110
180
|
*/
|
|
111
181
|
private static chatBody;
|
|
182
|
+
/**
|
|
183
|
+
* Normalise the Tina4-shaped messages into the provider's on-wire shape.
|
|
184
|
+
* The `tool` role and the `tool_result` content part are translated
|
|
185
|
+
* between the OpenAI and Anthropic forms so either input works against
|
|
186
|
+
* either provider (ADR-0061 return-path table).
|
|
187
|
+
*/
|
|
188
|
+
private static normalizeMessagesForProvider;
|
|
189
|
+
/**
|
|
190
|
+
* Attach the outbound `tools` and `tool_choice` (ADR-0061 outbound
|
|
191
|
+
* translation tables) to the body in place. When toolChoice is 'none'
|
|
192
|
+
* on Anthropic (Anthropic has no "none" mode) the tools list is omitted
|
|
193
|
+
* entirely — the model cannot call what it cannot see.
|
|
194
|
+
*/
|
|
195
|
+
private static applyTools;
|
|
112
196
|
/**
|
|
113
197
|
* Translate one message content value into the provider's on-wire shape.
|
|
114
198
|
* A plain string is passed through (both providers accept a string
|
|
@@ -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, AiEvent, ContentPart, AiMessageContent } from "./aiClient.js";
|
|
61
|
+
export type { ChatResponse, AiMessage, AiChatOptions, AiEmbedOptions, AiEvent, ContentPart, AiMessageContent, AiToolDeclaration, AiToolChoice } 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";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
import type { Tina4Config } from "./types.js";
|
|
2
|
+
import type { Tina4Config, Tina4Request, Tina4Response } from "./types.js";
|
|
3
3
|
import { Router } from "./router.js";
|
|
4
4
|
import { MiddlewareChain } from "./middleware.js";
|
|
5
5
|
/** How long a graceful shutdown waits for in-flight requests, in seconds. */
|
|
@@ -167,6 +167,28 @@ export declare function stop(): void;
|
|
|
167
167
|
* Useful for testing and embedding.
|
|
168
168
|
*/
|
|
169
169
|
export declare function handle(rawReq: IncomingMessage, rawRes: ServerResponse): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Invoke a matched route's handler, binding path params BY NAME.
|
|
172
|
+
*
|
|
173
|
+
* A handler declares whatever it needs - `(id, request, response)`, `(req, res)`,
|
|
174
|
+
* or nothing - and each parameter is resolved by its name: a path param wins,
|
|
175
|
+
* then `request`/`req`, then the response.
|
|
176
|
+
*/
|
|
177
|
+
/**
|
|
178
|
+
* Resolve a handler's argument list to `[reqOrParam, resOrParam, ...]` values.
|
|
179
|
+
*
|
|
180
|
+
* By-name path preserved (route-param names, `req`/`request`, `res`/`response`)
|
|
181
|
+
* so existing code keeps its DX. Any remaining unmatched name falls back to
|
|
182
|
+
* POSITIONAL binding: first unmatched -> request, rest -> response. That makes
|
|
183
|
+
* dispatch bundler-safe by construction: Bun `--compile` and terser/esbuild
|
|
184
|
+
* identifier-mangling rename `(req, res)` to `(req2, r$0)` — the by-name path
|
|
185
|
+
* misses, the positional fallback catches, and the handler still receives the
|
|
186
|
+
* request as its first argument. Fixes #56.
|
|
187
|
+
*
|
|
188
|
+
* Exported so the regression test can pin the behaviour directly, without a
|
|
189
|
+
* live HTTP server.
|
|
190
|
+
*/
|
|
191
|
+
export declare function resolveHandlerArgs(handler: unknown, req: Tina4Request, res: Tina4Response, routeParams: Record<string, unknown>): unknown[];
|
|
170
192
|
/**
|
|
171
193
|
* Everything one request's dispatch needs beyond req/res: the resolved
|
|
172
194
|
* router, middleware chain, filesystem roots and template engine a boot
|