@combycode/llm-sdk 2.2.1 → 2.3.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/CHANGELOG.md +206 -0
- package/dist/agent/loop-internals.d.ts +4 -0
- package/dist/agent/loop.d.ts +35 -0
- package/dist/{llm/providers → catalog}/builtin-tools.d.ts +1 -1
- package/dist/{plugins/model-catalog → catalog}/catalog.d.ts +34 -0
- package/dist/helpers/client-pool.d.ts +1 -1
- package/dist/helpers/client-resolver.d.ts +1 -1
- package/dist/helpers/engine.d.ts +12 -1
- package/dist/helpers/mcp.d.ts +6 -1
- package/dist/helpers/models.d.ts +1 -1
- package/dist/helpers/one-shot.d.ts +2 -2
- package/dist/helpers/select-model.d.ts +1 -1
- package/dist/index.browser.js +1438 -891
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1438 -891
- package/dist/llm/client-config.d.ts +1 -1
- package/dist/llm/client-internal.d.ts +11 -0
- package/dist/llm/client.d.ts +4 -0
- package/dist/llm/providers/_shared/sse.d.ts +19 -0
- package/dist/llm/providers/google/files.d.ts +15 -0
- package/dist/llm/providers/google/media.d.ts +22 -4
- package/dist/llm/providers/google/realtime.d.ts +15 -2
- package/dist/llm/providers/openai/media.d.ts +10 -1
- package/dist/llm/providers/openai/realtime.d.ts +15 -2
- package/dist/llm/server-state.d.ts +1 -1
- package/dist/llm/types/options.d.ts +2 -2
- package/dist/llm/types/request.d.ts +50 -1
- package/dist/plugins/context-measurer/counter/count-api.d.ts +1 -1
- package/dist/plugins/context-measurer/counter/heuristic.d.ts +1 -1
- package/dist/plugins/context-measurer/counter/hybrid.d.ts +1 -1
- package/dist/plugins/context-measurer/measurer.d.ts +1 -1
- package/dist/plugins/cost-collector/collector.d.ts +1 -1
- package/dist/plugins/cost-collector/cost-collector-internal.d.ts +1 -1
- package/dist/plugins/cost-collector/cost-collector-types.d.ts +1 -1
- package/dist/plugins/files/registry.d.ts +1 -1
- package/dist/plugins/files/strategy.d.ts +1 -1
- package/dist/plugins/internal-tools/registry.d.ts +1 -1
- package/dist/plugins/internal-tools/runner/types.d.ts +1 -1
- package/dist/plugins/mcp/sampling.d.ts +23 -1
- package/dist/plugins/media/output.d.ts +1 -1
- package/dist/plugins/telemetry/telemetry.d.ts +2 -133
- package/dist/plugins/telemetry/types.d.ts +139 -0
- package/dist/util/hash.d.ts +8 -0
- package/dist/{plugins/media → util}/source-image.d.ts +1 -1
- package/dist/wire/inherit.d.ts +47 -0
- package/dist/wire/interpreter.d.ts +236 -0
- package/dist/wire/registry.d.ts +18 -0
- package/dist/wire/transforms.d.ts +22 -0
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** LLMClient configuration types. */
|
|
2
2
|
import type { HookBus } from '../bus/hook-bus';
|
|
3
3
|
import type { EngineFetch, EngineFetchStream } from '../network/types';
|
|
4
|
-
import type { ModelCatalog } from '../
|
|
4
|
+
import type { ModelCatalog } from '../catalog/catalog';
|
|
5
5
|
import type { RequestContext } from '../types/request-context';
|
|
6
6
|
import type { ApiType, ProviderAdapter, ProviderName } from './types/provider';
|
|
7
7
|
import type { NormalizedRequest } from './types/request';
|
|
@@ -34,6 +34,17 @@ export declare function extractSystem(messages: Message[]): {
|
|
|
34
34
|
/** Strip leading/trailing markdown fences and JSON.parse. Exported so AgentLoop
|
|
35
35
|
* + helper can share the same parsing rules. */
|
|
36
36
|
export declare function parseStructured<T>(text: string): T;
|
|
37
|
+
/** The routing names `buildContext` needs from a client.
|
|
38
|
+
*
|
|
39
|
+
* These were read with `as unknown as { queueName: string }` casts straight into
|
|
40
|
+
* LLMClient's privates — which compiles, and silently returns `undefined` the
|
|
41
|
+
* day a field is renamed. LLMClient now exposes them deliberately as
|
|
42
|
+
* `client.routing`, so a rename is a type error instead. */
|
|
43
|
+
export interface ClientRouting {
|
|
44
|
+
readonly queueName: string;
|
|
45
|
+
readonly configName: string;
|
|
46
|
+
readonly cacheName: string;
|
|
47
|
+
}
|
|
37
48
|
export declare function buildContext(client: LLMClient, options: ExecuteOptions): RequestContext;
|
|
38
49
|
export declare function resolveApi(provider: ProviderName, api?: ApiType | 'auto'): ApiType;
|
|
39
50
|
export declare function resolveAdapter(config: LLMClientConfig, api: ApiType): ProviderAdapter;
|
package/dist/llm/client.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ import type { ApiType, ProviderName } from './types/provider';
|
|
|
25
25
|
import type { CompletionResponse, FileOutput } from './types/response';
|
|
26
26
|
import type { StreamEvent } from './types/stream';
|
|
27
27
|
import type { LLMClientConfig } from './client-config';
|
|
28
|
+
import { type ClientRouting } from './client-internal';
|
|
28
29
|
export declare class LLMClient {
|
|
29
30
|
readonly id: string;
|
|
30
31
|
/** Trace session id (from the engine, or self-minted for a standalone client). */
|
|
@@ -44,6 +45,9 @@ export declare class LLMClient {
|
|
|
44
45
|
private readonly queueName;
|
|
45
46
|
private readonly configName;
|
|
46
47
|
private readonly cacheName;
|
|
48
|
+
/** The routing names this client was configured with, exposed so context
|
|
49
|
+
* building does not have to cast into the privates above. */
|
|
50
|
+
readonly routing: ClientRouting;
|
|
47
51
|
private readonly cacheKeyFn?;
|
|
48
52
|
private readonly catalog;
|
|
49
53
|
constructor(config: LLMClientConfig);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** The one piece of SSE handling every provider genuinely shares.
|
|
2
|
+
*
|
|
3
|
+
* Report 035 proposed a shared "SSE -> StreamEvent parser" because the parsing
|
|
4
|
+
* looked duplicated ~5x. Measured, it is not: the six parse bodies (76-149
|
|
5
|
+
* lines each) share ZERO runs of three or more identical lines, because they
|
|
6
|
+
* decode different wire schemas — Anthropic's `content_block_*` events,
|
|
7
|
+
* OpenAI chat's `choices[].delta`, OpenAI Responses' typed events, and Google's
|
|
8
|
+
* `candidates[].content.parts`. A "shared" parser would be a switch on provider
|
|
9
|
+
* wearing a common signature.
|
|
10
|
+
*
|
|
11
|
+
* What IS shared is exactly this line, repeated six times. Naming it gives the
|
|
12
|
+
* three language ports one primitive to agree on instead of six independent
|
|
13
|
+
* decisions, and one place to harden if malformed frames ever need handling
|
|
14
|
+
* (today a bad frame throws out of the parser, which is the existing
|
|
15
|
+
* behaviour and deliberately unchanged here).
|
|
16
|
+
*/
|
|
17
|
+
import type { SSEEvent } from '../../../network/types';
|
|
18
|
+
/** Decode an SSE frame's `data` payload as a JSON object. */
|
|
19
|
+
export declare function sseJson(event: SSEEvent): Record<string, unknown>;
|
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
import type { EngineFetch } from '../../../network/types';
|
|
4
4
|
import type { FileAttachment } from '../../../plugins/files/attachment';
|
|
5
5
|
import type { FileProviderAdapter, FileUploadResult, RemoteFileInfo } from '../../../plugins/files/provider-adapter';
|
|
6
|
+
/** Reduce any form of Google file id to the bare name the REST path wants.
|
|
7
|
+
*
|
|
8
|
+
* Three forms reach this, and only two used to work:
|
|
9
|
+
*
|
|
10
|
+
* https://.../v1beta/files/abc the `uri` this adapter hands back from
|
|
11
|
+
* upload() and list() — matched on `/files/`
|
|
12
|
+
* abc a bare name — passed through
|
|
13
|
+
* files/abc Google's CANONICAL resource name, the `name`
|
|
14
|
+
* field its own API returns
|
|
15
|
+
*
|
|
16
|
+
* The third fell through the `/files/` test (no leading slash) and produced
|
|
17
|
+
* `/v1beta/files/files/abc` — a 404. It never broke this library's own
|
|
18
|
+
* round-trip, because upload() and list() return the `uri`; it broke the
|
|
19
|
+
* moment a caller passed the id Google itself gave them. */
|
|
20
|
+
export declare function googleFileName(remoteId: string): string;
|
|
6
21
|
export interface GoogleFileAdapterConfig {
|
|
7
22
|
apiKey: string;
|
|
8
23
|
baseURL?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Google media adapter — Imagen (:predict) + Veo (:predictLongRunning).
|
|
2
2
|
* All HTTP calls go through an injected EngineFetch (NetworkEngine queue). */
|
|
3
|
-
import type { EngineFetch } from '../../../network/types';
|
|
3
|
+
import type { EngineFetch, HttpRequest } from '../../../network/types';
|
|
4
4
|
import type { AudioGenRequest, ImageEditRequest, ImageGenRequest, MediaCapabilities, MediaProviderAdapter, RawMediaResult, VideoGenRequest, VideoStatus } from '../../../plugins/media/types';
|
|
5
5
|
export interface GoogleMediaAdapterConfig {
|
|
6
6
|
apiKey: string;
|
|
@@ -12,14 +12,32 @@ export declare class GoogleMediaAdapter implements MediaProviderAdapter {
|
|
|
12
12
|
private readonly baseURL;
|
|
13
13
|
constructor(config: GoogleMediaAdapterConfig);
|
|
14
14
|
capabilities(): MediaCapabilities;
|
|
15
|
+
/** Imagen image generation: the Vertex-style `:predict` envelope. */
|
|
16
|
+
buildImagenRequest(req: ImageGenRequest, model?: string): HttpRequest;
|
|
17
|
+
/** The inline-media path shared by gemini image generation, editing and TTS. */
|
|
18
|
+
buildGenerateContentRequest(model: string, text: string, generationConfig: Record<string, unknown>, extraParts?: Array<Record<string, unknown>>): HttpRequest;
|
|
19
|
+
/** Veo video submission — a long-running operation, hence the endpoint. */
|
|
20
|
+
buildVideoRequest(req: VideoGenRequest, model?: string): HttpRequest;
|
|
21
|
+
/** `generationConfig` for the gemini image paths — generation and editing take
|
|
22
|
+
* the same one. */
|
|
23
|
+
private imageGenerationConfig;
|
|
24
|
+
/** The complete image request, whichever of the two Google image paths applies:
|
|
25
|
+
* Imagen models use `:predict`, gemini-* models generate inline via
|
|
26
|
+
* `:generateContent` steered by responseModalities. */
|
|
27
|
+
buildImageRequest(req: ImageGenRequest, model?: string): HttpRequest;
|
|
28
|
+
/** Gemini TTS: the same inline path with an AUDIO modality and a speechConfig. */
|
|
29
|
+
buildAudioRequest(req: AudioGenRequest, model?: string): HttpRequest;
|
|
30
|
+
/** Image-to-image edit: image generation plus the source image as a second part. */
|
|
31
|
+
buildEditImageRequest(req: ImageEditRequest, model?: string): HttpRequest;
|
|
15
32
|
generateImage(req: ImageGenRequest, fetch: EngineFetch): Promise<RawMediaResult[]>;
|
|
16
33
|
generateAudio(req: AudioGenRequest, fetch: EngineFetch): Promise<RawMediaResult>;
|
|
17
34
|
/** Image-to-image edit: gemini generateContent with the source image as an
|
|
18
35
|
* extra inline/file part next to the instruction. */
|
|
19
36
|
editImage(req: ImageEditRequest, fetch: EngineFetch): Promise<RawMediaResult[]>;
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
|
|
37
|
+
/** Collect inlineData parts + reported usage from a `:generateContent`
|
|
38
|
+
* response. The request half is `buildGenerateContentRequest`; keeping the two
|
|
39
|
+
* apart is what lets a request be asserted without performing it. */
|
|
40
|
+
private parseGenerateContent;
|
|
23
41
|
submitVideo(req: VideoGenRequest, fetch: EngineFetch): Promise<string>;
|
|
24
42
|
getVideoStatus(operationId: string, fetch: EngineFetch): Promise<VideoStatus>;
|
|
25
43
|
downloadVideo(operationId: string, fetch: EngineFetch): Promise<RawMediaResult>;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Gemini Live models are audio-native: with responseModalities ['AUDIO'] the
|
|
15
15
|
* parts carry inlineData audio, not text. */
|
|
16
|
-
import type { EngineConnect } from '../../../network/types';
|
|
17
|
-
import type { RealtimeProviderAdapter, RealtimeSession, RealtimeSessionConfig } from '../../realtime/types';
|
|
16
|
+
import type { EngineConnect, WsRequest } from '../../../network/types';
|
|
17
|
+
import type { RealtimeInput, RealtimeProviderAdapter, RealtimeSession, RealtimeSessionConfig } from '../../realtime/types';
|
|
18
18
|
export interface GoogleRealtimeAdapterConfig {
|
|
19
19
|
apiKey: string;
|
|
20
20
|
baseURL?: string;
|
|
@@ -23,5 +23,18 @@ export declare class GoogleRealtimeAdapter implements RealtimeProviderAdapter {
|
|
|
23
23
|
private readonly apiKey;
|
|
24
24
|
private readonly base;
|
|
25
25
|
constructor(config: GoogleRealtimeAdapterConfig);
|
|
26
|
+
/** The WebSocket descriptor. Separated from `connect` so it can be asserted
|
|
27
|
+
* without opening a socket. Gemini authenticates with a query-string key and
|
|
28
|
+
* does NOT name the model in the URL — that goes in the setup frame. */
|
|
29
|
+
buildConnectRequest(config: RealtimeSessionConfig): WsRequest;
|
|
26
30
|
connect(config: RealtimeSessionConfig, connect: EngineConnect): RealtimeSession;
|
|
27
31
|
}
|
|
32
|
+
/** The handshake frame. Pure: a function of the session config, so it can be
|
|
33
|
+
* asserted without opening a socket. Gemini Live names the model HERE rather
|
|
34
|
+
* than in the URL, which is the opposite of OpenAI. */
|
|
35
|
+
export declare function buildGoogleSetupFrame(config: RealtimeSessionConfig): Record<string, unknown>;
|
|
36
|
+
/** The frames for one turn. Gemini carries turn completion as a FIELD, where
|
|
37
|
+
* OpenAI signals it by sending a second frame. */
|
|
38
|
+
export declare function buildGoogleTurnFrames(input: RealtimeInput, opts?: {
|
|
39
|
+
turnComplete?: boolean;
|
|
40
|
+
}): Array<Record<string, unknown>>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** OpenAI media adapter — image generation (/v1/images/generations) and TTS
|
|
2
2
|
* (/v1/audio/speech). All HTTP calls flow through an injected EngineFetch
|
|
3
3
|
* so they share the NetworkEngine queue, rate-limits, retry, and hooks. */
|
|
4
|
-
import type { EngineFetch } from '../../../network/types';
|
|
4
|
+
import type { EngineFetch, HttpRequest } from '../../../network/types';
|
|
5
5
|
import type { AudioGenRequest, ImageEditRequest, ImageGenRequest, MediaCapabilities, MediaProviderAdapter, RawMediaResult, VideoGenRequest, VideoStatus } from '../../../plugins/media/types';
|
|
6
6
|
export interface OpenAIMediaAdapterConfig {
|
|
7
7
|
apiKey: string;
|
|
@@ -14,6 +14,15 @@ export declare class OpenAIMediaAdapter implements MediaProviderAdapter {
|
|
|
14
14
|
constructor(config: OpenAIMediaAdapterConfig);
|
|
15
15
|
capabilities(): MediaCapabilities;
|
|
16
16
|
private authHeaders;
|
|
17
|
+
/** Text-to-image. */
|
|
18
|
+
buildGenerateImageRequest(req: ImageGenRequest, model?: string): HttpRequest;
|
|
19
|
+
/** Image-to-image edit. Generation's field set minus `style`, plus the source
|
|
20
|
+
* image and an optional mask. */
|
|
21
|
+
buildEditImageRequest(req: ImageEditRequest, model?: string): HttpRequest;
|
|
22
|
+
/** TTS. `responseType` is arraybuffer because the response is audio bytes. */
|
|
23
|
+
buildAudioRequest(req: AudioGenRequest, model: string): HttpRequest;
|
|
24
|
+
/** Sora video submission. `seconds` goes on the wire as a string. */
|
|
25
|
+
buildVideoRequest(req: VideoGenRequest, model?: string): HttpRequest;
|
|
17
26
|
generateImage(req: ImageGenRequest, fetch: EngineFetch): Promise<RawMediaResult[]>;
|
|
18
27
|
/** Parse `/v1/images/{generations,edits}` response → RawMediaResult[], with
|
|
19
28
|
* the request-level usage attached to the first item (billed once). */
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* response.output_audio.delta → { audio, base64 delta }
|
|
11
11
|
* response.done → turn complete
|
|
12
12
|
* error → error */
|
|
13
|
-
import type { EngineConnect } from '../../../network/types';
|
|
14
|
-
import type { RealtimeProviderAdapter, RealtimeSession, RealtimeSessionConfig } from '../../realtime/types';
|
|
13
|
+
import type { EngineConnect, WsRequest } from '../../../network/types';
|
|
14
|
+
import type { RealtimeInput, RealtimeProviderAdapter, RealtimeSession, RealtimeSessionConfig } from '../../realtime/types';
|
|
15
15
|
export interface OpenAIRealtimeAdapterConfig {
|
|
16
16
|
apiKey: string;
|
|
17
17
|
baseURL?: string;
|
|
@@ -20,5 +20,18 @@ export declare class OpenAIRealtimeAdapter implements RealtimeProviderAdapter {
|
|
|
20
20
|
private readonly apiKey;
|
|
21
21
|
private readonly baseURL;
|
|
22
22
|
constructor(config: OpenAIRealtimeAdapterConfig);
|
|
23
|
+
/** The WebSocket descriptor. Separated from `connect` so it can be asserted
|
|
24
|
+
* without opening a socket. Note the auth: OpenAI carries the key in a
|
|
25
|
+
* SUBPROTOCOL, not a header or query param, because browsers cannot set
|
|
26
|
+
* WebSocket headers. */
|
|
27
|
+
buildConnectRequest(config: RealtimeSessionConfig): WsRequest;
|
|
23
28
|
connect(config: RealtimeSessionConfig, connect: EngineConnect): RealtimeSession;
|
|
24
29
|
}
|
|
30
|
+
/** The handshake frame, sent once the socket opens. */
|
|
31
|
+
export declare function buildOpenAISessionUpdate(config: Pick<RealtimeSessionConfig, 'modalities' | 'instructions' | 'voice'>): Record<string, unknown>;
|
|
32
|
+
/** The frames for one turn. `response.create` is what asks the model to reply,
|
|
33
|
+
* so `turnComplete: false` withholds it and the turn stays open — where Gemini
|
|
34
|
+
* carries the same meaning as a field on its single frame. */
|
|
35
|
+
export declare function buildOpenAITurnFrames(input: RealtimeInput, opts?: {
|
|
36
|
+
turnComplete?: boolean;
|
|
37
|
+
}): Array<Record<string, unknown>>;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - it's within the retention TTL (catalog duration),
|
|
14
14
|
* - the model matches, OR the provider is not model-bound (catalog).
|
|
15
15
|
* Otherwise we fall back to resending full history (always correct). */
|
|
16
|
-
import type { ModelCatalog } from '../
|
|
16
|
+
import type { ModelCatalog } from '../catalog/catalog';
|
|
17
17
|
import type { Message } from './types/messages';
|
|
18
18
|
import type { ProviderName } from './types/provider';
|
|
19
19
|
export interface ServerStateDecision {
|
|
@@ -3,7 +3,7 @@ import type { ConversationHistory } from '../../agent/history';
|
|
|
3
3
|
import type { RequestContext } from '../../types/request-context';
|
|
4
4
|
import type { ModerationRequest } from '../moderation/types';
|
|
5
5
|
import type { AudioOptions } from './audio';
|
|
6
|
-
import type { CacheConfig, ThinkingConfig } from './request';
|
|
6
|
+
import type { CacheConfig, ProviderOptions, ThinkingConfig } from './request';
|
|
7
7
|
import type { ServiceTier } from './tiers';
|
|
8
8
|
import type { Tool, ToolChoice } from './tools';
|
|
9
9
|
export interface ExecuteOptions {
|
|
@@ -65,7 +65,7 @@ export interface ExecuteOptions {
|
|
|
65
65
|
* OpenAI runs it natively; other providers are emulated via OpenAI's
|
|
66
66
|
* moderations endpoint. See ModerationRequest. */
|
|
67
67
|
moderation?: ModerationRequest;
|
|
68
|
-
providerOptions?:
|
|
68
|
+
providerOptions?: ProviderOptions;
|
|
69
69
|
previousResponseId?: string;
|
|
70
70
|
/** Server-state optimization: when the prior assistant turn carries a usable
|
|
71
71
|
* server id (same provider, within TTL, model ok), send the id + only the new
|
|
@@ -4,10 +4,54 @@
|
|
|
4
4
|
* and system are fixed at construction. The LLMClient internally builds
|
|
5
5
|
* this `NormalizedRequest` from (input, options, this.model, this.system). */
|
|
6
6
|
import type { ModerationRequest } from '../moderation/types';
|
|
7
|
+
import type { ModelWire } from '../../catalog/catalog';
|
|
7
8
|
import type { AudioOptions } from './audio';
|
|
8
9
|
import type { Message } from './messages';
|
|
9
10
|
import type { ServiceTier } from './tiers';
|
|
10
11
|
import type { Tool, ToolChoice } from './tools';
|
|
12
|
+
/** Provider-specific request options that have no unified equivalent.
|
|
13
|
+
*
|
|
14
|
+
* This was `Record<string, unknown>` — the one untyped hole in the request, and
|
|
15
|
+
* therefore the one place a typo produced silence rather than an error:
|
|
16
|
+
* `promtCacheOptions` type-checked and was simply never sent.
|
|
17
|
+
*
|
|
18
|
+
* Every key below is one an adapter actually reads; the list is derived from
|
|
19
|
+
* the read sites, not invented. The index signature stays so a caller can still
|
|
20
|
+
* pass something the SDK does not know about yet — a provider ships a parameter
|
|
21
|
+
* before we model it, and refusing it would make the escape hatch useless. What
|
|
22
|
+
* changed is that the keys we DO know are checked and discoverable.
|
|
23
|
+
*
|
|
24
|
+
* Keys are grouped by the provider that consumes them; sending one to a
|
|
25
|
+
* different provider is ignored, not an error. */
|
|
26
|
+
export interface ProviderOptions {
|
|
27
|
+
/** Forwarded as the `anthropic-user-profile-id` header: identifies the end
|
|
28
|
+
* user a request acts on behalf of. Needs the account-level
|
|
29
|
+
* `user-profiles` beta. */
|
|
30
|
+
userProfileId?: string;
|
|
31
|
+
/** Native moderation policy, sent alongside the `moderation` request field. */
|
|
32
|
+
moderationPolicy?: Record<string, unknown>;
|
|
33
|
+
/** `prompt_cache_options` — OpenAI-only prompt-cache controls. */
|
|
34
|
+
promptCacheOptions?: Record<string, unknown>;
|
|
35
|
+
/** `reasoning.mode` on the Responses API. */
|
|
36
|
+
reasoningMode?: 'standard' | 'pro';
|
|
37
|
+
/** Overrides `generationConfig.responseModalities`, e.g. for image or audio
|
|
38
|
+
* generation. Wins over the modality implied by `outputModalities`. */
|
|
39
|
+
responseModalities?: string[];
|
|
40
|
+
/** `generationConfig.speechConfig` — voice selection for audio output. */
|
|
41
|
+
speechConfig?: Record<string, unknown>;
|
|
42
|
+
/** `generationConfig.imageConfig` — aspect ratio / size for image output. */
|
|
43
|
+
imageConfig?: Record<string, unknown>;
|
|
44
|
+
/** `generationConfig.translationConfig`. */
|
|
45
|
+
translationConfig?: Record<string, unknown>;
|
|
46
|
+
/** Name of a cached-content handle to reuse. Forwarded only when it is a
|
|
47
|
+
* non-empty string. */
|
|
48
|
+
cachedContent?: string;
|
|
49
|
+
/** Routing options merged into the request body (provider order, transforms,
|
|
50
|
+
* and the rest of OpenRouter's routing surface). */
|
|
51
|
+
openrouter?: Record<string, unknown>;
|
|
52
|
+
/** Anything the SDK does not model yet. Adapters ignore what they do not read. */
|
|
53
|
+
[key: string]: unknown;
|
|
54
|
+
}
|
|
11
55
|
export interface NormalizedRequest {
|
|
12
56
|
/** From LLMClientConfig.model — fixed at construction. */
|
|
13
57
|
model: string;
|
|
@@ -47,7 +91,12 @@ export interface NormalizedRequest {
|
|
|
47
91
|
cache?: CacheConfig;
|
|
48
92
|
serviceTier?: ServiceTier;
|
|
49
93
|
moderation?: ModerationRequest;
|
|
50
|
-
providerOptions?:
|
|
94
|
+
providerOptions?: ProviderOptions;
|
|
95
|
+
/** Wire traits for THIS model, resolved from the catalog by `LLMClient`.
|
|
96
|
+
* Adapters prefer this over parsing the model id. Absent when the engine runs
|
|
97
|
+
* without a catalog or the model is not catalogued, in which case adapters
|
|
98
|
+
* fall back to the id. */
|
|
99
|
+
wire?: ModelWire;
|
|
51
100
|
audio?: AudioOptions;
|
|
52
101
|
outputModalities?: Array<'text' | 'audio'>;
|
|
53
102
|
previousResponseId?: string;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { Message } from '../../../llm/types/messages';
|
|
3
3
|
import type { TokenCountContext, TokenCounter, LearnInput } from '../../../agent/types';
|
|
4
4
|
import type { FetchFn } from '../../../network/types';
|
|
5
|
-
import type { ModelCatalog } from '
|
|
5
|
+
import type { ModelCatalog } from '../../../catalog/catalog';
|
|
6
6
|
/** Anthropic count endpoint: POST /v1/messages/count_tokens */
|
|
7
7
|
export declare class AnthropicCountApi {
|
|
8
8
|
private readonly apiKey;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Heuristic token counter — chars-per-token with optional calibration. */
|
|
2
2
|
import type { Message } from '../../../llm/types/messages';
|
|
3
3
|
import type { TokenCountContext, TokenCounter, LearnInput } from '../../../agent/types';
|
|
4
|
-
import type { ModelCatalog } from '
|
|
4
|
+
import type { ModelCatalog } from '../../../catalog/catalog';
|
|
5
5
|
import type { CalibrationStore } from '../types';
|
|
6
6
|
/** Count chars across a message's content parts. */
|
|
7
7
|
export declare function messageChars(msg: Message): number;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** HybridTokenCounter — selects strategy per model based on catalog config. */
|
|
2
2
|
import type { Message } from '../../../llm/types/messages';
|
|
3
3
|
import type { TokenCountContext, TokenCounter, LearnInput } from '../../../agent/types';
|
|
4
|
-
import type { ModelCatalog } from '
|
|
4
|
+
import type { ModelCatalog } from '../../../catalog/catalog';
|
|
5
5
|
import type { CalibrationStore } from '../types';
|
|
6
6
|
export interface HybridCounterConfig {
|
|
7
7
|
catalog?: ModelCatalog;
|
|
@@ -4,7 +4,7 @@ import type { HookBus } from '../../bus/hook-bus';
|
|
|
4
4
|
import type { Message } from '../../llm/types/messages';
|
|
5
5
|
import type { TokenCounter } from '../../agent/types';
|
|
6
6
|
import type { ConversationHistory } from '../../agent/history';
|
|
7
|
-
import type { ModelCatalog } from '
|
|
7
|
+
import type { ModelCatalog } from '../../catalog/catalog';
|
|
8
8
|
import type { Persistence } from '../persistence/types';
|
|
9
9
|
import type { CalibrationStore, ContextThresholds, CalibrationConfig } from './types';
|
|
10
10
|
export interface ContextMeasurerConfig {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* pricing or provider-reported totals, emits onCostEntry/onBudgetWarning/
|
|
3
3
|
* onBudgetExceeded. */
|
|
4
4
|
import type { CostEntry } from '../../bus/hook-map';
|
|
5
|
-
import type { ModelCatalog } from '
|
|
5
|
+
import type { ModelCatalog } from '../../catalog/catalog';
|
|
6
6
|
import type { Budget, CostCollectorConfig, CostFilter, CostSummary } from './cost-collector-types';
|
|
7
7
|
export declare class CostCollector {
|
|
8
8
|
private ledger;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** CostCollector internals — pure cost-math + filtering helpers, split out of
|
|
2
2
|
* the class so each is independently testable. */
|
|
3
3
|
import type { CostEntry } from '../../bus/hook-map';
|
|
4
|
-
import type { ModelCatalog } from '
|
|
4
|
+
import type { ModelCatalog } from '../../catalog/catalog';
|
|
5
5
|
import type { CostFilter, CostSummary } from './cost-collector-types';
|
|
6
6
|
/** Pull provider-reported cost evidence out of a raw response body. */
|
|
7
7
|
export declare function extractProviderCost(provider: string, raw: unknown): Record<string, unknown>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** CostCollector public types: config, budgets, filters, summaries. */
|
|
2
2
|
import type { HookBus } from '../../bus/hook-bus';
|
|
3
|
-
import type { ModelCatalog } from '
|
|
3
|
+
import type { ModelCatalog } from '../../catalog/catalog';
|
|
4
4
|
export interface CostCollectorConfig {
|
|
5
5
|
hooks: HookBus;
|
|
6
6
|
catalog: ModelCatalog;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* parts (provider_ref / inline base64 / url). */
|
|
4
4
|
import type { HookBus } from '../../bus/hook-bus';
|
|
5
5
|
import type { EngineFetch } from '../../network/types';
|
|
6
|
-
import type { ModelCatalog } from '
|
|
6
|
+
import type { ModelCatalog } from '../../catalog/catalog';
|
|
7
7
|
import { FileAttachment, type FileContent } from './attachment';
|
|
8
8
|
import type { FileProviderAdapter, RemoteFileInfo } from './provider-adapter';
|
|
9
9
|
import { type FileStrategy } from './strategy';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** FileStrategy — pluggable decision maker for how to attach files. */
|
|
2
|
-
import type { ModelInfo } from '
|
|
2
|
+
import type { ModelInfo } from '../../catalog/catalog';
|
|
3
3
|
import type { FileAttachment } from './attachment';
|
|
4
4
|
export interface FileStrategyContext {
|
|
5
5
|
file: FileAttachment;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** ToolRegistry — unified access across multiple backends with caching, search, filtering. */
|
|
2
2
|
import type { InternalTool, ToolBackend, ToolFilter, SearchOptions } from './types';
|
|
3
|
-
import type { ModelCatalog } from '
|
|
3
|
+
import type { ModelCatalog } from '../../catalog/catalog';
|
|
4
4
|
export declare class ToolRegistry {
|
|
5
5
|
private backends;
|
|
6
6
|
private cache;
|
|
@@ -3,7 +3,7 @@ import type { HookBus } from '../../../bus/hook-bus';
|
|
|
3
3
|
import type { LLMClientConfig } from '../../../llm/client-config';
|
|
4
4
|
import type { ProviderName } from '../../../llm/types/provider';
|
|
5
5
|
import type { JsonSchema } from '../../../llm/types/tools';
|
|
6
|
-
import type { ModelCatalog } from '
|
|
6
|
+
import type { ModelCatalog } from '../../../catalog/catalog';
|
|
7
7
|
import type { ToolRegistry } from '../registry';
|
|
8
8
|
import type { CompatFile, ModelPreference } from '../types';
|
|
9
9
|
import type { TokenCounter } from '../../../agent/types';
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* custom handler or a model id to auto-wire. */
|
|
5
5
|
import type { EngineHandle } from '../../helpers/engine';
|
|
6
6
|
import type { ProviderName } from '../../llm/types/provider';
|
|
7
|
+
import type { Message } from '../../llm/types/messages';
|
|
7
8
|
import type { McpCreateMessageParams, McpCreateMessageResult } from './types';
|
|
8
9
|
export type McpSamplingHandler = (params: McpCreateMessageParams) => Promise<McpCreateMessageResult>;
|
|
9
10
|
/** Auto-wire sampling to our LLM. */
|
|
@@ -13,5 +14,26 @@ export interface McpSamplingViaLLM {
|
|
|
13
14
|
engine?: EngineHandle;
|
|
14
15
|
}
|
|
15
16
|
export type McpSamplingConfig = McpSamplingHandler | McpSamplingViaLLM;
|
|
17
|
+
/** The one thing this module needs from the ergonomic layer: run a completion.
|
|
18
|
+
*
|
|
19
|
+
* Taken as a parameter rather than imported, because `plugins` importing
|
|
20
|
+
* `helpers` closed a cycle (`helpers` already imports most of `plugins`). The
|
|
21
|
+
* public `samplingHandler` lives in `helpers/mcp` and supplies `complete`; the
|
|
22
|
+
* mapping between MCP's message shape and ours stays here, where it belongs. */
|
|
23
|
+
export type McpCompleteFn = (args: {
|
|
24
|
+
model: string;
|
|
25
|
+
provider?: ProviderName;
|
|
26
|
+
engine?: EngineHandle;
|
|
27
|
+
system?: string;
|
|
28
|
+
prompt: Message[];
|
|
29
|
+
maxTokens?: number;
|
|
30
|
+
temperature?: number;
|
|
31
|
+
}) => Promise<{
|
|
32
|
+
text: string;
|
|
33
|
+
response: {
|
|
34
|
+
model: string;
|
|
35
|
+
finishReason: string;
|
|
36
|
+
};
|
|
37
|
+
}>;
|
|
16
38
|
/** Build a sampling handler: pass-through a custom function, or auto-wire a model. */
|
|
17
|
-
export declare function
|
|
39
|
+
export declare function samplingHandlerWith(complete: McpCompleteFn, config: McpSamplingConfig): McpSamplingHandler;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* by core LLM adapters + an onCompletion subscriber, NOT this class. */
|
|
8
8
|
import type { HookBus } from '../../bus/hook-bus';
|
|
9
9
|
import type { EngineFetch } from '../../network/types';
|
|
10
|
-
import type { ModelCatalog } from '
|
|
10
|
+
import type { ModelCatalog } from '../../catalog/catalog';
|
|
11
11
|
import { type AudioGenRequest, type ImageEditRequest, type ImageGenRequest, type MediaOutputConfig, type MediaProviderAdapter, type MediaResult, type MediaStore, type VideoGenRequest } from './types';
|
|
12
12
|
export interface MediaOutputInit {
|
|
13
13
|
hooks: HookBus;
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* An in-memory store backs the sandbox sidebar; `toOtlpTraces()` shapes spans
|
|
11
11
|
* into OTLP-compatible JSON for a real OTel exporter to forward. */
|
|
12
12
|
import type { HookBus } from '../../bus/hook-bus';
|
|
13
|
-
|
|
13
|
+
export type { Span, SpanKind, TelemetryAdapterOptions, TelemetryEvent, TelemetryMetrics, TelemetryResource, TraceEvent, TraceEventType, TraceFilter, TraceHandler, } from './types';
|
|
14
|
+
import type { Span, TelemetryAdapterOptions, TelemetryEvent, TelemetryMetrics, TelemetryResource, TraceFilter, TraceHandler } from './types';
|
|
14
15
|
/** Derive a conformant hex id from one of our readable ids. `bytes` is 16 for a trace
|
|
15
16
|
* id, 8 for a span id.
|
|
16
17
|
*
|
|
@@ -22,81 +23,6 @@ export declare function toOtlpId(input: string, bytes: 8 | 16): string;
|
|
|
22
23
|
* `intValue` carrying a STRING, which is how OTLP/JSON encodes 64-bit integers; send
|
|
23
24
|
* them as plain strings instead and no backend can sum them. */
|
|
24
25
|
export declare function toOtlpValue(value: unknown): Record<string, unknown>;
|
|
25
|
-
export type SpanKind = 'llm' | 'http' | 'media' | 'agent' | 'tool' | 'mcp' | 'other';
|
|
26
|
-
export interface Span {
|
|
27
|
-
traceId: string;
|
|
28
|
-
spanId: string;
|
|
29
|
-
/** The span this one runs under. Without it every span is a sibling and a backend
|
|
30
|
-
* draws a flat list instead of a tree — so a run reads as "9 things happened", not
|
|
31
|
-
* "a turn, which called a tool, which asked a second model".
|
|
32
|
-
*
|
|
33
|
-
* Resolved in this order: the innermost container span still open on this trace
|
|
34
|
-
* (`agent.run` / `tool.call`), else the app's span from a supplied `traceparent`,
|
|
35
|
-
* else none — this span is the root. */
|
|
36
|
-
parentSpanId?: string;
|
|
37
|
-
name: string;
|
|
38
|
-
kind: SpanKind;
|
|
39
|
-
startTime: number;
|
|
40
|
-
endTime?: number;
|
|
41
|
-
durationMs?: number;
|
|
42
|
-
status: 'unset' | 'ok' | 'error';
|
|
43
|
-
attributes: Record<string, unknown>;
|
|
44
|
-
}
|
|
45
|
-
/** What kind of work an event describes. `message` is conversation content, which is not
|
|
46
|
-
* a span — it is the thing you want in a debug store and NOT in your metrics backend,
|
|
47
|
-
* which is exactly why it filters separately. */
|
|
48
|
-
export type TraceEventType = 'agent' | 'tool' | 'llm' | 'http' | 'mcp' | 'media' | 'message' | 'other';
|
|
49
|
-
/** One piece of work, carrying enough of the tree that a consumer can push it straight
|
|
50
|
-
* into their own tracer without reconstructing anything. */
|
|
51
|
-
export interface TraceEvent {
|
|
52
|
-
type: TraceEventType;
|
|
53
|
-
/** The app's trace when it supplied a `traceparent`, else ours. */
|
|
54
|
-
traceId: string;
|
|
55
|
-
spanId: string;
|
|
56
|
-
/** Already resolved past anything this subscriber filtered out — see `survivingParent`. */
|
|
57
|
-
parentSpanId?: string;
|
|
58
|
-
/** The conventional name (`chat gpt-5.4-nano`, `execute_tool search`). */
|
|
59
|
-
name: string;
|
|
60
|
-
startTime: number;
|
|
61
|
-
endTime?: number;
|
|
62
|
-
durationMs?: number;
|
|
63
|
-
status: 'unset' | 'ok' | 'error';
|
|
64
|
-
attributes: Record<string, unknown>;
|
|
65
|
-
}
|
|
66
|
-
/** Declarative on purpose, rather than a predicate: knowing the types up front lets a
|
|
67
|
-
* filtered-out event cost nothing, where a predicate would force us to build the payload
|
|
68
|
-
* just to let the caller throw it away. */
|
|
69
|
-
export interface TraceFilter {
|
|
70
|
-
types?: readonly TraceEventType[];
|
|
71
|
-
}
|
|
72
|
-
export type TraceHandler = (event: TraceEvent) => void;
|
|
73
|
-
export interface TelemetryEvent {
|
|
74
|
-
seq: number;
|
|
75
|
-
time: number;
|
|
76
|
-
name: HookName;
|
|
77
|
-
category: string;
|
|
78
|
-
traceId?: string;
|
|
79
|
-
ctx: unknown;
|
|
80
|
-
}
|
|
81
|
-
export interface TelemetryMetrics {
|
|
82
|
-
requests: number;
|
|
83
|
-
errors: number;
|
|
84
|
-
retries: number;
|
|
85
|
-
rateLimitHits: number;
|
|
86
|
-
completions: number;
|
|
87
|
-
mediaGenerated: number;
|
|
88
|
-
costUsd: number;
|
|
89
|
-
inputTokens: number;
|
|
90
|
-
outputTokens: number;
|
|
91
|
-
inFlight: number;
|
|
92
|
-
queueDepth: number;
|
|
93
|
-
latency: {
|
|
94
|
-
count: number;
|
|
95
|
-
min: number;
|
|
96
|
-
max: number;
|
|
97
|
-
avg: number;
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
26
|
/** Parse a W3C `traceparent`: `00-<32 hex trace>-<16 hex span>-<flags>`.
|
|
101
27
|
* Returns null for anything malformed or for the all-zero ids the spec forbids —
|
|
102
28
|
* a bad header must not silently reroute telemetry into a garbage trace. */
|
|
@@ -104,63 +30,6 @@ export declare function parseTraceparent(value: string | undefined): {
|
|
|
104
30
|
traceId: string;
|
|
105
31
|
spanId: string;
|
|
106
32
|
} | null;
|
|
107
|
-
/** OpenTelemetry Resource — identifies the SERVICE producing this telemetry, so
|
|
108
|
-
* a shared backend can separate streams from different apps and attribute cost
|
|
109
|
-
* per service (`sum by service.name`). Stamped on every span/metric/log. */
|
|
110
|
-
export interface TelemetryResource {
|
|
111
|
-
/** Primary grouping key, e.g. "billing-api". OTel default: "unknown_service". */
|
|
112
|
-
serviceName: string;
|
|
113
|
-
/** Optional namespace/group, e.g. "prod" or a team. */
|
|
114
|
-
serviceNamespace?: string;
|
|
115
|
-
/** Unique instance (pod/host/process); a good default is the engine sessionId. */
|
|
116
|
-
serviceInstanceId?: string;
|
|
117
|
-
serviceVersion?: string;
|
|
118
|
-
/** Arbitrary resource attributes (deployment.environment, cloud.region, …). */
|
|
119
|
-
attributes?: Record<string, string>;
|
|
120
|
-
}
|
|
121
|
-
export interface TelemetryAdapterOptions {
|
|
122
|
-
/** Cap on retained events (ring buffer). Default 2000. */
|
|
123
|
-
maxEvents?: number;
|
|
124
|
-
/** Service identity stamped on all exported telemetry. */
|
|
125
|
-
resource?: TelemetryResource;
|
|
126
|
-
/** Whether provider error TEXT may be stored in telemetry. Default `true`
|
|
127
|
-
* (unchanged behaviour, and the same default as the OpenAI Agents SDK's
|
|
128
|
-
* `trace_include_sensitive_data`).
|
|
129
|
-
*
|
|
130
|
-
* A provider's `error.message` / `error.raw` can echo request content back —
|
|
131
|
-
* a moderation refusal quotes the prompt, a validation error names the offending
|
|
132
|
-
* field and value. URLs and headers are always redacted regardless; this switch
|
|
133
|
-
* governs the free-text payload. Set `false` when telemetry leaves your trust
|
|
134
|
-
* boundary (a shared collector, a vendor APM) and the message is replaced by a
|
|
135
|
-
* fixed `[redacted]` string while name/code/status are kept for triage. */
|
|
136
|
-
includeSensitiveData?: boolean;
|
|
137
|
-
/** Which event types to hand to `onTrace`. Omitted → everything.
|
|
138
|
-
*
|
|
139
|
-
* Filtering SPLICES the tree rather than punching holes in it: drop `http` and the
|
|
140
|
-
* spans under it re-parent to the nearest surviving ancestor. Dropping without that
|
|
141
|
-
* leaves orphans, and a backend draws an orphan as a second root — worse than not
|
|
142
|
-
* filtering at all. */
|
|
143
|
-
types?: readonly TraceEventType[];
|
|
144
|
-
/** Whether conversation content rides along on `message` events. Default `'none'`:
|
|
145
|
-
* prompts and completions are the debugging gold AND the PII, so sending them is a
|
|
146
|
-
* decision to make on purpose rather than inherit. `'full'` adds the Opt-In
|
|
147
|
-
* `gen_ai.input.messages` / `gen_ai.output.messages` attributes; `'none'` still
|
|
148
|
-
* reports the shape (counts and sizes), which is enough to spot a runaway prompt. */
|
|
149
|
-
content?: 'none' | 'full';
|
|
150
|
-
/** Fraction of TRACES to emit, 0..1. Default 1.
|
|
151
|
-
*
|
|
152
|
-
* Per trace, never per span: sampling spans independently shreds every tree it touches
|
|
153
|
-
* — a tool call with no run, a model call with no tool. The decision is a hash of the
|
|
154
|
-
* trace id, so it is stable across processes and two services sharing a trace agree
|
|
155
|
-
* without coordinating.
|
|
156
|
-
*
|
|
157
|
-
* This is HEAD sampling: the choice is made when the trace first appears, before we
|
|
158
|
-
* know whether it ends in an error. Keeping all errors needs tail sampling, which
|
|
159
|
-
* needs buffering; do that in your collector, which is built for it. */
|
|
160
|
-
sample?: number;
|
|
161
|
-
/** Convenience for the common case of a single sink — same as calling `onTrace`. */
|
|
162
|
-
onTrace?: TraceHandler;
|
|
163
|
-
}
|
|
164
33
|
export declare class TelemetryAdapter {
|
|
165
34
|
readonly events: TelemetryEvent[];
|
|
166
35
|
readonly spans: Span[];
|