ibm-watsonx-orchestrate 1.7.0a0__py3-none-any.whl → 1.8.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.
- ibm_watsonx_orchestrate/__init__.py +1 -1
- ibm_watsonx_orchestrate/agent_builder/agents/agent.py +3 -3
- ibm_watsonx_orchestrate/agent_builder/agents/assistant_agent.py +3 -2
- ibm_watsonx_orchestrate/agent_builder/agents/external_agent.py +3 -2
- ibm_watsonx_orchestrate/agent_builder/agents/types.py +38 -9
- ibm_watsonx_orchestrate/agent_builder/agents/webchat_customizations/prompts.py +1 -0
- ibm_watsonx_orchestrate/agent_builder/connections/connections.py +25 -10
- ibm_watsonx_orchestrate/agent_builder/connections/types.py +19 -11
- ibm_watsonx_orchestrate/agent_builder/knowledge_bases/knowledge_base_requests.py +1 -22
- ibm_watsonx_orchestrate/agent_builder/knowledge_bases/types.py +1 -17
- ibm_watsonx_orchestrate/agent_builder/tools/base_tool.py +2 -1
- ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py +14 -13
- ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +136 -92
- ibm_watsonx_orchestrate/agent_builder/tools/types.py +10 -9
- ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +7 -7
- ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +35 -7
- ibm_watsonx_orchestrate/cli/commands/channels/types.py +15 -2
- ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +35 -25
- ibm_watsonx_orchestrate/cli/commands/chat/chat_command.py +2 -0
- ibm_watsonx_orchestrate/cli/commands/connections/connections_command.py +14 -6
- ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +12 -12
- ibm_watsonx_orchestrate/cli/commands/copilot/copilot_command.py +65 -0
- ibm_watsonx_orchestrate/cli/commands/copilot/copilot_controller.py +368 -0
- ibm_watsonx_orchestrate/cli/commands/copilot/copilot_server_controller.py +170 -0
- ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +6 -6
- ibm_watsonx_orchestrate/cli/commands/environment/types.py +3 -1
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +134 -36
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +42 -11
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +0 -18
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +36 -20
- ibm_watsonx_orchestrate/cli/commands/models/models_command.py +1 -1
- ibm_watsonx_orchestrate/cli/commands/models/models_controller.py +5 -8
- ibm_watsonx_orchestrate/cli/commands/server/server_command.py +59 -10
- ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_command.py +1 -1
- ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +93 -14
- ibm_watsonx_orchestrate/cli/config.py +3 -3
- ibm_watsonx_orchestrate/cli/init_helper.py +10 -1
- ibm_watsonx_orchestrate/cli/main.py +5 -0
- ibm_watsonx_orchestrate/client/base_api_client.py +12 -0
- ibm_watsonx_orchestrate/client/connections/connections_client.py +5 -30
- ibm_watsonx_orchestrate/client/copilot/cpe/copilot_cpe_client.py +67 -0
- ibm_watsonx_orchestrate/client/knowledge_bases/knowledge_base_client.py +1 -1
- ibm_watsonx_orchestrate/client/local_service_instance.py +3 -1
- ibm_watsonx_orchestrate/client/service_instance.py +33 -7
- ibm_watsonx_orchestrate/client/utils.py +49 -8
- ibm_watsonx_orchestrate/docker/compose-lite.yml +25 -6
- ibm_watsonx_orchestrate/docker/default.env +26 -15
- ibm_watsonx_orchestrate/flow_builder/flows/__init__.py +9 -4
- ibm_watsonx_orchestrate/flow_builder/flows/decorators.py +4 -2
- ibm_watsonx_orchestrate/flow_builder/flows/events.py +10 -9
- ibm_watsonx_orchestrate/flow_builder/flows/flow.py +131 -20
- ibm_watsonx_orchestrate/flow_builder/node.py +18 -1
- ibm_watsonx_orchestrate/flow_builder/types.py +271 -15
- ibm_watsonx_orchestrate/flow_builder/utils.py +121 -6
- ibm_watsonx_orchestrate/utils/exceptions.py +23 -0
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/METADATA +5 -5
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/RECORD +60 -56
- ibm_watsonx_orchestrate/flow_builder/resources/flow_status.openapi.yml +0 -66
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/WHEEL +0 -0
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/entry_points.txt +0 -0
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,7 +5,7 @@ import uuid
|
|
5
5
|
import yaml
|
6
6
|
from pydantic import BaseModel, Field, SerializeAsAny
|
7
7
|
|
8
|
-
from .types import EndNodeSpec, NodeSpec, AgentNodeSpec, PromptNodeSpec, StartNodeSpec, ToolNodeSpec, UserFieldKind, UserFieldOption, UserNodeSpec
|
8
|
+
from .types import EndNodeSpec, NodeSpec, AgentNodeSpec, PromptNodeSpec, StartNodeSpec, ToolNodeSpec, UserFieldKind, UserFieldOption, UserNodeSpec, DocProcSpec, DecisionsNodeSpec
|
9
9
|
from .data_map import DataMap
|
10
10
|
|
11
11
|
class Node(BaseModel):
|
@@ -78,6 +78,8 @@ class UserNode(Node):
|
|
78
78
|
description: str | None = None,
|
79
79
|
default: Any | None = None,
|
80
80
|
option: UserFieldOption | None = None,
|
81
|
+
min: Any | None = None,
|
82
|
+
max: Any | None = None,
|
81
83
|
is_list: bool = False,
|
82
84
|
custom: dict[str, Any] | None = None,
|
83
85
|
widget: str | None = None):
|
@@ -88,6 +90,8 @@ class UserNode(Node):
|
|
88
90
|
description=description,
|
89
91
|
default=default,
|
90
92
|
option=option,
|
93
|
+
min=min,
|
94
|
+
max=max,
|
91
95
|
is_list=is_list,
|
92
96
|
custom=custom,
|
93
97
|
widget=widget)
|
@@ -105,7 +109,20 @@ class PromptNode(Node):
|
|
105
109
|
|
106
110
|
def get_spec(self) -> PromptNodeSpec:
|
107
111
|
return cast(PromptNodeSpec, self.spec)
|
112
|
+
|
113
|
+
class DocProcNode(Node):
|
114
|
+
def __repr__(self):
|
115
|
+
return f"DocProcNode(name='{self.spec.name}', description='{self.spec.description}')"
|
108
116
|
|
117
|
+
def get_spec(self) -> DocProcSpec:
|
118
|
+
return cast(DocProcSpec, self.spec)
|
119
|
+
class DecisionsNode(Node):
|
120
|
+
def __repr__(self):
|
121
|
+
return f"DecisionsNode(name='{self.spec.name}', description='{self.spec.description}')"
|
122
|
+
|
123
|
+
def get_spec(self) -> DecisionsNodeSpec:
|
124
|
+
return cast(DecisionsNodeSpec, self.spec)
|
125
|
+
|
109
126
|
class NodeInstance(BaseModel):
|
110
127
|
node: Node
|
111
128
|
id: str # unique id of this task instance
|
@@ -1,5 +1,7 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from enum import Enum
|
2
|
+
from enum import Enum, StrEnum, auto
|
3
|
+
from datetime import date
|
4
|
+
import numbers
|
3
5
|
import inspect
|
4
6
|
import logging
|
5
7
|
from typing import (
|
@@ -116,7 +118,7 @@ def _to_json_from_output_schema(schema: Union[ToolResponseBody, SchemaRef]) -> d
|
|
116
118
|
return model_spec
|
117
119
|
|
118
120
|
class NodeSpec(BaseModel):
|
119
|
-
kind: Literal["node", "tool", "user", "agent", "flow", "start", "decisions", "prompt", "branch", "wait", "foreach", "loop", "userflow", "end"] = "node"
|
121
|
+
kind: Literal["node", "tool", "user", "agent", "flow", "start", "decisions", "prompt", "branch", "wait", "foreach", "loop", "userflow", "end", "docproc" ] = "node"
|
120
122
|
name: str
|
121
123
|
display_name: str | None = None
|
122
124
|
description: str | None = None
|
@@ -162,6 +164,24 @@ class NodeSpec(BaseModel):
|
|
162
164
|
|
163
165
|
return model_spec
|
164
166
|
|
167
|
+
class DocProcTask(StrEnum):
|
168
|
+
'''
|
169
|
+
Possible names for the Document processing task parameter
|
170
|
+
'''
|
171
|
+
text_extraction = auto()
|
172
|
+
|
173
|
+
class DocProcSpec(NodeSpec):
|
174
|
+
task: DocProcTask = Field(description='The document processing operation name', default=DocProcTask.text_extraction)
|
175
|
+
|
176
|
+
def __init__(self, **data):
|
177
|
+
super().__init__(**data)
|
178
|
+
self.kind = "docproc"
|
179
|
+
|
180
|
+
def to_json(self) -> dict[str, Any]:
|
181
|
+
model_spec = super().to_json()
|
182
|
+
model_spec["task"] = self.task
|
183
|
+
return model_spec
|
184
|
+
|
165
185
|
class StartNodeSpec(NodeSpec):
|
166
186
|
def __init__(self, **data):
|
167
187
|
super().__init__(**data)
|
@@ -296,6 +316,8 @@ class UserField(BaseModel):
|
|
296
316
|
description: str | None = None
|
297
317
|
default: Any | None = None
|
298
318
|
option: UserFieldOption | None = None
|
319
|
+
min: Any | None = None,
|
320
|
+
max: Any | None = None,
|
299
321
|
is_list: bool = False
|
300
322
|
custom: dict[str, Any] | None = None
|
301
323
|
widget: str | None = None
|
@@ -314,6 +336,10 @@ class UserField(BaseModel):
|
|
314
336
|
model_spec["description"] = self.description
|
315
337
|
if self.default:
|
316
338
|
model_spec["default"] = self.default
|
339
|
+
if self.min:
|
340
|
+
model_spec["min"] = self.min
|
341
|
+
if self.max:
|
342
|
+
model_spec["min"] = self.max
|
317
343
|
if self.is_list:
|
318
344
|
model_spec["is_list"] = self.is_list
|
319
345
|
if self.option:
|
@@ -356,7 +382,10 @@ class UserNodeSpec(NodeSpec):
|
|
356
382
|
display_name: str | None = None,
|
357
383
|
description: str | None = None,
|
358
384
|
default: Any | None = None,
|
359
|
-
option: list[str] | None = None,
|
385
|
+
option: list[str] | None = None,
|
386
|
+
min: Any | None = None,
|
387
|
+
max: Any | None = None,
|
388
|
+
is_list: bool = False,
|
360
389
|
custom: dict[str, Any] | None = None,
|
361
390
|
widget: str | None = None):
|
362
391
|
userfield = UserField(name=name,
|
@@ -366,6 +395,8 @@ class UserNodeSpec(NodeSpec):
|
|
366
395
|
description=description,
|
367
396
|
default=default,
|
368
397
|
option=option,
|
398
|
+
min=min,
|
399
|
+
max=max,
|
369
400
|
is_list=is_list,
|
370
401
|
custom=custom,
|
371
402
|
widget=widget)
|
@@ -402,6 +433,8 @@ class UserNodeSpec(NodeSpec):
|
|
402
433
|
default=prop_schema.default,
|
403
434
|
option=self.setup_field_options(prop_schema.title, prop_schema.enum),
|
404
435
|
is_list=prop_schema.type == "array",
|
436
|
+
min=prop_schema.minimum,
|
437
|
+
max=prop_schema.maximum,
|
405
438
|
custom=prop_schema.model_extra))
|
406
439
|
|
407
440
|
def setup_field_options(self, name: str, enums: List[str]) -> UserFieldOption:
|
@@ -415,6 +448,7 @@ class UserNodeSpec(NodeSpec):
|
|
415
448
|
|
416
449
|
class AgentNodeSpec(ToolNodeSpec):
|
417
450
|
message: str | None = Field(default=None, description="The instructions for the task.")
|
451
|
+
title: str | None = Field(default=None, description="The title of the message.")
|
418
452
|
guidelines: str | None = Field(default=None, description="The guidelines for the task.")
|
419
453
|
agent: str
|
420
454
|
|
@@ -430,6 +464,8 @@ class AgentNodeSpec(ToolNodeSpec):
|
|
430
464
|
model_spec["guidelines"] = self.guidelines
|
431
465
|
if self.agent:
|
432
466
|
model_spec["agent"] = self.agent
|
467
|
+
if self.title:
|
468
|
+
model_spec["title"] = self.title
|
433
469
|
return model_spec
|
434
470
|
|
435
471
|
class PromptLLMParameters(BaseModel):
|
@@ -479,6 +515,7 @@ class PromptNodeSpec(NodeSpec):
|
|
479
515
|
model_spec["llm_parameters"] = self.llm_parameters.to_json()
|
480
516
|
|
481
517
|
return model_spec
|
518
|
+
|
482
519
|
|
483
520
|
class Expression(BaseModel):
|
484
521
|
'''An expression could return a boolean or a value'''
|
@@ -553,10 +590,9 @@ class WaitNodeSpec(FlowControlNodeSpec):
|
|
553
590
|
return my_dict
|
554
591
|
|
555
592
|
class FlowSpec(NodeSpec):
|
556
|
-
|
557
|
-
|
558
593
|
# who can initiate the flow
|
559
594
|
initiators: Sequence[str] = [ANY_USER]
|
595
|
+
schedulable: bool = False
|
560
596
|
|
561
597
|
def __init__(self, **kwargs):
|
562
598
|
super().__init__(**kwargs)
|
@@ -566,6 +602,8 @@ class FlowSpec(NodeSpec):
|
|
566
602
|
model_spec = super().to_json()
|
567
603
|
if self.initiators:
|
568
604
|
model_spec["initiators"] = self.initiators
|
605
|
+
|
606
|
+
model_spec["schedulable"] = self.schedulable
|
569
607
|
|
570
608
|
return model_spec
|
571
609
|
|
@@ -631,11 +669,11 @@ class TaskData(NamedTuple):
|
|
631
669
|
|
632
670
|
class TaskEventType(Enum):
|
633
671
|
|
634
|
-
ON_TASK_WAIT = "on_task_wait" # the task is waiting for inputs before proceeding
|
635
|
-
ON_TASK_START = "on_task_start"
|
636
|
-
ON_TASK_END = "on_task_end"
|
637
|
-
ON_TASK_STREAM = "on_task_stream"
|
638
|
-
ON_TASK_ERROR = "on_task_error"
|
672
|
+
ON_TASK_WAIT = "task:on_task_wait" # the task is waiting for inputs before proceeding
|
673
|
+
ON_TASK_START = "task:on_task_start"
|
674
|
+
ON_TASK_END = "task:on_task_end"
|
675
|
+
ON_TASK_STREAM = "task:on_task_stream"
|
676
|
+
ON_TASK_ERROR = "task:on_task_error"
|
639
677
|
|
640
678
|
class FlowData(BaseModel):
|
641
679
|
'''This class represents the data that is passed between tasks in a flow.'''
|
@@ -667,9 +705,9 @@ class FlowContext(BaseModel):
|
|
667
705
|
|
668
706
|
class FlowEventType(Enum):
|
669
707
|
|
670
|
-
ON_FLOW_START = "on_flow_start"
|
671
|
-
ON_FLOW_END = "on_flow_end"
|
672
|
-
ON_FLOW_ERROR = "on_flow_error"
|
708
|
+
ON_FLOW_START = "flow:on_flow_start"
|
709
|
+
ON_FLOW_END = "flow:on_flow_end"
|
710
|
+
ON_FLOW_ERROR = "flow:on_flow_error"
|
673
711
|
|
674
712
|
|
675
713
|
@dataclass
|
@@ -691,9 +729,227 @@ class Assignment(BaseModel):
|
|
691
729
|
e.g. "node.input.name" or "=f'{node.output.name}_{node.output.id}'"
|
692
730
|
|
693
731
|
'''
|
694
|
-
|
695
|
-
|
732
|
+
target_variable: str
|
733
|
+
value_expression: str | None = None
|
734
|
+
has_no_value: bool = False
|
735
|
+
default_value: Any | None = None
|
736
|
+
metadata: dict = Field(default_factory=dict[str, Any])
|
737
|
+
|
738
|
+
class LanguageCode(StrEnum):
|
739
|
+
'''
|
740
|
+
The ISO-639 language codes understood by Document Processing functions.
|
741
|
+
A special 'en_hw' code is used to enable an English handwritten model.
|
742
|
+
'''
|
743
|
+
en = auto()
|
744
|
+
fr = auto()
|
745
|
+
en_hw = auto()
|
746
|
+
|
747
|
+
class File(BaseModel):
|
748
|
+
'''
|
749
|
+
This class represents the input of a Document processing task.
|
750
|
+
|
751
|
+
Attributes:
|
752
|
+
document_ref (bytes|str): This is either a URL to the location of the document bytes or an ID that we use to resolve the location of the document
|
753
|
+
language (LanguageCode): Optional language code used when processing the input document
|
754
|
+
'''
|
755
|
+
# This is declared as bytes but the runtime will understand if a URL is send in as input.
|
756
|
+
# We need to use bytes here for Chat-with-doc to recognize the input as a File.
|
757
|
+
document_ref: bytes | str = Field(
|
758
|
+
description="Either an ID or a URL identifying the document to be used.",
|
759
|
+
title='Document reference',
|
760
|
+
default=None,
|
761
|
+
json_schema_extra={"format": "binary"})
|
762
|
+
language: Optional[LanguageCode] = Field(
|
763
|
+
description='Optional language code of the document, defaults to "en"',
|
764
|
+
title='Document language code',
|
765
|
+
default=LanguageCode.en)
|
766
|
+
|
767
|
+
class TextExtraction(BaseModel):
|
768
|
+
'''
|
769
|
+
This class represents the output generated by a "text_extraction" document processing (docproc) operation.
|
770
|
+
Attributes:
|
771
|
+
text (str): the text extracted from the input document.
|
772
|
+
'''
|
773
|
+
text: str = Field(description='The text extracted from the input document', title='Text extraction')
|
774
|
+
|
775
|
+
class TextExtractionResponse(BaseModel):
|
776
|
+
'''
|
777
|
+
The text extraction operation response.
|
778
|
+
Attributes:
|
779
|
+
output (TextExtraction): a wrapper for the text extraction response
|
780
|
+
'''
|
781
|
+
output: TextExtraction = Field(description='The text extraction response')
|
782
|
+
|
783
|
+
|
784
|
+
class DecisionsCondition(BaseModel):
|
785
|
+
_condition: str | None = None
|
786
|
+
|
787
|
+
def greater_than(self, value: Union[numbers.Number, date, str]) -> Self:
|
788
|
+
self._check_type_is_number_or_date_or_str(value)
|
789
|
+
self._condition = f"> {self._format_value(value)}"
|
790
|
+
return self
|
791
|
+
|
792
|
+
def greater_than_or_equal(self, value: Union[numbers.Number, date, str]) -> Self:
|
793
|
+
self._check_type_is_number_or_date_or_str(value)
|
794
|
+
self._condition = f">= {self._format_value(value)}"
|
795
|
+
return self
|
796
|
+
|
797
|
+
def less_than(self, value: Union[numbers.Number, date, str]) -> Self:
|
798
|
+
self._check_type_is_number_or_date_or_str(value)
|
799
|
+
self._condition = f"< {self._format_value(value)}"
|
800
|
+
return self
|
801
|
+
|
802
|
+
def less_than_or_equal(self, value: Union[numbers.Number, date, str]) -> Self:
|
803
|
+
self._check_type_is_number_or_date_or_str(value)
|
804
|
+
self._condition = f"<= {self._format_value(value)}"
|
805
|
+
return self
|
806
|
+
|
807
|
+
def equal(self, value: Union[numbers.Number, date, str]) -> Self:
|
808
|
+
self._check_type_is_number_or_date_or_str(value)
|
809
|
+
self._condition = f"== {self._format_value(value)}"
|
810
|
+
return self
|
811
|
+
|
812
|
+
def not_equal(self, value: Union[numbers.Number, date, str]) -> Self:
|
813
|
+
self._check_type_is_number_or_date_or_str(value)
|
814
|
+
self._condition = f"== {self._format_value(value)}"
|
815
|
+
return self
|
816
|
+
|
817
|
+
def contains(self, value: str) -> Self:
|
818
|
+
self._check_type_is_str(value)
|
819
|
+
self._condition = f"contains {self._format_value(value)}"
|
820
|
+
return self
|
821
|
+
|
822
|
+
def not_contains(self, value: str) -> Self:
|
823
|
+
self._check_type_is_str(value)
|
824
|
+
self._condition = f"doesNotContain {self._format_value(value)}"
|
825
|
+
return self
|
826
|
+
|
827
|
+
def is_in(self, value: str) -> Self:
|
828
|
+
self._check_type_is_str(value)
|
829
|
+
self._condition = f"in {self._format_value(value)}"
|
830
|
+
return self
|
831
|
+
|
832
|
+
def is_not_in(self, value: str) -> Self:
|
833
|
+
self._check_type_is_str(value)
|
834
|
+
self._condition = f"notIn {self._format_value(value)}"
|
835
|
+
return self
|
836
|
+
|
837
|
+
def startswith(self, value: str) -> Self:
|
838
|
+
self._check_type_is_str(value)
|
839
|
+
self._condition = f"startsWith {self._format_value(value)}"
|
840
|
+
return self
|
841
|
+
|
842
|
+
def endswith(self, value: str) -> Self:
|
843
|
+
self._check_type_is_str(value)
|
844
|
+
self._condition = f"endsWith {self._format_value(value)}"
|
845
|
+
return self
|
846
|
+
|
847
|
+
|
848
|
+
def in_range(self, startValue: Union[numbers.Number, date], endValue: Union[numbers.Number, date],
|
849
|
+
startsInclusive: bool = False, endsInclusive: bool = False) -> Self:
|
850
|
+
self._check_type_is_number_or_date_or_str(startValue)
|
851
|
+
self._check_type_is_number_or_date_or_str(endValue)
|
852
|
+
if type(startValue) is not type(endValue):
|
853
|
+
raise TypeError("startValue and endValue must be of the same type")
|
854
|
+
start_op = "[" if startsInclusive else "(" # [ is inclusive, ( is exclusive
|
855
|
+
end_op = "]" if endsInclusive else ")"
|
856
|
+
self._condition = f"{start_op}{self._format_value(startValue)}:{self._format_value(endValue)}{end_op}"
|
857
|
+
return self
|
858
|
+
|
859
|
+
def _check_type_is_number_or_date(self, value: Union[numbers.Number, date]):
|
860
|
+
if not isinstance(value, (numbers.Number, date)):
|
861
|
+
raise TypeError("Value must be a number or a date")
|
862
|
+
|
863
|
+
def _check_type_is_number_or_date_or_str(self, value: Union[numbers.Number, date, str]):
|
864
|
+
if not isinstance(value, (numbers.Number, date, str)):
|
865
|
+
raise TypeError("Value must be a number or a date or a string")
|
866
|
+
|
867
|
+
def _check_type_is_str(self, value: str):
|
868
|
+
if not isinstance(value, str):
|
869
|
+
raise TypeError("Value must be a string")
|
870
|
+
|
871
|
+
@staticmethod
|
872
|
+
def _format_value(value: Union[numbers.Number, date, str]):
|
873
|
+
if isinstance(value, numbers.Number):
|
874
|
+
return f"{value}"
|
875
|
+
if isinstance(value, date):
|
876
|
+
return f"\"{value.strftime('%B %d, %Y')}\""
|
877
|
+
return f"\"{value}\""
|
878
|
+
|
879
|
+
def condition(self):
|
880
|
+
return self._condition
|
881
|
+
|
882
|
+
|
883
|
+
|
884
|
+
class DecisionsRule(BaseModel):
|
885
|
+
'''
|
886
|
+
A set of decisions rules.
|
887
|
+
'''
|
888
|
+
_conditions: dict[str, str]
|
889
|
+
_actions: dict[str, Union[numbers.Number, str]]
|
890
|
+
|
891
|
+
def __init__(self, **data):
|
892
|
+
super().__init__(**data)
|
893
|
+
self._conditions = {}
|
894
|
+
self._actions = {}
|
895
|
+
|
896
|
+
def condition(self, key: str, cond: DecisionsCondition) -> Self:
|
897
|
+
self._conditions[key] = cond.condition()
|
898
|
+
return self
|
696
899
|
|
900
|
+
def action(self, key: str, value: Union[numbers.Number, date, str]) -> Self:
|
901
|
+
if isinstance(value, date):
|
902
|
+
self._actions[key] = value.strftime("%B %d, %Y")
|
903
|
+
return self
|
904
|
+
self._actions[key] = value
|
905
|
+
return self
|
906
|
+
|
907
|
+
def to_json(self) -> dict[str, Any]:
|
908
|
+
'''
|
909
|
+
Serialize the rules into JSON object
|
910
|
+
'''
|
911
|
+
model_spec = {}
|
912
|
+
if self._conditions:
|
913
|
+
model_spec["conditions"] = self._conditions
|
914
|
+
if self._actions:
|
915
|
+
model_spec["actions"] = self._actions
|
916
|
+
return model_spec
|
917
|
+
|
918
|
+
|
919
|
+
class DecisionsNodeSpec(NodeSpec):
|
920
|
+
'''
|
921
|
+
Node specification for Decision Table
|
922
|
+
'''
|
923
|
+
locale: str | None = None
|
924
|
+
rules: list[DecisionsRule]
|
925
|
+
default_actions: dict[str, Union[int, float, complex, str]] | None
|
926
|
+
|
927
|
+
def __init__(self, **data):
|
928
|
+
super().__init__(**data)
|
929
|
+
self.kind = "decisions"
|
930
|
+
|
931
|
+
def default_action(self, key: str, value: Union[int, float, complex, date, str]) -> Self:
|
932
|
+
'''
|
933
|
+
create a new default action
|
934
|
+
'''
|
935
|
+
if isinstance(value, date):
|
936
|
+
self.default_actions[key] = value.strftime("%B %d, %Y")
|
937
|
+
return self
|
938
|
+
self.default_actions[key] = value
|
939
|
+
return self
|
940
|
+
|
941
|
+
def to_json(self) -> dict[str, Any]:
|
942
|
+
model_spec = super().to_json()
|
943
|
+
if self.locale:
|
944
|
+
model_spec["locale"] = self.locale
|
945
|
+
if self.rules:
|
946
|
+
model_spec["rules"] = [rule.to_json() for rule in self.rules]
|
947
|
+
if self.default_actions:
|
948
|
+
model_spec["default_actions"] = self.default_actions
|
949
|
+
|
950
|
+
return model_spec
|
951
|
+
|
952
|
+
|
697
953
|
def extract_node_spec(
|
698
954
|
fn: Callable | PythonTool,
|
699
955
|
name: Optional[str] = None,
|
@@ -87,9 +87,15 @@ def _get_tool_request_body(schema_obj: JsonSchemaObject) -> ToolRequestBody:
|
|
87
87
|
return None
|
88
88
|
|
89
89
|
if isinstance(schema_obj, JsonSchemaObject):
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
if schema_obj.type == "object":
|
91
|
+
request_obj = ToolRequestBody(type='object', properties=schema_obj.properties, required=schema_obj.required)
|
92
|
+
if schema_obj.model_extra:
|
93
|
+
request_obj.__pydantic_extra__ = schema_obj.model_extra
|
94
|
+
else: # we need to wrap a simple type with an object
|
95
|
+
request_obj = ToolRequestBody(type='object', properties={}, required=[])
|
96
|
+
request_obj.properties["data"] = schema_obj
|
97
|
+
if schema_obj.model_extra:
|
98
|
+
request_obj.__pydantic_extra__ = schema_obj.model_extra
|
93
99
|
|
94
100
|
return request_obj
|
95
101
|
|
@@ -162,17 +168,27 @@ async def import_flow_model(model):
|
|
162
168
|
|
163
169
|
return tool_id
|
164
170
|
|
165
|
-
def import_flow_support_tools():
|
171
|
+
def import_flow_support_tools(model):
|
166
172
|
|
167
173
|
if not is_local_dev():
|
168
174
|
# we can't import support tools into non-local environments yet
|
169
|
-
return
|
175
|
+
return []
|
176
|
+
|
177
|
+
|
178
|
+
schedulable = False
|
179
|
+
if "schedulable" in model["spec"]:
|
180
|
+
schedulable = model["spec"]["schedulable"]
|
170
181
|
|
171
182
|
client = instantiate_client(TempusClient)
|
172
183
|
|
173
184
|
logger.info(f"Import 'get_flow_status' tool spec...")
|
174
185
|
tools = [create_flow_status_tool("i__get_flow_status_intrinsic_tool__")]
|
175
186
|
|
187
|
+
if schedulable:
|
188
|
+
get_schedule_tool = create_get_schedule_tool("i__get_schedule_intrinsic_tool__")
|
189
|
+
delete_schedule_tool = create_delete_schedule_tool("i__delete_schedule_intrinsic_tool__")
|
190
|
+
tools.extend([get_schedule_tool, delete_schedule_tool])
|
191
|
+
|
176
192
|
return tools
|
177
193
|
|
178
194
|
# Assisted by watsonx Code Assistant
|
@@ -187,7 +203,7 @@ def create_flow_status_tool(flow_status_tool: str, TEMPUS_ENDPOINT: str="http://
|
|
187
203
|
)
|
188
204
|
|
189
205
|
openapi_binding = OpenApiToolBinding(
|
190
|
-
http_path="/flows",
|
206
|
+
http_path="/v1/flows",
|
191
207
|
http_method="GET",
|
192
208
|
security=[],
|
193
209
|
servers=[TEMPUS_ENDPOINT]
|
@@ -213,3 +229,102 @@ def create_flow_status_tool(flow_status_tool: str, TEMPUS_ENDPOINT: str="http://
|
|
213
229
|
|
214
230
|
return OpenAPITool(spec=spec)
|
215
231
|
|
232
|
+
|
233
|
+
def create_get_schedule_tool(name: str, TEMPUS_ENDPOINT: str="http://wxo-tempus-runtime:9044") -> dict:
|
234
|
+
|
235
|
+
spec = ToolSpec(
|
236
|
+
name=name,
|
237
|
+
description="Use this tool to show the current schedules.",
|
238
|
+
permission='read_only',
|
239
|
+
display_name= "Get Schedules"
|
240
|
+
)
|
241
|
+
|
242
|
+
openapi_binding = OpenApiToolBinding(
|
243
|
+
http_path="/v1/schedules/simple",
|
244
|
+
http_method="GET",
|
245
|
+
security=[],
|
246
|
+
servers=[TEMPUS_ENDPOINT]
|
247
|
+
)
|
248
|
+
|
249
|
+
spec.binding = ToolBinding(openapi=openapi_binding)
|
250
|
+
# Input Schema
|
251
|
+
properties = {
|
252
|
+
"query_schedule_id": {
|
253
|
+
"type": "string",
|
254
|
+
"title": "schedule_id",
|
255
|
+
"description": "Identifies the schedule instance.",
|
256
|
+
"in": "query"
|
257
|
+
},
|
258
|
+
"query_schedule_name": {
|
259
|
+
"type": "string",
|
260
|
+
"title": "schedule_name",
|
261
|
+
"description": "Identifies the schedule name.",
|
262
|
+
"in": "query"
|
263
|
+
},
|
264
|
+
}
|
265
|
+
|
266
|
+
spec.input_schema = ToolRequestBody(
|
267
|
+
type='object',
|
268
|
+
properties=properties,
|
269
|
+
required=[]
|
270
|
+
)
|
271
|
+
|
272
|
+
response_properties = {
|
273
|
+
"schedule_id": {
|
274
|
+
"type": "string",
|
275
|
+
},
|
276
|
+
"schedule_name": {
|
277
|
+
"type": "string",
|
278
|
+
},
|
279
|
+
"schedule_data": {
|
280
|
+
"type": "string",
|
281
|
+
},
|
282
|
+
"schedule_time": {
|
283
|
+
"type": "string",
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
spec.output_schema = ToolResponseBody(type='object',
|
288
|
+
properties=response_properties,
|
289
|
+
description='Return the information about the schedule.')
|
290
|
+
|
291
|
+
return OpenAPITool(spec=spec)
|
292
|
+
|
293
|
+
|
294
|
+
def create_delete_schedule_tool(name: str, TEMPUS_ENDPOINT: str="http://wxo-tempus-runtime:9044") -> dict:
|
295
|
+
|
296
|
+
spec = ToolSpec(
|
297
|
+
name=name,
|
298
|
+
description="Use this tool to delete/remove a schedule based on the schedule_id.",
|
299
|
+
permission='read_only',
|
300
|
+
display_name= "Delete Schedule"
|
301
|
+
)
|
302
|
+
|
303
|
+
openapi_binding = OpenApiToolBinding(
|
304
|
+
http_path="/v1/schedules/{schedule_id}",
|
305
|
+
http_method="DELETE",
|
306
|
+
security=[],
|
307
|
+
servers=[TEMPUS_ENDPOINT]
|
308
|
+
)
|
309
|
+
|
310
|
+
spec.binding = ToolBinding(openapi=openapi_binding)
|
311
|
+
# Input Schema
|
312
|
+
properties = {
|
313
|
+
"path_schedule_id": {
|
314
|
+
"type": "string",
|
315
|
+
"title": "schedule_id",
|
316
|
+
"description": "Identifies the schedule instance.",
|
317
|
+
"in": "query"
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
spec.input_schema = ToolRequestBody(
|
322
|
+
type='object',
|
323
|
+
properties=properties,
|
324
|
+
required=[]
|
325
|
+
)
|
326
|
+
|
327
|
+
spec.output_schema = ToolResponseBody(type='object',
|
328
|
+
description='Schedule deleted.')
|
329
|
+
|
330
|
+
return OpenAPITool(spec=spec)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import logging
|
2
|
+
import sys
|
3
|
+
import os
|
4
|
+
|
5
|
+
logger = logging.getLogger(__name__)
|
6
|
+
|
7
|
+
class BadRequest(Exception):
|
8
|
+
def __init__(self, message: str):
|
9
|
+
super().__init__(message)
|
10
|
+
self.message = message
|
11
|
+
logger.error(message)
|
12
|
+
|
13
|
+
# We need to exit to avoid getting 2 error messages printed
|
14
|
+
# We don't want to exit while running tests
|
15
|
+
# Only exit if not running in a test and no --debug
|
16
|
+
if not self._in_test() and "--debug" not in sys.argv:
|
17
|
+
sys.exit(1)
|
18
|
+
|
19
|
+
def _in_test(self):
|
20
|
+
return "PYTEST_CURRENT_TEST" in os.environ
|
21
|
+
|
22
|
+
def __str__(self):
|
23
|
+
return self.message
|
{ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.8.0.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.8.0
|
4
4
|
Summary: IBM watsonx.orchestrate SDK
|
5
5
|
Author-email: IBM <support@ibm.com>
|
6
6
|
License: MIT License
|
@@ -10,13 +10,13 @@ Requires-Dist: certifi>=2024.8.30
|
|
10
10
|
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
|
-
Requires-Dist: ibm-cloud-sdk-core>=3.
|
14
|
-
Requires-Dist: ibm-watsonx-orchestrate-evaluation-framework==1.0.
|
13
|
+
Requires-Dist: ibm-cloud-sdk-core>=3.24.2
|
14
|
+
Requires-Dist: ibm-watsonx-orchestrate-evaluation-framework==1.0.8
|
15
15
|
Requires-Dist: jsonref==1.1.0
|
16
16
|
Requires-Dist: jsonschema<5.0.0,>=4.23.0
|
17
|
-
Requires-Dist: langchain-
|
17
|
+
Requires-Dist: langchain-core<=0.3.63
|
18
|
+
Requires-Dist: langsmith<=0.3.45
|
18
19
|
Requires-Dist: munch>=4.0.0
|
19
|
-
Requires-Dist: numpy>=1.26.0
|
20
20
|
Requires-Dist: packaging>=24.2
|
21
21
|
Requires-Dist: pydantic<3.0.0,>=2.10.3
|
22
22
|
Requires-Dist: pyjwt<3.0.0,>=2.10.1
|