@kloddy/kloddy-js 0.1.0 → 0.1.1
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 +71 -102
- package/dist/chunk-WSN7MLKR.mjs +166 -0
- package/dist/chunk-WWAXYTZO.mjs +265 -0
- package/dist/index-BaQw1DKg.d.ts +178 -0
- package/dist/index-CqX8s53x.d.mts +178 -0
- package/dist/index.d.mts +48 -180
- package/dist/index.d.ts +48 -180
- package/dist/index.js +215 -33
- package/dist/index.mjs +37 -257
- package/dist/libs/react/index.d.mts +3 -0
- package/dist/libs/react/index.d.ts +3 -0
- package/dist/libs/react/index.js +458 -0
- package/dist/libs/react/index.mjs +14 -0
- package/dist/next.d.mts +21 -0
- package/dist/next.d.ts +21 -0
- package/dist/next.js +220 -0
- package/dist/next.mjs +26 -0
- package/dist/types-BrCFkSyd.d.mts +91 -0
- package/dist/types-BrCFkSyd.d.ts +91 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @kloddy/kloddy-js
|
|
2
2
|
|
|
3
|
-
Kloddy is the ultimate platform for Prompt Engineering and LLM Analytics. This SDK allows you to fetch, compile, and execute prompts directly from your Node.js or React applications.
|
|
3
|
+
Kloddy is the ultimate platform for Prompt Engineering and LLM Analytics. This SDK allows you to fetch, compile, and execute prompts directly from your Node.js or React applications with full type safety and zero-config support.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
# via npm
|
|
@@ -14,140 +14,109 @@ yarn add @kloddy/kloddy-js
|
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### Zero-Config Initialization (Node.js)
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
import { Kloddy } from 'kloddy-js';
|
|
19
|
+
Kloddy automatically looks for `KLODDY_API_KEY` and `KLODDY_API_SECRET` in your environment variables.
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
apiSecret: '<your_personal_api_key>',
|
|
25
|
-
host: 'https://api.kloddy.com' // Optional
|
|
26
|
-
});
|
|
21
|
+
```typescript
|
|
22
|
+
import { Kloddy } from '@kloddy/kloddy-js';
|
|
27
23
|
|
|
28
|
-
//
|
|
29
|
-
const
|
|
30
|
-
fallback: 'You are a helpful assistant.'
|
|
31
|
-
});
|
|
24
|
+
// Zero-config! Uses process.env.KLODDY_API_KEY and process.env.KLODDY_API_SECRET
|
|
25
|
+
const kloddy = new Kloddy();
|
|
32
26
|
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
// Type-safe prompts (Optional but recommended)
|
|
28
|
+
type MyPrompts = 'exam-generator' | 'customer-support' | 'welcome-email';
|
|
29
|
+
const kloddyTyped = new Kloddy<MyPrompts>();
|
|
30
|
+
|
|
31
|
+
// One-step execution (Play)
|
|
32
|
+
const { result } = await kloddyTyped.prompts.play('exam-generator', {
|
|
33
|
+
variables: { locale: 'en-US', topic: 'Physics' }
|
|
37
34
|
});
|
|
38
35
|
|
|
39
|
-
console.log(
|
|
36
|
+
console.log(result);
|
|
40
37
|
```
|
|
41
38
|
|
|
42
|
-
###
|
|
39
|
+
### Next.js Integration (App Router)
|
|
43
40
|
|
|
44
|
-
|
|
41
|
+
Securely generate tokens on the server without exposing secrets to the client.
|
|
45
42
|
|
|
46
|
-
```
|
|
47
|
-
|
|
43
|
+
```typescript
|
|
44
|
+
// app/api/kloddy/token/route.ts
|
|
45
|
+
import { createKloddyAdapter } from '@kloddy/kloddy-js/next';
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
export const GET = createKloddyAdapter({
|
|
48
|
+
// Credentials picked up from env vars automatically
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
const prompt = await getPrompt('welcome-message');
|
|
54
|
-
const response = await getAwnser('welcome-message', {
|
|
55
|
-
variables: { name: 'Alice' }
|
|
56
|
-
});
|
|
57
|
-
console.log(response.result);
|
|
58
|
-
};
|
|
52
|
+
### React Hooks
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
}
|
|
54
|
+
Wrap your application with `KloddyProvider` and use the simplified hooks.
|
|
62
55
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
```tsx
|
|
57
|
+
// app/layout.tsx
|
|
58
|
+
import { KloddyProvider } from '@kloddy/kloddy-js';
|
|
66
59
|
|
|
60
|
+
export default function RootLayout({ children }) {
|
|
67
61
|
return (
|
|
68
|
-
<KloddyProvider
|
|
69
|
-
|
|
62
|
+
<KloddyProvider authEndpoint="/api/kloddy/token">
|
|
63
|
+
{children}
|
|
70
64
|
</KloddyProvider>
|
|
71
65
|
);
|
|
72
66
|
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Advanced Usage
|
|
76
67
|
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
// components/PromptExecutor.tsx
|
|
69
|
+
'use client';
|
|
70
|
+
import { usePrompt } from '@kloddy/kloddy-js';
|
|
79
71
|
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
apiKey: '...',
|
|
83
|
-
defaultOrgId: 'org_123',
|
|
84
|
-
defaultFeatureId: 'feat_456'
|
|
85
|
-
});
|
|
72
|
+
export function PromptExecutor() {
|
|
73
|
+
const { getAwnser, isLoading } = usePrompt<'exam-generator'>();
|
|
86
74
|
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
75
|
+
const handleRun = async () => {
|
|
76
|
+
const { result } = await getAwnser('exam-generator', {
|
|
77
|
+
variables: { topic: 'Math' }
|
|
78
|
+
});
|
|
79
|
+
alert(result);
|
|
80
|
+
};
|
|
91
81
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
82
|
+
return (
|
|
83
|
+
<button onClick={handleRun} disabled={isLoading}>
|
|
84
|
+
{isLoading ? 'Running...' : 'Generate Exam'}
|
|
85
|
+
</button>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
97
88
|
```
|
|
98
89
|
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
// List all prompts
|
|
102
|
-
const allPrompts = await kloddy.prompts.list({ pageSize: 50 });
|
|
90
|
+
## Features
|
|
103
91
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
model: 'gpt-4'
|
|
111
|
-
});
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Evaluations
|
|
115
|
-
```javascript
|
|
116
|
-
const evalResult = await kloddy.evaluations.evaluate({
|
|
117
|
-
name: 'model-comparison',
|
|
118
|
-
models: ['gpt-4', 'claude-3'],
|
|
119
|
-
judge: 'gpt-4-judge',
|
|
120
|
-
variables: { input: '...' },
|
|
121
|
-
temperature: 0.7
|
|
122
|
-
});
|
|
123
|
-
```
|
|
92
|
+
- **Zero-Config**: Works out of the box with `process.env`.
|
|
93
|
+
- **Type Safety**: Use Generics to get autocomplete for your prompt names.
|
|
94
|
+
- **Next.js Ready**: Built-in adapter for secure token handling.
|
|
95
|
+
- **Graceful Degradation**: Built-in fallback support for offline mode or API issues.
|
|
96
|
+
- **Professional Error Handling**: Custom error classes like `KloddyAuthError` and `KloddyNotFoundError`.
|
|
97
|
+
- **Tree-Shakable**: Optimized for small bundle sizes.
|
|
124
98
|
|
|
125
99
|
## API Reference
|
|
126
100
|
|
|
127
|
-
### `Kloddy
|
|
128
|
-
|
|
129
|
-
- `
|
|
130
|
-
- `
|
|
131
|
-
- `prompts.
|
|
132
|
-
- `
|
|
133
|
-
- `prompts.play(name, options)`: Execute a prompt directly.
|
|
134
|
-
- `prompts.update()`: Sync all prompts.
|
|
135
|
-
- `evaluations.evaluate(options)`: Run model evaluations.
|
|
101
|
+
### `Kloddy<TPromptNames>`
|
|
102
|
+
The main entry point for the SDK.
|
|
103
|
+
- `prompts.get(name, options)`: Fetch a template with optional version and fallback.
|
|
104
|
+
- `prompts.play(name, options)`: Execute a prompt directly in one step.
|
|
105
|
+
- `prompts.compile(template, variables)`: Locally compile a template string.
|
|
106
|
+
- `evaluations.run(options)`: Run model evaluations.
|
|
136
107
|
|
|
137
108
|
### React Hooks
|
|
138
|
-
- `usePrompt()`:
|
|
139
|
-
|
|
140
|
-
|
|
109
|
+
- `usePrompt<TPromptNames>()`: Manage prompts and execution state.
|
|
110
|
+
- `useEvaluations()`: Manage model evaluations and comparisons.
|
|
111
|
+
- `usePromptStream<TPromptNames>()`: Support for streaming responses.
|
|
141
112
|
|
|
142
|
-
|
|
113
|
+
## Advanced Fallback Strategy
|
|
143
114
|
|
|
144
|
-
|
|
145
|
-
const template = await kloddy.prompts.get('support-agent');
|
|
146
|
-
const systemPrompt = kloddy.prompts.compile(template, { user: 'Alice' });
|
|
115
|
+
Prevent outages by providing a local fallback for critical prompts.
|
|
147
116
|
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
117
|
+
```typescript
|
|
118
|
+
const template = await kloddy.prompts.get('critical-prompt', {
|
|
119
|
+
fallback: 'You are a helpful assistant. (Offline Fallback)'
|
|
151
120
|
});
|
|
152
121
|
```
|
|
153
122
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var KloddyError = class _KloddyError extends Error {
|
|
3
|
+
constructor(message, status, code) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.status = status;
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.name = "KloddyError";
|
|
8
|
+
Object.setPrototypeOf(this, _KloddyError.prototype);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var KloddyAuthError = class _KloddyAuthError extends KloddyError {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message, 401, "AUTH_FAILED");
|
|
14
|
+
this.name = "KloddyAuthError";
|
|
15
|
+
Object.setPrototypeOf(this, _KloddyAuthError.prototype);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var KloddyNotFoundError = class _KloddyNotFoundError extends KloddyError {
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message, 404, "NOT_FOUND");
|
|
21
|
+
this.name = "KloddyNotFoundError";
|
|
22
|
+
Object.setPrototypeOf(this, _KloddyNotFoundError.prototype);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var KloddyRateLimitError = class _KloddyRateLimitError extends KloddyError {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message, 429, "RATE_LIMIT_EXCEEDED");
|
|
28
|
+
this.name = "KloddyRateLimitError";
|
|
29
|
+
Object.setPrototypeOf(this, _KloddyRateLimitError.prototype);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/client.ts
|
|
34
|
+
import fetch from "cross-fetch";
|
|
35
|
+
var KloddyClient = class {
|
|
36
|
+
apiKey;
|
|
37
|
+
apiSecret;
|
|
38
|
+
host;
|
|
39
|
+
defaultOrgId = null;
|
|
40
|
+
defaultFeatureId = null;
|
|
41
|
+
token = null;
|
|
42
|
+
tokenExpires = null;
|
|
43
|
+
/**
|
|
44
|
+
* Initialize a new KloddyClient.
|
|
45
|
+
* If no credentials are provided, it will look for:
|
|
46
|
+
* - KLODDY_API_KEY / KLODDY_APP_ID
|
|
47
|
+
* - KLODDY_API_SECRET / KLODDY_SECRET_KEY
|
|
48
|
+
* in process.env.
|
|
49
|
+
*/
|
|
50
|
+
constructor(apiKeyOrOptions, options) {
|
|
51
|
+
const envApiKey = typeof process !== "undefined" ? process.env?.KLODDY_API_KEY || process.env?.KLODDY_APP_ID || "" : "";
|
|
52
|
+
const envApiSecret = typeof process !== "undefined" ? process.env?.KLODDY_API_SECRET || process.env?.KLODDY_SECRET_KEY || "" : "";
|
|
53
|
+
if (!apiKeyOrOptions || apiKeyOrOptions === "") {
|
|
54
|
+
this.apiKey = envApiKey;
|
|
55
|
+
this.apiSecret = envApiSecret;
|
|
56
|
+
this.host = "https://api.kloddy.com";
|
|
57
|
+
} else if (typeof apiKeyOrOptions === "string") {
|
|
58
|
+
this.apiKey = apiKeyOrOptions;
|
|
59
|
+
this.apiSecret = options?.apiSecret || options?.personalApiKey || options?.secretKey || envApiSecret || "";
|
|
60
|
+
this.token = options?.token || null;
|
|
61
|
+
this.host = options?.host || "https://api.kloddy.com";
|
|
62
|
+
this.defaultOrgId = options?.defaultOrgId || null;
|
|
63
|
+
this.defaultFeatureId = options?.defaultFeatureId || null;
|
|
64
|
+
} else {
|
|
65
|
+
this.apiKey = apiKeyOrOptions.apiKey || apiKeyOrOptions.projectApiKey || apiKeyOrOptions.applicationId || envApiKey || "";
|
|
66
|
+
this.apiSecret = apiKeyOrOptions.apiSecret || apiKeyOrOptions.personalApiKey || apiKeyOrOptions.secretKey || envApiSecret || "";
|
|
67
|
+
this.token = apiKeyOrOptions.token || null;
|
|
68
|
+
this.host = apiKeyOrOptions.host || "https://api.kloddy.com";
|
|
69
|
+
this.defaultOrgId = apiKeyOrOptions.defaultOrgId || null;
|
|
70
|
+
this.defaultFeatureId = apiKeyOrOptions.defaultFeatureId || null;
|
|
71
|
+
}
|
|
72
|
+
if (!this.token && (!this.apiKey || !this.apiSecret)) {
|
|
73
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
|
|
74
|
+
console.warn("Kloddy SDK: API Key or Secret missing. Set KLODDY_API_KEY and KLODDY_API_SECRET env vars or pass them to the constructor.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Authenticate with the Kloddy API and retrieve a session token.
|
|
80
|
+
*/
|
|
81
|
+
async login() {
|
|
82
|
+
if (!this.apiKey || !this.apiSecret) {
|
|
83
|
+
throw new KloddyAuthError("KloddyClient: Cannot login without apiKey and apiSecret.");
|
|
84
|
+
}
|
|
85
|
+
const response = await fetch(`${this.host}/api/login`, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: { "Content-Type": "application/json" },
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
applicationId: this.apiKey,
|
|
90
|
+
secretKey: this.apiSecret
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
const errorContent = await response.text();
|
|
95
|
+
if (response.status === 401) throw new KloddyAuthError(`Authentication failed: ${errorContent}`);
|
|
96
|
+
if (response.status === 429) throw new KloddyRateLimitError(`Rate limit exceeded: ${errorContent}`);
|
|
97
|
+
throw new KloddyError(`Kloddy Auth failed: ${response.status} ${errorContent}`, response.status);
|
|
98
|
+
}
|
|
99
|
+
const data = await response.json();
|
|
100
|
+
this.token = data.token;
|
|
101
|
+
this.tokenExpires = Date.now() + (data.expiresAt ? new Date(data.expiresAt).getTime() - Date.now() : 36e5);
|
|
102
|
+
return this.token;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get the current active token, refreshing it if necessary.
|
|
106
|
+
*/
|
|
107
|
+
async getToken() {
|
|
108
|
+
if (this.token && !this.apiSecret) {
|
|
109
|
+
return this.token;
|
|
110
|
+
}
|
|
111
|
+
if (!this.token || this.tokenExpires && Date.now() >= this.tokenExpires - 6e4) {
|
|
112
|
+
return this.login();
|
|
113
|
+
}
|
|
114
|
+
return this.token;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Make an authenticated request to the Kloddy API.
|
|
118
|
+
*/
|
|
119
|
+
async request(path, options = {}) {
|
|
120
|
+
const token = await this.getToken();
|
|
121
|
+
const url = path.startsWith("http") ? path : `${this.host}${path}`;
|
|
122
|
+
const response = await fetch(url, {
|
|
123
|
+
...options,
|
|
124
|
+
headers: {
|
|
125
|
+
...options.headers,
|
|
126
|
+
Authorization: `Bearer ${token}`,
|
|
127
|
+
"Content-Type": "application/json"
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
if (!response.ok) {
|
|
131
|
+
const errorContent = await response.text();
|
|
132
|
+
if (response.status === 404) throw new KloddyNotFoundError(`Resource not found: ${path}`);
|
|
133
|
+
if (response.status === 401) throw new KloddyAuthError(`Unauthorized: ${errorContent}`);
|
|
134
|
+
if (response.status === 429) throw new KloddyRateLimitError(`Rate limit exceeded: ${errorContent}`);
|
|
135
|
+
throw new KloddyError(`Kloddy API error: ${response.status} ${errorContent}`, response.status);
|
|
136
|
+
}
|
|
137
|
+
return await response.json();
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get current user information.
|
|
141
|
+
*/
|
|
142
|
+
async whoAmI() {
|
|
143
|
+
return this.request("/api/whoiam");
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* List organizations for the current user.
|
|
147
|
+
*/
|
|
148
|
+
async listOrganizations() {
|
|
149
|
+
return this.request("/api/organizations");
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* List features, optionally filtered by organization.
|
|
153
|
+
*/
|
|
154
|
+
async listFeatures(orgId) {
|
|
155
|
+
const path = orgId ? `/api/features?org_id=${orgId}` : "/api/features";
|
|
156
|
+
return this.request(path);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export {
|
|
161
|
+
KloddyError,
|
|
162
|
+
KloddyAuthError,
|
|
163
|
+
KloddyNotFoundError,
|
|
164
|
+
KloddyRateLimitError,
|
|
165
|
+
KloddyClient
|
|
166
|
+
};
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KloddyClient
|
|
3
|
+
} from "./chunk-WSN7MLKR.mjs";
|
|
4
|
+
|
|
5
|
+
// src/libs/react/index.tsx
|
|
6
|
+
import { createContext, useContext, useMemo, useState, useEffect } from "react";
|
|
7
|
+
|
|
8
|
+
// src/prompts.ts
|
|
9
|
+
var Prompts = class {
|
|
10
|
+
client;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
if ("client" in options && options.client) {
|
|
13
|
+
this.client = options.client;
|
|
14
|
+
} else if ("posthog" in options && options.posthog) {
|
|
15
|
+
this.client = options.posthog;
|
|
16
|
+
} else {
|
|
17
|
+
this.client = new KloddyClient(options);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* List prompts with filters.
|
|
22
|
+
*/
|
|
23
|
+
async list(options = {}) {
|
|
24
|
+
const params = new URLSearchParams();
|
|
25
|
+
if (options.page) params.append("page", options.page.toString());
|
|
26
|
+
if (options.pageSize) params.append("pageSize", options.pageSize.toString());
|
|
27
|
+
if (options.name) params.append("name", options.name);
|
|
28
|
+
const orgId = options.org_id || this.client.defaultOrgId;
|
|
29
|
+
if (orgId) params.append("org_id", orgId);
|
|
30
|
+
const featureId = options.feature_id || this.client.defaultFeatureId;
|
|
31
|
+
if (featureId) params.append("feature_id", featureId);
|
|
32
|
+
const queryString = params.toString() ? `?${params.toString()}` : "";
|
|
33
|
+
return this.client.request(`/api/prompts${queryString}`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Fetch a prompt template.
|
|
37
|
+
*
|
|
38
|
+
* @param name The unique name of the prompt.
|
|
39
|
+
* @param options Fetching options (version, fallback, etc.)
|
|
40
|
+
*/
|
|
41
|
+
async get(name, options) {
|
|
42
|
+
const params = new URLSearchParams();
|
|
43
|
+
if (options?.version) params.append("version", options.version.toString());
|
|
44
|
+
const resolve = options?.resolve !== void 0 ? options.resolve : true;
|
|
45
|
+
params.append("resolve", resolve.toString());
|
|
46
|
+
const queryString = params.toString() ? `?${params.toString()}` : "";
|
|
47
|
+
try {
|
|
48
|
+
const template = await this.client.request(`/api/prompt/${name}${queryString}`, {
|
|
49
|
+
method: "GET"
|
|
50
|
+
});
|
|
51
|
+
return template;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (options?.fallback) {
|
|
54
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
|
|
55
|
+
console.warn(`Kloddy SDK: Prompt '${name}' not found, using provided fallback.`);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
id: "fallback",
|
|
59
|
+
name,
|
|
60
|
+
content: options.fallback,
|
|
61
|
+
version: 0
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Execute a prompt via the Kloddy API.
|
|
69
|
+
*
|
|
70
|
+
* @param name The unique name of the prompt.
|
|
71
|
+
* @param options Execution variables and model overrides.
|
|
72
|
+
*/
|
|
73
|
+
async execute(name, options = {}) {
|
|
74
|
+
return this.client.request(`/api/prompt/${name}`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
body: JSON.stringify({
|
|
77
|
+
...options,
|
|
78
|
+
resolve: options.resolve !== void 0 ? options.resolve : true
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Play: Direct execution for a single model/version.
|
|
84
|
+
* Same as execute but follows specific naming/body requirements.
|
|
85
|
+
*
|
|
86
|
+
* @param name The unique name of the prompt.
|
|
87
|
+
* @param options Execution variables and model overrides.
|
|
88
|
+
*/
|
|
89
|
+
async play(name, options = {}) {
|
|
90
|
+
return this.client.request("/api/play", {
|
|
91
|
+
method: "POST",
|
|
92
|
+
body: JSON.stringify({
|
|
93
|
+
name,
|
|
94
|
+
...options,
|
|
95
|
+
resolve: options.resolve !== void 0 ? options.resolve : true
|
|
96
|
+
})
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Update: Download all prompts for the user/organization.
|
|
101
|
+
*/
|
|
102
|
+
async update(options = {}) {
|
|
103
|
+
return this.list(options);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Local compilation of a template string with variables.
|
|
107
|
+
*
|
|
108
|
+
* @param template The template string or PromptTemplate object.
|
|
109
|
+
* @param variables Dictionary of variables to inject (e.g., {{variable}}).
|
|
110
|
+
*/
|
|
111
|
+
compile(template, variables) {
|
|
112
|
+
let content = typeof template === "string" ? template : template.content;
|
|
113
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
114
|
+
const regex = new RegExp(`{{${key}}}|{${key}}`, "g");
|
|
115
|
+
content = content.replace(regex, String(value));
|
|
116
|
+
}
|
|
117
|
+
return content;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/evaluations.ts
|
|
122
|
+
var Evaluations = class {
|
|
123
|
+
client;
|
|
124
|
+
constructor(options) {
|
|
125
|
+
if ("client" in options && options.client) {
|
|
126
|
+
this.client = options.client;
|
|
127
|
+
} else if ("posthog" in options && options.posthog) {
|
|
128
|
+
this.client = options.posthog;
|
|
129
|
+
} else {
|
|
130
|
+
this.client = new KloddyClient(options);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Run or retrieve an evaluation.
|
|
135
|
+
*
|
|
136
|
+
* @param options Evaluation criteria including models, judge, and variables.
|
|
137
|
+
*/
|
|
138
|
+
async run(options) {
|
|
139
|
+
return this.client.request("/api/evaluate", {
|
|
140
|
+
method: "POST",
|
|
141
|
+
body: JSON.stringify(options)
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Alias for run().
|
|
146
|
+
*
|
|
147
|
+
* @param options Evaluation criteria.
|
|
148
|
+
*/
|
|
149
|
+
async evaluate(options) {
|
|
150
|
+
return this.run(options);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Simple one-step evaluation call.
|
|
154
|
+
*
|
|
155
|
+
* @param name The name of the evaluation to run.
|
|
156
|
+
* @param variables Variables to inject into the evaluation.
|
|
157
|
+
*/
|
|
158
|
+
async get(name, variables = {}) {
|
|
159
|
+
return this.run({ name, variables });
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// src/libs/react/index.tsx
|
|
164
|
+
import { jsx } from "react/jsx-runtime";
|
|
165
|
+
var KloddyContext = createContext(null);
|
|
166
|
+
var KloddyProvider = ({
|
|
167
|
+
children,
|
|
168
|
+
client,
|
|
169
|
+
options,
|
|
170
|
+
apiKey,
|
|
171
|
+
token: initialToken,
|
|
172
|
+
authEndpoint
|
|
173
|
+
}) => {
|
|
174
|
+
const [token, setToken] = useState(initialToken);
|
|
175
|
+
const [isLoading, setIsLoading] = useState(!!authEndpoint && !initialToken);
|
|
176
|
+
const [error, setError] = useState(null);
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (authEndpoint && !token) {
|
|
179
|
+
setIsLoading(true);
|
|
180
|
+
fetch(authEndpoint).then((res) => res.json()).then((data) => {
|
|
181
|
+
if (data.token) {
|
|
182
|
+
setToken(data.token);
|
|
183
|
+
} else {
|
|
184
|
+
throw new Error("No token returned from authEndpoint");
|
|
185
|
+
}
|
|
186
|
+
}).catch((err) => {
|
|
187
|
+
console.error("KloddyProvider: Failed to fetch token:", err);
|
|
188
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
189
|
+
}).finally(() => {
|
|
190
|
+
setIsLoading(false);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}, [authEndpoint, token]);
|
|
194
|
+
const value = useMemo(() => {
|
|
195
|
+
const activeClient = client || new KloddyClient({ ...options, apiKey, token });
|
|
196
|
+
return {
|
|
197
|
+
prompts: new Prompts({ client: activeClient }),
|
|
198
|
+
evaluations: new Evaluations({ client: activeClient }),
|
|
199
|
+
isLoading,
|
|
200
|
+
error
|
|
201
|
+
};
|
|
202
|
+
}, [client, options, apiKey, token, isLoading, error]);
|
|
203
|
+
return /* @__PURE__ */ jsx(KloddyContext.Provider, { value, children });
|
|
204
|
+
};
|
|
205
|
+
var usePrompt = () => {
|
|
206
|
+
const context = useContext(KloddyContext);
|
|
207
|
+
if (!context) {
|
|
208
|
+
throw new Error("usePrompt must be used within a KloddyProvider");
|
|
209
|
+
}
|
|
210
|
+
const { prompts, evaluations, isLoading, error } = context;
|
|
211
|
+
const typedPrompts = prompts;
|
|
212
|
+
return {
|
|
213
|
+
prompts: typedPrompts,
|
|
214
|
+
isLoading,
|
|
215
|
+
error,
|
|
216
|
+
getPrompt: (id, options = {}) => typedPrompts.get(id, options),
|
|
217
|
+
getAwnser: (id, options = {}) => typedPrompts.execute(id, options),
|
|
218
|
+
/** @deprecated Use useEvaluations instead */
|
|
219
|
+
getEvaluation: (id, variables = {}) => evaluations.get(id, variables),
|
|
220
|
+
compile: (template, variables) => typedPrompts.compile(template, variables)
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
var useEvaluations = () => {
|
|
224
|
+
const context = useContext(KloddyContext);
|
|
225
|
+
if (!context) {
|
|
226
|
+
throw new Error("useEvaluations must be used within a KloddyProvider");
|
|
227
|
+
}
|
|
228
|
+
const { evaluations, isLoading, error } = context;
|
|
229
|
+
return {
|
|
230
|
+
evaluations,
|
|
231
|
+
isLoading,
|
|
232
|
+
error,
|
|
233
|
+
run: (options) => evaluations.run(options),
|
|
234
|
+
evaluate: (options) => evaluations.evaluate(options),
|
|
235
|
+
get: (name, variables = {}) => evaluations.get(name, variables)
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
var usePromptStream = () => {
|
|
239
|
+
const { prompts } = usePrompt();
|
|
240
|
+
const [stream, setStream] = useState("");
|
|
241
|
+
const [isStreaming, setIsStreaming] = useState(false);
|
|
242
|
+
const executeStream = async (name, options = {}) => {
|
|
243
|
+
setIsStreaming(true);
|
|
244
|
+
setStream("");
|
|
245
|
+
console.warn("usePromptStream: Streaming is currently a placeholder.");
|
|
246
|
+
const result = await prompts.execute(name, options);
|
|
247
|
+
setStream(result.result);
|
|
248
|
+
setIsStreaming(false);
|
|
249
|
+
return result;
|
|
250
|
+
};
|
|
251
|
+
return {
|
|
252
|
+
stream,
|
|
253
|
+
isStreaming,
|
|
254
|
+
executeStream
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export {
|
|
259
|
+
Prompts,
|
|
260
|
+
Evaluations,
|
|
261
|
+
KloddyProvider,
|
|
262
|
+
usePrompt,
|
|
263
|
+
useEvaluations,
|
|
264
|
+
usePromptStream
|
|
265
|
+
};
|