@combycode/llm-sdk 1.0.0 → 1.1.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.
@@ -0,0 +1,18 @@
1
+ /** Native OpenAI inline-moderation wire helpers.
2
+ *
3
+ * buildNativeModeration → the `moderation` request field OpenAI accepts on both
4
+ * the Responses API and Chat Completions.
5
+ *
6
+ * parseNativeModeration → reads the `moderation` field OpenAI returns. Handles
7
+ * BOTH wire shapes:
8
+ * - Responses API: moderation.{input,output} = moderation_result | error
9
+ * - Chat Completions: moderation.{input,output} = moderation_results | error,
10
+ * where moderation_results wraps `results: [moderation_result]`. */
11
+ import type { ModerationReport, ModerationRequest } from './types';
12
+ /** The `moderation` request field for the OpenAI native path. */
13
+ export declare function buildNativeModeration(mod: ModerationRequest): {
14
+ model: string;
15
+ };
16
+ /** Parse OpenAI's returned `moderation` object into a unified report, or undefined
17
+ * when the server returned nothing usable. */
18
+ export declare function parseNativeModeration(raw: unknown): ModerationReport | undefined;
@@ -0,0 +1,33 @@
1
+ /** Emulated-moderation runner + streaming strategy wrappers.
2
+ *
3
+ * The emulated path runs OpenAI's moderations endpoint around a call for any
4
+ * provider. This module owns:
5
+ * - mode resolution (native vs emulate, by provider)
6
+ * - input-text extraction (the last user message)
7
+ * - a single moderation call (errors → an `{error}` entry, report-only)
8
+ * - the buffer / parallel / post stream wrappers
9
+ *
10
+ * It depends only on Layer-2 primitives (the OpenAI moderations adapter + the
11
+ * injected fetch) — never on the helpers layer — so the client can use it
12
+ * without an upward import. */
13
+ import type { HookBus } from '../../bus/hook-bus';
14
+ import type { Message } from '../types/messages';
15
+ import type { ProviderName } from '../types/provider';
16
+ import type { StreamEvent } from '../types/stream';
17
+ import type { EmulationConfig, ModerationEntry, ModerationRequest, ModerationStreamStrategy } from './types';
18
+ /** Native for OpenAI, emulated for everyone else — unless explicitly forced. */
19
+ export declare function resolveModerationMode(provider: ProviderName, mod: ModerationRequest): 'native' | 'emulate';
20
+ /** Text of the last user message — what input moderation runs on. */
21
+ export declare function moderationInputText(messages: Message[]): string;
22
+ /** One moderation call. Empty text → an un-flagged empty result (nothing to check).
23
+ * A moderation-infra failure → an `{error}` entry (report-only; never throws so a
24
+ * flaky moderations endpoint can't take down the primary call). */
25
+ export declare function runModeration(text: string, cfg: EmulationConfig): Promise<ModerationEntry>;
26
+ export declare function moderationModel(mod: ModerationRequest): string;
27
+ /** Emit an honest-zero cost entry for one emulated moderation call (the
28
+ * moderations endpoint is free) so the cost ledger has no gaps. */
29
+ export declare function emitModerationZeroCost(hooks: HookBus, model: string): void;
30
+ type Moderate = (text: string) => Promise<ModerationEntry>;
31
+ /** Dispatch to the chosen strategy. `interval` defaults applied by the caller. */
32
+ export declare function wrapModeratedStream(raw: AsyncIterable<StreamEvent>, strategy: ModerationStreamStrategy, interval: number, moderate: Moderate): AsyncIterable<StreamEvent>;
33
+ export {};
@@ -0,0 +1,75 @@
1
+ /** Inline-moderation option + result shapes (parity with OpenAI's `moderation`
2
+ * request field, extended to work across all providers).
3
+ *
4
+ * Two halves:
5
+ * - `ModerationRequest` — the per-call request option (ExecuteOptions.moderation).
6
+ * - `ModerationReport` — what lands on `CompletionResponse.moderation`.
7
+ *
8
+ * The option is REPORT-ONLY: it attaches results, it never aborts the call. To
9
+ * BLOCK on flagged content use `moderationGuardrail` at the agent layer.
10
+ *
11
+ * Provider coverage:
12
+ * - OpenAI satisfies it NATIVELY (one round-trip; `mode:'native'`).
13
+ * - Every other provider is satisfied by EMULATION — the client runs OpenAI's
14
+ * moderations endpoint around the call (`mode:'emulate'`). Emulation needs an
15
+ * OpenAI API key (the only public moderations endpoint). */
16
+ import type { EngineFetch } from '../../network/types';
17
+ import type { ModerationResult } from '../../helpers/moderate-types';
18
+ /** One side's outcome: a result, or an error string if moderation itself failed. */
19
+ export type ModerationEntry = ModerationResult | {
20
+ error: string;
21
+ };
22
+ /** Streaming output-moderation strategy (emulated path only):
23
+ * - `buffer` — hold chunks, moderate at each boundary, emit the result BEFORE
24
+ * releasing the held chunks (flag never arrives later than the
25
+ * text it refers to). Highest containment, adds latency.
26
+ * - `parallel` — forward chunks in real-time; moderate concurrently; surface the
27
+ * result as soon as it lands. Preserves streaming; the triggering
28
+ * segment is already delivered when the flag arrives.
29
+ * - `post` — forward everything, moderate once after the stream ends. Pure
30
+ * after-the-fact observability. */
31
+ export type ModerationStreamStrategy = 'buffer' | 'parallel' | 'post';
32
+ export interface ModerationStreamOptions {
33
+ /** How output moderation interleaves with streamed chunks. Default 'buffer'. */
34
+ strategy?: ModerationStreamStrategy;
35
+ /** Characters of new output between moderation checks (also released on newline
36
+ * boundaries). Default 400. */
37
+ interval?: number;
38
+ }
39
+ export interface ModerationRequest {
40
+ /** Moderation model. Default 'omni-moderation-latest'. */
41
+ model?: string;
42
+ /** Moderate the request input. Default true. */
43
+ input?: boolean;
44
+ /** Moderate the generated output. Default true. */
45
+ output?: boolean;
46
+ /** Force native (OpenAI passthrough) or emulated (client-side moderations call).
47
+ * Default: 'native' for the OpenAI provider, 'emulate' for everyone else. */
48
+ mode?: 'native' | 'emulate';
49
+ /** OpenAI API key for the emulated path. Falls back to the client's own key when
50
+ * the client provider is OpenAI; otherwise required (emulation throws without it). */
51
+ apiKey?: string;
52
+ /** Streaming output-moderation controls (emulated path). */
53
+ stream?: ModerationStreamOptions;
54
+ }
55
+ /** Moderation outcome attached to a response (`CompletionResponse.moderation`). */
56
+ export interface ModerationReport {
57
+ /** Moderation of the request input, when requested. */
58
+ input?: ModerationEntry;
59
+ /** Moderation of the generated output, when requested. */
60
+ output?: ModerationEntry;
61
+ /** Whether the provider produced it natively or the client emulated it. */
62
+ source: 'native' | 'emulated';
63
+ }
64
+ /** Resolved config for one emulated-moderation call (OpenAI moderations endpoint). */
65
+ export interface EmulationConfig {
66
+ apiKey: string;
67
+ model: string;
68
+ fetch: EngineFetch;
69
+ }
70
+ /** Default moderation model when none is specified. */
71
+ export declare const MODERATION_DEFAULT_MODEL = "omni-moderation-latest";
72
+ /** Default streaming strategy. */
73
+ export declare const MODERATION_DEFAULT_STRATEGY: ModerationStreamStrategy;
74
+ /** Default characters between streaming moderation checks. */
75
+ export declare const MODERATION_DEFAULT_INTERVAL = 400;
@@ -0,0 +1,15 @@
1
+ /** Google service-tier mapping — provider-specific (shared by the generate adapter),
2
+ * never leaked into the SDK core. Google accepts flex|standard|priority on the request
3
+ * (top-level `serviceTier`) and reports the billed tier on `usageMetadata.serviceTier`. */
4
+ import type { ServiceTier } from '../../types/tiers';
5
+ /** unified ServiceTier → Google request `serviceTier`. Unsupported values
6
+ * ('auto', 'scale', or anything Google doesn't take) are omitted so Google
7
+ * applies its default (standard). */
8
+ export declare function googleRequestTier(t?: ServiceTier): string | undefined;
9
+ /** Google billed tier (response `usageMetadata.serviceTier`, e.g. 'FLEX') →
10
+ * {raw, normalized catalog key}. pricingTier is lower-cased to key `pricing.tiers`;
11
+ * serviceTier preserves the provider's raw value. */
12
+ export declare function googleBilledTier(raw: unknown): {
13
+ serviceTier?: string;
14
+ pricingTier?: string;
15
+ };
@@ -1,6 +1,7 @@
1
1
  /** ExecuteOptions — per-call overrides for client.complete()/.stream(). */
2
2
  import type { ConversationHistory } from '../../agent/history';
3
3
  import type { RequestContext } from '../../types/request-context';
4
+ import type { ModerationRequest } from '../moderation/types';
4
5
  import type { AudioOptions } from './audio';
5
6
  import type { CacheConfig, ThinkingConfig } from './request';
6
7
  import type { ServiceTier } from './tiers';
@@ -35,6 +36,10 @@ export interface ExecuteOptions {
35
36
  * any provider-accepted string). Maps per-provider; unsupported → no-op.
36
37
  * `batch` is the separate Batch API, not a value here. */
37
38
  serviceTier?: ServiceTier;
39
+ /** Inline content moderation (report-only — attaches results, never blocks).
40
+ * OpenAI runs it natively; other providers are emulated via OpenAI's
41
+ * moderations endpoint. See ModerationRequest. */
42
+ moderation?: ModerationRequest;
38
43
  providerOptions?: Record<string, unknown>;
39
44
  previousResponseId?: string;
40
45
  /** Server-state optimization: when the prior assistant turn carries a usable
@@ -3,6 +3,7 @@
3
3
  * In v2, the public surface is `client.complete(input, options?)` — model
4
4
  * and system are fixed at construction. The LLMClient internally builds
5
5
  * this `NormalizedRequest` from (input, options, this.model, this.system). */
6
+ import type { ModerationRequest } from '../moderation/types';
6
7
  import type { AudioOptions } from './audio';
7
8
  import type { Message } from './messages';
8
9
  import type { ServiceTier } from './tiers';
@@ -28,6 +29,7 @@ export interface NormalizedRequest {
28
29
  thinking?: ThinkingConfig;
29
30
  cache?: CacheConfig;
30
31
  serviceTier?: ServiceTier;
32
+ moderation?: ModerationRequest;
31
33
  providerOptions?: Record<string, unknown>;
32
34
  audio?: AudioOptions;
33
35
  outputModalities?: Array<'text' | 'audio'>;
@@ -35,12 +37,20 @@ export interface NormalizedRequest {
35
37
  timeout?: number;
36
38
  signal?: AbortSignal;
37
39
  }
40
+ /** OpenAI Responses-only: which of the model's prior-turn reasoning items are
41
+ * rendered back to it on later turns of a stateful conversation (chained via
42
+ * `previousResponseId` / server-state). `all_turns` keeps continuity at higher
43
+ * token cost; `current_turn` drops earlier reasoning; `auto` lets OpenAI decide.
44
+ * Ignored by every other provider. */
45
+ export type ReasoningContext = 'auto' | 'current_turn' | 'all_turns';
38
46
  export type ThinkingConfig = {
39
47
  mode: 'auto';
40
48
  effort?: 'low' | 'medium' | 'high' | 'max';
49
+ context?: ReasoningContext;
41
50
  } | {
42
51
  mode: 'on';
43
52
  effort?: 'low' | 'medium' | 'high' | 'max';
53
+ context?: ReasoningContext;
44
54
  } | {
45
55
  mode: 'off';
46
56
  };
@@ -1,4 +1,5 @@
1
1
  /** Universal completion response. */
2
+ import type { ModerationReport } from '../moderation/types';
2
3
  import type { ContentPart, MediaOutputPart, ToolCallPart } from './messages';
3
4
  export interface CompletionResponse {
4
5
  id: string;
@@ -11,9 +12,31 @@ export interface CompletionResponse {
11
12
  thinking: string | null;
12
13
  /** Media output parts (images, audio, video generated by model). */
13
14
  media: MediaOutputPart[];
15
+ /** Files produced by hosted tools (e.g. code execution) - charts, data files,
16
+ * etc. Unified across providers. When only `id` is set, fetch the bytes via the
17
+ * provider's files API; some providers return `data` inline. Absent when none. */
18
+ files?: FileOutput[];
19
+ /** Inline-moderation outcome, when the `moderation` request option was used.
20
+ * Report-only: present for observability; it never blocks the call. Absent when
21
+ * moderation was not requested. */
22
+ moderation?: ModerationReport;
14
23
  latencyMs: number;
15
24
  raw: unknown;
16
25
  }
26
+ /** A file produced by a hosted tool (code execution output, etc.). */
27
+ export interface FileOutput {
28
+ /** Provider file id, to fetch the bytes separately (e.g. Anthropic container
29
+ * file_id, OpenAI file_id). */
30
+ id?: string;
31
+ /** Filename, when the provider supplies one. */
32
+ name?: string;
33
+ /** MIME type, when known. */
34
+ mimeType?: string;
35
+ /** Inline bytes (base64) when the provider returns the file inline; else absent. */
36
+ data?: string;
37
+ /** What produced it (e.g. 'code_execution'). */
38
+ source?: string;
39
+ }
17
40
  export type FinishReason = 'stop' | 'tool_use' | 'length' | 'content_filter' | 'error';
18
41
  export interface Usage {
19
42
  inputTokens: number;
@@ -1,4 +1,5 @@
1
1
  /** Universal streaming event types. */
2
+ import type { ModerationEntry } from '../moderation/types';
2
3
  import type { Usage } from './response';
3
4
  export type MediaStreamType = 'image' | 'audio' | 'video';
4
5
  export type StreamEvent = {
@@ -39,4 +40,13 @@ export type StreamEvent = {
39
40
  } | {
40
41
  type: 'media_end';
41
42
  mediaId?: string;
43
+ }
44
+ /** A moderation result for the input or output. `source` distinguishes a
45
+ * provider-native result from a client-emulated one. Emitted by the moderation
46
+ * option (report-only). */
47
+ | {
48
+ type: 'moderation';
49
+ phase: 'input' | 'output';
50
+ result: ModerationEntry;
51
+ source: 'native' | 'emulated';
42
52
  };
@@ -11,6 +11,27 @@ export interface BuiltinTool {
11
11
  type: 'image_generation' | 'web_search' | 'code_interpreter' | 'file_search' | 'mcp';
12
12
  params?: Record<string, unknown>;
13
13
  }
14
+ /** Typed shape for an `mcp` builtin's `params` (OpenAI hosted MCP tool). The
15
+ * adapter forwards `params` verbatim, so this is for editor help — assign it as
16
+ * `{ type: 'mcp', params: <McpToolParams> }`. Exactly one of `server_url`,
17
+ * `connector_id`, or `tunnel_id` identifies the server (OpenAI enforces this):
18
+ * - `server_url` — a publicly reachable MCP server OpenAI dials directly.
19
+ * - `connector_id` — a managed first-party connector (Gmail, Drive, …).
20
+ * - `tunnel_id` — a Secure MCP Tunnel: reach a private/local server with no
21
+ * public URL (behind NAT/firewall) via an outbound tunnel. */
22
+ export interface McpToolParams {
23
+ server_label: string;
24
+ server_url?: string;
25
+ connector_id?: string;
26
+ tunnel_id?: string;
27
+ authorization?: string;
28
+ headers?: Record<string, string>;
29
+ require_approval?: 'always' | 'never' | Record<string, unknown>;
30
+ allowed_tools?: string[] | Record<string, unknown>;
31
+ server_description?: string;
32
+ /** Forward-compat: any other field OpenAI accepts is passed through. */
33
+ [key: string]: unknown;
34
+ }
14
35
  export type Tool = FunctionTool | BuiltinTool;
15
36
  export type ToolChoice = 'auto' | 'none' | 'required' | {
16
37
  name: string;
@@ -105,6 +105,9 @@ export interface ModelInfo {
105
105
  version?: string;
106
106
  /** Lifecycle: stable | preview | legacy. */
107
107
  status?: string;
108
+ /** Access tier, independent of lifecycle: undefined = generally available;
109
+ * 'limited' = gated / not enabled for every account; 'preview' = early access. */
110
+ availability?: string;
108
111
  /** Callable from this account/SDK now (probe-verified). false = don't call. */
109
112
  active?: boolean;
110
113
  /** End-of-life signalled by a source. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combycode/llm-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Unified, pluggable AI SDK for accessing the LLMs of every major provider (Anthropic, OpenAI, Google, xAI, OpenRouter) through one API. Cross-environment: Node, Bun, and the browser.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",