@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,153 @@
1
+ ---
2
+ id: integration-python-anthropic
3
+ name: "Integrate Moda with the Anthropic SDK (Python)"
4
+ version: 1.0.0
5
+ category: integration
6
+ targets:
7
+ language: python
8
+ frameworks: []
9
+ providers:
10
+ - anthropic
11
+ sdk_package: moda-ai
12
+ summary: "Auto-instrument anthropic client calls with Moda in a Python app; no per-call changes required."
13
+ ---
14
+
15
+ # Integrate Moda with the Anthropic SDK (Python)
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/anthropic and
21
+ https://docs.moda.dev/ingestion/moda-sdk.
22
+
23
+ ## Safety rules (apply to every step)
24
+
25
+ - Only touch the repository you were launched in.
26
+ - Never write the `MODA_API_KEY` value (or any secret) into source files, and
27
+ never create or edit `.env` files. The key belongs in the runtime
28
+ environment or a secret manager.
29
+ - Make the smallest correct change. Match the existing code style and imports.
30
+ - Do not commit unless the user asks.
31
+ - If a step is ambiguous in this repository, stop and report rather than
32
+ guessing.
33
+
34
+ ## Step 1: Confirm the raw Anthropic client is the integration surface
35
+
36
+ Find the real LLM call sites: `client.messages.create(...)` or
37
+ `client.messages.stream(...)` on a client constructed with `Anthropic()`
38
+ from the `anthropic` package.
39
+
40
+ - If the Anthropic calls go through a wrapper framework instead (LangChain,
41
+ CrewAI, the Claude Agent SDK, or similar), stop: instrument the wrapper
42
+ layer with its dedicated skill, never the underlying provider client.
43
+ - If the repo wraps its Anthropic client in a helper module (for example
44
+ `app/llm.py` exporting a shared client), plan to instrument at that one
45
+ place; do not edit every call site.
46
+ - If there are no Anthropic call sites at all, stop and report.
47
+
48
+ ## Step 2: Install the SDK
49
+
50
+ Install `moda-ai` with the package manager this repository already uses
51
+ (`uv.lock` means uv, `poetry.lock` means poetry, otherwise pip):
52
+
53
+ ```bash
54
+ pip install moda-ai
55
+ ```
56
+
57
+ With uv:
58
+
59
+ ```bash
60
+ uv add moda-ai
61
+ ```
62
+
63
+ With poetry:
64
+
65
+ ```bash
66
+ poetry add moda-ai
67
+ ```
68
+
69
+ If `moda-ai` is already a dependency, skip the install. `moda-ai` includes
70
+ the OpenAI and Anthropic instrumentation packages; nothing else is needed
71
+ for this integration.
72
+
73
+ ## Step 3: Initialize Moda once at startup, before the client is created
74
+
75
+ Instrumentation is automatic: once `moda.init` has run, every
76
+ `messages.create` / `messages.stream` call (including extended thinking and
77
+ tool use) is captured with no per-call changes.
78
+
79
+ `moda.init` is synchronous and must run before the Anthropic client is
80
+ constructed. If a `moda.init` call already exists, verify it runs at startup
81
+ before client creation and skip this step; never add a second call.
82
+
83
+ ```python
84
+ import os
85
+
86
+ import moda
87
+ from anthropic import Anthropic
88
+
89
+ moda.init(os.environ["MODA_API_KEY"])
90
+
91
+ client = Anthropic()
92
+ ```
93
+
94
+ For web frameworks, initialize at import time of the application module (as
95
+ above) so the client-creation ordering holds; requirement: `moda.init` runs
96
+ before any `Anthropic()` construction.
97
+
98
+ ## Step 4: Set conversation and user context
99
+
100
+ Set a stable conversation id before each LLM call so multi-turn
101
+ conversations group together, and a user id when one user can be identified.
102
+
103
+ For sequential code, use the module-level properties:
104
+
105
+ ```python
106
+ moda.conversation_id = f"session_{session_id}"
107
+ moda.user_id = user_id
108
+ ```
109
+
110
+ For concurrent request handlers (any web server), use the scoped context
111
+ managers so overlapping requests do not leak context into each other:
112
+
113
+ ```python
114
+ from moda import set_conversation_id, set_user_id
115
+
116
+ with set_conversation_id(f"session_{session_id}"):
117
+ with set_user_id(user_id):
118
+ response = client.messages.create(
119
+ model="claude-sonnet-4-20250514",
120
+ max_tokens=1024,
121
+ messages=[{"role": "user", "content": user_message}],
122
+ )
123
+ ```
124
+
125
+ Reuse the session/thread identifier the app already has. If no session
126
+ identifier exists anywhere, the SDK falls back to hashing the first user
127
+ message plus the system prompt — acceptable only for simple chatbots that
128
+ pass full message history on every call. If this repo is an agent framework
129
+ or does not pass full history, an explicit conversation id is required; stop
130
+ and report if you cannot find a session identifier to use.
131
+
132
+ ## Step 5: Flush before exit
133
+
134
+ Flush pending telemetry before the process exits (short-lived scripts) or on
135
+ shutdown (servers):
136
+
137
+ ```python
138
+ moda.flush()
139
+ ```
140
+
141
+ ## Step 6: Validate
142
+
143
+ Report the packages installed, files edited, and any step a human still needs
144
+ to do (for example setting `MODA_API_KEY` in the deploy environment). Then
145
+ verify telemetry reaches Moda:
146
+
147
+ ```bash
148
+ moda doctor --online --json
149
+ ```
150
+
151
+ The report should show recent traces. If it does not, confirm `MODA_API_KEY`
152
+ is available in the runtime environment and that `moda.init()` runs before
153
+ the Anthropic client is created.
@@ -0,0 +1,61 @@
1
+ # Golden reference: Claude Agent SDK + Moda
2
+
3
+ The complete finished integration for a minimal Claude Agent SDK script.
4
+ Match this structure; adapt names to the target repository.
5
+
6
+ ## agent.py
7
+
8
+ ```python
9
+ import asyncio
10
+ import os
11
+
12
+ import moda
13
+ from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient
14
+
15
+ # Initialize Moda before creating the ClaudeSDKClient. When
16
+ # moda-claude-agent-sdk is installed, the instrumentor is enabled
17
+ # automatically.
18
+ moda.init(os.environ["MODA_API_KEY"])
19
+
20
+ # Explicit conversation and user context so all turns group together.
21
+ moda.conversation_id = "session_123"
22
+ moda.user_id = "user_456"
23
+
24
+
25
+ async def main():
26
+ options = ClaudeAgentOptions(model="claude-sonnet-4-20250514")
27
+
28
+ async with ClaudeSDKClient(options=options) as client:
29
+ await client.query("What is the capital of France?")
30
+
31
+ # Consume the full stream: token usage arrives in the final
32
+ # ResultMessage.
33
+ async for msg in client.receive_response():
34
+ print(msg)
35
+
36
+
37
+ asyncio.run(main())
38
+
39
+ # Flush pending telemetry before exit.
40
+ moda.flush()
41
+ ```
42
+
43
+ ## Dependencies
44
+
45
+ Both packages are required; `moda-claude-agent-sdk` is not included with
46
+ `moda-ai`:
47
+
48
+ ```bash
49
+ pip install moda-ai moda-claude-agent-sdk claude-agent-sdk
50
+ ```
51
+
52
+ ## What changed, and what did not
53
+
54
+ - `moda-ai` and `moda-claude-agent-sdk` added to the project dependencies.
55
+ - One `moda.init` call added at startup, before `ClaudeSDKClient` is
56
+ constructed.
57
+ - Conversation and user ids set before the agent runs.
58
+ - The agent code itself is unchanged; the instrumentor wraps
59
+ `ClaudeSDKClient` automatically.
60
+ - No `.env` file was created or edited; `MODA_API_KEY` is read from the
61
+ runtime environment.
@@ -0,0 +1,129 @@
1
+ ---
2
+ id: integration-python-claude-agent-sdk
3
+ name: "Integrate Moda with the Claude Agent SDK (Python)"
4
+ version: 1.0.0
5
+ category: integration
6
+ targets:
7
+ language: python
8
+ frameworks:
9
+ - claude-agent-sdk
10
+ providers: []
11
+ sdk_package: moda-claude-agent-sdk
12
+ summary: "Instrument Claude Agent SDK sessions (ClaudeSDKClient) with Moda via the dedicated moda-claude-agent-sdk instrumentor."
13
+ ---
14
+
15
+ # Integrate Moda with the Claude Agent SDK (Python)
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/claude-agent-sdk.
21
+
22
+ ## Safety rules (apply to every step)
23
+
24
+ - Only touch the repository you were launched in.
25
+ - Never write the `MODA_API_KEY` value (or any secret) into source files, and
26
+ never create or edit `.env` files. The key belongs in the runtime
27
+ environment or a secret manager.
28
+ - Make the smallest correct change. Match the existing code style and imports.
29
+ - Do not commit unless the user asks.
30
+ - If a step is ambiguous in this repository, stop and report rather than
31
+ guessing.
32
+
33
+ ## Why this integration needs a separate package
34
+
35
+ The Claude Agent SDK spawns Claude as a subprocess rather than making direct
36
+ Anthropic API calls, so standard Anthropic API instrumentation does not
37
+ fire. The `moda-claude-agent-sdk` package provides a dedicated instrumentor
38
+ that wraps `ClaudeSDKClient` to capture agent-level spans (token usage, tool
39
+ calls, turns, session metadata). The Claude Agent SDK is Python-only; if
40
+ this repository is Node.js, stop and report — there is no Node.js support.
41
+
42
+ ## Step 1: Find the Claude Agent SDK call sites
43
+
44
+ Find where the application constructs `ClaudeSDKClient` (from
45
+ `claude_agent_sdk`). If there are none, stop and report: this skill only
46
+ applies to apps using the Claude Agent SDK.
47
+
48
+ ## Step 2: Install the SDK packages
49
+
50
+ Install both `moda-ai` and `moda-claude-agent-sdk` with the package manager
51
+ this repository already uses (`uv.lock` means uv, `poetry.lock` means
52
+ poetry, otherwise pip). `moda-claude-agent-sdk` is NOT included with
53
+ `moda-ai`; it must be installed separately:
54
+
55
+ ```bash
56
+ pip install moda-ai moda-claude-agent-sdk
57
+ ```
58
+
59
+ With uv:
60
+
61
+ ```bash
62
+ uv add moda-ai moda-claude-agent-sdk
63
+ ```
64
+
65
+ With poetry:
66
+
67
+ ```bash
68
+ poetry add moda-ai moda-claude-agent-sdk
69
+ ```
70
+
71
+ If both are already dependencies, skip the install.
72
+
73
+ ## Step 3: Initialize Moda once at startup, before the client is created
74
+
75
+ `moda.init` is synchronous, automatically enables the Claude Agent SDK
76
+ instrumentor when `moda-claude-agent-sdk` is installed, and must run before
77
+ any `ClaudeSDKClient` is constructed. If a `moda.init` call already exists,
78
+ verify it runs at startup and skip this step; never add a second call.
79
+
80
+ ```python
81
+ import os
82
+
83
+ import moda
84
+
85
+ moda.init(os.environ["MODA_API_KEY"])
86
+ ```
87
+
88
+ ## Step 4: Set conversation and user context
89
+
90
+ Set a stable conversation id (and user id when one user can be identified)
91
+ before running the agent, so all turns of a session group together:
92
+
93
+ ```python
94
+ moda.conversation_id = f"session_{session_id}"
95
+ moda.user_id = user_id
96
+ ```
97
+
98
+ Reuse the session identifier the app already has. If no session identifier
99
+ exists anywhere, stop and report; do not invent one.
100
+
101
+ ## Step 5: Consume the full response stream
102
+
103
+ Token usage comes from the `ResultMessage` at the end of the stream. Verify
104
+ the code consumes the full async generator from `receive_response()`; if it
105
+ breaks out early, token counts will be missing. Do not restructure working
106
+ code — just confirm the stream is fully consumed, and report if it is not.
107
+
108
+ ## Step 6: Flush before exit
109
+
110
+ Flush pending telemetry before the process exits:
111
+
112
+ ```python
113
+ moda.flush()
114
+ ```
115
+
116
+ ## Step 7: Validate
117
+
118
+ Report the packages installed, files edited, and any step a human still needs
119
+ to do (for example setting `MODA_API_KEY` in the deploy environment). Then
120
+ verify telemetry reaches Moda:
121
+
122
+ ```bash
123
+ moda doctor --online --json
124
+ ```
125
+
126
+ The report should show recent traces. If it does not: confirm
127
+ `moda-claude-agent-sdk` is installed (it is separate from `moda-ai`), that
128
+ `moda.init()` runs before `ClaudeSDKClient` is created, and that
129
+ `MODA_API_KEY` is available in the runtime environment.
@@ -0,0 +1,46 @@
1
+ # Golden reference: generic Python app + Moda
2
+
3
+ The complete finished integration for a small Python chat script whose LLM
4
+ calls go through the `openai` client (automatically instrumented). Match
5
+ this structure; adapt names to the target repository.
6
+
7
+ ## app/main.py
8
+
9
+ ```python
10
+ import os
11
+
12
+ import moda
13
+ from moda import set_conversation_id, set_user_id
14
+ from openai import OpenAI
15
+
16
+ # Initialize Moda once, before any LLM client is created.
17
+ moda.init(os.environ["MODA_API_KEY"])
18
+
19
+ client = OpenAI()
20
+
21
+
22
+ def answer(session_id: str, user_id: str, message: str) -> str:
23
+ # Scoped context: safe under concurrent callers.
24
+ with set_conversation_id(f"session_{session_id}"):
25
+ with set_user_id(user_id):
26
+ response = client.chat.completions.create(
27
+ model="gpt-4o",
28
+ messages=[{"role": "user", "content": message}],
29
+ )
30
+ return response.choices[0].message.content
31
+
32
+
33
+ print(answer("demo-session", "user-123", "Hello!"))
34
+
35
+ # Flush pending telemetry before exit.
36
+ moda.flush()
37
+ ```
38
+
39
+ ## What changed, and what did not
40
+
41
+ - `moda-ai` added to the project dependencies.
42
+ - One `moda.init` call added at startup, before any LLM client is created.
43
+ - Call sites through instrumented clients are unchanged; only context
44
+ scoping was added around them.
45
+ - No `.env` file was created or edited; `MODA_API_KEY` is read from the
46
+ runtime environment.
@@ -0,0 +1,146 @@
1
+ ---
2
+ id: integration-python-generic
3
+ name: "Integrate the Moda SDK (Python, any provider)"
4
+ version: 1.0.0
5
+ category: integration
6
+ targets:
7
+ language: python
8
+ frameworks: []
9
+ providers: []
10
+ sdk_package: moda-ai
11
+ summary: "General Moda SDK integration for a Python app when no specific framework or provider skill matches."
12
+ ---
13
+
14
+ # Integrate the Moda SDK (Python, any provider)
15
+
16
+ This is the general Python integration path, used when no framework- or
17
+ provider-specific skill matches. Follow the steps below in order. Each step
18
+ has a stop condition; when you hit one, stop and report instead of guessing.
19
+ `EXAMPLE.md` in this directory shows a complete finished integration; match
20
+ its structure. For API details beyond this skill, read
21
+ https://docs.moda.dev/ingestion/moda-sdk.
22
+
23
+ ## Safety rules (apply to every step)
24
+
25
+ - Only touch the repository you were launched in.
26
+ - Never write the `MODA_API_KEY` value (or any secret) into source files, and
27
+ never create or edit `.env` files. The key belongs in the runtime
28
+ environment or a secret manager.
29
+ - Make the smallest correct change. Match the existing code style and imports.
30
+ - Do not commit unless the user asks.
31
+ - If a step is ambiguous in this repository, stop and report rather than
32
+ guessing.
33
+
34
+ ## Step 1: Find the real LLM call sites and pick the right surface
35
+
36
+ Search the repository for LLM calls and classify them:
37
+
38
+ - Calls through an instrumented provider or framework: automatically
39
+ captured once Moda is initialized (Step 3); no per-call changes. The
40
+ Python SDK's `Instruments` set covers providers including OpenAI,
41
+ Anthropic, Cohere, Mistral, Groq, Ollama, Bedrock, VertexAI, and
42
+ frameworks including LangChain, LlamaIndex, Haystack, and CrewAI (full
43
+ table: https://docs.moda.dev/ingestion/moda-sdk). OpenAI-compatible
44
+ gateways (for example OpenRouter used through the `openai` client with a
45
+ custom `base_url`) count as OpenAI here.
46
+ - Calls through LangChain or the Claude Agent SDK: stop — use the dedicated
47
+ skill instead; never instrument the underlying provider client when a
48
+ wrapper framework is in use.
49
+ - Direct HTTP calls to a provider outside the instruments table: the Python
50
+ SDK does not capture these automatically. Note them in your report and
51
+ point the user at https://docs.moda.dev/ingestion/direct-api; do not
52
+ build a custom ingestion path yourself.
53
+
54
+ If the repository has no LLM call sites at all, stop and report.
55
+
56
+ ## Step 2: Install the SDK
57
+
58
+ Install `moda-ai` with the package manager this repository already uses
59
+ (`uv.lock` means uv, `poetry.lock` means poetry, otherwise pip):
60
+
61
+ ```bash
62
+ pip install moda-ai
63
+ ```
64
+
65
+ With uv:
66
+
67
+ ```bash
68
+ uv add moda-ai
69
+ ```
70
+
71
+ With poetry:
72
+
73
+ ```bash
74
+ poetry add moda-ai
75
+ ```
76
+
77
+ If `moda-ai` is already a dependency, skip the install.
78
+
79
+ ## Step 3: Initialize Moda once at startup
80
+
81
+ `moda.init` is synchronous and must run once, at startup, before any LLM
82
+ client is created. If a `moda.init` call already exists, verify it runs at
83
+ startup and skip this step; never add a second call.
84
+
85
+ ```python
86
+ import os
87
+
88
+ import moda
89
+
90
+ moda.init(os.environ["MODA_API_KEY"])
91
+ ```
92
+
93
+ ## Step 4: Set conversation and user context
94
+
95
+ Set a stable conversation id before each LLM call so multi-turn
96
+ conversations group together, and a user id when one user can be identified.
97
+ If one user reaches the same agent through several channels, use the same
98
+ user id across channels.
99
+
100
+ For sequential code, use the module-level properties:
101
+
102
+ ```python
103
+ moda.conversation_id = f"session_{session_id}"
104
+ moda.user_id = user_id
105
+ ```
106
+
107
+ For concurrent request handlers (any web server), use the scoped context
108
+ managers so overlapping requests do not leak context into each other:
109
+
110
+ ```python
111
+ from moda import set_conversation_id, set_user_id
112
+
113
+ with set_conversation_id(f"session_{session_id}"):
114
+ with set_user_id(user_id):
115
+ response = make_llm_call(user_message)
116
+ ```
117
+
118
+ Reuse the session/thread identifier the app already has. If no session
119
+ identifier exists anywhere, the SDK falls back to hashing the first user
120
+ message plus the system prompt — acceptable only for simple chatbots that
121
+ pass full message history on every call. If this repo is an agent framework
122
+ or does not pass full history, an explicit conversation id is required; stop
123
+ and report if you cannot find a session identifier to use.
124
+
125
+ ## Step 5: Flush before exit
126
+
127
+ Flush pending telemetry before the process exits (short-lived scripts) or on
128
+ shutdown (servers):
129
+
130
+ ```python
131
+ moda.flush()
132
+ ```
133
+
134
+ ## Step 6: Validate
135
+
136
+ Report the packages installed, files edited, and any step a human still needs
137
+ to do (for example setting `MODA_API_KEY` in the deploy environment). Then
138
+ verify telemetry reaches Moda:
139
+
140
+ ```bash
141
+ moda doctor --online --json
142
+ ```
143
+
144
+ The report should show recent traces. If it does not, confirm `MODA_API_KEY`
145
+ is available in the runtime environment and that `moda.init()` runs before
146
+ the first LLM client is created.
@@ -0,0 +1,63 @@
1
+ # Golden reference: Python LangChain agent + Moda
2
+
3
+ The complete finished integration for a minimal LangChain app. Match this
4
+ structure; adapt names to the target repository. Note what is absent: no
5
+ LangChain callbacks or handler classes for Moda — `moda.init()` enables all
6
+ instruments (including LangChain) by default, and the only per-run change is
7
+ the explicit conversation id wrapper.
8
+
9
+ ## app/agent.py
10
+
11
+ ```python
12
+ import os
13
+
14
+ import moda
15
+ from langchain_core.prompts import ChatPromptTemplate
16
+ from langchain_openai import ChatOpenAI
17
+ from moda import set_conversation_id, set_user_id
18
+
19
+ # Initialize Moda once, before LangChain models are constructed. moda.init
20
+ # enables all instruments (including LangChain) by default.
21
+ moda.init(os.environ["MODA_API_KEY"])
22
+
23
+ model = ChatOpenAI(model="gpt-4o")
24
+ prompt = ChatPromptTemplate.from_messages([
25
+ ("system", "You are a helpful assistant."),
26
+ ("human", "{input}"),
27
+ ])
28
+ chain = prompt | model
29
+
30
+
31
+ def run_agent(session_id: str, user_id: str, user_query: str):
32
+ # Explicit conversation id around the whole run: every internal LLM call
33
+ # made during this invocation shares it. Automatic detection does NOT
34
+ # work for agent frameworks.
35
+ with set_conversation_id(f"agent_session_{session_id}"):
36
+ with set_user_id(user_id):
37
+ return chain.invoke({"input": user_query})
38
+ ```
39
+
40
+ ## app/main.py
41
+
42
+ ```python
43
+ import moda
44
+
45
+ from app.agent import run_agent
46
+
47
+ result = run_agent("demo-session", "user-123", "What is Python?")
48
+ print(result.content)
49
+
50
+ # Flush pending telemetry before exit.
51
+ moda.flush()
52
+ ```
53
+
54
+ ## What changed, and what did not
55
+
56
+ - `moda-ai` added to the project dependencies.
57
+ - One `moda.init` call added at startup, before any LangChain model is
58
+ constructed.
59
+ - Each agent/chain entry point is wrapped in the scoped context managers
60
+ with an explicit conversation id; the LangChain code itself is unchanged.
61
+ - No LangChain callbacks or handler classes were added for Moda.
62
+ - No `.env` file was created or edited; `MODA_API_KEY` is read from the
63
+ runtime environment.