Skip to content

Commit 158261a

Browse files
committed
listSkills sync action defining the available AI agent skills 🤖
eventually the response of this sync action shall be generated dynamically based on component configuration
1 parent bec13f2 commit 158261a

File tree

2 files changed

+140
-9
lines changed

2 files changed

+140
-9
lines changed

‎.github/workflows/push.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ jobs:
6767
TAG="${GITHUB_REF##*/}"
6868
IS_SEMANTIC_TAG=$(echo "$TAG" | grep -q '^v\?[0-9]\+\.[0-9]\+\.[0-9]\+$' && echo true || echo false)
6969
echo "is_semantic_tag=$IS_SEMANTIC_TAG" | tee -a $GITHUB_OUTPUT
70-
echo "app_image_tag=$TAG" | tee -a $GITHUB_OUTPUT
70+
echo "app_image_tag=$TAG-${{ github.run_id }}" | tee -a $GITHUB_OUTPUT
7171
7272
- name: Deploy-Ready check
7373
id: deploy_ready

‎src/component.py

+139-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import csv
2+
import json
23
import logging
34
import os
45
import shutil
@@ -60,6 +61,115 @@
6061

6162
DEFAULT_LOGIN_METHOD = "security_token"
6263

64+
# the listSkills response shall be generated based on user config in a very near future,
65+
# so I just hardcoded it here for now
66+
LIST_SKILLS_STATIC_RESPONSE = [
67+
{
68+
"name": "Get Salesforce contacts",
69+
"description": "Returns list of Salesforce contacts.",
70+
"parameters": [
71+
{
72+
"name": "action",
73+
"type": "string",
74+
"required": True,
75+
"enum": ["runSkill"],
76+
},
77+
{
78+
"name": "parameters",
79+
"type": "object",
80+
"required": True,
81+
"parameters": {
82+
"name": "configData",
83+
"type": "object",
84+
"required": True,
85+
"parameters": [
86+
{
87+
"name": "object",
88+
"type": "string",
89+
"required": True,
90+
"enum": ["Contact"],
91+
"description": "String identifer of the agent skill to run.",
92+
},
93+
],
94+
},
95+
},
96+
],
97+
"response": {
98+
"type": "object",
99+
"properties": {
100+
"status": {
101+
"title": "Response status",
102+
"type": "string",
103+
"enum": ["ok", "error"],
104+
},
105+
"number_of_records": {
106+
"title": "Number of records in the response",
107+
"type": "integer",
108+
},
109+
"records": {
110+
"title": "Salesforce records",
111+
"type": "array",
112+
"items": {
113+
"type": "object",
114+
},
115+
},
116+
},
117+
},
118+
},
119+
{
120+
"name": "Get Salesforce reports",
121+
"description": "Returns list of Salesforce reports.",
122+
"parameters": [
123+
{
124+
"name": "action",
125+
"type": "string",
126+
"required": True,
127+
"enum": ["runSkill"],
128+
},
129+
{
130+
"name": "parameters",
131+
"type": "object",
132+
"required": True,
133+
"parameters": {
134+
"name": "configData",
135+
"type": "object",
136+
"required": True,
137+
"parameters": [
138+
{
139+
"name": "object",
140+
"type": "string",
141+
"required": True,
142+
"enum": ["Report"],
143+
"description": "String identifer of the agent skill to run.",
144+
},
145+
],
146+
},
147+
},
148+
],
149+
"response": {
150+
"type": "object",
151+
"properties": {
152+
"status": {
153+
"title": "Response status",
154+
"type": "string",
155+
"enum": ["ok", "error"],
156+
},
157+
"number_of_records": {
158+
"title": "Number of records in the response",
159+
"type": "integer",
160+
},
161+
"records": {
162+
"title": "Salesforce records",
163+
"type": "array",
164+
"items": {
165+
"type": "object",
166+
},
167+
},
168+
},
169+
},
170+
},
171+
]
172+
63173

64174
class LoginType(str, Enum):
65175
SECURITY_TOKEN_LOGIN = "security_token"
@@ -86,13 +196,16 @@ class Component(ComponentBase):
86196
def __init__(self):
87197
super().__init__()
88198

89-
def run(self, return_data=False):
199+
def run(self, return_json=False):
90200
self.validate_configuration_parameters(REQUIRED_PARAMETERS)
91201
self.validate_image_parameters(REQUIRED_IMAGE_PARS)
92202

93203
start_run_time = str(datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z"))
94204

95205
params = self.configuration.parameters
206+
207+
logging.info("%s", json.dumps(params, indent=4))
208+
96209
loading_options = params.get(KEY_LOADING_OPTIONS, {})
97210

98211
bucket_name = params.get(KEY_BUCKET_NAME, self.get_bucket_name())
@@ -130,7 +243,15 @@ def run(self, return_data=False):
130243
logging.debug([result for result in results])
131244
logging.info(f"Downloaded {total_records} records in total")
132245

133-
if return_data:
246+
if return_json:
247+
for result in results:
248+
if "file" not in result:
249+
result["status"] = "fileError"
250+
continue
251+
result["records"] = list(self._csv_result_to_dict(result.pop("file")))
252+
result["status"] = "ok"
253+
with open("response.json", "w") as f:
254+
json.dump(results, f)
134255
return results
135256

136257
# remove headers and get columns
@@ -180,6 +301,12 @@ def _fix_header_from_csv(results: list[dict]) -> list[str]:
180301
os.replace(temp_file_path, result_file_path)
181302
return expected_header
182303

304+
def _csv_result_to_dict(self, filename: str):
305+
with open(filename) as f:
306+
reader = csv.DictReader(f)
307+
for row in reader:
308+
yield row
309+
183310
def set_proxy(self) -> None:
184311
"""Sets proxy if defined"""
185312
proxy_config = self.configuration.parameters.get(KEY_PROXY, {})
@@ -622,12 +749,16 @@ def load_possible_primary_keys(self) -> list[SelectElement]:
622749
else:
623750
raise UserException(f"Invalid {KEY_QUERY_TYPE}")
624751

625-
# @sync_action("runComponent")
626-
# def sync_run_component(self):
627-
# """
628-
# Run the component as a sync action
629-
# """
630-
# return self.run(return_data=True)
752+
@sync_action("runSkill")
753+
def sync_run_component(self):
754+
"""
755+
Run the component as a skill for an AI agent
756+
"""
757+
return self.run(return_json=True)
758+
759+
@sync_action("listSkills")
760+
def list_skills(self):
761+
return LIST_SKILLS_STATIC_RESPONSE
631762

632763
def _get_object_name_from_custom_query(self) -> str:
633764
params = self.configuration.parameters

0 commit comments

Comments
 (0)