@combycode/llm-sdk 1.6.1 → 2.0.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 +518 -1
- package/MIGRATION.md +93 -0
- package/README.md +17 -2
- package/dist/agent/loop-config.d.ts +22 -0
- package/dist/agent/loop-step-state.d.ts +2 -0
- package/dist/agent/loop.d.ts +7 -0
- package/dist/agent/reflect-retry.d.ts +56 -0
- package/dist/agent/tool-key.d.ts +3 -0
- package/dist/bus/hook-map.d.ts +11 -0
- package/dist/helpers/mcp.d.ts +24 -2
- package/dist/helpers/provenance-types.d.ts +63 -0
- package/dist/helpers/provenance.d.ts +12 -0
- package/dist/helpers/transcribe.d.ts +35 -6
- package/dist/index.browser.js +3134 -731
- package/dist/index.d.ts +19 -7
- package/dist/index.js +3134 -731
- package/dist/llm/moderation/native.d.ts +5 -4
- package/dist/llm/providers/anthropic/constants.d.ts +2 -0
- package/dist/llm/providers/google/constants.d.ts +17 -2
- package/dist/llm/providers/openai/completions.d.ts +18 -2
- package/dist/llm/providers/openai/provenance.d.ts +26 -0
- package/dist/llm/providers/openai/responses.d.ts +4 -2
- package/dist/llm/providers/openai/transcription.d.ts +39 -2
- package/dist/llm/providers/xai/completions.d.ts +2 -2
- package/dist/llm/providers/xai/media.d.ts +8 -0
- package/dist/llm/types/audio.d.ts +31 -0
- package/dist/llm/types/messages.d.ts +89 -1
- package/dist/llm/types/options.d.ts +15 -0
- package/dist/llm/types/request.d.ts +21 -1
- package/dist/llm/types/response.d.ts +31 -1
- package/dist/llm/types/stream.d.ts +14 -1
- package/dist/llm/types/tiers.d.ts +6 -6
- package/dist/llm/types/tools.d.ts +10 -1
- package/dist/network/queue-state-config.d.ts +5 -0
- package/dist/network/queue-state.d.ts +7 -0
- package/dist/network/types.d.ts +23 -0
- package/dist/plugins/context-guard/strategies/anchored.d.ts +47 -0
- package/dist/plugins/context-measurer/counter/hybrid.d.ts +4 -1
- package/dist/plugins/context-measurer/counter/tiktoken.d.ts +8 -1
- package/dist/plugins/mcp/base-transport.d.ts +16 -0
- package/dist/plugins/mcp/client.d.ts +144 -7
- package/dist/plugins/mcp/input-required.d.ts +35 -0
- package/dist/plugins/mcp/jsonrpc.d.ts +7 -0
- package/dist/plugins/mcp/oauth.d.ts +21 -1
- package/dist/plugins/mcp/protocol-version.d.ts +61 -0
- package/dist/plugins/mcp/result-cache.d.ts +31 -0
- package/dist/plugins/mcp/subscriptions.d.ts +69 -0
- package/dist/plugins/mcp/transport-http.d.ts +31 -0
- package/dist/plugins/mcp/transport-stdio.d.ts +2 -0
- package/dist/plugins/mcp/transport-ws.d.ts +11 -1
- package/dist/plugins/mcp/transport.d.ts +11 -0
- package/dist/plugins/mcp/types.d.ts +54 -2
- package/dist/plugins/media/source-image.d.ts +9 -0
- package/dist/plugins/media/types.d.ts +21 -0
- package/dist/plugins/model-catalog/catalog.d.ts +3 -0
- package/dist/plugins/telemetry/telemetry.d.ts +12 -0
- package/dist/util/http.d.ts +8 -0
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ A unified, pluggable AI SDK for accessing the LLMs of every major provider —
|
|
|
10
10
|
`model:tier` selectors, capability-based `select()`, tiered pricing, and cost
|
|
11
11
|
tracking.
|
|
12
12
|
- **Cross-environment.** The same code runs on Node, Bun, and the browser. Zero
|
|
13
|
-
runtime dependencies, ESM.
|
|
13
|
+
**required** runtime dependencies, ESM.
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
@@ -18,7 +18,22 @@ A unified, pluggable AI SDK for accessing the LLMs of every major provider —
|
|
|
18
18
|
npm install @combycode/llm-sdk # or: bun add @combycode/llm-sdk
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Upgrading from 1.x? See [MIGRATION.md](./MIGRATION.md) — three things can
|
|
22
|
+
require action, and none of them is a provider change.
|
|
23
|
+
|
|
24
|
+
Requires **Node ≥ 22** or Bun ≥ 1.1. (Node 18 and 20 are end-of-life; 22 is also the floor
|
|
25
|
+
`openai-node` 7 adopted.)
|
|
26
|
+
|
|
27
|
+
`dependencies` is empty. The one optional extra is `tiktoken`, an **optional peer** for exact local
|
|
28
|
+
OpenAI token counting — install it only if you want that:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm install tiktoken
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Without it everything still works: token counting falls back to the provider count-API
|
|
35
|
+
(Anthropic/Google) or a calibrated heuristic. It is a peer rather than an `optionalDependency` so
|
|
36
|
+
its ~5.6 MB wasm is not installed — or bundled — for people who never use it.
|
|
22
37
|
|
|
23
38
|
## Quickstart
|
|
24
39
|
|
|
@@ -4,6 +4,7 @@ import type { LLMClient } from '../llm/client';
|
|
|
4
4
|
import type { CacheConfig, ThinkingConfig } from '../llm/types/request';
|
|
5
5
|
import type { ConversationHistory } from './history';
|
|
6
6
|
import type { HistorySnapshot } from './history-types';
|
|
7
|
+
import type { ReflectAndRetryConfig } from './reflect-retry';
|
|
7
8
|
import type { AgentTool } from './types';
|
|
8
9
|
import type { Guardrail, ToolInputGuardrail } from './guardrail-types';
|
|
9
10
|
import type { PermissionPolicy } from '../plugins/permissions/policy';
|
|
@@ -23,6 +24,27 @@ export interface AgentLoopConfig {
|
|
|
23
24
|
context?: string;
|
|
24
25
|
/** Executable tools. Indexed by function name (FunctionTool) or type (BuiltinTool). */
|
|
25
26
|
tools?: AgentTool[];
|
|
27
|
+
/** What to do when two tools claim the same registry key.
|
|
28
|
+
*
|
|
29
|
+
* Registration is a map keyed by function name / builtin type, so a collision means one tool
|
|
30
|
+
* SILENTLY replaces another and the model never sees it. The failure then surfaces much later
|
|
31
|
+
* as "the model called the wrong tool", with nothing in the logs pointing at the cause.
|
|
32
|
+
*
|
|
33
|
+
* - `'warn'` (default) — keep last-write-wins, but emit an `onWarning`
|
|
34
|
+
* (`code: 'tool_name_collision'`) naming the key and which tool lost.
|
|
35
|
+
* - `'error'` — throw at construction / `addTool()`, before the model is ever called.
|
|
36
|
+
*
|
|
37
|
+
* Defaults to `'warn'` so an app that unknowingly has a collision keeps working
|
|
38
|
+
* (CONSTITUTION.md R4) — the collision just stops being invisible. */
|
|
39
|
+
toolNameCollisionPolicy?: 'warn' | 'error';
|
|
40
|
+
/** Self-healing recovery from a recoverable MODEL failure (a malformed tool call, a hallucinated
|
|
41
|
+
* tool name, a truncated call). The model is given structured guidance naming the attempt and
|
|
42
|
+
* told not to repeat the same call, then the step is retried within a bounded budget.
|
|
43
|
+
*
|
|
44
|
+
* Off unless configured: a retry costs a real request, so it is the caller's decision. This is
|
|
45
|
+
* NOT a network retry — the engine already handles transport failures. This one is for a request
|
|
46
|
+
* that succeeded and came back unusable, which resending unchanged would never fix. */
|
|
47
|
+
reflectAndRetry?: ReflectAndRetryConfig;
|
|
26
48
|
/** Reuse an existing history (or rehydrate from a snapshot). New history
|
|
27
49
|
* is created when omitted. */
|
|
28
50
|
history?: ConversationHistory | HistorySnapshot;
|
|
@@ -12,6 +12,8 @@ export interface ToolCallAccumEntry {
|
|
|
12
12
|
/** All mutable state for one streaming step inside AgentLoop.stream(). */
|
|
13
13
|
export interface StepState {
|
|
14
14
|
stepText: string;
|
|
15
|
+
/** Commentary deltas, kept apart from stepText so the step's answer excludes narration. */
|
|
16
|
+
stepCommentary: string;
|
|
15
17
|
stepThinking: string;
|
|
16
18
|
stepToolCalls: ToolCallPart[];
|
|
17
19
|
toolCallAccum: Map<string, ToolCallAccumEntry>;
|
package/dist/agent/loop.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export declare class AgentLoop {
|
|
|
36
36
|
private _temperature?;
|
|
37
37
|
private _thinking?;
|
|
38
38
|
private _cache?;
|
|
39
|
+
private _collisionPolicy;
|
|
40
|
+
private readonly _reflectRetry;
|
|
39
41
|
private _parallelToolCalls;
|
|
40
42
|
private _toolTimeout;
|
|
41
43
|
private _maxSteps;
|
|
@@ -71,6 +73,11 @@ export declare class AgentLoop {
|
|
|
71
73
|
get lastReport(): AgentRunReport | null;
|
|
72
74
|
get metadata(): Record<string, unknown>;
|
|
73
75
|
addTool(tool: AgentTool): void;
|
|
76
|
+
/** Register a tool, surfacing a name collision instead of letting the last write win silently.
|
|
77
|
+
*
|
|
78
|
+
* The `warn` path still overwrites — that is the pre-existing behaviour and changing it would
|
|
79
|
+
* break apps that depend on a deliberate override — but it now says which tool lost. */
|
|
80
|
+
private registerTool;
|
|
74
81
|
removeTool(name: string): void;
|
|
75
82
|
toolNames(): string[];
|
|
76
83
|
stop(): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Reflect-and-retry — self-healing recovery from a recoverable MODEL failure.
|
|
2
|
+
*
|
|
3
|
+
* Some turns fail in a way the model itself can fix: it produced malformed tool arguments, named a
|
|
4
|
+
* tool that does not exist, or was cut off mid-call. Surfacing that straight to the caller wastes a
|
|
5
|
+
* turn that a single corrective nudge would have salvaged. This injects structured guidance —
|
|
6
|
+
* naming the attempt number and telling the model not to repeat the same call — and lets the loop
|
|
7
|
+
* try again within a bounded budget.
|
|
8
|
+
*
|
|
9
|
+
* Ported from google-adk `ReflectAndRetryModelPlugin` (adk 2.6), including its default trigger
|
|
10
|
+
* (`MALFORMED_FUNCTION_CALL`) and its raise-vs-give-up switch.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately NOT a network retry: `NetworkEngine` already retries transport failures. This is for
|
|
13
|
+
* a request that SUCCEEDED and came back unusable, which no amount of resending would fix. */
|
|
14
|
+
import type { FinishReason } from '../llm/types/response';
|
|
15
|
+
export interface ReflectAndRetryConfig {
|
|
16
|
+
/** Consecutive recoverable failures to tolerate before giving up. Default 3. */
|
|
17
|
+
maxRetries?: number;
|
|
18
|
+
/** Which finish reasons count as recoverable. Default `['malformed_tool_call']`.
|
|
19
|
+
*
|
|
20
|
+
* Adding `'content_filter'` is possible but rarely wise: a refusal is usually a decision, not a
|
|
21
|
+
* mistake, and retrying it burns budget to be refused again. */
|
|
22
|
+
onFinishReasons?: FinishReason[];
|
|
23
|
+
/** When the budget is exhausted: `true` (default) throws, `false` returns the last response as-is
|
|
24
|
+
* so the caller can decide. Upstream calls this `throw_exception_if_retry_exceeded`. */
|
|
25
|
+
throwIfExceeded?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const DEFAULT_REFLECT_RETRY_REASONS: FinishReason[];
|
|
28
|
+
export declare class ReflectAndRetryPolicy {
|
|
29
|
+
readonly maxRetries: number;
|
|
30
|
+
readonly throwIfExceeded: boolean;
|
|
31
|
+
private readonly reasons;
|
|
32
|
+
/** Consecutive failures for the CURRENT run. Reset by any successful turn, so an agent that
|
|
33
|
+
* recovers and then fails again much later gets a fresh budget rather than inheriting one. */
|
|
34
|
+
private consecutive;
|
|
35
|
+
constructor(config?: ReflectAndRetryConfig);
|
|
36
|
+
/** Is this finish reason one we try to recover from? */
|
|
37
|
+
handles(finishReason: FinishReason): boolean;
|
|
38
|
+
/** Record a successful turn — the failure streak is broken. */
|
|
39
|
+
recordSuccess(): void;
|
|
40
|
+
/** Record a recoverable failure and report what to do next.
|
|
41
|
+
*
|
|
42
|
+
* `attempt` counts from 1 so the guidance can say "attempt 1 of 3" the way a human would. */
|
|
43
|
+
recordFailure(): {
|
|
44
|
+
retry: boolean;
|
|
45
|
+
attempt: number;
|
|
46
|
+
exhausted: boolean;
|
|
47
|
+
};
|
|
48
|
+
get consecutiveFailures(): number;
|
|
49
|
+
/** Reset between runs so one run's failures never spend another run's budget. */
|
|
50
|
+
reset(): void;
|
|
51
|
+
}
|
|
52
|
+
/** The corrective message fed back to the model.
|
|
53
|
+
*
|
|
54
|
+
* Names the attempt number and explicitly forbids repeating the identical call — without that, a
|
|
55
|
+
* model tends to re-emit the same malformed arguments and burn the whole budget on one mistake. */
|
|
56
|
+
export declare function reflectionGuidance(finishReason: FinishReason, attempt: number, maxRetries: number, detail?: string): string;
|
package/dist/agent/tool-key.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
/** Registry key for an AgentTool: the function name, else the builtin type. */
|
|
2
2
|
import type { AgentTool } from './types';
|
|
3
3
|
export declare function toolKey(tool: AgentTool): string;
|
|
4
|
+
/** A short label for a tool, for collision diagnostics. Names the KIND as well as the key, because
|
|
5
|
+
* a function tool shadowing a builtin (or the reverse) is the case that reads as impossible. */
|
|
6
|
+
export declare function describeTool(tool: AgentTool): string;
|
package/dist/bus/hook-map.d.ts
CHANGED
|
@@ -467,6 +467,16 @@ export interface MediaErrorContext {
|
|
|
467
467
|
/** For async ops (video). */
|
|
468
468
|
operationId?: string;
|
|
469
469
|
}
|
|
470
|
+
/** Progress ping for a long-running async media op (video generation/extend/
|
|
471
|
+
* edit) — emitted once per poll while the job runs, so a UI can show a bar. */
|
|
472
|
+
export interface MediaProgressContext {
|
|
473
|
+
type: 'video';
|
|
474
|
+
provider: string;
|
|
475
|
+
operationId: string;
|
|
476
|
+
/** 0–100 when the provider reports it; omitted otherwise. */
|
|
477
|
+
progress?: number;
|
|
478
|
+
model?: string;
|
|
479
|
+
}
|
|
470
480
|
export interface ServerRequestContext {
|
|
471
481
|
serverId: string;
|
|
472
482
|
requestId: string;
|
|
@@ -581,6 +591,7 @@ export interface HookMap {
|
|
|
581
591
|
onContextMeasure: ContextMeasureContext;
|
|
582
592
|
onMediaGenerated: MediaGeneratedContext;
|
|
583
593
|
onMediaError: MediaErrorContext;
|
|
594
|
+
onMediaProgress: MediaProgressContext;
|
|
584
595
|
onInternalToolCallStart: InternalToolCallStartContext;
|
|
585
596
|
onInternalToolCallComplete: InternalToolCallCompleteContext;
|
|
586
597
|
onInternalToolCallError: InternalToolCallErrorContext;
|
package/dist/helpers/mcp.d.ts
CHANGED
|
@@ -40,8 +40,22 @@ 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
|
-
/** Send a `ping` every N ms to keep the connection alive (0 = off).
|
|
43
|
+
/** Send a `ping` every N ms to keep the connection alive (0 = off).
|
|
44
|
+
* Ignored on a 2026-07-28 session, where `ping` no longer exists. */
|
|
44
45
|
keepAliveMs?: number;
|
|
46
|
+
/** How to negotiate the MCP protocol revision.
|
|
47
|
+
*
|
|
48
|
+
* - `'auto'` (default) — probe `server/discover` first; fall back to the `initialize` handshake
|
|
49
|
+
* on anything that is not positive evidence of a 2026-07-28 server.
|
|
50
|
+
* - `'legacy'` — skip the probe entirely. Use for a server that mishandles unknown methods
|
|
51
|
+
* (the spec says answer with an error; not every implementation does).
|
|
52
|
+
* - a version string such as `'2026-07-28'` — adopt it directly, no probe. */
|
|
53
|
+
protocolMode?: 'auto' | 'legacy' | (string & {});
|
|
54
|
+
/** Honour the server's `ttlMs` / `cacheScope` hints on list and read results (2026-07-28).
|
|
55
|
+
* Off by default; a server that sends no hints caches nothing either way. */
|
|
56
|
+
cacheResults?: boolean;
|
|
57
|
+
/** Cap on `input_required` (MRTR) retry rounds before giving up. Default 10. */
|
|
58
|
+
inputRequiredMaxRounds?: number;
|
|
45
59
|
/** OAuth provider for servers that require authorization (HTTP only). On a
|
|
46
60
|
* required interactive grant, `connectMcp` throws `McpUnauthorizedError`
|
|
47
61
|
* after the provider redirects; finish with `finishMcpAuth`, then reconnect. */
|
|
@@ -69,11 +83,19 @@ export declare function connectMcp(config: McpServerConfig, opts?: ConnectMcpOpt
|
|
|
69
83
|
/** Finish an interactive OAuth grant: exchange the callback `code` for tokens
|
|
70
84
|
* (saved via the provider). The `state` from the authorization callback MUST
|
|
71
85
|
* be provided and is validated against the persisted value (CSRF guard).
|
|
72
|
-
* Call after catching `McpUnauthorizedError`, then `connectMcp` again.
|
|
86
|
+
* Call after catching `McpUnauthorizedError`, then `connectMcp` again.
|
|
87
|
+
*
|
|
88
|
+
* **Pass `opts.iss` if the callback URL carried one** (RFC 9207). It is validated against the
|
|
89
|
+
* authorization server's issuer before the code is redeemed, which is what stops a malicious
|
|
90
|
+
* server handing you a code minted elsewhere and having you replay the user's credentials against
|
|
91
|
+
* it. Optional so existing callers keep working, but a server that advertises
|
|
92
|
+
* `authorization_response_iss_parameter_supported` will make a missing `iss` an error — as it
|
|
93
|
+
* should, since an attacker could otherwise strip the parameter to skip the check. */
|
|
73
94
|
export declare function finishMcpAuth(serverUrl: string, code: string, state: string, opts: {
|
|
74
95
|
auth: McpAuthProvider;
|
|
75
96
|
engine?: EngineHandle;
|
|
76
97
|
security?: SsrfGuardOptions;
|
|
98
|
+
iss?: string;
|
|
77
99
|
}): Promise<void>;
|
|
78
100
|
export declare function mcpToolset(configs: McpServerConfig[], opts?: ConnectMcpOptions): Promise<{
|
|
79
101
|
tools: AgentTool[];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Types for `checkProvenance()` — detecting provider provenance signals in a file. */
|
|
2
|
+
import type { EngineHandle } from './engine';
|
|
3
|
+
/** Which provenance scheme a signal came from.
|
|
4
|
+
*
|
|
5
|
+
* - `c2pa` — a signed Content Credentials manifest (who made it, with what, when).
|
|
6
|
+
* - `synthid` — Google's imperceptible watermark; survives some edits a manifest does not.
|
|
7
|
+
*
|
|
8
|
+
* Open union (CONSTITUTION.md R1): more schemes will appear, and a new one must not break a
|
|
9
|
+
* consumer's `switch`. */
|
|
10
|
+
export type ProvenanceSignalKind = 'c2pa' | 'synthid' | (string & {});
|
|
11
|
+
/** How much a detected C2PA manifest can be believed. `trusted` is the only state that means the
|
|
12
|
+
* signature verified against a known issuer. Open by R1. */
|
|
13
|
+
export type ProvenanceValidationState = 'trusted' | 'valid' | 'invalid' | 'not_present' | (string & {});
|
|
14
|
+
export interface ProvenanceSignal {
|
|
15
|
+
kind: ProvenanceSignalKind;
|
|
16
|
+
detected: boolean;
|
|
17
|
+
validationState?: ProvenanceValidationState;
|
|
18
|
+
/** Who signed the manifest (C2PA only). */
|
|
19
|
+
issuer?: string;
|
|
20
|
+
/** The model named in the manifest, when it records one. */
|
|
21
|
+
model?: string;
|
|
22
|
+
/** When the content was generated, per the manifest. */
|
|
23
|
+
generatedAt?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ProvenanceCheckResult {
|
|
26
|
+
/** Any signal detected at all.
|
|
27
|
+
*
|
|
28
|
+
* **`false` is not proof a human made the file.** Provenance signals are strippable — a
|
|
29
|
+
* re-encode, a crop, or a screenshot usually removes them — so absence is absence of evidence,
|
|
30
|
+
* not evidence of absence. */
|
|
31
|
+
detected: boolean;
|
|
32
|
+
/** A signal was detected AND its manifest validated against a trusted issuer. This is the only
|
|
33
|
+
* positive statement the check supports. */
|
|
34
|
+
trusted: boolean;
|
|
35
|
+
/** Every signal reported, including the ones that came back `detected: false` — an image is
|
|
36
|
+
* checked for both C2PA and SynthID, audio for SynthID only. */
|
|
37
|
+
signals: ProvenanceSignal[];
|
|
38
|
+
createdAt?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface CheckProvenanceOptions {
|
|
41
|
+
/** File bytes to check. */
|
|
42
|
+
file: Uint8Array;
|
|
43
|
+
/** Filename with an extension — the API uses it to pick a decoder. */
|
|
44
|
+
filename: string;
|
|
45
|
+
/** MIME type of the file (e.g. `image/png`, `audio/wav`). */
|
|
46
|
+
mimeType: string;
|
|
47
|
+
provider?: string;
|
|
48
|
+
apiKey?: string;
|
|
49
|
+
engine?: EngineHandle;
|
|
50
|
+
}
|
|
51
|
+
/** The raw wire shape, normalised by `parseProvenanceResponse`. */
|
|
52
|
+
export interface ProvenanceRawResponse {
|
|
53
|
+
object?: string;
|
|
54
|
+
created_at?: number;
|
|
55
|
+
results?: Array<{
|
|
56
|
+
type?: string;
|
|
57
|
+
outcome?: string;
|
|
58
|
+
validation_state?: string;
|
|
59
|
+
issuer?: string;
|
|
60
|
+
model?: string;
|
|
61
|
+
generated_at?: string;
|
|
62
|
+
}>;
|
|
63
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** checkProvenance() — does this file carry provider provenance signals?
|
|
2
|
+
*
|
|
3
|
+
* const v = await checkProvenance({ file: bytes, filename: 'photo.png', mimeType: 'image/png' });
|
|
4
|
+
* if (v.trusted) { … } // a manifest that actually validated
|
|
5
|
+
*
|
|
6
|
+
* Same shape as `moderate()`: bytes in, structured verdict out, HTTP through engine.fetch.
|
|
7
|
+
*
|
|
8
|
+
* **Read `detected: false` carefully.** Provenance signals are strippable — a re-encode, a crop or
|
|
9
|
+
* a screenshot usually removes them — so a negative result is absence of evidence, not evidence
|
|
10
|
+
* that a human made the file. Only `trusted` is a positive statement. */
|
|
11
|
+
import type { CheckProvenanceOptions, ProvenanceCheckResult } from './provenance-types';
|
|
12
|
+
export declare function checkProvenance(opts: CheckProvenanceOptions): Promise<ProvenanceCheckResult>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* (gpt-4o-transcribe / whisper). Routed to OpenAITranscriptionAdapter.
|
|
6
6
|
* - generateContent providers (google, …): transcription is just a normal
|
|
7
7
|
* completion with the audio attached, so reuse complete(). */
|
|
8
|
-
import type { AudioInput } from '../llm/types/audio';
|
|
8
|
+
import type { AudioInput, TranscriptLanguage, TranscriptSegment, TranscriptWord } from '../llm/types/audio';
|
|
9
9
|
import type { ProviderName } from '../llm/types/provider';
|
|
10
10
|
import type { EngineHandle } from './engine';
|
|
11
11
|
export interface TranscribeOptions {
|
|
@@ -15,19 +15,48 @@ export interface TranscribeOptions {
|
|
|
15
15
|
/** Audio source: a file path, raw bytes, or an AudioInput (with explicit
|
|
16
16
|
* mimeType for raw/stream audio). */
|
|
17
17
|
audio: string | Uint8Array | AudioInput;
|
|
18
|
-
/** Optional language hint (BCP-47, e.g. "en").
|
|
18
|
+
/** Optional language hint (BCP-47, e.g. "en") — the language the audio IS in.
|
|
19
|
+
* Supported by `whisper-1` and `gpt-4o-transcribe`. Use `languages` instead for
|
|
20
|
+
* `gpt-transcribe`, which rejects this field. */
|
|
19
21
|
language?: string;
|
|
22
|
+
/** Candidate languages for the audio (ISO-639-1), when the language is not known
|
|
23
|
+
* up front. Narrowing the candidates changes what the model reports detecting.
|
|
24
|
+
* OpenAI: `gpt-transcribe` only — other models reject it with a 400. */
|
|
25
|
+
languages?: string[];
|
|
26
|
+
/** Words or phrases that steer spelling — product names, people, jargon. Verified
|
|
27
|
+
* to work: an invented name transcribed as "Zalbrequist" without keywords comes
|
|
28
|
+
* back as "Zylberquist" with it.
|
|
29
|
+
* OpenAI: `gpt-transcribe` only — other models reject it with a 400. */
|
|
30
|
+
keywords?: string[];
|
|
31
|
+
/** Ask for word-level timings (and segments).
|
|
32
|
+
* OpenAI: `whisper-1` only — other models reject it with a 400. */
|
|
33
|
+
wordTimestamps?: boolean;
|
|
34
|
+
/** Ask for speaker-labelled segments.
|
|
35
|
+
* OpenAI: `gpt-4o-transcribe-diarize` only — other models reject it with a 400.
|
|
36
|
+
* Cannot be combined with `wordTimestamps`: no model returns both. */
|
|
37
|
+
diarization?: boolean;
|
|
20
38
|
/** Prompt used for generateContent-style providers (ignored by openai). */
|
|
21
39
|
prompt?: string;
|
|
22
|
-
/** Caller-supplied audio duration in seconds
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
40
|
+
/** Caller-supplied audio duration in seconds, used to price the call.
|
|
41
|
+
* Takes precedence when set. Otherwise the provider's own reported duration is
|
|
42
|
+
* used when it returns one, then a WAV-header estimate; if none of the three is
|
|
43
|
+
* available the cost hook emits an honest zero with a note. */
|
|
26
44
|
audioDurationSeconds?: number;
|
|
27
45
|
engine?: EngineHandle;
|
|
28
46
|
}
|
|
47
|
+
/** `text` is the only guaranteed field. Everything else appears when the chosen
|
|
48
|
+
* model returns it, so a consumer written against `text` keeps working forever
|
|
49
|
+
* (CONSTITUTION.md R3). */
|
|
29
50
|
export interface TranscribeResult {
|
|
30
51
|
text: string;
|
|
52
|
+
/** Languages the provider reports detecting. */
|
|
53
|
+
languages?: TranscriptLanguage[];
|
|
54
|
+
/** Timed segments. `speaker` is set only when diarization ran. */
|
|
55
|
+
segments?: TranscriptSegment[];
|
|
56
|
+
/** Word-level timings. */
|
|
57
|
+
words?: TranscriptWord[];
|
|
58
|
+
/** Audio duration in seconds as the provider measured it. */
|
|
59
|
+
durationSeconds?: number;
|
|
31
60
|
}
|
|
32
61
|
export declare function transcribe(opts: TranscribeOptions): Promise<TranscribeResult>;
|
|
33
62
|
/** WAV PCM duration from raw bytes — pure arithmetic, cross-env.
|