intentkit 0.5.2__py3-none-any.whl → 0.6.0__py3-none-any.whl
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.
Potentially problematic release.
This version of intentkit might be problematic. Click here for more details.
- intentkit/__init__.py +1 -1
- intentkit/abstracts/skill.py +12 -0
- intentkit/clients/cdp.py +114 -16
- intentkit/config/config.py +12 -4
- intentkit/core/engine.py +39 -31
- intentkit/core/node.py +8 -4
- intentkit/core/prompt.py +5 -6
- intentkit/core/skill.py +11 -0
- intentkit/models/agent.py +2 -9
- intentkit/models/agent_data.py +18 -0
- intentkit/models/agent_schema.json +12 -0
- intentkit/models/chat.py +50 -0
- intentkit/models/skill.py +19 -0
- intentkit/skills/base.py +37 -17
- intentkit/skills/cdp/__init__.py +6 -14
- intentkit/skills/cdp/get_balance.py +77 -25
- intentkit/skills/cdp/schema.json +0 -64
- intentkit/skills/cryptocompare/fetch_news.py +2 -2
- intentkit/skills/cryptocompare/fetch_price.py +2 -2
- intentkit/skills/cryptocompare/fetch_top_exchanges.py +2 -2
- intentkit/skills/cryptocompare/fetch_top_market_cap.py +2 -2
- intentkit/skills/cryptocompare/fetch_top_volume.py +2 -2
- intentkit/skills/cryptocompare/fetch_trading_signals.py +2 -2
- intentkit/skills/defillama/base.py +3 -3
- intentkit/skills/enso/base.py +27 -4
- intentkit/skills/enso/networks.py +1 -1
- intentkit/skills/enso/route.py +24 -23
- intentkit/skills/enso/tokens.py +1 -1
- intentkit/skills/enso/wallet.py +27 -23
- intentkit/skills/firecrawl/README.md +211 -0
- intentkit/skills/firecrawl/__init__.py +107 -0
- intentkit/skills/firecrawl/base.py +28 -0
- intentkit/skills/firecrawl/clear.py +87 -0
- intentkit/skills/firecrawl/crawl.py +399 -0
- intentkit/skills/firecrawl/firecrawl.png +0 -0
- intentkit/skills/firecrawl/query.py +123 -0
- intentkit/skills/firecrawl/schema.json +153 -0
- intentkit/skills/firecrawl/scrape.py +318 -0
- intentkit/skills/firecrawl/utils.py +306 -0
- intentkit/skills/heurist/image_generation_animagine_xl.py +1 -1
- intentkit/skills/heurist/image_generation_arthemy_comics.py +1 -1
- intentkit/skills/heurist/image_generation_arthemy_real.py +1 -1
- intentkit/skills/heurist/image_generation_braindance.py +1 -1
- intentkit/skills/heurist/image_generation_cyber_realistic_xl.py +1 -1
- intentkit/skills/heurist/image_generation_flux_1_dev.py +1 -1
- intentkit/skills/heurist/image_generation_sdxl.py +1 -1
- intentkit/skills/http/README.md +78 -0
- intentkit/skills/http/__init__.py +100 -0
- intentkit/skills/http/base.py +21 -0
- intentkit/skills/http/get.py +96 -0
- intentkit/skills/http/http.svg +15 -0
- intentkit/skills/http/post.py +113 -0
- intentkit/skills/http/put.py +113 -0
- intentkit/skills/http/schema.json +80 -0
- intentkit/skills/lifi/token_execute.py +1 -1
- intentkit/skills/openai/dalle_image_generation.py +1 -1
- intentkit/skills/openai/gpt_image_generation.py +1 -1
- intentkit/skills/openai/gpt_image_to_image.py +1 -1
- intentkit/skills/supabase/__init__.py +116 -0
- intentkit/skills/supabase/base.py +72 -0
- intentkit/skills/supabase/delete_data.py +102 -0
- intentkit/skills/supabase/fetch_data.py +120 -0
- intentkit/skills/supabase/insert_data.py +70 -0
- intentkit/skills/supabase/invoke_function.py +74 -0
- intentkit/skills/supabase/schema.json +170 -0
- intentkit/skills/supabase/supabase.svg +15 -0
- intentkit/skills/supabase/update_data.py +105 -0
- intentkit/skills/supabase/upsert_data.py +77 -0
- intentkit/skills/system/read_agent_api_key.py +1 -1
- intentkit/skills/system/regenerate_agent_api_key.py +1 -1
- intentkit/skills/token/base.py +1 -39
- intentkit/skills/twitter/follow_user.py +3 -3
- intentkit/skills/twitter/get_mentions.py +6 -6
- intentkit/skills/twitter/get_timeline.py +5 -5
- intentkit/skills/twitter/get_user_by_username.py +3 -3
- intentkit/skills/twitter/get_user_tweets.py +5 -5
- intentkit/skills/twitter/like_tweet.py +3 -3
- intentkit/skills/twitter/post_tweet.py +4 -4
- intentkit/skills/twitter/reply_tweet.py +4 -4
- intentkit/skills/twitter/retweet.py +3 -3
- intentkit/skills/twitter/search_tweets.py +5 -5
- intentkit/skills/unrealspeech/text_to_speech.py +1 -1
- intentkit/skills/web_scraper/README.md +35 -4
- intentkit/skills/web_scraper/__init__.py +16 -0
- intentkit/skills/web_scraper/document_indexer.py +143 -0
- intentkit/skills/web_scraper/schema.json +28 -0
- intentkit/skills/web_scraper/scrape_and_index.py +135 -200
- intentkit/skills/web_scraper/utils.py +684 -0
- intentkit/skills/web_scraper/website_indexer.py +456 -0
- intentkit/utils/logging.py +1 -1
- {intentkit-0.5.2.dist-info → intentkit-0.6.0.dist-info}/METADATA +1 -1
- {intentkit-0.5.2.dist-info → intentkit-0.6.0.dist-info}/RECORD +94 -63
- {intentkit-0.5.2.dist-info → intentkit-0.6.0.dist-info}/WHEEL +0 -0
- {intentkit-0.5.2.dist-info → intentkit-0.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"title": "Supabase",
|
|
5
|
+
"description": "Integration with Supabase backend-as-a-service platform enabling database operations and Edge Function invocations",
|
|
6
|
+
"x-icon": "https://ai.service.crestal.dev/skills/supabase/supabase.svg",
|
|
7
|
+
"x-tags": [
|
|
8
|
+
"Database",
|
|
9
|
+
"Backend"
|
|
10
|
+
],
|
|
11
|
+
"properties": {
|
|
12
|
+
"enabled": {
|
|
13
|
+
"type": "boolean",
|
|
14
|
+
"title": "Enabled",
|
|
15
|
+
"description": "Whether this skill is enabled",
|
|
16
|
+
"default": false
|
|
17
|
+
},
|
|
18
|
+
"states": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"fetch_data": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"title": "Fetch Data",
|
|
24
|
+
"enum": [
|
|
25
|
+
"disabled",
|
|
26
|
+
"public",
|
|
27
|
+
"private"
|
|
28
|
+
],
|
|
29
|
+
"x-enum-title": [
|
|
30
|
+
"Disabled",
|
|
31
|
+
"Agent Owner + All Users",
|
|
32
|
+
"Agent Owner Only"
|
|
33
|
+
],
|
|
34
|
+
"description": "Fetch data from Supabase tables with filtering, ordering, and pagination support",
|
|
35
|
+
"default": "disabled"
|
|
36
|
+
},
|
|
37
|
+
"insert_data": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"title": "Insert Data",
|
|
40
|
+
"enum": [
|
|
41
|
+
"disabled",
|
|
42
|
+
"public",
|
|
43
|
+
"private"
|
|
44
|
+
],
|
|
45
|
+
"x-enum-title": [
|
|
46
|
+
"Disabled",
|
|
47
|
+
"Agent Owner + All Users",
|
|
48
|
+
"Agent Owner Only"
|
|
49
|
+
],
|
|
50
|
+
"description": "Insert new records into Supabase tables",
|
|
51
|
+
"default": "disabled"
|
|
52
|
+
},
|
|
53
|
+
"update_data": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"title": "Update Data",
|
|
56
|
+
"enum": [
|
|
57
|
+
"disabled",
|
|
58
|
+
"public",
|
|
59
|
+
"private"
|
|
60
|
+
],
|
|
61
|
+
"x-enum-title": [
|
|
62
|
+
"Disabled",
|
|
63
|
+
"Agent Owner + All Users",
|
|
64
|
+
"Agent Owner Only"
|
|
65
|
+
],
|
|
66
|
+
"description": "Update existing records in Supabase tables based on filter conditions",
|
|
67
|
+
"default": "disabled"
|
|
68
|
+
},
|
|
69
|
+
"upsert_data": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"title": "Upsert Data",
|
|
72
|
+
"enum": [
|
|
73
|
+
"disabled",
|
|
74
|
+
"public",
|
|
75
|
+
"private"
|
|
76
|
+
],
|
|
77
|
+
"x-enum-title": [
|
|
78
|
+
"Disabled",
|
|
79
|
+
"Agent Owner + All Users",
|
|
80
|
+
"Agent Owner Only"
|
|
81
|
+
],
|
|
82
|
+
"description": "Insert or update records in Supabase tables based on conflict resolution",
|
|
83
|
+
"default": "disabled"
|
|
84
|
+
},
|
|
85
|
+
"delete_data": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"title": "Delete Data",
|
|
88
|
+
"enum": [
|
|
89
|
+
"disabled",
|
|
90
|
+
"public",
|
|
91
|
+
"private"
|
|
92
|
+
],
|
|
93
|
+
"x-enum-title": [
|
|
94
|
+
"Disabled",
|
|
95
|
+
"Agent Owner + All Users",
|
|
96
|
+
"Agent Owner Only"
|
|
97
|
+
],
|
|
98
|
+
"description": "Delete records from Supabase tables based on filter conditions",
|
|
99
|
+
"default": "disabled"
|
|
100
|
+
},
|
|
101
|
+
"invoke_function": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"title": "Invoke Edge Function",
|
|
104
|
+
"enum": [
|
|
105
|
+
"disabled",
|
|
106
|
+
"public",
|
|
107
|
+
"private"
|
|
108
|
+
],
|
|
109
|
+
"x-enum-title": [
|
|
110
|
+
"Disabled",
|
|
111
|
+
"Agent Owner + All Users",
|
|
112
|
+
"Agent Owner Only"
|
|
113
|
+
],
|
|
114
|
+
"description": "Invoke Supabase Edge Functions with optional parameters and headers",
|
|
115
|
+
"default": "disabled"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"description": "States for each Supabase skill"
|
|
119
|
+
},
|
|
120
|
+
"api_key_provider": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"title": "API Key Provider",
|
|
123
|
+
"description": "Who provides the API key",
|
|
124
|
+
"enum": [
|
|
125
|
+
"agent_owner"
|
|
126
|
+
],
|
|
127
|
+
"x-enum-title": [
|
|
128
|
+
"Owner Provided"
|
|
129
|
+
],
|
|
130
|
+
"default": "agent_owner"
|
|
131
|
+
},
|
|
132
|
+
"supabase_url": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"title": "Supabase URL",
|
|
135
|
+
"description": "Your Supabase project URL (e.g., https://your-project.supabase.co). You can find it in Project Settings -> Data API",
|
|
136
|
+
"x-link": "https://supabase.com/",
|
|
137
|
+
"format": "uri"
|
|
138
|
+
},
|
|
139
|
+
"supabase_key": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"title": "Supabase API Key",
|
|
142
|
+
"description": "Your Supabase project's API key. You can find it in Project Settings -> API Keys",
|
|
143
|
+
"x-sensitive": true,
|
|
144
|
+
"format": "password"
|
|
145
|
+
},
|
|
146
|
+
"public_write_tables": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"title": "Public Write Tables",
|
|
149
|
+
"description": "Add tables separated by commas. When insert, update, upsert, or delete operations are enabled for public use, only tables from this list can be used. This list does not restrict the skills executed by the owner or in autonomous chat.",
|
|
150
|
+
"default": ""
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"required": [
|
|
154
|
+
"states",
|
|
155
|
+
"enabled"
|
|
156
|
+
],
|
|
157
|
+
"if": {
|
|
158
|
+
"properties": {
|
|
159
|
+
"enabled": {
|
|
160
|
+
"const": true
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"then": {
|
|
165
|
+
"required": [
|
|
166
|
+
"supabase_url",
|
|
167
|
+
"supabase_key"
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<svg width="109" height="113" viewBox="0 0 109 113" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M63.7076 110.284C60.8481 113.885 55.0502 111.912 54.9813 107.314L53.9738 40.0627L99.1935 40.0627C107.384 40.0627 111.952 49.5228 106.859 55.9374L63.7076 110.284Z" fill="url(#paint0_linear)"/>
|
|
3
|
+
<path d="M63.7076 110.284C60.8481 113.885 55.0502 111.912 54.9813 107.314L53.9738 40.0627L99.1935 40.0627C107.384 40.0627 111.952 49.5228 106.859 55.9374L63.7076 110.284Z" fill="url(#paint1_linear)" fill-opacity="0.2"/>
|
|
4
|
+
<path d="M45.317 2.07103C48.1765 -1.53037 53.9745 0.442937 54.0434 5.041L54.4849 72.2922H9.83113C1.64038 72.2922 -2.92775 62.8321 2.1655 56.4175L45.317 2.07103Z" fill="#3ECF8E"/>
|
|
5
|
+
<defs>
|
|
6
|
+
<linearGradient id="paint0_linear" x1="53.9738" y1="54.974" x2="94.1635" y2="71.8295" gradientUnits="userSpaceOnUse">
|
|
7
|
+
<stop stop-color="#249361"/>
|
|
8
|
+
<stop offset="1" stop-color="#3ECF8E"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<linearGradient id="paint1_linear" x1="36.1558" y1="30.578" x2="54.4844" y2="65.0806" gradientUnits="userSpaceOnUse">
|
|
11
|
+
<stop/>
|
|
12
|
+
<stop offset="1" stop-opacity="0"/>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
</defs>
|
|
15
|
+
</svg>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Dict, Type
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
from supabase import Client, create_client
|
|
8
|
+
|
|
9
|
+
from intentkit.skills.supabase.base import SupabaseBaseTool
|
|
10
|
+
|
|
11
|
+
NAME = "supabase_update_data"
|
|
12
|
+
PROMPT = "Update existing data in a Supabase table with filtering conditions."
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SupabaseUpdateDataInput(BaseModel):
|
|
18
|
+
"""Input for SupabaseUpdateData tool."""
|
|
19
|
+
|
|
20
|
+
table: str = Field(description="The name of the table to update data in")
|
|
21
|
+
data: Dict[str, Any] = Field(
|
|
22
|
+
description="The data to update (key-value pairs of columns and new values)"
|
|
23
|
+
)
|
|
24
|
+
filters: Dict[str, Any] = Field(
|
|
25
|
+
description="Dictionary of filters to identify which records to update (e.g., {'id': 123})"
|
|
26
|
+
)
|
|
27
|
+
returning: str = Field(
|
|
28
|
+
default="*", description="Columns to return after update (default: '*' for all)"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SupabaseUpdateData(SupabaseBaseTool):
|
|
33
|
+
"""Tool for updating data in Supabase tables.
|
|
34
|
+
|
|
35
|
+
This tool allows updating records in Supabase tables based on filter conditions.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
name: str = NAME
|
|
39
|
+
description: str = PROMPT
|
|
40
|
+
args_schema: Type[BaseModel] = SupabaseUpdateDataInput
|
|
41
|
+
|
|
42
|
+
async def _arun(
|
|
43
|
+
self,
|
|
44
|
+
table: str,
|
|
45
|
+
data: Dict[str, Any],
|
|
46
|
+
filters: Dict[str, Any],
|
|
47
|
+
returning: str = "*",
|
|
48
|
+
config: RunnableConfig = None,
|
|
49
|
+
**kwargs,
|
|
50
|
+
):
|
|
51
|
+
try:
|
|
52
|
+
context = self.context_from_config(config)
|
|
53
|
+
|
|
54
|
+
# Validate table access for public mode
|
|
55
|
+
self.validate_table_access(table, context)
|
|
56
|
+
|
|
57
|
+
supabase_url, supabase_key = self.get_supabase_config(context.config)
|
|
58
|
+
|
|
59
|
+
# Create Supabase client
|
|
60
|
+
supabase: Client = create_client(supabase_url, supabase_key)
|
|
61
|
+
|
|
62
|
+
# Start building the update query
|
|
63
|
+
query = supabase.table(table).update(data)
|
|
64
|
+
|
|
65
|
+
# Apply filters to identify which records to update
|
|
66
|
+
for column, value in filters.items():
|
|
67
|
+
if isinstance(value, dict):
|
|
68
|
+
# Handle complex filters like {'gte': 18}
|
|
69
|
+
for operator, filter_value in value.items():
|
|
70
|
+
if operator == "eq":
|
|
71
|
+
query = query.eq(column, filter_value)
|
|
72
|
+
elif operator == "neq":
|
|
73
|
+
query = query.neq(column, filter_value)
|
|
74
|
+
elif operator == "gt":
|
|
75
|
+
query = query.gt(column, filter_value)
|
|
76
|
+
elif operator == "gte":
|
|
77
|
+
query = query.gte(column, filter_value)
|
|
78
|
+
elif operator == "lt":
|
|
79
|
+
query = query.lt(column, filter_value)
|
|
80
|
+
elif operator == "lte":
|
|
81
|
+
query = query.lte(column, filter_value)
|
|
82
|
+
elif operator == "like":
|
|
83
|
+
query = query.like(column, filter_value)
|
|
84
|
+
elif operator == "ilike":
|
|
85
|
+
query = query.ilike(column, filter_value)
|
|
86
|
+
elif operator == "in":
|
|
87
|
+
query = query.in_(column, filter_value)
|
|
88
|
+
else:
|
|
89
|
+
logger.warning(f"Unknown filter operator: {operator}")
|
|
90
|
+
else:
|
|
91
|
+
# Simple equality filter
|
|
92
|
+
query = query.eq(column, value)
|
|
93
|
+
|
|
94
|
+
# Execute the update
|
|
95
|
+
response = query.execute()
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
"success": True,
|
|
99
|
+
"data": response.data,
|
|
100
|
+
"count": len(response.data) if response.data else 0,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
except Exception as e:
|
|
104
|
+
logger.error(f"Error updating data in Supabase: {str(e)}")
|
|
105
|
+
raise ToolException(f"Failed to update data in table '{table}': {str(e)}")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Dict, List, Type, Union
|
|
3
|
+
|
|
4
|
+
from langchain_core.runnables import RunnableConfig
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
from supabase import Client, create_client
|
|
8
|
+
|
|
9
|
+
from intentkit.skills.supabase.base import SupabaseBaseTool
|
|
10
|
+
|
|
11
|
+
NAME = "supabase_upsert_data"
|
|
12
|
+
PROMPT = (
|
|
13
|
+
"Upsert (insert or update) data in a Supabase table based on conflict resolution."
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SupabaseUpsertDataInput(BaseModel):
|
|
20
|
+
"""Input for SupabaseUpsertData tool."""
|
|
21
|
+
|
|
22
|
+
table: str = Field(description="The name of the table to upsert data into")
|
|
23
|
+
data: Union[Dict[str, Any], List[Dict[str, Any]]] = Field(
|
|
24
|
+
description="The data to upsert. Can be a single object or a list of objects"
|
|
25
|
+
)
|
|
26
|
+
on_conflict: str = Field(
|
|
27
|
+
description="The column(s) to use for conflict resolution (e.g., 'id' or 'email,username')"
|
|
28
|
+
)
|
|
29
|
+
returning: str = Field(
|
|
30
|
+
default="*", description="Columns to return after upsert (default: '*' for all)"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SupabaseUpsertData(SupabaseBaseTool):
|
|
35
|
+
"""Tool for upserting data in Supabase tables.
|
|
36
|
+
|
|
37
|
+
This tool allows inserting new records or updating existing ones based on conflict resolution.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
name: str = NAME
|
|
41
|
+
description: str = PROMPT
|
|
42
|
+
args_schema: Type[BaseModel] = SupabaseUpsertDataInput
|
|
43
|
+
|
|
44
|
+
async def _arun(
|
|
45
|
+
self,
|
|
46
|
+
table: str,
|
|
47
|
+
data: Union[Dict[str, Any], List[Dict[str, Any]]],
|
|
48
|
+
on_conflict: str,
|
|
49
|
+
returning: str = "*",
|
|
50
|
+
config: RunnableConfig = None,
|
|
51
|
+
**kwargs,
|
|
52
|
+
):
|
|
53
|
+
try:
|
|
54
|
+
context = self.context_from_config(config)
|
|
55
|
+
|
|
56
|
+
# Validate table access for public mode
|
|
57
|
+
self.validate_table_access(table, context)
|
|
58
|
+
|
|
59
|
+
supabase_url, supabase_key = self.get_supabase_config(context.config)
|
|
60
|
+
|
|
61
|
+
# Create Supabase client
|
|
62
|
+
supabase: Client = create_client(supabase_url, supabase_key)
|
|
63
|
+
|
|
64
|
+
# Upsert data
|
|
65
|
+
response = (
|
|
66
|
+
supabase.table(table).upsert(data, on_conflict=on_conflict).execute()
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
"success": True,
|
|
71
|
+
"data": response.data,
|
|
72
|
+
"count": len(response.data) if response.data else 0,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
except Exception as e:
|
|
76
|
+
logger.error(f"Error upserting data in Supabase: {str(e)}")
|
|
77
|
+
raise ToolException(f"Failed to upsert data in table '{table}': {str(e)}")
|
|
@@ -40,7 +40,7 @@ class ReadAgentApiKey(SystemBaseTool):
|
|
|
40
40
|
"""Retrieve or generate an API key for the agent."""
|
|
41
41
|
# Get context from runnable config to access agent.id
|
|
42
42
|
context = self.context_from_config(config)
|
|
43
|
-
agent_id = context.
|
|
43
|
+
agent_id = context.agent_id
|
|
44
44
|
|
|
45
45
|
# Get agent data from skill store
|
|
46
46
|
agent_data = await self.skill_store.get_agent_data(agent_id)
|
|
@@ -44,7 +44,7 @@ class RegenerateAgentApiKey(SystemBaseTool):
|
|
|
44
44
|
"""Generate and set a new API key for the agent."""
|
|
45
45
|
# Get context from runnable config to access agent.id
|
|
46
46
|
context = self.context_from_config(config)
|
|
47
|
-
agent_id = context.
|
|
47
|
+
agent_id = context.agent_id
|
|
48
48
|
|
|
49
49
|
# Get agent data from skill store
|
|
50
50
|
agent_data = await self.skill_store.get_agent_data(agent_id)
|
intentkit/skills/token/base.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"""Base class for token-related skills."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Any, Dict
|
|
4
|
+
from typing import Any, Dict
|
|
5
5
|
|
|
6
6
|
import aiohttp
|
|
7
|
-
from langchain_core.runnables import RunnableConfig
|
|
8
7
|
|
|
9
8
|
from intentkit.abstracts.skill import SkillStoreABC
|
|
10
9
|
from intentkit.skills.base import IntentKitSkill, SkillContext
|
|
@@ -42,43 +41,6 @@ class TokenBaseTool(IntentKitSkill):
|
|
|
42
41
|
return skill_config.get("api_key")
|
|
43
42
|
return self.skill_store.get_system_config("moralis_api_key")
|
|
44
43
|
|
|
45
|
-
def context_from_config(self, config: Optional[RunnableConfig] = None) -> Any:
|
|
46
|
-
"""Extract context from the runnable config."""
|
|
47
|
-
if not config:
|
|
48
|
-
logger.error("No config provided to context_from_config")
|
|
49
|
-
return None
|
|
50
|
-
|
|
51
|
-
if "configurable" not in config:
|
|
52
|
-
logger.error("'configurable' not in config")
|
|
53
|
-
return None
|
|
54
|
-
|
|
55
|
-
if "agent" not in config["configurable"]:
|
|
56
|
-
logger.error("'agent' not in config['configurable']")
|
|
57
|
-
return None
|
|
58
|
-
|
|
59
|
-
agent = config["configurable"].get("agent")
|
|
60
|
-
category_config = None
|
|
61
|
-
|
|
62
|
-
if agent.skills:
|
|
63
|
-
category_config = agent.skills.get(self.category)
|
|
64
|
-
|
|
65
|
-
if not category_config:
|
|
66
|
-
category_config = getattr(agent, self.category + "_config", {})
|
|
67
|
-
|
|
68
|
-
if not category_config:
|
|
69
|
-
category_config = {}
|
|
70
|
-
|
|
71
|
-
from intentkit.skills.base import SkillContext
|
|
72
|
-
|
|
73
|
-
context = SkillContext(
|
|
74
|
-
agent=agent,
|
|
75
|
-
config=category_config,
|
|
76
|
-
user_id=config["configurable"].get("user_id"),
|
|
77
|
-
entrypoint=config["configurable"].get("entrypoint"),
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
return context
|
|
81
|
-
|
|
82
44
|
def _prepare_params(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
83
45
|
"""Convert boolean values to lowercase strings for API compatibility.
|
|
84
46
|
|
|
@@ -41,7 +41,7 @@ class TwitterFollowUser(TwitterBaseTool):
|
|
|
41
41
|
try:
|
|
42
42
|
context = self.context_from_config(config)
|
|
43
43
|
twitter = get_twitter_client(
|
|
44
|
-
agent_id=context.
|
|
44
|
+
agent_id=context.agent_id,
|
|
45
45
|
skill_store=self.skill_store,
|
|
46
46
|
config=context.config,
|
|
47
47
|
)
|
|
@@ -50,7 +50,7 @@ class TwitterFollowUser(TwitterBaseTool):
|
|
|
50
50
|
# Check rate limit only when not using OAuth
|
|
51
51
|
if not twitter.use_key:
|
|
52
52
|
await self.check_rate_limit(
|
|
53
|
-
context.
|
|
53
|
+
context.agent_id, max_requests=5, interval=15
|
|
54
54
|
)
|
|
55
55
|
|
|
56
56
|
# Follow the user using tweepy client
|
|
@@ -66,4 +66,4 @@ class TwitterFollowUser(TwitterBaseTool):
|
|
|
66
66
|
|
|
67
67
|
except Exception as e:
|
|
68
68
|
logger.error("Error following user: %s", str(e))
|
|
69
|
-
raise type(e)(f"[agent:{context.
|
|
69
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|
|
@@ -45,7 +45,7 @@ class TwitterGetMentions(TwitterBaseTool):
|
|
|
45
45
|
try:
|
|
46
46
|
context = self.context_from_config(config)
|
|
47
47
|
twitter = get_twitter_client(
|
|
48
|
-
agent_id=context.
|
|
48
|
+
agent_id=context.agent_id,
|
|
49
49
|
skill_store=self.skill_store,
|
|
50
50
|
config=context.config,
|
|
51
51
|
)
|
|
@@ -56,14 +56,14 @@ class TwitterGetMentions(TwitterBaseTool):
|
|
|
56
56
|
# Check rate limit only when not using OAuth
|
|
57
57
|
if not twitter.use_key:
|
|
58
58
|
await self.check_rate_limit(
|
|
59
|
-
context.
|
|
59
|
+
context.agent_id,
|
|
60
60
|
max_requests=1,
|
|
61
61
|
interval=59, # TODO: tmp to 59, back to 240 later
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
# get since id from store
|
|
65
65
|
last = await self.skill_store.get_agent_skill_data(
|
|
66
|
-
context.
|
|
66
|
+
context.agent_id, self.name, "last"
|
|
67
67
|
)
|
|
68
68
|
last = last or {}
|
|
69
69
|
max_results = 10
|
|
@@ -114,11 +114,11 @@ class TwitterGetMentions(TwitterBaseTool):
|
|
|
114
114
|
if mentions.get("meta") and mentions["meta"].get("newest_id"):
|
|
115
115
|
last["since_id"] = mentions["meta"].get("newest_id")
|
|
116
116
|
await self.skill_store.save_agent_skill_data(
|
|
117
|
-
context.
|
|
117
|
+
context.agent_id, self.name, "last", last
|
|
118
118
|
)
|
|
119
119
|
|
|
120
120
|
return mentions
|
|
121
121
|
|
|
122
122
|
except Exception as e:
|
|
123
|
-
logger.error(f"[agent:{context.
|
|
124
|
-
raise type(e)(f"[agent:{context.
|
|
123
|
+
logger.error(f"[agent:{context.agent_id}]: {e}")
|
|
124
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|
|
@@ -44,7 +44,7 @@ class TwitterGetTimeline(TwitterBaseTool):
|
|
|
44
44
|
|
|
45
45
|
context = self.context_from_config(config)
|
|
46
46
|
twitter = get_twitter_client(
|
|
47
|
-
agent_id=context.
|
|
47
|
+
agent_id=context.agent_id,
|
|
48
48
|
skill_store=self.skill_store,
|
|
49
49
|
config=context.config,
|
|
50
50
|
)
|
|
@@ -53,12 +53,12 @@ class TwitterGetTimeline(TwitterBaseTool):
|
|
|
53
53
|
# Check rate limit only when not using OAuth
|
|
54
54
|
if not twitter.use_key:
|
|
55
55
|
await self.check_rate_limit(
|
|
56
|
-
context.
|
|
56
|
+
context.agent_id, max_requests=3, interval=60 * 24
|
|
57
57
|
)
|
|
58
58
|
|
|
59
59
|
# get since id from store
|
|
60
60
|
last = await self.skill_store.get_agent_skill_data(
|
|
61
|
-
context.
|
|
61
|
+
context.agent_id, self.name, "last"
|
|
62
62
|
)
|
|
63
63
|
last = last or {}
|
|
64
64
|
since_id = last.get("since_id")
|
|
@@ -101,11 +101,11 @@ class TwitterGetTimeline(TwitterBaseTool):
|
|
|
101
101
|
if timeline.get("meta") and timeline["meta"].get("newest_id"):
|
|
102
102
|
last["since_id"] = timeline["meta"]["newest_id"]
|
|
103
103
|
await self.skill_store.save_agent_skill_data(
|
|
104
|
-
context.
|
|
104
|
+
context.agent_id, self.name, "last", last
|
|
105
105
|
)
|
|
106
106
|
|
|
107
107
|
return timeline
|
|
108
108
|
|
|
109
109
|
except Exception as e:
|
|
110
110
|
logger.error("Error getting timeline: %s", str(e))
|
|
111
|
-
raise type(e)(f"[agent:{context.
|
|
111
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|
|
@@ -42,7 +42,7 @@ class TwitterGetUserByUsername(TwitterBaseTool):
|
|
|
42
42
|
try:
|
|
43
43
|
context = self.context_from_config(config)
|
|
44
44
|
twitter = get_twitter_client(
|
|
45
|
-
agent_id=context.
|
|
45
|
+
agent_id=context.agent_id,
|
|
46
46
|
skill_store=self.skill_store,
|
|
47
47
|
config=context.config,
|
|
48
48
|
)
|
|
@@ -51,7 +51,7 @@ class TwitterGetUserByUsername(TwitterBaseTool):
|
|
|
51
51
|
# Check rate limit only when not using OAuth
|
|
52
52
|
if not twitter.use_key:
|
|
53
53
|
await self.check_rate_limit(
|
|
54
|
-
context.
|
|
54
|
+
context.agent_id, max_requests=3, interval=60 * 24
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
user_data = await client.get_user(
|
|
@@ -81,4 +81,4 @@ class TwitterGetUserByUsername(TwitterBaseTool):
|
|
|
81
81
|
|
|
82
82
|
except Exception as e:
|
|
83
83
|
logger.error(f"Error getting user by username: {str(e)}")
|
|
84
|
-
raise type(e)(f"[agent:{context.
|
|
84
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|
|
@@ -58,7 +58,7 @@ class TwitterGetUserTweets(TwitterBaseTool):
|
|
|
58
58
|
|
|
59
59
|
context = self.context_from_config(config)
|
|
60
60
|
twitter = get_twitter_client(
|
|
61
|
-
agent_id=context.
|
|
61
|
+
agent_id=context.agent_id,
|
|
62
62
|
skill_store=self.skill_store,
|
|
63
63
|
config=context.config,
|
|
64
64
|
)
|
|
@@ -67,12 +67,12 @@ class TwitterGetUserTweets(TwitterBaseTool):
|
|
|
67
67
|
# Check rate limit only when not using OAuth
|
|
68
68
|
if not twitter.use_key:
|
|
69
69
|
await self.check_rate_limit(
|
|
70
|
-
context.
|
|
70
|
+
context.agent_id, max_requests=3, interval=60 * 24
|
|
71
71
|
)
|
|
72
72
|
|
|
73
73
|
# get since id from store
|
|
74
74
|
last = await self.skill_store.get_agent_skill_data(
|
|
75
|
-
context.
|
|
75
|
+
context.agent_id, self.name, user_id
|
|
76
76
|
)
|
|
77
77
|
last = last or {}
|
|
78
78
|
since_id = last.get("since_id")
|
|
@@ -113,11 +113,11 @@ class TwitterGetUserTweets(TwitterBaseTool):
|
|
|
113
113
|
if tweets.get("meta") and tweets["meta"].get("newest_id"):
|
|
114
114
|
last["since_id"] = tweets["meta"]["newest_id"]
|
|
115
115
|
await self.skill_store.save_agent_skill_data(
|
|
116
|
-
context.
|
|
116
|
+
context.agent_id, self.name, user_id, last
|
|
117
117
|
)
|
|
118
118
|
|
|
119
119
|
return tweets
|
|
120
120
|
|
|
121
121
|
except Exception as e:
|
|
122
122
|
logger.error("Error getting user tweets: %s", str(e))
|
|
123
|
-
raise type(e)(f"[agent:{context.
|
|
123
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|
|
@@ -39,7 +39,7 @@ class TwitterLikeTweet(TwitterBaseTool):
|
|
|
39
39
|
try:
|
|
40
40
|
context = self.context_from_config(config)
|
|
41
41
|
twitter = get_twitter_client(
|
|
42
|
-
agent_id=context.
|
|
42
|
+
agent_id=context.agent_id,
|
|
43
43
|
skill_store=self.skill_store,
|
|
44
44
|
config=context.config,
|
|
45
45
|
)
|
|
@@ -48,7 +48,7 @@ class TwitterLikeTweet(TwitterBaseTool):
|
|
|
48
48
|
# Check rate limit only when not using OAuth
|
|
49
49
|
if not twitter.use_key:
|
|
50
50
|
await self.check_rate_limit(
|
|
51
|
-
context.
|
|
51
|
+
context.agent_id, max_requests=100, interval=1440
|
|
52
52
|
)
|
|
53
53
|
|
|
54
54
|
# Like the tweet using tweepy client
|
|
@@ -62,4 +62,4 @@ class TwitterLikeTweet(TwitterBaseTool):
|
|
|
62
62
|
|
|
63
63
|
except Exception as e:
|
|
64
64
|
logger.error(f"Error liking tweet: {str(e)}")
|
|
65
|
-
raise type(e)(f"[agent:{context.
|
|
65
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|
|
@@ -54,7 +54,7 @@ class TwitterPostTweet(TwitterBaseTool):
|
|
|
54
54
|
try:
|
|
55
55
|
context = self.context_from_config(config)
|
|
56
56
|
twitter = get_twitter_client(
|
|
57
|
-
agent_id=context.
|
|
57
|
+
agent_id=context.agent_id,
|
|
58
58
|
skill_store=self.skill_store,
|
|
59
59
|
config=context.config,
|
|
60
60
|
)
|
|
@@ -63,7 +63,7 @@ class TwitterPostTweet(TwitterBaseTool):
|
|
|
63
63
|
# Check rate limit only when not using OAuth
|
|
64
64
|
if not twitter.use_key:
|
|
65
65
|
await self.check_rate_limit(
|
|
66
|
-
context.
|
|
66
|
+
context.agent_id, max_requests=24, interval=1440
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
media_ids = []
|
|
@@ -71,7 +71,7 @@ class TwitterPostTweet(TwitterBaseTool):
|
|
|
71
71
|
# Handle image upload if provided
|
|
72
72
|
if image:
|
|
73
73
|
# Use the TwitterClient method to upload the image
|
|
74
|
-
media_ids = await twitter.upload_media(context.
|
|
74
|
+
media_ids = await twitter.upload_media(context.agent_id, image)
|
|
75
75
|
|
|
76
76
|
# Post tweet using tweepy client
|
|
77
77
|
tweet_params = {"text": text, "user_auth": twitter.use_key}
|
|
@@ -87,4 +87,4 @@ class TwitterPostTweet(TwitterBaseTool):
|
|
|
87
87
|
|
|
88
88
|
except Exception as e:
|
|
89
89
|
logger.error(f"Error posting tweet: {str(e)}")
|
|
90
|
-
raise type(e)(f"[agent:{context.
|
|
90
|
+
raise type(e)(f"[agent:{context.agent_id}]: {e}") from e
|