joopjs 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 +678 -0
- package/README.md +583 -0
- package/dist/a11y.service-C-DQQfgO.d.mts +143 -0
- package/dist/a11y.service-CauEJrJe.d.ts +143 -0
- package/dist/adapters-B6slG6hQ.d.mts +84 -0
- package/dist/adapters-B6slG6hQ.d.ts +84 -0
- package/dist/aes.service-CkoupAww.d.mts +95 -0
- package/dist/aes.service-CkoupAww.d.ts +95 -0
- package/dist/ai/index.d.mts +99 -0
- package/dist/ai/index.d.ts +99 -0
- package/dist/ai/index.js +307 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/index.mjs +304 -0
- package/dist/ai/index.mjs.map +1 -0
- package/dist/analytics/index.d.mts +42 -0
- package/dist/analytics/index.d.ts +42 -0
- package/dist/analytics/index.js +139 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/index.mjs +136 -0
- package/dist/analytics/index.mjs.map +1 -0
- package/dist/angular/index.d.mts +148 -0
- package/dist/angular/index.d.ts +148 -0
- package/dist/angular/index.js +122 -0
- package/dist/angular/index.js.map +1 -0
- package/dist/angular/index.mjs +101 -0
- package/dist/angular/index.mjs.map +1 -0
- package/dist/api/index.d.mts +128 -0
- package/dist/api/index.d.ts +128 -0
- package/dist/api/index.js +1358 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/index.mjs +1332 -0
- package/dist/api/index.mjs.map +1 -0
- package/dist/auth/index.d.mts +105 -0
- package/dist/auth/index.d.ts +105 -0
- package/dist/auth/index.js +989 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/index.mjs +979 -0
- package/dist/auth/index.mjs.map +1 -0
- package/dist/auth.service-DNVB-L4U.d.mts +16 -0
- package/dist/auth.service-PjUUSUIt.d.ts +16 -0
- package/dist/banking/index.d.mts +1530 -0
- package/dist/banking/index.d.ts +1530 -0
- package/dist/banking/index.js +4739 -0
- package/dist/banking/index.js.map +1 -0
- package/dist/banking/index.mjs +4661 -0
- package/dist/banking/index.mjs.map +1 -0
- package/dist/cache/index.d.mts +40 -0
- package/dist/cache/index.d.ts +40 -0
- package/dist/cache/index.js +174 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/index.mjs +172 -0
- package/dist/cache/index.mjs.map +1 -0
- package/dist/client-profile.service-BuPeXVp5.d.mts +28 -0
- package/dist/client-profile.service-D5bRRYQp.d.ts +28 -0
- package/dist/config.models-Cqg04fAQ.d.mts +84 -0
- package/dist/config.models-Cqg04fAQ.d.ts +84 -0
- package/dist/config.service-CrCvI-JS.d.ts +31 -0
- package/dist/config.service-Cz4QQLlf.d.mts +31 -0
- package/dist/core/index.d.mts +4 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +631 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/index.mjs +619 -0
- package/dist/core/index.mjs.map +1 -0
- package/dist/crypto-utils-DriNhLdx.d.mts +30 -0
- package/dist/crypto-utils-DriNhLdx.d.ts +30 -0
- package/dist/data-storage.service-DT6xaTxE.d.ts +51 -0
- package/dist/data-storage.service-LvhGRCmw.d.mts +51 -0
- package/dist/deeplink/index.d.mts +39 -0
- package/dist/deeplink/index.d.ts +39 -0
- package/dist/deeplink/index.js +268 -0
- package/dist/deeplink/index.js.map +1 -0
- package/dist/deeplink/index.mjs +265 -0
- package/dist/deeplink/index.mjs.map +1 -0
- package/dist/deeplink.service-Ctd5u243.d.mts +35 -0
- package/dist/deeplink.service-uUuTnY9_.d.ts +35 -0
- package/dist/dev/index.d.mts +20 -0
- package/dist/dev/index.d.ts +20 -0
- package/dist/dev/index.js +51 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/index.mjs +49 -0
- package/dist/dev/index.mjs.map +1 -0
- package/dist/device/index.d.mts +108 -0
- package/dist/device/index.d.ts +108 -0
- package/dist/device/index.js +960 -0
- package/dist/device/index.js.map +1 -0
- package/dist/device/index.mjs +951 -0
- package/dist/device/index.mjs.map +1 -0
- package/dist/differential-privacy-BcAv1G80.d.mts +210 -0
- package/dist/differential-privacy-C8mAUjZr.d.ts +210 -0
- package/dist/encryption/index.d.mts +75 -0
- package/dist/encryption/index.d.ts +75 -0
- package/dist/encryption/index.js +605 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/encryption/index.mjs +598 -0
- package/dist/encryption/index.mjs.map +1 -0
- package/dist/form-validator-3tkmzr_o.d.mts +72 -0
- package/dist/form-validator-3tkmzr_o.d.ts +72 -0
- package/dist/forms/index.d.mts +59 -0
- package/dist/forms/index.d.ts +59 -0
- package/dist/forms/index.js +446 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/index.mjs +442 -0
- package/dist/forms/index.mjs.map +1 -0
- package/dist/i18n/index.d.mts +37 -0
- package/dist/i18n/index.d.ts +37 -0
- package/dist/i18n/index.js +147 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/index.mjs +145 -0
- package/dist/i18n/index.mjs.map +1 -0
- package/dist/idempotency.service-_6LqhivP.d.mts +372 -0
- package/dist/idempotency.service-eOKoISRD.d.ts +372 -0
- package/dist/index-B_ksKpS1.d.mts +202 -0
- package/dist/index-CqDKWTUP.d.mts +28 -0
- package/dist/index-CqDKWTUP.d.ts +28 -0
- package/dist/index-DFqEoX_l.d.ts +202 -0
- package/dist/index-Dz0gOur2.d.mts +36 -0
- package/dist/index-Dz0gOur2.d.ts +36 -0
- package/dist/index.d.mts +1336 -0
- package/dist/index.d.ts +1336 -0
- package/dist/index.js +19464 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +19155 -0
- package/dist/index.mjs.map +1 -0
- package/dist/india/index.d.mts +75 -0
- package/dist/india/index.d.ts +75 -0
- package/dist/india/index.js +325 -0
- package/dist/india/index.js.map +1 -0
- package/dist/india/index.mjs +303 -0
- package/dist/india/index.mjs.map +1 -0
- package/dist/joop-Bx7Iwj5p.d.mts +155 -0
- package/dist/joop-CA3DMeOO.d.ts +155 -0
- package/dist/native-bridge/index.d.mts +27 -0
- package/dist/native-bridge/index.d.ts +27 -0
- package/dist/native-bridge/index.js +98 -0
- package/dist/native-bridge/index.js.map +1 -0
- package/dist/native-bridge/index.mjs +96 -0
- package/dist/native-bridge/index.mjs.map +1 -0
- package/dist/network/index.d.mts +85 -0
- package/dist/network/index.d.ts +85 -0
- package/dist/network/index.js +454 -0
- package/dist/network/index.js.map +1 -0
- package/dist/network/index.mjs +451 -0
- package/dist/network/index.mjs.map +1 -0
- package/dist/network-monitor-BIwPSXme.d.mts +179 -0
- package/dist/network-monitor-Bqp2hvZr.d.ts +179 -0
- package/dist/notification.service-Dm4fvfZf.d.mts +25 -0
- package/dist/notification.service-tEMKatWJ.d.ts +25 -0
- package/dist/observability/index.d.mts +179 -0
- package/dist/observability/index.d.ts +179 -0
- package/dist/observability/index.js +559 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/index.mjs +552 -0
- package/dist/observability/index.mjs.map +1 -0
- package/dist/oidc-client-DIJcClmB.d.mts +190 -0
- package/dist/oidc-client-DxhyE59t.d.ts +190 -0
- package/dist/platform/index.d.mts +73 -0
- package/dist/platform/index.d.ts +73 -0
- package/dist/platform/index.js +127 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/index.mjs +125 -0
- package/dist/platform/index.mjs.map +1 -0
- package/dist/pwa/index.d.mts +31 -0
- package/dist/pwa/index.d.ts +31 -0
- package/dist/pwa/index.js +247 -0
- package/dist/pwa/index.js.map +1 -0
- package/dist/pwa/index.mjs +244 -0
- package/dist/pwa/index.mjs.map +1 -0
- package/dist/react/index.d.mts +133 -0
- package/dist/react/index.d.ts +133 -0
- package/dist/react/index.js +632 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +630 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/router/index.d.mts +39 -0
- package/dist/router/index.d.ts +39 -0
- package/dist/router/index.js +168 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/index.mjs +166 -0
- package/dist/router/index.mjs.map +1 -0
- package/dist/security/index.d.mts +206 -0
- package/dist/security/index.d.ts +206 -0
- package/dist/security/index.js +1297 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/index.mjs +1285 -0
- package/dist/security/index.mjs.map +1 -0
- package/dist/session/index.d.mts +115 -0
- package/dist/session/index.d.ts +115 -0
- package/dist/session/index.js +297 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/index.mjs +292 -0
- package/dist/session/index.mjs.map +1 -0
- package/dist/state/index.d.mts +43 -0
- package/dist/state/index.d.ts +43 -0
- package/dist/state/index.js +156 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/index.mjs +152 -0
- package/dist/state/index.mjs.map +1 -0
- package/dist/statement-parser-BHQtXwCM.d.ts +260 -0
- package/dist/statement-parser-C2qNmb49.d.mts +260 -0
- package/dist/storage/index.d.mts +40 -0
- package/dist/storage/index.d.ts +40 -0
- package/dist/storage/index.js +256 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/index.mjs +252 -0
- package/dist/storage/index.mjs.map +1 -0
- package/dist/sync/index.d.mts +69 -0
- package/dist/sync/index.d.ts +69 -0
- package/dist/sync/index.js +330 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/index.mjs +323 -0
- package/dist/sync/index.mjs.map +1 -0
- package/dist/sync-engine-DCIMRG5s.d.ts +61 -0
- package/dist/sync-engine-DZqyKHkK.d.mts +61 -0
- package/dist/theme/index.d.mts +53 -0
- package/dist/theme/index.d.ts +53 -0
- package/dist/theme/index.js +169 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/index.mjs +167 -0
- package/dist/theme/index.mjs.map +1 -0
- package/dist/ui/index.d.mts +66 -0
- package/dist/ui/index.d.ts +66 -0
- package/dist/ui/index.js +811 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/index.mjs +803 -0
- package/dist/ui/index.mjs.map +1 -0
- package/dist/utilities/index.d.mts +199 -0
- package/dist/utilities/index.d.ts +199 -0
- package/dist/utilities/index.js +1991 -0
- package/dist/utilities/index.js.map +1 -0
- package/dist/utilities/index.mjs +1923 -0
- package/dist/utilities/index.mjs.map +1 -0
- package/dist/validation/index.d.mts +60 -0
- package/dist/validation/index.d.ts +60 -0
- package/dist/validation/index.js +460 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/index.mjs +455 -0
- package/dist/validation/index.mjs.map +1 -0
- package/dist/vue/index.d.mts +135 -0
- package/dist/vue/index.d.ts +135 -0
- package/dist/vue/index.js +621 -0
- package/dist/vue/index.js.map +1 -0
- package/dist/vue/index.mjs +619 -0
- package/dist/vue/index.mjs.map +1 -0
- package/dist/watermark.service-Detur5tq.d.ts +235 -0
- package/dist/watermark.service-QNegMeQZ.d.mts +235 -0
- package/dist/workers/index.d.mts +42 -0
- package/dist/workers/index.d.ts +42 -0
- package/dist/workers/index.js +359 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/index.mjs +356 -0
- package/dist/workers/index.mjs.map +1 -0
- package/dist/workflow/index.d.mts +99 -0
- package/dist/workflow/index.d.ts +99 -0
- package/dist/workflow/index.js +282 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/index.mjs +279 -0
- package/dist/workflow/index.mjs.map +1 -0
- package/package.json +226 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { J as JoopObservable } from '../index-Dz0gOur2.mjs';
|
|
2
|
+
|
|
3
|
+
interface JoopToolParameter {
|
|
4
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
5
|
+
description?: string;
|
|
6
|
+
enum?: unknown[];
|
|
7
|
+
items?: JoopToolParameter;
|
|
8
|
+
properties?: Record<string, JoopToolParameter>;
|
|
9
|
+
required?: string[];
|
|
10
|
+
}
|
|
11
|
+
interface JoopToolDefinition {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
parameters: Record<string, JoopToolParameter>;
|
|
15
|
+
required?: string[];
|
|
16
|
+
handler: (args: Record<string, unknown>) => Promise<unknown>;
|
|
17
|
+
}
|
|
18
|
+
interface JoopToolCall {
|
|
19
|
+
name: string;
|
|
20
|
+
arguments: string | Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
interface JoopToolResult {
|
|
23
|
+
name: string;
|
|
24
|
+
result: unknown;
|
|
25
|
+
error?: string;
|
|
26
|
+
durationMs: number;
|
|
27
|
+
}
|
|
28
|
+
declare class JoopToolRegistry {
|
|
29
|
+
private _tools;
|
|
30
|
+
register(tool: JoopToolDefinition): void;
|
|
31
|
+
update(tool: JoopToolDefinition): void;
|
|
32
|
+
unregister(name: string): void;
|
|
33
|
+
has(name: string): boolean;
|
|
34
|
+
list(): string[];
|
|
35
|
+
get(name: string): JoopToolDefinition | undefined;
|
|
36
|
+
clear(): void;
|
|
37
|
+
dispatch(call: JoopToolCall): Promise<JoopToolResult>;
|
|
38
|
+
/** Dispatch multiple tool calls in parallel */
|
|
39
|
+
dispatchAll(calls: JoopToolCall[]): Promise<JoopToolResult[]>;
|
|
40
|
+
/** Format for OpenAI function-calling */
|
|
41
|
+
toOpenAiFormat(): object[];
|
|
42
|
+
/** Format for Anthropic tool-use */
|
|
43
|
+
toAnthropicFormat(): object[];
|
|
44
|
+
/** Format for Google Gemini function declarations */
|
|
45
|
+
toGeminiFormat(): object[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type JoopAiProvider = 'openai' | 'anthropic' | 'gemini' | 'ollama' | 'custom';
|
|
49
|
+
interface JoopAiMessage {
|
|
50
|
+
role: 'system' | 'user' | 'assistant';
|
|
51
|
+
content: string;
|
|
52
|
+
}
|
|
53
|
+
interface JoopAiConfig {
|
|
54
|
+
provider: JoopAiProvider;
|
|
55
|
+
apiKey?: string;
|
|
56
|
+
baseUrl?: string;
|
|
57
|
+
model: string;
|
|
58
|
+
maxTokens?: number;
|
|
59
|
+
temperature?: number;
|
|
60
|
+
systemPrompt?: string;
|
|
61
|
+
timeout?: number;
|
|
62
|
+
}
|
|
63
|
+
interface JoopAiStreamOptions {
|
|
64
|
+
stream?: boolean;
|
|
65
|
+
onChunk?: (token: string) => void;
|
|
66
|
+
onComplete?: (full: string) => void;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
maxTokens?: number;
|
|
69
|
+
temperature?: number;
|
|
70
|
+
}
|
|
71
|
+
interface JoopAiUsage {
|
|
72
|
+
promptTokens: number;
|
|
73
|
+
completionTokens: number;
|
|
74
|
+
totalTokens: number;
|
|
75
|
+
}
|
|
76
|
+
declare class JoopAiClient {
|
|
77
|
+
private _cfg;
|
|
78
|
+
private _usage$;
|
|
79
|
+
private _abort;
|
|
80
|
+
private _history;
|
|
81
|
+
constructor(config: JoopAiConfig);
|
|
82
|
+
configure(patch: Partial<JoopAiConfig>): void;
|
|
83
|
+
lastUsage(): JoopAiUsage;
|
|
84
|
+
usage$(): JoopObservable<JoopAiUsage>;
|
|
85
|
+
getHistory(): JoopAiMessage[];
|
|
86
|
+
clearHistory(): void;
|
|
87
|
+
abort(): void;
|
|
88
|
+
/** Approximate token count (4 chars ≈ 1 token) */
|
|
89
|
+
estimateTokens(text: string): number;
|
|
90
|
+
complete(prompt: string, opts?: JoopAiStreamOptions): Promise<string>;
|
|
91
|
+
chat(messages: JoopAiMessage[], opts?: JoopAiStreamOptions): Promise<string>;
|
|
92
|
+
private _fetchChat;
|
|
93
|
+
private _streamChat;
|
|
94
|
+
private _buildRequest;
|
|
95
|
+
private _parseStreamLine;
|
|
96
|
+
private _extractContent;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { JoopAiClient, type JoopAiConfig, type JoopAiMessage, type JoopAiProvider, type JoopAiStreamOptions, type JoopAiUsage, type JoopToolCall, type JoopToolDefinition, type JoopToolParameter, JoopToolRegistry, type JoopToolResult };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { J as JoopObservable } from '../index-Dz0gOur2.js';
|
|
2
|
+
|
|
3
|
+
interface JoopToolParameter {
|
|
4
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
5
|
+
description?: string;
|
|
6
|
+
enum?: unknown[];
|
|
7
|
+
items?: JoopToolParameter;
|
|
8
|
+
properties?: Record<string, JoopToolParameter>;
|
|
9
|
+
required?: string[];
|
|
10
|
+
}
|
|
11
|
+
interface JoopToolDefinition {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
parameters: Record<string, JoopToolParameter>;
|
|
15
|
+
required?: string[];
|
|
16
|
+
handler: (args: Record<string, unknown>) => Promise<unknown>;
|
|
17
|
+
}
|
|
18
|
+
interface JoopToolCall {
|
|
19
|
+
name: string;
|
|
20
|
+
arguments: string | Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
interface JoopToolResult {
|
|
23
|
+
name: string;
|
|
24
|
+
result: unknown;
|
|
25
|
+
error?: string;
|
|
26
|
+
durationMs: number;
|
|
27
|
+
}
|
|
28
|
+
declare class JoopToolRegistry {
|
|
29
|
+
private _tools;
|
|
30
|
+
register(tool: JoopToolDefinition): void;
|
|
31
|
+
update(tool: JoopToolDefinition): void;
|
|
32
|
+
unregister(name: string): void;
|
|
33
|
+
has(name: string): boolean;
|
|
34
|
+
list(): string[];
|
|
35
|
+
get(name: string): JoopToolDefinition | undefined;
|
|
36
|
+
clear(): void;
|
|
37
|
+
dispatch(call: JoopToolCall): Promise<JoopToolResult>;
|
|
38
|
+
/** Dispatch multiple tool calls in parallel */
|
|
39
|
+
dispatchAll(calls: JoopToolCall[]): Promise<JoopToolResult[]>;
|
|
40
|
+
/** Format for OpenAI function-calling */
|
|
41
|
+
toOpenAiFormat(): object[];
|
|
42
|
+
/** Format for Anthropic tool-use */
|
|
43
|
+
toAnthropicFormat(): object[];
|
|
44
|
+
/** Format for Google Gemini function declarations */
|
|
45
|
+
toGeminiFormat(): object[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type JoopAiProvider = 'openai' | 'anthropic' | 'gemini' | 'ollama' | 'custom';
|
|
49
|
+
interface JoopAiMessage {
|
|
50
|
+
role: 'system' | 'user' | 'assistant';
|
|
51
|
+
content: string;
|
|
52
|
+
}
|
|
53
|
+
interface JoopAiConfig {
|
|
54
|
+
provider: JoopAiProvider;
|
|
55
|
+
apiKey?: string;
|
|
56
|
+
baseUrl?: string;
|
|
57
|
+
model: string;
|
|
58
|
+
maxTokens?: number;
|
|
59
|
+
temperature?: number;
|
|
60
|
+
systemPrompt?: string;
|
|
61
|
+
timeout?: number;
|
|
62
|
+
}
|
|
63
|
+
interface JoopAiStreamOptions {
|
|
64
|
+
stream?: boolean;
|
|
65
|
+
onChunk?: (token: string) => void;
|
|
66
|
+
onComplete?: (full: string) => void;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
maxTokens?: number;
|
|
69
|
+
temperature?: number;
|
|
70
|
+
}
|
|
71
|
+
interface JoopAiUsage {
|
|
72
|
+
promptTokens: number;
|
|
73
|
+
completionTokens: number;
|
|
74
|
+
totalTokens: number;
|
|
75
|
+
}
|
|
76
|
+
declare class JoopAiClient {
|
|
77
|
+
private _cfg;
|
|
78
|
+
private _usage$;
|
|
79
|
+
private _abort;
|
|
80
|
+
private _history;
|
|
81
|
+
constructor(config: JoopAiConfig);
|
|
82
|
+
configure(patch: Partial<JoopAiConfig>): void;
|
|
83
|
+
lastUsage(): JoopAiUsage;
|
|
84
|
+
usage$(): JoopObservable<JoopAiUsage>;
|
|
85
|
+
getHistory(): JoopAiMessage[];
|
|
86
|
+
clearHistory(): void;
|
|
87
|
+
abort(): void;
|
|
88
|
+
/** Approximate token count (4 chars ≈ 1 token) */
|
|
89
|
+
estimateTokens(text: string): number;
|
|
90
|
+
complete(prompt: string, opts?: JoopAiStreamOptions): Promise<string>;
|
|
91
|
+
chat(messages: JoopAiMessage[], opts?: JoopAiStreamOptions): Promise<string>;
|
|
92
|
+
private _fetchChat;
|
|
93
|
+
private _streamChat;
|
|
94
|
+
private _buildRequest;
|
|
95
|
+
private _parseStreamLine;
|
|
96
|
+
private _extractContent;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { JoopAiClient, type JoopAiConfig, type JoopAiMessage, type JoopAiProvider, type JoopAiStreamOptions, type JoopAiUsage, type JoopToolCall, type JoopToolDefinition, type JoopToolParameter, JoopToolRegistry, type JoopToolResult };
|
package/dist/ai/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/events/index.ts
|
|
4
|
+
var JoopSubject = class {
|
|
5
|
+
_listeners = [];
|
|
6
|
+
subscribe(listener) {
|
|
7
|
+
this._listeners.push(listener);
|
|
8
|
+
return () => {
|
|
9
|
+
this._listeners = this._listeners.filter((l) => l !== listener);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
next(value) {
|
|
13
|
+
for (const listener of this._listeners) {
|
|
14
|
+
listener(value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
asObservable() {
|
|
18
|
+
return new JoopObservable((listener) => this.subscribe(listener));
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var JoopBehaviorSubject = class extends JoopSubject {
|
|
22
|
+
_value;
|
|
23
|
+
constructor(initialValue) {
|
|
24
|
+
super();
|
|
25
|
+
this._value = initialValue;
|
|
26
|
+
}
|
|
27
|
+
getValue() {
|
|
28
|
+
return this._value;
|
|
29
|
+
}
|
|
30
|
+
next(value) {
|
|
31
|
+
this._value = value;
|
|
32
|
+
super.next(value);
|
|
33
|
+
}
|
|
34
|
+
subscribe(listener) {
|
|
35
|
+
listener(this._value);
|
|
36
|
+
return super.subscribe(listener);
|
|
37
|
+
}
|
|
38
|
+
asObservable() {
|
|
39
|
+
return new JoopObservable((listener) => this.subscribe(listener));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var JoopObservable = class {
|
|
43
|
+
constructor(_subscribeFn) {
|
|
44
|
+
this._subscribeFn = _subscribeFn;
|
|
45
|
+
}
|
|
46
|
+
_subscribeFn;
|
|
47
|
+
subscribe(listener) {
|
|
48
|
+
return this._subscribeFn(listener);
|
|
49
|
+
}
|
|
50
|
+
/** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */
|
|
51
|
+
getOnce() {
|
|
52
|
+
let result;
|
|
53
|
+
const unsub = this.subscribe((v) => {
|
|
54
|
+
result = v;
|
|
55
|
+
});
|
|
56
|
+
unsub();
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// src/ai/ai-client.ts
|
|
62
|
+
var PROVIDER_DEFAULTS = {
|
|
63
|
+
openai: { baseUrl: "https://api.openai.com" },
|
|
64
|
+
anthropic: { baseUrl: "https://api.anthropic.com" },
|
|
65
|
+
gemini: { baseUrl: "https://generativelanguage.googleapis.com" },
|
|
66
|
+
ollama: { baseUrl: "http://localhost:11434" },
|
|
67
|
+
custom: { baseUrl: "" }
|
|
68
|
+
};
|
|
69
|
+
var JoopAiClient = class {
|
|
70
|
+
_cfg;
|
|
71
|
+
_usage$ = new JoopBehaviorSubject({ promptTokens: 0, completionTokens: 0, totalTokens: 0 });
|
|
72
|
+
_abort = null;
|
|
73
|
+
_history = [];
|
|
74
|
+
constructor(config) {
|
|
75
|
+
this._cfg = config;
|
|
76
|
+
}
|
|
77
|
+
configure(patch) {
|
|
78
|
+
this._cfg = { ...this._cfg, ...patch };
|
|
79
|
+
}
|
|
80
|
+
lastUsage() {
|
|
81
|
+
return this._usage$.getValue();
|
|
82
|
+
}
|
|
83
|
+
usage$() {
|
|
84
|
+
return this._usage$.asObservable();
|
|
85
|
+
}
|
|
86
|
+
getHistory() {
|
|
87
|
+
return [...this._history];
|
|
88
|
+
}
|
|
89
|
+
clearHistory() {
|
|
90
|
+
this._history = [];
|
|
91
|
+
}
|
|
92
|
+
abort() {
|
|
93
|
+
this._abort?.abort();
|
|
94
|
+
this._abort = null;
|
|
95
|
+
}
|
|
96
|
+
/** Approximate token count (4 chars ≈ 1 token) */
|
|
97
|
+
estimateTokens(text) {
|
|
98
|
+
return Math.ceil(text.length / 4);
|
|
99
|
+
}
|
|
100
|
+
async complete(prompt, opts = {}) {
|
|
101
|
+
return this.chat([{ role: "user", content: prompt }], opts);
|
|
102
|
+
}
|
|
103
|
+
async chat(messages, opts = {}) {
|
|
104
|
+
this._abort = new AbortController();
|
|
105
|
+
const signal = opts.signal ? _combineSignals(opts.signal, this._abort.signal) : this._abort.signal;
|
|
106
|
+
const allMessages = [];
|
|
107
|
+
if (this._cfg.systemPrompt) allMessages.push({ role: "system", content: this._cfg.systemPrompt });
|
|
108
|
+
allMessages.push(...this._history, ...messages);
|
|
109
|
+
const result = opts.stream !== false ? await this._streamChat(allMessages, opts, signal) : await this._fetchChat(allMessages, opts, signal);
|
|
110
|
+
for (const m of messages) this._history.push(m);
|
|
111
|
+
this._history.push({ role: "assistant", content: result });
|
|
112
|
+
opts.onComplete?.(result);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
async _fetchChat(messages, opts, signal) {
|
|
116
|
+
const { url, headers, body } = this._buildRequest(messages, opts, false);
|
|
117
|
+
const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body), signal });
|
|
118
|
+
if (!res.ok) throw new Error(`JoopAiClient: ${res.status} ${await res.text()}`);
|
|
119
|
+
const json = await res.json();
|
|
120
|
+
return this._extractContent(json);
|
|
121
|
+
}
|
|
122
|
+
async _streamChat(messages, opts, signal) {
|
|
123
|
+
const { url, headers, body } = this._buildRequest(messages, opts, true);
|
|
124
|
+
const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body), signal });
|
|
125
|
+
if (!res.ok) throw new Error(`JoopAiClient: ${res.status} ${await res.text()}`);
|
|
126
|
+
const reader = res.body.getReader();
|
|
127
|
+
const decoder = new TextDecoder();
|
|
128
|
+
let full = "";
|
|
129
|
+
let buf = "";
|
|
130
|
+
while (true) {
|
|
131
|
+
const { done, value } = await reader.read();
|
|
132
|
+
if (done) break;
|
|
133
|
+
buf += decoder.decode(value, { stream: true });
|
|
134
|
+
const lines = buf.split("\n");
|
|
135
|
+
buf = lines.pop() ?? "";
|
|
136
|
+
for (const line of lines) {
|
|
137
|
+
const token = this._parseStreamLine(line.trim());
|
|
138
|
+
if (token) {
|
|
139
|
+
full += token;
|
|
140
|
+
opts.onChunk?.(token);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return full;
|
|
145
|
+
}
|
|
146
|
+
_buildRequest(messages, opts, stream) {
|
|
147
|
+
const { provider, apiKey, model, maxTokens, temperature } = this._cfg;
|
|
148
|
+
const baseUrl = this._cfg.baseUrl ?? PROVIDER_DEFAULTS[provider].baseUrl;
|
|
149
|
+
const mt = opts.maxTokens ?? maxTokens ?? 1024;
|
|
150
|
+
const temp = opts.temperature ?? temperature ?? 0.7;
|
|
151
|
+
switch (provider) {
|
|
152
|
+
case "openai":
|
|
153
|
+
case "custom":
|
|
154
|
+
return {
|
|
155
|
+
url: `${baseUrl}/v1/chat/completions`,
|
|
156
|
+
headers: { "Content-Type": "application/json", ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {} },
|
|
157
|
+
body: { model, messages, stream, max_tokens: mt, temperature: temp }
|
|
158
|
+
};
|
|
159
|
+
case "anthropic":
|
|
160
|
+
return {
|
|
161
|
+
url: `${baseUrl}/v1/messages`,
|
|
162
|
+
headers: { "Content-Type": "application/json", "x-api-key": apiKey ?? "", "anthropic-version": "2023-06-01" },
|
|
163
|
+
body: {
|
|
164
|
+
model,
|
|
165
|
+
stream,
|
|
166
|
+
max_tokens: mt,
|
|
167
|
+
temperature: temp,
|
|
168
|
+
system: messages.find((m) => m.role === "system")?.content,
|
|
169
|
+
messages: messages.filter((m) => m.role !== "system")
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
case "gemini": {
|
|
173
|
+
const contents = messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role === "assistant" ? "model" : "user", parts: [{ text: m.content }] }));
|
|
174
|
+
const path = stream ? "streamGenerateContent?alt=sse" : "generateContent";
|
|
175
|
+
return {
|
|
176
|
+
url: `${baseUrl}/v1beta/models/${model}:${path}${apiKey ? `&key=${apiKey}` : ""}`,
|
|
177
|
+
headers: { "Content-Type": "application/json" },
|
|
178
|
+
body: { contents, generationConfig: { maxOutputTokens: mt, temperature: temp } }
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
case "ollama":
|
|
182
|
+
return {
|
|
183
|
+
url: `${baseUrl}/api/chat`,
|
|
184
|
+
headers: { "Content-Type": "application/json" },
|
|
185
|
+
body: { model, messages, stream, options: { num_predict: mt, temperature: temp } }
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
_parseStreamLine(line) {
|
|
190
|
+
if (!line.startsWith("data: ") && !line.startsWith("{")) return "";
|
|
191
|
+
const raw = line.startsWith("data: ") ? line.slice(6) : line;
|
|
192
|
+
if (raw === "[DONE]") return "";
|
|
193
|
+
try {
|
|
194
|
+
const json = JSON.parse(raw);
|
|
195
|
+
const oaChoice = json?.choices?.[0];
|
|
196
|
+
if (oaChoice?.delta?.content) return oaChoice.delta.content;
|
|
197
|
+
if (json?.type === "content_block_delta") return json?.delta?.text ?? "";
|
|
198
|
+
const gmPart = json?.candidates?.[0]?.content?.parts?.[0];
|
|
199
|
+
if (gmPart?.text) return gmPart.text;
|
|
200
|
+
if (json?.message?.content) return json.message.content;
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
return "";
|
|
204
|
+
}
|
|
205
|
+
_extractContent(json) {
|
|
206
|
+
const j = json;
|
|
207
|
+
const oa = j?.choices?.[0]?.message?.content;
|
|
208
|
+
if (oa) return oa;
|
|
209
|
+
const an = j?.content?.[0]?.text;
|
|
210
|
+
if (an) return an;
|
|
211
|
+
const gm = j?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
212
|
+
if (gm) return gm;
|
|
213
|
+
const ol = j?.message?.content;
|
|
214
|
+
if (ol) return ol;
|
|
215
|
+
return "";
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
function _combineSignals(...signals) {
|
|
219
|
+
const ctrl = new AbortController();
|
|
220
|
+
for (const s of signals) s.addEventListener("abort", () => ctrl.abort(), { once: true });
|
|
221
|
+
return ctrl.signal;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/ai/tool-registry.ts
|
|
225
|
+
var JoopToolRegistry = class {
|
|
226
|
+
_tools = /* @__PURE__ */ new Map();
|
|
227
|
+
register(tool) {
|
|
228
|
+
if (this._tools.has(tool.name)) throw new Error(`Tool '${tool.name}' already registered. Use update() to replace.`);
|
|
229
|
+
this._tools.set(tool.name, tool);
|
|
230
|
+
}
|
|
231
|
+
update(tool) {
|
|
232
|
+
this._tools.set(tool.name, tool);
|
|
233
|
+
}
|
|
234
|
+
unregister(name) {
|
|
235
|
+
this._tools.delete(name);
|
|
236
|
+
}
|
|
237
|
+
has(name) {
|
|
238
|
+
return this._tools.has(name);
|
|
239
|
+
}
|
|
240
|
+
list() {
|
|
241
|
+
return Array.from(this._tools.keys());
|
|
242
|
+
}
|
|
243
|
+
get(name) {
|
|
244
|
+
return this._tools.get(name);
|
|
245
|
+
}
|
|
246
|
+
clear() {
|
|
247
|
+
this._tools.clear();
|
|
248
|
+
}
|
|
249
|
+
async dispatch(call) {
|
|
250
|
+
const tool = this._tools.get(call.name);
|
|
251
|
+
if (!tool) return { name: call.name, result: null, error: `Unknown tool: ${call.name}`, durationMs: 0 };
|
|
252
|
+
const args = typeof call.arguments === "string" ? JSON.parse(call.arguments) : call.arguments;
|
|
253
|
+
const t0 = Date.now();
|
|
254
|
+
try {
|
|
255
|
+
const result = await tool.handler(args);
|
|
256
|
+
return { name: call.name, result, durationMs: Date.now() - t0 };
|
|
257
|
+
} catch (e) {
|
|
258
|
+
return { name: call.name, result: null, error: String(e), durationMs: Date.now() - t0 };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** Dispatch multiple tool calls in parallel */
|
|
262
|
+
async dispatchAll(calls) {
|
|
263
|
+
return Promise.all(calls.map((c) => this.dispatch(c)));
|
|
264
|
+
}
|
|
265
|
+
/** Format for OpenAI function-calling */
|
|
266
|
+
toOpenAiFormat() {
|
|
267
|
+
return Array.from(this._tools.values()).map((t) => ({
|
|
268
|
+
type: "function",
|
|
269
|
+
function: {
|
|
270
|
+
name: t.name,
|
|
271
|
+
description: t.description,
|
|
272
|
+
parameters: {
|
|
273
|
+
type: "object",
|
|
274
|
+
properties: t.parameters,
|
|
275
|
+
required: t.required ?? []
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
/** Format for Anthropic tool-use */
|
|
281
|
+
toAnthropicFormat() {
|
|
282
|
+
return Array.from(this._tools.values()).map((t) => ({
|
|
283
|
+
name: t.name,
|
|
284
|
+
description: t.description,
|
|
285
|
+
input_schema: {
|
|
286
|
+
type: "object",
|
|
287
|
+
properties: t.parameters,
|
|
288
|
+
required: t.required ?? []
|
|
289
|
+
}
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
/** Format for Google Gemini function declarations */
|
|
293
|
+
toGeminiFormat() {
|
|
294
|
+
return [{
|
|
295
|
+
function_declarations: Array.from(this._tools.values()).map((t) => ({
|
|
296
|
+
name: t.name,
|
|
297
|
+
description: t.description,
|
|
298
|
+
parameters: { type: "object", properties: t.parameters, required: t.required ?? [] }
|
|
299
|
+
}))
|
|
300
|
+
}];
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
exports.JoopAiClient = JoopAiClient;
|
|
305
|
+
exports.JoopToolRegistry = JoopToolRegistry;
|
|
306
|
+
//# sourceMappingURL=index.js.map
|
|
307
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/events/index.ts","../../src/ai/ai-client.ts","../../src/ai/tool-registry.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export type Unsubscribe = () => void;\nexport type Listener<T> = (value: T) => void;\n\n/**\n * Lightweight pub/sub subject — emits to all current subscribers.\n * Replaces RxJS Subject without pulling in the full RxJS dependency.\n */\nexport class JoopSubject<T> {\n private _listeners: Listener<T>[] = [];\n\n subscribe(listener: Listener<T>): Unsubscribe {\n this._listeners.push(listener);\n return () => {\n this._listeners = this._listeners.filter(l => l !== listener);\n };\n }\n\n next(value: T): void {\n for (const listener of this._listeners) {\n listener(value);\n }\n }\n\n asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Stateful subject — replays the current value to any new subscriber immediately.\n * Replaces RxJS BehaviorSubject.\n */\nexport class JoopBehaviorSubject<T> extends JoopSubject<T> {\n private _value: T;\n\n constructor(initialValue: T) {\n super();\n this._value = initialValue;\n }\n\n getValue(): T {\n return this._value;\n }\n\n override next(value: T): void {\n this._value = value;\n super.next(value);\n }\n\n override subscribe(listener: Listener<T>): Unsubscribe {\n listener(this._value);\n return super.subscribe(listener);\n }\n\n override asObservable(): JoopObservable<T> {\n return new JoopObservable<T>(listener => this.subscribe(listener));\n }\n}\n\n/**\n * Read-only observable handle returned from asObservable().\n */\nexport class JoopObservable<T> {\n constructor(private _subscribeFn: (listener: Listener<T>) => Unsubscribe) {}\n\n subscribe(listener: Listener<T>): Unsubscribe {\n return this._subscribeFn(listener);\n }\n\n /** Returns the current value without subscribing (only meaningful for BehaviorSubject-backed observables). */\n getOnce(): T | undefined {\n let result: T | undefined;\n const unsub = this.subscribe(v => { result = v; });\n unsub();\n return result;\n }\n}\n","import { JoopBehaviorSubject } from '../events';\n\nexport type JoopAiProvider = 'openai' | 'anthropic' | 'gemini' | 'ollama' | 'custom';\n\nexport interface JoopAiMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport interface JoopAiConfig {\n provider: JoopAiProvider;\n apiKey?: string;\n baseUrl?: string;\n model: string;\n maxTokens?: number;\n temperature?: number;\n systemPrompt?: string;\n timeout?: number;\n}\n\nexport interface JoopAiStreamOptions {\n stream?: boolean;\n onChunk?: (token: string) => void;\n onComplete?: (full: string) => void;\n signal?: AbortSignal;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface JoopAiUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\nconst PROVIDER_DEFAULTS: Record<JoopAiProvider, { baseUrl: string }> = {\n openai: { baseUrl: 'https://api.openai.com' },\n anthropic: { baseUrl: 'https://api.anthropic.com' },\n gemini: { baseUrl: 'https://generativelanguage.googleapis.com' },\n ollama: { baseUrl: 'http://localhost:11434' },\n custom: { baseUrl: '' },\n};\n\nexport class JoopAiClient {\n private _cfg: JoopAiConfig;\n private _usage$ = new JoopBehaviorSubject<JoopAiUsage>({ promptTokens: 0, completionTokens: 0, totalTokens: 0 });\n private _abort: AbortController | null = null;\n private _history: JoopAiMessage[] = [];\n\n constructor(config: JoopAiConfig) { this._cfg = config; }\n\n configure(patch: Partial<JoopAiConfig>): void { this._cfg = { ...this._cfg, ...patch }; }\n lastUsage(): JoopAiUsage { return this._usage$.getValue(); }\n usage$() { return this._usage$.asObservable(); }\n getHistory(): JoopAiMessage[] { return [...this._history]; }\n clearHistory(): void { this._history = []; }\n\n abort(): void { this._abort?.abort(); this._abort = null; }\n\n /** Approximate token count (4 chars ≈ 1 token) */\n estimateTokens(text: string): number { return Math.ceil(text.length / 4); }\n\n async complete(prompt: string, opts: JoopAiStreamOptions = {}): Promise<string> {\n return this.chat([{ role: 'user', content: prompt }], opts);\n }\n\n async chat(messages: JoopAiMessage[], opts: JoopAiStreamOptions = {}): Promise<string> {\n this._abort = new AbortController();\n const signal = opts.signal\n ? _combineSignals(opts.signal, this._abort.signal)\n : this._abort.signal;\n\n const allMessages: JoopAiMessage[] = [];\n if (this._cfg.systemPrompt) allMessages.push({ role: 'system', content: this._cfg.systemPrompt });\n allMessages.push(...this._history, ...messages);\n\n const result = opts.stream !== false\n ? await this._streamChat(allMessages, opts, signal)\n : await this._fetchChat(allMessages, opts, signal);\n\n // Append to history\n for (const m of messages) this._history.push(m);\n this._history.push({ role: 'assistant', content: result });\n\n opts.onComplete?.(result);\n return result;\n }\n\n private async _fetchChat(messages: JoopAiMessage[], opts: JoopAiStreamOptions, signal: AbortSignal): Promise<string> {\n const { url, headers, body } = this._buildRequest(messages, opts, false);\n const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body), signal });\n if (!res.ok) throw new Error(`JoopAiClient: ${res.status} ${await res.text()}`);\n const json = await res.json();\n return this._extractContent(json);\n }\n\n private async _streamChat(messages: JoopAiMessage[], opts: JoopAiStreamOptions, signal: AbortSignal): Promise<string> {\n const { url, headers, body } = this._buildRequest(messages, opts, true);\n const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body), signal });\n if (!res.ok) throw new Error(`JoopAiClient: ${res.status} ${await res.text()}`);\n\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let full = '';\n let buf = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split('\\n');\n buf = lines.pop() ?? '';\n for (const line of lines) {\n const token = this._parseStreamLine(line.trim());\n if (token) { full += token; opts.onChunk?.(token); }\n }\n }\n return full;\n }\n\n private _buildRequest(messages: JoopAiMessage[], opts: JoopAiStreamOptions, stream: boolean): { url: string; headers: Record<string, string>; body: unknown } {\n const { provider, apiKey, model, maxTokens, temperature } = this._cfg;\n const baseUrl = this._cfg.baseUrl ?? PROVIDER_DEFAULTS[provider].baseUrl;\n const mt = opts.maxTokens ?? maxTokens ?? 1024;\n const temp = opts.temperature ?? temperature ?? 0.7;\n\n switch (provider) {\n case 'openai':\n case 'custom':\n return {\n url: `${baseUrl}/v1/chat/completions`,\n headers: { 'Content-Type': 'application/json', ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}) },\n body: { model, messages, stream, max_tokens: mt, temperature: temp },\n };\n case 'anthropic':\n return {\n url: `${baseUrl}/v1/messages`,\n headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey ?? '', 'anthropic-version': '2023-06-01' },\n body: {\n model, stream, max_tokens: mt, temperature: temp,\n system: messages.find(m => m.role === 'system')?.content,\n messages: messages.filter(m => m.role !== 'system'),\n },\n };\n case 'gemini': {\n const contents = messages.filter(m => m.role !== 'system').map(m => ({ role: m.role === 'assistant' ? 'model' : 'user', parts: [{ text: m.content }] }));\n const path = stream ? 'streamGenerateContent?alt=sse' : 'generateContent';\n return {\n url: `${baseUrl}/v1beta/models/${model}:${path}${apiKey ? `&key=${apiKey}` : ''}`,\n headers: { 'Content-Type': 'application/json' },\n body: { contents, generationConfig: { maxOutputTokens: mt, temperature: temp } },\n };\n }\n case 'ollama':\n return {\n url: `${baseUrl}/api/chat`,\n headers: { 'Content-Type': 'application/json' },\n body: { model, messages, stream, options: { num_predict: mt, temperature: temp } },\n };\n }\n }\n\n private _parseStreamLine(line: string): string {\n if (!line.startsWith('data: ') && !line.startsWith('{')) return '';\n const raw = line.startsWith('data: ') ? line.slice(6) : line;\n if (raw === '[DONE]') return '';\n try {\n const json = JSON.parse(raw);\n // OpenAI\n const oaChoice = json?.choices?.[0];\n if (oaChoice?.delta?.content) return oaChoice.delta.content;\n // Anthropic\n if (json?.type === 'content_block_delta') return json?.delta?.text ?? '';\n // Gemini\n const gmPart = json?.candidates?.[0]?.content?.parts?.[0];\n if (gmPart?.text) return gmPart.text;\n // Ollama\n if (json?.message?.content) return json.message.content;\n } catch {}\n return '';\n }\n\n private _extractContent(json: unknown): string {\n const j = json as Record<string, unknown>;\n // OpenAI\n const oa = (j?.choices as Array<{message:{content:string}}>)?.[0]?.message?.content;\n if (oa) return oa;\n // Anthropic\n const an = (j?.content as Array<{text:string}>)?.[0]?.text;\n if (an) return an;\n // Gemini\n const gm = ((j?.candidates as Array<{content:{parts:Array<{text:string}>}}>)?.[0]?.content?.parts)?.[0]?.text;\n if (gm) return gm;\n // Ollama\n const ol = (j?.message as {content:string})?.content;\n if (ol) return ol;\n return '';\n }\n}\n\nfunction _combineSignals(...signals: AbortSignal[]): AbortSignal {\n const ctrl = new AbortController();\n for (const s of signals) s.addEventListener('abort', () => ctrl.abort(), { once: true });\n return ctrl.signal;\n}\n","export interface JoopToolParameter {\n type: 'string' | 'number' | 'boolean' | 'object' | 'array';\n description?: string;\n enum?: unknown[];\n items?: JoopToolParameter;\n properties?: Record<string, JoopToolParameter>;\n required?: string[];\n}\n\nexport interface JoopToolDefinition {\n name: string;\n description: string;\n parameters: Record<string, JoopToolParameter>;\n required?: string[];\n handler: (args: Record<string, unknown>) => Promise<unknown>;\n}\n\nexport interface JoopToolCall {\n name: string;\n arguments: string | Record<string, unknown>;\n}\n\nexport interface JoopToolResult {\n name: string;\n result: unknown;\n error?: string;\n durationMs: number;\n}\n\nexport class JoopToolRegistry {\n private _tools = new Map<string, JoopToolDefinition>();\n\n register(tool: JoopToolDefinition): void {\n if (this._tools.has(tool.name)) throw new Error(`Tool '${tool.name}' already registered. Use update() to replace.`);\n this._tools.set(tool.name, tool);\n }\n\n update(tool: JoopToolDefinition): void { this._tools.set(tool.name, tool); }\n unregister(name: string): void { this._tools.delete(name); }\n has(name: string): boolean { return this._tools.has(name); }\n list(): string[] { return Array.from(this._tools.keys()); }\n get(name: string): JoopToolDefinition | undefined { return this._tools.get(name); }\n clear(): void { this._tools.clear(); }\n\n async dispatch(call: JoopToolCall): Promise<JoopToolResult> {\n const tool = this._tools.get(call.name);\n if (!tool) return { name: call.name, result: null, error: `Unknown tool: ${call.name}`, durationMs: 0 };\n\n const args = typeof call.arguments === 'string' ? JSON.parse(call.arguments) : call.arguments;\n const t0 = Date.now();\n try {\n const result = await tool.handler(args as Record<string, unknown>);\n return { name: call.name, result, durationMs: Date.now() - t0 };\n } catch (e) {\n return { name: call.name, result: null, error: String(e), durationMs: Date.now() - t0 };\n }\n }\n\n /** Dispatch multiple tool calls in parallel */\n async dispatchAll(calls: JoopToolCall[]): Promise<JoopToolResult[]> {\n return Promise.all(calls.map(c => this.dispatch(c)));\n }\n\n /** Format for OpenAI function-calling */\n toOpenAiFormat(): object[] {\n return Array.from(this._tools.values()).map(t => ({\n type: 'function',\n function: {\n name: t.name,\n description: t.description,\n parameters: {\n type: 'object',\n properties: t.parameters,\n required: t.required ?? [],\n },\n },\n }));\n }\n\n /** Format for Anthropic tool-use */\n toAnthropicFormat(): object[] {\n return Array.from(this._tools.values()).map(t => ({\n name: t.name,\n description: t.description,\n input_schema: {\n type: 'object',\n properties: t.parameters,\n required: t.required ?? [],\n },\n }));\n }\n\n /** Format for Google Gemini function declarations */\n toGeminiFormat(): object[] {\n return [{\n function_declarations: Array.from(this._tools.values()).map(t => ({\n name: t.name,\n description: t.description,\n parameters: { type: 'object', properties: t.parameters, required: t.required ?? [] },\n })),\n }];\n }\n}\n"]}
|