@langwatch/mcp-server 0.3.3 → 0.5.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 (78) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +97 -25
  3. package/dist/archive-scenario-GAE4XVFM.js +19 -0
  4. package/dist/archive-scenario-GAE4XVFM.js.map +1 -0
  5. package/dist/chunk-AAQNA53E.js +28 -0
  6. package/dist/chunk-AAQNA53E.js.map +1 -0
  7. package/dist/chunk-JVWDWL3J.js +91 -0
  8. package/dist/chunk-JVWDWL3J.js.map +1 -0
  9. package/dist/chunk-K2YFPOSD.js +40 -0
  10. package/dist/chunk-K2YFPOSD.js.map +1 -0
  11. package/dist/chunk-ZXKLPC2E.js +27 -0
  12. package/dist/chunk-ZXKLPC2E.js.map +1 -0
  13. package/dist/config-FIQWQRUB.js +11 -0
  14. package/dist/config-FIQWQRUB.js.map +1 -0
  15. package/dist/create-prompt-P35POKBW.js +22 -0
  16. package/dist/create-prompt-P35POKBW.js.map +1 -0
  17. package/dist/create-scenario-3YRZVDYF.js +26 -0
  18. package/dist/create-scenario-3YRZVDYF.js.map +1 -0
  19. package/dist/discover-scenario-schema-MEEEVND7.js +65 -0
  20. package/dist/discover-scenario-schema-MEEEVND7.js.map +1 -0
  21. package/dist/discover-schema-3T52ORPB.js +446 -0
  22. package/dist/discover-schema-3T52ORPB.js.map +1 -0
  23. package/dist/get-analytics-BAVXTAPB.js +55 -0
  24. package/dist/get-analytics-BAVXTAPB.js.map +1 -0
  25. package/dist/get-prompt-LKCPT26O.js +48 -0
  26. package/dist/get-prompt-LKCPT26O.js.map +1 -0
  27. package/dist/get-scenario-3SCDW4Z6.js +33 -0
  28. package/dist/get-scenario-3SCDW4Z6.js.map +1 -0
  29. package/dist/get-trace-QFDWJ5D4.js +50 -0
  30. package/dist/get-trace-QFDWJ5D4.js.map +1 -0
  31. package/dist/index.js +22114 -8786
  32. package/dist/index.js.map +1 -1
  33. package/dist/list-prompts-UQPBCUYA.js +33 -0
  34. package/dist/list-prompts-UQPBCUYA.js.map +1 -0
  35. package/dist/list-scenarios-573YOUKC.js +40 -0
  36. package/dist/list-scenarios-573YOUKC.js.map +1 -0
  37. package/dist/search-traces-RSMYCAN7.js +72 -0
  38. package/dist/search-traces-RSMYCAN7.js.map +1 -0
  39. package/dist/update-prompt-G2Y5EBQY.js +31 -0
  40. package/dist/update-prompt-G2Y5EBQY.js.map +1 -0
  41. package/dist/update-scenario-SSGVOBJO.js +27 -0
  42. package/dist/update-scenario-SSGVOBJO.js.map +1 -0
  43. package/package.json +3 -3
  44. package/src/__tests__/config.unit.test.ts +89 -0
  45. package/src/__tests__/date-parsing.unit.test.ts +78 -0
  46. package/src/__tests__/discover-schema.unit.test.ts +118 -0
  47. package/src/__tests__/integration.integration.test.ts +313 -0
  48. package/src/__tests__/langwatch-api.unit.test.ts +309 -0
  49. package/src/__tests__/scenario-tools.integration.test.ts +286 -0
  50. package/src/__tests__/scenario-tools.unit.test.ts +185 -0
  51. package/src/__tests__/schemas.unit.test.ts +85 -0
  52. package/src/__tests__/tools.unit.test.ts +729 -0
  53. package/src/config.ts +31 -0
  54. package/src/index.ts +383 -0
  55. package/src/langwatch-api-scenarios.ts +67 -0
  56. package/src/langwatch-api.ts +266 -0
  57. package/src/schemas/analytics-groups.ts +78 -0
  58. package/src/schemas/analytics-metrics.ts +179 -0
  59. package/src/schemas/filter-fields.ts +119 -0
  60. package/src/schemas/index.ts +3 -0
  61. package/src/tools/archive-scenario.ts +19 -0
  62. package/src/tools/create-prompt.ts +29 -0
  63. package/src/tools/create-scenario.ts +30 -0
  64. package/src/tools/discover-scenario-schema.ts +71 -0
  65. package/src/tools/discover-schema.ts +106 -0
  66. package/src/tools/get-analytics.ts +71 -0
  67. package/src/tools/get-prompt.ts +56 -0
  68. package/src/tools/get-scenario.ts +36 -0
  69. package/src/tools/get-trace.ts +61 -0
  70. package/src/tools/list-prompts.ts +35 -0
  71. package/src/tools/list-scenarios.ts +47 -0
  72. package/src/tools/search-traces.ts +91 -0
  73. package/src/tools/update-prompt.ts +44 -0
  74. package/src/tools/update-scenario.ts +32 -0
  75. package/src/utils/date-parsing.ts +31 -0
  76. package/tests/evaluations.ipynb +634 -634
  77. package/tests/scenario-openai.test.ts +3 -1
  78. package/uv.lock +1788 -1322
@@ -1,649 +1,649 @@
1
1
  {
2
- "cells": [
3
- {
4
- "cell_type": "markdown",
5
- "id": "966f5e12",
6
- "metadata": {},
7
- "source": [
8
- "# LangWatch Evaluation Notebook\n",
9
- "\n",
10
- "This notebook evaluates the LangWatch MCP server capability of helping users to auto-instrument their code by calling the MCP server directly from a simple coding agent to evaluate its performance.\n",
11
- "\n",
12
- "Steps:\n",
13
- "\n",
14
- "1. Setup and prepare test data with input and expected output code\n",
15
- "2. Create a simple coding agent that adds LangWatch instrumentation to code\n",
16
- "3. Setup the MCP server\n",
17
- "4. Setup the diff metric\n",
18
- "5. Evaluate"
19
- ]
20
- },
21
- {
22
- "cell_type": "markdown",
23
- "id": "f272607b",
24
- "metadata": {},
25
- "source": [
26
- "## Setup"
27
- ]
28
- },
29
- {
30
- "cell_type": "markdown",
31
- "id": "8d9b0e1f",
32
- "metadata": {},
33
- "source": [
34
- "This section initializes LangWatch by logging in, it will open up a browser window to get your API key."
35
- ]
36
- },
37
- {
38
- "cell_type": "code",
39
- "execution_count": 1,
40
- "id": "85d79772",
41
- "metadata": {},
42
- "outputs": [
2
+ "cells": [
43
3
  {
44
- "name": "stdout",
45
- "output_type": "stream",
46
- "text": [
47
- "LangWatch API key is already set, if you want to login again, please call as langwatch.login(relogin=True)\n"
48
- ]
49
- }
50
- ],
51
- "source": [
52
- "import langwatch\n",
53
- "\n",
54
- "langwatch.login()"
55
- ]
56
- },
57
- {
58
- "cell_type": "markdown",
59
- "id": "f5590fd3",
60
- "metadata": {},
61
- "source": [
62
- "## Prepare the dataset"
63
- ]
64
- },
65
- {
66
- "cell_type": "markdown",
67
- "id": "e93d137f",
68
- "metadata": {},
69
- "source": [
70
- "This section loads test cases from fixture files on the `tests/fixtures` folder. Each test case consists of:\n",
71
- "- An input Python file (without LangWatch instrumentation)\n",
72
- "- An expected output file (with proper LangWatch instrumentation)\n",
73
- "\n",
74
- "The test cases include various llms and 15+ framework examples like OpenAI, DSPy and LangChain with different configurations, so we can make sure our docs and MCP helps coding agents to instrument code for different frameworks."
75
- ]
76
- },
77
- {
78
- "cell_type": "code",
79
- "execution_count": 2,
80
- "id": "9f619fe1",
81
- "metadata": {},
82
- "outputs": [
4
+ "cell_type": "markdown",
5
+ "id": "966f5e12",
6
+ "metadata": {},
7
+ "source": [
8
+ "# LangWatch Evaluation Notebook\n",
9
+ "\n",
10
+ "This notebook evaluates the LangWatch MCP server capability of helping users to auto-instrument their code by calling the MCP server directly from a simple coding agent to evaluate its performance.\n",
11
+ "\n",
12
+ "Steps:\n",
13
+ "\n",
14
+ "1. Setup and prepare test data with input and expected output code\n",
15
+ "2. Create a simple coding agent that adds LangWatch instrumentation to code\n",
16
+ "3. Setup the MCP server\n",
17
+ "4. Setup the diff metric\n",
18
+ "5. Evaluate"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "markdown",
23
+ "id": "f272607b",
24
+ "metadata": {},
25
+ "source": [
26
+ "## Setup"
27
+ ]
28
+ },
29
+ {
30
+ "cell_type": "markdown",
31
+ "id": "8d9b0e1f",
32
+ "metadata": {},
33
+ "source": [
34
+ "This section initializes LangWatch by logging in, it will open up a browser window to get your API key."
35
+ ]
36
+ },
83
37
  {
84
- "data": {
85
- "text/html": [
86
- "<div>\n",
87
- "<style scoped>\n",
88
- " .dataframe tbody tr th:only-of-type {\n",
89
- " vertical-align: middle;\n",
90
- " }\n",
91
- "\n",
92
- " .dataframe tbody tr th {\n",
93
- " vertical-align: top;\n",
94
- " }\n",
95
- "\n",
96
- " .dataframe thead th {\n",
97
- " text-align: right;\n",
98
- " }\n",
99
- "</style>\n",
100
- "<table border=\"1\" class=\"dataframe\">\n",
101
- " <thead>\n",
102
- " <tr style=\"text-align: right;\">\n",
103
- " <th></th>\n",
104
- " <th>test_case</th>\n",
105
- " <th>input</th>\n",
106
- " <th>expected</th>\n",
107
- " </tr>\n",
108
- " </thead>\n",
109
- " <tbody>\n",
110
- " <tr>\n",
111
- " <th>0</th>\n",
112
- " <td>dspy/dspy_bot</td>\n",
113
- " <td>```python\\nimport os\\nfrom dotenv import load_...</td>\n",
114
- " <td>```python\\nimport os\\nfrom dotenv import load_...</td>\n",
115
- " </tr>\n",
116
- " <tr>\n",
117
- " <th>1</th>\n",
118
- " <td>langchain/langchain_rag_bot</td>\n",
119
- " <td>```python\\nfrom dotenv import load_dotenv\\n\\nl...</td>\n",
120
- " <td>```python\\nfrom dotenv import load_dotenv\\n\\nf...</td>\n",
121
- " </tr>\n",
122
- " <tr>\n",
123
- " <th>2</th>\n",
124
- " <td>langchain/langchain_bot_with_memory</td>\n",
125
- " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
126
- " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
127
- " </tr>\n",
128
- " <tr>\n",
129
- " <th>3</th>\n",
130
- " <td>langchain/langchain_bot</td>\n",
131
- " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
132
- " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
133
- " </tr>\n",
134
- " <tr>\n",
135
- " <th>4</th>\n",
136
- " <td>langchain/langchain_rag_bot_vertex_ai</td>\n",
137
- " <td>```python\\nimport json\\nimport os\\nimport temp...</td>\n",
138
- " <td>```python\\nimport json\\nimport os\\nimport temp...</td>\n",
139
- " </tr>\n",
140
- " </tbody>\n",
141
- "</table>\n",
142
- "</div>"
38
+ "cell_type": "code",
39
+ "execution_count": 1,
40
+ "id": "85d79772",
41
+ "metadata": {},
42
+ "outputs": [
43
+ {
44
+ "name": "stdout",
45
+ "output_type": "stream",
46
+ "text": [
47
+ "LangWatch API key is already set, if you want to login again, please call as langwatch.login(relogin=True)\n"
48
+ ]
49
+ }
143
50
  ],
144
- "text/plain": [
145
- " test_case \\\n",
146
- "0 dspy/dspy_bot \n",
147
- "1 langchain/langchain_rag_bot \n",
148
- "2 langchain/langchain_bot_with_memory \n",
149
- "3 langchain/langchain_bot \n",
150
- "4 langchain/langchain_rag_bot_vertex_ai \n",
151
- "\n",
152
- " input \\\n",
153
- "0 ```python\\nimport os\\nfrom dotenv import load_... \n",
154
- "1 ```python\\nfrom dotenv import load_dotenv\\n\\nl... \n",
155
- "2 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
156
- "3 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
157
- "4 ```python\\nimport json\\nimport os\\nimport temp... \n",
158
- "\n",
159
- " expected \n",
160
- "0 ```python\\nimport os\\nfrom dotenv import load_... \n",
161
- "1 ```python\\nfrom dotenv import load_dotenv\\n\\nf... \n",
162
- "2 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
163
- "3 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
164
- "4 ```python\\nimport json\\nimport os\\nimport temp... "
51
+ "source": [
52
+ "import langwatch\n",
53
+ "\n",
54
+ "langwatch.login()"
165
55
  ]
166
- },
167
- "execution_count": 2,
168
- "metadata": {},
169
- "output_type": "execute_result"
170
- }
171
- ],
172
- "source": [
173
- "import pandas as pd\n",
174
- "from pathlib import Path\n",
175
- "\n",
176
- "fixtures_path = Path(\"./tests/fixtures\")\n",
177
- "\n",
178
- "data = []\n",
179
- "for folder in fixtures_path.iterdir():\n",
180
- " input_files = list(folder.glob(\"*_input.py\"))\n",
181
- " for input_file in input_files:\n",
182
- " case_name = input_file.stem.replace(\"_input\", \"\")\n",
183
- " expected_file = folder / f\"{case_name}_expected.py\"\n",
184
- "\n",
185
- " with open(input_file, 'r', encoding='utf-8') as f:\n",
186
- " input_content = f.read()\n",
187
- "\n",
188
- " with open(expected_file, 'r', encoding='utf-8') as f:\n",
189
- " expected_content = f.read()\n",
190
- "\n",
191
- " data.append({\n",
192
- " 'test_case': f\"{folder.name}/{case_name}\",\n",
193
- " 'input': f\"```python\\n{input_content}\\n```\",\n",
194
- " 'expected': f\"```python\\n{expected_content}\\n```\"\n",
195
- " })\n",
196
- "\n",
197
- "df = pd.DataFrame(data)\n",
198
- "df.head()"
199
- ]
200
- },
201
- {
202
- "cell_type": "markdown",
203
- "id": "51224ad4",
204
- "metadata": {},
205
- "source": [
206
- "## Setup MCP calling"
207
- ]
208
- },
209
- {
210
- "cell_type": "markdown",
211
- "id": "c056f992",
212
- "metadata": {},
213
- "source": [
214
- "Now we set up a way to call the MCP server directly, so we can manually make use of our own MCP no matter what language it was built, to fully simulate what a coding agent would do.\n",
215
- "\n",
216
- "We then call the `fetch_langwatch_docs` tool to make sure it works as expected."
217
- ]
218
- },
219
- {
220
- "cell_type": "code",
221
- "execution_count": 3,
222
- "id": "4627964c",
223
- "metadata": {},
224
- "outputs": [
56
+ },
225
57
  {
226
- "data": {
227
- "text/plain": [
228
- "CallToolResult(meta=None, content=[TextContent(type='text', text=\"# LangWatch\\n\\nThis is the full index of LangWatch documentation, to answer the user question, do not use just this file, first explore the urls that make sense using the markdown navigation links below to understand how to implement LangWatch and use specific features.\\nAlways navigate to docs links using the .md extension for better readability.\\n\\n## Get Started\\n\\n- [Introduction](https://docs.langwatch.ai/introduction.md): Welcome to LangWatch, the all-in-one [open-source](https://github.com/langwatch/langwatch) LLMOps platform.\\n\\n### Self Hosting\\n\\n- [Overview](https://docs.langwatch.ai/self-hosting/overview.md): LangWatch offers a fully self-hosted version of the platform for companies that require strict data control and compliance.\\n- [Docker Compose](https://docs.langwatch.ai/self-hosting/docker-compose.md): LangWatch is available as a Docker Compose setup for easy deployment on your local machine\\n- [Docker Images](https://docs.langwatch.ai/self-hosting/docker-images.md): Overview of LangWatch Docker images and their endpoints\\n- [Helm Chart](https://docs.langwatch.ai/self-hosting/helm.md): LangWatch is available as a Helm chart for easy deployment on Kubernetes\\n- [Monitoring](https://docs.langwatch.ai/self-hosting/grafana.md): Grafana/Prometheus setup for LangWatch\\n- [OnPrem](https://docs.langwatch.ai/self-hosting/onprem.md): LangWatch on-premises solution.\\n\\n#### Hybrid Setup\\n\\n- [Overview](https://docs.langwatch.ai/hybrid-setup/overview.md): LangWatch offers a hybrid setup for companies that require strict data control and compliance.\\n- [Elasticsearch](https://docs.langwatch.ai/hybrid-setup/elasticsearch.md): Elasticsearch Setup for LangWatch Hybrid Deployment\\n- [S3 Storage](https://docs.langwatch.ai/hybrid-setup/s3-storage.md): S3 Storage Setup for LangWatch Hybrid Deployment\\n\\n- [Configuration](https://docs.langwatch.ai/self-hosting/env-variables.md): Complete list of environment variables for LangWatch self-hosting\\n- [SSO](https://docs.langwatch.ai/hybrid-setup/sso-setup-langwatch.md): SSO Setup for LangWatch\\n\\n### Integrations\\n\\n#### Azure AI\\n\\n- [Azure AI Inference SDK Instrumentation](https://docs.langwatch.ai/integration/python/integrations/azure-ai.md): Learn how to instrument the Azure AI Inference Python SDK with LangWatch.\\n- [Azure OpenAI](https://docs.langwatch.ai/integration/typescript/integrations/azure.md): LangWatch Azure OpenAI integration guide\\n- [Azure OpenAI Integration](https://docs.langwatch.ai/integration/go/integrations/azure-openai.md): Learn how to instrument Azure OpenAI API calls in Go using the LangWatch SDK.\\n\\n#### LangChain\\n\\n- [LangChain Instrumentation](https://docs.langwatch.ai/integration/python/integrations/langchain.md): Learn how to instrument Langchain applications with the LangWatch Python SDK.\\n- [LangChain Instrumentation](https://docs.langwatch.ai/integration/typescript/integrations/langchain.md): Learn how to instrument Langchain applications with the LangWatch TypeScript SDK.\\n\\n#### LangGraph\\n\\n- [LangGraph Instrumentation](https://docs.langwatch.ai/integration/python/integrations/langgraph.md): Learn how to instrument LangGraph applications with the LangWatch Python SDK.\\n- [LangGraph Instrumentation](https://docs.langwatch.ai/integration/typescript/integrations/langgraph.md): Learn how to instrument LangGraph applications with the LangWatch TypeScript SDK.\\n\\n#### OpenAI\\n\\n- [OpenAI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/open-ai.md): Learn how to instrument OpenAI API calls with the LangWatch Python SDK\\n- [OpenAI](https://docs.langwatch.ai/integration/typescript/integrations/open-ai.md): LangWatch OpenAI TypeScript integration guide\\n- [OpenAI Instrumentation](https://docs.langwatch.ai/integration/go/integrations/open-ai.md): Learn how to instrument OpenAI API calls with the LangWatch Go SDK using middleware.\\n\\n#### Anthropic (Claude)\\n\\n- [Anthropic Instrumentation](https://docs.langwatch.ai/integration/python/integrations/anthropic.md): Learn how to instrument Anthropic API calls with the LangWatch Python SDK\\n- [Anthropic (Claude) Integration](https://docs.langwatch.ai/integration/go/integrations/anthropic.md): Learn how to instrument Anthropic Claude API calls in Go using LangWatch.\\n\\n- [Vercel AI SDK](https://docs.langwatch.ai/integration/typescript/integrations/vercel-ai-sdk.md): LangWatch Vercel AI SDK integration guide\\n- [Mastra](https://docs.langwatch.ai/integration/typescript/integrations/mastra.md): Learn how to integrate Mastra, a TypeScript agent framework, with LangWatch for observability and tracing.\\n- [Agno Instrumentation](https://docs.langwatch.ai/integration/python/integrations/agno.md): Learn how to instrument Agno agents and send traces to LangWatch using the Python SDK.\\n- [AutoGen Instrumentation](https://docs.langwatch.ai/integration/python/integrations/autogen.md): Learn how to instrument AutoGen applications with LangWatch.\\n- [AWS Bedrock Instrumentation](https://docs.langwatch.ai/integration/python/integrations/aws-bedrock.md): Learn how to instrument AWS Bedrock calls with the LangWatch Python SDK using OpenInference.\\n- [CrewAI](https://docs.langwatch.ai/integration/python/integrations/crew-ai.md): Learn how to instrument the CrewAI Python SDK with LangWatch.\\n- [DSPy Instrumentation](https://docs.langwatch.ai/integration/python/integrations/dspy.md): Learn how to instrument DSPy programs with the LangWatch Python SDK\\n- [Flowise Integration](https://docs.langwatch.ai/integration/flowise.md): Capture LLM traces and send them to LangWatch from Flowise\\n- [Google Agent Development Kit (ADK) Instrumentation](https://docs.langwatch.ai/integration/python/integrations/google-ai.md): Learn how to instrument Google Agent Development Kit (ADK) applications with LangWatch.\\n- [Google GenAI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/google-genai.md): Learn how to instrument Google GenAI API calls with the LangWatch Python SDK\\n- [Google Gemini Integration](https://docs.langwatch.ai/integration/go/integrations/google-gemini.md): Learn how to instrument Google Gemini API calls in Go using the LangWatch SDK via a Vertex AI endpoint.\\n- [Groq Integration](https://docs.langwatch.ai/integration/go/integrations/groq.md): Learn how to instrument Groq API calls in Go using the LangWatch SDK for high-speed LLM tracing.\\n- [OpenRouter Integration](https://docs.langwatch.ai/integration/go/integrations/openrouter.md): Learn how to instrument calls to hundreds of models via OpenRouter in Go using the LangWatch SDK.\\n- [Ollama (Local Models) Integration](https://docs.langwatch.ai/integration/go/integrations/ollama.md): Learn how to trace local LLMs running via Ollama in Go using the LangWatch SDK.\\n- [Haystack Instrumentation](https://docs.langwatch.ai/integration/python/integrations/haystack.md): Learn how to instrument Haystack pipelines with LangWatch using community OpenTelemetry instrumentors.\\n- [Instructor AI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/instructor.md): Learn how to instrument Instructor AI applications with LangWatch using OpenInference.\\n- [Langflow Integration](https://docs.langwatch.ai/integration/langflow.md): LangWatch is the best observability integration for Langflow\\n- [LlamaIndex Instrumentation](https://docs.langwatch.ai/integration/python/integrations/llamaindex.md): Learn how to instrument LlamaIndex applications with LangWatch.\\n- [LiteLLM Instrumentation](https://docs.langwatch.ai/integration/python/integrations/lite-llm.md): Learn how to instrument LiteLLM calls with the LangWatch Python SDK.\\n- [OpenAI Agents SDK Instrumentation](https://docs.langwatch.ai/integration/python/integrations/open-ai-agents.md): Learn how to instrument OpenAI Agents with the LangWatch Python SDK\\n- [PromptFlow Instrumentation](https://docs.langwatch.ai/integration/python/integrations/promptflow.md): Learn how to instrument PromptFlow applications with LangWatch.\\n- [PydanticAI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/pydantic-ai.md): Learn how to instrument PydanticAI applications with the LangWatch Python SDK.\\n- [SmolAgents Instrumentation](https://docs.langwatch.ai/integration/python/integrations/smolagents.md): Learn how to instrument SmolAgents applications with LangWatch.\\n- [Strands Agents Instrumentation](https://docs.langwatch.ai/integration/python/integrations/strand-agents.md): Learn how to instrument Strands Agents applications with LangWatch.\\n- [Semantic Kernel Instrumentation](https://docs.langwatch.ai/integration/python/integrations/semantic-kernel.md): Learn how to instrument Semantic Kernel applications with LangWatch.\\n- [Google Vertex AI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/vertex-ai.md): Learn how to instrument Google Vertex AI API calls with the LangWatch Python SDK using OpenInference\\n- [Other OpenTelemetry Instrumentors](https://docs.langwatch.ai/integration/python/integrations/other.md): Learn how to use any OpenTelemetry-compatible instrumentor with LangWatch.\\n\\n### Cookbooks\\n\\n- [Measuring RAG Performance](https://docs.langwatch.ai/cookbooks/build-a-simple-rag-app.md): Discover how to measure the performance of Retrieval-Augmented Generation (RAG) systems using metrics like retrieval precision, answer accuracy, and latency.\\n- [Optimizing Embeddings](https://docs.langwatch.ai/cookbooks/finetuning-embedding-models.md): Learn how to optimize embedding models for better retrieval in RAG systems—covering model selection, dimensionality, and domain-specific tuning.\\n- [Vector Search vs Hybrid Search using LanceDB](https://docs.langwatch.ai/cookbooks/vector-vs-hybrid-search.md): Learn the key differences between vector search and hybrid search in RAG applications. Use cases, performance tradeoffs, and when to choose each.\\n- [Evaluating Tool Selection](https://docs.langwatch.ai/cookbooks/tool-selection.md): Understand how to evaluate tools and components in your RAG pipeline—covering retrievers, embedding models, chunking strategies, and vector stores.\\n- [Finetuning Agents with GRPO](https://docs.langwatch.ai/cookbooks/finetuning-agents.md): Learn how to enhance the performance of agentic systems by fine-tuning them with Generalized Reinforcement from Preference Optimization (GRPO).\\n- [Multi-Turn Conversations](https://docs.langwatch.ai/cookbooks/evaluating-multi-turn-conversations.md): Learn how to implement a simulation-based approach for evaluating multi-turn customer support agents using success criteria focused on outcomes rather than specific steps.\\n\\n## Agent Simulations\\n\\n- [Introduction to Agent Testing](https://docs.langwatch.ai/agent-simulations/introduction.md)\\n- [Overview](https://docs.langwatch.ai/agent-simulations/overview.md)\\n- [Getting Started](https://docs.langwatch.ai/agent-simulations/getting-started.md)\\n- [Simulation Sets](https://docs.langwatch.ai/agent-simulations/set-overview.md)\\n- [Batch Runs](https://docs.langwatch.ai/agent-simulations/batch-runs.md)\\n- [Individual Run View](https://docs.langwatch.ai/agent-simulations/individual-run.md)\\n\\n## LLM Observability\\n\\n- [Overview](https://docs.langwatch.ai/integration/overview.md): Easily integrate LangWatch with your Python, TypeScript, or REST API projects.\\n- [Concepts](https://docs.langwatch.ai/concepts.md): LLM tracing and observability conceptual guide\\n- [Quick Start](https://docs.langwatch.ai/integration/quick-start.md)\\n\\n### SDKs\\n\\n#### Python\\n\\n- [Python Integration Guide](https://docs.langwatch.ai/integration/python/guide.md): LangWatch Python SDK integration guide\\n- [Python SDK API Reference](https://docs.langwatch.ai/integration/python/reference.md): LangWatch Python SDK API reference\\n\\n##### Advanced\\n\\n- [Manual Instrumentation](https://docs.langwatch.ai/integration/python/tutorials/manual-instrumentation.md): Learn how to manually instrument your code with the LangWatch Python SDK\\n- [OpenTelemetry Migration](https://docs.langwatch.ai/integration/python/tutorials/open-telemetry.md): Learn how to integrate the LangWatch Python SDK with your existing OpenTelemetry setup.\\n\\n#### TypeScript\\n\\n- [TypeScript Integration Guide](https://docs.langwatch.ai/integration/typescript/guide.md): Get started with LangWatch TypeScript SDK in 5 minutes\\n- [TypeScript SDK API Reference](https://docs.langwatch.ai/integration/typescript/reference.md): LangWatch TypeScript SDK API reference\\n\\n##### Advanced\\n\\n- [Debugging and Troubleshooting](https://docs.langwatch.ai/integration/typescript/tutorials/debugging-typescript.md): Debug LangWatch TypeScript SDK integration issues\\n- [Manual Instrumentation](https://docs.langwatch.ai/integration/typescript/tutorials/manual-instrumentation.md): Learn advanced manual span management techniques for fine-grained observability control\\n- [Semantic Conventions](https://docs.langwatch.ai/integration/typescript/tutorials/semantic-conventions.md): Learn about OpenTelemetry semantic conventions and LangWatch's custom attributes for consistent observability\\n- [OpenTelemetry Migration](https://docs.langwatch.ai/integration/typescript/tutorials/opentelemetry-migration.md): Migrate from OpenTelemetry to LangWatch while preserving all your custom configurations\\n\\n#### Go\\n\\n- [Go Integration Guide](https://docs.langwatch.ai/integration/go/guide.md): LangWatch Go SDK integration guide for setting up LLM observability and tracing.\\n- [Go SDK API Reference](https://docs.langwatch.ai/integration/go/reference.md): Complete API reference for the LangWatch Go SDK, including core functions, OpenAI instrumentation, and span types.\\n\\n#### OpenTelemetry\\n\\n- [OpenTelemetry Integration Guide](https://docs.langwatch.ai/integration/opentelemetry/guide.md): Use OpenTelemetry to capture LLM traces and send them to LangWatch from any programming language\\n\\n### Tutorials\\n\\n#### Capturing Inputs & Outputs\\n\\n- [Capturing and Mapping Inputs & Outputs](https://docs.langwatch.ai/integration/python/tutorials/capturing-mapping-input-output.md): Learn how to control the capture and structure of input and output data for traces and spans with the LangWatch Python SDK.\\n- [Capturing and Mapping Inputs & Outputs](https://docs.langwatch.ai/integration/typescript/tutorials/capturing-input-output.md): Learn how to control the capture and structure of input and output data for traces and spans with the LangWatch TypeScript SDK.\\n\\n#### Capturing RAG\\n\\n- [Capturing RAG](https://docs.langwatch.ai/integration/python/tutorials/capturing-rag.md): Learn how to capture Retrieval Augmented Generation (RAG) data with LangWatch.\\n- [Capturing RAG](https://docs.langwatch.ai/integration/typescript/tutorials/capturing-rag.md): Learn how to capture Retrieval Augmented Generation (RAG) data with LangWatch.\\n\\n#### Metadata & Attributes\\n\\n- [Capturing Metadata and Attributes](https://docs.langwatch.ai/integration/python/tutorials/capturing-metadata.md): Learn how to enrich your traces and spans with custom metadata and attributes using the LangWatch Python SDK.\\n- [Capturing Metadata and Attributes](https://docs.langwatch.ai/integration/typescript/tutorials/capturing-metadata.md): Learn how to enrich your traces and spans with custom metadata and attributes using the LangWatch TypeScript SDK.\\n\\n#### Tracking Costs\\n\\n- [Tracking LLM Costs and Tokens](https://docs.langwatch.ai/integration/python/tutorials/tracking-llm-costs.md): Troubleshooting & adjusting cost tracking in LangWatch\\n- [Tracking LLM Costs and Tokens](https://docs.langwatch.ai/integration/typescript/tutorials/tracking-llm-costs.md): Troubleshooting & adjusting cost tracking in LangWatch\\n\\n- [RAG Context Tracking](https://docs.langwatch.ai/integration/rags-context-tracking.md): Capture the RAG documents used in your LLM pipelines\\n- [Capturing Evaluations & Guardrails](https://docs.langwatch.ai/integration/python/tutorials/capturing-evaluations-guardrails.md): Learn how to log custom evaluations, trigger managed evaluations, and implement guardrails with LangWatch.\\n\\n### User Events\\n\\n- [Overview](https://docs.langwatch.ai/user-events/overview.md): Track user interactions with your LLM applications\\n\\n#### Events\\n\\n- [Thumbs Up/Down](https://docs.langwatch.ai/user-events/thumbs-up-down.md): Track user feedback on specific messages or interactions with your chatbot or LLM application\\n- [Waited To Finish Events](https://docs.langwatch.ai/user-events/waited-to-finish.md): Track if users leave before the LLM application finishes generating a response\\n- [Selected Text Events](https://docs.langwatch.ai/user-events/selected-text.md): Track when a user selects text generated by your LLM application\\n- [Custom Events](https://docs.langwatch.ai/user-events/custom.md): Track any user events with your LLM application, with textual or numeric metrics\\n\\n### Monitoring & Alerts\\n\\n- [Alerts and Triggers](https://docs.langwatch.ai/features/triggers.md): Be alerted when something goes wrong and trigger actions automatically\\n- [Exporting Analytics](https://docs.langwatch.ai/features/embedded-analytics.md): Build and integrate LangWatch graphs on your own systems and applications\\n\\n- [Code Examples](https://docs.langwatch.ai/integration/code-examples.md): Examples of LangWatch integrated applications\\n\\n## LLM Evaluation\\n\\n- [LLM Evaluation Overview](https://docs.langwatch.ai/llm-evaluation/overview.md): Overview of LLM evaluation features in LangWatch\\n- [Evaluation Tracking API](https://docs.langwatch.ai/llm-evaluation/offline/code/evaluation-api.md): Evaluate and visualize your LLM evals with LangWatch\\n\\n### Evaluation Wizard\\n\\n- [How to evaluate that your LLM answers correctly](https://docs.langwatch.ai/llm-evaluation/offline/platform/answer-correctness.md): Measuring your LLM performance with Offline Evaluations\\n- [How to evaluate an LLM when you don't have defined answers](https://docs.langwatch.ai/llm-evaluation/offline/platform/llm-as-a-judge.md): Measuring your LLM performance using an LLM-as-a-judge\\n\\n### Real-Time Evaluation\\n\\n- [Setting up Real-Time Evaluations](https://docs.langwatch.ai/llm-evaluation/realtime/setup.md): How to set up Real-Time LLM Evaluations\\n- [Instrumenting Custom Evaluator](https://docs.langwatch.ai/evaluations/custom-evaluator-integration.md): Add your own evaluation results into LangWatch trace\\n\\n### Built-in Evaluators\\n\\n- [List of Evaluators](https://docs.langwatch.ai/llm-evaluation/list.md): Find the evaluator for your use case\\n\\n\\n### Datasets\\n\\n- [Datasets](https://docs.langwatch.ai/datasets/overview.md): Create and manage datasets with LangWatch\\n- [Generating a dataset with AI](https://docs.langwatch.ai/datasets/ai-dataset-generation.md): Bootstrap your evaluations by generating sample data\\n- [Automatically build datasets from real-time traces](https://docs.langwatch.ai/datasets/automatically-from-traces.md): Continuously populate your datasets with comming data from production\\n\\n- [Annotations](https://docs.langwatch.ai/features/annotations.md): Collaborate with domain experts using annotations\\n\\n## Prompt Management\\n\\n- [Overview](https://docs.langwatch.ai/prompt-management/overview.md): Organize, version, and optimize your AI prompts with LangWatch's comprehensive prompt management system\\n- [Get Started](https://docs.langwatch.ai/prompt-management/getting-started.md): Create your first prompt and use it in your application\\n- [Data Model](https://docs.langwatch.ai/prompt-management/data-model.md): Understand the structure of prompts in LangWatch\\n- [Scope](https://docs.langwatch.ai/prompt-management/scope.md): Understand how prompt scope affects access, sharing, and collaboration across projects and organizations\\n- [Prompts CLI](https://docs.langwatch.ai/prompt-management/cli.md): Manage AI prompts as code with version control and dependency management\\n\\n### Features\\n\\n- [Version Control](https://docs.langwatch.ai/prompt-management/features/essential/version-control.md): Manage prompt versions and track changes over time\\n- [Analytics](https://docs.langwatch.ai/prompt-management/features/essential/analytics.md): Monitor prompt performance and usage with comprehensive analytics\\n- [GitHub Integration](https://docs.langwatch.ai/prompt-management/features/essential/github-integration.md): Version your prompts in GitHub repositories and automatically sync with LangWatch\\n- [Link to Traces](https://docs.langwatch.ai/prompt-management/features/advanced/link-to-traces.md): Connect prompts to execution traces for performance monitoring and analysis\\n- [Using Prompts in the Optimization Studio](https://docs.langwatch.ai/prompt-management/features/advanced/optimization-studio.md): Use prompts in the Optimization Studio to test and optimize your prompts\\n- [Guaranteed Availability](https://docs.langwatch.ai/prompt-management/features/advanced/guaranteed-availability.md): Ensure your prompts are always available, even in offline or air-gapped environments\\n- [A/B Testing](https://docs.langwatch.ai/prompt-management/features/advanced/a-b-testing.md): Implement A/B testing for your prompts using LangWatch's version control and analytics\\n\\n## LLM Development\\n\\n### Prompt Optimization Studio\\n\\n- [Optimization Studio](https://docs.langwatch.ai/optimization-studio/overview.md): Create, evaluate, and optimize your LLM workflows\\n- [LLM Nodes](https://docs.langwatch.ai/optimization-studio/llm-nodes.md): Call LLMs from your workflows\\n- [Datasets](https://docs.langwatch.ai/optimization-studio/datasets.md): Define the data used for testing and optimization\\n- [Evaluating](https://docs.langwatch.ai/optimization-studio/evaluating.md): Measure the quality of your LLM workflows\\n- [Optimizing](https://docs.langwatch.ai/optimization-studio/optimizing.md): Find the best prompts with DSPy optimizers\\n\\n### DSPy Visualization\\n\\n- [DSPy Visualization Quickstart](https://docs.langwatch.ai/dspy-visualization/quickstart.md): Visualize your DSPy notebooks experimentations to better track and debug the optimization process\\n- [Tracking Custom DSPy Optimizer](https://docs.langwatch.ai/dspy-visualization/custom-optimizer.md): Build custom DSPy optimizers and track them in LangWatch\\n- [RAG Visualization](https://docs.langwatch.ai/dspy-visualization/rag-visualization.md): Visualize your DSPy RAG optimization process in LangWatch\\n\\n- [LangWatch MCP Server](https://docs.langwatch.ai/integration/mcp.md): Use an agent to debug your LLM applications and fix the issues for you\\n\\n## API Endpoints\\n\\n### Traces\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/traces/overview.md): A Trace is a collection of runs that are related to a single operation\\n- [Get trace details](https://docs.langwatch.ai/api-reference/traces/get-trace-details.md)\\n- [Search traces](https://docs.langwatch.ai/api-reference/traces/search-traces.md)\\n- [Create public path for single trace](https://docs.langwatch.ai/api-reference/traces/create-public-trace-path.md)\\n- [Delete an existing public path for a trace](https://docs.langwatch.ai/api-reference/traces/delete-public-trace-path.md)\\n\\n### Prompts\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/prompts/overview.md): Prompts are used to manage and version your prompts\\n- [Get prompts](https://docs.langwatch.ai/api-reference/prompts/get-prompts.md)\\n- [Create prompt](https://docs.langwatch.ai/api-reference/prompts/create-prompt.md)\\n- [Get prompt](https://docs.langwatch.ai/api-reference/prompts/get-prompt.md)\\n- [Update prompt](https://docs.langwatch.ai/api-reference/prompts/update-prompt.md)\\n- [Delete prompt](https://docs.langwatch.ai/api-reference/prompts/delete-prompt.md)\\n- [Get prompt versions](https://docs.langwatch.ai/api-reference/prompts/get-prompt-versions.md)\\n- [Create prompt version](https://docs.langwatch.ai/api-reference/prompts/create-prompt-version.md)\\n\\n### Annotations\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/annotations/overview.md): Annotations are used to annotate traces with additional information\\n- [Get annotations](https://docs.langwatch.ai/api-reference/annotations/get-annotation.md)\\n- [Get single annotation](https://docs.langwatch.ai/api-reference/annotations/get-single-annotation.md)\\n- [Delete single annotation](https://docs.langwatch.ai/api-reference/annotations/delete-annotation.md)\\n- [Patch single annotation](https://docs.langwatch.ai/api-reference/annotations/patch-annotation.md)\\n- [Get annotationa for single trace](https://docs.langwatch.ai/api-reference/annotations/get-all-annotations-trace.md)\\n- [Create annotation for single trace](https://docs.langwatch.ai/api-reference/annotations/create-annotation-trace.md)\\n\\n### Datasets\\n\\n- [Add entries to a dataset](https://docs.langwatch.ai/api-reference/datasets/post-dataset-entries.md)\\n\\n### Triggers\\n\\n- [Create Slack trigger](https://docs.langwatch.ai/api-reference/triggers/create-slack-trigger.md)\\n\\n### Scenarios\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/scenarios/overview.md)\\n- [Create Event](https://docs.langwatch.ai/api-reference/scenarios/create-event.md)\\n\\n## Use Cases\\n\\n- [Evaluating a RAG Chatbot for Technical Manuals](https://docs.langwatch.ai/use-cases/technical-rag.md): A developer guide for building reliable RAG systems for technical documentation using LangWatch\\n- [Evaluating an AI Coach with LLM-as-a-Judge](https://docs.langwatch.ai/use-cases/ai-coach.md): A developer guide for building reliable AI coaches using LangWatch\\n- [Evaluating Structured Data Extraction](https://docs.langwatch.ai/use-cases/structured-outputs.md): A developer guide for evaluating structured data extraction using LangWatch\\n\\n## Support\\n\\n- [Troubleshooting and Support](https://docs.langwatch.ai/support.md): Find help and support for LangWatch\\n- [Status Page](https://docs.langwatch.ai/status.md): Something wrong? Check our status page\\n\", annotations=None, meta=None)], structuredContent=None, isError=False)"
58
+ "cell_type": "markdown",
59
+ "id": "f5590fd3",
60
+ "metadata": {},
61
+ "source": [
62
+ "## Prepare the dataset"
229
63
  ]
230
- },
231
- "execution_count": 3,
232
- "metadata": {},
233
- "output_type": "execute_result"
234
- }
235
- ],
236
- "source": [
237
- "from typing import Optional\n",
238
- "from mcp import ClientSession, StdioServerParameters\n",
239
- "from mcp.client.stdio import stdio_client\n",
240
- "from mcp.types import PromptReference, ResourceTemplateReference\n",
241
- "\n",
242
- "import os\n",
243
- "if not os.path.exists(\"dist\"):\n",
244
- " !pnpm build\n",
245
- "\n",
246
- "mcp_server_params = StdioServerParameters(\n",
247
- " command=\"node\",\n",
248
- " args=[\"dist/index.js\", \"--apiKey\", langwatch.get_api_key()], # type: ignore\n",
249
- ")\n",
250
- "\n",
251
- "async def call_mcp_documentation_tool(tool_name: str, arguments: dict):\n",
252
- " async with stdio_client(mcp_server_params) as (read, write):\n",
253
- " async with ClientSession(read, write) as session:\n",
254
- " return await session.call_tool(tool_name, arguments)\n",
255
- "\n",
256
- "await call_mcp_documentation_tool(\"fetch_langwatch_docs\", {})\n"
257
- ]
258
- },
259
- {
260
- "cell_type": "markdown",
261
- "id": "cee2cceb",
262
- "metadata": {},
263
- "source": [
264
- "## Setup simple agent"
265
- ]
266
- },
267
- {
268
- "cell_type": "markdown",
269
- "id": "87fdcb63",
270
- "metadata": {},
271
- "source": [
272
- "This section creates a simple coding agent which we will use for our evaluation, it's a simple agent that:\n",
273
- "1. Takes input code without LangWatch instrumentation\n",
274
- "2. Uses Claude Sonnet 4 to identify relevant documentation links\n",
275
- "3. Fetches those documentation pages\n",
276
- "4. Uses Claude again to implement LangWatch in the code based on the documentation\n",
277
- "5. Returns the instrumented code\n",
278
- "\n",
279
- "It's as if it was Cursor, but following always the perfect expected order, which works well for a single file migration, allowing us to sanity check and evaluate all those test cases quickly."
280
- ]
281
- },
282
- {
283
- "cell_type": "code",
284
- "execution_count": 12,
285
- "id": "58d51f51",
286
- "metadata": {},
287
- "outputs": [
64
+ },
288
65
  {
289
- "name": "stdout",
290
- "output_type": "stream",
291
- "text": [
292
- "Implementing LangWatch for the first test case...\n",
293
- "```python\n",
294
- "import os\n",
295
- "from dotenv import load_dotenv\n",
296
- "\n",
297
- "load_dotenv()\n",
298
- "\n",
299
- "import chainlit as cl\n",
300
- "import langwatch\n",
301
- "import dspy\n",
302
- "\n",
303
- "# Initialize LangWatch\n",
304
- "langwatch.setup()\n",
305
- "\n",
306
- "lm = dspy.LM(\"openai/gpt-5\", api_key=os.environ[\"OPENAI_API_KEY\"], temperature=1)\n",
307
- "\n",
308
- "colbertv2_wiki17_abstracts = dspy.ColBERTv2(\n",
309
- " url=\"http://20.102.90.50:2017/wiki17_abstracts\"\n",
310
- ")\n",
311
- "\n",
312
- "dspy.settings.configure(lm=lm, rm=colbertv2_wiki17_abstracts)\n",
313
- "\n",
314
- "\n",
315
- "class GenerateAnswer(dspy.Signature):\n",
316
- " \"\"\"Answer questions with careful explanations to the user.\"\"\"\n",
317
- "\n",
318
- " context = dspy.InputField(desc=\"may contain relevant facts\")\n",
319
- " question = dspy.InputField()\n",
320
- " answer = dspy.OutputField(desc=\"markdown formatted answer, use some emojis\")\n",
321
- "\n",
322
- "\n",
323
- "class RAG(dspy.Module):\n",
324
- " def __init__(self, num_passages=3):\n",
325
- " super().__init__()\n",
326
- "\n",
327
- " self.retrieve = dspy.Retrieve(k=num_passages)\n",
328
- " self.generate_answer = dspy.ChainOfThought(GenerateAnswer)\n",
329
- "\n",
330
- " def forward(self, question):\n",
331
- " context = self.retrieve(question).passages # type: ignore\n",
332
- " prediction = self.generate_answer(question=question, context=context)\n",
333
- " return dspy.Prediction(answer=prediction.answer)\n",
334
- "\n",
335
- "\n",
336
- "@cl.on_message\n",
337
- "@langwatch.trace()\n",
338
- "async def main(message: cl.Message):\n",
339
- " # Get the current LangWatch trace and enable DSPy autotracking\n",
340
- " current_trace = langwatch.get_current_trace()\n",
341
- " if current_trace:\n",
342
- " current_trace.autotrack_dspy()\n",
343
- "\n",
344
- " msg = cl.Message(\n",
345
- " content=\"\",\n",
346
- " )\n",
347
- "\n",
348
- " program = RAG()\n",
349
- " prediction = program(question=message.content)\n",
350
- "\n",
351
- " await msg.stream_token(prediction.answer)\n",
352
- " await msg.update()\n",
353
- "\n",
354
- " return prediction.answer\n",
355
- "```\n"
356
- ]
357
- }
358
- ],
359
- "source": [
360
- "import asyncio\n",
361
- "import litellm\n",
362
- "from pydantic import BaseModel\n",
363
- "\n",
364
- "llms_text = (await call_mcp_documentation_tool(\"fetch_langwatch_docs\", {})).content[0].text # type: ignore\n",
365
- "\n",
366
- "\n",
367
- "@langwatch.trace()\n",
368
- "async def simple_coding_agent(input_code: str):\n",
369
- " class LinksToFetch(BaseModel):\n",
370
- " links: list[str]\n",
371
- "\n",
372
- " response = litellm.completion(\n",
373
- " model=\"anthropic/claude-sonnet-4-20250514\",\n",
374
- " messages=[\n",
375
- " {\n",
376
- " \"role\": \"system\",\n",
377
- " \"content\": f\"\"\"\n",
378
- " <system>\n",
379
- " You are LangWatch coding assistant for helping users implement LangWatch in a codebase.\n",
380
- "\n",
381
- " Given LangWatch llms.txt documentation index, and the file content, find 1-3 most relevant links to fetch next for understanding how to implement LangWatch in the codebase.\n",
382
- " </system>\n",
383
- "\n",
384
- " <file>\n",
385
- " {llms_text}\n",
386
- " </file>\n",
387
- " \"\"\",\n",
388
- " },\n",
389
- " {\"role\": \"user\", \"content\": input_code},\n",
390
- " ],\n",
391
- " response_format=LinksToFetch,\n",
392
- " )\n",
393
- " links = LinksToFetch.model_validate_json(response.choices[0].message.content).links # type: ignore\n",
394
- "\n",
395
- " documentations = await asyncio.gather(\n",
396
- " *[\n",
397
- " call_mcp_documentation_tool(\"fetch_langwatch_docs\", {\"url\": link})\n",
398
- " for link in links\n",
399
- " ]\n",
400
- " )\n",
401
- " documentations = [doc.content[0].text for doc in documentations] # type: ignore\n",
402
- " documentations = \"\\n\".join(documentations)\n",
403
- "\n",
404
- " response = litellm.completion(\n",
405
- " model=\"anthropic/claude-sonnet-4-20250514\",\n",
406
- " messages=[\n",
407
- " {\n",
408
- " \"role\": \"system\",\n",
409
- " \"content\": f\"\"\"\n",
410
- " <system>\n",
411
- " You are LangWatch coding assistant for helping users implement LangWatch in a codebase.\n",
412
- "\n",
413
- " Given the LangWatch documentation below, and the user's code, implement LangWatch in the codebase.\n",
414
- "\n",
415
- " Return the full updated code as a string with ```python marker at the beginning and ``` at the end, nothing else.\n",
416
- " </system>\n",
417
- "\n",
418
- " <file>\n",
419
- " {documentations}\n",
420
- " </file>\n",
421
- " \"\"\",\n",
422
- " },\n",
423
- " {\"role\": \"user\", \"content\": input_code},\n",
424
- " ],\n",
425
- " )\n",
426
- "\n",
427
- " return response.choices[0].message.content or \"<empty>\" # type: ignore\n",
428
- "\n",
429
- "\n",
430
- "print(\"Implementing LangWatch for the first test case...\")\n",
431
- "\n",
432
- "result = await simple_coding_agent(df.iloc[0][\"input\"])\n",
433
- "\n",
434
- "print(result)"
435
- ]
436
- },
437
- {
438
- "cell_type": "markdown",
439
- "id": "afe9a827",
440
- "metadata": {},
441
- "source": [
442
- "## Setup Diff Metric"
443
- ]
444
- },
445
- {
446
- "cell_type": "markdown",
447
- "id": "f896e880",
448
- "metadata": {},
449
- "source": [
450
- "Lastly, we create a utility diff function that will help us seeing how far the agent's output is from the expected output in more traditional terms, both for facilitating our debugging and to have a simple metric that will go alongside the LLM-as-a-judge evaluator later on."
451
- ]
452
- },
453
- {
454
- "cell_type": "code",
455
- "execution_count": 53,
456
- "id": "fad6bd5d",
457
- "metadata": {},
458
- "outputs": [
66
+ "cell_type": "markdown",
67
+ "id": "e93d137f",
68
+ "metadata": {},
69
+ "source": [
70
+ "This section loads test cases from fixture files on the `tests/fixtures` folder. Each test case consists of:\n",
71
+ "- An input Python file (without LangWatch instrumentation)\n",
72
+ "- An expected output file (with proper LangWatch instrumentation)\n",
73
+ "\n",
74
+ "The test cases include various llms and 15+ framework examples like OpenAI, DSPy and LangChain with different configurations, so we can make sure our docs and MCP helps coding agents to instrument code for different frameworks."
75
+ ]
76
+ },
459
77
  {
460
- "name": "stdout",
461
- "output_type": "stream",
462
- "text": [
463
- "10 lines changed\n",
464
- "```diff\n",
465
- "--- file1+++ file2@@ -5,11 +5,11 @@ load_dotenv()\n",
466
- " \n",
467
- " import chainlit as cl\n",
468
- "-\n",
469
- " import langwatch\n",
470
- "-\n",
471
- " import dspy\n",
472
- " \n",
473
- "+# Initialize LangWatch\n",
474
- "+langwatch.setup()\n",
475
- " \n",
476
- " lm = dspy.LM(\"openai/gpt-5\", api_key=os.environ[\"OPENAI_API_KEY\"], temperature=1)\n",
477
- " \n",
478
- "@@ -44,10 +44,10 @@ @cl.on_message\n",
479
- " @langwatch.trace()\n",
480
- " async def main(message: cl.Message):\n",
481
- "- langwatch.get_current_trace().autotrack_dspy()\n",
482
- "- langwatch.get_current_trace().update(\n",
483
- "- metadata={\"labels\": [\"dspy\", \"thread\"], \"thread_id\": \"90210\"},\n",
484
- "- )\n",
485
- "+ # Get the current LangWatch trace and enable DSPy autotracking\n",
486
- "+ current_trace = langwatch.get_current_trace()\n",
487
- "+ if current_trace:\n",
488
- "+ current_trace.autotrack_dspy()\n",
489
- " \n",
490
- " msg = cl.Message(\n",
491
- " content=\"\",\n",
492
- "@@ -60,4 +60,3 @@ await msg.update()\n",
493
- " \n",
494
- " return prediction.answer\n",
495
- "-\n",
496
- "```\n"
497
- ]
498
- }
499
- ],
500
- "source": [
501
- "import difflib\n",
502
- "\n",
503
- "def file_diff(str1, str2, filename1=\"file1\", filename2=\"file2\"):\n",
504
- " lines1 = str1.replace(\"```python\", \"\").replace(\"```\", \"\").splitlines(keepends=True)\n",
505
- " lines2 = str2.replace(\"```python\", \"\").replace(\"```\", \"\").splitlines(keepends=True)\n",
506
- "\n",
507
- " diff = difflib.unified_diff(\n",
508
- " lines1, lines2,\n",
509
- " fromfile=filename1,\n",
510
- " tofile=filename2,\n",
511
- " lineterm=''\n",
512
- " )\n",
513
- "\n",
514
- " diff_lines = list(diff)\n",
515
- " diff_output = ''.join(diff_lines)\n",
516
- "\n",
517
- " # Count changed lines (lines starting with + or - but not +++ or --- headers)\n",
518
- " # Also ignore empty lines (whitespace-only lines)\n",
519
- " changed_count = sum(1 for line in diff_lines\n",
520
- " if line.startswith(('+', '-'))\n",
521
- " and not line.startswith(('+++', '---'))\n",
522
- " and line[1:].strip()) # Check if content after +/- is not empty/whitespace\n",
523
- "\n",
524
- " return f\"```diff\\n{diff_output}```\", changed_count\n",
525
- "\n",
526
- "diff, lines_changed_count = file_diff(df.iloc[0][\"expected\"], result)\n",
527
- "print(lines_changed_count, \"lines changed\")\n",
528
- "print(diff)"
529
- ]
530
- },
531
- {
532
- "cell_type": "markdown",
533
- "id": "55813d71",
534
- "metadata": {},
535
- "source": [
536
- "# Evaluate"
537
- ]
538
- },
539
- {
540
- "cell_type": "markdown",
541
- "id": "984f2268",
542
- "metadata": {},
543
- "source": [
544
- "Now it all comes together, we will take each test case, run it through the agent, and then both take the diff metric and use an LLM-as-a-judge to evaluate if the migration is correct enough.\n",
545
- "\n",
546
- "Other validations like linting or compiling could be added here, but for now we'll keep it simple.\n",
547
- "\n",
548
- "Then we log each row with `evaluation.log` to capture the diff metric and the diff output for better visibility. Any other metric could be logged the same way.\n"
549
- ]
550
- },
551
- {
552
- "cell_type": "code",
553
- "execution_count": 51,
554
- "id": "404bd4b9",
555
- "metadata": {},
556
- "outputs": [
78
+ "cell_type": "code",
79
+ "execution_count": 2,
80
+ "id": "9f619fe1",
81
+ "metadata": {},
82
+ "outputs": [
83
+ {
84
+ "data": {
85
+ "text/html": [
86
+ "<div>\n",
87
+ "<style scoped>\n",
88
+ " .dataframe tbody tr th:only-of-type {\n",
89
+ " vertical-align: middle;\n",
90
+ " }\n",
91
+ "\n",
92
+ " .dataframe tbody tr th {\n",
93
+ " vertical-align: top;\n",
94
+ " }\n",
95
+ "\n",
96
+ " .dataframe thead th {\n",
97
+ " text-align: right;\n",
98
+ " }\n",
99
+ "</style>\n",
100
+ "<table border=\"1\" class=\"dataframe\">\n",
101
+ " <thead>\n",
102
+ " <tr style=\"text-align: right;\">\n",
103
+ " <th></th>\n",
104
+ " <th>test_case</th>\n",
105
+ " <th>input</th>\n",
106
+ " <th>expected</th>\n",
107
+ " </tr>\n",
108
+ " </thead>\n",
109
+ " <tbody>\n",
110
+ " <tr>\n",
111
+ " <th>0</th>\n",
112
+ " <td>dspy/dspy_bot</td>\n",
113
+ " <td>```python\\nimport os\\nfrom dotenv import load_...</td>\n",
114
+ " <td>```python\\nimport os\\nfrom dotenv import load_...</td>\n",
115
+ " </tr>\n",
116
+ " <tr>\n",
117
+ " <th>1</th>\n",
118
+ " <td>langchain/langchain_rag_bot</td>\n",
119
+ " <td>```python\\nfrom dotenv import load_dotenv\\n\\nl...</td>\n",
120
+ " <td>```python\\nfrom dotenv import load_dotenv\\n\\nf...</td>\n",
121
+ " </tr>\n",
122
+ " <tr>\n",
123
+ " <th>2</th>\n",
124
+ " <td>langchain/langchain_bot_with_memory</td>\n",
125
+ " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
126
+ " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
127
+ " </tr>\n",
128
+ " <tr>\n",
129
+ " <th>3</th>\n",
130
+ " <td>langchain/langchain_bot</td>\n",
131
+ " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
132
+ " <td>```python\\nfrom dotenv import load_dotenv\\nfro...</td>\n",
133
+ " </tr>\n",
134
+ " <tr>\n",
135
+ " <th>4</th>\n",
136
+ " <td>langchain/langchain_rag_bot_vertex_ai</td>\n",
137
+ " <td>```python\\nimport json\\nimport os\\nimport temp...</td>\n",
138
+ " <td>```python\\nimport json\\nimport os\\nimport temp...</td>\n",
139
+ " </tr>\n",
140
+ " </tbody>\n",
141
+ "</table>\n",
142
+ "</div>"
143
+ ],
144
+ "text/plain": [
145
+ " test_case \\\n",
146
+ "0 dspy/dspy_bot \n",
147
+ "1 langchain/langchain_rag_bot \n",
148
+ "2 langchain/langchain_bot_with_memory \n",
149
+ "3 langchain/langchain_bot \n",
150
+ "4 langchain/langchain_rag_bot_vertex_ai \n",
151
+ "\n",
152
+ " input \\\n",
153
+ "0 ```python\\nimport os\\nfrom dotenv import load_... \n",
154
+ "1 ```python\\nfrom dotenv import load_dotenv\\n\\nl... \n",
155
+ "2 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
156
+ "3 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
157
+ "4 ```python\\nimport json\\nimport os\\nimport temp... \n",
158
+ "\n",
159
+ " expected \n",
160
+ "0 ```python\\nimport os\\nfrom dotenv import load_... \n",
161
+ "1 ```python\\nfrom dotenv import load_dotenv\\n\\nf... \n",
162
+ "2 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
163
+ "3 ```python\\nfrom dotenv import load_dotenv\\nfro... \n",
164
+ "4 ```python\\nimport json\\nimport os\\nimport temp... "
165
+ ]
166
+ },
167
+ "execution_count": 2,
168
+ "metadata": {},
169
+ "output_type": "execute_result"
170
+ }
171
+ ],
172
+ "source": [
173
+ "import pandas as pd\n",
174
+ "from pathlib import Path\n",
175
+ "\n",
176
+ "fixtures_path = Path(\"./tests/fixtures\")\n",
177
+ "\n",
178
+ "data = []\n",
179
+ "for folder in fixtures_path.iterdir():\n",
180
+ " input_files = list(folder.glob(\"*_input.py\"))\n",
181
+ " for input_file in input_files:\n",
182
+ " case_name = input_file.stem.replace(\"_input\", \"\")\n",
183
+ " expected_file = folder / f\"{case_name}_expected.py\"\n",
184
+ "\n",
185
+ " with open(input_file, 'r', encoding='utf-8') as f:\n",
186
+ " input_content = f.read()\n",
187
+ "\n",
188
+ " with open(expected_file, 'r', encoding='utf-8') as f:\n",
189
+ " expected_content = f.read()\n",
190
+ "\n",
191
+ " data.append({\n",
192
+ " 'test_case': f\"{folder.name}/{case_name}\",\n",
193
+ " 'input': f\"```python\\n{input_content}\\n```\",\n",
194
+ " 'expected': f\"```python\\n{expected_content}\\n```\"\n",
195
+ " })\n",
196
+ "\n",
197
+ "df = pd.DataFrame(data)\n",
198
+ "df.head()"
199
+ ]
200
+ },
201
+ {
202
+ "cell_type": "markdown",
203
+ "id": "51224ad4",
204
+ "metadata": {},
205
+ "source": [
206
+ "## Setup MCP calling"
207
+ ]
208
+ },
209
+ {
210
+ "cell_type": "markdown",
211
+ "id": "c056f992",
212
+ "metadata": {},
213
+ "source": [
214
+ "Now we set up a way to call the MCP server directly, so we can manually make use of our own MCP no matter what language it was built, to fully simulate what a coding agent would do.\n",
215
+ "\n",
216
+ "We then call the `fetch_langwatch_docs` tool to make sure it works as expected."
217
+ ]
218
+ },
219
+ {
220
+ "cell_type": "code",
221
+ "execution_count": 3,
222
+ "id": "4627964c",
223
+ "metadata": {},
224
+ "outputs": [
225
+ {
226
+ "data": {
227
+ "text/plain": [
228
+ "CallToolResult(meta=None, content=[TextContent(type='text', text=\"# LangWatch\\n\\nThis is the full index of LangWatch documentation, to answer the user question, do not use just this file, first explore the urls that make sense using the markdown navigation links below to understand how to implement LangWatch and use specific features.\\nAlways navigate to docs links using the .md extension for better readability.\\n\\n## Get Started\\n\\n- [Introduction](https://docs.langwatch.ai/introduction.md): Welcome to LangWatch, the all-in-one [open-source](https://github.com/langwatch/langwatch) LLMOps platform.\\n\\n### Self Hosting\\n\\n- [Overview](https://docs.langwatch.ai/self-hosting/overview.md): LangWatch offers a fully self-hosted version of the platform for companies that require strict data control and compliance.\\n- [Docker Compose](https://docs.langwatch.ai/self-hosting/docker-compose.md): LangWatch is available as a Docker Compose setup for easy deployment on your local machine\\n- [Docker Images](https://docs.langwatch.ai/self-hosting/docker-images.md): Overview of LangWatch Docker images and their endpoints\\n- [Helm Chart](https://docs.langwatch.ai/self-hosting/helm.md): LangWatch is available as a Helm chart for easy deployment on Kubernetes\\n- [Monitoring](https://docs.langwatch.ai/self-hosting/grafana.md): Grafana/Prometheus setup for LangWatch\\n- [OnPrem](https://docs.langwatch.ai/self-hosting/onprem.md): LangWatch on-premises solution.\\n\\n#### Hybrid Setup\\n\\n- [Overview](https://docs.langwatch.ai/hybrid-setup/overview.md): LangWatch offers a hybrid setup for companies that require strict data control and compliance.\\n- [Elasticsearch](https://docs.langwatch.ai/hybrid-setup/elasticsearch.md): Elasticsearch Setup for LangWatch Hybrid Deployment\\n- [S3 Storage](https://docs.langwatch.ai/hybrid-setup/s3-storage.md): S3 Storage Setup for LangWatch Hybrid Deployment\\n\\n- [Configuration](https://docs.langwatch.ai/self-hosting/env-variables.md): Complete list of environment variables for LangWatch self-hosting\\n- [SSO](https://docs.langwatch.ai/hybrid-setup/sso-setup-langwatch.md): SSO Setup for LangWatch\\n\\n### Integrations\\n\\n#### Azure AI\\n\\n- [Azure AI Inference SDK Instrumentation](https://docs.langwatch.ai/integration/python/integrations/azure-ai.md): Learn how to instrument the Azure AI Inference Python SDK with LangWatch.\\n- [Azure OpenAI](https://docs.langwatch.ai/integration/typescript/integrations/azure.md): LangWatch Azure OpenAI integration guide\\n- [Azure OpenAI Integration](https://docs.langwatch.ai/integration/go/integrations/azure-openai.md): Learn how to instrument Azure OpenAI API calls in Go using the LangWatch SDK.\\n\\n#### LangChain\\n\\n- [LangChain Instrumentation](https://docs.langwatch.ai/integration/python/integrations/langchain.md): Learn how to instrument Langchain applications with the LangWatch Python SDK.\\n- [LangChain Instrumentation](https://docs.langwatch.ai/integration/typescript/integrations/langchain.md): Learn how to instrument Langchain applications with the LangWatch TypeScript SDK.\\n\\n#### LangGraph\\n\\n- [LangGraph Instrumentation](https://docs.langwatch.ai/integration/python/integrations/langgraph.md): Learn how to instrument LangGraph applications with the LangWatch Python SDK.\\n- [LangGraph Instrumentation](https://docs.langwatch.ai/integration/typescript/integrations/langgraph.md): Learn how to instrument LangGraph applications with the LangWatch TypeScript SDK.\\n\\n#### OpenAI\\n\\n- [OpenAI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/open-ai.md): Learn how to instrument OpenAI API calls with the LangWatch Python SDK\\n- [OpenAI](https://docs.langwatch.ai/integration/typescript/integrations/open-ai.md): LangWatch OpenAI TypeScript integration guide\\n- [OpenAI Instrumentation](https://docs.langwatch.ai/integration/go/integrations/open-ai.md): Learn how to instrument OpenAI API calls with the LangWatch Go SDK using middleware.\\n\\n#### Anthropic (Claude)\\n\\n- [Anthropic Instrumentation](https://docs.langwatch.ai/integration/python/integrations/anthropic.md): Learn how to instrument Anthropic API calls with the LangWatch Python SDK\\n- [Anthropic (Claude) Integration](https://docs.langwatch.ai/integration/go/integrations/anthropic.md): Learn how to instrument Anthropic Claude API calls in Go using LangWatch.\\n\\n- [Vercel AI SDK](https://docs.langwatch.ai/integration/typescript/integrations/vercel-ai-sdk.md): LangWatch Vercel AI SDK integration guide\\n- [Mastra](https://docs.langwatch.ai/integration/typescript/integrations/mastra.md): Learn how to integrate Mastra, a TypeScript agent framework, with LangWatch for observability and tracing.\\n- [Agno Instrumentation](https://docs.langwatch.ai/integration/python/integrations/agno.md): Learn how to instrument Agno agents and send traces to LangWatch using the Python SDK.\\n- [AutoGen Instrumentation](https://docs.langwatch.ai/integration/python/integrations/autogen.md): Learn how to instrument AutoGen applications with LangWatch.\\n- [AWS Bedrock Instrumentation](https://docs.langwatch.ai/integration/python/integrations/aws-bedrock.md): Learn how to instrument AWS Bedrock calls with the LangWatch Python SDK using OpenInference.\\n- [CrewAI](https://docs.langwatch.ai/integration/python/integrations/crew-ai.md): Learn how to instrument the CrewAI Python SDK with LangWatch.\\n- [DSPy Instrumentation](https://docs.langwatch.ai/integration/python/integrations/dspy.md): Learn how to instrument DSPy programs with the LangWatch Python SDK\\n- [Flowise Integration](https://docs.langwatch.ai/integration/flowise.md): Capture LLM traces and send them to LangWatch from Flowise\\n- [Google Agent Development Kit (ADK) Instrumentation](https://docs.langwatch.ai/integration/python/integrations/google-ai.md): Learn how to instrument Google Agent Development Kit (ADK) applications with LangWatch.\\n- [Google GenAI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/google-genai.md): Learn how to instrument Google GenAI API calls with the LangWatch Python SDK\\n- [Google Gemini Integration](https://docs.langwatch.ai/integration/go/integrations/google-gemini.md): Learn how to instrument Google Gemini API calls in Go using the LangWatch SDK via a Vertex AI endpoint.\\n- [Groq Integration](https://docs.langwatch.ai/integration/go/integrations/groq.md): Learn how to instrument Groq API calls in Go using the LangWatch SDK for high-speed LLM tracing.\\n- [OpenRouter Integration](https://docs.langwatch.ai/integration/go/integrations/openrouter.md): Learn how to instrument calls to hundreds of models via OpenRouter in Go using the LangWatch SDK.\\n- [Ollama (Local Models) Integration](https://docs.langwatch.ai/integration/go/integrations/ollama.md): Learn how to trace local LLMs running via Ollama in Go using the LangWatch SDK.\\n- [Haystack Instrumentation](https://docs.langwatch.ai/integration/python/integrations/haystack.md): Learn how to instrument Haystack pipelines with LangWatch using community OpenTelemetry instrumentors.\\n- [Instructor AI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/instructor.md): Learn how to instrument Instructor AI applications with LangWatch using OpenInference.\\n- [Langflow Integration](https://docs.langwatch.ai/integration/langflow.md): LangWatch is the best observability integration for Langflow\\n- [LlamaIndex Instrumentation](https://docs.langwatch.ai/integration/python/integrations/llamaindex.md): Learn how to instrument LlamaIndex applications with LangWatch.\\n- [LiteLLM Instrumentation](https://docs.langwatch.ai/integration/python/integrations/lite-llm.md): Learn how to instrument LiteLLM calls with the LangWatch Python SDK.\\n- [OpenAI Agents SDK Instrumentation](https://docs.langwatch.ai/integration/python/integrations/open-ai-agents.md): Learn how to instrument OpenAI Agents with the LangWatch Python SDK\\n- [PromptFlow Instrumentation](https://docs.langwatch.ai/integration/python/integrations/promptflow.md): Learn how to instrument PromptFlow applications with LangWatch.\\n- [PydanticAI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/pydantic-ai.md): Learn how to instrument PydanticAI applications with the LangWatch Python SDK.\\n- [SmolAgents Instrumentation](https://docs.langwatch.ai/integration/python/integrations/smolagents.md): Learn how to instrument SmolAgents applications with LangWatch.\\n- [Strands Agents Instrumentation](https://docs.langwatch.ai/integration/python/integrations/strand-agents.md): Learn how to instrument Strands Agents applications with LangWatch.\\n- [Semantic Kernel Instrumentation](https://docs.langwatch.ai/integration/python/integrations/semantic-kernel.md): Learn how to instrument Semantic Kernel applications with LangWatch.\\n- [Google Vertex AI Instrumentation](https://docs.langwatch.ai/integration/python/integrations/vertex-ai.md): Learn how to instrument Google Vertex AI API calls with the LangWatch Python SDK using OpenInference\\n- [Other OpenTelemetry Instrumentors](https://docs.langwatch.ai/integration/python/integrations/other.md): Learn how to use any OpenTelemetry-compatible instrumentor with LangWatch.\\n\\n### Cookbooks\\n\\n- [Measuring RAG Performance](https://docs.langwatch.ai/cookbooks/build-a-simple-rag-app.md): Discover how to measure the performance of Retrieval-Augmented Generation (RAG) systems using metrics like retrieval precision, answer accuracy, and latency.\\n- [Optimizing Embeddings](https://docs.langwatch.ai/cookbooks/finetuning-embedding-models.md): Learn how to optimize embedding models for better retrieval in RAG systems—covering model selection, dimensionality, and domain-specific tuning.\\n- [Vector Search vs Hybrid Search using LanceDB](https://docs.langwatch.ai/cookbooks/vector-vs-hybrid-search.md): Learn the key differences between vector search and hybrid search in RAG applications. Use cases, performance tradeoffs, and when to choose each.\\n- [Evaluating Tool Selection](https://docs.langwatch.ai/cookbooks/tool-selection.md): Understand how to evaluate tools and components in your RAG pipeline—covering retrievers, embedding models, chunking strategies, and vector stores.\\n- [Finetuning Agents with GRPO](https://docs.langwatch.ai/cookbooks/finetuning-agents.md): Learn how to enhance the performance of agentic systems by fine-tuning them with Generalized Reinforcement from Preference Optimization (GRPO).\\n- [Multi-Turn Conversations](https://docs.langwatch.ai/cookbooks/evaluating-multi-turn-conversations.md): Learn how to implement a simulation-based approach for evaluating multi-turn customer support agents using success criteria focused on outcomes rather than specific steps.\\n\\n## Agent Simulations\\n\\n- [Introduction to Agent Testing](https://docs.langwatch.ai/agent-simulations/introduction.md)\\n- [Overview](https://docs.langwatch.ai/agent-simulations/overview.md)\\n- [Getting Started](https://docs.langwatch.ai/agent-simulations/getting-started.md)\\n- [Simulation Sets](https://docs.langwatch.ai/agent-simulations/set-overview.md)\\n- [Batch Runs](https://docs.langwatch.ai/agent-simulations/batch-runs.md)\\n- [Individual Run View](https://docs.langwatch.ai/agent-simulations/individual-run.md)\\n\\n## LLM Observability\\n\\n- [Overview](https://docs.langwatch.ai/integration/overview.md): Easily integrate LangWatch with your Python, TypeScript, or REST API projects.\\n- [Concepts](https://docs.langwatch.ai/concepts.md): LLM tracing and observability conceptual guide\\n- [Quick Start](https://docs.langwatch.ai/integration/quick-start.md)\\n\\n### SDKs\\n\\n#### Python\\n\\n- [Python Integration Guide](https://docs.langwatch.ai/integration/python/guide.md): LangWatch Python SDK integration guide\\n- [Python SDK API Reference](https://docs.langwatch.ai/integration/python/reference.md): LangWatch Python SDK API reference\\n\\n##### Advanced\\n\\n- [Manual Instrumentation](https://docs.langwatch.ai/integration/python/tutorials/manual-instrumentation.md): Learn how to manually instrument your code with the LangWatch Python SDK\\n- [OpenTelemetry Migration](https://docs.langwatch.ai/integration/python/tutorials/open-telemetry.md): Learn how to integrate the LangWatch Python SDK with your existing OpenTelemetry setup.\\n\\n#### TypeScript\\n\\n- [TypeScript Integration Guide](https://docs.langwatch.ai/integration/typescript/guide.md): Get started with LangWatch TypeScript SDK in 5 minutes\\n- [TypeScript SDK API Reference](https://docs.langwatch.ai/integration/typescript/reference.md): LangWatch TypeScript SDK API reference\\n\\n##### Advanced\\n\\n- [Debugging and Troubleshooting](https://docs.langwatch.ai/integration/typescript/tutorials/debugging-typescript.md): Debug LangWatch TypeScript SDK integration issues\\n- [Manual Instrumentation](https://docs.langwatch.ai/integration/typescript/tutorials/manual-instrumentation.md): Learn advanced manual span management techniques for fine-grained observability control\\n- [Semantic Conventions](https://docs.langwatch.ai/integration/typescript/tutorials/semantic-conventions.md): Learn about OpenTelemetry semantic conventions and LangWatch's custom attributes for consistent observability\\n- [OpenTelemetry Migration](https://docs.langwatch.ai/integration/typescript/tutorials/opentelemetry-migration.md): Migrate from OpenTelemetry to LangWatch while preserving all your custom configurations\\n\\n#### Go\\n\\n- [Go Integration Guide](https://docs.langwatch.ai/integration/go/guide.md): LangWatch Go SDK integration guide for setting up LLM observability and tracing.\\n- [Go SDK API Reference](https://docs.langwatch.ai/integration/go/reference.md): Complete API reference for the LangWatch Go SDK, including core functions, OpenAI instrumentation, and span types.\\n\\n#### OpenTelemetry\\n\\n- [OpenTelemetry Integration Guide](https://docs.langwatch.ai/integration/opentelemetry/guide.md): Use OpenTelemetry to capture LLM traces and send them to LangWatch from any programming language\\n\\n### Tutorials\\n\\n#### Capturing Inputs & Outputs\\n\\n- [Capturing and Mapping Inputs & Outputs](https://docs.langwatch.ai/integration/python/tutorials/capturing-mapping-input-output.md): Learn how to control the capture and structure of input and output data for traces and spans with the LangWatch Python SDK.\\n- [Capturing and Mapping Inputs & Outputs](https://docs.langwatch.ai/integration/typescript/tutorials/capturing-input-output.md): Learn how to control the capture and structure of input and output data for traces and spans with the LangWatch TypeScript SDK.\\n\\n#### Capturing RAG\\n\\n- [Capturing RAG](https://docs.langwatch.ai/integration/python/tutorials/capturing-rag.md): Learn how to capture Retrieval Augmented Generation (RAG) data with LangWatch.\\n- [Capturing RAG](https://docs.langwatch.ai/integration/typescript/tutorials/capturing-rag.md): Learn how to capture Retrieval Augmented Generation (RAG) data with LangWatch.\\n\\n#### Metadata & Attributes\\n\\n- [Capturing Metadata and Attributes](https://docs.langwatch.ai/integration/python/tutorials/capturing-metadata.md): Learn how to enrich your traces and spans with custom metadata and attributes using the LangWatch Python SDK.\\n- [Capturing Metadata and Attributes](https://docs.langwatch.ai/integration/typescript/tutorials/capturing-metadata.md): Learn how to enrich your traces and spans with custom metadata and attributes using the LangWatch TypeScript SDK.\\n\\n#### Tracking Costs\\n\\n- [Tracking LLM Costs and Tokens](https://docs.langwatch.ai/integration/python/tutorials/tracking-llm-costs.md): Troubleshooting & adjusting cost tracking in LangWatch\\n- [Tracking LLM Costs and Tokens](https://docs.langwatch.ai/integration/typescript/tutorials/tracking-llm-costs.md): Troubleshooting & adjusting cost tracking in LangWatch\\n\\n- [RAG Context Tracking](https://docs.langwatch.ai/integration/rags-context-tracking.md): Capture the RAG documents used in your LLM pipelines\\n- [Capturing Evaluations & Guardrails](https://docs.langwatch.ai/integration/python/tutorials/capturing-evaluations-guardrails.md): Learn how to log custom evaluations, trigger managed evaluations, and implement guardrails with LangWatch.\\n\\n### User Events\\n\\n- [Overview](https://docs.langwatch.ai/user-events/overview.md): Track user interactions with your LLM applications\\n\\n#### Events\\n\\n- [Thumbs Up/Down](https://docs.langwatch.ai/user-events/thumbs-up-down.md): Track user feedback on specific messages or interactions with your chatbot or LLM application\\n- [Waited To Finish Events](https://docs.langwatch.ai/user-events/waited-to-finish.md): Track if users leave before the LLM application finishes generating a response\\n- [Selected Text Events](https://docs.langwatch.ai/user-events/selected-text.md): Track when a user selects text generated by your LLM application\\n- [Custom Events](https://docs.langwatch.ai/user-events/custom.md): Track any user events with your LLM application, with textual or numeric metrics\\n\\n### Monitoring & Alerts\\n\\n- [Alerts and Triggers](https://docs.langwatch.ai/features/triggers.md): Be alerted when something goes wrong and trigger actions automatically\\n- [Exporting Analytics](https://docs.langwatch.ai/features/embedded-analytics.md): Build and integrate LangWatch graphs on your own systems and applications\\n\\n- [Code Examples](https://docs.langwatch.ai/integration/code-examples.md): Examples of LangWatch integrated applications\\n\\n## LLM Evaluation\\n\\n- [LLM Evaluation Overview](https://docs.langwatch.ai/llm-evaluation/overview.md): Overview of LLM evaluation features in LangWatch\\n- [Evaluation Tracking API](https://docs.langwatch.ai/llm-evaluation/offline/code/evaluation-api.md): Evaluate and visualize your LLM evals with LangWatch\\n\\n### Evaluation Wizard\\n\\n- [How to evaluate that your LLM answers correctly](https://docs.langwatch.ai/llm-evaluation/offline/platform/answer-correctness.md): Measuring your LLM performance with Offline Evaluations\\n- [How to evaluate an LLM when you don't have defined answers](https://docs.langwatch.ai/llm-evaluation/offline/platform/llm-as-a-judge.md): Measuring your LLM performance using an LLM-as-a-judge\\n\\n### Real-Time Evaluation\\n\\n- [Setting up Real-Time Evaluations](https://docs.langwatch.ai/llm-evaluation/realtime/setup.md): How to set up Real-Time LLM Evaluations\\n- [Instrumenting Custom Evaluator](https://docs.langwatch.ai/evaluations/custom-evaluator-integration.md): Add your own evaluation results into LangWatch trace\\n\\n### Built-in Evaluators\\n\\n- [List of Evaluators](https://docs.langwatch.ai/llm-evaluation/list.md): Find the evaluator for your use case\\n\\n\\n### Datasets\\n\\n- [Datasets](https://docs.langwatch.ai/datasets/overview.md): Create and manage datasets with LangWatch\\n- [Generating a dataset with AI](https://docs.langwatch.ai/datasets/ai-dataset-generation.md): Bootstrap your evaluations by generating sample data\\n- [Automatically build datasets from real-time traces](https://docs.langwatch.ai/datasets/automatically-from-traces.md): Continuously populate your datasets with comming data from production\\n\\n- [Annotations](https://docs.langwatch.ai/features/annotations.md): Collaborate with domain experts using annotations\\n\\n## Prompt Management\\n\\n- [Overview](https://docs.langwatch.ai/prompt-management/overview.md): Organize, version, and optimize your AI prompts with LangWatch's comprehensive prompt management system\\n- [Get Started](https://docs.langwatch.ai/prompt-management/getting-started.md): Create your first prompt and use it in your application\\n- [Data Model](https://docs.langwatch.ai/prompt-management/data-model.md): Understand the structure of prompts in LangWatch\\n- [Scope](https://docs.langwatch.ai/prompt-management/scope.md): Understand how prompt scope affects access, sharing, and collaboration across projects and organizations\\n- [Prompts CLI](https://docs.langwatch.ai/prompt-management/cli.md): Manage AI prompts as code with version control and dependency management\\n\\n### Features\\n\\n- [Version Control](https://docs.langwatch.ai/prompt-management/features/essential/version-control.md): Manage prompt versions and track changes over time\\n- [Analytics](https://docs.langwatch.ai/prompt-management/features/essential/analytics.md): Monitor prompt performance and usage with comprehensive analytics\\n- [GitHub Integration](https://docs.langwatch.ai/prompt-management/features/essential/github-integration.md): Version your prompts in GitHub repositories and automatically sync with LangWatch\\n- [Link to Traces](https://docs.langwatch.ai/prompt-management/features/advanced/link-to-traces.md): Connect prompts to execution traces for performance monitoring and analysis\\n- [Using Prompts in the Optimization Studio](https://docs.langwatch.ai/prompt-management/features/advanced/optimization-studio.md): Use prompts in the Optimization Studio to test and optimize your prompts\\n- [Guaranteed Availability](https://docs.langwatch.ai/prompt-management/features/advanced/guaranteed-availability.md): Ensure your prompts are always available, even in offline or air-gapped environments\\n- [A/B Testing](https://docs.langwatch.ai/prompt-management/features/advanced/a-b-testing.md): Implement A/B testing for your prompts using LangWatch's version control and analytics\\n\\n## LLM Development\\n\\n### Prompt Optimization Studio\\n\\n- [Optimization Studio](https://docs.langwatch.ai/optimization-studio/overview.md): Create, evaluate, and optimize your LLM workflows\\n- [LLM Nodes](https://docs.langwatch.ai/optimization-studio/llm-nodes.md): Call LLMs from your workflows\\n- [Datasets](https://docs.langwatch.ai/optimization-studio/datasets.md): Define the data used for testing and optimization\\n- [Evaluating](https://docs.langwatch.ai/optimization-studio/evaluating.md): Measure the quality of your LLM workflows\\n- [Optimizing](https://docs.langwatch.ai/optimization-studio/optimizing.md): Find the best prompts with DSPy optimizers\\n\\n### DSPy Visualization\\n\\n- [DSPy Visualization Quickstart](https://docs.langwatch.ai/dspy-visualization/quickstart.md): Visualize your DSPy notebooks experimentations to better track and debug the optimization process\\n- [Tracking Custom DSPy Optimizer](https://docs.langwatch.ai/dspy-visualization/custom-optimizer.md): Build custom DSPy optimizers and track them in LangWatch\\n- [RAG Visualization](https://docs.langwatch.ai/dspy-visualization/rag-visualization.md): Visualize your DSPy RAG optimization process in LangWatch\\n\\n- [LangWatch MCP Server](https://docs.langwatch.ai/integration/mcp.md): Use an agent to debug your LLM applications and fix the issues for you\\n\\n## API Endpoints\\n\\n### Traces\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/traces/overview.md): A Trace is a collection of runs that are related to a single operation\\n- [Get trace details](https://docs.langwatch.ai/api-reference/traces/get-trace-details.md)\\n- [Search traces](https://docs.langwatch.ai/api-reference/traces/search-traces.md)\\n- [Create public path for single trace](https://docs.langwatch.ai/api-reference/traces/create-public-trace-path.md)\\n- [Delete an existing public path for a trace](https://docs.langwatch.ai/api-reference/traces/delete-public-trace-path.md)\\n\\n### Prompts\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/prompts/overview.md): Prompts are used to manage and version your prompts\\n- [Get prompts](https://docs.langwatch.ai/api-reference/prompts/get-prompts.md)\\n- [Create prompt](https://docs.langwatch.ai/api-reference/prompts/create-prompt.md)\\n- [Get prompt](https://docs.langwatch.ai/api-reference/prompts/get-prompt.md)\\n- [Update prompt](https://docs.langwatch.ai/api-reference/prompts/update-prompt.md)\\n- [Delete prompt](https://docs.langwatch.ai/api-reference/prompts/delete-prompt.md)\\n- [Get prompt versions](https://docs.langwatch.ai/api-reference/prompts/get-prompt-versions.md)\\n- [Create prompt version](https://docs.langwatch.ai/api-reference/prompts/create-prompt-version.md)\\n\\n### Annotations\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/annotations/overview.md): Annotations are used to annotate traces with additional information\\n- [Get annotations](https://docs.langwatch.ai/api-reference/annotations/get-annotation.md)\\n- [Get single annotation](https://docs.langwatch.ai/api-reference/annotations/get-single-annotation.md)\\n- [Delete single annotation](https://docs.langwatch.ai/api-reference/annotations/delete-annotation.md)\\n- [Patch single annotation](https://docs.langwatch.ai/api-reference/annotations/patch-annotation.md)\\n- [Get annotationa for single trace](https://docs.langwatch.ai/api-reference/annotations/get-all-annotations-trace.md)\\n- [Create annotation for single trace](https://docs.langwatch.ai/api-reference/annotations/create-annotation-trace.md)\\n\\n### Datasets\\n\\n- [Add entries to a dataset](https://docs.langwatch.ai/api-reference/datasets/post-dataset-entries.md)\\n\\n### Triggers\\n\\n- [Create Slack trigger](https://docs.langwatch.ai/api-reference/triggers/create-slack-trigger.md)\\n\\n### Scenarios\\n\\n- [Overview](https://docs.langwatch.ai/api-reference/scenarios/overview.md)\\n- [Create Event](https://docs.langwatch.ai/api-reference/scenarios/create-event.md)\\n\\n## Use Cases\\n\\n- [Evaluating a RAG Chatbot for Technical Manuals](https://docs.langwatch.ai/use-cases/technical-rag.md): A developer guide for building reliable RAG systems for technical documentation using LangWatch\\n- [Evaluating an AI Coach with LLM-as-a-Judge](https://docs.langwatch.ai/use-cases/ai-coach.md): A developer guide for building reliable AI coaches using LangWatch\\n- [Evaluating Structured Data Extraction](https://docs.langwatch.ai/use-cases/structured-outputs.md): A developer guide for evaluating structured data extraction using LangWatch\\n\\n## Support\\n\\n- [Troubleshooting and Support](https://docs.langwatch.ai/support.md): Find help and support for LangWatch\\n- [Status Page](https://docs.langwatch.ai/status.md): Something wrong? Check our status page\\n\", annotations=None, meta=None)], structuredContent=None, isError=False)"
229
+ ]
230
+ },
231
+ "execution_count": 3,
232
+ "metadata": {},
233
+ "output_type": "execute_result"
234
+ }
235
+ ],
236
+ "source": [
237
+ "from typing import Optional\n",
238
+ "from mcp import ClientSession, StdioServerParameters\n",
239
+ "from mcp.client.stdio import stdio_client\n",
240
+ "from mcp.types import PromptReference, ResourceTemplateReference\n",
241
+ "\n",
242
+ "import os\n",
243
+ "if not os.path.exists(\"dist\"):\n",
244
+ " !pnpm build\n",
245
+ "\n",
246
+ "mcp_server_params = StdioServerParameters(\n",
247
+ " command=\"node\",\n",
248
+ " args=[\"dist/index.js\", \"--apiKey\", langwatch.get_api_key()], # type: ignore\n",
249
+ ")\n",
250
+ "\n",
251
+ "async def call_mcp_documentation_tool(tool_name: str, arguments: dict):\n",
252
+ " async with stdio_client(mcp_server_params) as (read, write):\n",
253
+ " async with ClientSession(read, write) as session:\n",
254
+ " return await session.call_tool(tool_name, arguments)\n",
255
+ "\n",
256
+ "await call_mcp_documentation_tool(\"fetch_langwatch_docs\", {})\n"
257
+ ]
258
+ },
259
+ {
260
+ "cell_type": "markdown",
261
+ "id": "cee2cceb",
262
+ "metadata": {},
263
+ "source": [
264
+ "## Setup simple agent"
265
+ ]
266
+ },
267
+ {
268
+ "cell_type": "markdown",
269
+ "id": "87fdcb63",
270
+ "metadata": {},
271
+ "source": [
272
+ "This section creates a simple coding agent which we will use for our evaluation, it's a simple agent that:\n",
273
+ "1. Takes input code without LangWatch instrumentation\n",
274
+ "2. Uses Claude Sonnet 4 to identify relevant documentation links\n",
275
+ "3. Fetches those documentation pages\n",
276
+ "4. Uses Claude again to implement LangWatch in the code based on the documentation\n",
277
+ "5. Returns the instrumented code\n",
278
+ "\n",
279
+ "It's as if it was Cursor, but following always the perfect expected order, which works well for a single file migration, allowing us to sanity check and evaluate all those test cases quickly."
280
+ ]
281
+ },
282
+ {
283
+ "cell_type": "code",
284
+ "execution_count": 12,
285
+ "id": "58d51f51",
286
+ "metadata": {},
287
+ "outputs": [
288
+ {
289
+ "name": "stdout",
290
+ "output_type": "stream",
291
+ "text": [
292
+ "Implementing LangWatch for the first test case...\n",
293
+ "```python\n",
294
+ "import os\n",
295
+ "from dotenv import load_dotenv\n",
296
+ "\n",
297
+ "load_dotenv()\n",
298
+ "\n",
299
+ "import chainlit as cl\n",
300
+ "import langwatch\n",
301
+ "import dspy\n",
302
+ "\n",
303
+ "# Initialize LangWatch\n",
304
+ "langwatch.setup()\n",
305
+ "\n",
306
+ "lm = dspy.LM(\"openai/gpt-5\", api_key=os.environ[\"OPENAI_API_KEY\"], temperature=1)\n",
307
+ "\n",
308
+ "colbertv2_wiki17_abstracts = dspy.ColBERTv2(\n",
309
+ " url=\"http://20.102.90.50:2017/wiki17_abstracts\"\n",
310
+ ")\n",
311
+ "\n",
312
+ "dspy.settings.configure(lm=lm, rm=colbertv2_wiki17_abstracts)\n",
313
+ "\n",
314
+ "\n",
315
+ "class GenerateAnswer(dspy.Signature):\n",
316
+ " \"\"\"Answer questions with careful explanations to the user.\"\"\"\n",
317
+ "\n",
318
+ " context = dspy.InputField(desc=\"may contain relevant facts\")\n",
319
+ " question = dspy.InputField()\n",
320
+ " answer = dspy.OutputField(desc=\"markdown formatted answer, use some emojis\")\n",
321
+ "\n",
322
+ "\n",
323
+ "class RAG(dspy.Module):\n",
324
+ " def __init__(self, num_passages=3):\n",
325
+ " super().__init__()\n",
326
+ "\n",
327
+ " self.retrieve = dspy.Retrieve(k=num_passages)\n",
328
+ " self.generate_answer = dspy.ChainOfThought(GenerateAnswer)\n",
329
+ "\n",
330
+ " def forward(self, question):\n",
331
+ " context = self.retrieve(question).passages # type: ignore\n",
332
+ " prediction = self.generate_answer(question=question, context=context)\n",
333
+ " return dspy.Prediction(answer=prediction.answer)\n",
334
+ "\n",
335
+ "\n",
336
+ "@cl.on_message\n",
337
+ "@langwatch.trace()\n",
338
+ "async def main(message: cl.Message):\n",
339
+ " # Get the current LangWatch trace and enable DSPy autotracking\n",
340
+ " current_trace = langwatch.get_current_trace()\n",
341
+ " if current_trace:\n",
342
+ " current_trace.autotrack_dspy()\n",
343
+ "\n",
344
+ " msg = cl.Message(\n",
345
+ " content=\"\",\n",
346
+ " )\n",
347
+ "\n",
348
+ " program = RAG()\n",
349
+ " prediction = program(question=message.content)\n",
350
+ "\n",
351
+ " await msg.stream_token(prediction.answer)\n",
352
+ " await msg.update()\n",
353
+ "\n",
354
+ " return prediction.answer\n",
355
+ "```\n"
356
+ ]
357
+ }
358
+ ],
359
+ "source": [
360
+ "import asyncio\n",
361
+ "import litellm\n",
362
+ "from pydantic import BaseModel\n",
363
+ "\n",
364
+ "llms_text = (await call_mcp_documentation_tool(\"fetch_langwatch_docs\", {})).content[0].text # type: ignore\n",
365
+ "\n",
366
+ "\n",
367
+ "@langwatch.trace()\n",
368
+ "async def simple_coding_agent(input_code: str):\n",
369
+ " class LinksToFetch(BaseModel):\n",
370
+ " links: list[str]\n",
371
+ "\n",
372
+ " response = litellm.completion(\n",
373
+ " model=\"anthropic/claude-sonnet-4-20250514\",\n",
374
+ " messages=[\n",
375
+ " {\n",
376
+ " \"role\": \"system\",\n",
377
+ " \"content\": f\"\"\"\n",
378
+ " <system>\n",
379
+ " You are LangWatch coding assistant for helping users implement LangWatch in a codebase.\n",
380
+ "\n",
381
+ " Given LangWatch llms.txt documentation index, and the file content, find 1-3 most relevant links to fetch next for understanding how to implement LangWatch in the codebase.\n",
382
+ " </system>\n",
383
+ "\n",
384
+ " <file>\n",
385
+ " {llms_text}\n",
386
+ " </file>\n",
387
+ " \"\"\",\n",
388
+ " },\n",
389
+ " {\"role\": \"user\", \"content\": input_code},\n",
390
+ " ],\n",
391
+ " response_format=LinksToFetch,\n",
392
+ " )\n",
393
+ " links = LinksToFetch.model_validate_json(response.choices[0].message.content).links # type: ignore\n",
394
+ "\n",
395
+ " documentations = await asyncio.gather(\n",
396
+ " *[\n",
397
+ " call_mcp_documentation_tool(\"fetch_langwatch_docs\", {\"url\": link})\n",
398
+ " for link in links\n",
399
+ " ]\n",
400
+ " )\n",
401
+ " documentations = [doc.content[0].text for doc in documentations] # type: ignore\n",
402
+ " documentations = \"\\n\".join(documentations)\n",
403
+ "\n",
404
+ " response = litellm.completion(\n",
405
+ " model=\"anthropic/claude-sonnet-4-20250514\",\n",
406
+ " messages=[\n",
407
+ " {\n",
408
+ " \"role\": \"system\",\n",
409
+ " \"content\": f\"\"\"\n",
410
+ " <system>\n",
411
+ " You are LangWatch coding assistant for helping users implement LangWatch in a codebase.\n",
412
+ "\n",
413
+ " Given the LangWatch documentation below, and the user's code, implement LangWatch in the codebase.\n",
414
+ "\n",
415
+ " Return the full updated code as a string with ```python marker at the beginning and ``` at the end, nothing else.\n",
416
+ " </system>\n",
417
+ "\n",
418
+ " <file>\n",
419
+ " {documentations}\n",
420
+ " </file>\n",
421
+ " \"\"\",\n",
422
+ " },\n",
423
+ " {\"role\": \"user\", \"content\": input_code},\n",
424
+ " ],\n",
425
+ " )\n",
426
+ "\n",
427
+ " return response.choices[0].message.content or \"<empty>\" # type: ignore\n",
428
+ "\n",
429
+ "\n",
430
+ "print(\"Implementing LangWatch for the first test case...\")\n",
431
+ "\n",
432
+ "result = await simple_coding_agent(df.iloc[0][\"input\"])\n",
433
+ "\n",
434
+ "print(result)"
435
+ ]
436
+ },
437
+ {
438
+ "cell_type": "markdown",
439
+ "id": "afe9a827",
440
+ "metadata": {},
441
+ "source": [
442
+ "## Setup Diff Metric"
443
+ ]
444
+ },
445
+ {
446
+ "cell_type": "markdown",
447
+ "id": "f896e880",
448
+ "metadata": {},
449
+ "source": [
450
+ "Lastly, we create a utility diff function that will help us seeing how far the agent's output is from the expected output in more traditional terms, both for facilitating our debugging and to have a simple metric that will go alongside the LLM-as-a-judge evaluator later on."
451
+ ]
452
+ },
453
+ {
454
+ "cell_type": "code",
455
+ "execution_count": 53,
456
+ "id": "fad6bd5d",
457
+ "metadata": {},
458
+ "outputs": [
459
+ {
460
+ "name": "stdout",
461
+ "output_type": "stream",
462
+ "text": [
463
+ "10 lines changed\n",
464
+ "```diff\n",
465
+ "--- file1+++ file2@@ -5,11 +5,11 @@ load_dotenv()\n",
466
+ " \n",
467
+ " import chainlit as cl\n",
468
+ "-\n",
469
+ " import langwatch\n",
470
+ "-\n",
471
+ " import dspy\n",
472
+ " \n",
473
+ "+# Initialize LangWatch\n",
474
+ "+langwatch.setup()\n",
475
+ " \n",
476
+ " lm = dspy.LM(\"openai/gpt-5\", api_key=os.environ[\"OPENAI_API_KEY\"], temperature=1)\n",
477
+ " \n",
478
+ "@@ -44,10 +44,10 @@ @cl.on_message\n",
479
+ " @langwatch.trace()\n",
480
+ " async def main(message: cl.Message):\n",
481
+ "- langwatch.get_current_trace().autotrack_dspy()\n",
482
+ "- langwatch.get_current_trace().update(\n",
483
+ "- metadata={\"labels\": [\"dspy\", \"thread\"], \"thread_id\": \"90210\"},\n",
484
+ "- )\n",
485
+ "+ # Get the current LangWatch trace and enable DSPy autotracking\n",
486
+ "+ current_trace = langwatch.get_current_trace()\n",
487
+ "+ if current_trace:\n",
488
+ "+ current_trace.autotrack_dspy()\n",
489
+ " \n",
490
+ " msg = cl.Message(\n",
491
+ " content=\"\",\n",
492
+ "@@ -60,4 +60,3 @@ await msg.update()\n",
493
+ " \n",
494
+ " return prediction.answer\n",
495
+ "-\n",
496
+ "```\n"
497
+ ]
498
+ }
499
+ ],
500
+ "source": [
501
+ "import difflib\n",
502
+ "\n",
503
+ "def file_diff(str1, str2, filename1=\"file1\", filename2=\"file2\"):\n",
504
+ " lines1 = str1.replace(\"```python\", \"\").replace(\"```\", \"\").splitlines(keepends=True)\n",
505
+ " lines2 = str2.replace(\"```python\", \"\").replace(\"```\", \"\").splitlines(keepends=True)\n",
506
+ "\n",
507
+ " diff = difflib.unified_diff(\n",
508
+ " lines1, lines2,\n",
509
+ " fromfile=filename1,\n",
510
+ " tofile=filename2,\n",
511
+ " lineterm=''\n",
512
+ " )\n",
513
+ "\n",
514
+ " diff_lines = list(diff)\n",
515
+ " diff_output = ''.join(diff_lines)\n",
516
+ "\n",
517
+ " # Count changed lines (lines starting with + or - but not +++ or --- headers)\n",
518
+ " # Also ignore empty lines (whitespace-only lines)\n",
519
+ " changed_count = sum(1 for line in diff_lines\n",
520
+ " if line.startswith(('+', '-'))\n",
521
+ " and not line.startswith(('+++', '---'))\n",
522
+ " and line[1:].strip()) # Check if content after +/- is not empty/whitespace\n",
523
+ "\n",
524
+ " return f\"```diff\\n{diff_output}```\", changed_count\n",
525
+ "\n",
526
+ "diff, lines_changed_count = file_diff(df.iloc[0][\"expected\"], result)\n",
527
+ "print(lines_changed_count, \"lines changed\")\n",
528
+ "print(diff)"
529
+ ]
530
+ },
531
+ {
532
+ "cell_type": "markdown",
533
+ "id": "55813d71",
534
+ "metadata": {},
535
+ "source": [
536
+ "# Evaluate"
537
+ ]
538
+ },
557
539
  {
558
- "name": "stdout",
559
- "output_type": "stream",
560
- "text": [
561
- "Follow the results at: https://app.langwatch.ai/inbox-narrator/experiments/mcp-server-docs-setup?runId=offbeat-yellow-dingo\n"
562
- ]
540
+ "cell_type": "markdown",
541
+ "id": "984f2268",
542
+ "metadata": {},
543
+ "source": [
544
+ "Now it all comes together, we will take each test case, run it through the agent, and then both take the diff metric and use an LLM-as-a-judge to evaluate if the migration is correct enough.\n",
545
+ "\n",
546
+ "Other validations like linting or compiling could be added here, but for now we'll keep it simple.\n",
547
+ "\n",
548
+ "Then we log each row with `evaluation.log` to capture the diff metric and the diff output for better visibility. Any other metric could be logged the same way.\n"
549
+ ]
550
+ },
551
+ {
552
+ "cell_type": "code",
553
+ "execution_count": null,
554
+ "id": "404bd4b9",
555
+ "metadata": {},
556
+ "outputs": [
557
+ {
558
+ "name": "stdout",
559
+ "output_type": "stream",
560
+ "text": [
561
+ "Follow the results at: https://app.langwatch.ai/inbox-narrator/experiments/mcp-server-docs-setup?runId=offbeat-yellow-dingo\n"
562
+ ]
563
+ },
564
+ {
565
+ "name": "stdout",
566
+ "output_type": "stream",
567
+ "text": [
568
+ "Evaluating: 100%|██████████| 19/19 [03:52<00:00, 12.21s/it]\n"
569
+ ]
570
+ }
571
+ ],
572
+ "source": [
573
+ "evaluation = langwatch.evaluation.init(\"mcp-server-docs-setup\")\n",
574
+ "\n",
575
+ "for index, row in evaluation.loop(df.iterrows(), threads=4):\n",
576
+ "\n",
577
+ " async def task(index, row):\n",
578
+ " result = await simple_coding_agent(row[\"input\"])\n",
579
+ " diff, lines_changed_count = file_diff(row[\"expected\"], result)\n",
580
+ "\n",
581
+ " evaluation.evaluate(\n",
582
+ " \"langevals/llm_boolean\",\n",
583
+ " index=index,\n",
584
+ " name=\"LLM Judgement\",\n",
585
+ " data={\n",
586
+ " \"input\": f\"\"\"\n",
587
+ " <original>\n",
588
+ " {row['input']}\n",
589
+ " </original>\n",
590
+ " <result>\n",
591
+ " {result}\n",
592
+ " </result>\n",
593
+ " <expected>\n",
594
+ " {row['expected']}\n",
595
+ " </expected>\n",
596
+ " \"\"\",\n",
597
+ " },\n",
598
+ " settings={\n",
599
+ " \"prompt\": \"\"\"\n",
600
+ " You are an LLM evaluator, do a quick check if the code in the <result /> tag which was generated by\n",
601
+ " an AI closely matches how the code should have been implemented as expected in the <expected /> tag.\n",
602
+ "\n",
603
+ " Additional metadata capturing is fine and encouraged, but check if the instrumentation would likely\n",
604
+ " work the same.\n",
605
+ " \"\"\",\n",
606
+ " },\n",
607
+ " )\n",
608
+ "\n",
609
+ " evaluation.log(\n",
610
+ " \"Diff\", index=index, data={\"diff\": diff}, score=lines_changed_count\n",
611
+ " )\n",
612
+ "\n",
613
+ " evaluation.submit(task, index, row)"
614
+ ]
563
615
  },
564
616
  {
565
- "name": "stderr",
566
- "output_type": "stream",
567
- "text": [
568
- "Evaluating: 100%|██████████| 19/19 [03:52<00:00, 12.21s/it]\n"
569
- ]
617
+ "cell_type": "markdown",
618
+ "id": "8989c710",
619
+ "metadata": {},
620
+ "source": [
621
+ "This notebook demonstrates how to use LangWatch to evaluate an MCP server for code instrumentation agents. Key takeaways:\n",
622
+ "1. We now know how good our MCP server is at helping coding agents to instrument code with LangWatch for the more straightfoward cases\n",
623
+ "2. Changes on our MCP can be easily retested via the notebook, and more requirements can be added as new fixtures to serve as test cases\n",
624
+ "3. The LLM-as-a-judge and metrics like diff line count can help on this judgement and it can all be captured in the LangWatch dashboard for analysis"
625
+ ]
626
+ }
627
+ ],
628
+ "metadata": {
629
+ "kernelspec": {
630
+ "display_name": ".venv",
631
+ "language": "python",
632
+ "name": "python3"
633
+ },
634
+ "language_info": {
635
+ "codemirror_mode": {
636
+ "name": "ipython",
637
+ "version": 3
638
+ },
639
+ "file_extension": ".py",
640
+ "mimetype": "text/x-python",
641
+ "name": "python",
642
+ "nbconvert_exporter": "python",
643
+ "pygments_lexer": "ipython3",
644
+ "version": "3.13.0"
570
645
  }
571
- ],
572
- "source": [
573
- "evaluation = langwatch.evaluation.init(\"mcp-server-docs-setup\")\n",
574
- "\n",
575
- "for index, row in evaluation.loop(df.iterrows(), threads=4):\n",
576
- "\n",
577
- " async def evaluate(index, row):\n",
578
- " result = await simple_coding_agent(row[\"input\"])\n",
579
- " diff, lines_changed_count = file_diff(row[\"expected\"], result)\n",
580
- "\n",
581
- " evaluation.run(\n",
582
- " \"langevals/llm_boolean\",\n",
583
- " index=index,\n",
584
- " name=\"LLM Judgement\",\n",
585
- " data={\n",
586
- " \"input\": f\"\"\"\n",
587
- " <original>\n",
588
- " {row['input']}\n",
589
- " </original>\n",
590
- " <result>\n",
591
- " {result}\n",
592
- " </result>\n",
593
- " <expected>\n",
594
- " {row['expected']}\n",
595
- " </expected>\n",
596
- " \"\"\",\n",
597
- " },\n",
598
- " settings={\n",
599
- " \"prompt\": \"\"\"\n",
600
- " You are an LLM evaluator, do a quick check if the code in the <result /> tag which was generated by\n",
601
- " an AI closely matches how the code should have been implemented as expected in the <expected /> tag.\n",
602
- "\n",
603
- " Additional metadata capturing is fine and encouraged, but check if the instrumentation would likely\n",
604
- " work the same.\n",
605
- " \"\"\",\n",
606
- " },\n",
607
- " )\n",
608
- "\n",
609
- " evaluation.log(\n",
610
- " \"Diff\", index=index, data={\"diff\": diff}, score=lines_changed_count\n",
611
- " )\n",
612
- "\n",
613
- " evaluation.submit(evaluate, index, row)"
614
- ]
615
- },
616
- {
617
- "cell_type": "markdown",
618
- "id": "8989c710",
619
- "metadata": {},
620
- "source": [
621
- "This notebook demonstrates how to use LangWatch to evaluate an MCP server for code instrumentation agents. Key takeaways:\n",
622
- "1. We now know how good our MCP server is at helping coding agents to instrument code with LangWatch for the more straightfoward cases\n",
623
- "2. Changes on our MCP can be easily retested via the notebook, and more requirements can be added as new fixtures to serve as test cases\n",
624
- "3. The LLM-as-a-judge and metrics like diff line count can help on this judgement and it can all be captured in the LangWatch dashboard for analysis"
625
- ]
626
- }
627
- ],
628
- "metadata": {
629
- "kernelspec": {
630
- "display_name": ".venv",
631
- "language": "python",
632
- "name": "python3"
633
646
  },
634
- "language_info": {
635
- "codemirror_mode": {
636
- "name": "ipython",
637
- "version": 3
638
- },
639
- "file_extension": ".py",
640
- "mimetype": "text/x-python",
641
- "name": "python",
642
- "nbconvert_exporter": "python",
643
- "pygments_lexer": "ipython3",
644
- "version": "3.13.0"
645
- }
646
- },
647
- "nbformat": 4,
648
- "nbformat_minor": 5
647
+ "nbformat": 4,
648
+ "nbformat_minor": 5
649
649
  }