@moda-ai/cli 1.11.0 → 1.12.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.
Files changed (36) hide show
  1. package/dist/init/sdk-guide.d.ts +28 -1
  2. package/dist/init/sdk-guide.js +102 -98
  3. package/dist/init/sdk-integration.d.ts +23 -3
  4. package/dist/init/sdk-integration.js +106 -24
  5. package/dist/init/skill-resolver.d.ts +19 -0
  6. package/dist/init/skill-resolver.js +78 -0
  7. package/dist/skills-bundled.d.ts +35 -0
  8. package/dist/skills-bundled.js +157 -0
  9. package/dist/skills-manifest.d.ts +33 -0
  10. package/dist/skills-manifest.js +244 -0
  11. package/dist/skills.js +22 -142
  12. package/package.json +6 -4
  13. package/skills/integration/index.json +123 -0
  14. package/skills/integration/integration-node-anthropic/EXAMPLE.md +59 -0
  15. package/skills/integration/integration-node-anthropic/SKILL.md +150 -0
  16. package/skills/integration/integration-node-generic/EXAMPLE.md +77 -0
  17. package/skills/integration/integration-node-generic/SKILL.md +170 -0
  18. package/skills/integration/integration-node-langchain/EXAMPLE.md +59 -0
  19. package/skills/integration/integration-node-langchain/SKILL.md +144 -0
  20. package/skills/integration/integration-node-openai/EXAMPLE.md +55 -0
  21. package/skills/integration/integration-node-openai/SKILL.md +148 -0
  22. package/skills/integration/integration-node-vercel-ai-sdk/EXAMPLE.md +55 -0
  23. package/skills/integration/integration-node-vercel-ai-sdk/SKILL.md +179 -0
  24. package/skills/integration/integration-node-vercel-ai-sdk/references/prompt-attribution.md +31 -0
  25. package/skills/integration/integration-python-anthropic/EXAMPLE.md +66 -0
  26. package/skills/integration/integration-python-anthropic/SKILL.md +153 -0
  27. package/skills/integration/integration-python-claude-agent-sdk/EXAMPLE.md +61 -0
  28. package/skills/integration/integration-python-claude-agent-sdk/SKILL.md +129 -0
  29. package/skills/integration/integration-python-generic/EXAMPLE.md +46 -0
  30. package/skills/integration/integration-python-generic/SKILL.md +146 -0
  31. package/skills/integration/integration-python-langchain/EXAMPLE.md +63 -0
  32. package/skills/integration/integration-python-langchain/SKILL.md +141 -0
  33. package/skills/integration/integration-python-openai/EXAMPLE.md +65 -0
  34. package/skills/integration/integration-python-openai/SKILL.md +151 -0
  35. package/dist/init/detect.d.ts +0 -9
  36. package/dist/init/detect.js +0 -179
@@ -0,0 +1,144 @@
1
+ ---
2
+ id: integration-node-langchain
3
+ name: "Integrate Moda with LangChain / LangGraph (Node.js / TypeScript)"
4
+ version: 1.0.0
5
+ category: integration
6
+ targets:
7
+ language: node
8
+ frameworks:
9
+ - langchain
10
+ providers: []
11
+ sdk_package: moda-ai
12
+ summary: "Instrument a Node.js LangChain or LangGraph app with Moda: init before the framework, explicit conversation ids around every run."
13
+ ---
14
+
15
+ # Integrate Moda with LangChain / LangGraph (Node.js / TypeScript)
16
+
17
+ Follow the steps below in order. Each step has a stop condition; when you hit
18
+ one, stop and report instead of guessing. `EXAMPLE.md` in this directory shows
19
+ the complete finished integration; match its structure. For API details beyond
20
+ this skill, read https://docs.moda.dev/ingestion/moda-sdk-node (if the
21
+ installed `moda-ai` package ships docs under `node_modules/moda-ai/docs/`,
22
+ prefer those; they match the installed SDK version).
23
+
24
+ ## Safety rules (apply to every step)
25
+
26
+ - Only touch the repository you were launched in.
27
+ - Never write the `MODA_API_KEY` value (or any secret) into source files, and
28
+ never create or edit `.env` files. The key belongs in the runtime
29
+ environment or a secret manager.
30
+ - Make the smallest correct change. Match the existing code style and imports.
31
+ - Do not commit unless the user asks.
32
+ - If a step is ambiguous in this repository, stop and report rather than
33
+ guessing.
34
+
35
+ ## What is different about agent frameworks
36
+
37
+ Two constraints drive every step below:
38
+
39
+ 1. Instrument at the Moda SDK level, not inside LangChain. Initialize Moda
40
+ once and set an explicit conversation id around each run; the LLM calls
41
+ the agent makes internally are then captured and share that id (this is
42
+ the documented agent-framework pattern — see the "Solution for Agent
43
+ Applications" section of the Node SDK docs). Do not add LangChain
44
+ callbacks, handlers, or tracer classes for Moda — no such Moda API
45
+ exists.
46
+ 2. Explicit conversation ids are mandatory. Moda's automatic conversation
47
+ detection hashes the first user message, and agent frameworks construct
48
+ different messages on every internal iteration, so without an explicit id
49
+ every iteration lands in a different conversation.
50
+
51
+ ## Step 1: Find the agent/chain entry points
52
+
53
+ Find where the application invokes LangChain or LangGraph: `.invoke(...)`,
54
+ `.stream(...)`, agent executor runs, or graph runs. These entry points — not
55
+ the internal LLM calls — are where conversation context gets set.
56
+
57
+ - If you cannot find any LangChain/LangGraph entry point, stop and report.
58
+ - If the repository's LLM calls actually go through the Vercel AI SDK (the
59
+ `ai` package) rather than LangChain, stop: use the Vercel AI SDK skill
60
+ instead.
61
+
62
+ ## Step 2: Install the SDK
63
+
64
+ Install `moda-ai` with the package manager this repository already uses
65
+ (check the lockfile: `bun.lock`/`bun.lockb` means bun, `pnpm-lock.yaml` means
66
+ pnpm, `yarn.lock` means yarn, otherwise npm):
67
+
68
+ ```bash
69
+ npm install moda-ai
70
+ ```
71
+
72
+ If `moda-ai` is already in `package.json`, skip the install.
73
+
74
+ ## Step 3: Initialize Moda once at startup
75
+
76
+ `Moda.init` must run before LangChain constructs any provider client (which
77
+ usually happens at model/agent construction). Initialize at the top of the
78
+ application entry point. If a `Moda.init` call already exists, verify it runs
79
+ at startup and skip this step; never add a second call.
80
+
81
+ ```typescript
82
+ import { Moda } from 'moda-ai';
83
+
84
+ await Moda.init(process.env.MODA_API_KEY!);
85
+ ```
86
+
87
+ ## Step 4: Wrap every agent/chain run in an explicit conversation id
88
+
89
+ Wrap each entry point found in Step 1 so all internal LLM calls made during
90
+ that run share one conversation id. Use the scoped helpers so concurrent
91
+ runs do not leak context into each other:
92
+
93
+ ```typescript
94
+ import { withContext } from 'moda-ai';
95
+
96
+ const result = await withContext(`agent_session_${sessionId}`, userId, async () =>
97
+ agent.invoke({ input: userQuery }),
98
+ );
99
+ ```
100
+
101
+ For strictly sequential code, the global property form is equivalent:
102
+
103
+ ```typescript
104
+ Moda.conversationId = `agent_session_${sessionId}`;
105
+ const result = await agent.invoke({ input: userQuery });
106
+ Moda.conversationId = null;
107
+ ```
108
+
109
+ Reuse the session/thread identifier the app already has (LangGraph
110
+ `thread_id`, a chat session id, a ticket id). If no session identifier
111
+ exists anywhere, stop and report; do not invent one.
112
+
113
+ ## Step 5: Flush before exit
114
+
115
+ For short-lived scripts and CLIs, flush before the process exits:
116
+
117
+ ```typescript
118
+ await Moda.flush();
119
+ ```
120
+
121
+ For long-running servers, flush on shutdown:
122
+
123
+ ```typescript
124
+ process.on('SIGTERM', async () => {
125
+ await Moda.flush();
126
+ await Moda.shutdown();
127
+ process.exit(0);
128
+ });
129
+ ```
130
+
131
+ ## Step 6: Validate
132
+
133
+ Report the packages installed, files edited, and any step a human still needs
134
+ to do (for example setting `MODA_API_KEY` in the deploy environment). Then
135
+ verify telemetry reaches Moda:
136
+
137
+ ```bash
138
+ moda doctor --online --json
139
+ ```
140
+
141
+ The report should show recent traces, and multi-step agent runs should share
142
+ one conversation id. If each internal LLM call shows up as its own
143
+ conversation, the explicit conversation id from Step 4 is not wrapping the
144
+ run — fix that before finishing.
@@ -0,0 +1,55 @@
1
+ # Golden reference: Express + OpenAI SDK + Moda
2
+
3
+ The complete finished integration for a minimal Express chat server that
4
+ calls the OpenAI SDK directly. Match this structure; adapt names to the
5
+ target repository.
6
+
7
+ ## src/server.ts
8
+
9
+ ```typescript
10
+ import express from 'express';
11
+ import { Moda, withContext } from 'moda-ai';
12
+ import OpenAI from 'openai';
13
+
14
+ // Initialize Moda once, before the OpenAI client is created. After this,
15
+ // every chat.completions.create call is captured automatically.
16
+ await Moda.init(process.env.MODA_API_KEY!);
17
+
18
+ const client = new OpenAI();
19
+ const app = express();
20
+ app.use(express.json());
21
+
22
+ app.post('/chat', async (req, res) => {
23
+ const { sessionId, userId, message } = req.body;
24
+
25
+ // Scoped context: safe under concurrent requests.
26
+ const response = await withContext(`session_${sessionId}`, userId, async () =>
27
+ client.chat.completions.create({
28
+ model: 'gpt-4o',
29
+ messages: [{ role: 'user', content: message }],
30
+ }),
31
+ );
32
+
33
+ res.json({ reply: response.choices[0].message.content });
34
+ });
35
+
36
+ // Flush pending telemetry on shutdown.
37
+ process.on('SIGTERM', async () => {
38
+ await Moda.flush();
39
+ await Moda.shutdown();
40
+ process.exit(0);
41
+ });
42
+
43
+ app.listen(3000);
44
+ ```
45
+
46
+ ## What changed, and what did not
47
+
48
+ - `moda-ai` added to `package.json` dependencies.
49
+ - One `Moda.init` call added at startup, before `new OpenAI()`.
50
+ - The handler wraps its existing OpenAI call in `withContext`; the
51
+ `chat.completions.create` call itself is unchanged — instrumentation is
52
+ automatic.
53
+ - A `SIGTERM` handler flushes telemetry on shutdown.
54
+ - No `.env` file was created or edited; `MODA_API_KEY` is read from the
55
+ runtime environment.
@@ -0,0 +1,148 @@
1
+ ---
2
+ id: integration-node-openai
3
+ name: "Integrate Moda with the OpenAI SDK (Node.js / TypeScript)"
4
+ version: 1.0.0
5
+ category: integration
6
+ targets:
7
+ language: node
8
+ frameworks: []
9
+ providers:
10
+ - openai
11
+ sdk_package: moda-ai
12
+ summary: "Auto-instrument direct openai client calls with Moda in a Node.js or TypeScript app; no per-call changes required."
13
+ ---
14
+
15
+ # Integrate Moda with the OpenAI SDK (Node.js / TypeScript)
16
+
17
+ Follow the steps below in order. Each step has a stop condition; when you hit
18
+ one, stop and report instead of guessing. `EXAMPLE.md` in this directory shows
19
+ the complete finished integration; match its structure. For API details beyond
20
+ this skill, read https://docs.moda.dev/ingestion/providers/openai and
21
+ https://docs.moda.dev/ingestion/moda-sdk-node (if the installed `moda-ai`
22
+ package ships docs under `node_modules/moda-ai/docs/`, prefer those; they
23
+ match the installed SDK version).
24
+
25
+ ## Safety rules (apply to every step)
26
+
27
+ - Only touch the repository you were launched in.
28
+ - Never write the `MODA_API_KEY` value (or any secret) into source files, and
29
+ never create or edit `.env` files. The key belongs in the runtime
30
+ environment or a secret manager.
31
+ - Make the smallest correct change. Match the existing code style and imports.
32
+ - Do not commit unless the user asks.
33
+ - If a step is ambiguous in this repository, stop and report rather than
34
+ guessing.
35
+
36
+ ## Step 1: Confirm the raw OpenAI client is the integration surface
37
+
38
+ Find the real LLM call sites: `client.chat.completions.create(...)` on a
39
+ client constructed with `new OpenAI()` from the `openai` package.
40
+
41
+ - If the OpenAI calls go through a wrapper framework instead — the `ai`
42
+ package (Vercel AI SDK) or LangChain — stop: instrument the wrapper layer
43
+ with its dedicated skill, never the underlying provider client.
44
+ - If the repo wraps its OpenAI client in a helper module (for example
45
+ `lib/openai.ts` exporting a shared client), plan to instrument at that one
46
+ place; do not edit every call site.
47
+ - If there are no OpenAI call sites at all, stop and report.
48
+
49
+ ## Step 2: Install the SDK
50
+
51
+ Install `moda-ai` with the package manager this repository already uses
52
+ (check the lockfile: `bun.lock`/`bun.lockb` means bun, `pnpm-lock.yaml` means
53
+ pnpm, `yarn.lock` means yarn, otherwise npm):
54
+
55
+ ```bash
56
+ npm install moda-ai
57
+ ```
58
+
59
+ If `moda-ai` is already in `package.json`, skip the install.
60
+
61
+ ## Step 3: Initialize Moda once at startup, before the client is created
62
+
63
+ Instrumentation is automatic: once `Moda.init` has run, every
64
+ `chat.completions.create` call (including streaming, function calling, and
65
+ embeddings) is captured with no per-call changes.
66
+
67
+ `Moda.init` must run before the OpenAI client is constructed. If a
68
+ `Moda.init` call already exists, verify it runs at startup before client
69
+ creation and skip this step; never add a second call.
70
+
71
+ ```typescript
72
+ import { Moda } from 'moda-ai';
73
+ import OpenAI from 'openai';
74
+
75
+ await Moda.init(process.env.MODA_API_KEY!);
76
+
77
+ const client = new OpenAI();
78
+ ```
79
+
80
+ If the client lives in a shared helper module, initialize Moda at the top of
81
+ the application entry point (before that module is imported), or at the top
82
+ of the helper module itself — whichever the existing structure makes
83
+ smallest.
84
+
85
+ ## Step 4: Set conversation and user context
86
+
87
+ Set a stable conversation id before each LLM call so multi-turn
88
+ conversations group together, and a user id when one user can be identified.
89
+
90
+ For sequential code, use the global properties:
91
+
92
+ ```typescript
93
+ Moda.conversationId = `session_${sessionId}`;
94
+ Moda.userId = userId;
95
+ ```
96
+
97
+ For concurrent request handlers (any web server), use the scoped helper so
98
+ overlapping requests do not leak context into each other:
99
+
100
+ ```typescript
101
+ import { withContext } from 'moda-ai';
102
+
103
+ const response = await withContext(`session_${sessionId}`, userId, async () =>
104
+ client.chat.completions.create({
105
+ model: 'gpt-4o',
106
+ messages: [{ role: 'user', content: userMessage }],
107
+ }),
108
+ );
109
+ ```
110
+
111
+ Reuse the session/thread identifier the app already has. If no session
112
+ identifier exists anywhere, the SDK falls back to hashing the first user
113
+ message plus the system prompt — acceptable only for simple chatbots that
114
+ pass full message history on every call. If this repo is an agent framework
115
+ or does not pass full history, an explicit conversation id is required; stop
116
+ and report if you cannot find a session identifier to use.
117
+
118
+ ## Step 5: Flush before exit
119
+
120
+ For short-lived scripts and CLIs, flush before the process exits:
121
+
122
+ ```typescript
123
+ await Moda.flush();
124
+ ```
125
+
126
+ For long-running servers, flush on shutdown:
127
+
128
+ ```typescript
129
+ process.on('SIGTERM', async () => {
130
+ await Moda.flush();
131
+ await Moda.shutdown();
132
+ process.exit(0);
133
+ });
134
+ ```
135
+
136
+ ## Step 6: Validate
137
+
138
+ Report the packages installed, files edited, and any step a human still needs
139
+ to do (for example setting `MODA_API_KEY` in the deploy environment). Then
140
+ verify telemetry reaches Moda:
141
+
142
+ ```bash
143
+ moda doctor --online --json
144
+ ```
145
+
146
+ The report should show recent traces. If it does not, confirm `MODA_API_KEY`
147
+ is available in the runtime environment and that `Moda.init()` runs before
148
+ the OpenAI client is created.
@@ -0,0 +1,55 @@
1
+ # Golden reference: Next.js App Router + Vercel AI SDK + Moda
2
+
3
+ The complete finished integration for a minimal Next.js chat route. Match
4
+ this structure; adapt names to the target repository.
5
+
6
+ ## instrumentation.ts (project root)
7
+
8
+ Moda initializes once at server startup, before any AI SDK call.
9
+
10
+ ```typescript
11
+ export async function register() {
12
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
13
+ const { Moda } = await import('moda-ai');
14
+ await Moda.init(process.env.MODA_API_KEY!);
15
+ }
16
+ }
17
+ ```
18
+
19
+ ## app/api/chat/route.ts
20
+
21
+ Every AI SDK call passes `experimental_telemetry`, and conversation/user
22
+ context is scoped per request with `withContext` so concurrent requests
23
+ never leak into each other.
24
+
25
+ ```typescript
26
+ import { Moda, withContext } from 'moda-ai';
27
+ import { generateText } from 'ai';
28
+ import { openai } from '@ai-sdk/openai';
29
+
30
+ export async function POST(request: Request) {
31
+ const { sessionId, userId, message } = await request.json();
32
+
33
+ const result = await withContext(`session_${sessionId}`, userId, async () =>
34
+ generateText({
35
+ model: openai('gpt-4o'),
36
+ prompt: message,
37
+ experimental_telemetry: Moda.getVercelAITelemetry(),
38
+ }),
39
+ );
40
+
41
+ await Moda.flush();
42
+
43
+ return Response.json({ reply: result.text });
44
+ }
45
+ ```
46
+
47
+ ## What changed, and what did not
48
+
49
+ - `moda-ai` added to `package.json` dependencies.
50
+ - `instrumentation.ts` created (or extended) with the one-time `Moda.init`.
51
+ - Each AI SDK call site gained `experimental_telemetry` and scoped context.
52
+ - No `.env` file was created or edited; `MODA_API_KEY` is read from the
53
+ runtime environment.
54
+ - The raw `@ai-sdk/openai` provider client was NOT separately instrumented;
55
+ the AI SDK telemetry layer is the single integration surface.
@@ -0,0 +1,179 @@
1
+ ---
2
+ id: integration-node-vercel-ai-sdk
3
+ name: "Integrate Moda with the Vercel AI SDK (Node.js / TypeScript)"
4
+ version: 1.0.0
5
+ category: integration
6
+ targets:
7
+ language: node
8
+ frameworks:
9
+ - vercel-ai-sdk
10
+ providers: []
11
+ sdk_package: moda-ai
12
+ summary: "Instrument Vercel AI SDK calls (generateText, streamText, generateObject) with Moda telemetry in a Node.js or TypeScript app."
13
+ ---
14
+
15
+ # Integrate Moda with the Vercel AI SDK (Node.js / TypeScript)
16
+
17
+ Follow the steps below in order. Each step has a stop condition; when you hit
18
+ one, stop and report instead of guessing. `EXAMPLE.md` in this directory shows
19
+ the complete finished integration; match its structure. For API details beyond
20
+ this skill, read https://docs.moda.dev/ingestion/vercel-ai-sdk (if the
21
+ installed `moda-ai` package ships docs under `node_modules/moda-ai/docs/`,
22
+ prefer those; they match the installed SDK version).
23
+
24
+ ## Safety rules (apply to every step)
25
+
26
+ - Only touch the repository you were launched in.
27
+ - Never write the `MODA_API_KEY` value (or any secret) into source files, and
28
+ never create or edit `.env` files. The key belongs in the runtime
29
+ environment or a secret manager.
30
+ - Make the smallest correct change. Match the existing code style and imports.
31
+ - Do not commit unless the user asks.
32
+ - If a step is ambiguous in this repository, stop and report rather than
33
+ guessing.
34
+
35
+ ## Step 1: Confirm the Vercel AI SDK is the integration surface
36
+
37
+ Find the real LLM call sites: search for `generateText`, `streamText`,
38
+ `generateObject`, or `streamObject` imported from the `ai` package.
39
+
40
+ - If you find none, stop and report: this skill only applies to apps that
41
+ call the Vercel AI SDK directly.
42
+ - Instrument the Vercel AI SDK layer only. Do NOT also instrument raw
43
+ `openai` / `@anthropic-ai/sdk` clients that are used through the AI SDK;
44
+ that produces duplicate telemetry for the same call.
45
+
46
+ ## Step 2: Install the SDK
47
+
48
+ Install `moda-ai` with the package manager this repository already uses
49
+ (check the lockfile: `bun.lock`/`bun.lockb` means bun, `pnpm-lock.yaml` means
50
+ pnpm, `yarn.lock` means yarn, otherwise npm):
51
+
52
+ ```bash
53
+ npm install moda-ai
54
+ ```
55
+
56
+ If `moda-ai` is already in `package.json`, skip the install.
57
+
58
+ ## Step 3: Initialize Moda once at startup
59
+
60
+ `Moda.init` must run once, before the first AI SDK call. If a `Moda.init`
61
+ call already exists somewhere in the codebase, verify it runs at startup and
62
+ skip this step; never add a second call.
63
+
64
+ Next.js: put it in `instrumentation.ts` at the project root (create the file
65
+ if it does not exist):
66
+
67
+ ```typescript
68
+ export async function register() {
69
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
70
+ const { Moda } = await import('moda-ai');
71
+ await Moda.init(process.env.MODA_API_KEY!);
72
+ }
73
+ }
74
+ ```
75
+
76
+ Any other Node app: initialize at the top of the entry point, before the
77
+ first AI SDK call:
78
+
79
+ ```typescript
80
+ import { Moda } from 'moda-ai';
81
+
82
+ await Moda.init(process.env.MODA_API_KEY!);
83
+ ```
84
+
85
+ `Moda.init` is async. Await it so initialization completes before the first
86
+ LLM call; skipping the await risks the first call going uninstrumented.
87
+
88
+ ## Step 4: Pass Moda telemetry at every AI SDK call site
89
+
90
+ Add `experimental_telemetry: Moda.getVercelAITelemetry()` to every
91
+ `generateText` / `streamText` / `generateObject` / `streamObject` call:
92
+
93
+ ```typescript
94
+ import { Moda } from 'moda-ai';
95
+ import { generateText } from 'ai';
96
+ import { openai } from '@ai-sdk/openai';
97
+
98
+ const result = await generateText({
99
+ model: openai('gpt-4o'),
100
+ prompt: userMessage,
101
+ experimental_telemetry: Moda.getVercelAITelemetry(),
102
+ });
103
+ ```
104
+
105
+ Streaming works the same way; telemetry is captured after the stream
106
+ completes. If a call site already passes `experimental_telemetry`, stop and
107
+ report that call site instead of overwriting it.
108
+
109
+ ## Step 5: Set conversation and user context
110
+
111
+ Set a stable conversation id before each AI SDK call so multi-turn
112
+ conversations group together, and a user id when one user can be identified.
113
+ Set them before calling `Moda.getVercelAITelemetry()`; the telemetry config
114
+ captures them at call time.
115
+
116
+ For sequential code, use the global properties:
117
+
118
+ ```typescript
119
+ Moda.conversationId = `session_${sessionId}`;
120
+ Moda.userId = userId;
121
+ ```
122
+
123
+ For concurrent request handlers (any web server), use the scoped helper so
124
+ overlapping requests do not leak context into each other:
125
+
126
+ ```typescript
127
+ import { Moda, withContext } from 'moda-ai';
128
+
129
+ const result = await withContext(`session_${sessionId}`, userId, async () =>
130
+ generateText({
131
+ model: openai('gpt-4o'),
132
+ prompt: userMessage,
133
+ experimental_telemetry: Moda.getVercelAITelemetry(),
134
+ }),
135
+ );
136
+ ```
137
+
138
+ Reuse the session/thread identifier the app already has. If no session
139
+ identifier exists anywhere, stop and report; do not invent one.
140
+
141
+ ## Step 6: Attribute managed prompts (only if the repo uses them)
142
+
143
+ Only if this repository has a `.moda/prompts.yml` manifest: render managed
144
+ prompts through the SDK before creating the telemetry config, so traces point
145
+ at exact prompt versions. See
146
+ [references/prompt-attribution.md](references/prompt-attribution.md).
147
+ If there is no prompt manifest, skip this step.
148
+
149
+ ## Step 7: Flush before exit
150
+
151
+ For short-lived scripts and CLIs, flush before the process exits:
152
+
153
+ ```typescript
154
+ await Moda.flush();
155
+ ```
156
+
157
+ For long-running servers, flush on shutdown:
158
+
159
+ ```typescript
160
+ process.on('SIGTERM', async () => {
161
+ await Moda.flush();
162
+ await Moda.shutdown();
163
+ process.exit(0);
164
+ });
165
+ ```
166
+
167
+ ## Step 8: Validate
168
+
169
+ Report the packages installed, files edited, and any step a human still needs
170
+ to do (for example setting `MODA_API_KEY` in the deploy environment). Then
171
+ verify telemetry reaches Moda:
172
+
173
+ ```bash
174
+ moda doctor --online --json
175
+ ```
176
+
177
+ The report should show recent traces. If it does not, confirm `MODA_API_KEY`
178
+ is available in the runtime environment and that `Moda.init()` runs before
179
+ the first AI SDK call.
@@ -0,0 +1,31 @@
1
+ # Prompt attribution with the Vercel AI SDK
2
+
3
+ Only relevant when the repository manages prompts with Moda
4
+ (`.moda/prompts.yml` exists and prompts are synced with `moda prompts sync`).
5
+
6
+ Render the managed prompt through the SDK, then create the telemetry config.
7
+ `Moda.getVercelAITelemetry()` includes the rendered prompt's metadata
8
+ (`moda.prompt_key`, `moda.prompt_id`, `moda.prompt_version`,
9
+ `moda.prompt_version_id`) in `experimental_telemetry.metadata`, so production
10
+ traces point at the exact prompt version:
11
+
12
+ ```typescript
13
+ import { Moda } from 'moda-ai';
14
+ import { generateText } from 'ai';
15
+ import { openai } from '@ai-sdk/openai';
16
+
17
+ const rendered = Moda.prompt('support.triage').render({
18
+ ticket: { text: userMessage },
19
+ });
20
+
21
+ const result = await generateText({
22
+ model: openai('gpt-4o'),
23
+ messages: rendered.messages,
24
+ experimental_telemetry: Moda.getVercelAITelemetry(),
25
+ });
26
+ ```
27
+
28
+ Order matters: render the prompt before calling
29
+ `Moda.getVercelAITelemetry()` so prompt metadata is attached.
30
+
31
+ Full reference: https://docs.moda.dev/ingestion/vercel-ai-sdk
@@ -0,0 +1,66 @@
1
+ # Golden reference: FastAPI + Anthropic SDK + Moda
2
+
3
+ The complete finished integration for a minimal FastAPI chat service that
4
+ calls the Anthropic SDK directly. Match this structure; adapt names to the
5
+ target repository.
6
+
7
+ ## app/main.py
8
+
9
+ ```python
10
+ import os
11
+ from contextlib import asynccontextmanager
12
+
13
+ import moda
14
+ from anthropic import Anthropic
15
+ from fastapi import FastAPI
16
+ from moda import set_conversation_id, set_user_id
17
+ from pydantic import BaseModel
18
+
19
+ # Initialize Moda before creating any LLM client so instrumentation is
20
+ # active. After this, every messages.create call is captured automatically.
21
+ moda.init(os.environ["MODA_API_KEY"])
22
+
23
+ client = Anthropic()
24
+
25
+
26
+ @asynccontextmanager
27
+ async def lifespan(app: FastAPI):
28
+ yield
29
+ # Flush pending telemetry on shutdown.
30
+ moda.flush()
31
+
32
+
33
+ app = FastAPI(lifespan=lifespan)
34
+
35
+
36
+ class ChatRequest(BaseModel):
37
+ session_id: str
38
+ user_id: str
39
+ message: str
40
+
41
+
42
+ @app.post("/chat")
43
+ def chat(request: ChatRequest):
44
+ # Scoped context: safe under concurrent requests.
45
+ with set_conversation_id(f"session_{request.session_id}"):
46
+ with set_user_id(request.user_id):
47
+ response = client.messages.create(
48
+ model="claude-sonnet-4-20250514",
49
+ max_tokens=1024,
50
+ messages=[{"role": "user", "content": request.message}],
51
+ )
52
+ reply = "".join(block.text for block in response.content if block.type == "text")
53
+ return {"reply": reply}
54
+ ```
55
+
56
+ ## What changed, and what did not
57
+
58
+ - `moda-ai` added to the project dependencies.
59
+ - One `moda.init` call added at module import time, before `Anthropic()` is
60
+ constructed.
61
+ - The handler wraps its existing Anthropic call in the scoped context
62
+ managers; the `messages.create` call itself is unchanged — instrumentation
63
+ is automatic.
64
+ - Shutdown flushes telemetry via the FastAPI lifespan hook.
65
+ - No `.env` file was created or edited; `MODA_API_KEY` is read from the
66
+ runtime environment.