@frankieai/core 0.1.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.
@@ -0,0 +1,377 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Tenant configuration. One config == one embedded agent. Everything a
5
+ * customer needs to change to make Frankie theirs lives here, so the code
6
+ * itself stays generic.
7
+ */
8
+ declare const widgetThemeSchema: z.ZodPrefault<z.ZodObject<{
9
+ primary: z.ZodOptional<z.ZodString>;
10
+ primaryForeground: z.ZodOptional<z.ZodString>;
11
+ background: z.ZodOptional<z.ZodString>;
12
+ foreground: z.ZodOptional<z.ZodString>;
13
+ muted: z.ZodOptional<z.ZodString>;
14
+ border: z.ZodOptional<z.ZodString>;
15
+ radius: z.ZodOptional<z.ZodString>;
16
+ fontFamily: z.ZodOptional<z.ZodString>;
17
+ mode: z.ZodDefault<z.ZodEnum<{
18
+ light: "light";
19
+ dark: "dark";
20
+ system: "system";
21
+ }>>;
22
+ }, z.core.$strip>>;
23
+ declare const thinkingLevelSchema: z.ZodEnum<{
24
+ minimal: "minimal";
25
+ low: "low";
26
+ medium: "medium";
27
+ high: "high";
28
+ xhigh: "xhigh";
29
+ max: "max";
30
+ }>;
31
+ declare const modelConfigSchema: z.ZodObject<{
32
+ provider: z.ZodDefault<z.ZodString>;
33
+ model: z.ZodDefault<z.ZodString>;
34
+ apiKeyEnv: z.ZodDefault<z.ZodString>;
35
+ baseUrl: z.ZodOptional<z.ZodString>;
36
+ maxTokens: z.ZodDefault<z.ZodNumber>;
37
+ temperature: z.ZodDefault<z.ZodNumber>;
38
+ thinkingLevel: z.ZodDefault<z.ZodEnum<{
39
+ minimal: "minimal";
40
+ low: "low";
41
+ medium: "medium";
42
+ high: "high";
43
+ xhigh: "xhigh";
44
+ max: "max";
45
+ }>>;
46
+ streamReasoning: z.ZodDefault<z.ZodBoolean>;
47
+ }, z.core.$strip>;
48
+ declare const mcpServerSchema: z.ZodObject<{
49
+ name: z.ZodString;
50
+ transport: z.ZodDefault<z.ZodEnum<{
51
+ http: "http";
52
+ sse: "sse";
53
+ }>>;
54
+ url: z.ZodString;
55
+ headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
56
+ forwardUserTokenAs: z.ZodOptional<z.ZodString>;
57
+ forwardUserClaims: z.ZodDefault<z.ZodArray<z.ZodString>>;
58
+ }, z.core.$strip>;
59
+ /**
60
+ * An HTTP API described by an OpenAPI document, turned into tools directly.
61
+ *
62
+ * This is the "no MCP server to write" path: point Frankie at a spec, name the
63
+ * operations the agent may use, and it builds the tools at startup.
64
+ */
65
+ declare const apiSourceSchema: z.ZodObject<{
66
+ name: z.ZodString;
67
+ spec: z.ZodString;
68
+ baseUrl: z.ZodOptional<z.ZodString>;
69
+ operations: z.ZodDefault<z.ZodArray<z.ZodString>>;
70
+ includePaths: z.ZodDefault<z.ZodArray<z.ZodString>>;
71
+ methods: z.ZodDefault<z.ZodArray<z.ZodEnum<{
72
+ GET: "GET";
73
+ POST: "POST";
74
+ PUT: "PUT";
75
+ PATCH: "PATCH";
76
+ DELETE: "DELETE";
77
+ }>>>;
78
+ headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
79
+ forwardUserTokenAs: z.ZodOptional<z.ZodString>;
80
+ forwardUserClaims: z.ZodDefault<z.ZodArray<z.ZodString>>;
81
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
82
+ maxResponseChars: z.ZodDefault<z.ZodNumber>;
83
+ }, z.core.$strip>;
84
+ declare const toolPolicySchema: z.ZodObject<{
85
+ allow: z.ZodDefault<z.ZodArray<z.ZodString>>;
86
+ deny: z.ZodDefault<z.ZodArray<z.ZodString>>;
87
+ denyByDefault: z.ZodDefault<z.ZodBoolean>;
88
+ }, z.core.$strip>;
89
+ declare const agentConfigSchema: z.ZodObject<{
90
+ systemPrompt: z.ZodDefault<z.ZodString>;
91
+ greeting: z.ZodDefault<z.ZodString>;
92
+ suggestedPrompts: z.ZodDefault<z.ZodArray<z.ZodString>>;
93
+ maxTurns: z.ZodDefault<z.ZodNumber>;
94
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
95
+ tools: z.ZodPrefault<z.ZodObject<{
96
+ allow: z.ZodDefault<z.ZodArray<z.ZodString>>;
97
+ deny: z.ZodDefault<z.ZodArray<z.ZodString>>;
98
+ denyByDefault: z.ZodDefault<z.ZodBoolean>;
99
+ }, z.core.$strip>>;
100
+ showToolActivity: z.ZodDefault<z.ZodBoolean>;
101
+ }, z.core.$strip>;
102
+ declare const authConfigSchema: z.ZodObject<{
103
+ publishableKey: z.ZodString;
104
+ allowedOrigins: z.ZodDefault<z.ZodArray<z.ZodString>>;
105
+ allowAnonymous: z.ZodDefault<z.ZodBoolean>;
106
+ jwtSecretEnv: z.ZodDefault<z.ZodString>;
107
+ jwksUrl: z.ZodOptional<z.ZodString>;
108
+ jwtIssuer: z.ZodOptional<z.ZodString>;
109
+ jwtAudience: z.ZodOptional<z.ZodString>;
110
+ sessionTtlSeconds: z.ZodDefault<z.ZodNumber>;
111
+ sessionSecretEnv: z.ZodDefault<z.ZodString>;
112
+ }, z.core.$strip>;
113
+ declare const limitsConfigSchema: z.ZodObject<{
114
+ messagesPerWindow: z.ZodDefault<z.ZodNumber>;
115
+ windowSeconds: z.ZodDefault<z.ZodNumber>;
116
+ sessionsPerIpPerWindow: z.ZodDefault<z.ZodNumber>;
117
+ turnTimeoutMs: z.ZodDefault<z.ZodNumber>;
118
+ }, z.core.$strip>;
119
+ declare const brandingConfigSchema: z.ZodObject<{
120
+ name: z.ZodDefault<z.ZodString>;
121
+ tagline: z.ZodOptional<z.ZodString>;
122
+ avatarUrl: z.ZodOptional<z.ZodString>;
123
+ launcherLabel: z.ZodDefault<z.ZodString>;
124
+ }, z.core.$strip>;
125
+ declare const frankieConfigSchema: z.ZodObject<{
126
+ tenantId: z.ZodString;
127
+ branding: z.ZodPrefault<z.ZodObject<{
128
+ name: z.ZodDefault<z.ZodString>;
129
+ tagline: z.ZodOptional<z.ZodString>;
130
+ avatarUrl: z.ZodOptional<z.ZodString>;
131
+ launcherLabel: z.ZodDefault<z.ZodString>;
132
+ }, z.core.$strip>>;
133
+ theme: z.ZodPrefault<z.ZodObject<{
134
+ primary: z.ZodOptional<z.ZodString>;
135
+ primaryForeground: z.ZodOptional<z.ZodString>;
136
+ background: z.ZodOptional<z.ZodString>;
137
+ foreground: z.ZodOptional<z.ZodString>;
138
+ muted: z.ZodOptional<z.ZodString>;
139
+ border: z.ZodOptional<z.ZodString>;
140
+ radius: z.ZodOptional<z.ZodString>;
141
+ fontFamily: z.ZodOptional<z.ZodString>;
142
+ mode: z.ZodDefault<z.ZodEnum<{
143
+ light: "light";
144
+ dark: "dark";
145
+ system: "system";
146
+ }>>;
147
+ }, z.core.$strip>>;
148
+ model: z.ZodPrefault<z.ZodObject<{
149
+ provider: z.ZodDefault<z.ZodString>;
150
+ model: z.ZodDefault<z.ZodString>;
151
+ apiKeyEnv: z.ZodDefault<z.ZodString>;
152
+ baseUrl: z.ZodOptional<z.ZodString>;
153
+ maxTokens: z.ZodDefault<z.ZodNumber>;
154
+ temperature: z.ZodDefault<z.ZodNumber>;
155
+ thinkingLevel: z.ZodDefault<z.ZodEnum<{
156
+ minimal: "minimal";
157
+ low: "low";
158
+ medium: "medium";
159
+ high: "high";
160
+ xhigh: "xhigh";
161
+ max: "max";
162
+ }>>;
163
+ streamReasoning: z.ZodDefault<z.ZodBoolean>;
164
+ }, z.core.$strip>>;
165
+ agent: z.ZodPrefault<z.ZodObject<{
166
+ systemPrompt: z.ZodDefault<z.ZodString>;
167
+ greeting: z.ZodDefault<z.ZodString>;
168
+ suggestedPrompts: z.ZodDefault<z.ZodArray<z.ZodString>>;
169
+ maxTurns: z.ZodDefault<z.ZodNumber>;
170
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
171
+ tools: z.ZodPrefault<z.ZodObject<{
172
+ allow: z.ZodDefault<z.ZodArray<z.ZodString>>;
173
+ deny: z.ZodDefault<z.ZodArray<z.ZodString>>;
174
+ denyByDefault: z.ZodDefault<z.ZodBoolean>;
175
+ }, z.core.$strip>>;
176
+ showToolActivity: z.ZodDefault<z.ZodBoolean>;
177
+ }, z.core.$strip>>;
178
+ auth: z.ZodObject<{
179
+ publishableKey: z.ZodString;
180
+ allowedOrigins: z.ZodDefault<z.ZodArray<z.ZodString>>;
181
+ allowAnonymous: z.ZodDefault<z.ZodBoolean>;
182
+ jwtSecretEnv: z.ZodDefault<z.ZodString>;
183
+ jwksUrl: z.ZodOptional<z.ZodString>;
184
+ jwtIssuer: z.ZodOptional<z.ZodString>;
185
+ jwtAudience: z.ZodOptional<z.ZodString>;
186
+ sessionTtlSeconds: z.ZodDefault<z.ZodNumber>;
187
+ sessionSecretEnv: z.ZodDefault<z.ZodString>;
188
+ }, z.core.$strip>;
189
+ mcpServers: z.ZodDefault<z.ZodArray<z.ZodObject<{
190
+ name: z.ZodString;
191
+ transport: z.ZodDefault<z.ZodEnum<{
192
+ http: "http";
193
+ sse: "sse";
194
+ }>>;
195
+ url: z.ZodString;
196
+ headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
197
+ forwardUserTokenAs: z.ZodOptional<z.ZodString>;
198
+ forwardUserClaims: z.ZodDefault<z.ZodArray<z.ZodString>>;
199
+ }, z.core.$strip>>>;
200
+ apis: z.ZodDefault<z.ZodArray<z.ZodObject<{
201
+ name: z.ZodString;
202
+ spec: z.ZodString;
203
+ baseUrl: z.ZodOptional<z.ZodString>;
204
+ operations: z.ZodDefault<z.ZodArray<z.ZodString>>;
205
+ includePaths: z.ZodDefault<z.ZodArray<z.ZodString>>;
206
+ methods: z.ZodDefault<z.ZodArray<z.ZodEnum<{
207
+ GET: "GET";
208
+ POST: "POST";
209
+ PUT: "PUT";
210
+ PATCH: "PATCH";
211
+ DELETE: "DELETE";
212
+ }>>>;
213
+ headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
214
+ forwardUserTokenAs: z.ZodOptional<z.ZodString>;
215
+ forwardUserClaims: z.ZodDefault<z.ZodArray<z.ZodString>>;
216
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
217
+ maxResponseChars: z.ZodDefault<z.ZodNumber>;
218
+ }, z.core.$strip>>>;
219
+ limits: z.ZodPrefault<z.ZodObject<{
220
+ messagesPerWindow: z.ZodDefault<z.ZodNumber>;
221
+ windowSeconds: z.ZodDefault<z.ZodNumber>;
222
+ sessionsPerIpPerWindow: z.ZodDefault<z.ZodNumber>;
223
+ turnTimeoutMs: z.ZodDefault<z.ZodNumber>;
224
+ }, z.core.$strip>>;
225
+ }, z.core.$strip>;
226
+ type ThinkingLevel = z.infer<typeof thinkingLevelSchema>;
227
+ type WidgetThemeConfig = z.infer<typeof widgetThemeSchema>;
228
+ type ModelConfig = z.infer<typeof modelConfigSchema>;
229
+ type McpServerConfig = z.infer<typeof mcpServerSchema>;
230
+ type ApiSourceConfig = z.infer<typeof apiSourceSchema>;
231
+ type ToolPolicy = z.infer<typeof toolPolicySchema>;
232
+ type AgentConfig = z.infer<typeof agentConfigSchema>;
233
+ type AuthConfig = z.infer<typeof authConfigSchema>;
234
+ type LimitsConfig = z.infer<typeof limitsConfigSchema>;
235
+ type BrandingConfig = z.infer<typeof brandingConfigSchema>;
236
+ type FrankieConfig = z.infer<typeof frankieConfigSchema>;
237
+ type FrankieConfigInput = z.input<typeof frankieConfigSchema>;
238
+ declare function parseFrankieConfig(input: unknown): FrankieConfig;
239
+ /** Helper for `frankie.config.ts` files — gives editors full completion. */
240
+ declare function defineFrankieConfig(config: FrankieConfigInput): FrankieConfigInput;
241
+
242
+ /**
243
+ * The wire protocol between the embedded widget and the Frankie server.
244
+ *
245
+ * Everything the widget renders arrives as one of these events over SSE, so a
246
+ * host that wants to build its own UI only has to implement this union.
247
+ */
248
+ /** A single turn's stop reason, normalised across providers. */
249
+ type StopReason = "end_turn" | "max_tokens" | "max_turns" | "stop_sequence" | "aborted" | "error";
250
+ interface UsageSummary {
251
+ inputTokens: number;
252
+ outputTokens: number;
253
+ /** Present only when the upstream provider reports a price. */
254
+ costUsd?: number;
255
+ }
256
+ /** Server -> client events, streamed as `data: <json>\n\n` over `text/event-stream`. */
257
+ type FrankieServerEvent = {
258
+ type: "session";
259
+ sessionId: string;
260
+ resumed: boolean;
261
+ } | {
262
+ type: "message_start";
263
+ messageId: string;
264
+ } | {
265
+ type: "text_delta";
266
+ text: string;
267
+ } | {
268
+ type: "thinking_delta";
269
+ text: string;
270
+ } | {
271
+ type: "tool_start";
272
+ toolUseId: string;
273
+ name: string;
274
+ label: string;
275
+ input: unknown;
276
+ } | {
277
+ type: "tool_end";
278
+ toolUseId: string;
279
+ ok: boolean;
280
+ preview?: string;
281
+ } | {
282
+ type: "tool_denied";
283
+ toolUseId: string;
284
+ name: string;
285
+ reason: string;
286
+ } | {
287
+ type: "turn_end";
288
+ stopReason: StopReason;
289
+ usage?: UsageSummary;
290
+ } | {
291
+ type: "error";
292
+ code: FrankieErrorCode;
293
+ message: string;
294
+ retryable: boolean;
295
+ } | {
296
+ type: "ping";
297
+ };
298
+ type FrankieErrorCode = "unauthorized" | "forbidden_origin" | "rate_limited" | "session_not_found" | "upstream_error" | "budget_exceeded" | "internal";
299
+ /** Client -> server body for `POST /v1/chat`. */
300
+ interface ChatRequestBody {
301
+ /** Omit to start a new conversation; the server replies with a `session` event. */
302
+ sessionId?: string;
303
+ message: string;
304
+ /**
305
+ * Free-form page context the host passes through (current route, plan tier,
306
+ * feature flags). Surfaced to the agent as a system reminder, never trusted
307
+ * as an instruction.
308
+ */
309
+ context?: Record<string, string | number | boolean | null>;
310
+ }
311
+ /** Client -> server body for `POST /v1/session`. */
312
+ interface CreateSessionBody {
313
+ /**
314
+ * A JWT signed by the host's backend identifying the end user. Required
315
+ * unless the tenant allows anonymous sessions.
316
+ */
317
+ userToken?: string;
318
+ context?: Record<string, string | number | boolean | null>;
319
+ }
320
+ interface CreateSessionResponse {
321
+ /** Short-lived bearer token scoped to this one chat session. */
322
+ sessionToken: string;
323
+ sessionId: string;
324
+ expiresAt: string;
325
+ user: {
326
+ id: string;
327
+ displayName?: string;
328
+ anonymous: boolean;
329
+ };
330
+ }
331
+ /** The subset of tenant config the widget is allowed to see. */
332
+ interface PublicWidgetConfig {
333
+ tenantId: string;
334
+ branding: {
335
+ name: string;
336
+ tagline?: string;
337
+ avatarUrl?: string;
338
+ launcherLabel: string;
339
+ };
340
+ greeting: string;
341
+ suggestedPrompts: string[];
342
+ theme: WidgetTheme;
343
+ /** Whether the widget may open a session without a host-signed user token. */
344
+ allowAnonymous: boolean;
345
+ /** Show tool calls inline as they run. */
346
+ showToolActivity: boolean;
347
+ }
348
+ interface WidgetTheme {
349
+ /** CSS color for primary actions. Any valid CSS color string. */
350
+ primary?: string;
351
+ primaryForeground?: string;
352
+ background?: string;
353
+ foreground?: string;
354
+ muted?: string;
355
+ border?: string;
356
+ /** Border radius in rem, e.g. "0.75". */
357
+ radius?: string;
358
+ fontFamily?: string;
359
+ mode?: "light" | "dark" | "system";
360
+ }
361
+
362
+ interface ToolDecision {
363
+ allowed: boolean;
364
+ reason: string;
365
+ }
366
+ /**
367
+ * Decide whether the agent may run a tool.
368
+ *
369
+ * Patterns are matched exactly, or as a prefix when they end in `*`. MCP tools
370
+ * arrive as `mcp__<server>__<tool>`, so listing `mcp__acme` (no trailing star)
371
+ * also allows every tool on the `acme` server.
372
+ */
373
+ declare function evaluateToolPolicy(toolName: string, policy: ToolPolicy): ToolDecision;
374
+ /** A short human label for a tool call, for the "Frankie is …" line in the UI. */
375
+ declare function describeTool(toolName: string, input: unknown): string;
376
+
377
+ export { type AgentConfig, type ApiSourceConfig, type AuthConfig, type BrandingConfig, type ChatRequestBody, type CreateSessionBody, type CreateSessionResponse, type FrankieConfig, type FrankieConfigInput, type FrankieErrorCode, type FrankieServerEvent, type LimitsConfig, type McpServerConfig, type ModelConfig, type PublicWidgetConfig, type StopReason, type ThinkingLevel, type ToolDecision, type ToolPolicy, type UsageSummary, type WidgetTheme, type WidgetThemeConfig, agentConfigSchema, apiSourceSchema, authConfigSchema, brandingConfigSchema, defineFrankieConfig, describeTool, evaluateToolPolicy, frankieConfigSchema, limitsConfigSchema, mcpServerSchema, modelConfigSchema, parseFrankieConfig, thinkingLevelSchema, toolPolicySchema, widgetThemeSchema };
package/dist/index.js ADDED
@@ -0,0 +1,230 @@
1
+ // src/config.ts
2
+ import { z } from "zod";
3
+ var widgetThemeSchema = z.object({
4
+ primary: z.string().optional(),
5
+ primaryForeground: z.string().optional(),
6
+ background: z.string().optional(),
7
+ foreground: z.string().optional(),
8
+ muted: z.string().optional(),
9
+ border: z.string().optional(),
10
+ radius: z.string().optional(),
11
+ fontFamily: z.string().optional(),
12
+ mode: z.enum(["light", "dark", "system"]).default("system")
13
+ }).prefault({});
14
+ var thinkingLevelSchema = z.enum(["minimal", "low", "medium", "high", "xhigh", "max"]);
15
+ var modelConfigSchema = z.object({
16
+ /**
17
+ * Any provider the model layer knows about. `fireworks` is the default;
18
+ * `anthropic`, `openai`, `google`, `groq`, `together`, `openrouter` and
19
+ * ~30 others resolve too, which is what makes the model a config choice.
20
+ */
21
+ provider: z.string().min(1).default("fireworks"),
22
+ /**
23
+ * Model id within that provider. The default is Kimi K2.7 on Fireworks,
24
+ * which serves a native Anthropic-Messages endpoint and a 262K window.
25
+ */
26
+ model: z.string().default("accounts/fireworks/models/kimi-k2p7-code"),
27
+ /** Env var holding the provider key. Never put the key in config itself. */
28
+ apiKeyEnv: z.string().default("FIREWORKS_API_KEY"),
29
+ /** Override the provider's base URL (self-hosted gateways, tests). */
30
+ baseUrl: z.string().url().optional(),
31
+ maxTokens: z.number().int().positive().max(2e5).default(8192),
32
+ temperature: z.number().min(0).max(2).default(0.6),
33
+ /**
34
+ * Reasoning depth. Lowest by default: an onboarding widget is latency-
35
+ * sensitive and its questions rarely need deliberation.
36
+ */
37
+ thinkingLevel: thinkingLevelSchema.default("minimal"),
38
+ /** Forward the model's reasoning stream to the client as thinking deltas. */
39
+ streamReasoning: z.boolean().default(false)
40
+ });
41
+ var mcpServerSchema = z.object({
42
+ name: z.string().min(1).regex(/^[a-z0-9][a-z0-9_-]*$/i, "MCP server names must be alphanumeric with - or _"),
43
+ /** `http` covers streamable HTTP; `sse` is the legacy transport. */
44
+ transport: z.enum(["http", "sse"]).default("http"),
45
+ url: z.string().url(),
46
+ /** Static headers, e.g. a service token for the company's own MCP server. */
47
+ headers: z.record(z.string(), z.string()).default({}),
48
+ /**
49
+ * When set, the verified end-user JWT is forwarded to the MCP server in this
50
+ * header so the company's tools can act as that user. Use with care: only
51
+ * enable it for MCP servers you control.
52
+ */
53
+ forwardUserTokenAs: z.string().optional(),
54
+ /** Extra claims from the user token to forward as `x-frankie-<claim>`. */
55
+ forwardUserClaims: z.array(z.string()).default([])
56
+ });
57
+ var apiSourceSchema = z.object({
58
+ name: z.string().min(1).regex(/^[a-z0-9][a-z0-9_-]*$/i, "API source names must be alphanumeric with - or _"),
59
+ /** URL or local path to an OpenAPI 3.x document (JSON or YAML). */
60
+ spec: z.string().min(1),
61
+ /** Overrides the spec's own `servers[0].url`. Required if the spec has none. */
62
+ baseUrl: z.string().url().optional(),
63
+ /**
64
+ * Operation ids the agent may call. Empty means "every operation that passes
65
+ * the other filters" — fine for a small internal API, risky for a large one.
66
+ */
67
+ operations: z.array(z.string()).default([]),
68
+ /**
69
+ * Path globs to include, e.g. `/projects/**`. Empty means all paths.
70
+ */
71
+ includePaths: z.array(z.string()).default([]),
72
+ /**
73
+ * HTTP methods the agent may use. Read-only by default: an onboarding agent
74
+ * wired to a whole API should not be able to DELETE on its first day. Widen
75
+ * deliberately, per API.
76
+ */
77
+ methods: z.array(z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"])).default(["GET"]),
78
+ /** Static headers, e.g. a service token. */
79
+ headers: z.record(z.string(), z.string()).default({}),
80
+ /**
81
+ * When set, the verified end-user JWT is forwarded in this header, so your
82
+ * API authorises the call exactly as it would any other request from them.
83
+ */
84
+ forwardUserTokenAs: z.string().optional(),
85
+ /** Extra claims from the user token to forward as `x-frankie-<claim>`. */
86
+ forwardUserClaims: z.array(z.string()).default([]),
87
+ /** Per-call timeout. */
88
+ timeoutMs: z.number().int().positive().default(3e4),
89
+ /** Response bodies longer than this are truncated before the model sees them. */
90
+ maxResponseChars: z.number().int().positive().default(8e3)
91
+ });
92
+ var toolPolicySchema = z.object({
93
+ /**
94
+ * Tool names the agent may call without asking. MCP tools are named
95
+ * `mcp__<server>__<tool>` and generated API tools `api__<name>__<operation>`;
96
+ * naming the prefix alone (`mcp__acme`, `api__acme`) allows all of them.
97
+ */
98
+ allow: z.array(z.string()).default([]),
99
+ /** Explicit denials; evaluated before `allow`. */
100
+ deny: z.array(z.string()).default([]),
101
+ /**
102
+ * Deny anything not in `allow`. On by default — an onboarding agent living
103
+ * on a public marketing page should not have an open tool surface.
104
+ */
105
+ denyByDefault: z.boolean().default(true)
106
+ });
107
+ var agentConfigSchema = z.object({
108
+ /** Prepended to the runtime's own operating instructions. */
109
+ systemPrompt: z.string().default(""),
110
+ /** First message the widget shows before the user types anything. */
111
+ greeting: z.string().default("Hi! I can walk you through getting set up. What are you trying to do?"),
112
+ suggestedPrompts: z.array(z.string()).max(6).default([]),
113
+ maxTurns: z.number().int().positive().max(50).default(12),
114
+ /** Hard stop on estimated spend per session. */
115
+ maxBudgetUsd: z.number().positive().optional(),
116
+ tools: toolPolicySchema.prefault({}),
117
+ /** Show tool activity in the transcript. */
118
+ showToolActivity: z.boolean().default(true)
119
+ });
120
+ var authConfigSchema = z.object({
121
+ /**
122
+ * Safe to ship in client bundles. Identifies the tenant; it authorises
123
+ * nothing on its own — the origin allowlist and the user token do that.
124
+ */
125
+ publishableKey: z.string().min(8),
126
+ /** Exact origins allowed to open sessions, e.g. `https://app.acme.com`. */
127
+ allowedOrigins: z.array(z.string()).default([]),
128
+ /** Let visitors chat without a host-signed token (marketing pages). */
129
+ allowAnonymous: z.boolean().default(false),
130
+ /** Env var holding the HS256 secret the host signs user tokens with. */
131
+ jwtSecretEnv: z.string().default("FRANKIE_JWT_SECRET"),
132
+ /** Verify against a JWKS endpoint instead of a shared secret (RS/ES256). */
133
+ jwksUrl: z.string().url().optional(),
134
+ jwtIssuer: z.string().optional(),
135
+ jwtAudience: z.string().optional(),
136
+ /** How long an issued session token is good for. */
137
+ sessionTtlSeconds: z.number().int().positive().default(60 * 60),
138
+ /** Env var holding the secret used to sign Frankie's own session tokens. */
139
+ sessionSecretEnv: z.string().default("FRANKIE_SESSION_SECRET")
140
+ });
141
+ var limitsConfigSchema = z.object({
142
+ /** Messages per session per window. */
143
+ messagesPerWindow: z.number().int().positive().default(30),
144
+ windowSeconds: z.number().int().positive().default(15 * 60),
145
+ /** Sessions a single IP may open per window. */
146
+ sessionsPerIpPerWindow: z.number().int().positive().default(20),
147
+ /** Longest a single turn may run before it is aborted. */
148
+ turnTimeoutMs: z.number().int().positive().default(12e4)
149
+ });
150
+ var brandingConfigSchema = z.object({
151
+ name: z.string().default("Assistant"),
152
+ tagline: z.string().optional(),
153
+ avatarUrl: z.string().url().optional(),
154
+ launcherLabel: z.string().default("Need a hand?")
155
+ });
156
+ var frankieConfigSchema = z.object({
157
+ tenantId: z.string().min(1),
158
+ branding: brandingConfigSchema.prefault({}),
159
+ theme: widgetThemeSchema,
160
+ model: modelConfigSchema.prefault({}),
161
+ agent: agentConfigSchema.prefault({}),
162
+ auth: authConfigSchema,
163
+ mcpServers: z.array(mcpServerSchema).default([]),
164
+ /** APIs turned into tools from their OpenAPI document. */
165
+ apis: z.array(apiSourceSchema).default([]),
166
+ limits: limitsConfigSchema.prefault({})
167
+ });
168
+ function parseFrankieConfig(input) {
169
+ return frankieConfigSchema.parse(input);
170
+ }
171
+ function defineFrankieConfig(config) {
172
+ return config;
173
+ }
174
+
175
+ // src/tools.ts
176
+ function evaluateToolPolicy(toolName, policy) {
177
+ if (matchesAny(toolName, policy.deny)) {
178
+ return { allowed: false, reason: `"${toolName}" is on the deny list for this agent.` };
179
+ }
180
+ if (matchesAny(toolName, policy.allow)) {
181
+ return { allowed: true, reason: "allowed by policy" };
182
+ }
183
+ if (policy.denyByDefault) {
184
+ return { allowed: false, reason: `"${toolName}" is not in this agent's allow list.` };
185
+ }
186
+ return { allowed: true, reason: "no policy match; default allow" };
187
+ }
188
+ function matchesAny(toolName, patterns) {
189
+ return patterns.some((pattern) => matches(toolName, pattern));
190
+ }
191
+ function matches(toolName, pattern) {
192
+ if (pattern === "*") return true;
193
+ if (pattern.endsWith("*")) return toolName.startsWith(pattern.slice(0, -1));
194
+ if (toolName === pattern) return true;
195
+ return toolName.startsWith(`${pattern}__`);
196
+ }
197
+ function describeTool(toolName, input) {
198
+ const mcp = /^mcp__([^_]+(?:_[^_]+)*)__(.+)$/.exec(toolName);
199
+ if (mcp) {
200
+ const [, server, tool] = mcp;
201
+ return `${humanise(tool ?? toolName)} \xB7 ${server}`;
202
+ }
203
+ const inputRecord = typeof input === "object" && input !== null ? input : {};
204
+ const hint = inputRecord["path"] ?? inputRecord["url"] ?? inputRecord["query"] ?? inputRecord["command"];
205
+ return typeof hint === "string" ? `${humanise(toolName)}: ${truncate(hint, 60)}` : humanise(toolName);
206
+ }
207
+ function humanise(name) {
208
+ return name.replace(/[_-]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase()).trim();
209
+ }
210
+ function truncate(value, max) {
211
+ return value.length <= max ? value : `${value.slice(0, max - 1)}\u2026`;
212
+ }
213
+ export {
214
+ agentConfigSchema,
215
+ apiSourceSchema,
216
+ authConfigSchema,
217
+ brandingConfigSchema,
218
+ defineFrankieConfig,
219
+ describeTool,
220
+ evaluateToolPolicy,
221
+ frankieConfigSchema,
222
+ limitsConfigSchema,
223
+ mcpServerSchema,
224
+ modelConfigSchema,
225
+ parseFrankieConfig,
226
+ thinkingLevelSchema,
227
+ toolPolicySchema,
228
+ widgetThemeSchema
229
+ };
230
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/tools.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Tenant configuration. One config == one embedded agent. Everything a\n * customer needs to change to make Frankie theirs lives here, so the code\n * itself stays generic.\n */\n\nexport const widgetThemeSchema = z\n .object({\n primary: z.string().optional(),\n primaryForeground: z.string().optional(),\n background: z.string().optional(),\n foreground: z.string().optional(),\n muted: z.string().optional(),\n border: z.string().optional(),\n radius: z.string().optional(),\n fontFamily: z.string().optional(),\n mode: z.enum([\"light\", \"dark\", \"system\"]).default(\"system\"),\n })\n .prefault({});\n\nexport const thinkingLevelSchema = z.enum([\"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"]);\n\nexport const modelConfigSchema = z.object({\n /**\n * Any provider the model layer knows about. `fireworks` is the default;\n * `anthropic`, `openai`, `google`, `groq`, `together`, `openrouter` and\n * ~30 others resolve too, which is what makes the model a config choice.\n */\n provider: z.string().min(1).default(\"fireworks\"),\n /**\n * Model id within that provider. The default is Kimi K2.7 on Fireworks,\n * which serves a native Anthropic-Messages endpoint and a 262K window.\n */\n model: z.string().default(\"accounts/fireworks/models/kimi-k2p7-code\"),\n /** Env var holding the provider key. Never put the key in config itself. */\n apiKeyEnv: z.string().default(\"FIREWORKS_API_KEY\"),\n /** Override the provider's base URL (self-hosted gateways, tests). */\n baseUrl: z.string().url().optional(),\n maxTokens: z.number().int().positive().max(200_000).default(8192),\n temperature: z.number().min(0).max(2).default(0.6),\n /**\n * Reasoning depth. Lowest by default: an onboarding widget is latency-\n * sensitive and its questions rarely need deliberation.\n */\n thinkingLevel: thinkingLevelSchema.default(\"minimal\"),\n /** Forward the model's reasoning stream to the client as thinking deltas. */\n streamReasoning: z.boolean().default(false),\n});\n\nexport const mcpServerSchema = z.object({\n name: z\n .string()\n .min(1)\n .regex(/^[a-z0-9][a-z0-9_-]*$/i, \"MCP server names must be alphanumeric with - or _\"),\n /** `http` covers streamable HTTP; `sse` is the legacy transport. */\n transport: z.enum([\"http\", \"sse\"]).default(\"http\"),\n url: z.string().url(),\n /** Static headers, e.g. a service token for the company's own MCP server. */\n headers: z.record(z.string(), z.string()).default({}),\n /**\n * When set, the verified end-user JWT is forwarded to the MCP server in this\n * header so the company's tools can act as that user. Use with care: only\n * enable it for MCP servers you control.\n */\n forwardUserTokenAs: z.string().optional(),\n /** Extra claims from the user token to forward as `x-frankie-<claim>`. */\n forwardUserClaims: z.array(z.string()).default([]),\n});\n\n/**\n * An HTTP API described by an OpenAPI document, turned into tools directly.\n *\n * This is the \"no MCP server to write\" path: point Frankie at a spec, name the\n * operations the agent may use, and it builds the tools at startup.\n */\nexport const apiSourceSchema = z.object({\n name: z\n .string()\n .min(1)\n .regex(/^[a-z0-9][a-z0-9_-]*$/i, \"API source names must be alphanumeric with - or _\"),\n /** URL or local path to an OpenAPI 3.x document (JSON or YAML). */\n spec: z.string().min(1),\n /** Overrides the spec's own `servers[0].url`. Required if the spec has none. */\n baseUrl: z.string().url().optional(),\n /**\n * Operation ids the agent may call. Empty means \"every operation that passes\n * the other filters\" — fine for a small internal API, risky for a large one.\n */\n operations: z.array(z.string()).default([]),\n /**\n * Path globs to include, e.g. `/projects/**`. Empty means all paths.\n */\n includePaths: z.array(z.string()).default([]),\n /**\n * HTTP methods the agent may use. Read-only by default: an onboarding agent\n * wired to a whole API should not be able to DELETE on its first day. Widen\n * deliberately, per API.\n */\n methods: z.array(z.enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"])).default([\"GET\"]),\n /** Static headers, e.g. a service token. */\n headers: z.record(z.string(), z.string()).default({}),\n /**\n * When set, the verified end-user JWT is forwarded in this header, so your\n * API authorises the call exactly as it would any other request from them.\n */\n forwardUserTokenAs: z.string().optional(),\n /** Extra claims from the user token to forward as `x-frankie-<claim>`. */\n forwardUserClaims: z.array(z.string()).default([]),\n /** Per-call timeout. */\n timeoutMs: z.number().int().positive().default(30_000),\n /** Response bodies longer than this are truncated before the model sees them. */\n maxResponseChars: z.number().int().positive().default(8_000),\n});\n\nexport const toolPolicySchema = z.object({\n /**\n * Tool names the agent may call without asking. MCP tools are named\n * `mcp__<server>__<tool>` and generated API tools `api__<name>__<operation>`;\n * naming the prefix alone (`mcp__acme`, `api__acme`) allows all of them.\n */\n allow: z.array(z.string()).default([]),\n /** Explicit denials; evaluated before `allow`. */\n deny: z.array(z.string()).default([]),\n /**\n * Deny anything not in `allow`. On by default — an onboarding agent living\n * on a public marketing page should not have an open tool surface.\n */\n denyByDefault: z.boolean().default(true),\n});\n\nexport const agentConfigSchema = z.object({\n /** Prepended to the runtime's own operating instructions. */\n systemPrompt: z.string().default(\"\"),\n /** First message the widget shows before the user types anything. */\n greeting: z.string().default(\"Hi! I can walk you through getting set up. What are you trying to do?\"),\n suggestedPrompts: z.array(z.string()).max(6).default([]),\n maxTurns: z.number().int().positive().max(50).default(12),\n /** Hard stop on estimated spend per session. */\n maxBudgetUsd: z.number().positive().optional(),\n tools: toolPolicySchema.prefault({}),\n /** Show tool activity in the transcript. */\n showToolActivity: z.boolean().default(true),\n});\n\nexport const authConfigSchema = z.object({\n /**\n * Safe to ship in client bundles. Identifies the tenant; it authorises\n * nothing on its own — the origin allowlist and the user token do that.\n */\n publishableKey: z.string().min(8),\n /** Exact origins allowed to open sessions, e.g. `https://app.acme.com`. */\n allowedOrigins: z.array(z.string()).default([]),\n /** Let visitors chat without a host-signed token (marketing pages). */\n allowAnonymous: z.boolean().default(false),\n /** Env var holding the HS256 secret the host signs user tokens with. */\n jwtSecretEnv: z.string().default(\"FRANKIE_JWT_SECRET\"),\n /** Verify against a JWKS endpoint instead of a shared secret (RS/ES256). */\n jwksUrl: z.string().url().optional(),\n jwtIssuer: z.string().optional(),\n jwtAudience: z.string().optional(),\n /** How long an issued session token is good for. */\n sessionTtlSeconds: z.number().int().positive().default(60 * 60),\n /** Env var holding the secret used to sign Frankie's own session tokens. */\n sessionSecretEnv: z.string().default(\"FRANKIE_SESSION_SECRET\"),\n});\n\nexport const limitsConfigSchema = z.object({\n /** Messages per session per window. */\n messagesPerWindow: z.number().int().positive().default(30),\n windowSeconds: z.number().int().positive().default(15 * 60),\n /** Sessions a single IP may open per window. */\n sessionsPerIpPerWindow: z.number().int().positive().default(20),\n /** Longest a single turn may run before it is aborted. */\n turnTimeoutMs: z.number().int().positive().default(120_000),\n});\n\nexport const brandingConfigSchema = z.object({\n name: z.string().default(\"Assistant\"),\n tagline: z.string().optional(),\n avatarUrl: z.string().url().optional(),\n launcherLabel: z.string().default(\"Need a hand?\"),\n});\n\nexport const frankieConfigSchema = z.object({\n tenantId: z.string().min(1),\n branding: brandingConfigSchema.prefault({}),\n theme: widgetThemeSchema,\n model: modelConfigSchema.prefault({}),\n agent: agentConfigSchema.prefault({}),\n auth: authConfigSchema,\n mcpServers: z.array(mcpServerSchema).default([]),\n /** APIs turned into tools from their OpenAPI document. */\n apis: z.array(apiSourceSchema).default([]),\n limits: limitsConfigSchema.prefault({}),\n});\n\nexport type ThinkingLevel = z.infer<typeof thinkingLevelSchema>;\nexport type WidgetThemeConfig = z.infer<typeof widgetThemeSchema>;\nexport type ModelConfig = z.infer<typeof modelConfigSchema>;\nexport type McpServerConfig = z.infer<typeof mcpServerSchema>;\nexport type ApiSourceConfig = z.infer<typeof apiSourceSchema>;\nexport type ToolPolicy = z.infer<typeof toolPolicySchema>;\nexport type AgentConfig = z.infer<typeof agentConfigSchema>;\nexport type AuthConfig = z.infer<typeof authConfigSchema>;\nexport type LimitsConfig = z.infer<typeof limitsConfigSchema>;\nexport type BrandingConfig = z.infer<typeof brandingConfigSchema>;\nexport type FrankieConfig = z.infer<typeof frankieConfigSchema>;\nexport type FrankieConfigInput = z.input<typeof frankieConfigSchema>;\n\nexport function parseFrankieConfig(input: unknown): FrankieConfig {\n return frankieConfigSchema.parse(input);\n}\n\n/** Helper for `frankie.config.ts` files — gives editors full completion. */\nexport function defineFrankieConfig(config: FrankieConfigInput): FrankieConfigInput {\n return config;\n}\n","import type { ToolPolicy } from \"./config.js\";\n\nexport interface ToolDecision {\n allowed: boolean;\n reason: string;\n}\n\n/**\n * Decide whether the agent may run a tool.\n *\n * Patterns are matched exactly, or as a prefix when they end in `*`. MCP tools\n * arrive as `mcp__<server>__<tool>`, so listing `mcp__acme` (no trailing star)\n * also allows every tool on the `acme` server.\n */\nexport function evaluateToolPolicy(toolName: string, policy: ToolPolicy): ToolDecision {\n if (matchesAny(toolName, policy.deny)) {\n return { allowed: false, reason: `\"${toolName}\" is on the deny list for this agent.` };\n }\n if (matchesAny(toolName, policy.allow)) {\n return { allowed: true, reason: \"allowed by policy\" };\n }\n if (policy.denyByDefault) {\n return { allowed: false, reason: `\"${toolName}\" is not in this agent's allow list.` };\n }\n return { allowed: true, reason: \"no policy match; default allow\" };\n}\n\nfunction matchesAny(toolName: string, patterns: readonly string[]): boolean {\n return patterns.some((pattern) => matches(toolName, pattern));\n}\n\nfunction matches(toolName: string, pattern: string): boolean {\n if (pattern === \"*\") return true;\n if (pattern.endsWith(\"*\")) return toolName.startsWith(pattern.slice(0, -1));\n if (toolName === pattern) return true;\n // `mcp__acme` covers `mcp__acme__create_workspace`.\n return toolName.startsWith(`${pattern}__`);\n}\n\n/** A short human label for a tool call, for the \"Frankie is …\" line in the UI. */\nexport function describeTool(toolName: string, input: unknown): string {\n const mcp = /^mcp__([^_]+(?:_[^_]+)*)__(.+)$/.exec(toolName);\n if (mcp) {\n const [, server, tool] = mcp;\n return `${humanise(tool ?? toolName)} · ${server}`;\n }\n const inputRecord = typeof input === \"object\" && input !== null ? (input as Record<string, unknown>) : {};\n const hint = inputRecord[\"path\"] ?? inputRecord[\"url\"] ?? inputRecord[\"query\"] ?? inputRecord[\"command\"];\n return typeof hint === \"string\" ? `${humanise(toolName)}: ${truncate(hint, 60)}` : humanise(toolName);\n}\n\nfunction humanise(name: string): string {\n return name\n .replace(/[_-]+/g, \" \")\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replace(/\\b\\w/g, (c) => c.toUpperCase())\n .trim();\n}\n\nfunction truncate(value: string, max: number): string {\n return value.length <= max ? value : `${value.slice(0, max - 1)}…`;\n}\n"],"mappings":"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","names":[]}