noosphere 0.9.0 → 0.9.2
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/README.md +98 -0
- package/dist/index.cjs +288 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -1
- package/dist/index.d.ts +61 -1
- package/dist/index.js +266 -31
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, ApiOptionsMap, AssistantMessageEvent, AssistantMessageEventStream, KnownProvider, OptionsForApi, Api as PiApi, AssistantMessage as PiAssistantMessage, Context as PiContext, ImageContent as PiImageContent, Message as PiMessage, Model as PiModel, Provider as PiProvider, StreamOptions as PiStreamOptions, ToolResultMessage as PiToolResultMessage, Usage as PiUsage, UserMessage as PiUserMessage, QueuedMessage, ReasoningEffort, SimpleStreamOptions, StopReason, StreamFunction, TextContent, ThinkingContent, ToolCall, agentLoop, calculateCost, getApiKey, getModel as getPiModel, getModels as getPiModels, getProviders as getPiProviders, complete as piComplete, completeSimple as piCompleteSimple, stream as piStream, streamSimple as piStreamSimple, setApiKey } from '@mariozechner/pi-ai';
|
|
2
|
+
|
|
1
3
|
type Modality = 'llm' | 'image' | 'video' | 'tts' | 'stt' | 'music' | 'embedding';
|
|
2
4
|
type ModelStatus = 'installed' | 'available' | 'downloading' | 'running' | 'error';
|
|
3
5
|
interface LocalModelInfo {
|
|
@@ -302,6 +304,59 @@ declare class OllamaProvider implements NoosphereProvider {
|
|
|
302
304
|
getRunningModels(): Promise<OllamaRunningModel[]>;
|
|
303
305
|
}
|
|
304
306
|
|
|
307
|
+
type TokenCountProvider = 'openai' | 'google' | 'anthropic' | 'mistral' | 'groq' | 'xai' | 'cerebras' | 'openrouter' | 'ollama' | 'unknown';
|
|
308
|
+
interface TokenCountResult {
|
|
309
|
+
tokens: number;
|
|
310
|
+
model: string;
|
|
311
|
+
provider: TokenCountProvider;
|
|
312
|
+
method: 'tiktoken' | 'api' | 'estimate';
|
|
313
|
+
}
|
|
314
|
+
interface TokenCountOptions {
|
|
315
|
+
messages: Array<{
|
|
316
|
+
role: string;
|
|
317
|
+
content: string;
|
|
318
|
+
}>;
|
|
319
|
+
model?: string;
|
|
320
|
+
provider?: string;
|
|
321
|
+
}
|
|
322
|
+
declare function countTokensOpenAI(messages: Array<{
|
|
323
|
+
role: string;
|
|
324
|
+
content: string;
|
|
325
|
+
}>, model?: string): number;
|
|
326
|
+
declare function countTokensGoogle(messages: Array<{
|
|
327
|
+
role: string;
|
|
328
|
+
content: string;
|
|
329
|
+
}>, apiKey: string, model?: string): Promise<number>;
|
|
330
|
+
declare function countTokensAnthropic(messages: Array<{
|
|
331
|
+
role: string;
|
|
332
|
+
content: string;
|
|
333
|
+
}>, apiKey: string, model?: string): Promise<number>;
|
|
334
|
+
declare function countTokensGroq(messages: Array<{
|
|
335
|
+
role: string;
|
|
336
|
+
content: string;
|
|
337
|
+
}>, model?: string): number;
|
|
338
|
+
declare function countTokensMistral(messages: Array<{
|
|
339
|
+
role: string;
|
|
340
|
+
content: string;
|
|
341
|
+
}>, model?: string): number;
|
|
342
|
+
declare function countTokensXai(messages: Array<{
|
|
343
|
+
role: string;
|
|
344
|
+
content: string;
|
|
345
|
+
}>, model?: string): number;
|
|
346
|
+
declare function countTokensCerebras(messages: Array<{
|
|
347
|
+
role: string;
|
|
348
|
+
content: string;
|
|
349
|
+
}>, model?: string): number;
|
|
350
|
+
declare function countTokensOpenRouter(messages: Array<{
|
|
351
|
+
role: string;
|
|
352
|
+
content: string;
|
|
353
|
+
}>, model?: string): number;
|
|
354
|
+
declare function countTokensOllama(messages: Array<{
|
|
355
|
+
role: string;
|
|
356
|
+
content: string;
|
|
357
|
+
}>, model?: string): number;
|
|
358
|
+
declare function countTokens(options: TokenCountOptions, apiKeys?: Record<string, string>): Promise<TokenCountResult>;
|
|
359
|
+
|
|
305
360
|
declare class Noosphere {
|
|
306
361
|
private config;
|
|
307
362
|
private registry;
|
|
@@ -320,6 +375,7 @@ declare class Noosphere {
|
|
|
320
375
|
getModel(provider: string, modelId: string): Promise<ModelInfo | null>;
|
|
321
376
|
syncModels(modality?: Modality): Promise<SyncResult>;
|
|
322
377
|
getUsage(options?: UsageQueryOptions): UsageSummary;
|
|
378
|
+
countTokens(options: TokenCountOptions): Promise<TokenCountResult>;
|
|
323
379
|
installModel(name: string): Promise<AsyncGenerator<OllamaPullProgress>>;
|
|
324
380
|
uninstallModel(name: string): Promise<void>;
|
|
325
381
|
getHardware(): Promise<{
|
|
@@ -414,7 +470,10 @@ declare class OpenAIMediaProvider implements NoosphereProvider {
|
|
|
414
470
|
readonly modalities: Modality[];
|
|
415
471
|
readonly isLocal = false;
|
|
416
472
|
private modelsCache;
|
|
473
|
+
private voicesCache;
|
|
417
474
|
constructor(apiKey: string);
|
|
475
|
+
/** Auto-fetch available TTS voices by sending an invalid voice and parsing the error. */
|
|
476
|
+
private fetchVoices;
|
|
418
477
|
ping(): Promise<boolean>;
|
|
419
478
|
listModels(modality?: Modality): Promise<ModelInfo[]>;
|
|
420
479
|
image(options: ImageOptions): Promise<NoosphereResult>;
|
|
@@ -430,6 +489,7 @@ declare class GoogleMediaProvider implements NoosphereProvider {
|
|
|
430
489
|
readonly modalities: Modality[];
|
|
431
490
|
readonly isLocal = false;
|
|
432
491
|
private modelsCache;
|
|
492
|
+
private voicesCache;
|
|
433
493
|
constructor(apiKey: string);
|
|
434
494
|
ping(): Promise<boolean>;
|
|
435
495
|
listModels(modality?: Modality): Promise<ModelInfo[]>;
|
|
@@ -456,4 +516,4 @@ declare function getProviderLogo(providerId: string | undefined | null): Provide
|
|
|
456
516
|
declare function getAllProviderLogos(): Record<string, ProviderLogo>;
|
|
457
517
|
declare const PROVIDER_LOGOS: Record<string, ProviderLogo>;
|
|
458
518
|
|
|
459
|
-
export { AudioCraftProvider, type BaseOptions, type ChatOptions, GoogleMediaProvider, HfLocalProvider, type ImageOptions, type LocalModelInfo, type LocalServiceConfig, type Modality, type ModelInfo, type ModelStatus, type MusicOptions, Noosphere, type NoosphereConfig, NoosphereError, type NoosphereErrorCode, type NoosphereProvider, type NoosphereResult, type NoosphereStream, type OllamaModelDetail, OllamaProvider, type OllamaPullProgress, type OllamaRunningModel, type OpenAICompatConfig, OpenAICompatProvider, OpenAIMediaProvider, PROVIDER_IDS, PROVIDER_LOGOS, type ProviderInfo, type ProviderLogo$1 as ProviderLogo, type SpeakOptions, type StreamEvent, type SyncResult, type TranscriptionOptions, type TranscriptionResult, type UsageEvent, type UsageQueryOptions, type UsageSummary, type VideoOptions, WhisperLocalProvider, detectOpenAICompatServers, getAllProviderLogos, getProviderLogo };
|
|
519
|
+
export { AudioCraftProvider, type BaseOptions, type ChatOptions, GoogleMediaProvider, HfLocalProvider, type ImageOptions, type LocalModelInfo, type LocalServiceConfig, type Modality, type ModelInfo, type ModelStatus, type MusicOptions, Noosphere, type NoosphereConfig, NoosphereError, type NoosphereErrorCode, type NoosphereProvider, type NoosphereResult, type NoosphereStream, type OllamaModelDetail, OllamaProvider, type OllamaPullProgress, type OllamaRunningModel, type OpenAICompatConfig, OpenAICompatProvider, OpenAIMediaProvider, PROVIDER_IDS, PROVIDER_LOGOS, type ProviderInfo, type ProviderLogo$1 as ProviderLogo, type SpeakOptions, type StreamEvent, type SyncResult, type TokenCountOptions, type TokenCountProvider, type TokenCountResult, type TranscriptionOptions, type TranscriptionResult, type UsageEvent, type UsageQueryOptions, type UsageSummary, type VideoOptions, WhisperLocalProvider, countTokens, countTokensAnthropic, countTokensCerebras, countTokensGoogle, countTokensGroq, countTokensMistral, countTokensOllama, countTokensOpenAI, countTokensOpenRouter, countTokensXai, detectOpenAICompatServers, getAllProviderLogos, getProviderLogo };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { AgentContext, AgentEvent, AgentLoopConfig, AgentTool, ApiOptionsMap, AssistantMessageEvent, AssistantMessageEventStream, KnownProvider, OptionsForApi, Api as PiApi, AssistantMessage as PiAssistantMessage, Context as PiContext, ImageContent as PiImageContent, Message as PiMessage, Model as PiModel, Provider as PiProvider, StreamOptions as PiStreamOptions, ToolResultMessage as PiToolResultMessage, Usage as PiUsage, UserMessage as PiUserMessage, QueuedMessage, ReasoningEffort, SimpleStreamOptions, StopReason, StreamFunction, TextContent, ThinkingContent, ToolCall, agentLoop, calculateCost, getApiKey, getModel as getPiModel, getModels as getPiModels, getProviders as getPiProviders, complete as piComplete, completeSimple as piCompleteSimple, stream as piStream, streamSimple as piStreamSimple, setApiKey } from '@mariozechner/pi-ai';
|
|
2
|
+
|
|
1
3
|
type Modality = 'llm' | 'image' | 'video' | 'tts' | 'stt' | 'music' | 'embedding';
|
|
2
4
|
type ModelStatus = 'installed' | 'available' | 'downloading' | 'running' | 'error';
|
|
3
5
|
interface LocalModelInfo {
|
|
@@ -302,6 +304,59 @@ declare class OllamaProvider implements NoosphereProvider {
|
|
|
302
304
|
getRunningModels(): Promise<OllamaRunningModel[]>;
|
|
303
305
|
}
|
|
304
306
|
|
|
307
|
+
type TokenCountProvider = 'openai' | 'google' | 'anthropic' | 'mistral' | 'groq' | 'xai' | 'cerebras' | 'openrouter' | 'ollama' | 'unknown';
|
|
308
|
+
interface TokenCountResult {
|
|
309
|
+
tokens: number;
|
|
310
|
+
model: string;
|
|
311
|
+
provider: TokenCountProvider;
|
|
312
|
+
method: 'tiktoken' | 'api' | 'estimate';
|
|
313
|
+
}
|
|
314
|
+
interface TokenCountOptions {
|
|
315
|
+
messages: Array<{
|
|
316
|
+
role: string;
|
|
317
|
+
content: string;
|
|
318
|
+
}>;
|
|
319
|
+
model?: string;
|
|
320
|
+
provider?: string;
|
|
321
|
+
}
|
|
322
|
+
declare function countTokensOpenAI(messages: Array<{
|
|
323
|
+
role: string;
|
|
324
|
+
content: string;
|
|
325
|
+
}>, model?: string): number;
|
|
326
|
+
declare function countTokensGoogle(messages: Array<{
|
|
327
|
+
role: string;
|
|
328
|
+
content: string;
|
|
329
|
+
}>, apiKey: string, model?: string): Promise<number>;
|
|
330
|
+
declare function countTokensAnthropic(messages: Array<{
|
|
331
|
+
role: string;
|
|
332
|
+
content: string;
|
|
333
|
+
}>, apiKey: string, model?: string): Promise<number>;
|
|
334
|
+
declare function countTokensGroq(messages: Array<{
|
|
335
|
+
role: string;
|
|
336
|
+
content: string;
|
|
337
|
+
}>, model?: string): number;
|
|
338
|
+
declare function countTokensMistral(messages: Array<{
|
|
339
|
+
role: string;
|
|
340
|
+
content: string;
|
|
341
|
+
}>, model?: string): number;
|
|
342
|
+
declare function countTokensXai(messages: Array<{
|
|
343
|
+
role: string;
|
|
344
|
+
content: string;
|
|
345
|
+
}>, model?: string): number;
|
|
346
|
+
declare function countTokensCerebras(messages: Array<{
|
|
347
|
+
role: string;
|
|
348
|
+
content: string;
|
|
349
|
+
}>, model?: string): number;
|
|
350
|
+
declare function countTokensOpenRouter(messages: Array<{
|
|
351
|
+
role: string;
|
|
352
|
+
content: string;
|
|
353
|
+
}>, model?: string): number;
|
|
354
|
+
declare function countTokensOllama(messages: Array<{
|
|
355
|
+
role: string;
|
|
356
|
+
content: string;
|
|
357
|
+
}>, model?: string): number;
|
|
358
|
+
declare function countTokens(options: TokenCountOptions, apiKeys?: Record<string, string>): Promise<TokenCountResult>;
|
|
359
|
+
|
|
305
360
|
declare class Noosphere {
|
|
306
361
|
private config;
|
|
307
362
|
private registry;
|
|
@@ -320,6 +375,7 @@ declare class Noosphere {
|
|
|
320
375
|
getModel(provider: string, modelId: string): Promise<ModelInfo | null>;
|
|
321
376
|
syncModels(modality?: Modality): Promise<SyncResult>;
|
|
322
377
|
getUsage(options?: UsageQueryOptions): UsageSummary;
|
|
378
|
+
countTokens(options: TokenCountOptions): Promise<TokenCountResult>;
|
|
323
379
|
installModel(name: string): Promise<AsyncGenerator<OllamaPullProgress>>;
|
|
324
380
|
uninstallModel(name: string): Promise<void>;
|
|
325
381
|
getHardware(): Promise<{
|
|
@@ -414,7 +470,10 @@ declare class OpenAIMediaProvider implements NoosphereProvider {
|
|
|
414
470
|
readonly modalities: Modality[];
|
|
415
471
|
readonly isLocal = false;
|
|
416
472
|
private modelsCache;
|
|
473
|
+
private voicesCache;
|
|
417
474
|
constructor(apiKey: string);
|
|
475
|
+
/** Auto-fetch available TTS voices by sending an invalid voice and parsing the error. */
|
|
476
|
+
private fetchVoices;
|
|
418
477
|
ping(): Promise<boolean>;
|
|
419
478
|
listModels(modality?: Modality): Promise<ModelInfo[]>;
|
|
420
479
|
image(options: ImageOptions): Promise<NoosphereResult>;
|
|
@@ -430,6 +489,7 @@ declare class GoogleMediaProvider implements NoosphereProvider {
|
|
|
430
489
|
readonly modalities: Modality[];
|
|
431
490
|
readonly isLocal = false;
|
|
432
491
|
private modelsCache;
|
|
492
|
+
private voicesCache;
|
|
433
493
|
constructor(apiKey: string);
|
|
434
494
|
ping(): Promise<boolean>;
|
|
435
495
|
listModels(modality?: Modality): Promise<ModelInfo[]>;
|
|
@@ -456,4 +516,4 @@ declare function getProviderLogo(providerId: string | undefined | null): Provide
|
|
|
456
516
|
declare function getAllProviderLogos(): Record<string, ProviderLogo>;
|
|
457
517
|
declare const PROVIDER_LOGOS: Record<string, ProviderLogo>;
|
|
458
518
|
|
|
459
|
-
export { AudioCraftProvider, type BaseOptions, type ChatOptions, GoogleMediaProvider, HfLocalProvider, type ImageOptions, type LocalModelInfo, type LocalServiceConfig, type Modality, type ModelInfo, type ModelStatus, type MusicOptions, Noosphere, type NoosphereConfig, NoosphereError, type NoosphereErrorCode, type NoosphereProvider, type NoosphereResult, type NoosphereStream, type OllamaModelDetail, OllamaProvider, type OllamaPullProgress, type OllamaRunningModel, type OpenAICompatConfig, OpenAICompatProvider, OpenAIMediaProvider, PROVIDER_IDS, PROVIDER_LOGOS, type ProviderInfo, type ProviderLogo$1 as ProviderLogo, type SpeakOptions, type StreamEvent, type SyncResult, type TranscriptionOptions, type TranscriptionResult, type UsageEvent, type UsageQueryOptions, type UsageSummary, type VideoOptions, WhisperLocalProvider, detectOpenAICompatServers, getAllProviderLogos, getProviderLogo };
|
|
519
|
+
export { AudioCraftProvider, type BaseOptions, type ChatOptions, GoogleMediaProvider, HfLocalProvider, type ImageOptions, type LocalModelInfo, type LocalServiceConfig, type Modality, type ModelInfo, type ModelStatus, type MusicOptions, Noosphere, type NoosphereConfig, NoosphereError, type NoosphereErrorCode, type NoosphereProvider, type NoosphereResult, type NoosphereStream, type OllamaModelDetail, OllamaProvider, type OllamaPullProgress, type OllamaRunningModel, type OpenAICompatConfig, OpenAICompatProvider, OpenAIMediaProvider, PROVIDER_IDS, PROVIDER_LOGOS, type ProviderInfo, type ProviderLogo$1 as ProviderLogo, type SpeakOptions, type StreamEvent, type SyncResult, type TokenCountOptions, type TokenCountProvider, type TokenCountResult, type TranscriptionOptions, type TranscriptionResult, type UsageEvent, type UsageQueryOptions, type UsageSummary, type VideoOptions, WhisperLocalProvider, countTokens, countTokensAnthropic, countTokensCerebras, countTokensGoogle, countTokensGroq, countTokensMistral, countTokensOllama, countTokensOpenAI, countTokensOpenRouter, countTokensXai, detectOpenAICompatServers, getAllProviderLogos, getProviderLogo };
|
package/dist/index.js
CHANGED
|
@@ -108,6 +108,136 @@ function resolveConfig(input) {
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
// src/token-counter.ts
|
|
112
|
+
import { encoding_for_model } from "tiktoken";
|
|
113
|
+
var TIKTOKEN_MODEL_MAP = {
|
|
114
|
+
"gpt-4o": "gpt-4o",
|
|
115
|
+
"gpt-4o-mini": "gpt-4o-mini",
|
|
116
|
+
"gpt-4-turbo": "gpt-4-turbo",
|
|
117
|
+
"gpt-4": "gpt-4",
|
|
118
|
+
"gpt-3.5-turbo": "gpt-3.5-turbo"
|
|
119
|
+
};
|
|
120
|
+
function resolveTiktokenModel(model) {
|
|
121
|
+
if (model in TIKTOKEN_MODEL_MAP) return TIKTOKEN_MODEL_MAP[model];
|
|
122
|
+
for (const [prefix, tikModel] of Object.entries(TIKTOKEN_MODEL_MAP)) {
|
|
123
|
+
if (model.startsWith(prefix)) return tikModel;
|
|
124
|
+
}
|
|
125
|
+
return "gpt-4o";
|
|
126
|
+
}
|
|
127
|
+
function countWithTiktoken(messages, model) {
|
|
128
|
+
const tikModel = resolveTiktokenModel(model);
|
|
129
|
+
const enc = encoding_for_model(tikModel);
|
|
130
|
+
let tokens = 0;
|
|
131
|
+
for (const msg of messages) {
|
|
132
|
+
tokens += 4;
|
|
133
|
+
tokens += enc.encode(msg.role).length;
|
|
134
|
+
tokens += enc.encode(msg.content).length;
|
|
135
|
+
}
|
|
136
|
+
tokens += 2;
|
|
137
|
+
enc.free();
|
|
138
|
+
return tokens;
|
|
139
|
+
}
|
|
140
|
+
function countTokensOpenAI(messages, model = "gpt-4o") {
|
|
141
|
+
return countWithTiktoken(messages, model);
|
|
142
|
+
}
|
|
143
|
+
async function countTokensGoogle(messages, apiKey, model = "gemini-2.5-flash") {
|
|
144
|
+
const contents = messages.map((m) => ({
|
|
145
|
+
role: m.role === "assistant" ? "model" : "user",
|
|
146
|
+
parts: [{ text: m.content }]
|
|
147
|
+
}));
|
|
148
|
+
const res = await fetch(
|
|
149
|
+
`https://generativelanguage.googleapis.com/v1beta/models/${model}:countTokens?key=${apiKey}`,
|
|
150
|
+
{
|
|
151
|
+
method: "POST",
|
|
152
|
+
headers: { "Content-Type": "application/json" },
|
|
153
|
+
body: JSON.stringify({ contents })
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
if (!res.ok) {
|
|
157
|
+
throw new Error(`Google countTokens failed (${res.status}): ${await res.text()}`);
|
|
158
|
+
}
|
|
159
|
+
const data = await res.json();
|
|
160
|
+
return data.totalTokens;
|
|
161
|
+
}
|
|
162
|
+
async function countTokensAnthropic(messages, apiKey, model = "claude-sonnet-4-20250514") {
|
|
163
|
+
const anthropicMessages = messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, content: m.content }));
|
|
164
|
+
const systemPrompt = messages.find((m) => m.role === "system")?.content;
|
|
165
|
+
const body = {
|
|
166
|
+
model,
|
|
167
|
+
messages: anthropicMessages
|
|
168
|
+
};
|
|
169
|
+
if (systemPrompt) body.system = systemPrompt;
|
|
170
|
+
const res = await fetch("https://api.anthropic.com/v1/messages/count_tokens", {
|
|
171
|
+
method: "POST",
|
|
172
|
+
headers: {
|
|
173
|
+
"x-api-key": apiKey,
|
|
174
|
+
"anthropic-version": "2023-06-01",
|
|
175
|
+
"Content-Type": "application/json"
|
|
176
|
+
},
|
|
177
|
+
body: JSON.stringify(body)
|
|
178
|
+
});
|
|
179
|
+
if (!res.ok) {
|
|
180
|
+
throw new Error(`Anthropic countTokens failed (${res.status}): ${await res.text()}`);
|
|
181
|
+
}
|
|
182
|
+
const data = await res.json();
|
|
183
|
+
return data.input_tokens;
|
|
184
|
+
}
|
|
185
|
+
function countTokensGroq(messages, model = "llama-3.3-70b-versatile") {
|
|
186
|
+
return countWithTiktoken(messages, model);
|
|
187
|
+
}
|
|
188
|
+
function countTokensMistral(messages, model = "mistral-large-latest") {
|
|
189
|
+
return countWithTiktoken(messages, model);
|
|
190
|
+
}
|
|
191
|
+
function countTokensXai(messages, model = "grok-3") {
|
|
192
|
+
return countWithTiktoken(messages, model);
|
|
193
|
+
}
|
|
194
|
+
function countTokensCerebras(messages, model = "llama-3.3-70b") {
|
|
195
|
+
return countWithTiktoken(messages, model);
|
|
196
|
+
}
|
|
197
|
+
function countTokensOpenRouter(messages, model = "openai/gpt-4o") {
|
|
198
|
+
return countWithTiktoken(messages, model);
|
|
199
|
+
}
|
|
200
|
+
function countTokensOllama(messages, model = "llama3.2") {
|
|
201
|
+
return countWithTiktoken(messages, model);
|
|
202
|
+
}
|
|
203
|
+
var PROVIDER_MODEL_PREFIXES = [
|
|
204
|
+
{ prefixes: ["gemini", "imagen", "veo"], provider: "google" },
|
|
205
|
+
{ prefixes: ["claude"], provider: "anthropic" },
|
|
206
|
+
{ prefixes: ["gpt-", "o1", "o3", "o4", "chatgpt", "dall-e", "gpt-image", "tts-", "whisper", "sora"], provider: "openai" },
|
|
207
|
+
{ prefixes: ["grok"], provider: "xai" },
|
|
208
|
+
{ prefixes: ["mistral", "mixtral", "codestral", "ministral"], provider: "mistral" },
|
|
209
|
+
{ prefixes: ["llama", "gemma", "qwen", "deepseek", "phi"], provider: "groq" }
|
|
210
|
+
];
|
|
211
|
+
function inferProvider(model) {
|
|
212
|
+
const lower = model.toLowerCase();
|
|
213
|
+
for (const { prefixes, provider } of PROVIDER_MODEL_PREFIXES) {
|
|
214
|
+
for (const prefix of prefixes) {
|
|
215
|
+
if (lower.startsWith(prefix)) return provider;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return "unknown";
|
|
219
|
+
}
|
|
220
|
+
async function countTokens(options, apiKeys) {
|
|
221
|
+
const model = options.model ?? "gpt-4o";
|
|
222
|
+
const provider = options.provider ?? inferProvider(model);
|
|
223
|
+
if (provider === "google" && apiKeys?.google) {
|
|
224
|
+
const tokens2 = await countTokensGoogle(options.messages, apiKeys.google, model);
|
|
225
|
+
return { tokens: tokens2, model, provider: "google", method: "api" };
|
|
226
|
+
}
|
|
227
|
+
if (provider === "anthropic" && apiKeys?.anthropic) {
|
|
228
|
+
const tokens2 = await countTokensAnthropic(options.messages, apiKeys.anthropic, model);
|
|
229
|
+
return { tokens: tokens2, model, provider: "anthropic", method: "api" };
|
|
230
|
+
}
|
|
231
|
+
const tokens = countWithTiktoken(options.messages, model);
|
|
232
|
+
const resolvedProvider = provider === "unknown" ? "openai" : provider;
|
|
233
|
+
return {
|
|
234
|
+
tokens,
|
|
235
|
+
model,
|
|
236
|
+
provider: resolvedProvider,
|
|
237
|
+
method: provider === "openai" ? "tiktoken" : "tiktoken"
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
111
241
|
// src/logos.ts
|
|
112
242
|
var CDN_BASE = "https://blockchainstarter.nyc3.digitaloceanspaces.com/noosphere/logos";
|
|
113
243
|
var PROVIDER_IDS = [
|
|
@@ -2533,6 +2663,36 @@ var OpenAIMediaProvider = class {
|
|
|
2533
2663
|
modalities = ["image", "video", "tts", "stt"];
|
|
2534
2664
|
isLocal = false;
|
|
2535
2665
|
modelsCache = null;
|
|
2666
|
+
voicesCache = null;
|
|
2667
|
+
/** Auto-fetch available TTS voices by sending an invalid voice and parsing the error. */
|
|
2668
|
+
async fetchVoices() {
|
|
2669
|
+
if (this.voicesCache) return this.voicesCache;
|
|
2670
|
+
try {
|
|
2671
|
+
const res = await fetch(`${OPENAI_API_BASE}/audio/speech`, {
|
|
2672
|
+
method: "POST",
|
|
2673
|
+
headers: {
|
|
2674
|
+
"Content-Type": "application/json",
|
|
2675
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
2676
|
+
},
|
|
2677
|
+
body: JSON.stringify({ model: "tts-1", input: ".", voice: "__discover_voices__" })
|
|
2678
|
+
});
|
|
2679
|
+
if (!res.ok) {
|
|
2680
|
+
const data = await res.json();
|
|
2681
|
+
const msg = data?.error?.message ?? "";
|
|
2682
|
+
const shouldBe = msg.match(/Input should be ([^"]+)/);
|
|
2683
|
+
if (shouldBe) {
|
|
2684
|
+
const voiceList = shouldBe[1].match(/'([a-z]+)'/g);
|
|
2685
|
+
if (voiceList && voiceList.length > 0) {
|
|
2686
|
+
this.voicesCache = voiceList.map((v) => v.replace(/'/g, ""));
|
|
2687
|
+
return this.voicesCache;
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
} catch {
|
|
2692
|
+
}
|
|
2693
|
+
this.voicesCache = [];
|
|
2694
|
+
return this.voicesCache;
|
|
2695
|
+
}
|
|
2536
2696
|
async ping() {
|
|
2537
2697
|
try {
|
|
2538
2698
|
const controller = new AbortController();
|
|
@@ -2568,6 +2728,7 @@ var OpenAIMediaProvider = class {
|
|
|
2568
2728
|
} finally {
|
|
2569
2729
|
clearTimeout(timer);
|
|
2570
2730
|
}
|
|
2731
|
+
const voices = await this.fetchVoices();
|
|
2571
2732
|
const entries = data?.data ?? [];
|
|
2572
2733
|
const logo = getProviderLogo("openai");
|
|
2573
2734
|
const models = [];
|
|
@@ -2583,7 +2744,7 @@ var OpenAIMediaProvider = class {
|
|
|
2583
2744
|
cost: { price: 0, unit: "per_request" },
|
|
2584
2745
|
logo,
|
|
2585
2746
|
description: entry.description,
|
|
2586
|
-
capabilities: this.getCapabilities(entry.id, mod)
|
|
2747
|
+
capabilities: this.getCapabilities(entry.id, mod, voices)
|
|
2587
2748
|
};
|
|
2588
2749
|
models.push(info);
|
|
2589
2750
|
}
|
|
@@ -2728,7 +2889,7 @@ var OpenAIMediaProvider = class {
|
|
|
2728
2889
|
}
|
|
2729
2890
|
};
|
|
2730
2891
|
}
|
|
2731
|
-
getCapabilities(id, modality) {
|
|
2892
|
+
getCapabilities(id, modality, voices) {
|
|
2732
2893
|
if (modality === "image") {
|
|
2733
2894
|
return {
|
|
2734
2895
|
maxWidth: id.startsWith("dall-e-3") ? 1792 : 1024,
|
|
@@ -2737,7 +2898,7 @@ var OpenAIMediaProvider = class {
|
|
|
2737
2898
|
}
|
|
2738
2899
|
if (modality === "tts") {
|
|
2739
2900
|
return {
|
|
2740
|
-
voices:
|
|
2901
|
+
voices: voices && voices.length > 0 ? voices : void 0
|
|
2741
2902
|
};
|
|
2742
2903
|
}
|
|
2743
2904
|
if (modality === "video") {
|
|
@@ -2758,18 +2919,34 @@ var OpenAIMediaProvider = class {
|
|
|
2758
2919
|
// src/providers/google-media.ts
|
|
2759
2920
|
var GOOGLE_API_BASE = "https://generativelanguage.googleapis.com/v1beta";
|
|
2760
2921
|
var FETCH_TIMEOUT_MS6 = 8e3;
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2922
|
+
async function fetchGoogleVoices(apiKey) {
|
|
2923
|
+
try {
|
|
2924
|
+
const res = await fetch(
|
|
2925
|
+
`${GOOGLE_API_BASE}/models/gemini-2.5-flash-preview-tts:generateContent?key=${apiKey}`,
|
|
2926
|
+
{
|
|
2927
|
+
method: "POST",
|
|
2928
|
+
headers: { "Content-Type": "application/json" },
|
|
2929
|
+
body: JSON.stringify({
|
|
2930
|
+
contents: [{ parts: [{ text: "." }] }],
|
|
2931
|
+
generationConfig: {
|
|
2932
|
+
response_modalities: ["AUDIO"],
|
|
2933
|
+
speech_config: { voiceConfig: { prebuiltVoiceConfig: { voiceName: "__discover_voices__" } } }
|
|
2934
|
+
}
|
|
2935
|
+
})
|
|
2936
|
+
}
|
|
2937
|
+
);
|
|
2938
|
+
if (!res.ok) {
|
|
2939
|
+
const data = await res.json();
|
|
2940
|
+
const msg = data?.error?.message ?? "";
|
|
2941
|
+
const match = msg.match(/Allowed voice names are:\s*(.+)/i);
|
|
2942
|
+
if (match) {
|
|
2943
|
+
return match[1].split(",").map((v) => v.trim()).filter(Boolean);
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
} catch {
|
|
2947
|
+
}
|
|
2948
|
+
return [];
|
|
2949
|
+
}
|
|
2773
2950
|
function classifyGoogleModel(model) {
|
|
2774
2951
|
const name = (model.name ?? "").replace("models/", "");
|
|
2775
2952
|
const methods = model.supportedGenerationMethods ?? [];
|
|
@@ -2787,6 +2964,7 @@ var GoogleMediaProvider = class {
|
|
|
2787
2964
|
modalities = ["image", "video", "tts"];
|
|
2788
2965
|
isLocal = false;
|
|
2789
2966
|
modelsCache = null;
|
|
2967
|
+
voicesCache = null;
|
|
2790
2968
|
async ping() {
|
|
2791
2969
|
try {
|
|
2792
2970
|
const controller = new AbortController();
|
|
@@ -2821,6 +2999,9 @@ var GoogleMediaProvider = class {
|
|
|
2821
2999
|
clearTimeout(timer);
|
|
2822
3000
|
}
|
|
2823
3001
|
const entries = data?.models ?? [];
|
|
3002
|
+
if (!this.voicesCache) {
|
|
3003
|
+
this.voicesCache = await fetchGoogleVoices(this.apiKey);
|
|
3004
|
+
}
|
|
2824
3005
|
const logo = getProviderLogo("google");
|
|
2825
3006
|
const models = [];
|
|
2826
3007
|
for (const entry of entries) {
|
|
@@ -2837,7 +3018,7 @@ var GoogleMediaProvider = class {
|
|
|
2837
3018
|
cost: { price: 0, unit: modality2 === "video" ? "per_video" : "per_image" },
|
|
2838
3019
|
logo,
|
|
2839
3020
|
description: entry.description,
|
|
2840
|
-
capabilities: modality2 === "video" ? { maxDuration: 8, supportsStreaming: false } : modality2 === "tts" ? { voices:
|
|
3021
|
+
capabilities: modality2 === "video" ? { maxDuration: 8, supportsStreaming: false } : modality2 === "tts" ? { voices: this.voicesCache && this.voicesCache.length > 0 ? this.voicesCache : void 0 } : void 0
|
|
2841
3022
|
};
|
|
2842
3023
|
models.push(info);
|
|
2843
3024
|
}
|
|
@@ -2940,7 +3121,7 @@ var GoogleMediaProvider = class {
|
|
|
2940
3121
|
};
|
|
2941
3122
|
}
|
|
2942
3123
|
async video(options) {
|
|
2943
|
-
const model = options.model ?? "veo-
|
|
3124
|
+
const model = options.model ?? "veo-2.0-generate-001";
|
|
2944
3125
|
const start = Date.now();
|
|
2945
3126
|
const body = {
|
|
2946
3127
|
instances: [{ prompt: options.prompt }],
|
|
@@ -2975,10 +3156,15 @@ var GoogleMediaProvider = class {
|
|
|
2975
3156
|
if (!pollRes.ok) continue;
|
|
2976
3157
|
const status = await pollRes.json();
|
|
2977
3158
|
if (status.done) {
|
|
2978
|
-
|
|
2979
|
-
|
|
3159
|
+
if (status.error) {
|
|
3160
|
+
throw new Error(`Google video generation error: ${status.error.message ?? JSON.stringify(status.error)}`);
|
|
3161
|
+
}
|
|
3162
|
+
const resp = status.response ?? {};
|
|
3163
|
+
const samples = resp.generateVideoResponse?.generatedSamples ?? resp.generatedSamples ?? [];
|
|
3164
|
+
const video = samples[0]?.video;
|
|
3165
|
+
if (video?.bytesBase64Encoded) {
|
|
2980
3166
|
return {
|
|
2981
|
-
buffer: Buffer.from(
|
|
3167
|
+
buffer: Buffer.from(video.bytesBase64Encoded, "base64"),
|
|
2982
3168
|
provider: "google-media",
|
|
2983
3169
|
model,
|
|
2984
3170
|
modality: "video",
|
|
@@ -2987,16 +3173,32 @@ var GoogleMediaProvider = class {
|
|
|
2987
3173
|
media: { format: "mp4", duration: options.duration }
|
|
2988
3174
|
};
|
|
2989
3175
|
}
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3176
|
+
if (video?.uri) {
|
|
3177
|
+
const separator = video.uri.includes("?") ? "&" : "?";
|
|
3178
|
+
const videoRes = await fetch(`${video.uri}${separator}key=${this.apiKey}`, { redirect: "follow" });
|
|
3179
|
+
if (videoRes.ok) {
|
|
3180
|
+
const buffer = Buffer.from(await videoRes.arrayBuffer());
|
|
3181
|
+
return {
|
|
3182
|
+
buffer,
|
|
3183
|
+
provider: "google-media",
|
|
3184
|
+
model,
|
|
3185
|
+
modality: "video",
|
|
3186
|
+
latencyMs: Date.now() - start,
|
|
3187
|
+
usage: { cost: 0, unit: "per_video" },
|
|
3188
|
+
media: { format: "mp4", duration: options.duration }
|
|
3189
|
+
};
|
|
3190
|
+
}
|
|
3191
|
+
return {
|
|
3192
|
+
url: video.uri,
|
|
3193
|
+
provider: "google-media",
|
|
3194
|
+
model,
|
|
3195
|
+
modality: "video",
|
|
3196
|
+
latencyMs: Date.now() - start,
|
|
3197
|
+
usage: { cost: 0, unit: "per_video" },
|
|
3198
|
+
media: { format: "mp4", duration: options.duration }
|
|
3199
|
+
};
|
|
3200
|
+
}
|
|
3201
|
+
throw new Error("Google video generation completed but returned no video data");
|
|
3000
3202
|
}
|
|
3001
3203
|
}
|
|
3002
3204
|
throw new Error(`Google video generation timed out after 5 minutes`);
|
|
@@ -3193,6 +3395,12 @@ var Noosphere = class {
|
|
|
3193
3395
|
getUsage(options) {
|
|
3194
3396
|
return this.tracker.getSummary(options);
|
|
3195
3397
|
}
|
|
3398
|
+
async countTokens(options) {
|
|
3399
|
+
const keys = {};
|
|
3400
|
+
if (this.config.keys?.google) keys.google = this.config.keys.google;
|
|
3401
|
+
if (this.config.keys?.anthropic) keys.anthropic = this.config.keys.anthropic;
|
|
3402
|
+
return countTokens(options, keys);
|
|
3403
|
+
}
|
|
3196
3404
|
// --- Local Model Management ---
|
|
3197
3405
|
async installModel(name) {
|
|
3198
3406
|
if (!this.initialized) await this.init();
|
|
@@ -3427,6 +3635,12 @@ var Noosphere = class {
|
|
|
3427
3635
|
await this.tracker.record(event);
|
|
3428
3636
|
}
|
|
3429
3637
|
};
|
|
3638
|
+
|
|
3639
|
+
// src/index.ts
|
|
3640
|
+
import { agentLoop } from "@mariozechner/pi-ai";
|
|
3641
|
+
import { calculateCost, getModel, getModels as getModels2, getProviders as getProviders2 } from "@mariozechner/pi-ai";
|
|
3642
|
+
import { stream as stream2, complete as complete2, streamSimple, completeSimple } from "@mariozechner/pi-ai";
|
|
3643
|
+
import { setApiKey as setApiKey2, getApiKey } from "@mariozechner/pi-ai";
|
|
3430
3644
|
export {
|
|
3431
3645
|
AudioCraftProvider,
|
|
3432
3646
|
GoogleMediaProvider,
|
|
@@ -3439,8 +3653,29 @@ export {
|
|
|
3439
3653
|
PROVIDER_IDS,
|
|
3440
3654
|
PROVIDER_LOGOS,
|
|
3441
3655
|
WhisperLocalProvider,
|
|
3656
|
+
agentLoop,
|
|
3657
|
+
calculateCost,
|
|
3658
|
+
countTokens,
|
|
3659
|
+
countTokensAnthropic,
|
|
3660
|
+
countTokensCerebras,
|
|
3661
|
+
countTokensGoogle,
|
|
3662
|
+
countTokensGroq,
|
|
3663
|
+
countTokensMistral,
|
|
3664
|
+
countTokensOllama,
|
|
3665
|
+
countTokensOpenAI,
|
|
3666
|
+
countTokensOpenRouter,
|
|
3667
|
+
countTokensXai,
|
|
3442
3668
|
detectOpenAICompatServers,
|
|
3443
3669
|
getAllProviderLogos,
|
|
3444
|
-
|
|
3670
|
+
getApiKey,
|
|
3671
|
+
getModel as getPiModel,
|
|
3672
|
+
getModels2 as getPiModels,
|
|
3673
|
+
getProviders2 as getPiProviders,
|
|
3674
|
+
getProviderLogo,
|
|
3675
|
+
complete2 as piComplete,
|
|
3676
|
+
completeSimple as piCompleteSimple,
|
|
3677
|
+
stream2 as piStream,
|
|
3678
|
+
streamSimple as piStreamSimple,
|
|
3679
|
+
setApiKey2 as setApiKey
|
|
3445
3680
|
};
|
|
3446
3681
|
//# sourceMappingURL=index.js.map
|