@combycode/llm-sdk 1.0.0-rc.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 +19 -0
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/dist/agent/approval-types.d.ts +49 -0
- package/dist/agent/context-registry/layers.d.ts +39 -0
- package/dist/agent/context-registry/registry-internal.d.ts +14 -0
- package/dist/agent/context-registry/registry.d.ts +104 -0
- package/dist/agent/context-registry/types.d.ts +110 -0
- package/dist/agent/guardrail-types.d.ts +58 -0
- package/dist/agent/history-types.d.ts +40 -0
- package/dist/agent/history.d.ts +111 -0
- package/dist/agent/loop-config.d.ts +67 -0
- package/dist/agent/loop-internals.d.ts +46 -0
- package/dist/agent/loop-step-state.d.ts +20 -0
- package/dist/agent/loop.d.ts +133 -0
- package/dist/agent/tool-key.d.ts +3 -0
- package/dist/agent/types.d.ts +138 -0
- package/dist/bus/agent-bus.d.ts +99 -0
- package/dist/bus/async-context.browser.d.ts +13 -0
- package/dist/bus/async-context.d.ts +11 -0
- package/dist/bus/async-context.types.d.ts +14 -0
- package/dist/bus/hook-bus.d.ts +43 -0
- package/dist/bus/hook-map.d.ts +592 -0
- package/dist/helpers/agent.d.ts +32 -0
- package/dist/helpers/batch.d.ts +74 -0
- package/dist/helpers/calibration-store.d.ts +27 -0
- package/dist/helpers/calibration-types.d.ts +64 -0
- package/dist/helpers/chain.d.ts +30 -0
- package/dist/helpers/client-pool.d.ts +15 -0
- package/dist/helpers/client-resolver.d.ts +62 -0
- package/dist/helpers/collection.d.ts +19 -0
- package/dist/helpers/consolidate.d.ts +66 -0
- package/dist/helpers/content.d.ts +25 -0
- package/dist/helpers/conversation-export.d.ts +14 -0
- package/dist/helpers/conversation-zip.d.ts +28 -0
- package/dist/helpers/count-tokens.d.ts +26 -0
- package/dist/helpers/define-tool.d.ts +66 -0
- package/dist/helpers/delegate.d.ts +6 -0
- package/dist/helpers/embed.d.ts +24 -0
- package/dist/helpers/engine.d.ts +121 -0
- package/dist/helpers/estimate-types.d.ts +67 -0
- package/dist/helpers/estimate.d.ts +45 -0
- package/dist/helpers/estimator.d.ts +48 -0
- package/dist/helpers/handoff-types.d.ts +18 -0
- package/dist/helpers/handoff.d.ts +14 -0
- package/dist/helpers/llm.d.ts +24 -0
- package/dist/helpers/mcp.d.ts +82 -0
- package/dist/helpers/media.d.ts +58 -0
- package/dist/helpers/models.d.ts +36 -0
- package/dist/helpers/moderate-types.d.ts +73 -0
- package/dist/helpers/moderate.d.ts +13 -0
- package/dist/helpers/moderation-guardrail.d.ts +29 -0
- package/dist/helpers/observer.d.ts +36 -0
- package/dist/helpers/one-shot.d.ts +86 -0
- package/dist/helpers/parallel.d.ts +16 -0
- package/dist/helpers/realtime.d.ts +25 -0
- package/dist/helpers/route.d.ts +29 -0
- package/dist/helpers/select-model.d.ts +41 -0
- package/dist/helpers/server.d.ts +32 -0
- package/dist/helpers/transcribe.d.ts +36 -0
- package/dist/index.browser.js +38047 -0
- package/dist/index.d.ts +275 -0
- package/dist/index.js +37974 -0
- package/dist/llm/audio/voices.d.ts +7 -0
- package/dist/llm/client-config.d.ts +37 -0
- package/dist/llm/client-internal.d.ts +28 -0
- package/dist/llm/client.d.ts +68 -0
- package/dist/llm/providers/_shared/constants.d.ts +5 -0
- package/dist/llm/providers/_shared/response-utils.d.ts +8 -0
- package/dist/llm/providers/anthropic/batch.d.ts +19 -0
- package/dist/llm/providers/anthropic/constants.d.ts +13 -0
- package/dist/llm/providers/anthropic/files.d.ts +23 -0
- package/dist/llm/providers/anthropic/messages.d.ts +30 -0
- package/dist/llm/providers/google/batch.d.ts +20 -0
- package/dist/llm/providers/google/constants.d.ts +6 -0
- package/dist/llm/providers/google/embeddings.d.ts +15 -0
- package/dist/llm/providers/google/files.d.ts +22 -0
- package/dist/llm/providers/google/generate.d.ts +27 -0
- package/dist/llm/providers/google/interactions.d.ts +30 -0
- package/dist/llm/providers/google/media.d.ts +27 -0
- package/dist/llm/providers/google/realtime.d.ts +27 -0
- package/dist/llm/providers/openai/batch.d.ts +19 -0
- package/dist/llm/providers/openai/completions.d.ts +25 -0
- package/dist/llm/providers/openai/embeddings.d.ts +16 -0
- package/dist/llm/providers/openai/files.d.ts +23 -0
- package/dist/llm/providers/openai/media.d.ts +28 -0
- package/dist/llm/providers/openai/moderations.d.ts +19 -0
- package/dist/llm/providers/openai/realtime.d.ts +24 -0
- package/dist/llm/providers/openai/responses.d.ts +29 -0
- package/dist/llm/providers/openai/tiers.d.ts +13 -0
- package/dist/llm/providers/openai/transcription.d.ts +20 -0
- package/dist/llm/providers/openrouter/completions.d.ts +15 -0
- package/dist/llm/providers/openrouter/embeddings.d.ts +7 -0
- package/dist/llm/providers/openrouter/media.d.ts +25 -0
- package/dist/llm/providers/openrouter/responses.d.ts +17 -0
- package/dist/llm/providers/xai/batch.d.ts +19 -0
- package/dist/llm/providers/xai/completions.d.ts +24 -0
- package/dist/llm/providers/xai/files.d.ts +23 -0
- package/dist/llm/providers/xai/media.d.ts +27 -0
- package/dist/llm/providers/xai/responses.d.ts +20 -0
- package/dist/llm/realtime/session.d.ts +34 -0
- package/dist/llm/realtime/types.d.ts +66 -0
- package/dist/llm/server-state.d.ts +32 -0
- package/dist/llm/types/audio.d.ts +18 -0
- package/dist/llm/types/messages.d.ts +125 -0
- package/dist/llm/types/options.d.ts +51 -0
- package/dist/llm/types/provider.d.ts +39 -0
- package/dist/llm/types/request.d.ts +51 -0
- package/dist/llm/types/response.d.ts +36 -0
- package/dist/llm/types/schema-utils.d.ts +8 -0
- package/dist/llm/types/stream.d.ts +42 -0
- package/dist/llm/types/tiers.d.ts +11 -0
- package/dist/llm/types/tools.d.ts +20 -0
- package/dist/network/engine.d.ts +87 -0
- package/dist/network/errors.d.ts +14 -0
- package/dist/network/queue-state-config.d.ts +41 -0
- package/dist/network/queue-state.d.ts +45 -0
- package/dist/network/rate-limiter.d.ts +49 -0
- package/dist/network/realtime-connection.d.ts +40 -0
- package/dist/network/request-queue.d.ts +40 -0
- package/dist/network/semaphore.d.ts +12 -0
- package/dist/network/sse.d.ts +3 -0
- package/dist/network/types.d.ts +127 -0
- package/dist/plugins/batch/batcher.d.ts +45 -0
- package/dist/plugins/batch/strategy.d.ts +20 -0
- package/dist/plugins/batch/types.d.ts +54 -0
- package/dist/plugins/cache/cache.d.ts +50 -0
- package/dist/plugins/cache/file-store.d.ts +15 -0
- package/dist/plugins/cache/memory-store.d.ts +10 -0
- package/dist/plugins/cache/types.d.ts +28 -0
- package/dist/plugins/configuration/configuration.d.ts +71 -0
- package/dist/plugins/context-guard/facts.d.ts +14 -0
- package/dist/plugins/context-guard/guard.d.ts +27 -0
- package/dist/plugins/context-guard/strategies/layered.d.ts +24 -0
- package/dist/plugins/context-guard/strategies/truncate.d.ts +19 -0
- package/dist/plugins/context-guard/tools.d.ts +50 -0
- package/dist/plugins/context-guard/types.d.ts +110 -0
- package/dist/plugins/context-measurer/calibration/store.d.ts +19 -0
- package/dist/plugins/context-measurer/counter/count-api.d.ts +41 -0
- package/dist/plugins/context-measurer/counter/heuristic.d.ts +25 -0
- package/dist/plugins/context-measurer/counter/hybrid.d.ts +33 -0
- package/dist/plugins/context-measurer/counter/tiktoken.d.ts +13 -0
- package/dist/plugins/context-measurer/measurer.d.ts +49 -0
- package/dist/plugins/context-measurer/types.d.ts +40 -0
- package/dist/plugins/cost-collector/collector.d.ts +42 -0
- package/dist/plugins/cost-collector/cost-collector-internal.d.ts +58 -0
- package/dist/plugins/cost-collector/cost-collector-types.d.ts +42 -0
- package/dist/plugins/embeddings/types.d.ts +23 -0
- package/dist/plugins/files/attachment.d.ts +79 -0
- package/dist/plugins/files/provider-adapter.d.ts +37 -0
- package/dist/plugins/files/registry.d.ts +48 -0
- package/dist/plugins/files/strategy.d.ts +38 -0
- package/dist/plugins/internal-tools/backends/local.d.ts +12 -0
- package/dist/plugins/internal-tools/builtin/builtin.d.ts +21 -0
- package/dist/plugins/internal-tools/builtin/clarify.d.ts +12 -0
- package/dist/plugins/internal-tools/builtin/classify.d.ts +12 -0
- package/dist/plugins/internal-tools/builtin/score.d.ts +13 -0
- package/dist/plugins/internal-tools/builtin/structure.d.ts +11 -0
- package/dist/plugins/internal-tools/builtin/summarize.d.ts +19 -0
- package/dist/plugins/internal-tools/id.d.ts +12 -0
- package/dist/plugins/internal-tools/registry.d.ts +24 -0
- package/dist/plugins/internal-tools/runner/define.d.ts +7 -0
- package/dist/plugins/internal-tools/runner/json-enforcement.d.ts +3 -0
- package/dist/plugins/internal-tools/runner/runner.d.ts +47 -0
- package/dist/plugins/internal-tools/runner/template.d.ts +10 -0
- package/dist/plugins/internal-tools/runner/types.d.ts +57 -0
- package/dist/plugins/internal-tools/runner/variants.d.ts +34 -0
- package/dist/plugins/internal-tools/types.d.ts +80 -0
- package/dist/plugins/logger/console-sink.d.ts +26 -0
- package/dist/plugins/logger/logger.d.ts +38 -0
- package/dist/plugins/logger/types.d.ts +25 -0
- package/dist/plugins/mcp/base-transport.d.ts +58 -0
- package/dist/plugins/mcp/client.d.ts +92 -0
- package/dist/plugins/mcp/jsonrpc.d.ts +20 -0
- package/dist/plugins/mcp/oauth.d.ts +122 -0
- package/dist/plugins/mcp/sampling.d.ts +17 -0
- package/dist/plugins/mcp/tools.d.ts +20 -0
- package/dist/plugins/mcp/transport-http.d.ts +50 -0
- package/dist/plugins/mcp/transport-stdio.d.ts +23 -0
- package/dist/plugins/mcp/transport-ws.d.ts +32 -0
- package/dist/plugins/mcp/transport.d.ts +29 -0
- package/dist/plugins/mcp/types.d.ts +202 -0
- package/dist/plugins/mcp/url-guard.d.ts +70 -0
- package/dist/plugins/mcp/win-spawn.d.ts +20 -0
- package/dist/plugins/media/file-store.d.ts +24 -0
- package/dist/plugins/media/memory-store.d.ts +17 -0
- package/dist/plugins/media/output.d.ts +44 -0
- package/dist/plugins/media/source-image.d.ts +36 -0
- package/dist/plugins/media/types.d.ts +146 -0
- package/dist/plugins/model-catalog/catalog.d.ts +152 -0
- package/dist/plugins/permissions/glob.d.ts +6 -0
- package/dist/plugins/permissions/matchers.d.ts +7 -0
- package/dist/plugins/permissions/policy.d.ts +10 -0
- package/dist/plugins/permissions/types.d.ts +22 -0
- package/dist/plugins/persistence/file.d.ts +25 -0
- package/dist/plugins/persistence/memory.d.ts +23 -0
- package/dist/plugins/persistence/types.d.ts +21 -0
- package/dist/plugins/retrieval/chunker.d.ts +28 -0
- package/dist/plugins/retrieval/hosted-google.d.ts +60 -0
- package/dist/plugins/retrieval/hosted-openai.d.ts +45 -0
- package/dist/plugins/retrieval/hosted-xai.d.ts +57 -0
- package/dist/plugins/retrieval/index.d.ts +70 -0
- package/dist/plugins/retrieval/local.d.ts +50 -0
- package/dist/plugins/retrieval/types.d.ts +161 -0
- package/dist/plugins/retrieval/vector-store.d.ts +70 -0
- package/dist/plugins/scheduler/scheduler.d.ts +31 -0
- package/dist/plugins/telemetry/telemetry.d.ts +118 -0
- package/dist/plugins/tool-catalog/catalog.d.ts +31 -0
- package/dist/plugins/tool-catalog/errors.d.ts +22 -0
- package/dist/plugins/tool-catalog/types.d.ts +44 -0
- package/dist/runtime/runtime.d.ts +20 -0
- package/dist/server/auth.d.ts +25 -0
- package/dist/server/dispatch.d.ts +35 -0
- package/dist/server/loaders.d.ts +26 -0
- package/dist/server/oai-adapter.d.ts +30 -0
- package/dist/server/oai-types.d.ts +114 -0
- package/dist/server/response-store.d.ts +59 -0
- package/dist/server/router.d.ts +59 -0
- package/dist/server/server.d.ts +61 -0
- package/dist/types/request-context.d.ts +46 -0
- package/dist/util/async.d.ts +3 -0
- package/dist/util/base64.d.ts +8 -0
- package/dist/util/duration.d.ts +12 -0
- package/dist/util/http.d.ts +9 -0
- package/dist/util/image-mime.d.ts +8 -0
- package/dist/util/json-schema.d.ts +7 -0
- package/dist/util/wav.d.ts +20 -0
- package/package.json +95 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** dispatch — execute a chat-completion request against a ResolvedTarget.
|
|
2
|
+
*
|
|
3
|
+
* Takes the user message + ConversationHistory (already containing prior
|
|
4
|
+
* turns), wraps the target's LLMClient in a transient AgentLoop that
|
|
5
|
+
* reuses the history, runs it, and returns the assistant text plus token
|
|
6
|
+
* counts. The history is mutated in place: [user, assistant, ...]. */
|
|
7
|
+
import { AgentLoop } from '../agent/loop';
|
|
8
|
+
import type { ConversationHistory } from '../agent/history';
|
|
9
|
+
import type { HookBus } from '../bus/hook-bus';
|
|
10
|
+
import type { OaiToolDefinition } from './oai-types';
|
|
11
|
+
import type { ResolvedTarget } from './router';
|
|
12
|
+
export interface DispatchInput {
|
|
13
|
+
target: ResolvedTarget;
|
|
14
|
+
history: ConversationHistory;
|
|
15
|
+
userText: string;
|
|
16
|
+
systemPrompt?: string;
|
|
17
|
+
/** External tools requested by the OAI client. Filtered out when the entry
|
|
18
|
+
* has `allowExternalTools: false`. Wrapped as throw-on-execute AgentTools
|
|
19
|
+
* (server-side execution of caller-defined tools is not yet supported). */
|
|
20
|
+
externalTools?: OaiToolDefinition[];
|
|
21
|
+
maxOutputTokens?: number;
|
|
22
|
+
temperature?: number;
|
|
23
|
+
hooks: HookBus;
|
|
24
|
+
/** When provided, dispatch reuses this AgentLoop instead of building a fresh
|
|
25
|
+
* one. Resolved by an AgentLoaderPlugin so server callers can persist agent
|
|
26
|
+
* state across requests (system prompt, tools, attached history). */
|
|
27
|
+
agentLoop?: AgentLoop;
|
|
28
|
+
}
|
|
29
|
+
export interface DispatchResult {
|
|
30
|
+
text: string;
|
|
31
|
+
providerResponseId: string | null;
|
|
32
|
+
inputTokens: number;
|
|
33
|
+
outputTokens: number;
|
|
34
|
+
}
|
|
35
|
+
export declare function dispatch(input: DispatchInput): Promise<DispatchResult>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Loader plugin slots for OaiServer.
|
|
2
|
+
*
|
|
3
|
+
* AgentLoaderPlugin: dynamically resolves an AgentLoop for a given (userId,
|
|
4
|
+
* model) pair, allowing per-user / per-conversation agent instances rather
|
|
5
|
+
* than the static ServerEntry registration.
|
|
6
|
+
*
|
|
7
|
+
* ConversationLoaderPlugin: rehydrates a ConversationHistory by
|
|
8
|
+
* (userId, conversationId), letting persistence live outside ResponseStore. */
|
|
9
|
+
import type { AgentLoop } from '../agent/loop';
|
|
10
|
+
import type { ConversationHistory } from '../agent/history';
|
|
11
|
+
export interface AgentLoaderContext {
|
|
12
|
+
userId: string | null;
|
|
13
|
+
model: string;
|
|
14
|
+
conversationId?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface AgentLoaderPlugin {
|
|
17
|
+
load(ctx: AgentLoaderContext): Promise<AgentLoop | null>;
|
|
18
|
+
}
|
|
19
|
+
export interface ConversationLoaderContext {
|
|
20
|
+
userId: string | null;
|
|
21
|
+
conversationId: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ConversationLoaderPlugin {
|
|
24
|
+
load(ctx: ConversationLoaderContext): Promise<ConversationHistory | null>;
|
|
25
|
+
save(ctx: ConversationLoaderContext, history: ConversationHistory): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Pure mapping functions between OpenAI Chat Completions shapes and SDK types. */
|
|
2
|
+
import type { OaiChatMessage, OaiChatRequest, OaiChatResponse, OaiChatStreamChunk, OaiErrorBody, OaiFinishReason, OaiModelEntry } from './oai-types';
|
|
3
|
+
export declare function oaiContentToText(content: OaiChatMessage['content']): string;
|
|
4
|
+
export declare function extractLastUserText(messages: OaiChatMessage[]): string;
|
|
5
|
+
export declare function extractSystemText(messages: OaiChatMessage[]): string;
|
|
6
|
+
export declare function estimateTokens(text: string): number;
|
|
7
|
+
export interface BuildChatResponseInput {
|
|
8
|
+
model: string;
|
|
9
|
+
text: string;
|
|
10
|
+
promptTokens?: number;
|
|
11
|
+
completionTokens?: number;
|
|
12
|
+
finishReason?: OaiFinishReason;
|
|
13
|
+
id?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function buildChatResponse(input: BuildChatResponseInput): OaiChatResponse;
|
|
16
|
+
export interface BuildStreamChunkInput {
|
|
17
|
+
id: string;
|
|
18
|
+
model: string;
|
|
19
|
+
delta?: {
|
|
20
|
+
role?: 'assistant';
|
|
21
|
+
content?: string;
|
|
22
|
+
};
|
|
23
|
+
finishReason?: OaiFinishReason;
|
|
24
|
+
}
|
|
25
|
+
export declare function buildStreamChunk(input: BuildStreamChunkInput): OaiChatStreamChunk;
|
|
26
|
+
export declare function formatSseFrame(data: unknown): string;
|
|
27
|
+
export declare const SSE_TERMINATOR = "data: [DONE]\n\n";
|
|
28
|
+
export declare function buildModelsList(ids: string[]): OaiModelEntry[];
|
|
29
|
+
export declare function buildErrorBody(message: string, type?: string, code?: string): OaiErrorBody;
|
|
30
|
+
export declare function validateChatRequest(req: unknown): OaiChatRequest;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/** OpenAI Chat Completions API types — request/response shapes we accept and emit.
|
|
2
|
+
*
|
|
3
|
+
* V1 scope: the subset real clients (LM Studio, Open WebUI, the official
|
|
4
|
+
* openai npm package) actually send. Unused/rare fields are omitted. */
|
|
5
|
+
export type OaiRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
6
|
+
export interface OaiContentPartText {
|
|
7
|
+
type: 'text';
|
|
8
|
+
text: string;
|
|
9
|
+
}
|
|
10
|
+
export interface OaiContentPartImageUrl {
|
|
11
|
+
type: 'image_url';
|
|
12
|
+
image_url: {
|
|
13
|
+
url: string;
|
|
14
|
+
detail?: 'auto' | 'low' | 'high';
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export type OaiContentPart = OaiContentPartText | OaiContentPartImageUrl;
|
|
18
|
+
export interface OaiToolCall {
|
|
19
|
+
id: string;
|
|
20
|
+
type: 'function';
|
|
21
|
+
function: {
|
|
22
|
+
name: string;
|
|
23
|
+
arguments: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface OaiChatMessage {
|
|
27
|
+
role: OaiRole;
|
|
28
|
+
/** OAI clients use either a string or an array of parts. V1 reads text parts,
|
|
29
|
+
* ignores others. `null` appears for assistant messages that are pure tool
|
|
30
|
+
* calls — we treat it as empty string. */
|
|
31
|
+
content: string | OaiContentPart[] | null;
|
|
32
|
+
name?: string;
|
|
33
|
+
tool_call_id?: string;
|
|
34
|
+
tool_calls?: OaiToolCall[];
|
|
35
|
+
}
|
|
36
|
+
export interface OaiToolDefinition {
|
|
37
|
+
type: 'function';
|
|
38
|
+
function: {
|
|
39
|
+
name: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
parameters?: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface OaiChatRequest {
|
|
45
|
+
model: string;
|
|
46
|
+
messages: OaiChatMessage[];
|
|
47
|
+
stream?: boolean;
|
|
48
|
+
temperature?: number;
|
|
49
|
+
max_tokens?: number;
|
|
50
|
+
top_p?: number;
|
|
51
|
+
tools?: OaiToolDefinition[];
|
|
52
|
+
tool_choice?: 'auto' | 'none' | 'required' | {
|
|
53
|
+
type: 'function';
|
|
54
|
+
function: {
|
|
55
|
+
name: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
/** Arbitrary per-user identifier. */
|
|
59
|
+
user?: string;
|
|
60
|
+
}
|
|
61
|
+
export type OaiFinishReason = 'stop' | 'length' | 'tool_calls' | 'content_filter' | null;
|
|
62
|
+
export interface OaiChatChoice {
|
|
63
|
+
index: number;
|
|
64
|
+
message: OaiChatMessage;
|
|
65
|
+
finish_reason: OaiFinishReason;
|
|
66
|
+
}
|
|
67
|
+
export interface OaiUsage {
|
|
68
|
+
prompt_tokens: number;
|
|
69
|
+
completion_tokens: number;
|
|
70
|
+
total_tokens: number;
|
|
71
|
+
}
|
|
72
|
+
export interface OaiChatResponse {
|
|
73
|
+
id: string;
|
|
74
|
+
object: 'chat.completion';
|
|
75
|
+
created: number;
|
|
76
|
+
model: string;
|
|
77
|
+
choices: OaiChatChoice[];
|
|
78
|
+
usage: OaiUsage;
|
|
79
|
+
}
|
|
80
|
+
export interface OaiChatStreamDelta {
|
|
81
|
+
role?: OaiRole;
|
|
82
|
+
content?: string;
|
|
83
|
+
tool_calls?: OaiToolCall[];
|
|
84
|
+
}
|
|
85
|
+
export interface OaiChatStreamChoice {
|
|
86
|
+
index: number;
|
|
87
|
+
delta: OaiChatStreamDelta;
|
|
88
|
+
finish_reason: OaiFinishReason;
|
|
89
|
+
}
|
|
90
|
+
export interface OaiChatStreamChunk {
|
|
91
|
+
id: string;
|
|
92
|
+
object: 'chat.completion.chunk';
|
|
93
|
+
created: number;
|
|
94
|
+
model: string;
|
|
95
|
+
choices: OaiChatStreamChoice[];
|
|
96
|
+
}
|
|
97
|
+
export interface OaiModelEntry {
|
|
98
|
+
id: string;
|
|
99
|
+
object: 'model';
|
|
100
|
+
created: number;
|
|
101
|
+
owned_by: string;
|
|
102
|
+
}
|
|
103
|
+
export interface OaiModelsResponse {
|
|
104
|
+
object: 'list';
|
|
105
|
+
data: OaiModelEntry[];
|
|
106
|
+
}
|
|
107
|
+
export interface OaiErrorBody {
|
|
108
|
+
error: {
|
|
109
|
+
message: string;
|
|
110
|
+
type: string;
|
|
111
|
+
code?: string;
|
|
112
|
+
param?: string;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** ResponseStore — persistent registry keyed by `(userId, response_id)` for
|
|
2
|
+
* multi-user mode, or just by response_id when unauthenticated.
|
|
3
|
+
*
|
|
4
|
+
* Used by the OAI server to continue stateful conversations across requests.
|
|
5
|
+
* Backing store is the generic Persistence interface — in-memory for tests,
|
|
6
|
+
* FilePersistence on disk by default. */
|
|
7
|
+
import { ConversationHistory } from '../agent/history';
|
|
8
|
+
import type { Persistence } from '../plugins/persistence/types';
|
|
9
|
+
export interface ResponseTarget {
|
|
10
|
+
/** 'direct' (registered LLMClient) — server-side AgentLoop wraps it. */
|
|
11
|
+
kind: 'direct';
|
|
12
|
+
/** Human-readable model name (what the client asked for, before resolution). */
|
|
13
|
+
model: string;
|
|
14
|
+
/** Routing tag (provider/model for direct entries). */
|
|
15
|
+
id: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ResponseStoreEntryMeta {
|
|
18
|
+
localResponseId: string;
|
|
19
|
+
/** Owner — set when AuthPlugin is attached. null for unauthenticated. */
|
|
20
|
+
userId: string | null;
|
|
21
|
+
createdAt: number;
|
|
22
|
+
updatedAt: number;
|
|
23
|
+
target: ResponseTarget;
|
|
24
|
+
/** Provider-side response id (OpenAI / xAI) for chain passthrough. */
|
|
25
|
+
providerResponseId: string | null;
|
|
26
|
+
providerStateExpiresAt: number | null;
|
|
27
|
+
}
|
|
28
|
+
export interface ResponseStoreEntry extends ResponseStoreEntryMeta {
|
|
29
|
+
history: ConversationHistory;
|
|
30
|
+
}
|
|
31
|
+
export interface ResponseStoreConfig {
|
|
32
|
+
persistence?: Persistence;
|
|
33
|
+
/** Key prefix used when writing to the Persistence backend. Default 'response:'. */
|
|
34
|
+
keyPrefix?: string;
|
|
35
|
+
/** Max entries kept in-memory. Default 10_000. */
|
|
36
|
+
memoryCapacity?: number;
|
|
37
|
+
}
|
|
38
|
+
export declare class ResponseStore {
|
|
39
|
+
private readonly persistence;
|
|
40
|
+
private readonly keyPrefix;
|
|
41
|
+
private readonly memoryCapacity;
|
|
42
|
+
private readonly cache;
|
|
43
|
+
constructor(config?: ResponseStoreConfig);
|
|
44
|
+
get(localResponseId: string, userId?: string | null): Promise<ResponseStoreEntry | null>;
|
|
45
|
+
put(entry: Omit<ResponseStoreEntry, 'createdAt' | 'updatedAt'> & {
|
|
46
|
+
createdAt?: number;
|
|
47
|
+
updatedAt?: number;
|
|
48
|
+
}): Promise<ResponseStoreEntry>;
|
|
49
|
+
delete(localResponseId: string, userId?: string | null): Promise<void>;
|
|
50
|
+
/** List response ids for a given user (or all unauthenticated entries). */
|
|
51
|
+
list(userId?: string | null): Promise<string[]>;
|
|
52
|
+
static newId(): string;
|
|
53
|
+
static hasFreshProviderState(entry: Pick<ResponseStoreEntry, 'providerResponseId' | 'providerStateExpiresAt'>, now?: number): boolean;
|
|
54
|
+
private cacheKey;
|
|
55
|
+
private cacheKeyPrefix;
|
|
56
|
+
private persistKey;
|
|
57
|
+
private persistKeyPrefix;
|
|
58
|
+
private putInCache;
|
|
59
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** ModelRouter — resolves model names to registered ServerEntry targets. */
|
|
2
|
+
import type { AgentTool } from '../agent/types';
|
|
3
|
+
import type { LLMClient } from '../llm/client';
|
|
4
|
+
export interface ServerEntry {
|
|
5
|
+
/** Model id as it appears in OAI requests. */
|
|
6
|
+
model: string;
|
|
7
|
+
/** Pre-configured LLMClient for this model. */
|
|
8
|
+
client: LLMClient;
|
|
9
|
+
/** Internal tools (executable on the server) that this entry exposes. */
|
|
10
|
+
internalTools?: AgentTool[];
|
|
11
|
+
/** When false, client-supplied tools in the OAI request are dropped. Default true. */
|
|
12
|
+
allowExternalTools?: boolean;
|
|
13
|
+
/** Optional capability metadata exposed in /v1/models. */
|
|
14
|
+
capabilities?: {
|
|
15
|
+
supportsPreviousResponseId?: boolean;
|
|
16
|
+
stateRetentionDays?: number | null;
|
|
17
|
+
tools?: boolean;
|
|
18
|
+
vision?: boolean;
|
|
19
|
+
reasoning?: boolean;
|
|
20
|
+
maxContext?: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface ResolvedTarget {
|
|
24
|
+
entry: ServerEntry;
|
|
25
|
+
client: LLMClient;
|
|
26
|
+
model: string;
|
|
27
|
+
internalTools: AgentTool[];
|
|
28
|
+
allowExternalTools: boolean;
|
|
29
|
+
supportsPreviousResponseId: boolean;
|
|
30
|
+
stateRetentionDays: number | null;
|
|
31
|
+
}
|
|
32
|
+
export interface ModelListing {
|
|
33
|
+
id: string;
|
|
34
|
+
object: 'model';
|
|
35
|
+
created: number;
|
|
36
|
+
owned_by: string;
|
|
37
|
+
orxa?: {
|
|
38
|
+
routing: 'direct';
|
|
39
|
+
apis: Array<'responses' | 'chat.completions'>;
|
|
40
|
+
supports_previous_response_id?: boolean;
|
|
41
|
+
state_retention_days?: number | null;
|
|
42
|
+
capabilities?: {
|
|
43
|
+
tools?: boolean;
|
|
44
|
+
vision?: boolean;
|
|
45
|
+
reasoning?: boolean;
|
|
46
|
+
max_context?: number;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export declare class ModelRouter {
|
|
51
|
+
private readonly byModel;
|
|
52
|
+
constructor(config: {
|
|
53
|
+
entries: ServerEntry[];
|
|
54
|
+
});
|
|
55
|
+
register(e: ServerEntry): void;
|
|
56
|
+
unregister(model: string): boolean;
|
|
57
|
+
list(): ModelListing[];
|
|
58
|
+
resolve(modelName: string): ResolvedTarget;
|
|
59
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** OaiServer — OpenAI-compatible HTTP front-end for registered LLM clients.
|
|
2
|
+
*
|
|
3
|
+
* Endpoints:
|
|
4
|
+
* POST /v1/chat/completions — primary chat surface
|
|
5
|
+
* GET /v1/models — lists registered model entries
|
|
6
|
+
* GET /health — liveness probe
|
|
7
|
+
*
|
|
8
|
+
* Plugin slots:
|
|
9
|
+
* - AuthPlugin: per-request authentication (Bearer keys, OAuth, etc.)
|
|
10
|
+
* - AgentLoaderPlugin: dynamic AgentLoop resolution (per-user agents)
|
|
11
|
+
* - ConversationLoaderPlugin: history hydration from external storage
|
|
12
|
+
*
|
|
13
|
+
* Bun.serve is the runtime; tests can avoid binding a port by calling
|
|
14
|
+
* `handle(request)` directly. */
|
|
15
|
+
import { HookBus } from '../bus/hook-bus';
|
|
16
|
+
import type { AuthPlugin } from './auth';
|
|
17
|
+
import type { AgentLoaderPlugin, ConversationLoaderPlugin } from './loaders';
|
|
18
|
+
import { type ServerEntry } from './router';
|
|
19
|
+
import { ResponseStore } from './response-store';
|
|
20
|
+
import type { Persistence } from '../plugins/persistence/types';
|
|
21
|
+
export interface OaiServerConfig {
|
|
22
|
+
entries?: ServerEntry[];
|
|
23
|
+
port?: number;
|
|
24
|
+
hostname?: string;
|
|
25
|
+
hooks?: HookBus;
|
|
26
|
+
auth?: AuthPlugin;
|
|
27
|
+
agentLoader?: AgentLoaderPlugin;
|
|
28
|
+
conversationLoader?: ConversationLoaderPlugin;
|
|
29
|
+
responseStore?: ResponseStore;
|
|
30
|
+
responseStorePersistence?: Persistence;
|
|
31
|
+
/** Fake-streaming chunk size for /v1/chat/completions stream:true. Default 40. */
|
|
32
|
+
streamChunkChars?: number;
|
|
33
|
+
}
|
|
34
|
+
export declare class OaiServer {
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly hooks: HookBus;
|
|
37
|
+
private readonly router;
|
|
38
|
+
private readonly store;
|
|
39
|
+
private readonly auth;
|
|
40
|
+
private readonly agentLoader;
|
|
41
|
+
private readonly conversationLoader;
|
|
42
|
+
private readonly port;
|
|
43
|
+
private readonly hostname;
|
|
44
|
+
private server;
|
|
45
|
+
constructor(config?: OaiServerConfig);
|
|
46
|
+
register(entry: ServerEntry): void;
|
|
47
|
+
unregister(model: string): boolean;
|
|
48
|
+
start(): {
|
|
49
|
+
port: number;
|
|
50
|
+
hostname: string;
|
|
51
|
+
};
|
|
52
|
+
stop(): Promise<void>;
|
|
53
|
+
handle(request: Request): Promise<Response>;
|
|
54
|
+
private handleChatCompletions;
|
|
55
|
+
private emitResponse;
|
|
56
|
+
get responseStore(): ResponseStore;
|
|
57
|
+
/** @internal */
|
|
58
|
+
get _agentLoader(): AgentLoaderPlugin | null;
|
|
59
|
+
/** @internal */
|
|
60
|
+
get _conversationLoader(): ConversationLoaderPlugin | null;
|
|
61
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** RequestContext — propagates accumulating IDs and routing keys across the
|
|
2
|
+
* 4 layers (network → llm → agent → server) and through plugin handlers.
|
|
3
|
+
*
|
|
4
|
+
* Mint-if-absent rule: each layer fills in what's missing.
|
|
5
|
+
* - server mints requestId (or agent mints if no server)
|
|
6
|
+
* - agent mints callId (or LLM mints if no agent)
|
|
7
|
+
* - LLM mints clientId (per construction, persistent)
|
|
8
|
+
* - LLM computes queueName/cacheKey/configName (formula defaults)
|
|
9
|
+
*
|
|
10
|
+
* Override semantics:
|
|
11
|
+
* - agent MAY override cacheKey, configName (semantic)
|
|
12
|
+
* - agent MUST NOT override queueName (infrastructure)
|
|
13
|
+
*
|
|
14
|
+
* See reports/016 §RequestContext for full lifetime table. */
|
|
15
|
+
export interface RequestContext {
|
|
16
|
+
/** Minted by the HOLDER (engine/server/orchestrator) once, lives for its
|
|
17
|
+
* lifetime (a CLI process / browser page). Shared by every request under it.
|
|
18
|
+
* A bare standalone client mints its own. `sessionId:requestId` forms the
|
|
19
|
+
* OTel trace id. */
|
|
20
|
+
sessionId?: string;
|
|
21
|
+
/** Set by AuthPlugin on authenticated request. Identifies the user across
|
|
22
|
+
* requests. Used to scope ResponseStore + ConversationLoader. */
|
|
23
|
+
userId?: string;
|
|
24
|
+
/** Per-request id — minted at each request starting point (mint-if-absent:
|
|
25
|
+
* server/agent set it, else the LLM client mints in buildContext). Follows
|
|
26
|
+
* the whole chain; the request half of the trace id. */
|
|
27
|
+
requestId?: string;
|
|
28
|
+
/** = `history.id`. Stable for the lifetime of the conversation. */
|
|
29
|
+
conversationId?: string;
|
|
30
|
+
/** Unique per `.complete()` / `.stream()` call. */
|
|
31
|
+
callId?: string;
|
|
32
|
+
/** UUID per LLMClient instance. Set in client ctor. */
|
|
33
|
+
clientId?: string;
|
|
34
|
+
/** Routing key for the network engine's queues. Default formula:
|
|
35
|
+
* `"$provider/$model"`. NOT overridable from agent (infrastructure). */
|
|
36
|
+
queueName?: string;
|
|
37
|
+
/** Cache key. Computed as content hash by default. Agent MAY override. */
|
|
38
|
+
cacheKey?: string;
|
|
39
|
+
/** Cache namespace. Default: `"default"`. */
|
|
40
|
+
cacheName?: string;
|
|
41
|
+
/** Settings registry key for ConfigurationPlugin. Default formula:
|
|
42
|
+
* `"$provider/$model"`. Agent MAY override. */
|
|
43
|
+
configName?: string;
|
|
44
|
+
providerResponseId?: string;
|
|
45
|
+
previousResponseId?: string;
|
|
46
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Base64 <-> bytes helpers — the single source of truth across the SDK. */
|
|
2
|
+
/** Decode a base64 string to raw bytes. */
|
|
3
|
+
export declare function base64ToBytes(b64: string): Uint8Array;
|
|
4
|
+
/** Encode bytes as a base64 string. Uses Node/Bun `Buffer` when present
|
|
5
|
+
* (fastest), else a browser-safe `btoa`. */
|
|
6
|
+
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
7
|
+
/** Decode a base64 payload to a UTF-8 string. */
|
|
8
|
+
export declare function base64ToUtf8(b64: string): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Compact duration strings — a reusable pattern across the SDK (server-state
|
|
2
|
+
* retention, cache TTLs, timeouts, etc.).
|
|
3
|
+
*
|
|
4
|
+
* Format: `<number><unit>` where unit is one of s/m/h/d/w. Examples:
|
|
5
|
+
* "30s", "5m", "72h", "3d", "2w"
|
|
6
|
+
*
|
|
7
|
+
* parseDuration("72h") -> 259_200_000 (ms)
|
|
8
|
+
*/
|
|
9
|
+
/** Parse a duration string to milliseconds. Throws on malformed input. */
|
|
10
|
+
export declare function parseDuration(value: string): number;
|
|
11
|
+
/** Parse to milliseconds, or return null for null/undefined/empty (not for malformed). */
|
|
12
|
+
export declare function parseDurationOrNull(value: string | null | undefined): number | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Small HTTP header helpers shared across network + server layers. */
|
|
2
|
+
/** Lowercase-keyed plain record from a WHATWG `Headers`. */
|
|
3
|
+
export declare function headersToRecord(headers: Headers): Record<string, string>;
|
|
4
|
+
/** Parse an integer header value, or null if absent / not a number. */
|
|
5
|
+
export declare function parseIntHeader(headers: Record<string, string>, key: string): number | null;
|
|
6
|
+
/** Combine multiple AbortSignals into one that aborts when any of them does. */
|
|
7
|
+
export declare function anySignal(...signals: AbortSignal[]): AbortSignal;
|
|
8
|
+
/** Parse a fetch Response body by declared type. */
|
|
9
|
+
export declare function parseResponseBody(response: Response, type: 'json' | 'arraybuffer' | 'text'): Promise<unknown>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Detect an image's MIME type from its leading magic bytes.
|
|
2
|
+
*
|
|
3
|
+
* Providers sometimes return a generated image with the WRONG declared mime
|
|
4
|
+
* (e.g. xAI hands back JPEG bytes labeled "image/png"). When that image is then
|
|
5
|
+
* forwarded as a source for image-to-video / image-edit, strict validators like
|
|
6
|
+
* Google Veo compare the declared mime against the actual bytes and reject the
|
|
7
|
+
* request with a 400. Sniffing the bytes lets us self-correct the label. */
|
|
8
|
+
export declare function sniffImageMime(b: Uint8Array): string | undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Minimal JSON Schema validator (zero-dep). Covers the common keywords —
|
|
2
|
+
* type, required, properties, items, enum, const, additionalProperties — which
|
|
3
|
+
* is enough to validate MCP tool `structuredContent` against its `outputSchema`.
|
|
4
|
+
* Not a full Draft 2020-12 implementation (no $ref, allOf/anyOf, formats, …). */
|
|
5
|
+
/** Validate `value` against `schema`; returns a list of human-readable errors
|
|
6
|
+
* (empty = valid). */
|
|
7
|
+
export declare function validateJsonSchema(schema: Record<string, unknown>, value: unknown, path?: string): string[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** WAV (RIFF) container helpers.
|
|
2
|
+
*
|
|
3
|
+
* Some providers return raw, header-less PCM samples — notably Google TTS,
|
|
4
|
+
* which emits `audio/l16; rate=24000; channels=1`. Players that expect a
|
|
5
|
+
* container (browsers' <audio>, most audio libraries) can't read bare PCM,
|
|
6
|
+
* so we wrap it in a minimal 44-byte WAV header. */
|
|
7
|
+
/** True for raw PCM mime types that need a WAV container (e.g. Google's L16). */
|
|
8
|
+
export declare function isRawPcmMime(mime: string): boolean;
|
|
9
|
+
/** Parse `rate=` / `channels=` params out of an L16 mime, with sane defaults. */
|
|
10
|
+
export declare function parsePcmParams(mime: string): {
|
|
11
|
+
sampleRate: number;
|
|
12
|
+
channels: number;
|
|
13
|
+
};
|
|
14
|
+
/** Prepend a 44-byte WAV header to little-endian 16-bit PCM samples. */
|
|
15
|
+
export declare function pcmToWav(pcm: Uint8Array, sampleRate: number, channels: number): Uint8Array;
|
|
16
|
+
/** If `mime` is raw PCM, return WAV-wrapped bytes + `audio/wav`; else unchanged. */
|
|
17
|
+
export declare function ensurePlayableAudio(data: Uint8Array, mime: string): {
|
|
18
|
+
data: Uint8Array;
|
|
19
|
+
mimeType: string;
|
|
20
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@combycode/llm-sdk",
|
|
3
|
+
"version": "1.0.0-rc.0",
|
|
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
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"browser": {
|
|
10
|
+
"./src/bus/async-context.ts": "./src/bus/async-context.browser.ts"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"browser": "./dist/index.browser.js",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "bun run clean && bun run build:js && bun run build:types",
|
|
30
|
+
"build:js": "bun run scripts/build.ts",
|
|
31
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
32
|
+
"clean": "rm -rf dist",
|
|
33
|
+
"prepublishOnly": "bun run build",
|
|
34
|
+
"test": "bun test",
|
|
35
|
+
"test:unit": "bun test tests/unit",
|
|
36
|
+
"test:integration": "bun test tests/integration",
|
|
37
|
+
"test:helpers": "bun test tests/helpers",
|
|
38
|
+
"test:live": "bun test tests/live",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"lint": "biome lint src tests",
|
|
41
|
+
"lint:fix": "biome lint --write src tests",
|
|
42
|
+
"format": "biome format --write src tests",
|
|
43
|
+
"check": "biome check src tests",
|
|
44
|
+
"check:fix": "biome check --write src tests"
|
|
45
|
+
},
|
|
46
|
+
"optionalDependencies": {
|
|
47
|
+
"tiktoken": "^1.0.22"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@biomejs/biome": "^2.4.13",
|
|
51
|
+
"@types/bun": "latest",
|
|
52
|
+
"esbuild": "0.28.1",
|
|
53
|
+
"typescript": "^5.6.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"typescript": ">=5.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"typescript": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=18",
|
|
65
|
+
"bun": ">=1.1.0"
|
|
66
|
+
},
|
|
67
|
+
"repository": {
|
|
68
|
+
"type": "git",
|
|
69
|
+
"url": "git+https://github.com/combycode/llm-sdk-ts.git"
|
|
70
|
+
},
|
|
71
|
+
"homepage": "https://llm-sdk.combycode.com",
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": "https://github.com/combycode/llm-sdk-ts/issues"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"access": "public"
|
|
77
|
+
},
|
|
78
|
+
"keywords": [
|
|
79
|
+
"llm",
|
|
80
|
+
"agent",
|
|
81
|
+
"anthropic",
|
|
82
|
+
"openai",
|
|
83
|
+
"google",
|
|
84
|
+
"xai",
|
|
85
|
+
"openrouter",
|
|
86
|
+
"agentic",
|
|
87
|
+
"tools",
|
|
88
|
+
"streaming",
|
|
89
|
+
"openai-compatible",
|
|
90
|
+
"browser",
|
|
91
|
+
"bun"
|
|
92
|
+
],
|
|
93
|
+
"license": "MIT",
|
|
94
|
+
"author": "CombyCode"
|
|
95
|
+
}
|