@langwatch/mcp-server 0.7.0 → 0.9.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.
- package/.release-please-shim +1 -0
- package/CHANGELOG.md +87 -0
- package/LICENSE +7 -0
- package/dist/archive-project-HZBRPR2S.js +19 -0
- package/dist/{archive-scenario-WJ2A7ETN.js → archive-scenario-P5RRITRM.js} +4 -4
- package/dist/{archive-suite-4JOM4SSL.js → archive-suite-NUUFD2EM.js} +4 -4
- package/dist/{assign-prompt-tag-GL7EAAF3.js → assign-prompt-tag-FKCCZPML.js} +3 -3
- package/dist/{chunk-2WPLXEKF.js → chunk-42ZHHHIJ.js} +20 -5
- package/dist/chunk-ADSJ2FDA.js +44 -0
- package/dist/{chunk-IE4M5OGE.js → chunk-BB7EOKHR.js} +2 -2
- package/dist/chunk-BBJ5WAJB.js +24 -0
- package/dist/{chunk-EGH5RPXM.js → chunk-BYWYM2RP.js} +2 -2
- package/dist/{chunk-2GT7IFWK.js → chunk-CCM4ZFGF.js} +2 -2
- package/dist/{chunk-LUMEZEHL.js → chunk-CHKCEZBP.js} +2 -2
- package/dist/{chunk-ZVS4UKN2.js → chunk-HKY3GW45.js} +2 -2
- package/dist/{chunk-EUQDVOSU.js → chunk-JHOSVOHT.js} +2 -2
- package/dist/{chunk-E5JYYU3J.js → chunk-JVLJKQJG.js} +669 -94
- package/dist/{chunk-BWWY5KEF.js → chunk-KOO5733S.js} +3 -2
- package/dist/{chunk-HYMIWO3U.js → chunk-R7C7OUVG.js} +2 -2
- package/dist/{chunk-WQG2DFHX.js → chunk-TROIWSEQ.js} +2 -2
- package/dist/{chunk-CCWCIJJ3.js → chunk-X2SEURT2.js} +2 -2
- package/dist/{chunk-4AUB2BIA.js → chunk-XC62KJIT.js} +3 -3
- package/dist/config.js +1 -1
- package/dist/{create-agent-MBOOT3XK.js → create-agent-K5Q7BFGZ.js} +4 -4
- package/dist/{create-annotation-XMV6A7ED.js → create-annotation-KN3GE3DK.js} +4 -4
- package/dist/create-api-key-OQI5PUNQ.js +26 -0
- package/dist/{create-dashboard-VRKLFVZJ.js → create-dashboard-G4QA5AXP.js} +4 -4
- package/dist/{create-dataset-7HQPZCRE.js → create-dataset-WQSC37N7.js} +4 -4
- package/dist/{create-dataset-records-2NIVFYTV.js → create-dataset-records-B4RL3FLC.js} +4 -4
- package/dist/{create-evaluator-WYFRFLRC.js → create-evaluator-YFFQIR7E.js} +4 -4
- package/dist/create-mcp-server.js +3 -2
- package/dist/create-project-CUVQ67VN.js +44 -0
- package/dist/{create-prompt-IEN7O6JT.js → create-prompt-NGXKSP4X.js} +3 -3
- package/dist/{create-prompt-tag-CAEZ45VO.js → create-prompt-tag-IUKYPVHH.js} +3 -3
- package/dist/{create-scenario-6YHSMGLP.js → create-scenario-FNBXALH3.js} +4 -4
- package/dist/{create-suite-H5XOFDE5.js → create-suite-DJEPD4ZB.js} +4 -4
- package/dist/{delete-agent-JKTNBWAA.js → delete-agent-TJI5XBBM.js} +4 -4
- package/dist/{delete-annotation-ACMDV6QO.js → delete-annotation-KRP53TUU.js} +4 -4
- package/dist/{delete-dashboard-VJSR7CRU.js → delete-dashboard-N5SZJIR3.js} +4 -4
- package/dist/{delete-dataset-RTTTWP4D.js → delete-dataset-KDUOHL2P.js} +4 -4
- package/dist/{delete-dataset-records-KNQTIPQK.js → delete-dataset-records-DM4W3PAW.js} +4 -4
- package/dist/{delete-evaluator-7FVC5WM4.js → delete-evaluator-7ZATLJOA.js} +4 -4
- package/dist/{delete-prompt-tag-ZMZUAGFW.js → delete-prompt-tag-I6HNMSVJ.js} +3 -3
- package/dist/{delete-workflow-EYQ3T4RQ.js → delete-workflow-QEO74JQR.js} +4 -4
- package/dist/{get-agent-E3QSTVKG.js → get-agent-3KDWCP5N.js} +4 -4
- package/dist/{get-analytics-2OHV763I.js → get-analytics-GPVJX7SF.js} +3 -3
- package/dist/{get-dashboard-PC7JDHH6.js → get-dashboard-YPTIE5YY.js} +4 -4
- package/dist/{get-dataset-H5IK5FVU.js → get-dataset-6DQFYITM.js} +4 -4
- package/dist/{get-evaluator-UWVUPYTM.js → get-evaluator-PCM6XQAU.js} +4 -4
- package/dist/get-project-JCMWXVLU.js +26 -0
- package/dist/{get-prompt-WZUOLLQC.js → get-prompt-5XAGWWBG.js} +3 -3
- package/dist/{get-scenario-Q6LCNUYN.js → get-scenario-7XBCDZWX.js} +4 -4
- package/dist/{get-simulation-run-Z2XKO256.js → get-simulation-run-AV24FJWI.js} +4 -4
- package/dist/{get-suite-BXK5TN7P.js → get-suite-4DBVHFEM.js} +4 -4
- package/dist/{get-trace-4EJAYVBG.js → get-trace-MRBDS3HJ.js} +3 -3
- package/dist/{get-workflow-O34QJLHD.js → get-workflow-UR4Y6UFX.js} +4 -4
- package/dist/{http-server-ISHF7NJX.js → http-server-DEGNV5EP.js} +4 -3
- package/dist/index.js +1453 -431
- package/dist/{langwatch-api-annotations-ERBG27RF.js → langwatch-api-annotations-ZJDRB4JH.js} +4 -4
- package/dist/{langwatch-api-dashboards-G6TR7VVO.js → langwatch-api-dashboards-WARLI6NF.js} +4 -4
- package/dist/{langwatch-api-monitors-WSXZLS2B.js → langwatch-api-monitors-4XKXHYCG.js} +3 -3
- package/dist/{langwatch-api-secrets-RR5DKG2X.js → langwatch-api-secrets-6SHK5G7Q.js} +3 -3
- package/dist/{langwatch-api-triggers-2RTNSWQY.js → langwatch-api-triggers-5SX6R2WU.js} +3 -3
- package/dist/langwatch-api-workflows-NLJENNXE.js +15 -0
- package/dist/{list-agents-AW3P6FJV.js → list-agents-NECO7MPI.js} +4 -4
- package/dist/{list-annotations-QNCGWPQ3.js → list-annotations-3OJEO774.js} +4 -4
- package/dist/list-api-keys-AWW7ROLB.js +37 -0
- package/dist/{list-dashboards-R7RK2IXL.js → list-dashboards-DVPVVVKW.js} +4 -4
- package/dist/{list-dataset-records-WVCSQP7P.js → list-dataset-records-I4BYORF5.js} +4 -4
- package/dist/{list-datasets-KEXRLDEU.js → list-datasets-WUAE5HGX.js} +4 -4
- package/dist/{list-evaluators-7R2LB4JH.js → list-evaluators-B6OSVAM2.js} +4 -4
- package/dist/{list-model-providers-OBYJCKBX.js → list-model-providers-NL6IP4UZ.js} +4 -4
- package/dist/list-projects-5FHMJ4PQ.js +42 -0
- package/dist/{list-prompt-tags-6LY3ZPYI.js → list-prompt-tags-Z2DD6FLQ.js} +3 -3
- package/dist/{list-prompts-VWEZ4CDE.js → list-prompts-VNXKHK7T.js} +3 -3
- package/dist/{list-scenarios-TXD4W2ZJ.js → list-scenarios-CFZHXL76.js} +4 -4
- package/dist/{list-simulation-runs-RHPOLMFI.js → list-simulation-runs-AM2BXLBW.js} +4 -4
- package/dist/{list-suites-FSGBX27Z.js → list-suites-ZDOHAAXF.js} +4 -4
- package/dist/{list-workflows-VRGEZ3EN.js → list-workflows-WBRBKLIT.js} +4 -4
- package/dist/{rename-prompt-tag-VOJJLX4M.js → rename-prompt-tag-A4RJUK7Z.js} +3 -3
- package/dist/revoke-api-key-ZSPSPF5G.js +15 -0
- package/dist/{run-agent-KTCC7TB7.js → run-agent-JFNDY7MR.js} +4 -4
- package/dist/{run-suite-BTMHGI2D.js → run-suite-TH7LO5TJ.js} +4 -4
- package/dist/{run-workflow-IGAYGKJL.js → run-workflow-CK3JP5U2.js} +4 -4
- package/dist/{search-traces-VYFUIMXH.js → search-traces-3BBVYPC3.js} +3 -3
- package/dist/{set-model-provider-W5IUI326.js → set-model-provider-WOC5FNMV.js} +4 -4
- package/dist/{update-agent-4BB7EYLR.js → update-agent-YMEV5MTL.js} +4 -4
- package/dist/{update-dataset-CXBKZ4W3.js → update-dataset-EYT5POFM.js} +4 -4
- package/dist/{update-dataset-record-HOHAMHXG.js → update-dataset-record-VFF5JTX4.js} +4 -4
- package/dist/{update-evaluator-IVOR6FTR.js → update-evaluator-6IJHFG2E.js} +4 -4
- package/dist/update-project-OIT4WPFI.js +24 -0
- package/dist/{update-prompt-OWQAKE7K.js → update-prompt-ZU2DD6KM.js} +3 -3
- package/dist/{update-scenario-GDFVILPN.js → update-scenario-3VUTPDRU.js} +4 -4
- package/dist/{update-suite-BXYUYSPT.js → update-suite-C6JFDQHL.js} +4 -4
- package/package.json +7 -7
- package/pnpm-workspace.yaml +2 -0
- package/pyproject.toml +3 -0
- package/src/__tests__/all-tools.integration.test.ts +9 -0
- package/src/__tests__/datasets.integration.test.ts +17 -0
- package/src/__tests__/datasets.unit.test.ts +4 -0
- package/src/__tests__/experiment-list-tools.unit.test.ts +157 -0
- package/src/__tests__/get-experiment-results.unit.test.ts +222 -0
- package/src/__tests__/project-api-key-tools.unit.test.ts +451 -0
- package/src/__tests__/scenario-tools.unit.test.ts +3 -0
- package/src/config.ts +2 -0
- package/src/create-mcp-server.ts +257 -13
- package/src/langwatch-api-api-keys.ts +54 -0
- package/src/langwatch-api-projects.ts +82 -0
- package/src/langwatch-api.ts +22 -4
- package/src/tools/archive-project.ts +14 -0
- package/src/tools/create-api-key.ts +29 -0
- package/src/tools/create-project.ts +45 -0
- package/src/tools/get-experiment-results.ts +273 -0
- package/src/tools/get-project.ts +20 -0
- package/src/tools/list-api-keys.ts +33 -0
- package/src/tools/list-experiment-runs.ts +142 -0
- package/src/tools/list-experiments.ts +95 -0
- package/src/tools/list-projects.ts +41 -0
- package/src/tools/revoke-api-key.ts +9 -0
- package/src/tools/{run-evaluation.ts → run-experiment.ts} +5 -5
- package/src/tools/update-project.ts +22 -0
- package/uv.lock +192 -530
- package/Dockerfile +0 -22
- package/build.js +0 -12
- package/dist/archive-scenario-WJ2A7ETN.js.map +0 -1
- package/dist/archive-suite-4JOM4SSL.js.map +0 -1
- package/dist/assign-prompt-tag-GL7EAAF3.js.map +0 -1
- package/dist/chunk-2GT7IFWK.js.map +0 -1
- package/dist/chunk-2WPLXEKF.js.map +0 -1
- package/dist/chunk-4AUB2BIA.js.map +0 -1
- package/dist/chunk-BWWY5KEF.js.map +0 -1
- package/dist/chunk-CCWCIJJ3.js.map +0 -1
- package/dist/chunk-E5JYYU3J.js.map +0 -1
- package/dist/chunk-EGH5RPXM.js.map +0 -1
- package/dist/chunk-EUQDVOSU.js.map +0 -1
- package/dist/chunk-HYMIWO3U.js.map +0 -1
- package/dist/chunk-IE4M5OGE.js.map +0 -1
- package/dist/chunk-LUMEZEHL.js.map +0 -1
- package/dist/chunk-NUFPTHKU.js.map +0 -1
- package/dist/chunk-WQG2DFHX.js.map +0 -1
- package/dist/chunk-WVI5CJ6S.js.map +0 -1
- package/dist/chunk-ZVS4UKN2.js.map +0 -1
- package/dist/chunk-ZXKLPC2E.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/create-agent-MBOOT3XK.js.map +0 -1
- package/dist/create-annotation-XMV6A7ED.js.map +0 -1
- package/dist/create-dashboard-VRKLFVZJ.js.map +0 -1
- package/dist/create-dataset-7HQPZCRE.js.map +0 -1
- package/dist/create-dataset-records-2NIVFYTV.js.map +0 -1
- package/dist/create-evaluator-WYFRFLRC.js.map +0 -1
- package/dist/create-mcp-server.js.map +0 -1
- package/dist/create-prompt-IEN7O6JT.js.map +0 -1
- package/dist/create-prompt-tag-CAEZ45VO.js.map +0 -1
- package/dist/create-scenario-6YHSMGLP.js.map +0 -1
- package/dist/create-suite-H5XOFDE5.js.map +0 -1
- package/dist/delete-agent-JKTNBWAA.js.map +0 -1
- package/dist/delete-annotation-ACMDV6QO.js.map +0 -1
- package/dist/delete-dashboard-VJSR7CRU.js.map +0 -1
- package/dist/delete-dataset-RTTTWP4D.js.map +0 -1
- package/dist/delete-dataset-records-KNQTIPQK.js.map +0 -1
- package/dist/delete-evaluator-7FVC5WM4.js.map +0 -1
- package/dist/delete-prompt-tag-ZMZUAGFW.js.map +0 -1
- package/dist/delete-workflow-EYQ3T4RQ.js.map +0 -1
- package/dist/discover-evaluator-schema-H23XCLNE.js.map +0 -1
- package/dist/discover-scenario-schema-MEEEVND7.js.map +0 -1
- package/dist/discover-schema-3T52ORPB.js.map +0 -1
- package/dist/get-agent-E3QSTVKG.js.map +0 -1
- package/dist/get-analytics-2OHV763I.js.map +0 -1
- package/dist/get-dashboard-PC7JDHH6.js.map +0 -1
- package/dist/get-dataset-H5IK5FVU.js.map +0 -1
- package/dist/get-evaluator-UWVUPYTM.js.map +0 -1
- package/dist/get-prompt-WZUOLLQC.js.map +0 -1
- package/dist/get-scenario-Q6LCNUYN.js.map +0 -1
- package/dist/get-simulation-run-Z2XKO256.js.map +0 -1
- package/dist/get-suite-BXK5TN7P.js.map +0 -1
- package/dist/get-trace-4EJAYVBG.js.map +0 -1
- package/dist/get-workflow-O34QJLHD.js.map +0 -1
- package/dist/http-server-ISHF7NJX.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/langwatch-api-annotations-ERBG27RF.js.map +0 -1
- package/dist/langwatch-api-dashboards-G6TR7VVO.js.map +0 -1
- package/dist/langwatch-api-monitors-WSXZLS2B.js.map +0 -1
- package/dist/langwatch-api-secrets-RR5DKG2X.js.map +0 -1
- package/dist/langwatch-api-triggers-2RTNSWQY.js.map +0 -1
- package/dist/langwatch-api-workflows-VJRIIDZ7.js +0 -15
- package/dist/langwatch-api-workflows-VJRIIDZ7.js.map +0 -1
- package/dist/list-agents-AW3P6FJV.js.map +0 -1
- package/dist/list-annotations-QNCGWPQ3.js.map +0 -1
- package/dist/list-dashboards-R7RK2IXL.js.map +0 -1
- package/dist/list-dataset-records-WVCSQP7P.js.map +0 -1
- package/dist/list-datasets-KEXRLDEU.js.map +0 -1
- package/dist/list-evaluators-7R2LB4JH.js.map +0 -1
- package/dist/list-model-providers-OBYJCKBX.js.map +0 -1
- package/dist/list-prompt-tags-6LY3ZPYI.js.map +0 -1
- package/dist/list-prompts-VWEZ4CDE.js.map +0 -1
- package/dist/list-scenarios-TXD4W2ZJ.js.map +0 -1
- package/dist/list-simulation-runs-RHPOLMFI.js.map +0 -1
- package/dist/list-suites-FSGBX27Z.js.map +0 -1
- package/dist/list-workflows-VRGEZ3EN.js.map +0 -1
- package/dist/rename-prompt-tag-VOJJLX4M.js.map +0 -1
- package/dist/run-agent-KTCC7TB7.js.map +0 -1
- package/dist/run-evaluation-2X3V3Q6L.js +0 -64
- package/dist/run-evaluation-2X3V3Q6L.js.map +0 -1
- package/dist/run-suite-BTMHGI2D.js.map +0 -1
- package/dist/run-workflow-IGAYGKJL.js.map +0 -1
- package/dist/search-traces-VYFUIMXH.js.map +0 -1
- package/dist/set-model-provider-W5IUI326.js.map +0 -1
- package/dist/update-agent-4BB7EYLR.js.map +0 -1
- package/dist/update-dataset-CXBKZ4W3.js.map +0 -1
- package/dist/update-dataset-record-HOHAMHXG.js.map +0 -1
- package/dist/update-evaluator-IVOR6FTR.js.map +0 -1
- package/dist/update-prompt-OWQAKE7K.js.map +0 -1
- package/dist/update-scenario-GDFVILPN.js.map +0 -1
- package/dist/update-suite-BXYUYSPT.js.map +0 -1
- package/tests/evaluations.ipynb +0 -649
- package/tests/fixtures/azure/azure_openai_stream_bot_expected.py +0 -102
- package/tests/fixtures/azure/azure_openai_stream_bot_input.py +0 -78
- package/tests/fixtures/dspy/dspy_bot_expected.py +0 -61
- package/tests/fixtures/dspy/dspy_bot_input.py +0 -53
- package/tests/fixtures/fastapi/fastapi_app_expected.py +0 -68
- package/tests/fixtures/fastapi/fastapi_app_input.py +0 -60
- package/tests/fixtures/fastapi/prompt_management_fastapi_expected.py +0 -114
- package/tests/fixtures/fastapi/prompt_management_fastapi_input.py +0 -88
- package/tests/fixtures/haystack/haystack_bot_expected.py +0 -141
- package/tests/fixtures/haystack/haystack_bot_input.py +0 -69
- package/tests/fixtures/langchain/langchain_bot_expected.py +0 -53
- package/tests/fixtures/langchain/langchain_bot_input.py +0 -45
- package/tests/fixtures/langchain/langchain_bot_with_memory_expected.py +0 -69
- package/tests/fixtures/langchain/langchain_bot_with_memory_input.py +0 -61
- package/tests/fixtures/langchain/langchain_rag_bot_expected.py +0 -97
- package/tests/fixtures/langchain/langchain_rag_bot_input.py +0 -77
- package/tests/fixtures/langchain/langchain_rag_bot_vertex_ai_expected.py +0 -116
- package/tests/fixtures/langchain/langchain_rag_bot_vertex_ai_input.py +0 -81
- package/tests/fixtures/langchain/langgraph_rag_bot_with_threads_expected.py +0 -331
- package/tests/fixtures/langchain/langgraph_rag_bot_with_threads_input.py +0 -106
- package/tests/fixtures/litellm/litellm_bot_expected.py +0 -40
- package/tests/fixtures/litellm/litellm_bot_input.py +0 -35
- package/tests/fixtures/openai/openai_bot_expected.py +0 -43
- package/tests/fixtures/openai/openai_bot_function_call_expected.py +0 -91
- package/tests/fixtures/openai/openai_bot_function_call_input.py +0 -82
- package/tests/fixtures/openai/openai_bot_input.py +0 -36
- package/tests/fixtures/openai/openai_bot_rag_expected.py +0 -73
- package/tests/fixtures/openai/openai_bot_rag_input.py +0 -51
- package/tests/fixtures/opentelemetry/openinference_dspy_bot_expected.py +0 -63
- package/tests/fixtures/opentelemetry/openinference_dspy_bot_input.py +0 -58
- package/tests/fixtures/opentelemetry/openinference_langchain_bot_expected.py +0 -53
- package/tests/fixtures/opentelemetry/openinference_langchain_bot_input.py +0 -52
- package/tests/fixtures/opentelemetry/openinference_openai_bot_expected.py +0 -49
- package/tests/fixtures/opentelemetry/openinference_openai_bot_input.py +0 -41
- package/tests/fixtures/opentelemetry/openllmetry_openai_bot_expected.py +0 -44
- package/tests/fixtures/opentelemetry/openllmetry_openai_bot_input.py +0 -40
- package/tests/fixtures/strands/strands_bot_expected.py +0 -84
- package/tests/fixtures/strands/strands_bot_input.py +0 -52
- package/tests/scenario-openai.test.ts +0 -160
- package/tsup.config.ts +0 -14
- package/vitest.config.js +0 -7
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
import tempfile
|
|
4
|
-
from dotenv import load_dotenv
|
|
5
|
-
|
|
6
|
-
from langwatch.types import RAGChunk
|
|
7
|
-
|
|
8
|
-
load_dotenv()
|
|
9
|
-
|
|
10
|
-
import chainlit as cl
|
|
11
|
-
from langchain.prompts import ChatPromptTemplate
|
|
12
|
-
from langchain.schema import HumanMessage
|
|
13
|
-
from langchain.schema.runnable.config import RunnableConfig
|
|
14
|
-
|
|
15
|
-
import langwatch
|
|
16
|
-
|
|
17
|
-
from langchain_community.document_loaders import WebBaseLoader
|
|
18
|
-
from langchain_community.vectorstores.faiss import FAISS
|
|
19
|
-
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
|
|
20
|
-
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
|
21
|
-
from langchain.tools.retriever import create_retriever_tool
|
|
22
|
-
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
|
23
|
-
from langchain.tools import BaseTool, StructuredTool, tool
|
|
24
|
-
from langchain_google_vertexai import ChatVertexAI, VertexAI
|
|
25
|
-
|
|
26
|
-
loader = WebBaseLoader("https://docs.langwatch.ai")
|
|
27
|
-
docs = loader.load()
|
|
28
|
-
documents = RecursiveCharacterTextSplitter(
|
|
29
|
-
chunk_size=1000, chunk_overlap=200
|
|
30
|
-
).split_documents(docs)
|
|
31
|
-
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
|
|
32
|
-
retriever = vector.as_retriever()
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@cl.on_chat_start
|
|
36
|
-
async def on_chat_start():
|
|
37
|
-
retriever_tool = create_retriever_tool(
|
|
38
|
-
langwatch.langchain.capture_rag_from_retriever(
|
|
39
|
-
retriever,
|
|
40
|
-
lambda document: RAGChunk(
|
|
41
|
-
document_id=document.metadata["source"], content=document.page_content
|
|
42
|
-
),
|
|
43
|
-
),
|
|
44
|
-
"langwatch_search",
|
|
45
|
-
"Search for information about LangWatch. For any questions about LangWatch, use this tool if you didn't already",
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
# Alternative approach to retrievers
|
|
49
|
-
# wrapped_tool = langwatch.langchain.capture_rag_from_tool(
|
|
50
|
-
# retriever_tool, lambda response: [RAGChunk(content=response)]
|
|
51
|
-
# )
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
credentials_json = json.loads(os.environ["GOOGLE_APPLICATION_CREDENTIALS"])
|
|
55
|
-
credentials_file = tempfile.NamedTemporaryFile(mode="w", delete=False)
|
|
56
|
-
credentials_file.write(json.dumps(credentials_json))
|
|
57
|
-
credentials_file.close()
|
|
58
|
-
|
|
59
|
-
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = credentials_file.name
|
|
60
|
-
except:
|
|
61
|
-
pass
|
|
62
|
-
|
|
63
|
-
tools = [retriever_tool]
|
|
64
|
-
model = ChatVertexAI(
|
|
65
|
-
model_name="gemini-1.5-flash-001",
|
|
66
|
-
project=os.environ["VERTEXAI_PROJECT"],
|
|
67
|
-
location=os.environ["VERTEXAI_LOCATION"],
|
|
68
|
-
streaming=True,
|
|
69
|
-
)
|
|
70
|
-
prompt = ChatPromptTemplate.from_messages(
|
|
71
|
-
[
|
|
72
|
-
(
|
|
73
|
-
"system",
|
|
74
|
-
"You are a helpful assistant that only reply in short tweet-like responses, using lots of emojis and use tools only once.\n\n{agent_scratchpad}",
|
|
75
|
-
),
|
|
76
|
-
("human", "{question}"),
|
|
77
|
-
]
|
|
78
|
-
)
|
|
79
|
-
agent = create_tool_calling_agent(model, tools, prompt)
|
|
80
|
-
executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # type: ignore
|
|
81
|
-
cl.user_session.set("agent", executor)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@cl.on_message
|
|
85
|
-
@langwatch.trace()
|
|
86
|
-
async def main(message: cl.Message):
|
|
87
|
-
agent: AgentExecutor = cl.user_session.get("agent") # type: ignore
|
|
88
|
-
|
|
89
|
-
msg = cl.Message(content="")
|
|
90
|
-
|
|
91
|
-
langwatch.get_current_trace().update(
|
|
92
|
-
metadata={"customer_id": "customer_example", "labels": ["langchain", "rag", "vertex_ai"]}
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
async for chunk in agent.astream(
|
|
96
|
-
{
|
|
97
|
-
"question": message.content,
|
|
98
|
-
"messages": [HumanMessage(content="Hoi, dit is een test")],
|
|
99
|
-
},
|
|
100
|
-
config=RunnableConfig(
|
|
101
|
-
callbacks=[
|
|
102
|
-
cl.LangchainCallbackHandler(),
|
|
103
|
-
langwatch.get_current_trace().get_langchain_callback(),
|
|
104
|
-
]
|
|
105
|
-
),
|
|
106
|
-
):
|
|
107
|
-
if "output" in chunk:
|
|
108
|
-
await msg.stream_token(chunk["output"])
|
|
109
|
-
elif "actions" in chunk:
|
|
110
|
-
await msg.stream_token(chunk["actions"][0].log)
|
|
111
|
-
elif "steps" in chunk:
|
|
112
|
-
await msg.stream_token(chunk["steps"][0].observation + "\n\n")
|
|
113
|
-
else:
|
|
114
|
-
await msg.stream_token("<unammaped chunk>")
|
|
115
|
-
|
|
116
|
-
await msg.send()
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
import tempfile
|
|
4
|
-
from dotenv import load_dotenv
|
|
5
|
-
|
|
6
|
-
load_dotenv()
|
|
7
|
-
|
|
8
|
-
import chainlit as cl
|
|
9
|
-
from langchain.prompts import ChatPromptTemplate
|
|
10
|
-
from langchain.schema import HumanMessage
|
|
11
|
-
from langchain.schema.runnable.config import RunnableConfig
|
|
12
|
-
|
|
13
|
-
from langchain_community.document_loaders import WebBaseLoader
|
|
14
|
-
from langchain_community.vectorstores.faiss import FAISS
|
|
15
|
-
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
|
|
16
|
-
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
|
17
|
-
from langchain.tools.retriever import create_retriever_tool
|
|
18
|
-
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
|
19
|
-
from langchain.tools import BaseTool, StructuredTool, tool
|
|
20
|
-
from langchain_google_vertexai import ChatVertexAI, VertexAI
|
|
21
|
-
|
|
22
|
-
loader = WebBaseLoader("https://docs.langwatch.ai")
|
|
23
|
-
docs = loader.load()
|
|
24
|
-
documents = RecursiveCharacterTextSplitter(
|
|
25
|
-
chunk_size=1000, chunk_overlap=200
|
|
26
|
-
).split_documents(docs)
|
|
27
|
-
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
|
|
28
|
-
retriever = vector.as_retriever()
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@cl.on_chat_start
|
|
32
|
-
async def on_chat_start():
|
|
33
|
-
retriever_tool = create_retriever_tool(
|
|
34
|
-
retriever,
|
|
35
|
-
"langwatch_search",
|
|
36
|
-
"Search for information about LangWatch. For any questions about LangWatch, use this tool if you didn't already",
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
tools = [retriever_tool]
|
|
40
|
-
model = ChatVertexAI(model="gemini-pro", streaming=True)
|
|
41
|
-
prompt = ChatPromptTemplate.from_messages(
|
|
42
|
-
[
|
|
43
|
-
(
|
|
44
|
-
"system",
|
|
45
|
-
"You are a helpful assistant that only reply in short tweet-like responses, using lots of emojis and use tools only once.\n\n{agent_scratchpad}",
|
|
46
|
-
),
|
|
47
|
-
("human", "{question}"),
|
|
48
|
-
]
|
|
49
|
-
)
|
|
50
|
-
agent = create_tool_calling_agent(model, tools, prompt)
|
|
51
|
-
executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # type: ignore
|
|
52
|
-
cl.user_session.set("agent", executor)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@cl.on_message
|
|
56
|
-
async def main(message: cl.Message):
|
|
57
|
-
agent: AgentExecutor = cl.user_session.get("agent") # type: ignore
|
|
58
|
-
|
|
59
|
-
msg = cl.Message(content="")
|
|
60
|
-
|
|
61
|
-
async for chunk in agent.astream(
|
|
62
|
-
{
|
|
63
|
-
"question": message.content,
|
|
64
|
-
"messages": [HumanMessage(content="Hoi, dit is een test")],
|
|
65
|
-
},
|
|
66
|
-
config=RunnableConfig(
|
|
67
|
-
callbacks=[
|
|
68
|
-
cl.LangchainCallbackHandler(),
|
|
69
|
-
]
|
|
70
|
-
),
|
|
71
|
-
):
|
|
72
|
-
if "output" in chunk:
|
|
73
|
-
await msg.stream_token(chunk["output"])
|
|
74
|
-
elif "actions" in chunk:
|
|
75
|
-
await msg.stream_token(chunk["actions"][0].log)
|
|
76
|
-
elif "steps" in chunk:
|
|
77
|
-
await msg.stream_token(chunk["steps"][0].observation + "\n\n")
|
|
78
|
-
else:
|
|
79
|
-
await msg.stream_token("<unammaped chunk>")
|
|
80
|
-
|
|
81
|
-
await msg.send()
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
os.environ["CHAINLIT_AUTH_SECRET"] = (
|
|
4
|
-
"sSgdH4IfqM/%5swBnuwNdZ8rS/VBDW-WiBF?>DW_YPPKm9p9CiO6PPm6Z4Ih7IL"
|
|
5
|
-
)
|
|
6
|
-
|
|
7
|
-
import datetime
|
|
8
|
-
import os.path
|
|
9
|
-
import pickle
|
|
10
|
-
from typing import Dict, List, Literal, Optional
|
|
11
|
-
from dotenv import load_dotenv
|
|
12
|
-
|
|
13
|
-
from langwatch.types import RAGChunk
|
|
14
|
-
|
|
15
|
-
load_dotenv()
|
|
16
|
-
|
|
17
|
-
import chainlit as cl
|
|
18
|
-
from langchain.prompts import ChatPromptTemplate
|
|
19
|
-
from langchain.schema import HumanMessage
|
|
20
|
-
from langchain.schema.runnable.config import RunnableConfig
|
|
21
|
-
|
|
22
|
-
import langwatch
|
|
23
|
-
|
|
24
|
-
from langchain_community.document_loaders import WebBaseLoader
|
|
25
|
-
from langchain_community.vectorstores.faiss import FAISS
|
|
26
|
-
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
|
|
27
|
-
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
|
28
|
-
from langchain.tools.retriever import create_retriever_tool
|
|
29
|
-
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
|
30
|
-
from langchain.tools import BaseTool, StructuredTool, tool
|
|
31
|
-
import chainlit as cl
|
|
32
|
-
import chainlit.data as cl_data
|
|
33
|
-
from chainlit.data.utils import queue_until_user_message
|
|
34
|
-
from chainlit.element import Element, ElementDict
|
|
35
|
-
from chainlit.socket import persist_user_session
|
|
36
|
-
from chainlit.step import StepDict
|
|
37
|
-
from chainlit.types import (
|
|
38
|
-
Feedback,
|
|
39
|
-
PageInfo,
|
|
40
|
-
PaginatedResponse,
|
|
41
|
-
Pagination,
|
|
42
|
-
ThreadDict,
|
|
43
|
-
ThreadFilter,
|
|
44
|
-
)
|
|
45
|
-
from langgraph.graph import StateGraph, START, END, MessagesState
|
|
46
|
-
from langgraph.prebuilt import ToolNode
|
|
47
|
-
from langgraph.graph.state import CompiledStateGraph
|
|
48
|
-
|
|
49
|
-
loader = WebBaseLoader("https://docs.langwatch.ai")
|
|
50
|
-
docs = loader.load()
|
|
51
|
-
documents = RecursiveCharacterTextSplitter(
|
|
52
|
-
chunk_size=1000, chunk_overlap=200
|
|
53
|
-
).split_documents(docs)
|
|
54
|
-
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
|
|
55
|
-
retriever = vector.as_retriever()
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
now = datetime.datetime.now()
|
|
59
|
-
|
|
60
|
-
thread_history = [
|
|
61
|
-
{
|
|
62
|
-
"id": "test1",
|
|
63
|
-
"name": "thread 1",
|
|
64
|
-
"createdAt": now,
|
|
65
|
-
"userId": "test",
|
|
66
|
-
"userIdentifier": "admin",
|
|
67
|
-
"steps": [
|
|
68
|
-
{
|
|
69
|
-
"id": "test1",
|
|
70
|
-
"name": "test",
|
|
71
|
-
"createdAt": now,
|
|
72
|
-
"type": "user_message",
|
|
73
|
-
"output": "Message 1",
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"id": "test2",
|
|
77
|
-
"name": "test",
|
|
78
|
-
"createdAt": now,
|
|
79
|
-
"type": "assistant_message",
|
|
80
|
-
"output": "Message 2",
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"id": "test2",
|
|
86
|
-
"createdAt": now,
|
|
87
|
-
"userId": "test",
|
|
88
|
-
"userIdentifier": "admin",
|
|
89
|
-
"name": "thread 2",
|
|
90
|
-
"steps": [
|
|
91
|
-
{
|
|
92
|
-
"id": "test3",
|
|
93
|
-
"createdAt": now,
|
|
94
|
-
"name": "test",
|
|
95
|
-
"type": "user_message",
|
|
96
|
-
"output": "Message 3",
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
"id": "test4",
|
|
100
|
-
"createdAt": now,
|
|
101
|
-
"name": "test",
|
|
102
|
-
"type": "assistant_message",
|
|
103
|
-
"output": "Message 4",
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
},
|
|
107
|
-
]
|
|
108
|
-
deleted_thread_ids = []
|
|
109
|
-
|
|
110
|
-
THREAD_HISTORY_PICKLE_PATH = os.getenv("THREAD_HISTORY_PICKLE_PATH")
|
|
111
|
-
if THREAD_HISTORY_PICKLE_PATH and os.path.exists(THREAD_HISTORY_PICKLE_PATH):
|
|
112
|
-
with open(THREAD_HISTORY_PICKLE_PATH, "rb") as f:
|
|
113
|
-
thread_history = pickle.load(f)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
async def save_thread_history():
|
|
117
|
-
if THREAD_HISTORY_PICKLE_PATH:
|
|
118
|
-
# Force saving of thread history for reload when server restarts
|
|
119
|
-
await persist_user_session(
|
|
120
|
-
cl.context.session.thread_id, cl.context.session.to_persistable()
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
with open(THREAD_HISTORY_PICKLE_PATH, "wb") as out_file:
|
|
124
|
-
pickle.dump(thread_history, out_file)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
class TestDataLayer(cl_data.base.BaseDataLayer):
|
|
128
|
-
async def get_user(self, identifier: str):
|
|
129
|
-
return cl.PersistedUser(
|
|
130
|
-
id="test", createdAt=now.isoformat(), identifier=identifier
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
async def create_user(self, user: cl.User):
|
|
134
|
-
return cl.PersistedUser(
|
|
135
|
-
id="test", createdAt=now.isoformat(), identifier=user.identifier
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
async def update_thread(
|
|
139
|
-
self,
|
|
140
|
-
thread_id: str,
|
|
141
|
-
name: Optional[str] = None,
|
|
142
|
-
user_id: Optional[str] = None,
|
|
143
|
-
metadata: Optional[Dict] = None,
|
|
144
|
-
tags: Optional[List[str]] = None,
|
|
145
|
-
):
|
|
146
|
-
thread = next((t for t in thread_history if t["id"] == thread_id), None)
|
|
147
|
-
if thread:
|
|
148
|
-
if name:
|
|
149
|
-
thread["name"] = name
|
|
150
|
-
if metadata:
|
|
151
|
-
thread["metadata"] = metadata
|
|
152
|
-
if tags:
|
|
153
|
-
thread["tags"] = tags
|
|
154
|
-
else:
|
|
155
|
-
thread_history.append(
|
|
156
|
-
{
|
|
157
|
-
"id": thread_id,
|
|
158
|
-
"name": name,
|
|
159
|
-
"metadata": metadata,
|
|
160
|
-
"tags": tags,
|
|
161
|
-
"createdAt": now.isoformat(),
|
|
162
|
-
"userId": user_id,
|
|
163
|
-
"userIdentifier": "admin",
|
|
164
|
-
"steps": [],
|
|
165
|
-
}
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
@cl_data.queue_until_user_message()
|
|
169
|
-
async def create_step(self, step_dict: StepDict):
|
|
170
|
-
thread = next(
|
|
171
|
-
(t for t in thread_history if t["id"] == step_dict.get("threadId")), None
|
|
172
|
-
)
|
|
173
|
-
if thread:
|
|
174
|
-
thread["steps"].append(step_dict)
|
|
175
|
-
|
|
176
|
-
async def get_thread_author(self, thread_id: str):
|
|
177
|
-
return "admin"
|
|
178
|
-
|
|
179
|
-
async def list_threads(
|
|
180
|
-
self, pagination: Pagination, filters: ThreadFilter
|
|
181
|
-
) -> PaginatedResponse[ThreadDict]:
|
|
182
|
-
return PaginatedResponse(
|
|
183
|
-
data=[t for t in thread_history if t["id"] not in deleted_thread_ids],
|
|
184
|
-
pageInfo=PageInfo(hasNextPage=False, startCursor=None, endCursor=None),
|
|
185
|
-
) # type: ignore
|
|
186
|
-
|
|
187
|
-
async def get_thread(self, thread_id: str):
|
|
188
|
-
thread = next((t for t in thread_history if t["id"] == thread_id), None)
|
|
189
|
-
if not thread:
|
|
190
|
-
return None
|
|
191
|
-
thread["steps"] = sorted(thread["steps"], key=lambda x: x["createdAt"])
|
|
192
|
-
return thread
|
|
193
|
-
|
|
194
|
-
async def delete_thread(self, thread_id: str):
|
|
195
|
-
deleted_thread_ids.append(thread_id)
|
|
196
|
-
|
|
197
|
-
async def delete_feedback(
|
|
198
|
-
self,
|
|
199
|
-
feedback_id: str,
|
|
200
|
-
) -> bool:
|
|
201
|
-
return True
|
|
202
|
-
|
|
203
|
-
async def upsert_feedback(
|
|
204
|
-
self,
|
|
205
|
-
feedback: Feedback,
|
|
206
|
-
) -> str:
|
|
207
|
-
return ""
|
|
208
|
-
|
|
209
|
-
@queue_until_user_message()
|
|
210
|
-
async def create_element(self, element: "Element"):
|
|
211
|
-
pass
|
|
212
|
-
|
|
213
|
-
async def get_element(
|
|
214
|
-
self, thread_id: str, element_id: str
|
|
215
|
-
) -> Optional["ElementDict"]:
|
|
216
|
-
pass
|
|
217
|
-
|
|
218
|
-
@queue_until_user_message()
|
|
219
|
-
async def delete_element(self, element_id: str, thread_id: Optional[str] = None):
|
|
220
|
-
pass
|
|
221
|
-
|
|
222
|
-
@queue_until_user_message()
|
|
223
|
-
async def update_step(self, step_dict: "StepDict"):
|
|
224
|
-
pass
|
|
225
|
-
|
|
226
|
-
@queue_until_user_message()
|
|
227
|
-
async def delete_step(self, step_id: str):
|
|
228
|
-
pass
|
|
229
|
-
|
|
230
|
-
async def build_debug_url(self) -> str:
|
|
231
|
-
return ""
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
cl_data._data_layer = TestDataLayer()
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
retriever_tool = create_retriever_tool(
|
|
238
|
-
langwatch.langchain.capture_rag_from_retriever(
|
|
239
|
-
retriever,
|
|
240
|
-
lambda document: RAGChunk(
|
|
241
|
-
document_id=document.metadata["source"], content=document.page_content
|
|
242
|
-
),
|
|
243
|
-
),
|
|
244
|
-
"langwatch_search",
|
|
245
|
-
"Search for information about LangWatch. For any questions about LangWatch, use this tool if you didn't already",
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
tools = [retriever_tool]
|
|
249
|
-
tool_node = ToolNode(tools)
|
|
250
|
-
model = ChatOpenAI(streaming=True).bind_tools(tools)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def should_continue(state: MessagesState):
|
|
254
|
-
messages = state["messages"]
|
|
255
|
-
last_message = messages[-1]
|
|
256
|
-
# If the LLM makes a tool call, then we route to the "tools" node
|
|
257
|
-
if last_message.tool_calls: # type: ignore
|
|
258
|
-
return "tools"
|
|
259
|
-
return END
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
def call_model(state):
|
|
263
|
-
messages = state["messages"]
|
|
264
|
-
response = model.invoke(messages)
|
|
265
|
-
# We return a list, because this will get added to the existing list
|
|
266
|
-
return {"messages": [response]}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
# Define the graph
|
|
270
|
-
workflow = StateGraph(MessagesState)
|
|
271
|
-
|
|
272
|
-
workflow.add_node("agent", call_model)
|
|
273
|
-
workflow.add_node("tools", tool_node)
|
|
274
|
-
|
|
275
|
-
workflow.add_edge(START, "agent")
|
|
276
|
-
workflow.add_conditional_edges("agent", should_continue)
|
|
277
|
-
workflow.add_edge("tools", "agent")
|
|
278
|
-
|
|
279
|
-
# Compile the graph
|
|
280
|
-
app = workflow.compile()
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
@cl.on_message
|
|
284
|
-
@langwatch.trace()
|
|
285
|
-
async def main(message: cl.Message):
|
|
286
|
-
msg = cl.Message(content="")
|
|
287
|
-
|
|
288
|
-
langwatch.get_current_trace().update(
|
|
289
|
-
metadata={
|
|
290
|
-
"labels": ["langchain", "rag", "tools"],
|
|
291
|
-
"user_id": getattr(cl.user_session.get("user"), "identifier", "unknown"),
|
|
292
|
-
"thread_id": cl.context.session.thread_id,
|
|
293
|
-
}
|
|
294
|
-
)
|
|
295
|
-
|
|
296
|
-
async for event in app.astream(
|
|
297
|
-
{"messages": [HumanMessage(content=message.content)]},
|
|
298
|
-
config=RunnableConfig(
|
|
299
|
-
callbacks=[
|
|
300
|
-
cl.LangchainCallbackHandler(),
|
|
301
|
-
langwatch.get_current_trace().get_langchain_callback(),
|
|
302
|
-
]
|
|
303
|
-
),
|
|
304
|
-
):
|
|
305
|
-
if "agent" in event:
|
|
306
|
-
if "messages" in event["agent"]:
|
|
307
|
-
for message in event["agent"]["messages"]:
|
|
308
|
-
await msg.stream_token(message.content)
|
|
309
|
-
|
|
310
|
-
await msg.send()
|
|
311
|
-
|
|
312
|
-
await save_thread_history()
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
@cl.password_auth_callback
|
|
316
|
-
async def auth_callback(username: str, password: str) -> Optional[cl.User]:
|
|
317
|
-
if (username, password) == ("admin", "admin"):
|
|
318
|
-
return cl.User(identifier="admin")
|
|
319
|
-
else:
|
|
320
|
-
return None
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
@cl.on_chat_resume
|
|
324
|
-
async def on_chat_resume(thread: ThreadDict):
|
|
325
|
-
await cl.Message(f"Welcome back to {thread['name']}").send()
|
|
326
|
-
if "metadata" in thread and thread["metadata"]:
|
|
327
|
-
await cl.Message(thread["metadata"], author="metadata", language="json").send()
|
|
328
|
-
if "tags" in thread and thread["tags"]:
|
|
329
|
-
await cl.Message(
|
|
330
|
-
",".join(thread["tags"]), author="tags", language="json"
|
|
331
|
-
).send()
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
os.environ["CHAINLIT_AUTH_SECRET"] = (
|
|
4
|
-
"sSgdH4IfqM/%5swBnuwNdZ8rS/VBDW-WiBF?>DW_YPPKm9p9CiO6PPm6Z4Ih7IL"
|
|
5
|
-
)
|
|
6
|
-
|
|
7
|
-
import datetime
|
|
8
|
-
import os.path
|
|
9
|
-
import pickle
|
|
10
|
-
from typing import Dict, List, Literal, Optional
|
|
11
|
-
from dotenv import load_dotenv
|
|
12
|
-
|
|
13
|
-
load_dotenv()
|
|
14
|
-
|
|
15
|
-
import chainlit as cl
|
|
16
|
-
from langchain.prompts import ChatPromptTemplate
|
|
17
|
-
from langchain.schema import HumanMessage
|
|
18
|
-
from langchain.schema.runnable.config import RunnableConfig
|
|
19
|
-
|
|
20
|
-
from langchain_community.document_loaders import WebBaseLoader
|
|
21
|
-
from langchain_community.vectorstores.faiss import FAISS
|
|
22
|
-
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
|
|
23
|
-
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
|
24
|
-
from langchain.tools.retriever import create_retriever_tool
|
|
25
|
-
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
|
26
|
-
from langchain.tools import BaseTool, StructuredTool, tool
|
|
27
|
-
import chainlit as cl
|
|
28
|
-
import chainlit.data as cl_data
|
|
29
|
-
from chainlit.data.utils import queue_until_user_message
|
|
30
|
-
from chainlit.element import Element, ElementDict
|
|
31
|
-
from chainlit.socket import persist_user_session
|
|
32
|
-
from chainlit.step import StepDict
|
|
33
|
-
from chainlit.types import (
|
|
34
|
-
Feedback,
|
|
35
|
-
PageInfo,
|
|
36
|
-
PaginatedResponse,
|
|
37
|
-
Pagination,
|
|
38
|
-
ThreadDict,
|
|
39
|
-
ThreadFilter,
|
|
40
|
-
)
|
|
41
|
-
from langgraph.graph import StateGraph, START, END, MessagesState
|
|
42
|
-
from langgraph.prebuilt import ToolNode
|
|
43
|
-
from langgraph.graph.state import CompiledStateGraph
|
|
44
|
-
|
|
45
|
-
loader = WebBaseLoader("https://docs.langwatch.ai")
|
|
46
|
-
docs = loader.load()
|
|
47
|
-
documents = RecursiveCharacterTextSplitter(
|
|
48
|
-
chunk_size=1000, chunk_overlap=200
|
|
49
|
-
).split_documents(docs)
|
|
50
|
-
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
|
|
51
|
-
retriever = vector.as_retriever()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
@cl.on_chat_start
|
|
55
|
-
async def on_chat_start():
|
|
56
|
-
retriever_tool = create_retriever_tool(
|
|
57
|
-
retriever,
|
|
58
|
-
"langwatch_search",
|
|
59
|
-
"Search for information about LangWatch. For any questions about LangWatch, use this tool if you didn't already",
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
tools = [retriever_tool]
|
|
63
|
-
model = ChatOpenAI(model="gpt-5", streaming=True)
|
|
64
|
-
|
|
65
|
-
# Create LangGraph workflow
|
|
66
|
-
def should_continue(state: MessagesState) -> Literal["tools", END]:
|
|
67
|
-
messages = state['messages']
|
|
68
|
-
last_message = messages[-1]
|
|
69
|
-
if last_message.tool_calls:
|
|
70
|
-
return "tools"
|
|
71
|
-
return END
|
|
72
|
-
|
|
73
|
-
def call_model(state: MessagesState):
|
|
74
|
-
messages = state['messages']
|
|
75
|
-
response = model.invoke(messages)
|
|
76
|
-
return {"messages": [response]}
|
|
77
|
-
|
|
78
|
-
workflow = StateGraph(MessagesState)
|
|
79
|
-
workflow.add_node("agent", call_model)
|
|
80
|
-
workflow.add_node("tools", ToolNode(tools))
|
|
81
|
-
workflow.add_edge(START, "agent")
|
|
82
|
-
workflow.add_conditional_edges("agent", should_continue)
|
|
83
|
-
workflow.add_edge("tools", "agent")
|
|
84
|
-
|
|
85
|
-
app = workflow.compile()
|
|
86
|
-
cl.user_session.set("agent", app)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
@cl.on_message
|
|
90
|
-
async def main(message: cl.Message):
|
|
91
|
-
agent: CompiledStateGraph = cl.user_session.get("agent") # type: ignore
|
|
92
|
-
|
|
93
|
-
msg = cl.Message(content="")
|
|
94
|
-
|
|
95
|
-
async for chunk in agent.astream(
|
|
96
|
-
{"messages": [HumanMessage(content=message.content)]},
|
|
97
|
-
config=RunnableConfig(
|
|
98
|
-
callbacks=[
|
|
99
|
-
cl.LangchainCallbackHandler(),
|
|
100
|
-
]
|
|
101
|
-
),
|
|
102
|
-
):
|
|
103
|
-
if "agent" in chunk:
|
|
104
|
-
await msg.stream_token(chunk["agent"]["messages"][-1].content)
|
|
105
|
-
|
|
106
|
-
await msg.send()
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from typing import cast
|
|
2
|
-
from dotenv import load_dotenv
|
|
3
|
-
|
|
4
|
-
load_dotenv()
|
|
5
|
-
|
|
6
|
-
import chainlit as cl
|
|
7
|
-
import litellm
|
|
8
|
-
from litellm import CustomStreamWrapper
|
|
9
|
-
from litellm.types.utils import StreamingChoices
|
|
10
|
-
|
|
11
|
-
import langwatch
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@cl.on_message
|
|
15
|
-
@langwatch.trace()
|
|
16
|
-
async def main(message: cl.Message):
|
|
17
|
-
langwatch.get_current_trace().autotrack_litellm_calls(litellm)
|
|
18
|
-
|
|
19
|
-
msg = cl.Message(
|
|
20
|
-
content="",
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
response = litellm.completion(
|
|
24
|
-
model="cerebras/gpt-oss-120b",
|
|
25
|
-
messages=[
|
|
26
|
-
{
|
|
27
|
-
"role": "system",
|
|
28
|
-
"content": "You are a helpful assistant that only reply in short tweet-like responses, using lots of emojis.",
|
|
29
|
-
},
|
|
30
|
-
{"role": "user", "content": message.content},
|
|
31
|
-
],
|
|
32
|
-
stream=True,
|
|
33
|
-
stream_options={"include_usage": True},
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
for part in cast(CustomStreamWrapper, response):
|
|
37
|
-
if token := cast(StreamingChoices, part.choices[0]).delta.content or "":
|
|
38
|
-
await msg.stream_token(token)
|
|
39
|
-
|
|
40
|
-
await msg.update()
|