@firstflow/core 0.0.5

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 ADDED
@@ -0,0 +1,130 @@
1
+ # @firstflow/core
2
+
3
+ Server SDK for Firstflow. Two product areas:
4
+
5
+ 1. **Token route** — `firstflowToken()` — one-line Next.js handler that issues short-lived JWTs for your end-users.
6
+ 2. **LLM observability** — import a pre-wrapped `OpenAI` / `Anthropic` client and tag each call with `firstflowAgent` + `firstflowSession` to auto-track tokens, latency, cost, and conversations.
7
+
8
+ Both read `FIRSTFLOW_API_KEY` from env. That's the only required configuration.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @firstflow/core @firstflow/react
14
+ ```
15
+
16
+ ## Environment variables
17
+
18
+ | Variable | Purpose |
19
+ |----------|---------|
20
+ | `FIRSTFLOW_API_KEY` | **Required.** Clerk-backed API key scoped to one or more agents (`agent:<id>` scope). Create in dashboard → Settings → API Keys. Secret — never expose to the browser. |
21
+ | `FIRSTFLOW_API_BASE_URL` | Optional. Override Firstflow Cloud base URL. Defaults to `https://api.firstflow.app`. Only set when self-hosting. |
22
+ | `FIRSTFLOW_CAPTURE_LLM_CONTENT` | Optional `true` / `false` (default **`false`**). When **`false`**, prompts/completions are **not** captured by OTel spans (PII-safe default). Set to **`true`** to capture message bodies in LLM analytics. |
23
+
24
+ ## Quick start — widget integration
25
+
26
+ ```ts
27
+ // app/api/firstflow/route.ts
28
+ import { firstflowToken } from "@firstflow/core";
29
+ import { auth, currentUser } from "@clerk/nextjs/server";
30
+
31
+ export const POST = firstflowToken(async () => {
32
+ const { userId } = await auth();
33
+ if (!userId) throw new Error("Unauthorized");
34
+ const user = await currentUser();
35
+ return {
36
+ userId,
37
+ traits: {
38
+ name: user?.fullName,
39
+ email: user?.emailAddresses[0]?.emailAddress,
40
+ plan: user?.publicMetadata?.plan,
41
+ },
42
+ };
43
+ });
44
+ ```
45
+
46
+ ```tsx
47
+ // app/layout.tsx
48
+ import { FirstflowProvider, FirstflowWidget } from "@firstflow/react";
49
+
50
+ export default function RootLayout({ children }) {
51
+ return (
52
+ <FirstflowProvider agentId="agt_abc123">
53
+ {children}
54
+ <FirstflowWidget />
55
+ </FirstflowProvider>
56
+ );
57
+ }
58
+ ```
59
+
60
+ That's the full integration. The Provider defaults `tokenEndpoint` to `/api/firstflow` — matches the path you mounted in the route file.
61
+
62
+ ## Quick start — LLM observability
63
+
64
+ Import the pre-wrapped client and tag each call. No setup step, no async factory.
65
+
66
+ ```ts
67
+ import { OpenAI } from "@firstflow/core/openai";
68
+
69
+ const openai = new OpenAI();
70
+
71
+ const response = await openai.chat.completions.create({
72
+ firstflowAgentId: "agt_abc123", // the agent this call belongs to
73
+ sessionId: "user-session-1", // the conversation/thread
74
+ userId: "u_123", // the end-user (stable across sessions)
75
+ model: "gpt-4o",
76
+ messages: [{ role: "user", content: "Hello" }],
77
+ });
78
+ ```
79
+
80
+ All three identifiers are required. `firstflowAgentId`, `sessionId`, and `userId` are
81
+ stripped before the request reaches OpenAI / Anthropic. Tokens, latency, cost, and the
82
+ conversation turn are tracked automatically — no extra `observe()` call needed.
83
+ `Anthropic` works the same way on `messages.create`.
84
+
85
+ The model is **user → sessions → messages**: a user has many sessions; a session has
86
+ many messages.
87
+
88
+ ### Other LLM frameworks
89
+
90
+ If you don't call the OpenAI / Anthropic SDKs directly (e.g. the Vercel AI SDK),
91
+ record turns with the standalone `observe()`:
92
+
93
+ ```ts
94
+ import { observe } from "@firstflow/core";
95
+
96
+ observe({
97
+ firstflowAgentId: "agt_abc123",
98
+ sessionId: "user-session-1",
99
+ userId: "u_123",
100
+ role: "assistant",
101
+ content: text,
102
+ model: "gpt-4o",
103
+ inputTokens, outputTokens,
104
+ });
105
+ ```
106
+
107
+ ## API surface
108
+
109
+ ### Widget token route
110
+
111
+ - `firstflowToken(identity, opts?)` — Next.js `POST` handler. `identity()` returns `{ userId, traits? }` for the current request.
112
+
113
+ ### Observability
114
+
115
+ The SDK is agent-centric: every call is partitioned by `firstflowAgentId`. There is
116
+ no global "active agent" — the agent is always passed per-call. All helpers read
117
+ `FIRSTFLOW_API_KEY` from the environment. The three identifiers (`firstflowAgentId`,
118
+ `sessionId`, `userId`) are required wherever they apply.
119
+
120
+ - `new OpenAI()` (from `@firstflow/core/openai`) / `new Anthropic()` (from `@firstflow/core/anthropic`) — drop-in clients; tag calls with `firstflowAgentId` + `sessionId` + `userId`. Each subpath loads only its own peer SDK.
121
+ - `observe({ firstflowAgentId, sessionId, userId, role, content, ... })` — record a turn (non-wrapped integrations).
122
+ - `trace({ firstflowAgentId, ... })` — record a trace with optional nested spans.
123
+ - `outcome({ firstflowAgentId, sessionId, userId, outcome })` — signal session outcome (`completed`, `abandoned`, etc.).
124
+ - `feedback({ firstflowAgentId, sessionId, userId, rating })` — record thumbs-up/down.
125
+ - `track({ firstflowAgentId, userId, event })`, `identify({ firstflowAgentId, userId, traits })` — analytics.
126
+ - `wrapClient(client, ctx)` — advanced: wrap a client you construct yourself.
127
+
128
+ ### Internal
129
+
130
+ - `listAccessibleAgents({ apiKey })` — used by the test SDK's agent picker. Real customers know their agent IDs from the dashboard.
@@ -0,0 +1,19 @@
1
+ import RealAnthropic from '@anthropic-ai/sdk';
2
+
3
+ interface FirstflowRequestFields {
4
+ /** Agent this call is attributed to (primary routing key). Required to observe. */
5
+ firstflowAgentId?: string;
6
+ /** Session / conversation id for this call. Required to observe. */
7
+ sessionId?: string;
8
+ /** The end-user this call belongs to. Required to observe. */
9
+ userId?: string;
10
+ }
11
+ declare module "@anthropic-ai/sdk/resources/messages/messages" {
12
+ interface MessageCreateParamsBase extends FirstflowRequestFields {
13
+ }
14
+ }
15
+
16
+ /** Drop-in `Anthropic` client with Firstflow observability built in. */
17
+ declare const Anthropic: typeof RealAnthropic;
18
+
19
+ export { Anthropic };
@@ -0,0 +1,19 @@
1
+ import RealAnthropic from '@anthropic-ai/sdk';
2
+
3
+ interface FirstflowRequestFields {
4
+ /** Agent this call is attributed to (primary routing key). Required to observe. */
5
+ firstflowAgentId?: string;
6
+ /** Session / conversation id for this call. Required to observe. */
7
+ sessionId?: string;
8
+ /** The end-user this call belongs to. Required to observe. */
9
+ userId?: string;
10
+ }
11
+ declare module "@anthropic-ai/sdk/resources/messages/messages" {
12
+ interface MessageCreateParamsBase extends FirstflowRequestFields {
13
+ }
14
+ }
15
+
16
+ /** Drop-in `Anthropic` client with Firstflow observability built in. */
17
+ declare const Anthropic: typeof RealAnthropic;
18
+
19
+ export { Anthropic };