LONGYKING commited on
Commit
a36d1ff
·
2 Parent(s): 1585e50 0207cdc

fixed swap and bridging

Browse files
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
Dockerfile CHANGED
@@ -1,25 +1,34 @@
1
  # Use an official Python runtime as a parent image
2
  FROM python:3.11-slim
3
 
 
 
 
4
  # Set the working directory in the container
5
  WORKDIR /app
6
 
7
- # Install PostgreSQL client libraries and development headers
 
8
  RUN apt-get update && apt-get install -y \
 
9
  libpq-dev \
10
  gcc \
11
  && rm -rf /var/lib/apt/lists/*
12
 
 
 
 
 
 
 
13
  # Copy the rest of the application code into the container
14
- COPY . .
15
 
16
  # Install any needed packages specified in requirements.txt
17
  RUN pip install --no-cache-dir -r requirements.txt
18
 
19
- # Make port 8501 available to the world outside this container
20
- #EXPOSE 8000
21
- EXPOSE 8080
22
 
23
  # Run chainlit when the container launches
24
- CMD ["python", "-m", "chainlit", "run", "chatxbt-assistant.py", "-h", "--port", "8080"]
25
-
 
1
  # Use an official Python runtime as a parent image
2
  FROM python:3.11-slim
3
 
4
+ # Create a user and set permissions
5
+ RUN useradd -m -u 1000 user
6
+
7
  # Set the working directory in the container
8
  WORKDIR /app
9
 
10
+ # Install system dependencies
11
+ USER root
12
  RUN apt-get update && apt-get install -y \
13
+ python3-dev \
14
  libpq-dev \
15
  gcc \
16
  && rm -rf /var/lib/apt/lists/*
17
 
18
+ # Ensure .files directory exists and is writable
19
+ RUN mkdir -p /app/.files && chown -R user:user /app/.files
20
+
21
+ # Switch back to the non-root user
22
+ USER user
23
+
24
  # Copy the rest of the application code into the container
25
+ COPY --chown=user . .
26
 
27
  # Install any needed packages specified in requirements.txt
28
  RUN pip install --no-cache-dir -r requirements.txt
29
 
30
+ # Expose port 8080 to the world outside this container
31
+ EXPOSE 7860
 
32
 
33
  # Run chainlit when the container launches
34
+ CMD ["python", "-m", "chainlit", "run", "chatxbt-assistant.py", "-h", "--port", "7860"]
 
README.md CHANGED
@@ -1,11 +1,21 @@
1
- # ChatXBT Web3 AI Assitant Service
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  AI-powered unification and execution protocol for web3 applications
4
 
5
-
6
  ## Requirements
7
 
8
- The list below contains all the requirements needed to have a complete developer environment to sart working on this project.
9
  Follow the links to install or update these tools on your machine.
10
 
11
  1. [Python 3.12+](https://www.python.org/downloads/release/python-3120/)
@@ -13,17 +23,15 @@ Follow the links to install or update these tools on your machine.
13
  3. [Pip Installer](https://pip.pypa.io/en/stable/installation/)
14
  4. [Python Venv](https://docs.python.org/3/library/venv.html)
15
 
16
-
17
  ## Installation
18
 
19
  1. Clone the repository: `git clone https://github.com/ChatXBT/chatxbt-web3-ai-assistant.git`
20
- 2. Get a copy of the `\`.env`\` file from the project manager`
21
  3. Create a virtual environment: `python -m venv env`
22
  4. Activate the virtual environment: `source env/bin/activate`
23
- 4. Install the dependencies: `pip install -r requirements.txt`
24
- 5. Run the application: `chainlit run chatxbt-assistant.py -w`
25
- 6. Open the application in your browser: `http://localhost:8000`
26
-
27
 
28
  ## Project Overview
29
 
@@ -36,17 +44,15 @@ The project is structured as follows:
36
  5. src/search_services: `a list of search services that can be used to retrieve data for the AI assistant.`
37
  6. src/tools: `a list of tools that can be used to extend the functionality of the AI assistant.`
38
 
39
-
40
  ## Guides
41
 
42
  1. Follow the development, structure and documentation patterns of the `src/tools/coin_data_toolkit.py` to build custom toolkits
43
  2. Follow the development, structure and documentation patterns of the `src/tools/coin_data_toolkit.py` to build classes
44
- 3. Pay attention to the `constants` variables and `caching` decorators to optimize perfomance of class functions/methods across the project
45
  4. Create new classes in the appropriate folders to maintain an organized codebase and project
46
  5. After installing any new package run `` to update the dependency requirements list
47
  6. Expose RPC functions for SDKs that do not support python runtime. use [DeepKit](https://deepkit.io/documentation/rpc) and [BunJS](https://bun.sh/) if possible.
48
 
49
-
50
  ## Git Workflow
51
 
52
  For this project, we will be using a very simple version of the Gitflow workflow. This workflow is designed to manage the development, release, and maintenance of software projects. It provides a clear and structured approach to managing branches, releases, and feature development.
@@ -68,21 +74,19 @@ For this project, we will be using a very simple version of the Gitflow workflow
68
  3. Push your changes to the remote repository: `git push origin bugfix/my-bugfix`
69
  4. Open a pull request on GitHub and request a review from a team member.
70
  5. Deploy the bugfix branch to a staging environment for testing.
71
- 6. Once testing is finished, merge the pull request into the main branch.
72
  7. Once the pull request is approved, merge it into the main branch.
73
  8. Delete the bugfix branch: `git branch -d bugfix/my-bugfix`
74
  9. Update your local main branch: `git checkout main && git pull origin main`
75
 
76
-
77
- ## Deplopyment to producton
78
 
79
  To be finalised and added
80
 
81
-
82
  ## TODO
83
 
84
  1. Add deployment instructions
85
  2. Setup CI/CD pipelines for automatic deployment
86
  3. Setup and integrate `LiteLLM` instance for LLM service high availability
87
- 4. Add RPC class for remmote method calls to other chatxbt services written in other launguages such as `JS`, `TS` & `GO`
88
- 5. Write enough unit test to ensure class and function input and output correctness
 
1
+ ---
2
+ title: ChatXBT
3
+ emoji: 💬
4
+ colorFrom: purple
5
+ colorTo: pink
6
+ sdk: docker
7
+ sdk_version: "latest"
8
+ app_file: chatxbt-assistant.py
9
+ pinned: false
10
+ ---
11
+
12
+ # ChatXBT Web3 AI Assistant Service
13
 
14
  AI-powered unification and execution protocol for web3 applications
15
 
 
16
  ## Requirements
17
 
18
+ The list below contains all the requirements needed to have a complete developer environment to start working on this project.
19
  Follow the links to install or update these tools on your machine.
20
 
21
  1. [Python 3.12+](https://www.python.org/downloads/release/python-3120/)
 
23
  3. [Pip Installer](https://pip.pypa.io/en/stable/installation/)
24
  4. [Python Venv](https://docs.python.org/3/library/venv.html)
25
 
 
26
  ## Installation
27
 
28
  1. Clone the repository: `git clone https://github.com/ChatXBT/chatxbt-web3-ai-assistant.git`
29
+ 2. Get a copy of the `.env` file from the project manager
30
  3. Create a virtual environment: `python -m venv env`
31
  4. Activate the virtual environment: `source env/bin/activate`
32
+ 5. Install the dependencies: `pip install -r requirements.txt`
33
+ 6. Run the application: `chainlit run chatxbt-assistant.py -w`
34
+ 7. Open the application in your browser: `http://localhost:8000`
 
35
 
36
  ## Project Overview
37
 
 
44
  5. src/search_services: `a list of search services that can be used to retrieve data for the AI assistant.`
45
  6. src/tools: `a list of tools that can be used to extend the functionality of the AI assistant.`
46
 
 
47
  ## Guides
48
 
49
  1. Follow the development, structure and documentation patterns of the `src/tools/coin_data_toolkit.py` to build custom toolkits
50
  2. Follow the development, structure and documentation patterns of the `src/tools/coin_data_toolkit.py` to build classes
51
+ 3. Pay attention to the `constants` variables and `caching` decorators to optimize performance of class functions/methods across the project
52
  4. Create new classes in the appropriate folders to maintain an organized codebase and project
53
  5. After installing any new package run `` to update the dependency requirements list
54
  6. Expose RPC functions for SDKs that do not support python runtime. use [DeepKit](https://deepkit.io/documentation/rpc) and [BunJS](https://bun.sh/) if possible.
55
 
 
56
  ## Git Workflow
57
 
58
  For this project, we will be using a very simple version of the Gitflow workflow. This workflow is designed to manage the development, release, and maintenance of software projects. It provides a clear and structured approach to managing branches, releases, and feature development.
 
74
  3. Push your changes to the remote repository: `git push origin bugfix/my-bugfix`
75
  4. Open a pull request on GitHub and request a review from a team member.
76
  5. Deploy the bugfix branch to a staging environment for testing.
77
+ 6. Once testing is finished, merge the pull request into the main branch.
78
  7. Once the pull request is approved, merge it into the main branch.
79
  8. Delete the bugfix branch: `git branch -d bugfix/my-bugfix`
80
  9. Update your local main branch: `git checkout main && git pull origin main`
81
 
82
+ ## Deployment to production
 
83
 
84
  To be finalised and added
85
 
 
86
  ## TODO
87
 
88
  1. Add deployment instructions
89
  2. Setup CI/CD pipelines for automatic deployment
90
  3. Setup and integrate `LiteLLM` instance for LLM service high availability
91
+ 4. Add RPC class for remote method calls to other ChatXBT services written in other languages such as `JS`, `TS` & `GO`
92
+ 5. Write enough unit tests to ensure class and function input and output correctness
chatxbt-assistant.py CHANGED
@@ -1,23 +1,28 @@
1
- import os
2
  from typing import Optional, Dict
3
  from dotenv import load_dotenv
 
4
  load_dotenv()
5
 
6
  import chainlit as cl
7
  from phi.assistant import Assistant
8
  from phi.llm.openai import OpenAIChat
 
9
  from phi.llm.groq import Groq
10
  from phi.tools.duckduckgo import DuckDuckGo
11
  from phi.tools.yfinance import YFinanceTools
12
  from src.databases.postgres import sqlalchemy_engine
 
13
  from src.tools.crypto_swap_toolkit import CryptoSwapTools
14
  from src.tools.crypto_bridge_toolkit import CrossChainSwapTools
15
  from src.tools.crypto_data_toolkit import CryptoDataTools
16
- from src.tools.crypto_evm_wallet_toolkit import CryptoEVMWalletTools
 
17
  from src.tools.user_profile_toolkit import UserProfileToolkit
18
  from phi.storage.assistant.postgres import PgAssistantStorage
19
- from src.knowledge_bases.combined import knowledge_base
20
- from src.config.assistant import description, instruction
 
21
 
22
  storage = PgAssistantStorage(
23
  # stores runs in the ai.assistant_runs table
@@ -87,19 +92,22 @@ async def set_starters():
87
  async def start():
88
  is_dev_mode = True if os.getenv("DEV_MODE") else False
89
 
 
 
 
90
  # Initialize the assistant
91
  cxbt_assistant = Assistant(
92
- description=description,
93
- instruction=instruction,
94
- # llm=OpenAIChat(model="gpt-4o"),
95
- llm=Groq(model="llama3-70b-8192"),
96
  tools=[
97
- UserProfileToolkit(),
98
  DuckDuckGo(),
99
  CryptoDataTools(),
100
  CryptoSwapTools(),
101
  CrossChainSwapTools(),
 
102
  CryptoEVMWalletTools(),
 
103
  YFinanceTools(stock_price=True)
104
  ],
105
  show_tool_calls=is_dev_mode,
@@ -109,7 +117,9 @@ async def start():
109
  search_knowledge=True,
110
  read_chat_history=True,
111
  add_references_to_prompt=True,
112
- add_chat_history_to_prompt=True
 
 
113
  )
114
  cxbt_assistant.knowledge_base.load(recreate=False)
115
 
@@ -119,16 +129,20 @@ async def start():
119
  @cl.on_message
120
  async def main(message: cl.Message):
121
 
 
 
 
122
  # Retrieve the assistant from the user session
123
  agent = cl.user_session.get("agent")
124
 
125
  # Process the user message using the assistant
126
- response = ""
127
  for delta in agent.run(message.content, stream=True):
128
- response += delta
129
-
130
- # Send the response back to the user
131
- await cl.Message(content=response).send()
 
 
132
 
133
  # Run the Chainlit application
134
  if __name__ == "__main__":
 
1
+ import os, json
2
  from typing import Optional, Dict
3
  from dotenv import load_dotenv
4
+
5
  load_dotenv()
6
 
7
  import chainlit as cl
8
  from phi.assistant import Assistant
9
  from phi.llm.openai import OpenAIChat
10
+ from phi.llm.ollama import Ollama
11
  from phi.llm.groq import Groq
12
  from phi.tools.duckduckgo import DuckDuckGo
13
  from phi.tools.yfinance import YFinanceTools
14
  from src.databases.postgres import sqlalchemy_engine
15
+ from src.knowledge_bases.combined import knowledge_base
16
  from src.tools.crypto_swap_toolkit import CryptoSwapTools
17
  from src.tools.crypto_bridge_toolkit import CrossChainSwapTools
18
  from src.tools.crypto_data_toolkit import CryptoDataTools
19
+ from portkey_ai import PORTKEY_GATEWAY_URL, createHeaders
20
+ from src.config.portkey_config import generate_portkey_config
21
  from src.tools.user_profile_toolkit import UserProfileToolkit
22
  from phi.storage.assistant.postgres import PgAssistantStorage
23
+ from src.tools.crypto_evm_wallet_toolkit import CryptoEVMWalletTools
24
+ from src.tools.user_confirmation_pin_toolkit import UserConfirmationPinToolkit
25
+
26
 
27
  storage = PgAssistantStorage(
28
  # stores runs in the ai.assistant_runs table
 
92
  async def start():
93
  is_dev_mode = True if os.getenv("DEV_MODE") else False
94
 
95
+ portkey_local_gateway = True if os.getenv("PORTKEY_LOCAL_GATEWAY_URL") else False
96
+ portkey_config = generate_portkey_config(local=portkey_local_gateway)
97
+
98
  # Initialize the assistant
99
  cxbt_assistant = Assistant(
100
+ # llm=OpenAIChat(),
101
+ # llm=Groq(model="llama3-70b-8192"),
102
+ llm=Ollama(model="llama3"),
 
103
  tools=[
 
104
  DuckDuckGo(),
105
  CryptoDataTools(),
106
  CryptoSwapTools(),
107
  CrossChainSwapTools(),
108
+ UserProfileToolkit(),
109
  CryptoEVMWalletTools(),
110
+ UserConfirmationPinToolkit(),
111
  YFinanceTools(stock_price=True)
112
  ],
113
  show_tool_calls=is_dev_mode,
 
117
  search_knowledge=True,
118
  read_chat_history=True,
119
  add_references_to_prompt=True,
120
+ add_chat_history_to_prompt=True,
121
+ prevent_hallucinations=True,
122
+ prevent_prompt_injection=True
123
  )
124
  cxbt_assistant.knowledge_base.load(recreate=False)
125
 
 
129
  @cl.on_message
130
  async def main(message: cl.Message):
131
 
132
+ msg = cl.Message(content="")
133
+ await msg.send()
134
+
135
  # Retrieve the assistant from the user session
136
  agent = cl.user_session.get("agent")
137
 
138
  # Process the user message using the assistant
 
139
  for delta in agent.run(message.content, stream=True):
140
+ for part in delta:
141
+ if token := part or "":
142
+ # Send the response back to the user
143
+ await msg.stream_token(token)
144
+
145
+ await msg.update()
146
 
147
  # Run the Chainlit application
148
  if __name__ == "__main__":
docker-compose.yml CHANGED
@@ -3,7 +3,7 @@ services:
3
  image: chatxbt-web3-ai-assistant
4
  build: .
5
  ports:
6
- - "8080:8080"
7
  env_file:
8
  - .env
9
  depends_on:
 
3
  image: chatxbt-web3-ai-assistant
4
  build: .
5
  ports:
6
+ - "7860:7860"
7
  env_file:
8
  - .env
9
  depends_on:
pip ADDED
File without changes
requirements.txt CHANGED
@@ -8,12 +8,14 @@ anthropic==0.28.0
8
  anyio==3.7.1
9
  appdirs==1.4.4
10
  appnope==0.1.4
 
11
  asgiref==3.8.1
12
  asttokens==2.4.1
13
  async-timeout==4.0.3
14
  asyncer==0.0.2
15
  attrs==23.2.0
16
  backcall==0.2.0
 
17
  baize==0.20.8
18
  beautifulsoup4==4.12.3
19
  bidict==0.23.1
@@ -21,22 +23,26 @@ bitarray==2.9.2
21
  bleach==6.1.0
22
  boto3==1.34.106
23
  botocore==1.34.106
 
24
  certifi==2024.6.2
 
25
  chainlit==1.1.300
26
  charset-normalizer==3.3.2
27
- psycopg2-binary==2.9.9
28
  chevron==0.14.0
29
  ckzg==1.0.2
30
  click==8.1.7
31
  coingecko==0.13
 
32
  cytoolz==0.12.3
33
  dataclasses-json==0.5.14
34
  decorator==5.1.1
35
  defusedxml==0.7.1
36
  Deprecated==1.2.14
37
  distro==1.9.0
 
38
  docopt==0.6.2
39
  duckduckgo_search==6.1.6
 
40
  eth-account==0.11.2
41
  eth-hash==0.7.0
42
  eth-keyfile==0.8.1
@@ -47,7 +53,9 @@ eth-utils==4.1.1
47
  eth_abi==5.1.0
48
  exceptiongroup==1.2.1
49
  executing==2.0.1
50
- fastapi==0.110.3
 
 
51
  fastjsonschema==2.19.1
52
  filelock==3.15.1
53
  filetype==1.2.0
@@ -62,10 +70,12 @@ google_search_results==2.4.2
62
  googleapis-common-protos==1.63.1
63
  greenlet==3.0.3
64
  grpcio==1.64.1
 
65
  h11==0.14.0
66
  hexbytes==0.3.1
67
  html5lib==1.1
68
  httpcore==1.0.5
 
69
  httpx==0.27.0
70
  huggingface-hub==0.23.3
71
  idna==3.7
@@ -92,6 +102,7 @@ langchainhub==0.1.20
92
  langgraph==0.0.68
93
  langsmith==0.1.77
94
  Lazify==0.4.0
 
95
  literalai==0.0.604
96
  logfire==0.42.0
97
  lru-dict==1.2.0
@@ -104,6 +115,7 @@ mdurl==0.1.2
104
  mistune==3.0.2
105
  multidict==6.0.5
106
  multitasking==0.0.11
 
107
  mypy-extensions==1.0.0
108
  nbclient==0.10.0
109
  nbconvert==7.16.4
@@ -111,6 +123,7 @@ nbformat==5.10.4
111
  nest-asyncio==1.6.0
112
  numexpr==2.10.0
113
  numpy==1.26.4
 
114
  openai==1.34.0
115
  opentelemetry-api==1.25.0
116
  opentelemetry-exporter-otlp==1.25.0
@@ -142,6 +155,7 @@ pickleshare==0.7.5
142
  pipdeptree==2.22.0
143
  pipreqs==0.5.0
144
  platformdirs==4.2.2
 
145
  prompt_toolkit==3.0.47
146
  protobuf==4.25.3
147
  psutil==5.9.8
@@ -149,6 +163,7 @@ psycopg==3.1.19
149
  psycopg2==2.9.9
150
  ptyprocess==0.7.0
151
  pure-eval==0.2.2
 
152
  pycryptodome==3.20.0
153
  pydantic==2.7.4
154
  pydantic-settings==2.3.3
@@ -175,6 +190,7 @@ rich==13.7.1
175
  rlp==4.0.1
176
  rpc.py==0.6.0
177
  rpds-py==0.18.1
 
178
  s3fs==2024.6.0
179
  s3transfer==0.10.1
180
  shellingham==1.5.4
@@ -202,11 +218,13 @@ types-requests==2.32.0.20240602
202
  typing-inspect==0.9.0
203
  typing_extensions==4.12.2
204
  tzdata==2024.1
 
205
  ulid==1.1
206
  upstash-redis==1.1.0
207
  uptrace==1.24.0
208
  urllib3==2.2.1
209
- uvicorn==0.25.0
 
210
  watchfiles==0.20.0
211
  wcwidth==0.2.13
212
  web3==6.19.0
 
8
  anyio==3.7.1
9
  appdirs==1.4.4
10
  appnope==0.1.4
11
+ APScheduler==3.10.4
12
  asgiref==3.8.1
13
  asttokens==2.4.1
14
  async-timeout==4.0.3
15
  asyncer==0.0.2
16
  attrs==23.2.0
17
  backcall==0.2.0
18
+ backoff==2.2.1
19
  baize==0.20.8
20
  beautifulsoup4==4.12.3
21
  bidict==0.23.1
 
23
  bleach==6.1.0
24
  boto3==1.34.106
25
  botocore==1.34.106
26
+ cached-property==1.5.2
27
  certifi==2024.6.2
28
+ cffi==1.16.0
29
  chainlit==1.1.300
30
  charset-normalizer==3.3.2
 
31
  chevron==0.14.0
32
  ckzg==1.0.2
33
  click==8.1.7
34
  coingecko==0.13
35
+ cryptography==42.0.8
36
  cytoolz==0.12.3
37
  dataclasses-json==0.5.14
38
  decorator==5.1.1
39
  defusedxml==0.7.1
40
  Deprecated==1.2.14
41
  distro==1.9.0
42
+ dnspython==2.6.1
43
  docopt==0.6.2
44
  duckduckgo_search==6.1.6
45
+ email_validator==2.2.0
46
  eth-account==0.11.2
47
  eth-hash==0.7.0
48
  eth-keyfile==0.8.1
 
53
  eth_abi==5.1.0
54
  exceptiongroup==1.2.1
55
  executing==2.0.1
56
+ fastapi==0.111.1
57
+ fastapi-cli==0.0.4
58
+ fastapi-sso==0.10.0
59
  fastjsonschema==2.19.1
60
  filelock==3.15.1
61
  filetype==1.2.0
 
70
  googleapis-common-protos==1.63.1
71
  greenlet==3.0.3
72
  grpcio==1.64.1
73
+ gunicorn==22.0.0
74
  h11==0.14.0
75
  hexbytes==0.3.1
76
  html5lib==1.1
77
  httpcore==1.0.5
78
+ httptools==0.6.1
79
  httpx==0.27.0
80
  huggingface-hub==0.23.3
81
  idna==3.7
 
102
  langgraph==0.0.68
103
  langsmith==0.1.77
104
  Lazify==0.4.0
105
+ litellm==1.41.21
106
  literalai==0.0.604
107
  logfire==0.42.0
108
  lru-dict==1.2.0
 
115
  mistune==3.0.2
116
  multidict==6.0.5
117
  multitasking==0.0.11
118
+ mypy==1.10.1
119
  mypy-extensions==1.0.0
120
  nbclient==0.10.0
121
  nbconvert==7.16.4
 
123
  nest-asyncio==1.6.0
124
  numexpr==2.10.0
125
  numpy==1.26.4
126
+ oauthlib==3.2.2
127
  openai==1.34.0
128
  opentelemetry-api==1.25.0
129
  opentelemetry-exporter-otlp==1.25.0
 
155
  pipdeptree==2.22.0
156
  pipreqs==0.5.0
157
  platformdirs==4.2.2
158
+ portkey-ai==1.7.0
159
  prompt_toolkit==3.0.47
160
  protobuf==4.25.3
161
  psutil==5.9.8
 
163
  psycopg2==2.9.9
164
  ptyprocess==0.7.0
165
  pure-eval==0.2.2
166
+ pycparser==2.22
167
  pycryptodome==3.20.0
168
  pydantic==2.7.4
169
  pydantic-settings==2.3.3
 
190
  rlp==4.0.1
191
  rpc.py==0.6.0
192
  rpds-py==0.18.1
193
+ rq==1.16.2
194
  s3fs==2024.6.0
195
  s3transfer==0.10.1
196
  shellingham==1.5.4
 
218
  typing-inspect==0.9.0
219
  typing_extensions==4.12.2
220
  tzdata==2024.1
221
+ tzlocal==5.2
222
  ulid==1.1
223
  upstash-redis==1.1.0
224
  uptrace==1.24.0
225
  urllib3==2.2.1
226
+ uvicorn==0.22.0
227
+ uvloop==0.19.0
228
  watchfiles==0.20.0
229
  wcwidth==0.2.13
230
  web3==6.19.0
src/config/nemoguardrails/config.yml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # config.yml
2
+ models:
3
+ - type: main
4
+ engine: openai
5
+ model: gpt-3.5-turbo-instruct
6
+
7
+ rails:
8
+ # Input rails are invoked when new input from the user is received.
9
+ input:
10
+ flows:
11
+ - check jailbreak
12
+ - mask sensitive data on input
13
+
14
+ # Output rails are triggered after a bot message has been generated.
15
+ output:
16
+ flows:
17
+ - self check facts
18
+ - self check hallucination
19
+ - activefence moderation
20
+
21
+ config:
22
+ # Configure the types of entities that should be masked on user input.
23
+ sensitive_data_detection:
24
+ input:
25
+ entities:
26
+ - PERSON
27
+ - EMAIL_ADDRESS
src/config/portkey_config.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+ def generate_portkey_config(local: bool = True):
5
+ if local:
6
+ config = {
7
+ "strategy": {
8
+ "mode": "fallback"
9
+ },
10
+ "cache": {
11
+ "mode": "semantic",
12
+ "max_age": 10000
13
+ },
14
+ "retry": {
15
+ "attempts": 3,
16
+ "on_status_codes": [429]
17
+ },
18
+ "targets": [
19
+ # {
20
+ # "provider": "mistral-ai",
21
+ # "api_key": os.getenv("MISTRAL_API_KEY"),
22
+ # "override_params": {
23
+ # "model": "codestral-latest",
24
+ # "max_tokens": 1024,
25
+ # "temperature": 0
26
+ # }
27
+ # },
28
+ {
29
+ "provider": "anthropic",
30
+ "api_key": os.getenv("ANTHROPIC_API_KEY"),
31
+ "override_params": {
32
+ "model": "claude-3-5-sonnet-20240620",
33
+ "max_tokens": 1024,
34
+ "temperature": 0
35
+ }
36
+ },
37
+ {
38
+ "provider": "openai",
39
+ "api_key": os.getenv("OPENAI_API_KEY"),
40
+ "override_params": {
41
+ "model": "gpt-4o",
42
+ "max_tokens": 1024,
43
+ "temperature": 0
44
+ }
45
+ },
46
+ {
47
+ "provider": "anthropic",
48
+ "api_key": os.getenv("ANTHROPIC_API_KEY"),
49
+ "override_params": {
50
+ "model": "claude-3-opus-20240229",
51
+ "max_tokens": 1024,
52
+ "temperature": 0
53
+ }
54
+ }
55
+ ]
56
+ }
57
+ else:
58
+ config = {
59
+ "strategy": {
60
+ "mode": "fallback"
61
+ },
62
+ "cache": {
63
+ "mode": "semantic",
64
+ "max_age": 10000
65
+ },
66
+ "retry": {
67
+ "attempts": 3,
68
+ "on_status_codes": [429]
69
+ },
70
+ "targets": [
71
+
72
+ {
73
+ "virtual_key": os.getenv("PORTKEY_OPENAI_VIRTUAL_KEY"),
74
+ "override_params": {
75
+ "model": "gpt-4o",
76
+ "max_tokens": 1024,
77
+ "temperature": 0
78
+ }
79
+ },
80
+ {
81
+ "provider": "anthropic",
82
+ "api_key": os.getenv("POETRY_ANTHROPIC_API_KEY"),
83
+ "override_params": {
84
+ "model": "claude-3-5-sonnet-20240620",
85
+ "max_tokens": 1024,
86
+ "temperature": 0
87
+ }
88
+ },
89
+ {
90
+ "virtual_key": os.getenv("PORTKEY_ANTHROPIC_API_KEY"),
91
+ "override_params": {
92
+ "model": "claude-3-opus-20240229",
93
+ "max_tokens": 1024,
94
+ "temperature": 0
95
+ }
96
+ },
97
+ {
98
+ "virtual_key": os.getenv("PORTKEY_MISTRAL_API_KEY"),
99
+ "override_params": {
100
+ "model": "codestral-latest",
101
+ "max_tokens": 1024,
102
+ "temperature": 0
103
+ }
104
+ }
105
+ ]
106
+ }
107
+
108
+ return json.dumps(config)
src/libs/rpc_client.py CHANGED
@@ -1,7 +1,6 @@
1
  import httpx, uuid, os
2
  from typing import Optional, Union
3
  from dotenv import load_dotenv
4
- from src.libs.logger import logger
5
 
6
  load_dotenv()
7
 
@@ -10,7 +9,8 @@ rpc_server_url = os.getenv('CHATXBT_RPC_SERVER_URL')
10
  async def rpc_call(
11
  method_name: str, # The name of the RPC method to be called
12
  params: Optional[Union[dict, list]] = None, # Optional parameters for the RPC method
13
- url: str = rpc_server_url # The URL of the RPC server
 
14
  ) -> dict: # Returns the JSON response from the RPC server
15
  """
16
  This function makes an RPC call to the specified URL with the given method name and parameters.
@@ -44,10 +44,10 @@ async def rpc_call(
44
  }
45
 
46
  try:
47
- async with httpx.AsyncClient() as client:
48
  response = await client.post(url, json=payload, headers=headers, auth=auth)
49
  response.raise_for_status()
50
  return response.json()
51
  except httpx.RequestError as e:
52
  print(f"Error making RPC call: {e}")
53
- return None
 
1
  import httpx, uuid, os
2
  from typing import Optional, Union
3
  from dotenv import load_dotenv
 
4
 
5
  load_dotenv()
6
 
 
9
  async def rpc_call(
10
  method_name: str, # The name of the RPC method to be called
11
  params: Optional[Union[dict, list]] = None, # Optional parameters for the RPC method
12
+ url: str = rpc_server_url, # The URL of the RPC server
13
+ timeout: int = 60 # Timeout in seconds
14
  ) -> dict: # Returns the JSON response from the RPC server
15
  """
16
  This function makes an RPC call to the specified URL with the given method name and parameters.
 
44
  }
45
 
46
  try:
47
+ async with httpx.AsyncClient(timeout=timeout) as client:
48
  response = await client.post(url, json=payload, headers=headers, auth=auth)
49
  response.raise_for_status()
50
  return response.json()
51
  except httpx.RequestError as e:
52
  print(f"Error making RPC call: {e}")
53
+ raise ValueError(f"Error making RPC call: {e}")
src/tools/crypto_bridge_toolkit.py CHANGED
@@ -33,20 +33,22 @@ class CrossChainSwapTools(Toolkit):
33
  chainId: int,
34
  amountLD: str,
35
  recipient: str,
36
- wallet: Any,
37
- tokenIn: Any,
38
- tokenOut: Any
 
39
  ) -> str:
40
  """
41
- Performs a cross-chain token swap.
42
 
43
  Parameters:
44
  - chainId (int): The ID of the chain.
45
  - amountLD (str): The amount to be swapped, in lowest denomination (e.g., wei for ETH).
46
  - recipient (str): The recipient address.
47
- - wallet (WalletParams): The wallet parameters.
48
- - tokenIn (TokenParams): The input token parameters.
49
- - tokenOut (TokenParams): The output token parameters.
 
50
 
51
  Returns:
52
  - str: A string representation of the response from the RPC call.
@@ -63,7 +65,13 @@ class CrossChainSwapTools(Toolkit):
63
  'chainId': chainId,
64
  'amountLD': amountLD,
65
  'recipient': recipient,
66
- 'wallet': wallet,
 
 
 
 
 
 
67
  'tokenIn': tokenIn,
68
  'tokenOut': tokenOut,
69
  }
@@ -95,7 +103,8 @@ class CrossChainSwapTools(Toolkit):
95
 
96
  def get_cross_chain_swap_token_list(self, chainId: int) -> str:
97
  """
98
- Fetches the list of supported cross-chain swap tokens on the specified chainId.
 
99
 
100
  Parameters:
101
  - chainId (int): The ID of the chain.
 
33
  chainId: int,
34
  amountLD: str,
35
  recipient: str,
36
+ user_email: str,
37
+ tokenIn: str,
38
+ tokenOut: str,
39
+ chain: str = "base",
40
  ) -> str:
41
  """
42
+ Performs a cross-chain token swap. this is a sensitive function, show a preview and allow user to give final permission to execute function
43
 
44
  Parameters:
45
  - chainId (int): The ID of the chain.
46
  - amountLD (str): The amount to be swapped, in lowest denomination (e.g., wei for ETH).
47
  - recipient (str): The recipient address.
48
+ - user_email (str): The email of the user for whom the wallet is being fetched and used to sign the transaction.
49
+ - tokenIn (TokenParams): The input token parameters as structured from: get_cross_chain_swap_token_list. stringify object
50
+ - tokenOut (TokenParams): The output token parameters as structured from: get_cross_chain_swap_token_list. stringify object
51
+ - chain (str): The EVM chain for which the wallet is being fetched and used to execute this transaction. use chain base as default
52
 
53
  Returns:
54
  - str: A string representation of the response from the RPC call.
 
65
  'chainId': chainId,
66
  'amountLD': amountLD,
67
  'recipient': recipient,
68
+ 'wallet': {
69
+ "userEmail": user_email,
70
+ "chain": chain,
71
+ "testnet": True,
72
+ "gasless": True,
73
+ "connected": True
74
+ },
75
  'tokenIn': tokenIn,
76
  'tokenOut': tokenOut,
77
  }
 
103
 
104
  def get_cross_chain_swap_token_list(self, chainId: int) -> str:
105
  """
106
+ Fetches the list of supported cross-chain swap tokens on the specified chainId. always call before executing
107
+ cross_chain_swap to get accurate tokenIn and tokenOut data
108
 
109
  Parameters:
110
  - chainId (int): The ID of the chain.
src/tools/crypto_evm_wallet_toolkit.py CHANGED
@@ -9,9 +9,12 @@ class CryptoEVMWalletTools(Toolkit):
9
  super().__init__(name="crypto_evm_wallet_tools")
10
 
11
  # Registering methods to make them accessible via the toolkit
12
- self.register(self.get_evm_wallet_address)
13
  self.register(self.get_supported_evm_chains)
14
  self.register(self.get_evm_smart_wallet_address)
 
 
 
15
  self.chains = self.get_supported_evm_chains()
16
 
17
  def get_supported_evm_chains(self) -> list[str]:
@@ -30,14 +33,50 @@ class CryptoEVMWalletTools(Toolkit):
30
  response = asyncio.run(rpc_call(method_name="getEVMSupportedChains", params=params))
31
  return f"{response}"
32
 
33
- def get_evm_wallet_address(self, user_email: str, chain: str, testnet: bool = True) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  """
35
- Fetches an EVM wallet address for the given user email and supported chain.
36
- Creates and returns an EVM wallet address for the given user email and supported chain.
37
 
38
  Parameters:
39
- - user_email (str): The email of the user for whom the wallet is being created.
40
  - chain (ethereum | binance | base | polygon): The EVM chain for which the wallet is being fetched.
 
41
  - testnet (bool, optional): A flag indicating whether the wallet should be on the testnet. Defaults to `True`.
42
 
43
  Returns:
@@ -47,37 +86,37 @@ class CryptoEVMWalletTools(Toolkit):
47
  None
48
 
49
  Note:
50
- This method uses asyncio.run() to run the asynchronous RPC call.
51
  """
52
- logger.info(f"Creating crypto wallet account for {user_email}")
53
 
54
  params = {
55
  'chain': chain,
 
56
  'testnet': testnet,
57
  'userEmail': user_email,
58
  }
59
- response = asyncio.run(rpc_call(method_name="getEVMWallet", params=params))
60
  return f"{response}"
61
 
62
- def get_evm_smart_wallet_address(
63
  self,
 
64
  user_email: str,
65
  chain: str,
66
- gasless: bool = True,
67
  testnet: bool = True
68
  ) -> str:
69
  """
70
- Fetches a smart EVM wallet address for the given user email and supported chain.
71
- Creates and returns a smart EVM wallet address for the given user email and supported chain.
72
 
73
  Parameters:
 
74
  - user_email (str): The email of the user for whom the wallet is being fetched.
75
- - chain (ethereum | binance | base | polygon): The EVM chain for which the wallet is being fetched.
76
- - gasless (bool, optional): A flag indicating whether the wallet should be gasless. Defaults to `True`.
77
  - testnet (bool, optional): A flag indicating whether the wallet should be on the testnet. Defaults to `True`.
78
 
79
  Returns:
80
- - str: A string representation of the response from the RPC call.
81
 
82
  Raises:
83
  None
@@ -89,9 +128,9 @@ class CryptoEVMWalletTools(Toolkit):
89
 
90
  params = {
91
  'chain': chain,
92
- 'gasless': gasless,
93
  'testnet': testnet,
94
  'userEmail': user_email,
95
  }
96
- response = asyncio.run(rpc_call(method_name="getEVMSmartWallet", params=params))
97
  return f"{response}"
 
9
  super().__init__(name="crypto_evm_wallet_tools")
10
 
11
  # Registering methods to make them accessible via the toolkit
12
+ # self.register(self.get_evm_wallet_address)
13
  self.register(self.get_supported_evm_chains)
14
  self.register(self.get_evm_smart_wallet_address)
15
+ self.register(self.get_evm_smart_wallet_balances)
16
+
17
+ # Fetching the list of supported EVM chains
18
  self.chains = self.get_supported_evm_chains()
19
 
20
  def get_supported_evm_chains(self) -> list[str]:
 
33
  response = asyncio.run(rpc_call(method_name="getEVMSupportedChains", params=params))
34
  return f"{response}"
35
 
36
+ # def get_evm_wallet_address(self, user_email: str, chain: str, testnet: bool = True) -> str:
37
+ # """
38
+ # Fetches an EVM wallet address for the given user email and supported chain.
39
+ # Creates and returns an EVM wallet address for the given user email and supported chain.
40
+
41
+ # Parameters:
42
+ # - user_email (str): The email of the user for whom the wallet is being created.
43
+ # - chain (ethereum | binance | base | polygon): The EVM chain for which the wallet is being fetched.
44
+ # - testnet (bool, optional): A flag indicating whether the wallet should be on the testnet. Defaults to `True`.
45
+
46
+ # Returns:
47
+ # - str: A string representation of the response from the RPC call.
48
+
49
+ # Raises:
50
+ # None
51
+
52
+ # Note:
53
+ # This method uses asyncio.run() to run the asynchronous RPC call.
54
+ # """
55
+ # logger.info(f"Creating crypto wallet account for {user_email}")
56
+
57
+ # params = {
58
+ # 'chain': chain,
59
+ # 'testnet': testnet,
60
+ # 'userEmail': user_email,
61
+ # }
62
+ # response = asyncio.run(rpc_call(method_name="getEVMWallet", params=params))
63
+ # return f"{response}"
64
+
65
+ def get_evm_smart_wallet_address(
66
+ self,
67
+ user_email: str,
68
+ chain: str,
69
+ gasless: bool = True,
70
+ testnet: bool = True
71
+ ) -> str:
72
  """
73
+ Fetches a smart EVM wallet address for the given user email and supported chain.
74
+ Creates and returns a smart EVM wallet address for the given user email and supported chain.
75
 
76
  Parameters:
77
+ - user_email (str): The email of the user for whom the wallet is being fetched.
78
  - chain (ethereum | binance | base | polygon): The EVM chain for which the wallet is being fetched.
79
+ - gasless (bool, optional): A flag indicating whether the wallet should be gasless. Defaults to `True`.
80
  - testnet (bool, optional): A flag indicating whether the wallet should be on the testnet. Defaults to `True`.
81
 
82
  Returns:
 
86
  None
87
 
88
  Note:
89
+ This method uses `asyncio.run()` to run the asynchronous RPC call.
90
  """
91
+ logger.info(f"Fetching crypto wallet account for {user_email}")
92
 
93
  params = {
94
  'chain': chain,
95
+ 'gasless': gasless,
96
  'testnet': testnet,
97
  'userEmail': user_email,
98
  }
99
+ response = asyncio.run(rpc_call(method_name="getEVMSmartWallet", params=params))
100
  return f"{response}"
101
 
102
+ def get_evm_smart_wallet_balances(
103
  self,
104
+ address: str,
105
  user_email: str,
106
  chain: str,
 
107
  testnet: bool = True
108
  ) -> str:
109
  """
110
+ Fetches the balances of a smart EVM wallet address for the given user email and supported chain.
 
111
 
112
  Parameters:
113
+ - address (str): The address of the smart EVM wallet for which the balances are being fetched.
114
  - user_email (str): The email of the user for whom the wallet is being fetched.
115
+ - chain (str): The EVM chain for which the wallet is being fetched.
 
116
  - testnet (bool, optional): A flag indicating whether the wallet should be on the testnet. Defaults to `True`.
117
 
118
  Returns:
119
+ - str: A string representation of the response from the RPC call containing the balances of the smart EVM wallet address.
120
 
121
  Raises:
122
  None
 
128
 
129
  params = {
130
  'chain': chain,
131
+ 'address': address,
132
  'testnet': testnet,
133
  'userEmail': user_email,
134
  }
135
+ response = asyncio.run(rpc_call(method_name="getEVMSmartWalletAddressBalances", params=params))
136
  return f"{response}"
src/tools/crypto_swap_toolkit.py CHANGED
@@ -26,7 +26,7 @@ class CryptoSwapTools(Toolkit):
26
  self.register(self.get_swap_sources)
27
  self.register(self.execute_swap)
28
 
29
- def get_swap_quote(self, buy_token: str, sell_token: str, sell_amount: str) -> str:
30
  """
31
  Fetches a swap quote from the 0x Swap API.
32
 
@@ -46,7 +46,14 @@ class CryptoSwapTools(Toolkit):
46
  params = {
47
  'buyToken': buy_token,
48
  'sellToken': sell_token,
49
- 'sellAmount': sell_amount
 
 
 
 
 
 
 
50
  }
51
  response = asyncio.run(rpc_call(method_name="getSwapQuote", params=params))
52
  return f"{response}"
@@ -55,7 +62,7 @@ class CryptoSwapTools(Toolkit):
55
  # return {"error": str(e)}
56
  return f"Error: {e}"
57
 
58
- def get_swap_price(self, buy_token: str, sell_token: str, buy_amount: str) -> str:
59
  """
60
  Fetches the price for a swap from the 0x Swap API.
61
 
@@ -75,7 +82,14 @@ class CryptoSwapTools(Toolkit):
75
  params = {
76
  'buyToken': buy_token,
77
  'sellToken': sell_token,
78
- 'buyAmount': buy_amount
 
 
 
 
 
 
 
79
  }
80
  response = asyncio.run(rpc_call(method_name="getSwapPrice", params=params))
81
  return f"{response}"
@@ -99,35 +113,49 @@ class CryptoSwapTools(Toolkit):
99
  response = asyncio.run(rpc_call(method_name="getSwapSources"))
100
  return f"{response}"
101
 
102
- def execute_swap(self, buy_token: str, sell_token: str, sell_amount: str, eth_address: str) -> str:
 
 
 
 
 
 
 
103
  """
104
- Executes a swap using the 0x Swap API.
105
 
106
  Args:
107
- buy_token (str): The token to buy (e.g., 'DAI').
108
- sell_token (str): The token to sell (e.g., 'ETH').
109
- sell_amount (str): The amount of the sell token to swap, in the smallest unit (e.g., wei for ETH).
110
- eth_address (str): The Ethereum address of the user executing the swap.
 
111
 
112
  Returns:
113
  dict: The transaction receipt of the swap transaction.
114
 
115
  Example:
116
- >>> execute_swap('DAI', 'ETH', '1000000000000000000', '0xYourEthereumAddress')
117
  """
118
- logger.info(f"wap token: buying {buy_token} with {sell_token} amount {sell_amount}")
 
119
  try:
120
  params = {
121
  'buyToken': buy_token,
122
  'sellToken': sell_token,
123
  'sellAmount': sell_amount,
124
  'wallet': {
125
-
 
 
 
 
126
  }
127
  }
128
  response = asyncio.run(rpc_call(method_name="swapTokens", params=params))
 
129
  return f"{response}"
130
  except requests.exceptions.RequestException as e:
131
- logger.warning(f"Failed to swap tokens: {e}")
132
  # return {"error": str(e)}
133
  return f"Error: {e}"
 
26
  self.register(self.get_swap_sources)
27
  self.register(self.execute_swap)
28
 
29
+ def get_swap_quote(self, buy_token: str, sell_token: str, sell_amount: str, chain: str = "base") -> str:
30
  """
31
  Fetches a swap quote from the 0x Swap API.
32
 
 
46
  params = {
47
  'buyToken': buy_token,
48
  'sellToken': sell_token,
49
+ 'sellAmount': sell_amount,
50
+ 'wallet': {
51
+ "userEmail": "none",
52
+ "chain": chain,
53
+ "testnet": True,
54
+ "gasless": True,
55
+ "connected": True
56
+ }
57
  }
58
  response = asyncio.run(rpc_call(method_name="getSwapQuote", params=params))
59
  return f"{response}"
 
62
  # return {"error": str(e)}
63
  return f"Error: {e}"
64
 
65
+ def get_swap_price(self, buy_token: str, sell_token: str, buy_amount: str, chain: str = "base") -> str:
66
  """
67
  Fetches the price for a swap from the 0x Swap API.
68
 
 
82
  params = {
83
  'buyToken': buy_token,
84
  'sellToken': sell_token,
85
+ 'buyAmount': buy_amount,
86
+ 'wallet': {
87
+ "userEmail": "none",
88
+ "chain": chain,
89
+ "testnet": True,
90
+ "gasless": True,
91
+ "connected": True
92
+ }
93
  }
94
  response = asyncio.run(rpc_call(method_name="getSwapPrice", params=params))
95
  return f"{response}"
 
113
  response = asyncio.run(rpc_call(method_name="getSwapSources"))
114
  return f"{response}"
115
 
116
+ def execute_swap(
117
+ self,
118
+ buy_token: str,
119
+ sell_token: str,
120
+ sell_amount: str,
121
+ user_email: str,
122
+ chain: str = "base",
123
+ ) -> str:
124
  """
125
+ Executes a swap using the 0x Swap API. this is a sensitive function, show a preview and allow user to give final permission to execute function
126
 
127
  Args:
128
+ -buy_token (str): The token to buy (e.g., 'DAI').
129
+ -sell_token (str): The token to sell (e.g., 'ETH').
130
+ -sell_amount (str): The amount of the sell token to swap, in the smallest unit (e.g., wei for ETH).
131
+ - user_email (str): The email of the user for whom the wallet is being fetched.
132
+ - chain (str): The EVM chain for which the wallet is being fetched and used to execute this transaction. use chain base as default
133
 
134
  Returns:
135
  dict: The transaction receipt of the swap transaction.
136
 
137
  Example:
138
+ >>> execute_swap('DAI', 'ETH', '1000000000000000000', 'userEmail', 'base')
139
  """
140
+
141
+ logger.info("executing swap")
142
  try:
143
  params = {
144
  'buyToken': buy_token,
145
  'sellToken': sell_token,
146
  'sellAmount': sell_amount,
147
  'wallet': {
148
+ "userEmail": user_email,
149
+ "chain": chain,
150
+ "testnet": True,
151
+ "gasless": True,
152
+ "connected": True
153
  }
154
  }
155
  response = asyncio.run(rpc_call(method_name="swapTokens", params=params))
156
+ logger.info(f"Swap transaction receipt: {response}")
157
  return f"{response}"
158
  except requests.exceptions.RequestException as e:
159
+ logger.warning(f"Failed to execute swap: {e}")
160
  # return {"error": str(e)}
161
  return f"Error: {e}"
src/tools/user_confirmation_pin_toolkit.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import chainlit as cl
3
+ from phi.tools import Toolkit
4
+ from phi.utils.log import logger
5
+
6
+ from src.libs.rpc_client import rpc_call
7
+
8
+
9
+ class UserConfirmationPinToolkit(Toolkit):
10
+ def __init__(self):
11
+ super().__init__(name="user_confirmation_pin_toolkit")
12
+
13
+ # Registering methods to make them accessible via the toolkit
14
+ self.register(self.has_user_confirmation_pin)
15
+ self.register(self.set_user_confirmation_pin)
16
+ self.register(self.update_user_confirmation_pin)
17
+ self.register(self.verify_user_confirmation_pin)
18
+
19
+ def has_user_confirmation_pin(self, user_id: str) -> str:
20
+ """
21
+ Checks if a user has a confirmation PIN.
22
+
23
+ This method takes a user's ID and checks if the user has a confirmation
24
+ PIN via a remote procedure call (RPC).
25
+
26
+ Args:
27
+ user_id (str): The ID of the user to check for a confirmation PIN.
28
+
29
+ Returns:
30
+ str: The response from the RPC call indicating if the user has a PIN.
31
+ """
32
+ logger.info("Checking if user has confirmation pin")
33
+
34
+ params = {
35
+ "userId": user_id,
36
+ }
37
+ response = asyncio.run(rpc_call(method_name="hasUserPin", params=params))
38
+ return f"{response}"
39
+
40
+ def set_user_confirmation_pin(self, user_id: str, pin: str) -> str:
41
+ """
42
+ Sets a user's confirmation PIN.
43
+
44
+ This method takes a user's ID and a new PIN, and sets the user's PIN
45
+ via a remote procedure call (RPC).
46
+
47
+ Args:
48
+ user_id (str): The ID of the user whose PIN is to be set.
49
+ pin (str): The new confirmation PIN to be set.
50
+
51
+ Returns:
52
+ str: The response from the RPC call setting the PIN.
53
+ """
54
+ logger.info("Setting user confirmation pin")
55
+
56
+ params = {
57
+ "userId": user_id,
58
+ "pin": pin
59
+ }
60
+ response = asyncio.run(rpc_call(method_name="setUserPin", params=params))
61
+ return f"{response}"
62
+
63
+ def update_user_confirmation_pin(self, user_id: str, pin: str) -> str:
64
+ """
65
+ Updates a user's confirmation PIN.
66
+
67
+ This method takes a user's ID and a new PIN, and updates the user's PIN
68
+ via a remote procedure call (RPC).
69
+
70
+ Args:
71
+ user_id (str): The ID of the user whose PIN is to be updated.
72
+ pin (str): The new confirmation PIN to be set.
73
+
74
+ Returns:
75
+ str: The response from the RPC call updating the PIN.
76
+ """
77
+ logger.info("Updating user confirmation pin")
78
+
79
+ params = {
80
+ "userId": user_id,
81
+ "pin": pin
82
+ }
83
+ response = asyncio.run(rpc_call(method_name="updateUserPin", params=params))
84
+ return f"{response}"
85
+
86
+ def verify_user_confirmation_pin(self, user_id: str, pin: str) -> str:
87
+ """
88
+ Verifies a user's confirmation PIN.
89
+
90
+ This method takes a user's ID and a PIN, converts the email to lowercase,
91
+ and verifies the PIN via a remote procedure call (RPC).
92
+
93
+ Args:
94
+ user_id (str): The ID of the user whose PIN is to be verified.
95
+ pin (str): The confirmation PIN to be verified.
96
+
97
+ Returns:
98
+ str: The response from the RPC call verifying the PIN.
99
+ """
100
+ logger.info("Verifying user confirmation pin")
101
+
102
+ params = {
103
+ "userId": user_id,
104
+ "pin": pin
105
+ }
106
+ response = asyncio.run(rpc_call(method_name="verifyUserPin", params=params))
107
+ return f"{response}"
src/tools/user_profile_toolkit.py CHANGED
@@ -1,7 +1,10 @@
 
1
  import chainlit as cl
2
  from phi.tools import Toolkit
3
  from phi.utils.log import logger
4
 
 
 
5
 
6
  class UserProfileToolkit(Toolkit):
7
  def __init__(self):
@@ -16,10 +19,13 @@ class UserProfileToolkit(Toolkit):
16
  self.register(self.update_user_name)
17
  self.register(self.update_user_email)
18
  self.register(self.update_user_picture)
19
- self.allUserInfo = self.get_all_user_info()
 
 
 
20
 
21
  @cl.on_chat_start
22
- def get_user_info(self, info_type: str = "name") -> str:
23
  """
24
  Fetches user information from the Chainlit user session.
25
 
@@ -164,7 +170,7 @@ class UserProfileToolkit(Toolkit):
164
  str: Confirmation message.
165
 
166
  Example:
167
- >>> update_user_email('jane.doe@example.com')
168
  """
169
  response = self.update_user_info('email', email)
170
  return f"{response}"
@@ -184,3 +190,24 @@ class UserProfileToolkit(Toolkit):
184
  """
185
  response = self.update_user_info('picture', picture)
186
  return f"{response}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
  import chainlit as cl
3
  from phi.tools import Toolkit
4
  from phi.utils.log import logger
5
 
6
+ from src.libs.rpc_client import rpc_call
7
+
8
 
9
  class UserProfileToolkit(Toolkit):
10
  def __init__(self):
 
19
  self.register(self.update_user_name)
20
  self.register(self.update_user_email)
21
  self.register(self.update_user_picture)
22
+ self.register(self.get_user_id)
23
+
24
+ # fetching user email
25
+ self.email = self.get_user_email()
26
 
27
  @cl.on_chat_start
28
+ def get_user_info(self, info_type: str) -> str:
29
  """
30
  Fetches user information from the Chainlit user session.
31
 
 
170
  str: Confirmation message.
171
 
172
  Example:
173
+ >>> update_user_email('jane.doe@chatxbt.com')
174
  """
175
  response = self.update_user_info('email', email)
176
  return f"{response}"
 
190
  """
191
  response = self.update_user_info('picture', picture)
192
  return f"{response}"
193
+
194
+ def get_user_id(self, user_email: str) -> str:
195
+ """
196
+ Fetches the ChatXBT ID of the user associated with the given email.
197
+
198
+ Args:
199
+ user_email (str): The email address of the user whose ChatXBT ID needs to be fetched.
200
+
201
+ Returns:
202
+ str]: A string containing the ChatXBT ID of the user. If the user is not found, an empty string is returned.
203
+
204
+ Example:
205
+ >>> get_user_id('jane.doe@chatxbt.com')
206
+ """
207
+ logger.info("Fetching user ChatXBT ID")
208
+
209
+ params = {
210
+ "userEmail": user_email.lower()
211
+ }
212
+ response = asyncio.run(rpc_call(method_name="getUserId", params=params))
213
+ return f"{response}"