ibm-watsonx-orchestrate 1.7.0a0__py3-none-any.whl → 1.7.0b1__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 +2 -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 +9 -8
- 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 +5 -9
- 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/chat/chat_command.py +2 -0
- ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +6 -4
- ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +6 -6
- ibm_watsonx_orchestrate/cli/commands/environment/types.py +2 -0
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +118 -30
- ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +22 -9
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +0 -18
- ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_controller.py +33 -19
- ibm_watsonx_orchestrate/cli/commands/models/models_command.py +1 -1
- ibm_watsonx_orchestrate/cli/commands/server/server_command.py +64 -9
- 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 +2 -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/docker/compose-lite.yml +6 -4
- ibm_watsonx_orchestrate/docker/default.env +22 -15
- ibm_watsonx_orchestrate/flow_builder/flows/__init__.py +3 -1
- 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 +91 -20
- ibm_watsonx_orchestrate/flow_builder/node.py +12 -1
- ibm_watsonx_orchestrate/flow_builder/types.py +169 -16
- 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.7.0b1.dist-info}/METADATA +5 -5
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.7.0b1.dist-info}/RECORD +49 -49
- ibm_watsonx_orchestrate/flow_builder/resources/flow_status.openapi.yml +0 -66
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.7.0b1.dist-info}/WHEEL +0 -0
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.7.0b1.dist-info}/entry_points.txt +0 -0
- {ibm_watsonx_orchestrate-1.7.0a0.dist-info → ibm_watsonx_orchestrate-1.7.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -15,6 +15,7 @@ import logging
|
|
15
15
|
import copy
|
16
16
|
import uuid
|
17
17
|
import pytz
|
18
|
+
import os
|
18
19
|
|
19
20
|
from typing_extensions import Self
|
20
21
|
from pydantic import BaseModel, Field, SerializeAsAny
|
@@ -25,11 +26,13 @@ from ibm_watsonx_orchestrate.client.tools.tempus_client import TempusClient
|
|
25
26
|
from ibm_watsonx_orchestrate.client.utils import instantiate_client
|
26
27
|
from ..types import (
|
27
28
|
EndNodeSpec, Expression, ForeachPolicy, ForeachSpec, LoopSpec, BranchNodeSpec, MatchPolicy, PromptLLMParameters, PromptNodeSpec,
|
28
|
-
StartNodeSpec, ToolSpec, JsonSchemaObject, ToolRequestBody, ToolResponseBody, UserFieldKind, UserFieldOption, UserFlowSpec, UserNodeSpec, WaitPolicy
|
29
|
+
StartNodeSpec, ToolSpec, JsonSchemaObject, ToolRequestBody, ToolResponseBody, UserFieldKind, UserFieldOption, UserFlowSpec, UserNodeSpec, WaitPolicy,
|
30
|
+
DocProcSpec, TextExtractionResponse, KVPInvoicesExtractionResponse, KVPUtilityBillsExtractionResponse,
|
31
|
+
DocumentContent
|
29
32
|
)
|
30
33
|
from .constants import CURRENT_USER, START, END, ANY_USER
|
31
34
|
from ..node import (
|
32
|
-
EndNode, Node, PromptNode, StartNode, UserNode, AgentNode, DataMap, ToolNode
|
35
|
+
EndNode, Node, PromptNode, StartNode, UserNode, AgentNode, DataMap, ToolNode, DocProcNode
|
33
36
|
)
|
34
37
|
from ..types import (
|
35
38
|
AgentNodeSpec, extract_node_spec, FlowContext, FlowEventType, FlowEvent, FlowSpec,
|
@@ -114,7 +117,7 @@ class Flow(Node):
|
|
114
117
|
# pydantic suppport nested comparison by default
|
115
118
|
|
116
119
|
schema.title = title
|
117
|
-
|
120
|
+
|
118
121
|
if schema == existing_schema:
|
119
122
|
return existing_schema
|
120
123
|
# we need to do a deep compare
|
@@ -354,6 +357,7 @@ class Flow(Node):
|
|
354
357
|
name: str,
|
355
358
|
agent: str,
|
356
359
|
display_name: str|None=None,
|
360
|
+
title: str | None = None,
|
357
361
|
message: str | None = "Follow the agent instructions.",
|
358
362
|
description: str | None = None,
|
359
363
|
input_schema: type[BaseModel]|None = None,
|
@@ -371,6 +375,7 @@ class Flow(Node):
|
|
371
375
|
display_name=display_name,
|
372
376
|
description=description,
|
373
377
|
agent=agent,
|
378
|
+
title=title,
|
374
379
|
message=message,
|
375
380
|
guidelines=guidelines,
|
376
381
|
input_schema=_get_tool_request_body(input_schema_obj),
|
@@ -428,6 +433,50 @@ class Flow(Node):
|
|
428
433
|
# add the node to the list of node
|
429
434
|
node = self._add_node(node)
|
430
435
|
return cast(PromptNode, node)
|
436
|
+
|
437
|
+
def docproc(self,
|
438
|
+
name: str,
|
439
|
+
task: str,
|
440
|
+
display_name: str|None=None,
|
441
|
+
description: str | None = None,
|
442
|
+
input_map: DataMap = None) -> DocProcNode:
|
443
|
+
|
444
|
+
if name is None :
|
445
|
+
raise ValueError("name must be provided.")
|
446
|
+
|
447
|
+
if task is None:
|
448
|
+
raise ValueError("task must be provided.")
|
449
|
+
|
450
|
+
output_schema_dict = {
|
451
|
+
"text_extraction" : TextExtractionResponse,
|
452
|
+
"kvp_invoices_extraction" : KVPInvoicesExtractionResponse,
|
453
|
+
"kvp_utility_bills_extraction" : KVPUtilityBillsExtractionResponse
|
454
|
+
}
|
455
|
+
# create input spec
|
456
|
+
input_schema_obj = _get_json_schema_obj(parameter_name = "input", type_def = DocumentContent)
|
457
|
+
output_schema_obj = _get_json_schema_obj("output", output_schema_dict[task])
|
458
|
+
if "$defs" in output_schema_obj.model_extra:
|
459
|
+
output_schema_obj.model_extra.pop("$defs")
|
460
|
+
# Create the docproc spec
|
461
|
+
task_spec = DocProcSpec(
|
462
|
+
name=name,
|
463
|
+
display_name=display_name if display_name is not None else name,
|
464
|
+
description=description,
|
465
|
+
input_schema=_get_tool_request_body(input_schema_obj),
|
466
|
+
output_schema=_get_tool_response_body(output_schema_obj),
|
467
|
+
output_schema_object = output_schema_obj,
|
468
|
+
task=task
|
469
|
+
)
|
470
|
+
|
471
|
+
node = DocProcNode(spec=task_spec)
|
472
|
+
# setup input map
|
473
|
+
if input_map:
|
474
|
+
node.input_map = self._get_data_map(input_map)
|
475
|
+
|
476
|
+
# add the node to the list of node
|
477
|
+
node = self._add_node(node)
|
478
|
+
return cast(DocProcNode, node)
|
479
|
+
|
431
480
|
|
432
481
|
def node_exists(self, node: Union[str, Node]):
|
433
482
|
|
@@ -921,7 +970,8 @@ class FlowFactory(BaseModel):
|
|
921
970
|
description: str|None=None,
|
922
971
|
initiators: Sequence[str]|None=None,
|
923
972
|
input_schema: type[BaseModel]|None=None,
|
924
|
-
output_schema: type[BaseModel]|None=None
|
973
|
+
output_schema: type[BaseModel]|None=None,
|
974
|
+
schedulable: bool=False) -> Flow:
|
925
975
|
if isinstance(name, Callable):
|
926
976
|
flow_spec = getattr(name, "__flow_spec__", None)
|
927
977
|
if not flow_spec:
|
@@ -942,7 +992,8 @@ class FlowFactory(BaseModel):
|
|
942
992
|
initiators=initiators,
|
943
993
|
input_schema=_get_tool_request_body(input_schema_obj),
|
944
994
|
output_schema=_get_tool_response_body(output_schema_obj),
|
945
|
-
output_schema_object = output_schema_obj
|
995
|
+
output_schema_object = output_schema_obj,
|
996
|
+
schedulable=schedulable,
|
946
997
|
)
|
947
998
|
|
948
999
|
return Flow(spec = flow_spec)
|
@@ -1228,10 +1279,12 @@ class UserFlow(Flow):
|
|
1228
1279
|
kind: UserFieldKind = UserFieldKind.Text,
|
1229
1280
|
display_name: str | None = None,
|
1230
1281
|
description: str | None = None,
|
1231
|
-
owners: list[str] = [],
|
1232
1282
|
default: Any | None = None,
|
1233
|
-
text: str = None,
|
1283
|
+
text: str = None, # The text used to ask question to the user, e.g. 'what is your name?'
|
1234
1284
|
option: UserFieldOption | None = None,
|
1285
|
+
is_list: bool = False,
|
1286
|
+
min: Any | None = None,
|
1287
|
+
max: Any | None = None,
|
1235
1288
|
input_map: DataMap = None,
|
1236
1289
|
custom: dict[str, Any] = {}) -> UserNode:
|
1237
1290
|
'''create a node in the flow'''
|
@@ -1246,20 +1299,42 @@ class UserFlow(Flow):
|
|
1246
1299
|
schema_obj.properties = {}
|
1247
1300
|
schema_obj.properties[name] = UserFieldKind.convert_kind_to_schema_property(kind, name, description, default, option, custom)
|
1248
1301
|
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1302
|
+
task_spec = UserNodeSpec(
|
1303
|
+
name=name,
|
1304
|
+
display_name=display_name,
|
1305
|
+
description=description,
|
1306
|
+
owners=[CURRENT_USER],
|
1307
|
+
input_schema=_get_tool_request_body(schema_obj),
|
1308
|
+
output_schema=_get_tool_response_body(schema_obj),
|
1309
|
+
text=text,
|
1310
|
+
output_schema_object = schema_obj
|
1311
|
+
)
|
1312
|
+
|
1313
|
+
node = UserNode(spec = task_spec)
|
1314
|
+
node.field(name = name,
|
1315
|
+
kind = kind,
|
1316
|
+
display_name = display_name,
|
1317
|
+
description = description,
|
1318
|
+
default = default,
|
1319
|
+
text = text,
|
1320
|
+
option = option,
|
1321
|
+
is_list = is_list,
|
1322
|
+
min = min,
|
1323
|
+
max = max,
|
1324
|
+
custom = custom)
|
1325
|
+
|
1326
|
+
# setup input map
|
1327
|
+
if input_map:
|
1328
|
+
node.input_map = self._get_data_map(input_map)
|
1329
|
+
|
1330
|
+
node = self._add_node(node)
|
1331
|
+
return cast(UserNode, node)
|
1256
1332
|
|
1257
1333
|
def user(
|
1258
1334
|
self,
|
1259
1335
|
name: str | None = None,
|
1260
1336
|
display_name: str | None = None,
|
1261
1337
|
description: str | None = None,
|
1262
|
-
owners: list[str] = [],
|
1263
1338
|
text: str | None = None,
|
1264
1339
|
output_schema: type[BaseModel] | JsonSchemaObject| None = None,
|
1265
1340
|
input_map: DataMap = None,
|
@@ -1273,16 +1348,12 @@ class UserFlow(Flow):
|
|
1273
1348
|
# input and output is always the same in an user node
|
1274
1349
|
output_schema_obj = output_schema_obj
|
1275
1350
|
|
1276
|
-
# identify owner
|
1277
|
-
if not owners:
|
1278
|
-
owners = [ANY_USER]
|
1279
|
-
|
1280
1351
|
# Create the tool spec
|
1281
1352
|
task_spec = UserNodeSpec(
|
1282
1353
|
name=name,
|
1283
1354
|
display_name=display_name,
|
1284
1355
|
description=description,
|
1285
|
-
owners=
|
1356
|
+
owners=[CURRENT_USER],
|
1286
1357
|
input_schema=_get_tool_request_body(output_schema_obj),
|
1287
1358
|
output_schema=_get_tool_response_body(output_schema_obj),
|
1288
1359
|
text=text,
|
@@ -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
|
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,6 +109,13 @@ 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}')"
|
116
|
+
|
117
|
+
def get_spec(self) -> DocProcSpec:
|
118
|
+
return cast(DocProcSpec, self.spec)
|
108
119
|
|
109
120
|
class NodeInstance(BaseModel):
|
110
121
|
node: Node
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from enum import Enum
|
2
|
+
from enum import Enum, StrEnum, auto
|
3
3
|
import inspect
|
4
4
|
import logging
|
5
5
|
from typing import (
|
@@ -116,7 +116,7 @@ def _to_json_from_output_schema(schema: Union[ToolResponseBody, SchemaRef]) -> d
|
|
116
116
|
return model_spec
|
117
117
|
|
118
118
|
class NodeSpec(BaseModel):
|
119
|
-
kind: Literal["node", "tool", "user", "agent", "flow", "start", "decisions", "prompt", "branch", "wait", "foreach", "loop", "userflow", "end"] = "node"
|
119
|
+
kind: Literal["node", "tool", "user", "agent", "flow", "start", "decisions", "prompt", "branch", "wait", "foreach", "loop", "userflow", "end", "docproc" ] = "node"
|
120
120
|
name: str
|
121
121
|
display_name: str | None = None
|
122
122
|
description: str | None = None
|
@@ -162,6 +162,26 @@ class NodeSpec(BaseModel):
|
|
162
162
|
|
163
163
|
return model_spec
|
164
164
|
|
165
|
+
class DocProcTask(StrEnum):
|
166
|
+
'''
|
167
|
+
Possible names for the Document processing task parameter
|
168
|
+
'''
|
169
|
+
text_extraction = auto()
|
170
|
+
kvp_invoices_extraction = auto()
|
171
|
+
kvp_utility_bills_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):
|
@@ -553,10 +589,9 @@ class WaitNodeSpec(FlowControlNodeSpec):
|
|
553
589
|
return my_dict
|
554
590
|
|
555
591
|
class FlowSpec(NodeSpec):
|
556
|
-
|
557
|
-
|
558
592
|
# who can initiate the flow
|
559
593
|
initiators: Sequence[str] = [ANY_USER]
|
594
|
+
schedulable: bool = False
|
560
595
|
|
561
596
|
def __init__(self, **kwargs):
|
562
597
|
super().__init__(**kwargs)
|
@@ -566,6 +601,8 @@ class FlowSpec(NodeSpec):
|
|
566
601
|
model_spec = super().to_json()
|
567
602
|
if self.initiators:
|
568
603
|
model_spec["initiators"] = self.initiators
|
604
|
+
|
605
|
+
model_spec["schedulable"] = self.schedulable
|
569
606
|
|
570
607
|
return model_spec
|
571
608
|
|
@@ -631,11 +668,11 @@ class TaskData(NamedTuple):
|
|
631
668
|
|
632
669
|
class TaskEventType(Enum):
|
633
670
|
|
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"
|
671
|
+
ON_TASK_WAIT = "task:on_task_wait" # the task is waiting for inputs before proceeding
|
672
|
+
ON_TASK_START = "task:on_task_start"
|
673
|
+
ON_TASK_END = "task:on_task_end"
|
674
|
+
ON_TASK_STREAM = "task:on_task_stream"
|
675
|
+
ON_TASK_ERROR = "task:on_task_error"
|
639
676
|
|
640
677
|
class FlowData(BaseModel):
|
641
678
|
'''This class represents the data that is passed between tasks in a flow.'''
|
@@ -667,9 +704,9 @@ class FlowContext(BaseModel):
|
|
667
704
|
|
668
705
|
class FlowEventType(Enum):
|
669
706
|
|
670
|
-
ON_FLOW_START = "on_flow_start"
|
671
|
-
ON_FLOW_END = "on_flow_end"
|
672
|
-
ON_FLOW_ERROR = "on_flow_error"
|
707
|
+
ON_FLOW_START = "flow:on_flow_start"
|
708
|
+
ON_FLOW_END = "flow:on_flow_end"
|
709
|
+
ON_FLOW_ERROR = "flow:on_flow_error"
|
673
710
|
|
674
711
|
|
675
712
|
@dataclass
|
@@ -691,9 +728,125 @@ class Assignment(BaseModel):
|
|
691
728
|
e.g. "node.input.name" or "=f'{node.output.name}_{node.output.id}'"
|
692
729
|
|
693
730
|
'''
|
694
|
-
|
695
|
-
|
696
|
-
|
731
|
+
target_variable: str
|
732
|
+
value_expression: str | None = None
|
733
|
+
has_no_value: bool = False
|
734
|
+
default_value: Any | None = None
|
735
|
+
metadata: dict = Field(default_factory=dict[str, Any])
|
736
|
+
|
737
|
+
class LanguageCode(StrEnum):
|
738
|
+
'''
|
739
|
+
The ISO-639 language codes understood by Document Processing functions.
|
740
|
+
A special 'en_hw' code is used to enable an English handwritten model.
|
741
|
+
'''
|
742
|
+
en = auto()
|
743
|
+
fr = auto()
|
744
|
+
en_hw = auto()
|
745
|
+
|
746
|
+
class DocumentContent(BaseModel):
|
747
|
+
'''
|
748
|
+
This class represents the input of a Document processing task.
|
749
|
+
|
750
|
+
Attributes:
|
751
|
+
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
|
752
|
+
language (LanguageCode): Optional language code used when processing the input document
|
753
|
+
'''
|
754
|
+
# This is declared as bytes but the runtime will understand if a URL is send in as input.
|
755
|
+
# We need to use bytes here for Chat-with-doc to recognize the input as a Document.
|
756
|
+
document_ref: bytes | str = Field(
|
757
|
+
description="Either an ID or a URL identifying the document to be used.",
|
758
|
+
title='Document reference',
|
759
|
+
default=None,
|
760
|
+
json_schema_extra={"format": "binary"})
|
761
|
+
language: Optional[LanguageCode] = Field(
|
762
|
+
description='Optional language code of the document, defaults to "en"',
|
763
|
+
title='Document language code',
|
764
|
+
default=LanguageCode.en)
|
765
|
+
|
766
|
+
class TextExtraction(BaseModel):
|
767
|
+
'''
|
768
|
+
This class represents the output generated by a "text_extraction" document processing (docproc) operation.
|
769
|
+
Attributes:
|
770
|
+
text (str): the text extracted from the input document.
|
771
|
+
'''
|
772
|
+
text: str = Field(description='The text extracted from the input document', title='Text extraction')
|
773
|
+
|
774
|
+
class TextExtractionResponse(BaseModel):
|
775
|
+
'''
|
776
|
+
The text extraction operation response.
|
777
|
+
Attributes:
|
778
|
+
output (TextExtraction): a wrapper for the text extraction response
|
779
|
+
'''
|
780
|
+
output: TextExtraction = Field(description='The text extraction response')
|
781
|
+
|
782
|
+
class Invoice(BaseModel):
|
783
|
+
'''
|
784
|
+
This class represents the fields extracted by the "kvp_invoices_extraction" document processing (docproc) operation.
|
785
|
+
'''
|
786
|
+
bank_account_number: Optional[str] = Field(title='Bank account number', default=None)
|
787
|
+
bank_name: Optional[str] = Field(title='Bank name', default=None)
|
788
|
+
bill_to_address: Optional[str] = Field(title='Bill-to address', default=None)
|
789
|
+
bill_to_name: Optional[str] = Field(title='Bill-to name', default=None)
|
790
|
+
invoice_date: Optional[str] = Field(title='Invoice date', format='date', default=None)
|
791
|
+
invoice_number: Optional[str] = Field(title='Invoice number', default=None)
|
792
|
+
invoice_total: Optional[float] = Field(title='Invoice total', default=None)
|
793
|
+
payment_due_date: Optional[str] = Field(title='Payment due date', format='date', default=None)
|
794
|
+
payment_terms: Optional[str] = Field(title='Payment terms', default=None)
|
795
|
+
purchase_order_number: Optional[str] = Field(title='Purchase order number', default=None)
|
796
|
+
ship_to_address: Optional[str] = Field(title='Ship-to address', default=None)
|
797
|
+
ship_to_name: Optional[str] = Field(title='Ship-to name', default=None)
|
798
|
+
shipping_amount: Optional[float] = Field(title='Shipping amount', default=None)
|
799
|
+
subtotal: Optional[float] = Field(title='Subtotal', default=None)
|
800
|
+
tax_amount: Optional[float] = Field(title='Tax amount', default=None)
|
801
|
+
tax_rate: Optional[float] = Field(title='Tax rate', default=None)
|
802
|
+
tax_type: Optional[str] = Field(title='Tax type', default=None)
|
803
|
+
vendor_address: Optional[str] = Field(title='Vendor address', default=None)
|
804
|
+
vendor_name: Optional[str] = Field(title='Vendor name', default=None)
|
805
|
+
|
806
|
+
|
807
|
+
class KVPInvoicesExtractionResponse(BaseModel):
|
808
|
+
'''
|
809
|
+
The response of a "kvp_invoices_extraction" document processing (docproc) operation.
|
810
|
+
Attributes:
|
811
|
+
invoice: an object with the fields extracted from the input invoice document
|
812
|
+
'''
|
813
|
+
output: Invoice = Field(
|
814
|
+
title='Invoice',
|
815
|
+
description='The fields extracted from an invoice document'
|
816
|
+
)
|
817
|
+
|
818
|
+
|
819
|
+
class UtilityBill(BaseModel):
|
820
|
+
'''
|
821
|
+
This class represents the fields extracted by the "kvp_utility_bills_extraction" document processing (docproc) operation.
|
822
|
+
'''
|
823
|
+
account_number: Optional[str] = Field(title='Account number', default=None)
|
824
|
+
amount_due: Optional[float] = Field(title='Amount due', default=None)
|
825
|
+
client_number: Optional[str] = Field(title='Client number', default=None)
|
826
|
+
company_name: Optional[str] = Field(title='Company name', default=None)
|
827
|
+
company_address: Optional[str] = Field(title='Company address', default=None)
|
828
|
+
customer_name: Optional[str] = Field(title='Customer name', default=None)
|
829
|
+
customer_address: Optional[str] = Field(title='Customer address', default=None)
|
830
|
+
due_date: Optional[str] = Field(title='Due date', format='date', default=None)
|
831
|
+
payment_received: Optional[float] = Field(title='Payment received', default=None)
|
832
|
+
previous_balance: Optional[float] = Field(title='Previous balance', default=None)
|
833
|
+
service_address: Optional[str] = Field(title='Service address', default=None)
|
834
|
+
statement_date: Optional[str] = Field(title='Statement date', format='date', default=None)
|
835
|
+
|
836
|
+
#class UtilityBillResponse(BaseModel):
|
837
|
+
# field_value: UtilityBill = Field(title='Field value')
|
838
|
+
|
839
|
+
class KVPUtilityBillsExtractionResponse(BaseModel):
|
840
|
+
'''
|
841
|
+
The response of a "kvp_utility_bills_extraction" document processing (docproc) operation.
|
842
|
+
Attributes:
|
843
|
+
utility_bull: an object with the fields extracted from the input utility bill document
|
844
|
+
'''
|
845
|
+
output: UtilityBill = Field(
|
846
|
+
title='Utility bill',
|
847
|
+
description='The fields extracted from a utility bill document'
|
848
|
+
)
|
849
|
+
|
697
850
|
def extract_node_spec(
|
698
851
|
fn: Callable | PythonTool,
|
699
852
|
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)
|