ibm-watsonx-orchestrate 1.5.0b1__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.
Files changed (57) hide show
  1. ibm_watsonx_orchestrate/__init__.py +1 -1
  2. ibm_watsonx_orchestrate/agent_builder/agents/__init__.py +1 -1
  3. ibm_watsonx_orchestrate/agent_builder/agents/types.py +53 -3
  4. ibm_watsonx_orchestrate/agent_builder/model_policies/types.py +1 -1
  5. ibm_watsonx_orchestrate/agent_builder/models/types.py +0 -1
  6. ibm_watsonx_orchestrate/agent_builder/tools/openapi_tool.py +41 -3
  7. ibm_watsonx_orchestrate/agent_builder/tools/python_tool.py +2 -1
  8. ibm_watsonx_orchestrate/agent_builder/tools/types.py +7 -0
  9. ibm_watsonx_orchestrate/cli/commands/agents/agents_command.py +18 -1
  10. ibm_watsonx_orchestrate/cli/commands/agents/agents_controller.py +97 -3
  11. ibm_watsonx_orchestrate/cli/commands/channels/webchat/channels_webchat_controller.py +0 -1
  12. ibm_watsonx_orchestrate/cli/commands/connections/connections_controller.py +1 -1
  13. ibm_watsonx_orchestrate/cli/commands/environment/environment_command.py +29 -4
  14. ibm_watsonx_orchestrate/cli/commands/environment/environment_controller.py +74 -8
  15. ibm_watsonx_orchestrate/cli/commands/environment/types.py +1 -0
  16. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_command.py +224 -0
  17. ibm_watsonx_orchestrate/cli/commands/evaluations/evaluations_controller.py +158 -0
  18. ibm_watsonx_orchestrate/cli/commands/knowledge_bases/knowledge_bases_command.py +2 -2
  19. ibm_watsonx_orchestrate/cli/commands/models/model_provider_mapper.py +31 -25
  20. ibm_watsonx_orchestrate/cli/commands/models/models_command.py +6 -6
  21. ibm_watsonx_orchestrate/cli/commands/models/models_controller.py +17 -8
  22. ibm_watsonx_orchestrate/cli/commands/server/server_command.py +25 -17
  23. ibm_watsonx_orchestrate/cli/commands/server/types.py +2 -1
  24. ibm_watsonx_orchestrate/cli/commands/toolkit/toolkit_controller.py +0 -3
  25. ibm_watsonx_orchestrate/cli/commands/tools/tools_controller.py +14 -12
  26. ibm_watsonx_orchestrate/cli/config.py +2 -0
  27. ibm_watsonx_orchestrate/cli/main.py +6 -0
  28. ibm_watsonx_orchestrate/client/agents/agent_client.py +14 -8
  29. ibm_watsonx_orchestrate/client/agents/assistant_agent_client.py +3 -3
  30. ibm_watsonx_orchestrate/client/agents/external_agent_client.py +2 -2
  31. ibm_watsonx_orchestrate/client/base_api_client.py +9 -9
  32. ibm_watsonx_orchestrate/client/connections/connections_client.py +32 -6
  33. ibm_watsonx_orchestrate/client/connections/utils.py +1 -1
  34. ibm_watsonx_orchestrate/client/credentials.py +4 -0
  35. ibm_watsonx_orchestrate/client/model_policies/model_policies_client.py +2 -2
  36. ibm_watsonx_orchestrate/client/service_instance.py +42 -1
  37. ibm_watsonx_orchestrate/client/utils.py +27 -2
  38. ibm_watsonx_orchestrate/docker/compose-lite.yml +27 -17
  39. ibm_watsonx_orchestrate/docker/default.env +21 -15
  40. ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/__init__.py +3 -2
  41. ibm_watsonx_orchestrate/flow_builder/flows/decorators.py +77 -0
  42. ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/events.py +6 -1
  43. ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/flow.py +70 -87
  44. ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/types.py +15 -6
  45. ibm_watsonx_orchestrate/flow_builder/utils.py +185 -0
  46. {ibm_watsonx_orchestrate-1.5.0b1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/METADATA +2 -1
  47. {ibm_watsonx_orchestrate-1.5.0b1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/RECORD +55 -53
  48. ibm_watsonx_orchestrate/experimental/flow_builder/flows/decorators.py +0 -144
  49. ibm_watsonx_orchestrate/experimental/flow_builder/utils.py +0 -115
  50. /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/__init__.py +0 -0
  51. /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/data_map.py +0 -0
  52. /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/flows/constants.py +0 -0
  53. /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/node.py +0 -0
  54. /ibm_watsonx_orchestrate/{experimental/flow_builder → flow_builder}/resources/flow_status.openapi.yml +0 -0
  55. {ibm_watsonx_orchestrate-1.5.0b1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/WHEEL +0 -0
  56. {ibm_watsonx_orchestrate-1.5.0b1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/entry_points.txt +0 -0
  57. {ibm_watsonx_orchestrate-1.5.0b1.dist-info → ibm_watsonx_orchestrate-1.6.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -9,7 +9,9 @@ from ibm_watsonx_orchestrate.cli.config import (
9
9
  CONTEXT_SECTION_HEADER,
10
10
  CONTEXT_ACTIVE_ENV_OPT,
11
11
  ENVIRONMENTS_SECTION_HEADER,
12
- ENV_WXO_URL_OPT
12
+ ENV_WXO_URL_OPT,
13
+ BYPASS_SSL,
14
+ VERIFY
13
15
  )
14
16
  from threading import Lock
15
17
  from ibm_watsonx_orchestrate.client.base_api_client import BaseAPIClient
@@ -45,6 +47,11 @@ def is_local_dev(url: str | None = None) -> bool:
45
47
 
46
48
  return False
47
49
 
50
+ def is_cpd_env(url: str) -> bool:
51
+ if url.lower().startswith("https://cpd"):
52
+ return True
53
+ return False
54
+
48
55
  def check_token_validity(token: str) -> bool:
49
56
  try:
50
57
  token_claimset = jwt.decode(token, options={"verify_signature": False})
@@ -65,6 +72,17 @@ def instantiate_client(client: type[T] , url: str | None=None) -> T:
65
72
  with open(os.path.join(DEFAULT_CONFIG_FILE_FOLDER, DEFAULT_CONFIG_FILE), "r") as f:
66
73
  config = yaml_safe_load(f)
67
74
  active_env = config.get(CONTEXT_SECTION_HEADER, {}).get(CONTEXT_ACTIVE_ENV_OPT)
75
+ bypass_ssl = (
76
+ config.get(ENVIRONMENTS_SECTION_HEADER, {})
77
+ .get(active_env, {})
78
+ .get(BYPASS_SSL, None)
79
+ )
80
+
81
+ verify = (
82
+ config.get(ENVIRONMENTS_SECTION_HEADER, {})
83
+ .get(active_env, {})
84
+ .get(VERIFY, None)
85
+ )
68
86
 
69
87
  if not url:
70
88
  url = config.get(ENVIRONMENTS_SECTION_HEADER, {}).get(active_env, {}).get(ENV_WXO_URL_OPT)
@@ -86,7 +104,14 @@ def instantiate_client(client: type[T] , url: str | None=None) -> T:
86
104
  if not check_token_validity(token):
87
105
  logger.error(f"The token found for environment '{active_env}' is missing or expired. Use `orchestrate env activate {active_env}` to fetch a new one")
88
106
  exit(1)
89
- client_instance = client(base_url=url, api_key=token, is_local=is_local_dev(url))
107
+ is_cpd = is_cpd_env(url)
108
+ if is_cpd:
109
+ if bypass_ssl is True:
110
+ client_instance = client(base_url=url, api_key=token, is_local=is_local_dev(url), verify=False)
111
+ elif verify is not None:
112
+ client_instance = client(base_url=url, api_key=token, is_local=is_local_dev(url), verify=verify)
113
+ else:
114
+ client_instance = client(base_url=url, api_key=token, is_local=is_local_dev(url))
90
115
 
91
116
  return client_instance
92
117
  except FileNotFoundError as e:
@@ -46,6 +46,7 @@ services:
46
46
  WXO_SERVER_URL: http://wxo-server:4321
47
47
  MAX_POOL: 60
48
48
  DEPLOYMENT_MODE: laptop
49
+ SUFFIXLIST: '["global_05d7ba72", "ibm_184bdbd3"]'
49
50
  ports:
50
51
  - 3001:3001
51
52
 
@@ -60,6 +61,16 @@ services:
60
61
  WATSONX_URL: ${WATSONX_URL}
61
62
  WATSONX_SPACE_ID: ${WATSONX_SPACE_ID}
62
63
 
64
+ wxo-agent-gateway:
65
+ image: ${AGENT_GATEWAY_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-agent-gateway:${AGENT_GATEWAY_TAG:-latest}
66
+ platform: linux/amd64
67
+ restart: unless-stopped
68
+ ports:
69
+ - "8989:8989"
70
+ environment:
71
+ JWT_SECRET: ${JWT_SECRET}
72
+ DEPLOYMENT_PLATFORM: laptop-lite
73
+
63
74
  ui:
64
75
  image: ${UI_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-chat:${UITAG:-latest}
65
76
  platform: linux/amd64
@@ -107,6 +118,7 @@ services:
107
118
  WXO_DEPLOYMENT_TYPE: 'laptop'
108
119
  AGENT_RUNTIME_ENDPOINT: http://wxo-server:4321
109
120
  TEMPUS_RUNTIME_ENDPOINT: http://wxo-tempus-runtime:9044
121
+ CONNECTIONS_MANAGER_ENDPOINT: http://wxo-server-connection-manager:3001
110
122
  command: 'npm start'
111
123
  ports:
112
124
  - '4025:4025'
@@ -190,19 +202,8 @@ services:
190
202
  retries: 3
191
203
 
192
204
  socket-handler:
193
- container_name: socket-handler
194
- profiles:
195
- - webhooks
196
- - ui
197
- build:
198
- context: .
199
- dockerfile: ./socket_handler/Dockerfile
200
- target: socket-handler
201
- args:
202
- GIT_BRANCH: "main"
203
- ssh:
204
- - default
205
- image: docker.io/library/socket-handler:latest
205
+ image: ${SOCKET_HANDLER_REGISTRY:-us.icr.io/watson-orchestrate-private}/wxo-socket-handler:${SOCKET_HANDLER_TAG:-latest}
206
+ platform: linux/amd64
206
207
  command: "npm start"
207
208
  ports:
208
209
  - 4001:4001
@@ -248,12 +249,14 @@ services:
248
249
  condition: service_started
249
250
  required: False
250
251
  environment:
252
+ RUNTIME_MANAGER_API_KEY: ${RUNTIME_MANAGER_API_KEY:-testapikey}
251
253
  PIP_NO_CACHE_DIR:
252
254
  JWT_SECRET: ${JWT_SECRET}
253
255
  TRM_BASE_URL: http://tools-runtime-manager:8080
254
256
  POSTGRES_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@wxo-server-db:5432/postgres
255
257
  # POSTGRES_POOL_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@wxo-server-db:6432/postgres
256
258
  CELERY_BROKER_URL: redis://wxo-server-redis:6379/0
259
+ AGENT_GATEWAY_URI: http://wxo-agent-gateway:8989
257
260
  CELERY_RESULT_BACKEND: redis://wxo-server-redis:6379/0
258
261
  FLOWER_URL: http://wxo-server-flower:5555
259
262
  DB_ENCRYPTION_KEY: thisisthedbencryptionkeyforlocaltestingonly
@@ -340,11 +343,13 @@ services:
340
343
  - ./sdk:/packages
341
344
  - tools:/tools
342
345
  environment:
346
+ RUNTIME_MANAGER_API_KEY: ${RUNTIME_MANAGER_API_KEY:-testapikey}
343
347
  AI_GATEWAY_ENABLED : ${AI_GATEWAY_ENABLED}
344
348
  AI_GATEWAY_BASE_URL: ${AI_GATEWAY_BASE_URL}
345
349
  IS_WXO_LITE: 'TRUE'
346
350
  TRM_BASE_URL: http://tools-runtime-manager:8080
347
351
  AGENT_STEP_DETAILS: redis://wxo-server-redis:6379/0
352
+ AGENT_GATEWAY_URI: http://wxo-agent-gateway:8989
348
353
  JWT_SECRET: ${JWT_SECRET}
349
354
  POSTGRES_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@wxo-server-db:5432/postgres
350
355
  CELERY_BROKER_URL: redis://wxo-server-redis:6379/0
@@ -410,6 +415,8 @@ services:
410
415
  USE_SAAS_ML_TOOLS_RUNTIME: ${USE_SAAS_ML_TOOLS_RUNTIME}
411
416
  AUTHORIZATION_URL: ${AUTHORIZATION_URL}
412
417
  WO_AUTH_TYPE: ${WO_AUTH_TYPE}
418
+ WXO_DEPLOYMENT_PLATFORM: saas
419
+ CALLBACK_HOST_URL: http://wxo-server:4321
413
420
 
414
421
  tools-runtime-manager:
415
422
  image: ${TRM_REGISTRY:-us.icr.io/watson-orchestrate-private}/tools-runtime-manager:${TRM_TAG:-latest}
@@ -424,6 +431,7 @@ services:
424
431
  - $HOME/.kube/config:/root/.kube/config
425
432
  - tools-runtime-data:/shared-data
426
433
  environment:
434
+ RUNTIME_MANAGER_API_KEY: ${RUNTIME_MANAGER_API_KEY:-testapikey}
427
435
  KUBECONFIG: /root/.kube/config
428
436
  K8S_SERVER: "https://lima-rancher-desktop:6443" # Kubernetes API on host
429
437
  DB_HOST: wxo-server-db
@@ -439,7 +447,6 @@ services:
439
447
  SERVER_HOST: ${SERVER_HOST}
440
448
  SCHEMA_FILE_PATH: ${SCHEMA_FILE_PATH}
441
449
  WXO_BASE_URL: ${WXO_BASE_URL}
442
- RUNTIME_MANAGER_API_KEY: ${RUNTIME_MANAGER_API_KEY}
443
450
  NAMESPACE: ${NAMESPACE}
444
451
  DEPLOYMENT_PLATFORM: ${DEPLOYMENT_PLATFORM}
445
452
  VOLUME_MOUNT_PATH: "/shared-data"
@@ -469,7 +476,7 @@ services:
469
476
  environment:
470
477
  DEPLOYMENT_PLATFORM: ${DEPLOYMENT_PLATFORM}
471
478
  VOLUME_MOUNT_PATH: "/shared-data"
472
- RUNTIME_MANAGER_API_KEY: ${RUNTIME_MANAGER_API_KEY}
479
+ RUNTIME_MANAGER_API_KEY: ${RUNTIME_MANAGER_API_KEY:-testapikey}
473
480
  TOOLS_RUNTIME_MANAGER_BASE_URL: ${TOOLS_RUNTIME_MANAGER_BASE_URL}
474
481
  DB_HOST: wxo-server-db
475
482
  DB_PORT: ${DB_PORT:-5432} # Ensure default port
@@ -589,7 +596,8 @@ services:
589
596
  SERVER_HTTP_PORT: "9044"
590
597
  SERVER_CONTEXT_PATH:
591
598
  SERVER_JWK_URL: https://wo-ibm-dev.verify.ibm.com/v1.0/endpoint/default/jwks
592
- SERVER_CALLBACK_URL: http://wxo-tempus-runtime:9044/task/callback/{thread_id}/{requestId}
599
+ SERVER_STANDALONE_TASK_CALLBACK_URL: http://localhost:9044/task/callback/{thread_id}/{requestId}
600
+ SERVER_FLOW_CALLBACK_URL: http://localhost:9044/v1/flows/{flow_instance_id}/{task_instance_id}/resume/async
593
601
  JWT_SECRET: ${JWT_SECRET}
594
602
  SERVER_INTERNAL_PROTOCOL: http
595
603
  SERVER_INTERNAL_HOSTNAME: wxo-tempus-runtime
@@ -598,6 +606,7 @@ services:
598
606
  WATSONX_AI_PROJECT_ID: ""
599
607
  WATSONX_AI_SPACE_ID: ${WATSONX_SPACE_ID}
600
608
  WATSONX_AI_APIKEY: ${WATSONX_APIKEY}
609
+ WATSONX_AI_SERVICE_URL: ${WATSONX_URL}
601
610
  PG_HOST: wxo-server-db
602
611
  PG_PORT: "5432"
603
612
  PG_USER: ${POSTGRES_USER:-postgres}
@@ -616,6 +625,7 @@ services:
616
625
  LANGFUSE_PUBLIC_KEY: ${LANGFUSE_PUBLIC_KEY:-pk-lf-7417757e-d6df-421b-957e-683b76acb5df}
617
626
  LANGFUSE_SECRET_KEY: ${LANGFUSE_PRIVATE_KEY:-sk-lf-7bc4da63-7b2b-40c0-b5eb-1e0cf64f9af2}
618
627
  LOG_LEVEL: info
628
+ DISABLE_FLOW_BINDING: true
619
629
  healthcheck:
620
630
  test: curl -k http://localhost:9044/readiness --fail
621
631
  interval: 5s
@@ -652,4 +662,4 @@ volumes:
652
662
  networks:
653
663
  default:
654
664
  name: wxo-server
655
-
665
+
@@ -22,7 +22,6 @@ ASSISTANT_EMBEDDINGS_API_BASE=https://us-south.ml.cloud.ibm.com
22
22
  #ASSISTANT_EMBEDDINGS_SPACE_ID=#Will default to WATSONX_SPACE_ID if specified
23
23
  ROUTING_LLM_API_BASE=https://us-south.ml.cloud.ibm.com
24
24
  ROUTING_LLM_MODEL_ID=watsonx/ibm/granite-8b-unified-api-model-v2
25
- AUTHORIZATION_URL=https://iam.test.cloud.ibm.com/identity/token
26
25
  #ROUTING_LLM_API_KEY=#Will default to WATSONX_APIKEY if specified
27
26
  #ROUTING_LLM_SPACE_ID=#Will default to WATSONX_SPACE_ID if specified
28
27
  ASSISTANT_INDEX_CHUNK_SIZE=1000
@@ -53,44 +52,51 @@ EVENT_BROKER_TTL="-1"
53
52
  # See get_default_registry_env_vars_by_dev_edition_source() in src/ibm_watsonx_orchestrate/cli/commands/server/server_command.py for more details.
54
53
  REGISTRY_URL=
55
54
 
56
- SERVER_TAG=05-06-2025
55
+ SERVER_TAG=19-06-2025-v2
56
+
57
57
  SERVER_REGISTRY=
58
58
 
59
- WORKER_TAG=03-06-2025
59
+ WORKER_TAG=19-06-2025-v2
60
60
  WORKER_REGISTRY=
61
61
 
62
- AI_GATEWAY_TAG=03-06-2025
62
+ AI_GATEWAY_TAG=18-06-2025-v2
63
63
  AI_GATEWAY_REGISTRY=
64
64
 
65
+ AGENT_GATEWAY_TAG=16-06-2025
66
+ AGENT_GATEWAY_REGISTRY=
67
+
65
68
  DB_REGISTRY=
66
69
  # If you build multiarch set all three of these to the same, we have a pr against main
67
70
  # to not have this separation, but we can merge it later
68
- DBTAG=07-06-2025
69
- AMDDBTAG=07-06-2025
70
- ARM64DBTAG=07-06-2025
71
+ DBTAG=17-06-2025-v1
72
+ AMDDBTAG=17-06-2025-v1
73
+ ARM64DBTAG=17-06-2025-v1
71
74
 
72
75
  UI_REGISTRY=
73
- UITAG=03-06-2025
76
+ UITAG=19-06-2025
74
77
 
75
78
  CM_REGISTRY=
76
- CM_TAG=13-05-2025
79
+ CM_TAG=18-06-2025
77
80
 
78
- TRM_TAG=11-06-2025-1-5-0
81
+ TRM_TAG=10-06-2025
79
82
  TRM_REGISTRY=
80
83
 
81
- TR_TAG=11-06-2025-1-5-0
84
+ TR_TAG=10-06-2025
82
85
  TR_REGISTRY=
83
86
 
84
- BUILDER_TAG=03-06-2025
87
+ BUILDER_TAG=16-06-2025
85
88
  BUILDER_REGISTRY=
86
89
 
87
- FLOW_RUNTIME_TAG=13-05-2025
90
+ FLOW_RUNTIME_TAG=17-06-2025
88
91
  FLOW_RUMTIME_REGISTRY=
89
92
 
93
+ SOCKET_HANDLER_TAG=29-05-2025
94
+ SOCKET_HANDLER_REGISTRY=
95
+
90
96
  # END -- IMAGE REGISTRIES AND TAGS
91
97
 
92
98
  TAVILY_API_KEY=dummy_tavily_api_key
93
- PREFERRED_MODELS=meta-llama/llama-3-1-8b-instruct,meta-llama/llama-3-1-70b-instruct,meta-llama/llama-3-405b-instruct,meta-llama/llama-3-2-1b-instruct,meta-llama/llama-3-2-3b-instruct,meta-llama/llama-3-2-11b-vision-instruct,meta-llama/llama-3-2-90b-vision-instruct,mistralai/mistral-large,mistralai/mixtral-8x7b-instruct-v01,ibm/granite-3-2b-instruct,ibm/granite-3-8b-instruct
99
+ PREFERRED_MODELS=meta-llama/llama-3-2-90b-vision-instruct,meta-llama/llama-3-405b-instruct
94
100
  INCOMPATIBLE_MODELS=flan,embedding,cross-encoder,tinytimemixers
95
101
  #WATSONX_APIKEY= #Must define in .env
96
102
  WATSONX_URL=https://us-south.ml.cloud.ibm.com
@@ -119,7 +125,7 @@ TOOLS_RUNTIME_MANAGER_BASE_URL="http://tools-runtime-manager:8080"
119
125
  CONNECTION_SERVICE_BASE_URL="http://wxo-server-connection-manager:3001"
120
126
  AI_GATEWAY_BASE_URL="http://ai-gateway:8787/v1"
121
127
  AI_GATEWAY_ENABLED=True
122
-
128
+ AGENT_GATEWAY_URI="http://wxo-agent-gateway:8989"
123
129
  #To Prevent warnings
124
130
  VECTOR_STORE_PROVIDER=
125
131
  MILVUS_URI=
@@ -1,8 +1,8 @@
1
1
  from .constants import START, END, RESERVED
2
2
  from ..types import FlowContext, TaskData, TaskEventType
3
- from ..node import UserNode, AgentNode, StartNode, EndNode, PromptNode
3
+ from ..node import UserNode, AgentNode, StartNode, EndNode, PromptNode, ToolNode
4
4
  from .flow import Flow, CompiledFlow, FlowRun, FlowEvent, FlowEventType, FlowFactory, MatchPolicy, WaitPolicy, ForeachPolicy, Branch, Foreach, Loop
5
- from .decorators import user, flow_spec, flow
5
+ from .decorators import flow
6
6
  from ..data_map import Assignment, DataMap
7
7
 
8
8
 
@@ -20,6 +20,7 @@ __all__ = [
20
20
  "StartNode",
21
21
  "EndNode",
22
22
  "PromptNode",
23
+ "ToolNode",
23
24
  "Assignment",
24
25
  "DataMap",
25
26
 
@@ -0,0 +1,77 @@
1
+ """
2
+ A set of decorators to help define different Flow constructs.
3
+ """
4
+
5
+ import asyncio
6
+ from functools import wraps
7
+ import logging
8
+ import inspect
9
+ from typing import Callable, Optional, Sequence
10
+ from pydantic import BaseModel
11
+ from ..types import extract_node_spec, UserNodeSpec, FlowSpec
12
+
13
+ from .flow import FlowFactory, Flow
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class FlowWrapper:
19
+ def __init__(self, func, a_model):
20
+ self.func = func
21
+ self.a_model = a_model
22
+ wraps(func)(self) # Preserve metadata
23
+
24
+ def __call__(self, *args, **kwargs):
25
+ result = self.func(self.a_model)
26
+ if not isinstance(result, Flow):
27
+ raise ValueError("Return value must be of type Flow")
28
+ return result
29
+
30
+ def flow(*args,
31
+ name: Optional[str]=None,
32
+ display_name: Optional[str]=None,
33
+ description: str|None=None,
34
+ input_schema: type[BaseModel] | None = None,
35
+ output_schema: type[BaseModel] | None = None,
36
+ initiators: Sequence[str] = ()):
37
+ """Decorator to mark a function as a flow model builder."""
38
+
39
+ def decorator(func: Callable):
40
+ """
41
+ Decorator that takes a function as an argument and returns a wrapper function.
42
+ The wrapper function takes a single argument of type Flow and calls the original function with the created flow as an argument.
43
+ """
44
+
45
+ sig = inspect.signature(func)
46
+ if len(sig.parameters) != 1:
47
+ raise ValueError("Only one argument is allowed")
48
+ param = list(sig.parameters.values())[0]
49
+ if param.annotation != Flow:
50
+ raise ValueError("Argument must be of type Flow")
51
+ if sig.return_annotation != Flow:
52
+ raise ValueError("Return value must be of type Flow")
53
+
54
+ node_spec = extract_node_spec(func, name, description)
55
+ a_model = FlowFactory.create_flow(
56
+ name = node_spec.name,
57
+ display_name = display_name,
58
+ description = node_spec.description,
59
+ input_schema = input_schema,
60
+ output_schema = output_schema,
61
+ initiators = initiators)
62
+
63
+ # logger.info("Creating flow model: %s", a_model.spec.name)
64
+
65
+ # @wraps(func)
66
+ # def wrapper(*args, **kwargs):
67
+ # result = func(a_model)
68
+ # if not isinstance(result, Flow):
69
+ # raise ValueError("Return value must be of type Flow")
70
+ # return result
71
+
72
+ return FlowWrapper(func, a_model)
73
+
74
+ if len(args) == 1 and callable(args[0]):
75
+ return decorator(args[0])
76
+ else:
77
+ return decorator
@@ -47,8 +47,13 @@ class StreamConsumer:
47
47
  def deserialize_flow_event(byte_data: bytes) -> FlowEvent:
48
48
  """Deserialize byte data into a FlowEvent object."""
49
49
  # Decode the byte data
50
- decoded_data = byte_data[b'message'].decode('utf-8')
50
+ decoded_data = byte_data[b'data'].decode('utf-8') if b'data' in byte_data else None
51
+ if not decoded_data:
52
+ decoded_data = byte_data[b'message'].decode('utf-8') if b'message' in byte_data else None
51
53
 
54
+ if not decoded_data:
55
+ raise ValueError("No data in received event.")
56
+
52
57
  # Parse the JSON string into a dictionary
53
58
  parsed_data = json.loads(decoded_data)
54
59