@combycode/llm-sdk 2.0.1 → 2.2.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 +289 -3
- package/dist/agent/context-registry/layers.d.ts +19 -0
- package/dist/agent/lazy-tools.d.ts +85 -0
- package/dist/agent/loop-config.d.ts +28 -0
- package/dist/agent/loop-internals.d.ts +13 -0
- package/dist/agent/loop.d.ts +33 -1
- package/dist/agent/types.d.ts +15 -0
- package/dist/bus/hook-map.d.ts +20 -0
- package/dist/helpers/define-tool.d.ts +15 -6
- package/dist/helpers/engine.d.ts +36 -1
- package/dist/helpers/mcp.d.ts +9 -0
- package/dist/helpers/moderate.d.ts +13 -1
- package/dist/helpers/one-shot.d.ts +19 -0
- package/dist/index.browser.js +850 -76
- package/dist/index.d.ts +11 -4
- package/dist/index.js +850 -76
- package/dist/llm/types/schema-utils.d.ts +19 -0
- package/dist/network/engine.d.ts +10 -2
- package/dist/network/queue-state-config.d.ts +10 -2
- package/dist/network/types.d.ts +6 -0
- package/dist/plugins/cost-collector/collector.d.ts +12 -0
- package/dist/plugins/cost-collector/cost-collector-types.d.ts +8 -0
- package/dist/plugins/mcp/result-cache.d.ts +8 -1
- package/dist/plugins/mcp/tools.d.ts +2 -0
- package/dist/plugins/mcp/types.d.ts +43 -0
- package/dist/plugins/telemetry/telemetry.d.ts +144 -0
- package/dist/types/request-context.d.ts +11 -0
- package/package.json +5 -2
|
@@ -50,17 +50,26 @@ type InferParam<S> = S extends 'string' ? string : S extends 'number' | 'integer
|
|
|
50
50
|
} ? number : S extends {
|
|
51
51
|
type: 'boolean';
|
|
52
52
|
} ? boolean : unknown;
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
/** Keys named in `optional` are optional HERE TOO. Typing them as always-present is
|
|
54
|
+
* a lie the compiler then helps enforce: `args.unit.toUpperCase()` typechecks and
|
|
55
|
+
* throws at runtime whenever the model omits the argument — which, for an argument
|
|
56
|
+
* declared optional, is the expected case rather than the edge one. */
|
|
57
|
+
type InferArgs<P extends Record<string, ParamSpec>, O extends keyof P = never> = {
|
|
58
|
+
[K in Exclude<keyof P, O>]: InferParam<P[K]>;
|
|
59
|
+
} & {
|
|
60
|
+
[K in Extract<O, keyof P>]?: InferParam<P[K]>;
|
|
55
61
|
};
|
|
56
|
-
export interface DefineToolInput<P extends Record<string, ParamSpec
|
|
62
|
+
export interface DefineToolInput<P extends Record<string, ParamSpec>, O extends keyof P & string = never> {
|
|
57
63
|
name: string;
|
|
58
64
|
description: string;
|
|
59
65
|
/** Object spec — keys are arg names. All keys are treated as required by
|
|
60
66
|
* default; mark optional ones via `optional: ['x']`. */
|
|
61
67
|
params: P;
|
|
62
|
-
optional?:
|
|
63
|
-
|
|
68
|
+
optional?: readonly O[];
|
|
69
|
+
/** Register the tool without declaring it — the model finds it via `tool_search` and
|
|
70
|
+
* calls it through `call_tool`. See `AgentTool.lazy`. */
|
|
71
|
+
lazy?: boolean;
|
|
72
|
+
execute: (args: InferArgs<P, O>, context: ToolExecutionContext) => Promise<string | ContentPart[]> | string | ContentPart[];
|
|
64
73
|
}
|
|
65
|
-
export declare function defineTool<P extends Record<string, ParamSpec
|
|
74
|
+
export declare function defineTool<P extends Record<string, ParamSpec>, const O extends keyof P & string = never>(input: DefineToolInput<P, O>): AgentTool;
|
|
66
75
|
export {};
|
package/dist/helpers/engine.d.ts
CHANGED
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
import { AgentBus } from '../bus/agent-bus';
|
|
19
19
|
import { HookBus } from '../bus/hook-bus';
|
|
20
20
|
import type { ProviderName } from '../llm/types/provider';
|
|
21
|
-
import { NetworkEngine } from '../network/engine';
|
|
21
|
+
import { NetworkEngine, type QueueSettings } from '../network/engine';
|
|
22
|
+
import type { RetryPolicyOverride } from '../network/queue-state-config';
|
|
22
23
|
import type { EngineConnect, EngineFetch, EngineFetchStream, FetchFn } from '../network/types';
|
|
23
24
|
import { Cache } from '../plugins/cache/cache';
|
|
24
25
|
import { CostCollector } from '../plugins/cost-collector/collector';
|
|
25
26
|
import { ModelCatalog } from '../plugins/model-catalog/catalog';
|
|
27
|
+
import { TelemetryAdapter, type TelemetryAdapterOptions } from '../plugins/telemetry/telemetry';
|
|
26
28
|
import type { Persistence } from '../plugins/persistence/types';
|
|
27
29
|
export interface EngineHandle {
|
|
28
30
|
/** Trace session id — minted once for this engine (the holder), shared by
|
|
@@ -53,6 +55,10 @@ export interface EngineHandle {
|
|
|
53
55
|
/** CostCollector — subscribes to onCompletion + onMediaGenerated and
|
|
54
56
|
* prices via catalog. Call `engine.cost.total()` for a running tally. */
|
|
55
57
|
cost: CostCollector;
|
|
58
|
+
/** TelemetryAdapter — present only when `telemetry` was configured, because an
|
|
59
|
+
* unwanted one would sit there accumulating spans for a process that never reads
|
|
60
|
+
* them. Subscribe with `engine.telemetry.onTrace(...)`, or use it directly. */
|
|
61
|
+
telemetry: TelemetryAdapter | null;
|
|
56
62
|
/** API keys per provider. Helpers (createLLM, createAgent,
|
|
57
63
|
* createMediaOutput, complete) read these to wire LLM clients without
|
|
58
64
|
* the caller passing apiKey explicitly. */
|
|
@@ -94,6 +100,35 @@ export interface EngineConfig {
|
|
|
94
100
|
/** Per-provider API keys. Helpers consult this when no apiKey is passed
|
|
95
101
|
* alongside `model: 'provider/...'`. */
|
|
96
102
|
apiKeys?: Partial<Record<ProviderName, string>>;
|
|
103
|
+
/** Observability. Omitted → no adapter is built and nothing is collected.
|
|
104
|
+
*
|
|
105
|
+
* ```ts
|
|
106
|
+
* createEngine({
|
|
107
|
+
* telemetry: {
|
|
108
|
+
* types: ['agent', 'tool'], // http/llm detail stays out
|
|
109
|
+
* content: 'none', // conversation text off by default
|
|
110
|
+
* sample: 0.05, // per trace, not per span
|
|
111
|
+
* onTrace: (e) => myPipeline.push(e),
|
|
112
|
+
* },
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
telemetry?: TelemetryAdapterOptions;
|
|
117
|
+
/** Retry policy for every request this engine makes.
|
|
118
|
+
*
|
|
119
|
+
* Retry is a cross-cutting concern, so it is configured once here rather than threaded through
|
|
120
|
+
* each call. Anything omitted falls back to the built-in policy (`DEFAULT_RETRY`).
|
|
121
|
+
*
|
|
122
|
+
* ```ts
|
|
123
|
+
* createEngine({ retry: { maxRetries: 5, backoff: { initialMs: 200, maxMs: 8_000 } } });
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* Three layers, narrowest wins: `HttpRequest.retry` (one request) > `queues[name].retry`
|
|
127
|
+
* (one provider queue) > this (everything). */
|
|
128
|
+
retry?: RetryPolicyOverride;
|
|
129
|
+
/** Per-queue overrides, keyed by queue name (`provider/model` unless routed otherwise).
|
|
130
|
+
* Use when one provider needs a different policy from the rest. */
|
|
131
|
+
queues?: Record<string, QueueSettings>;
|
|
97
132
|
/** Register this engine as the default for `coreRegistry.get()` (used by
|
|
98
133
|
* helpers when the caller doesn't pass an explicit `engine`). Defaults to
|
|
99
134
|
* `true` so `createEngine({ ... })` followed by helper calls just works.
|
package/dist/helpers/mcp.d.ts
CHANGED
|
@@ -40,6 +40,15 @@ export interface ConnectMcpOptions {
|
|
|
40
40
|
roots?: McpRoot[] | (() => McpRoot[] | Promise<McpRoot[]>);
|
|
41
41
|
/** Validate tool `structuredContent` against the tool's `outputSchema`. */
|
|
42
42
|
validateOutput?: boolean;
|
|
43
|
+
/** Register this server's tools WITHOUT declaring them: the model finds them with
|
|
44
|
+
* `tool_search` and calls them through `call_tool`. Exposure only — every tool is
|
|
45
|
+
* still registered, namespaced and collision-checked exactly as today.
|
|
46
|
+
*
|
|
47
|
+
* This is the common case for the feature, since an MCP server is where a large tool
|
|
48
|
+
* block usually comes from. Measured over 308 tools: identical correctness, −72% cost
|
|
49
|
+
* per task on claude-haiku-4.5 and −97% on gpt-5.4-nano, for one extra round trip.
|
|
50
|
+
* Not worth it for a small server — see `AgentTool.lazy`. */
|
|
51
|
+
lazy?: boolean;
|
|
43
52
|
/** Send a `ping` every N ms to keep the connection alive (0 = off).
|
|
44
53
|
* Ignored on a 2026-07-28 session, where `ping` no longer exists. */
|
|
45
54
|
keepAliveMs?: number;
|
|
@@ -9,5 +9,17 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The moderations endpoint is FREE; an honest-zero cost entry is always emitted
|
|
11
11
|
* so the cost ledger has a record of each call. HTTP flows through engine.fetch. */
|
|
12
|
-
import type { ModerateOptions, ModerationResult } from './moderate-types';
|
|
12
|
+
import type { ModerateOptions, ModerationContentPart, ModerationResult } from './moderate-types';
|
|
13
|
+
/** One input in, one result out: a single string, or one content-part array that
|
|
14
|
+
* together forms a single multimodal item. */
|
|
15
|
+
export declare function moderate(opts: ModerateOptions & {
|
|
16
|
+
input: string | ModerationContentPart[];
|
|
17
|
+
}): Promise<ModerationResult>;
|
|
18
|
+
/** Many inputs in, one result each, in the same order. */
|
|
19
|
+
export declare function moderate(opts: ModerateOptions & {
|
|
20
|
+
input: string[] | ModerationContentPart[][];
|
|
21
|
+
}): Promise<ModerationResult[]>;
|
|
22
|
+
/** Fallback for a caller holding the wide `ModerateOptions['input']` union: the
|
|
23
|
+
* arity is only knowable at runtime, so the union comes back. Kept so existing
|
|
24
|
+
* code that already narrows the result keeps compiling. */
|
|
13
25
|
export declare function moderate(opts: ModerateOptions): Promise<ModerationResult | ModerationResult[]>;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* LLMClient.complete. Either way the helper destroys its created client
|
|
16
16
|
* before returning so callers don't leak. */
|
|
17
17
|
import type { AgentTool } from '../agent/types';
|
|
18
|
+
import type { CacheConfig } from '../llm/types/request';
|
|
18
19
|
import type { LLMClientConfig } from '../llm/client-config';
|
|
19
20
|
import type { AudioOptions } from '../llm/types/audio';
|
|
20
21
|
import type { ContentPart, Message } from '../llm/types/messages';
|
|
@@ -51,6 +52,12 @@ export interface CompleteOptions {
|
|
|
51
52
|
/** Generation control. */
|
|
52
53
|
maxTokens?: number;
|
|
53
54
|
temperature?: number;
|
|
55
|
+
/** Top-k sampling. Emitted only where the wire accepts it (Anthropic, Google, xAI,
|
|
56
|
+
* OpenRouter) and dropped for OpenAI, which defines no top-k. */
|
|
57
|
+
topK?: number;
|
|
58
|
+
/** Best-effort deterministic sampling. Dropped on Anthropic, which has no seed.
|
|
59
|
+
* Determinism is never guaranteed. */
|
|
60
|
+
seed?: number;
|
|
54
61
|
structured?: {
|
|
55
62
|
schema: Record<string, unknown>;
|
|
56
63
|
name?: string;
|
|
@@ -63,6 +70,13 @@ export interface CompleteOptions {
|
|
|
63
70
|
/** Service tier for this call. Also settable as a `model:tier` suffix (e.g.
|
|
64
71
|
* `anthropic/claude-opus-4.8:priority`); an explicit value here wins. */
|
|
65
72
|
serviceTier?: ServiceTier;
|
|
73
|
+
/** Provider prompt caching: `'auto'`, `'off'`, or which segments to mark
|
|
74
|
+
* (`{ system: true, tools: true }`).
|
|
75
|
+
*
|
|
76
|
+
* It matters most exactly where this helper is convenient — a long system
|
|
77
|
+
* prompt or a large tool block, both of which sit at the front of the request
|
|
78
|
+
* and are the cheapest part to cache. */
|
|
79
|
+
cache?: CacheConfig;
|
|
66
80
|
/** Optional engine to use. Falls back to coreRegistry default. */
|
|
67
81
|
engine?: EngineHandle;
|
|
68
82
|
/** Provider-specific request options (e.g. `{ openrouter: { models: [...] } }`). */
|
|
@@ -83,6 +97,11 @@ export interface CompleteResult<T = unknown> {
|
|
|
83
97
|
* otherwise `undefined`. The generic on `complete<T>(...)` types this. */
|
|
84
98
|
parsed?: T;
|
|
85
99
|
response: CompletionResponse;
|
|
100
|
+
/** In-band provider failure. Some providers report a failed generation IN the
|
|
101
|
+
* response rather than by throwing (OpenAI Responses `status: 'failed'`, Google
|
|
102
|
+
* Interactions likewise), so a caller that only catches sees empty text and no
|
|
103
|
+
* exception — a failure indistinguishable from a successful empty answer. */
|
|
104
|
+
error?: CompletionResponse['error'];
|
|
86
105
|
/** Fetch a hosted-tool output file (from `response.files`): bytes (`Blob`) +
|
|
87
106
|
* `name` / `mimeType` / `size` — bound to the SAME model + key this call used. */
|
|
88
107
|
retrieveFile(file: FileOutput): Promise<RetrievedFile>;
|