ibm-watsonx-orchestrate 1.5.1__py3-none-any.whl → 1.6.0b0__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.
- ibm_watsonx_orchestrate/__init__.py +1 -1
- ibm_watsonx_orchestrate/agent_builder/agents/__init__.py +1 -1
- ibm_watsonx_orchestrate/agent_builder/agents/types.py +53 -3
- ibm_watsonx_orchestrate/agent_builder/model_policies/types.py +1 -1
- ibm_watsonx_orchestrate/agent_builder/models/types.py +0 -1
- ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py +41 -3
- ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +2 -1
- ibm_watsonx_orchestrate/agent_builder/tools/types.py +7 -0
- ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +18 -1
- ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +97 -3
- ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +0 -1
- ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +1 -1
- ibm_watsonx_orchestrate/cli/commands/environment/environment_command.py +29 -4
- ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +74 -8
- ibm_watsonx_orchestrate/cli/commands/environment/types.py +1 -0
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +224 -0
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +158 -0
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +2 -2
- ibm_watsonx_orchestrate/cli/commands/models/model_provider_mapper.py +31 -25
- ibm_watsonx_orchestrate/cli/commands/models/models_command.py +6 -6
- ibm_watsonx_orchestrate/cli/commands/models/models_controller.py +17 -8
- ibm_watsonx_orchestrate/cli/commands/server/server_command.py +25 -17
- ibm_watsonx_orchestrate/cli/commands/server/types.py +2 -1
- ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +0 -3
- ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +14 -12
- ibm_watsonx_orchestrate/cli/config.py +2 -0
- ibm_watsonx_orchestrate/cli/main.py +6 -0
- ibm_watsonx_orchestrate/client/agents/agent_client.py +14 -8
- ibm_watsonx_orchestrate/client/agents/assistant_agent_client.py +3 -3
- ibm_watsonx_orchestrate/client/agents/external_agent_client.py +2 -2
- ibm_watsonx_orchestrate/client/base_api_client.py +9 -9
- ibm_watsonx_orchestrate/client/connections/connections_client.py +32 -6
- ibm_watsonx_orchestrate/client/connections/utils.py +1 -1
- ibm_watsonx_orchestrate/client/credentials.py +4 -0
- ibm_watsonx_orchestrate/client/model_policies/model_policies_client.py +2 -2
- ibm_watsonx_orchestrate/client/service_instance.py +42 -1
- ibm_watsonx_orchestrate/client/utils.py +27 -2
- ibm_watsonx_orchestrate/docker/compose-lite.yml +27 -17
- ibm_watsonx_orchestrate/docker/default.env +21 -15
- ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/__init__.py +3 -2
- ibm_watsonx_orchestrate/flow_builder/flows/decorators.py +77 -0
- ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/events.py +6 -1
- ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/flow.py +70 -87
- ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/types.py +15 -6
- ibm_watsonx_orchestrate/flow_builder/utils.py +185 -0
- {ibm_watsonx_orchestrate-1.5.1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/METADATA +2 -1
- {ibm_watsonx_orchestrate-1.5.1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/RECORD +55 -53
- ibm_watsonx_orchestrate/experimental/flow_builder/flows/decorators.py +0 -144
- ibm_watsonx_orchestrate/experimental/flow_builder/utils.py +0 -115
- /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/__init__.py +0 -0
- /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/data_map.py +0 -0
- /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/constants.py +0 -0
- /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/node.py +0 -0
- /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/resources/flow_status.openapi.yml +0 -0
- {ibm_watsonx_orchestrate-1.5.1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/WHEEL +0 -0
- {ibm_watsonx_orchestrate-1.5.1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/entry_points.txt +0 -0
- {ibm_watsonx_orchestrate-1.5.1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -20,6 +20,7 @@ from typing_extensions import Self
|
|
20
20
|
from pydantic import BaseModel, Field, SerializeAsAny
|
21
21
|
import yaml
|
22
22
|
from ibm_watsonx_orchestrate.agent_builder.tools.python_tool import PythonTool
|
23
|
+
from ibm_watsonx_orchestrate.client.tools.tool_client import ToolClient
|
23
24
|
from ibm_watsonx_orchestrate.client.tools.tempus_client import TempusClient
|
24
25
|
from ibm_watsonx_orchestrate.client.utils import instantiate_client
|
25
26
|
from ..types import (
|
@@ -36,7 +37,7 @@ from ..types import (
|
|
36
37
|
)
|
37
38
|
|
38
39
|
from ..data_map import DataMap
|
39
|
-
from ..utils import _get_json_schema_obj, get_valid_name, import_flow_model
|
40
|
+
from ..utils import _get_json_schema_obj, get_valid_name, import_flow_model, _get_tool_request_body, _get_tool_response_body
|
40
41
|
|
41
42
|
from .events import StreamConsumer
|
42
43
|
|
@@ -70,6 +71,7 @@ class Flow(Node):
|
|
70
71
|
metadata: dict[str, str] = {}
|
71
72
|
parent: Any = None
|
72
73
|
_sequence_id: int = 0 # internal-id
|
74
|
+
_tool_client: ToolClient = None
|
73
75
|
|
74
76
|
def __init__(self, **kwargs):
|
75
77
|
super().__init__(**kwargs)
|
@@ -77,6 +79,9 @@ class Flow(Node):
|
|
77
79
|
# extract data schemas
|
78
80
|
self._refactor_node_to_schemaref(self)
|
79
81
|
|
82
|
+
# get Tool Client
|
83
|
+
self._tool_client = instantiate_client(ToolClient)
|
84
|
+
|
80
85
|
def _find_topmost_flow(self) -> Self:
|
81
86
|
if self.parent:
|
82
87
|
return self.parent._find_topmost_flow()
|
@@ -104,7 +109,27 @@ class Flow(Node):
|
|
104
109
|
# if there is already a schema with the same name, return it
|
105
110
|
if title:
|
106
111
|
if title in top_flow.schemas:
|
107
|
-
|
112
|
+
existing_schema = top_flow.schemas[title]
|
113
|
+
# we need a deep compare if the incoming schema and existing_schema is the same
|
114
|
+
# pydantic suppport nested comparison by default
|
115
|
+
|
116
|
+
schema.title = title
|
117
|
+
|
118
|
+
if schema == existing_schema:
|
119
|
+
return existing_schema
|
120
|
+
# we need to do a deep compare
|
121
|
+
incoming_model = schema.model_dump(exclude_none=True, exclude_unset=True)
|
122
|
+
existing_model = existing_schema.model_dump(exclude_none=True, exclude_unset=True)
|
123
|
+
|
124
|
+
# log the model
|
125
|
+
# logger.info(f"incoming_model: {incoming_model}")
|
126
|
+
# logger.info(f"existing_model: {existing_model}")
|
127
|
+
|
128
|
+
if incoming_model == existing_model:
|
129
|
+
return existing_schema
|
130
|
+
|
131
|
+
# else we need a new name, and create a new schema
|
132
|
+
title = title + "_" + str(self._next_sequence_id())
|
108
133
|
|
109
134
|
# otherwise, create a deep copy of the schema, add it to the dictionary and return it
|
110
135
|
if schema:
|
@@ -122,7 +147,7 @@ class Flow(Node):
|
|
122
147
|
elif schema.aliasName:
|
123
148
|
title = get_valid_name(schema.aliasName)
|
124
149
|
else:
|
125
|
-
title = "bo_" +
|
150
|
+
title = "bo_" + str(self._next_sequence_id())
|
126
151
|
|
127
152
|
if new_schema.type == "object":
|
128
153
|
# iterate the properties and add schema recursively
|
@@ -193,7 +218,7 @@ class Flow(Node):
|
|
193
218
|
required= spec.output_schema.required)
|
194
219
|
spec.output_schema = self._add_schema_ref(json_obj, f"{spec.name}_output")
|
195
220
|
elif spec.output_schema.type == "array":
|
196
|
-
if spec.output_schema.items.type == "object":
|
221
|
+
if hasattr(spec.output_schema, "items") and hasattr(spec.output_schema.items, "type") and spec.output_schema.items.type == "object":
|
197
222
|
schema_ref = self._add_schema_ref(spec.output_schema.items)
|
198
223
|
spec.output_schema.items = JsonSchemaObjectRef(ref=f"{schema_ref.ref}")
|
199
224
|
|
@@ -265,23 +290,30 @@ class Flow(Node):
|
|
265
290
|
|
266
291
|
if isinstance(tool, str):
|
267
292
|
name = name if name is not None and name != "" else tool
|
268
|
-
|
269
|
-
|
293
|
+
|
294
|
+
if input_schema is None and output_schema is None:
|
295
|
+
# try to retrieve the schema from server
|
296
|
+
tool_specs: List[dict] = self._tool_client.get_draft_by_name(name)
|
297
|
+
if (tool_specs is None) or (len(tool_specs) == 0):
|
298
|
+
raise ValueError(f"tool '{name}' not found")
|
299
|
+
|
300
|
+
# use the first spec
|
301
|
+
tool_spec: ToolSpec = ToolSpec.model_validate(tool_specs[0])
|
302
|
+
# just pick the first one that is found
|
303
|
+
if hasattr(tool_spec, "input_schema"):
|
304
|
+
input_schema_obj = _get_json_schema_obj("input", tool_spec.input_schema, True)
|
305
|
+
if hasattr(tool_spec, "output_schema"):
|
306
|
+
output_schema_obj = _get_json_schema_obj("output", tool_spec.output_schema)
|
307
|
+
else:
|
308
|
+
input_schema_obj = _get_json_schema_obj("input", input_schema)
|
309
|
+
output_schema_obj = _get_json_schema_obj("output", output_schema)
|
270
310
|
|
271
311
|
toolnode_spec = ToolNodeSpec(type = "tool",
|
272
312
|
name = name,
|
273
313
|
display_name = display_name,
|
274
314
|
description = description,
|
275
|
-
input_schema=
|
276
|
-
|
277
|
-
properties=input_schema_obj.properties,
|
278
|
-
required=input_schema_obj.required,
|
279
|
-
) if input_schema is not None else None,
|
280
|
-
output_schema=ToolResponseBody(
|
281
|
-
type=output_schema_obj.type,
|
282
|
-
properties=output_schema_obj.properties,
|
283
|
-
required=output_schema_obj.required
|
284
|
-
) if output_schema is not None else None,
|
315
|
+
input_schema= _get_tool_request_body(input_schema_obj),
|
316
|
+
output_schema= _get_tool_response_body(output_schema_obj),
|
285
317
|
output_schema_object = output_schema_obj,
|
286
318
|
tool = tool)
|
287
319
|
|
@@ -341,16 +373,8 @@ class Flow(Node):
|
|
341
373
|
agent=agent,
|
342
374
|
message=message,
|
343
375
|
guidelines=guidelines,
|
344
|
-
input_schema=
|
345
|
-
|
346
|
-
properties=input_schema_obj.properties,
|
347
|
-
required=input_schema_obj.required,
|
348
|
-
),
|
349
|
-
output_schema=ToolResponseBody(
|
350
|
-
type=output_schema_obj.type,
|
351
|
-
properties=output_schema_obj.properties,
|
352
|
-
required=output_schema_obj.required
|
353
|
-
),
|
376
|
+
input_schema=_get_tool_request_body(input_schema_obj),
|
377
|
+
output_schema=_get_tool_response_body(output_schema_obj),
|
354
378
|
output_schema_object = output_schema_obj
|
355
379
|
)
|
356
380
|
|
@@ -391,16 +415,8 @@ class Flow(Node):
|
|
391
415
|
user_prompt=user_prompt,
|
392
416
|
llm=llm,
|
393
417
|
llm_parameters=llm_parameters,
|
394
|
-
input_schema=
|
395
|
-
|
396
|
-
properties=input_schema_obj.properties,
|
397
|
-
required=input_schema_obj.required,
|
398
|
-
),
|
399
|
-
output_schema=ToolResponseBody(
|
400
|
-
type=output_schema_obj.type,
|
401
|
-
properties=output_schema_obj.properties,
|
402
|
-
required=output_schema_obj.required
|
403
|
-
),
|
418
|
+
input_schema=_get_tool_request_body(input_schema_obj),
|
419
|
+
output_schema=_get_tool_response_body(output_schema_obj),
|
404
420
|
output_schema_object = output_schema_obj
|
405
421
|
)
|
406
422
|
|
@@ -543,21 +559,13 @@ class Flow(Node):
|
|
543
559
|
},
|
544
560
|
required = ["items"])
|
545
561
|
|
562
|
+
new_foreach_item_schema = self._add_schema(foreach_item_schema)
|
546
563
|
spec = ForeachSpec(name = "foreach_" + str(self._next_sequence_id()),
|
547
|
-
input_schema=
|
548
|
-
|
549
|
-
|
550
|
-
required=input_schema_obj.required,
|
551
|
-
),
|
552
|
-
output_schema=ToolResponseBody(
|
553
|
-
type=output_schema_obj.type,
|
554
|
-
properties=output_schema_obj.properties,
|
555
|
-
required=output_schema_obj.required
|
556
|
-
) if output_schema_obj is not None else None,
|
557
|
-
item_schema = foreach_item_schema)
|
564
|
+
input_schema=_get_tool_request_body(input_schema_obj),
|
565
|
+
output_schema=_get_tool_response_body(output_schema_obj),
|
566
|
+
item_schema = new_foreach_item_schema)
|
558
567
|
foreach_obj = Foreach(spec = spec, parent = self)
|
559
568
|
foreach_node = self._add_node(foreach_obj)
|
560
|
-
self._add_schema(foreach_item_schema)
|
561
569
|
|
562
570
|
return cast(Flow, foreach_node)
|
563
571
|
|
@@ -580,16 +588,8 @@ class Flow(Node):
|
|
580
588
|
|
581
589
|
loop_spec = LoopSpec(name = "loop_" + str(self._next_sequence_id()),
|
582
590
|
evaluator = e,
|
583
|
-
input_schema=
|
584
|
-
|
585
|
-
properties=input_schema_obj.properties,
|
586
|
-
required=input_schema_obj.required,
|
587
|
-
) if input_schema_obj is not None else None,
|
588
|
-
output_schema=ToolResponseBody(
|
589
|
-
type=output_schema_obj.type,
|
590
|
-
properties=output_schema_obj.properties,
|
591
|
-
required=output_schema_obj.required
|
592
|
-
) if output_schema_obj is not None else None)
|
591
|
+
input_schema=_get_tool_request_body(input_schema_obj),
|
592
|
+
output_schema=_get_tool_response_body(output_schema_obj))
|
593
593
|
while_loop = Loop(spec = loop_spec, parent = self)
|
594
594
|
while_node = self._add_node(while_loop)
|
595
595
|
return cast(Loop, while_node)
|
@@ -599,23 +599,15 @@ class Flow(Node):
|
|
599
599
|
input_schema: type[BaseModel] |None=None,
|
600
600
|
output_schema: type[BaseModel] |None=None) -> "UserFlow": # return a UserFlow object
|
601
601
|
|
602
|
-
|
602
|
+
raise ValueError("userflow is NOT supported yet and it's interface will change.")
|
603
603
|
|
604
604
|
output_schema_obj = _get_json_schema_obj("output", output_schema)
|
605
605
|
input_schema_obj = _get_json_schema_obj("input", input_schema)
|
606
606
|
|
607
607
|
spec = UserFlowSpec(name = "userflow_" + str(self._next_sequence_id()),
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
required=input_schema_obj.required,
|
612
|
-
) if input_schema_obj is not None else None,
|
613
|
-
output_schema=ToolResponseBody(
|
614
|
-
type=output_schema_obj.type,
|
615
|
-
properties=output_schema_obj.properties,
|
616
|
-
required=output_schema_obj.required
|
617
|
-
) if output_schema_obj is not None else None,
|
618
|
-
owners = owners)
|
608
|
+
input_schema=_get_tool_request_body(input_schema_obj),
|
609
|
+
output_schema=_get_tool_response_body(output_schema_obj),
|
610
|
+
owners = owners)
|
619
611
|
userflow_obj = UserFlow(spec = spec, parent = self)
|
620
612
|
userflow_node = self._add_node(userflow_obj)
|
621
613
|
|
@@ -822,7 +814,7 @@ class FlowRun(BaseModel):
|
|
822
814
|
def _on_flow_end(self, event:FlowEvent):
|
823
815
|
|
824
816
|
self.status = FlowRunStatus.COMPLETED
|
825
|
-
self.output = event.context.data
|
817
|
+
self.output = event.context.data.output
|
826
818
|
|
827
819
|
if self.debug:
|
828
820
|
logger.debug(f"Flow run `{self.name}`: on_complete handler called. Output: {self.output}")
|
@@ -938,16 +930,8 @@ class FlowFactory(BaseModel):
|
|
938
930
|
display_name=display_name,
|
939
931
|
description=description,
|
940
932
|
initiators=initiators,
|
941
|
-
input_schema=
|
942
|
-
|
943
|
-
properties=input_schema_obj.properties,
|
944
|
-
required=input_schema_obj.required,
|
945
|
-
) if input_schema_obj else None,
|
946
|
-
output_schema=ToolResponseBody(
|
947
|
-
type=output_schema_obj.type,
|
948
|
-
properties=output_schema_obj.properties,
|
949
|
-
required=output_schema_obj.required
|
950
|
-
) if output_schema_obj else None,
|
933
|
+
input_schema=_get_tool_request_body(input_schema_obj),
|
934
|
+
output_schema=_get_tool_response_body(output_schema_obj),
|
951
935
|
output_schema_object = output_schema_obj
|
952
936
|
)
|
953
937
|
|
@@ -974,6 +958,9 @@ class Branch(FlowControl):
|
|
974
958
|
Returns:
|
975
959
|
Self: The current node.
|
976
960
|
'''
|
961
|
+
if kind == MatchPolicy.ANY_MATCH:
|
962
|
+
raise ValueError("Branch with policy ANY_MATCH is not supported yet.")
|
963
|
+
|
977
964
|
self.spec.match_policy = kind
|
978
965
|
return self
|
979
966
|
|
@@ -1286,12 +1273,8 @@ class UserFlow(Flow):
|
|
1286
1273
|
display_name=display_name,
|
1287
1274
|
description=description,
|
1288
1275
|
owners=owners,
|
1289
|
-
input_schema=
|
1290
|
-
output_schema=
|
1291
|
-
type=output_schema_obj.type,
|
1292
|
-
properties=output_schema_obj.properties,
|
1293
|
-
required=output_schema_obj.required
|
1294
|
-
),
|
1276
|
+
input_schema=_get_tool_request_body(output_schema_obj),
|
1277
|
+
output_schema=_get_tool_response_body(output_schema_obj),
|
1295
1278
|
text=text,
|
1296
1279
|
output_schema_object = output_schema_obj
|
1297
1280
|
)
|
@@ -14,7 +14,7 @@ from langchain_core.tools.base import create_schema_from_function
|
|
14
14
|
from langchain_core.utils.json_schema import dereference_refs
|
15
15
|
|
16
16
|
from ibm_watsonx_orchestrate.agent_builder.tools import PythonTool
|
17
|
-
from ibm_watsonx_orchestrate.
|
17
|
+
from ibm_watsonx_orchestrate.flow_builder.flows.constants import ANY_USER
|
18
18
|
from ibm_watsonx_orchestrate.agent_builder.tools.types import (
|
19
19
|
ToolSpec, ToolRequestBody, ToolResponseBody, JsonSchemaObject
|
20
20
|
)
|
@@ -29,9 +29,9 @@ class SchemaRef(BaseModel):
|
|
29
29
|
|
30
30
|
ref: str = Field(description="The id of the schema to be used.", serialization_alias="$ref")
|
31
31
|
|
32
|
-
def _assign_attribute(
|
32
|
+
def _assign_attribute(model_spec, attr_name, schema):
|
33
33
|
if hasattr(schema, attr_name) and (getattr(schema, attr_name) is not None):
|
34
|
-
|
34
|
+
model_spec[attr_name] = getattr(schema, attr_name)
|
35
35
|
|
36
36
|
def _to_json_from_json_schema(schema: JsonSchemaObject) -> dict[str, Any]:
|
37
37
|
model_spec = {}
|
@@ -62,12 +62,14 @@ def _to_json_from_json_schema(schema: JsonSchemaObject) -> dict[str, Any]:
|
|
62
62
|
model_spec["anyOf"] = [_to_json_from_json_schema(schema) for schema in schema.anyOf]
|
63
63
|
|
64
64
|
_assign_attribute(model_spec, "in_field", schema)
|
65
|
+
_assign_attribute(model_spec, "in", schema)
|
65
66
|
_assign_attribute(model_spec, "aliasName", schema)
|
66
67
|
|
67
68
|
if hasattr(schema, 'model_extra') and schema.model_extra:
|
68
69
|
# for each extra fiels, add it to the model spec
|
69
70
|
for key, value in schema.model_extra.items():
|
70
|
-
|
71
|
+
if value is not None:
|
72
|
+
model_spec[key] = value
|
71
73
|
|
72
74
|
if isinstance(schema, JsonSchemaObjectRef):
|
73
75
|
model_spec["$ref"] = schema.ref
|
@@ -635,6 +637,11 @@ class TaskEventType(Enum):
|
|
635
637
|
ON_TASK_STREAM = "on_task_stream"
|
636
638
|
ON_TASK_ERROR = "on_task_error"
|
637
639
|
|
640
|
+
class FlowData(BaseModel):
|
641
|
+
'''This class represents the data that is passed between tasks in a flow.'''
|
642
|
+
input: dict[str, Any] = Field(default_factory=dict)
|
643
|
+
output: dict[str, Any] = Field(default_factory=dict)
|
644
|
+
|
638
645
|
class FlowContext(BaseModel):
|
639
646
|
|
640
647
|
name: str | None = None # name of the process or task
|
@@ -642,10 +649,12 @@ class FlowContext(BaseModel):
|
|
642
649
|
flow_id: str | None = None # id of the flow, this is at the flow definition level
|
643
650
|
instance_id: str | None = None
|
644
651
|
thread_id: str | None = None
|
652
|
+
correlation_id: str | None = None
|
653
|
+
tenant_id: str | None = None
|
645
654
|
parent_context: Any | None = None
|
646
655
|
child_context: List["FlowContext"] | None = None
|
647
656
|
metadata: dict = Field(default_factory=dict[str, Any])
|
648
|
-
data:
|
657
|
+
data: Optional[FlowData] = None
|
649
658
|
|
650
659
|
def get(self, key: str) -> Any:
|
651
660
|
|
@@ -655,7 +664,7 @@ class FlowContext(BaseModel):
|
|
655
664
|
if self.parent_context:
|
656
665
|
pc = cast(FlowContext, self.parent_conetxt)
|
657
666
|
return pc.get(key)
|
658
|
-
|
667
|
+
|
659
668
|
class FlowEventType(Enum):
|
660
669
|
|
661
670
|
ON_FLOW_START = "on_flow_start"
|
@@ -0,0 +1,185 @@
|
|
1
|
+
import inspect
|
2
|
+
import json
|
3
|
+
from pathlib import Path
|
4
|
+
import re
|
5
|
+
import logging
|
6
|
+
import importlib.resources
|
7
|
+
import yaml
|
8
|
+
|
9
|
+
from pydantic import BaseModel, TypeAdapter
|
10
|
+
from typing import types
|
11
|
+
|
12
|
+
from langchain_core.utils.json_schema import dereference_refs
|
13
|
+
import typer
|
14
|
+
|
15
|
+
from ibm_watsonx_orchestrate.agent_builder.connections.types import ConnectionEnvironment, ConnectionPreference, ConnectionSecurityScheme
|
16
|
+
from ibm_watsonx_orchestrate.agent_builder.tools.openapi_tool import create_openapi_json_tools_from_content
|
17
|
+
from ibm_watsonx_orchestrate.agent_builder.tools.types import JsonSchemaObject, ToolRequestBody, ToolResponseBody
|
18
|
+
from ibm_watsonx_orchestrate.cli.commands.connections.connections_controller import add_connection, configure_connection, set_credentials_connection
|
19
|
+
from ibm_watsonx_orchestrate.client.connections.utils import get_connections_client
|
20
|
+
from ibm_watsonx_orchestrate.client.tools.tempus_client import TempusClient
|
21
|
+
from ibm_watsonx_orchestrate.client.utils import instantiate_client, is_local_dev
|
22
|
+
|
23
|
+
logger = logging.getLogger(__name__)
|
24
|
+
|
25
|
+
def get_valid_name(name: str) -> str:
|
26
|
+
|
27
|
+
return re.sub('\\W|^(?=\\d)','_', name)
|
28
|
+
|
29
|
+
def _get_json_schema_obj(parameter_name: str, type_def: type[BaseModel] | ToolRequestBody | ToolResponseBody | None, openapi_decode: bool = False) -> JsonSchemaObject:
|
30
|
+
if not type_def or type_def is None or type_def == inspect._empty:
|
31
|
+
return None
|
32
|
+
|
33
|
+
if inspect.isclass(type_def) and issubclass(type_def, BaseModel):
|
34
|
+
schema_json = type_def.model_json_schema()
|
35
|
+
schema_json = dereference_refs(schema_json)
|
36
|
+
schema_obj = JsonSchemaObject(**schema_json)
|
37
|
+
if schema_obj.required is None:
|
38
|
+
schema_obj.required = []
|
39
|
+
return schema_obj
|
40
|
+
|
41
|
+
if isinstance(type_def, ToolRequestBody) or isinstance(type_def, ToolResponseBody):
|
42
|
+
schema_json = type_def.model_dump()
|
43
|
+
schema_obj = JsonSchemaObject.model_validate(schema_json)
|
44
|
+
|
45
|
+
if openapi_decode:
|
46
|
+
# during tool import for openapi - we convert header, path and query parameter
|
47
|
+
# with a prefix "header_", "path_" and "query_". We need to remove it.
|
48
|
+
if schema_obj.type == 'object':
|
49
|
+
# for each element in properties, we need to check the key and if it is
|
50
|
+
# prefixed with "header_", "path_" and "query_", we need to remove the prefix.
|
51
|
+
if hasattr(schema_obj, "properties"):
|
52
|
+
new_properties = {}
|
53
|
+
for key, value in schema_obj.properties.items():
|
54
|
+
if key.startswith('header_'):
|
55
|
+
new_properties[key[7:]] = value
|
56
|
+
elif key.startswith('path_'):
|
57
|
+
new_properties[key[5:]] = value
|
58
|
+
elif key.startswith('query_'):
|
59
|
+
new_properties[key[6:]] = value
|
60
|
+
else:
|
61
|
+
new_properties[key] = value
|
62
|
+
|
63
|
+
schema_obj.properties = new_properties
|
64
|
+
|
65
|
+
# we also need to go thru required and replace it
|
66
|
+
if hasattr(schema_obj, "required"):
|
67
|
+
new_required = []
|
68
|
+
for item in schema_obj.required:
|
69
|
+
if item.startswith('header_'):
|
70
|
+
new_required.append(item[7:])
|
71
|
+
elif item.startswith('path_'):
|
72
|
+
new_required.append(item[5:])
|
73
|
+
elif item.startswith('query_'):
|
74
|
+
new_required.append(item[6:])
|
75
|
+
else:
|
76
|
+
new_required.append(item)
|
77
|
+
schema_obj.required = new_required
|
78
|
+
|
79
|
+
return schema_obj
|
80
|
+
|
81
|
+
# handle the non-obvious cases
|
82
|
+
schema_json = TypeAdapter(type_def).json_schema()
|
83
|
+
schema_json = dereference_refs(schema_json)
|
84
|
+
return JsonSchemaObject.model_validate(schema_json)
|
85
|
+
|
86
|
+
|
87
|
+
def _get_tool_request_body(schema_obj: JsonSchemaObject) -> ToolRequestBody:
|
88
|
+
if schema_obj is None:
|
89
|
+
return None
|
90
|
+
|
91
|
+
if isinstance(schema_obj, JsonSchemaObject):
|
92
|
+
request_obj = ToolRequestBody(type='object', properties=schema_obj.properties, required=schema_obj.required)
|
93
|
+
if schema_obj.model_extra:
|
94
|
+
request_obj.__pydantic_extra__ = schema_obj.model_extra
|
95
|
+
|
96
|
+
return request_obj
|
97
|
+
|
98
|
+
raise ValueError(f"Invalid schema object: {schema_obj}")
|
99
|
+
|
100
|
+
def _get_tool_response_body(schema_obj: JsonSchemaObject) -> ToolResponseBody:
|
101
|
+
if schema_obj is None:
|
102
|
+
return None
|
103
|
+
|
104
|
+
if isinstance(schema_obj, JsonSchemaObject):
|
105
|
+
response_obj = ToolResponseBody(type=schema_obj.type)
|
106
|
+
if schema_obj.title:
|
107
|
+
response_obj.title = schema_obj.title
|
108
|
+
if schema_obj.description:
|
109
|
+
response_obj.description = schema_obj.description
|
110
|
+
if schema_obj.properties:
|
111
|
+
response_obj.properties = schema_obj.properties
|
112
|
+
if schema_obj.items:
|
113
|
+
response_obj.items = schema_obj.items
|
114
|
+
if schema_obj.uniqueItems:
|
115
|
+
response_obj.uniqueItems = schema_obj.uniqueItems
|
116
|
+
if schema_obj.anyOf:
|
117
|
+
response_obj.anyOf = schema_obj.anyOf
|
118
|
+
if schema_obj.required:
|
119
|
+
response_obj.required = schema_obj.required
|
120
|
+
|
121
|
+
if schema_obj.model_extra:
|
122
|
+
response_obj.__pydantic_extra__ = schema_obj.model_extra
|
123
|
+
|
124
|
+
return response_obj
|
125
|
+
|
126
|
+
raise ValueError(f"Invalid schema object: {schema_obj}")
|
127
|
+
|
128
|
+
|
129
|
+
async def import_flow_model(model):
|
130
|
+
|
131
|
+
if not is_local_dev():
|
132
|
+
raise typer.BadParameter(f"Flow tools are only supported in local environment.")
|
133
|
+
|
134
|
+
if model is None:
|
135
|
+
raise typer.BadParameter(f"No model provided.")
|
136
|
+
|
137
|
+
tools = []
|
138
|
+
|
139
|
+
flow_id = model["spec"]["name"]
|
140
|
+
|
141
|
+
tempus_client: TempusClient = instantiate_client(TempusClient)
|
142
|
+
|
143
|
+
flow_open_api = tempus_client.create_update_flow_model(flow_id=flow_id, model=model)
|
144
|
+
|
145
|
+
logger.info(f"Flow model `{flow_id}` deployed successfully.")
|
146
|
+
|
147
|
+
connections_client = get_connections_client()
|
148
|
+
|
149
|
+
app_id = "flow_tools_app"
|
150
|
+
logger.info(f"Creating connection for flow model...")
|
151
|
+
existing_app = connections_client.get(app_id=app_id)
|
152
|
+
if not existing_app:
|
153
|
+
# logger.info(f"Creating app `{app_id}`.")
|
154
|
+
add_connection(app_id=app_id)
|
155
|
+
# else:
|
156
|
+
# logger.info(f"App `{app_id}` already exists.")
|
157
|
+
|
158
|
+
# logger.info(f"Creating connection for app...")
|
159
|
+
configure_connection(
|
160
|
+
type=ConnectionPreference.MEMBER,
|
161
|
+
app_id=app_id,
|
162
|
+
token=connections_client.api_key,
|
163
|
+
environment=ConnectionEnvironment.DRAFT,
|
164
|
+
security_scheme=ConnectionSecurityScheme.BEARER_TOKEN,
|
165
|
+
shared=False
|
166
|
+
)
|
167
|
+
|
168
|
+
set_credentials_connection(app_id=app_id, environment=ConnectionEnvironment.DRAFT, token=connections_client.api_key)
|
169
|
+
|
170
|
+
connections = connections_client.get_draft_by_app_id(app_id=app_id)
|
171
|
+
|
172
|
+
# logger.info(f"Connection `{connections.connection_id}` created successfully.")
|
173
|
+
|
174
|
+
tools = await create_openapi_json_tools_from_content(flow_open_api, connections.connection_id)
|
175
|
+
|
176
|
+
logger.info(f"Generating 'get_flow_status' tool spec...")
|
177
|
+
# Temporary code to deploy a status tool until we have full async support
|
178
|
+
with importlib.resources.open_text('ibm_watsonx_orchestrate.flow_builder.resources', 'flow_status.openapi.yml', encoding='utf-8') as f:
|
179
|
+
get_status_openapi = f.read()
|
180
|
+
|
181
|
+
get_flow_status_spec = yaml.safe_load(get_status_openapi)
|
182
|
+
tools.extend(await create_openapi_json_tools_from_content(get_flow_status_spec, connections.connection_id))
|
183
|
+
|
184
|
+
|
185
|
+
return tools
|
{ibm_watsonx_orchestrate-1.5.1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ibm-watsonx-orchestrate
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.6.0b0
|
4
4
|
Summary: IBM watsonx.orchestrate SDK
|
5
5
|
Author-email: IBM <support@ibm.com>
|
6
6
|
License: MIT License
|
@@ -11,6 +11,7 @@ Requires-Dist: click<8.2.0,>=8.0.0
|
|
11
11
|
Requires-Dist: docstring-parser<1.0,>=0.16
|
12
12
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
13
13
|
Requires-Dist: ibm-cloud-sdk-core>=3.22.0
|
14
|
+
Requires-Dist: ibm-watsonx-orchestrate-evaluation-framework==1.0.2
|
14
15
|
Requires-Dist: jsonref==1.1.0
|
15
16
|
Requires-Dist: jsonschema<5.0.0,>=4.23.0
|
16
17
|
Requires-Dist: langchain-community<1.0.0,>=0.3.12
|