writer 1.23.0rc6__py3-none-any.whl → 1.26.0rc3__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 (81) hide show
  1. writer/ai/__init__.py +39 -1
  2. writer/blocks/__init__.py +2 -0
  3. writer/blocks/sharedblueprint.py +86 -0
  4. writer/blueprints.py +57 -64
  5. writer/journal.py +96 -38
  6. writer/static/assets/BaseMarkdown-C7JpFNzG.js +1 -0
  7. writer/static/assets/BlueprintToolbar-Qq1M1yPa.js +1 -0
  8. writer/static/assets/{BlueprintToolbar-BSIwpBPp.css → BlueprintToolbar-wpfX0jo_.css} +1 -1
  9. writer/static/assets/{BuilderApp-Df1h8-Eo.js → BuilderApp-CVdXjiyA.js} +3 -3
  10. writer/static/assets/{BuilderApplicationSelect-C112wzDI.js → BuilderApplicationSelect-BJ3WU4j8.js} +2 -2
  11. writer/static/assets/BuilderBlueprintLibraryPanel-BB2BzDiO.js +1 -0
  12. writer/static/assets/BuilderBlueprintLibraryPanel-qrkMQJpE.css +1 -0
  13. writer/static/assets/{BuilderEmbeddedCodeEditor-DG2PsuIn.js → BuilderEmbeddedCodeEditor-Bp4akO9H.js} +6 -6
  14. writer/static/assets/{BuilderGraphSelect-CZyeW98W.js → BuilderGraphSelect-DqqflOEF.js} +2 -2
  15. writer/static/assets/{BuilderInsertionLabel-CdV8k3Zg.js → BuilderInsertionLabel-DcnE9VFH.js} +1 -1
  16. writer/static/assets/{BuilderInsertionOverlay-DH0Erxyl.js → BuilderInsertionOverlay-CVXHfCDG.js} +1 -1
  17. writer/static/assets/BuilderJournal-BkdpDeUE.js +7 -0
  18. writer/static/assets/{BuilderJournal-DAQcshng.css → BuilderJournal-DHv3Pvvm.css} +1 -1
  19. writer/static/assets/{BuilderModelSelect-Bpt2wAoy.js → BuilderModelSelect-B3mOzDst.js} +2 -2
  20. writer/static/assets/BuilderSettings-7A3iq6cl.js +16 -0
  21. writer/static/assets/{BuilderSettings-BDCWmj-0.css → BuilderSettings-BN0g4wlH.css} +1 -1
  22. writer/static/assets/{BuilderSettingsArtifactAPITriggerDetails-Ce77KBfh.js → BuilderSettingsArtifactAPITriggerDetails-FkIt0kMq.js} +1 -1
  23. writer/static/assets/BuilderSettingsDeploySharedBlueprint-BdDSjNAL.css +1 -0
  24. writer/static/assets/BuilderSettingsDeploySharedBlueprint-BuSxeIj-.js +1 -0
  25. writer/static/assets/BuilderSettingsHandlers-DbeF71aV.js +1 -0
  26. writer/static/assets/BuilderSidebarComponentTree-C14x1rVr.js +1 -0
  27. writer/static/assets/BuilderSidebarComponentTree-DYu1F793.css +1 -0
  28. writer/static/assets/BuilderSidebarToolkit-CwqbjRv8.css +1 -0
  29. writer/static/assets/BuilderSidebarToolkit-jy_A1o9f.js +7 -0
  30. writer/static/assets/{BuilderTemplateEditor-C0IFlyo0.js → BuilderTemplateEditor-BIgBS6qi.js} +1 -1
  31. writer/static/assets/BuilderVault-BgiAbw0w.js +1 -0
  32. writer/static/assets/{ComponentRenderer-DQTge-u5.js → ComponentRenderer-BJGX_6iU.js} +1 -1
  33. writer/static/assets/{SharedCopyClipboardButton-DLDKJqmO.js → SharedCopyClipboardButton-ed8bYNvB.js} +1 -1
  34. writer/static/assets/{WdsCheckbox-DyaMkyjM.js → WdsCheckbox-BYGFbKQr.js} +1 -1
  35. writer/static/assets/{WdsDropdownMenu-1kTugbx4.js → WdsDropdownMenu-C1nXnj7Y.js} +1 -1
  36. writer/static/assets/WdsFieldWrapper-DUvtHQhU.js +1 -0
  37. writer/static/assets/{WdsTabs-cGyj5MvP.js → WdsTabs-D3_pIGba.js} +1 -1
  38. writer/static/assets/{cssMode-BNzP_LTj.js → cssMode-4RB2gbaz.js} +1 -1
  39. writer/static/assets/{freemarker2-3oFbujgY.js → freemarker2-DTEq8jtt.js} +1 -1
  40. writer/static/assets/{handlebars-tosvcMfZ.js → handlebars-Bgenl5pg.js} +1 -1
  41. writer/static/assets/{html-C40vkof5.js → html-bSIJxImc.js} +1 -1
  42. writer/static/assets/{htmlMode-IleWCzJi.js → htmlMode-DIJZeCM_.js} +1 -1
  43. writer/static/assets/{index-DOMal5wc.css → index-BKNuk68o.css} +1 -1
  44. writer/static/assets/{index-D7Q_1TlJ.js → index-BO2lDBxy.js} +1 -1
  45. writer/static/assets/{index-522ZtJjE.js → index-CStxQ_Zn.js} +1 -1
  46. writer/static/assets/{index-Bz7k91zI.js → index-Tfvjt7wd.js} +1684 -1684
  47. writer/static/assets/{javascript-B93kRLOk.js → javascript-DEKuJ5Kr.js} +1 -1
  48. writer/static/assets/{jsonMode-BvzFLYFi.js → jsonMode-P6mvp974.js} +1 -1
  49. writer/static/assets/{liquid-DUum66og.js → liquid-CLV-Oo7T.js} +1 -1
  50. writer/static/assets/{mapbox-gl-CxU14gUr.js → mapbox-gl-DBM-6gcD.js} +1 -1
  51. writer/static/assets/{mdx-dIi1xsKV.js → mdx-D9lLpWK9.js} +1 -1
  52. writer/static/assets/{pdf-C6_Z6EhB.js → pdf-Car1WtOr.js} +1 -1
  53. writer/static/assets/{plotly.min-B2Fen0AF.js → plotly.min-B_7RxSHC.js} +1 -1
  54. writer/static/assets/{python-DbQOvIm1.js → python-CKNDy5FF.js} +1 -1
  55. writer/static/assets/{razor-BmVb2CjQ.js → razor-Hz0J-1ka.js} +1 -1
  56. writer/static/assets/{tsMode-CA0I8nL6.js → tsMode-CNnhj71T.js} +1 -1
  57. writer/static/assets/{typescript-DZ0ESF3e.js → typescript-DBSqcEcy.js} +1 -1
  58. writer/static/assets/{useBlueprintRun-DSOR9GMr.js → useBlueprintRun-BfljCQFl.js} +1 -1
  59. writer/static/assets/useKeyValueEditor-D9cp0yxU.js +1 -0
  60. writer/static/assets/{useListResources-yMzGtfQ-.js → useListResources-Dz7zv-sv.js} +1 -1
  61. writer/static/assets/{xml-C_vN9YaG.js → xml-9fwRtLLU.js} +1 -1
  62. writer/static/assets/{yaml-CkZwQHIk.js → yaml-COXu8O5A.js} +1 -1
  63. writer/static/index.html +2 -2
  64. {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/METADATA +2 -2
  65. {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/RECORD +69 -64
  66. writer/static/assets/BaseMarkdown-CkzyohPW.js +0 -1
  67. writer/static/assets/BlueprintToolbar-Beg4BHcc.js +0 -1
  68. writer/static/assets/BuilderJournal-Cyr5afZb.js +0 -7
  69. writer/static/assets/BuilderSettings-oKMwMRAY.js +0 -16
  70. writer/static/assets/BuilderSettingsHandlers-B3yTZdYU.js +0 -1
  71. writer/static/assets/BuilderSidebarComponentTree-C5AMKQcR.css +0 -1
  72. writer/static/assets/BuilderSidebarComponentTree-l1fr5tUm.js +0 -1
  73. writer/static/assets/BuilderSidebarToolkit-OFxghtWy.css +0 -1
  74. writer/static/assets/BuilderSidebarToolkit-iUsHlK39.js +0 -1
  75. writer/static/assets/BuilderVault-CaBwjxyR.js +0 -1
  76. writer/static/assets/useComponentDescription-CI_QLr37.js +0 -1
  77. writer/static/assets/useKeyValueEditor-DctSXoZx.js +0 -1
  78. /writer/static/assets/{useKeyValueEditor-CsemOh8D.css → WdsFieldWrapper-CsemOh8D.css} +0 -0
  79. {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/WHEEL +0 -0
  80. {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/entry_points.txt +0 -0
  81. {writer-1.23.0rc6.dist-info → writer-1.26.0rc3.dist-info}/licenses/LICENSE.txt +0 -0
writer/ai/__init__.py CHANGED
@@ -2,6 +2,7 @@ import json
2
2
  import logging
3
3
  from contextvars import ContextVar
4
4
  from datetime import datetime
5
+ from functools import wraps
5
6
  from typing import (
6
7
  Any,
7
8
  Callable,
@@ -13,6 +14,7 @@ from typing import (
13
14
  Optional,
14
15
  Set,
15
16
  TypedDict,
17
+ TypeVar,
16
18
  Union,
17
19
  cast,
18
20
  )
@@ -20,7 +22,7 @@ from uuid import uuid4
20
22
 
21
23
  from httpx import Timeout
22
24
  from writerai import DefaultHttpxClient, Writer
23
- from writerai._exceptions import WriterError
25
+ from writerai._exceptions import BadRequestError, WriterError
24
26
  from writerai._response import BinaryAPIResponse
25
27
  from writerai._streaming import Stream
26
28
  from writerai._types import Body, Headers, NotGiven, Query
@@ -1041,6 +1043,39 @@ def delete_file(
1041
1043
  return files.delete(file_id, **config)
1042
1044
 
1043
1045
 
1046
+ class GuardrailError(Exception):
1047
+ def __init__(self, name: str, message: str, *args):
1048
+ super().__init__(f"{message}: {name}", *args)
1049
+
1050
+
1051
+ R = TypeVar("R")
1052
+
1053
+
1054
+ def catch_guardrail_error(func: Callable[..., R]) -> Callable[..., R]:
1055
+ @wraps(func)
1056
+ def wrapper(*args: Any, **kwargs: Any) -> R:
1057
+ try:
1058
+ return func(*args, **kwargs)
1059
+ except BadRequestError as e:
1060
+ parsed = e.response.json()
1061
+ errors = parsed.get("errors")
1062
+ if not errors:
1063
+ raise
1064
+
1065
+ extras = parsed.get("extras")
1066
+ if extras is None:
1067
+ raise
1068
+ guardrail_info = extras.get("guardrail_info")
1069
+ if guardrail_info is None:
1070
+ raise
1071
+
1072
+ raise GuardrailError(
1073
+ name=guardrail_info["guardrail_name"],
1074
+ message=errors[0]["description"],
1075
+ ) from None
1076
+
1077
+ return wrapper
1078
+
1044
1079
  class Conversation:
1045
1080
  """
1046
1081
  Manages messages within a conversation flow with an AI system,
@@ -1848,6 +1883,7 @@ class Conversation:
1848
1883
 
1849
1884
  self.__add__({"role": role, "content": content})
1850
1885
 
1886
+ @catch_guardrail_error
1851
1887
  def _send_chat_request(
1852
1888
  self,
1853
1889
  request_model: str,
@@ -2918,6 +2954,7 @@ class Tools:
2918
2954
  return result.entities
2919
2955
 
2920
2956
 
2957
+ @catch_guardrail_error
2921
2958
  def complete(
2922
2959
  initial_text: str,
2923
2960
  config: Optional['CreateOptions'] = None
@@ -2964,6 +3001,7 @@ def complete(
2964
3001
  f"{response_data}")
2965
3002
 
2966
3003
 
3004
+ @catch_guardrail_error
2967
3005
  def stream_complete(
2968
3006
  initial_text: str,
2969
3007
  config: Optional['CreateOptions'] = None
writer/blocks/__init__.py CHANGED
@@ -12,6 +12,7 @@ from writer.blocks.parsejson import ParseJSON
12
12
  from writer.blocks.returnvalue import ReturnValue
13
13
  from writer.blocks.runblueprint import RunBlueprint
14
14
  from writer.blocks.setstate import SetState
15
+ from writer.blocks.sharedblueprint import SharedBlueprint
15
16
  from writer.blocks.uieventtrigger import UIEventTrigger
16
17
  from writer.blocks.writeraddchatmessage import WriterAddChatMessage
17
18
  from writer.blocks.writeraddtokg import WriterAddToKG
@@ -63,3 +64,4 @@ WriterVision.register("blueprints_writervision")
63
64
  WriterWebSearch.register("blueprints_writerwebsearch")
64
65
  WriterKeyValueStorage.register("blueprints_writerkeyvaluestorage")
65
66
  WriterChatReplyWithToolConfig.register("blueprints_writerchatreplywithtoolconfig")
67
+ SharedBlueprint.register("blueprints_shared")
@@ -0,0 +1,86 @@
1
+ """
2
+ Shared blueprint implementation for user-created reusable blueprints.
3
+
4
+ Shared blueprints execute stored blueprint components by loading them from the component tree.
5
+ The component's content.sourceBlueprintId field references the source blueprint.
6
+ """
7
+
8
+ from writer.abstract import register_abstract_template
9
+ from writer.blocks.base_block import BlueprintBlock
10
+ from writer.ss_types import AbstractTemplate
11
+
12
+
13
+ class SharedBlueprint(BlueprintBlock):
14
+ """
15
+ Shared blueprint that executes components from a source blueprint in the component tree.
16
+
17
+ The source blueprint is identified by the sourceBlueprintId content field.
18
+ """
19
+
20
+ @classmethod
21
+ def register(cls, type: str):
22
+ """Register the blueprints_shared type with its abstract template."""
23
+ super(SharedBlueprint, cls).register(type)
24
+ register_abstract_template(
25
+ type,
26
+ AbstractTemplate(
27
+ baseType="blueprints_node",
28
+ writer={
29
+ "name": "Shared Blueprint",
30
+ "description": "Executes a shared blueprint from the component tree.",
31
+ "category": "Logic",
32
+ "toolkit": "blueprints",
33
+ "featureFlags": ["shared_blueprints"],
34
+ "fields": {
35
+ "payload": {
36
+ "name": "Payload",
37
+ "desc": "The value specified will be available using the template syntax, e.g. @{payload}.",
38
+ "default": "{}",
39
+ "type": "Text",
40
+ "control": "Textarea",
41
+ },
42
+ },
43
+ "outs": {
44
+ "success": {
45
+ "name": "Success",
46
+ "description": "Blueprint executed successfully.",
47
+ "style": "success",
48
+ },
49
+ "error": {
50
+ "name": "Error",
51
+ "description": "Blueprint execution failed.",
52
+ "style": "error",
53
+ },
54
+ },
55
+ },
56
+ ),
57
+ )
58
+
59
+ def run(self):
60
+ """Execute the source blueprint's components."""
61
+ source_blueprint_id = self.component.content.get("sourceBlueprintId", "")
62
+
63
+ if not source_blueprint_id:
64
+ raise ValueError("No source blueprint ID specified")
65
+
66
+ try:
67
+ payload = self._get_field("payload")
68
+ expanded_execution_environment = self.execution_environment | {"payload": payload}
69
+
70
+ # Get blueprint name for title (matching run_blueprint_by_key pattern)
71
+ source_blueprint = self.runner.session.session_component_tree.get_component(
72
+ source_blueprint_id
73
+ )
74
+ blueprint_name = source_blueprint.content.get("key", "Shared Blueprint") if source_blueprint else "Shared Blueprint"
75
+
76
+ return_value = self.runner.run_blueprint(
77
+ source_blueprint_id,
78
+ expanded_execution_environment,
79
+ title=f"Shared blueprint execution ({blueprint_name})"
80
+ )
81
+
82
+ self.result = return_value
83
+ self.outcome = "success"
84
+ except BaseException as e:
85
+ self.outcome = "error"
86
+ raise e
writer/blueprints.py CHANGED
@@ -8,13 +8,13 @@ import time
8
8
  from concurrent.futures import FIRST_COMPLETED, Future, ThreadPoolExecutor, wait
9
9
  from contextlib import contextmanager
10
10
  from contextvars import ContextVar, copy_context
11
- from typing import Any, Dict, Generator, List, Literal, Optional, OrderedDict, Union
11
+ from typing import Any, Dict, Generator, List, Literal, Optional, Union
12
12
 
13
13
  import writer.blocks
14
14
  import writer.blocks.base_block
15
15
  import writer.core
16
16
  import writer.core_ui
17
- from writer.journal import JournalRecord
17
+ from writer.journal import use_journal_record_context
18
18
  from writer.ss_types import BlueprintExecutionError, BlueprintExecutionLog, WriterConfigurationError
19
19
 
20
20
  MAX_DAG_DEPTH = 32
@@ -750,68 +750,61 @@ class GraphRunner:
750
750
  return self._execute(executor, event)
751
751
 
752
752
  def _execute(self, executor: ThreadPoolExecutor, abort_event: threading.Event) -> Optional[Any]:
753
- journal_record = JournalRecord(
754
- execution_environment=self.execution_environment,
755
- title=self.status_logger.title,
756
- graph=self.graph
757
- )
758
-
759
- while self.queue or self.futures:
760
- while self.queue:
761
- node: GraphNode = self.queue.pop(0)
762
- if node.can_run() and node.outcome is None:
763
- self.futures.append(node.run(self.execution_environment, self.runner, executor))
764
-
765
- self.status_logger.log("Executing...")
766
- done, _ = wait(self.futures, timeout=self.CANCELATION_CHECK_INTERVAL, return_when=FIRST_COMPLETED)
767
- if not done:
768
- if abort_event.is_set():
769
- self._cancel_all_jobs()
770
- self.status_logger.log("Terminated.", entry_type="info", exit="aborted")
771
- journal_record.save(result="stopped")
772
- return None
773
- else:
774
- continue
775
- self.status_logger.log("Executing...")
776
- for future in done:
777
- if future in self.futures:
778
- self.futures.remove(future)
779
- try:
780
- result_node: GraphNode = future.result()
781
- except BlueprintExecutionError as e:
782
- self._cancel_all_jobs()
783
- self.status_logger.log("Execution failed", entry_type="error", exit=str(e))
784
- journal_record.save(result="error")
785
- raise e
786
- except BaseException as e:
787
- abort_event.set()
788
- self._cancel_all_jobs()
789
- self.status_logger.log("Execution failed.", entry_type="error", exit=str(e))
790
- journal_record.save(result="error")
791
- raise BlueprintExecutionError(
792
- f"Blueprint execution was stopped due to an error - {e.__class__.__name__}: {e}"
793
- ) from e
794
- if result_node.outcome == "stopped":
795
- continue
796
- if result_node.return_value is not None:
797
- self._cancel_local_jobs()
798
- self.status_logger.log(
799
- f"Execution completed, node {result_node.id} returned value: {result_node.return_value}",
800
- entry_type="info",
801
- exit="return"
802
- )
803
-
804
- journal_record.save(result="success")
805
- return result_node.return_value
806
- for output in result_node.outputs:
807
- to_node_id = output.get("toNodeId")
808
- next_node = self.graph.get_node(to_node_id)
809
- if next_node:
810
- self.queue.append(next_node)
811
-
812
- self.status_logger.log("Execution completed.", entry_type="info", exit="completed")
813
- journal_record.save(result="success")
814
- return None
753
+ with use_journal_record_context(self.execution_environment, self.status_logger.title, self.graph) as journal_record:
754
+ while self.queue or self.futures:
755
+ while self.queue:
756
+ node: GraphNode = self.queue.pop(0)
757
+ if node.can_run() and node.outcome is None:
758
+ self.futures.append(node.run(self.execution_environment, self.runner, executor))
759
+
760
+ self.status_logger.log("Executing...")
761
+ done, _ = wait(self.futures, timeout=self.CANCELATION_CHECK_INTERVAL, return_when=FIRST_COMPLETED)
762
+ if not done:
763
+ if abort_event.is_set():
764
+ self._cancel_all_jobs()
765
+ self.status_logger.log("Terminated.", entry_type="info", exit="aborted")
766
+ journal_record.set_result("stopped")
767
+ return None
768
+ else:
769
+ continue
770
+ self.status_logger.log("Executing...")
771
+ for future in done:
772
+ if future in self.futures:
773
+ self.futures.remove(future)
774
+ try:
775
+ result_node: GraphNode = future.result()
776
+ except BlueprintExecutionError as e:
777
+ self._cancel_all_jobs()
778
+ self.status_logger.log("Execution failed", entry_type="error", exit=str(e))
779
+ raise e
780
+ except BaseException as e:
781
+ abort_event.set()
782
+ self._cancel_all_jobs()
783
+ self.status_logger.log("Execution failed.", entry_type="error", exit=str(e))
784
+ raise BlueprintExecutionError(
785
+ f"Blueprint execution was stopped due to an error - {e.__class__.__name__}: {e}"
786
+ ) from e
787
+ if result_node.outcome == "stopped":
788
+ continue
789
+ if result_node.return_value is not None:
790
+ self._cancel_local_jobs()
791
+ self.status_logger.log(
792
+ f"Execution completed, node {result_node.id} returned value: {result_node.return_value}",
793
+ entry_type="info",
794
+ exit="return"
795
+ )
796
+
797
+ journal_record.set_result("success")
798
+ return result_node.return_value
799
+ for output in result_node.outputs:
800
+ to_node_id = output.get("toNodeId")
801
+ next_node = self.graph.get_node(to_node_id)
802
+ if next_node:
803
+ self.queue.append(next_node)
804
+
805
+ self.status_logger.log("Execution completed.", entry_type="info", exit="completed")
806
+ journal_record.set_result("success")
807
+ return None
815
808
 
816
809
  def _cancel_local_jobs(self):
817
810
  self.queue.clear()
writer/journal.py CHANGED
@@ -1,14 +1,17 @@
1
+ import contextlib
1
2
  import json
2
3
  import logging
4
+ from contextvars import ContextVar
5
+ from copy import deepcopy
3
6
  from datetime import datetime, timezone
4
- from typing import TYPE_CHECKING, Any, Dict, Literal
7
+ from typing import TYPE_CHECKING, Any, Dict, Literal, Optional
5
8
 
6
9
  import writer.abstract
7
10
  from writer.core import Config
8
11
  from writer.keyvalue_storage import writer_kv_storage
9
12
 
10
13
  if TYPE_CHECKING:
11
- from writer.blueprints import Graph
14
+ from writer.blueprints import Graph, GraphNode
12
15
  from writer.core import Component
13
16
 
14
17
 
@@ -33,6 +36,7 @@ class JournalRecord:
33
36
  # All nodes in a blueprint share the same parent blueprint component
34
37
  self.blueprint_id = graph.nodes[0].component.parentId if graph.nodes else None
35
38
 
39
+ self.execution_environment = execution_environment
36
40
  self.trigger = {
37
41
  "event": execution_environment.get("context", {}).get("event"),
38
42
  "payload": execution_environment.get("payload"),
@@ -61,12 +65,26 @@ class JournalRecord:
61
65
  self.trigger["type"] = "On demand"
62
66
 
63
67
  self.graph = graph
68
+ self.block_outputs: Dict[str, Any] = {}
69
+ for graph_node in self.graph.nodes:
70
+ block_info = self._get_block_info(graph_node.component)
71
+ self.block_outputs[graph_node.id] = {
72
+ "component": {
73
+ "type": graph_node.component.type,
74
+ "id": graph_node.component.id,
75
+ "title": block_info["title"],
76
+ "category": block_info["category"]
77
+ },
78
+ "executions": []
79
+ }
80
+
64
81
  self.is_runable = True
82
+ self.result: Optional[Literal["success", "error", "stopped"]] = None
65
83
 
66
84
  def _get_block_info(self, component: "Component") -> Dict[str, str]:
67
85
  block_title = component.content.get("alias")
68
86
  component_definition = writer.abstract.templates.get(component.type)
69
-
87
+
70
88
  # If component has an alias, use it as title
71
89
  if block_title is not None:
72
90
  category = "Unknown category"
@@ -76,7 +94,7 @@ class JournalRecord:
76
94
  "title": block_title,
77
95
  "category": category
78
96
  }
79
-
97
+
80
98
  # If no component definition found, return defaults
81
99
  if component_definition is None:
82
100
  return {
@@ -91,39 +109,9 @@ class JournalRecord:
91
109
  }
92
110
 
93
111
  def to_dict(self) -> Dict[str, Any]:
94
- block_outputs = {}
112
+ block_outputs = deepcopy(self.block_outputs)
95
113
  for graph_node in self.graph.nodes:
96
- block_info = self._get_block_info(graph_node.component)
97
- block_data: Dict[str, Any] = {
98
- "result": graph_node.result,
99
- "outcome": graph_node.outcome,
100
- "component": {
101
- "type": graph_node.component.type,
102
- "id": graph_node.component.id,
103
- "title": block_info["title"],
104
- "category": block_info["category"]
105
- }
106
- }
107
-
108
- # Add timing information if available
109
- if graph_node.tool:
110
- if hasattr(graph_node.tool, 'started_at') and graph_node.tool.started_at >= 0:
111
- block_data["startedAt"] = graph_node.tool.started_at
112
- if hasattr(graph_node.tool, 'execution_time_in_seconds') and graph_node.tool.execution_time_in_seconds >= 0:
113
- block_data["executionTimeInSeconds"] = graph_node.tool.execution_time_in_seconds
114
-
115
- # Add captured logs if available
116
- if hasattr(graph_node.tool, 'captured_stdout') and graph_node.tool.captured_stdout:
117
- block_data["stdout"] = graph_node.tool.captured_stdout
118
- if hasattr(graph_node.tool, 'captured_logs') and graph_node.tool.captured_logs:
119
- block_data["logs"] = graph_node.tool.captured_logs
120
-
121
- # Add error message if available (contains the traceback for errors)
122
- if hasattr(graph_node.tool, 'message') and graph_node.tool.message:
123
- block_data["message"] = graph_node.tool.message
124
-
125
- block_outputs[graph_node.id] = block_data
126
-
114
+ block_outputs[graph_node.id]["executions"].append(self.get_execution_data(graph_node))
127
115
 
128
116
  data = {
129
117
  "timestamp": self.started_at.isoformat(),
@@ -131,6 +119,7 @@ class JournalRecord:
131
119
  "blueprintId": self.blueprint_id,
132
120
  "trigger": self.trigger,
133
121
  "blockOutputs": block_outputs,
122
+ "result": self.result,
134
123
  }
135
124
  sanitized_data = self._sanitize_data(data)
136
125
  return {
@@ -138,6 +127,31 @@ class JournalRecord:
138
127
  "isRunable": self.is_runable,
139
128
  }
140
129
 
130
+ def get_execution_data(self, graph_node: "GraphNode") -> Dict[str, Any]:
131
+ execution_data: Dict[str, Any] = {
132
+ "result": graph_node.result,
133
+ "outcome": graph_node.outcome,
134
+ }
135
+
136
+ # Add timing information if available
137
+ if graph_node.tool:
138
+ if hasattr(graph_node.tool, 'started_at') and graph_node.tool.started_at >= 0:
139
+ execution_data["startedAt"] = graph_node.tool.started_at
140
+ if hasattr(graph_node.tool, 'execution_time_in_seconds') and graph_node.tool.execution_time_in_seconds >= 0:
141
+ execution_data["executionTimeInSeconds"] = graph_node.tool.execution_time_in_seconds
142
+
143
+ # Add captured logs if available
144
+ if hasattr(graph_node.tool, 'captured_stdout') and graph_node.tool.captured_stdout:
145
+ execution_data["stdout"] = graph_node.tool.captured_stdout
146
+ if hasattr(graph_node.tool, 'captured_logs') and graph_node.tool.captured_logs:
147
+ execution_data["logs"] = graph_node.tool.captured_logs
148
+
149
+ # Add error message if available (contains the traceback for errors)
150
+ if hasattr(graph_node.tool, 'message') and graph_node.tool.message:
151
+ execution_data["message"] = graph_node.tool.message
152
+
153
+ return execution_data
154
+
141
155
  def _sanitize_data(self, data):
142
156
  if data is None:
143
157
  return None
@@ -161,9 +175,53 @@ class JournalRecord:
161
175
  def construct_key(self) -> str:
162
176
  return f"{JOURNAL_KEY_PREFIX}{self.instance_type[0]}-{int(self.started_at.timestamp() * 1000)}"
163
177
 
164
- def save(self, result: Literal["success", "error", "stopped"]) -> None:
178
+ def set_result(self, result: Literal["success", "error", "stopped"]) -> None:
179
+ self.result = result
180
+
181
+ def add_nested_execution(self, nested_record: "JournalRecord") -> None:
182
+ for graph_node in nested_record.graph.nodes:
183
+ if graph_node.id not in self.block_outputs:
184
+ self.block_outputs[graph_node.id] = nested_record.block_outputs[graph_node.id]
185
+ self.block_outputs[graph_node.id]["executions"].append(nested_record.get_execution_data(graph_node))
186
+
187
+ def save(self) -> None:
165
188
  if "journal" not in Config.feature_flags or not writer_kv_storage.is_accessible():
166
189
  return
167
190
  data = self.to_dict()
168
- data["result"] = result
169
191
  writer_kv_storage.save(self.construct_key(), data)
192
+
193
+
194
+ _parent_journal_record: ContextVar[Optional[JournalRecord]] = ContextVar("parent_journal_record", default=None)
195
+ _current_journal_record: ContextVar[Optional[JournalRecord]] = ContextVar("current_journal_record", default=None)
196
+
197
+ @contextlib.contextmanager
198
+ def use_journal_record_context(
199
+ execution_environment: Dict,
200
+ title: str,
201
+ graph: "Graph"
202
+ ):
203
+ parent_record = _parent_journal_record.get()
204
+ current_record = JournalRecord(execution_environment, title, graph)
205
+ _current_journal_record.set(current_record)
206
+ if parent_record is None:
207
+ _parent_journal_record.set(current_record)
208
+
209
+ try:
210
+ yield current_record
211
+ except BaseException as e:
212
+ current_record.set_result("error")
213
+ raise e
214
+ finally:
215
+ _current_journal_record.set(None)
216
+ if parent_record is not None:
217
+ parent_record.add_nested_execution(current_record)
218
+ else:
219
+ try:
220
+ current_record.save()
221
+ except Exception:
222
+ logger.exception("Failed to save a Journal entry")
223
+ _parent_journal_record.set(None)
224
+
225
+
226
+ def get_current_journal_record() -> Optional[JournalRecord]:
227
+ return _current_journal_record.get()
@@ -0,0 +1 @@
1
+ import{aV as f}from"./index-Tfvjt7wd.js";export{f as default};
@@ -0,0 +1 @@
1
+ import{u as E}from"./useBlueprintRun-BfljCQFl.js";import{d as j,c as S,m as I,r as J,aR as M,aS as P,o as c,f as g,g as b,J as N,x as l,y as v,z as _,K as G,R as w,S as A,as as K,G as F,_ as x,i as D,a as $,D as L,E as Y,W as T,t as W,aT as H,Y as Q,b as R,A as z,ae as U}from"./index-Tfvjt7wd.js";const X=["disabled"],Z=["disabled"],tt=j({__name:"WdsButtonSplit",props:{variant:{type:String,default:"primary"},size:{type:String,default:"default"},disabled:{type:Boolean,required:!1}},emits:{mainClick:()=>!0,dropdownOpen:()=>!0,dropdownClose:()=>!0},setup(u,{expose:C,emit:m}){const a=u,d=S(()=>[`WdsButtonSplit--size-${a.size}`,`WdsButtonSplit--variant-${a.variant}`,a.disabled?"WdsButtonSplit--disabled":void 0]),f=m,e=I("btn"),o=I("dropdown"),n=J(!1),{floatingStyles:r}=M(e,o,{placement:"bottom-end",middleware:[P(12)]});function s(B=!n.value){n.value=B,n.value?f("dropdownOpen"):f("dropdownClose")}return C({toggleDropdown:s}),(B,p)=>(c(),g("div",{ref_key:"btn",ref:e,class:F(["WdsButtonSplit",d.value])},[b("button",{type:"button",class:"WdsButtonSplit__main",disabled:u.disabled,onClick:p[0]||(p[0]=y=>B.$emit("mainClick"))},[N(B.$slots,"button",{},void 0,!0)],8,X),p[2]||(p[2]=b("hr",{class:"WdsButtonSplit__divider"},null,-1)),b("button",{class:"WdsButtonSplit__dropdownTrigger",type:"button",disabled:u.disabled,onClickCapture:p[1]||(p[1]=y=>s())},[l(v,{name:n.value?"chevron-up":"chevron-down"},null,8,["name"])],40,Z),l(K,null,{default:_(()=>[n.value?(c(),g("div",{key:0,ref_key:"dropdown",ref:o,style:G(w(r))},[N(B.$slots,"dropdown",{},void 0,!0)],4)):A("",!0)]),_:3})],2))}}),et=x(tt,[["__scopeId","data-v-e9224293"]]),nt={class:"BlueprintToolbarBlocksDropdown"},ot={class:"BlueprintToolbarBlocksDropdown__list"},st={class:"BlueprintToolbarBlocksDropdown__list__item__description"},at={class:"BlueprintToolbarBlocksDropdown__list__item__title"},rt=j({__name:"BlueprintToolbarBlocksDropdown",props:{components:{type:Array,required:!0}},emits:{jumpToComponent:u=>typeof u=="string",runBranch:u=>typeof u=="string"},setup(u){const C=u,m=D($.core);function a(e){const o=m.getComponentDefinition(e.type);return(o==null?void 0:o.name)??e.type}function d(e){if(e.type!=="blueprints_uieventtrigger"||!!e.content.defaultResult)return!0;const n=(e.outs??[]).map(s=>m.getComponentById(s.toNodeId)).flatMap(s=>Object.values(s.content??{}));return n.length===0?!0:!n.some(s=>s.includes("@{result}"))}const f=S(()=>C.components.map(e=>{var s;const o=m.getComponentDefinition(e.type),n=((s=e.content)==null?void 0:s.alias)||a(e),r=(o==null?void 0:o.name)??e.type;return{id:e.id,disabled:!d(e),title:n,description:n===r?void 0:r}}));return(e,o)=>(c(),g("div",nt,[o[0]||(o[0]=b("p",{class:"BlueprintToolbarBlocksDropdown__header"}," Start blueprint from ",-1)),b("div",ot,[(c(!0),g(L,null,Y(f.value,n=>(c(),g("div",{key:n.id,class:F(["BlueprintToolbarBlocksDropdown__list__item",{"BlueprintToolbarBlocksDropdown__list__item--disabled":n.disabled}])},[l(T,{variant:"primary",size:"smallIcon","custom-size":"20px",disabled:n.disabled,"data-writer-tooltip":n.disabled?"Can not run without a default result. Go to this block to define a default result.":"Run the branch",onClick:r=>e.$emit("runBranch",n.id)},{default:_(()=>[l(v,{name:"play"})]),_:2},1032,["disabled","data-writer-tooltip","onClick"]),b("div",null,[b("p",st,W(n.description),1),b("p",at,W(n.title),1)]),l(T,{variant:"neutral",size:"smallIcon","custom-size":"20px","data-writer-tooltip":"Jump to the blueprint",onClick:r=>e.$emit("jumpToComponent",n.id)},{default:_(()=>[l(v,{name:"square-dashed-mouse-pointer"})]),_:2},1032,["onClick"])],2))),128))])]))}}),lt=x(rt,[["__scopeId","data-v-e0d0a711"]]),it={ref:"root",class:"BlueprintToolbar","data-writer-unselectable":!0},ut=j({__name:"BlueprintToolbar",emits:{autogenClick:()=>!0,deploy:()=>!0},setup(u,{emit:C}){const m=C,a=D($.core),d=D($.builderManager),f=D($.componentId),e=I("runBlueprintBtn"),{run:o,stop:n,isRunning:r}=E(a,d,f),s=S(()=>Array.isArray(a.featureFlags.value)&&a.featureFlags.value.includes("blueprint_library")),B=S(()=>{const i=a.getComponentById(f);return H(i)}),p=S(()=>a.getComponents(f).filter(i=>{var t;return((t=a.getComponentDefinition(i.type))==null?void 0:t.category)==="Triggers"})),y=Q([]);function O(){y.value=U(d.selection.value),d.setSelection(null)}function q(){var i;if((i=y.value)!=null&&i.length){d.setSelection(null);for(const t of y.value)d.appendSelection(t.componentId,t.instancePath,t.source);y.value=[]}}function V(i){var t;d.setSelection(i,void 0,"click"),(t=e.value)==null||t.toggleDropdown(!1)}async function h(i){var t;(t=e.value)==null||t.toggleDropdown(!1),await o(i)}return(i,t)=>(c(),g("div",it,[l(T,{variant:"tertiary",size:"icon","data-automation-action":"run-autogen","data-writer-tooltip":"Autogen","data-writer-tooltip-placement":"bottom",onClick:t[0]||(t[0]=k=>m("autogenClick"))},{default:_(()=>[l(v,{name:"wand-sparkles"})]),_:1}),s.value&&B.value?(c(),R(T,{key:0,variant:"special","data-automation-action":"publish-shared-blueprint","data-writer-tooltip":"Publish this shared blueprint","data-writer-tooltip-placement":"bottom",onClick:t[1]||(t[1]=k=>m("deploy"))},{default:_(()=>[l(v,{name:"rocket"}),t[5]||(t[5]=z(" Publish blueprint "))]),_:1})):A("",!0),p.value.length&&!w(r)?(c(),R(et,{key:1,ref_key:"runBlueprintBtn",ref:e,class:"BlueprintToolbar__runBlueprintDropdown",variant:"special",onMainClick:t[3]||(t[3]=k=>h()),onDropdownOpen:O,onDropdownClose:q},{button:_(()=>[l(v,{name:"play"}),t[6]||(t[6]=z(" Run blueprint "))]),dropdown:_(()=>[l(lt,{components:p.value,onJumpToComponent:V,onRunBranch:t[2]||(t[2]=k=>h(k))},null,8,["components"])]),_:1},512)):(c(),R(T,{key:2,class:"BlueprintToolbar__runBlueprint","data-automation-action":"run-blueprint",variant:"special",onClick:t[4]||(t[4]=k=>w(r)?w(n)():h())},{default:_(()=>[l(v,{name:w(r)?"square":"play"},null,8,["name"]),z(" "+W(w(r)?"Stop run":"Run blueprint"),1)]),_:1}))],512))}}),ct=x(ut,[["__scopeId","data-v-5b7eb059"]]);export{ct as default};
@@ -1 +1 @@
1
- @layer wf{.WdsButtonSplit[data-v-e9224293]{position:relative;display:flex;border-radius:300px;box-shadow:var(--buttonShadow);border:1px solid transparent;align-items:center;height:40px;gap:8px;padding-left:12px;padding-right:12px}.WdsButtonSplit--disabled[data-v-e9224293]{opacity:40%}.WdsButtonSplit--disabled .WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit--disabled .WdsButtonSplit__main[data-v-e9224293]{cursor:not-allowed}.WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit__main[data-v-e9224293]{background-color:transparent;border:none;cursor:pointer}.WdsButtonSplit__main[data-v-e9224293]{display:flex;align-items:center;justify-content:flex-start;gap:8px;font-weight:600}.WdsButtonSplit__dropdownTrigger[data-v-e9224293]{display:flex;align-items:center;justify-content:center;font-size:20px;border-radius:50%;height:20px;width:20px}.WdsButtonSplit__divider[data-v-e9224293]{display:block;width:1px;height:100%;border:none;height:24px}.WdsButtonSplit--variant-primary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue4)}.WdsButtonSplit--variant-primary[data-v-e9224293],.WdsButtonSplit--variant-primary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-primary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-primary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue6)}.WdsButtonSplit--variant-secondary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray5)}.WdsButtonSplit--variant-secondary[data-v-e9224293],.WdsButtonSplit--variant-secondary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlack)}.WdsButtonSplit--variant-secondary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-secondary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorGray6)}.WdsButtonSplit--variant-tertiary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray2)}.WdsButtonSplit--variant-tertiary[data-v-e9224293],.WdsButtonSplit--variant-tertiary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlack);background:var(--wdsColorWhite)}.WdsButtonSplit--variant-tertiary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-tertiary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{color:var(--wdsColorGray4)}.WdsButtonSplit--variant-special .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-special[data-v-e9224293],.WdsButtonSplit--variant-special .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlue5);background:var(--wdsColorBlue2)}.WdsButtonSplit--variant-special[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-special:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue3)}.WdsButtonSplit--size-default .WdsButtonSplit__main[data-v-e9224293]{font-size:14px}.WdsButtonSplit--size-small .WdsButtonSplit__main[data-v-e9224293]{font-size:12px}}@layer wf{.BlueprintToolbarBlocksDropdown[data-v-e0d0a711]{min-width:185px;border:1px solid var(--wdsColorGray2);border:none;background:#fff;z-index:2;width:100%;max-height:40vh;border-radius:8px;padding:8px 10px;box-shadow:var(--wdsShadowMenu);box-sizing:border-box;color:var(--wdsColorGray6);max-height:300px;overflow-y:auto}.BlueprintToolbarBlocksDropdown__header[data-v-e0d0a711]{font-size:12px;text-transform:uppercase;font-weight:500;margin-bottom:10px}.BlueprintToolbarBlocksDropdown__list[data-v-e0d0a711]{display:flex;flex-direction:column;gap:8px}.BlueprintToolbarBlocksDropdown__list__item[data-v-e0d0a711]{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:16px;align-items:center}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711]{font-weight:400;color:var(--wdsColorGray4)}.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{opacity:50%}}@layer wf{.BlueprintToolbar__runBlueprint[data-v-a0eb1db5]{min-width:160px}.BlueprintToolbar__runBlueprintDropdown[data-v-a0eb1db5]{min-width:185px}}
1
+ @layer wf{.WdsButtonSplit[data-v-e9224293]{position:relative;display:flex;border-radius:300px;box-shadow:var(--buttonShadow);border:1px solid transparent;align-items:center;height:40px;gap:8px;padding-left:12px;padding-right:12px}.WdsButtonSplit--disabled[data-v-e9224293]{opacity:40%}.WdsButtonSplit--disabled .WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit--disabled .WdsButtonSplit__main[data-v-e9224293]{cursor:not-allowed}.WdsButtonSplit__dropdownTrigger[data-v-e9224293],.WdsButtonSplit__main[data-v-e9224293]{background-color:transparent;border:none;cursor:pointer}.WdsButtonSplit__main[data-v-e9224293]{display:flex;align-items:center;justify-content:flex-start;gap:8px;font-weight:600}.WdsButtonSplit__dropdownTrigger[data-v-e9224293]{display:flex;align-items:center;justify-content:center;font-size:20px;border-radius:50%;height:20px;width:20px}.WdsButtonSplit__divider[data-v-e9224293]{display:block;width:1px;height:100%;border:none;height:24px}.WdsButtonSplit--variant-primary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue4)}.WdsButtonSplit--variant-primary[data-v-e9224293],.WdsButtonSplit--variant-primary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-primary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-primary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue6)}.WdsButtonSplit--variant-secondary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray5)}.WdsButtonSplit--variant-secondary[data-v-e9224293],.WdsButtonSplit--variant-secondary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorWhite);background:var(--wdsColorBlack)}.WdsButtonSplit--variant-secondary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-secondary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorGray6)}.WdsButtonSplit--variant-tertiary .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorGray2)}.WdsButtonSplit--variant-tertiary[data-v-e9224293],.WdsButtonSplit--variant-tertiary .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlack);background:var(--wdsColorWhite)}.WdsButtonSplit--variant-tertiary[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-tertiary:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{color:var(--wdsColorGray4)}.WdsButtonSplit--variant-special .WdsButtonSplit__divider[data-v-e9224293]{background:var(--wdsColorBlue5)}.WdsButtonSplit--variant-special[data-v-e9224293],.WdsButtonSplit--variant-special .WdsButtonSplit__dropdownTrigger[data-v-e9224293]{color:var(--wdsColorBlue5);background:var(--wdsColorBlue2)}.WdsButtonSplit--variant-special[data-v-e9224293]:not(.WdsButtonSplit--disabled):hover,.WdsButtonSplit--variant-special:not(.WdsButtonSplit--disabled) .WdsButtonSplit__dropdownTrigger[data-v-e9224293]:hover{background:var(--wdsColorBlue3)}.WdsButtonSplit--size-default .WdsButtonSplit__main[data-v-e9224293]{font-size:14px}.WdsButtonSplit--size-small .WdsButtonSplit__main[data-v-e9224293]{font-size:12px}}@layer wf{.BlueprintToolbarBlocksDropdown[data-v-e0d0a711]{min-width:185px;border:1px solid var(--wdsColorGray2);border:none;background:#fff;z-index:2;width:100%;max-height:40vh;border-radius:8px;padding:8px 10px;box-shadow:var(--wdsShadowMenu);box-sizing:border-box;color:var(--wdsColorGray6);max-height:300px;overflow-y:auto}.BlueprintToolbarBlocksDropdown__header[data-v-e0d0a711]{font-size:12px;text-transform:uppercase;font-weight:500;margin-bottom:10px}.BlueprintToolbarBlocksDropdown__list[data-v-e0d0a711]{display:flex;flex-direction:column;gap:8px}.BlueprintToolbarBlocksDropdown__list__item[data-v-e0d0a711]{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:16px;align-items:center}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711]{font-weight:400;color:var(--wdsColorGray4)}.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__description[data-v-e0d0a711],.BlueprintToolbarBlocksDropdown__list__item--disabled .BlueprintToolbarBlocksDropdown__list__item__title[data-v-e0d0a711]{opacity:50%}}@layer wf{.BlueprintToolbar__runBlueprint[data-v-5b7eb059]{min-width:160px}.BlueprintToolbar__runBlueprintDropdown[data-v-5b7eb059]{min-width:185px}}