donna 0.2.0__py3-none-any.whl → 0.2.2__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 (70) hide show
  1. donna/artifacts/intro.md +39 -0
  2. donna/artifacts/research/specs/report.md +163 -0
  3. donna/artifacts/research/work/research.md +198 -0
  4. donna/artifacts/rfc/specs/request_for_change.md +270 -0
  5. donna/artifacts/rfc/work/create.md +120 -0
  6. donna/artifacts/rfc/work/do.md +109 -0
  7. donna/artifacts/rfc/work/plan.md +68 -0
  8. donna/artifacts/usage/artifacts.md +55 -12
  9. donna/artifacts/usage/cli.md +114 -39
  10. donna/artifacts/usage/worlds.md +8 -2
  11. donna/cli/__main__.py +1 -1
  12. donna/cli/commands/artifacts.py +104 -17
  13. donna/cli/commands/sessions.py +8 -8
  14. donna/cli/commands/workspaces.py +42 -0
  15. donna/cli/errors.py +18 -0
  16. donna/cli/types.py +16 -9
  17. donna/cli/utils.py +2 -2
  18. donna/core/errors.py +1 -11
  19. donna/core/result.py +5 -8
  20. donna/core/utils.py +0 -3
  21. donna/lib/__init__.py +4 -0
  22. donna/lib/sources.py +1 -1
  23. donna/lib/worlds.py +2 -2
  24. donna/machine/action_requests.py +0 -5
  25. donna/machine/artifacts.py +8 -6
  26. donna/machine/primitives.py +5 -5
  27. donna/machine/sessions.py +13 -5
  28. donna/machine/state.py +4 -4
  29. donna/machine/tasks.py +4 -18
  30. donna/machine/templates.py +4 -2
  31. donna/primitives/artifacts/specification.py +13 -2
  32. donna/primitives/artifacts/workflow.py +11 -2
  33. donna/primitives/directives/list.py +86 -0
  34. donna/primitives/directives/view.py +52 -11
  35. donna/primitives/operations/finish_workflow.py +13 -2
  36. donna/primitives/operations/output.py +87 -0
  37. donna/primitives/operations/request_action.py +3 -9
  38. donna/primitives/operations/run_script.py +2 -2
  39. donna/protocol/utils.py +22 -0
  40. donna/workspaces/artifacts.py +238 -0
  41. donna/{world → workspaces}/artifacts_discovery.py +1 -1
  42. donna/{world → workspaces}/config.py +18 -11
  43. donna/{world → workspaces}/errors.py +55 -45
  44. donna/workspaces/initialization.py +78 -0
  45. donna/{world → workspaces}/markdown.py +21 -26
  46. donna/{world → workspaces}/sources/base.py +2 -2
  47. donna/{world → workspaces}/sources/markdown.py +8 -7
  48. donna/{world → workspaces}/templates.py +4 -4
  49. donna/workspaces/tmp.py +51 -0
  50. donna/{world → workspaces}/worlds/base.py +6 -3
  51. donna/{world → workspaces}/worlds/filesystem.py +30 -10
  52. donna/{world → workspaces}/worlds/python.py +12 -9
  53. donna-0.2.2.dist-info/METADATA +463 -0
  54. donna-0.2.2.dist-info/RECORD +92 -0
  55. {donna-0.2.0.dist-info → donna-0.2.2.dist-info}/WHEEL +1 -1
  56. donna/artifacts/work/do_it.md +0 -142
  57. donna/artifacts/work/do_it_fast.md +0 -98
  58. donna/artifacts/work/planning.md +0 -245
  59. donna/cli/commands/projects.py +0 -49
  60. donna/world/artifacts.py +0 -122
  61. donna/world/initialization.py +0 -42
  62. donna/world/tmp.py +0 -33
  63. donna/world/worlds/__init__.py +0 -0
  64. donna-0.2.0.dist-info/METADATA +0 -44
  65. donna-0.2.0.dist-info/RECORD +0 -85
  66. /donna/{artifacts/work → workspaces}/__init__.py +0 -0
  67. /donna/{world → workspaces}/sources/__init__.py +0 -0
  68. /donna/{world → workspaces/worlds}/__init__.py +0 -0
  69. {donna-0.2.0.dist-info → donna-0.2.2.dist-info}/entry_points.txt +0 -0
  70. {donna-0.2.0.dist-info → donna-0.2.2.dist-info}/licenses/LICENSE +0 -0
donna/machine/tasks.py CHANGED
@@ -1,15 +1,12 @@
1
1
  import copy
2
- import sys
3
2
  from typing import TYPE_CHECKING, Any
4
3
 
5
- import pydantic
6
-
7
4
  from donna.core.entities import BaseEntity
8
5
  from donna.core.errors import ErrorsList
9
6
  from donna.core.result import Ok, Result, unwrap_to_error
10
7
  from donna.domain.ids import FullArtifactSectionId, TaskId, WorkUnitId
11
8
  from donna.protocol.cells import Cell
12
- from donna.protocol.modes import get_cell_formatter
9
+ from donna.protocol.utils import instant_output
13
10
 
14
11
  if TYPE_CHECKING:
15
12
  from donna.machine.changes import Change
@@ -19,9 +16,6 @@ class Task(BaseEntity):
19
16
  id: TaskId
20
17
  context: dict[str, Any]
21
18
 
22
- # TODO: we may want to make queue items frozen later
23
- model_config = pydantic.ConfigDict(frozen=False)
24
-
25
19
  @classmethod
26
20
  def build(cls, id: TaskId) -> "Task":
27
21
  return Task(
@@ -61,8 +55,8 @@ class WorkUnit(BaseEntity):
61
55
  def run(self, task: Task) -> Result[list["Change"], ErrorsList]:
62
56
  from donna.machine import artifacts as machine_artifacts
63
57
  from donna.machine.primitives import resolve_primitive
64
- from donna.world.artifacts import ArtifactRenderContext
65
- from donna.world.templates import RenderMode
58
+ from donna.workspaces.artifacts import ArtifactRenderContext
59
+ from donna.workspaces.templates import RenderMode
66
60
 
67
61
  render_context = ArtifactRenderContext(
68
62
  primary_mode=RenderMode.execute,
@@ -72,17 +66,9 @@ class WorkUnit(BaseEntity):
72
66
  operation = machine_artifacts.resolve(self.operation_id, render_context).unwrap()
73
67
  operation_kind = resolve_primitive(operation.kind).unwrap()
74
68
 
75
- ##########################
76
- # We log each operation here to help agent display the progress to the user
77
- # TODO: not a good solution from the agent perspective
78
- # let's hope there will some protocol appear that helps with that later
79
- # TODO: not so good place for and way of logging, should do smth with that
80
69
  log_message = f"{self.operation_id}: {operation.title}"
81
70
  log_cell = Cell.build(kind="donna_log", media_type="text/plain", content=log_message)
82
- formatter = get_cell_formatter()
83
- sys.stdout.buffer.write(formatter.format_log(log_cell, single_mode=True) + b"\n\n")
84
- sys.stdout.buffer.flush()
85
- ##########################
71
+ instant_output([log_cell])
86
72
 
87
73
  changes = list(operation_kind.execute_section(task, self, operation))
88
74
 
@@ -28,11 +28,12 @@ class Directive(Primitive, ABC):
28
28
  self,
29
29
  context: Context,
30
30
  *argv: Any,
31
+ **kwargs: Any,
31
32
  ) -> Result[Any, ErrorsList]:
32
- from donna.world import templates as world_templates
33
+ from donna.workspaces import templates as world_templates
33
34
 
34
35
  render_mode = context["render_mode"]
35
- arguments_result = self._prepare_arguments(context, *argv)
36
+ arguments_result = self._prepare_arguments(context, *argv, **kwargs)
36
37
  if arguments_result.is_err():
37
38
  return arguments_result
38
39
 
@@ -52,6 +53,7 @@ class Directive(Primitive, ABC):
52
53
  self,
53
54
  context: Context,
54
55
  *argv: Any,
56
+ **kwargs: Any,
55
57
  ) -> PreparedDirectiveResult:
56
58
  return Ok(argv)
57
59
 
@@ -1,8 +1,10 @@
1
1
  from typing import TYPE_CHECKING, ClassVar
2
2
 
3
+ import pydantic
4
+
3
5
  from donna.machine.artifacts import ArtifactSectionConfig
4
6
  from donna.machine.primitives import Primitive
5
- from donna.world.sources.markdown import MarkdownSectionMixin
7
+ from donna.workspaces.sources.markdown import MarkdownSectionMixin
6
8
 
7
9
  if TYPE_CHECKING:
8
10
  pass
@@ -16,5 +18,14 @@ class Text(MarkdownSectionMixin, Primitive):
16
18
  config_class: ClassVar[type[TextConfig]] = TextConfig
17
19
 
18
20
 
21
+ class SpecificationConfig(ArtifactSectionConfig):
22
+ @pydantic.field_validator("tags", mode="after")
23
+ @classmethod
24
+ def ensure_specification_tag(cls, value: list[str]) -> list[str]:
25
+ if "specification" in value:
26
+ return value
27
+ return [*value, "specification"]
28
+
29
+
19
30
  class Specification(MarkdownSectionMixin, Primitive):
20
- pass
31
+ config_class: ClassVar[type[SpecificationConfig]] = SpecificationConfig
@@ -1,5 +1,7 @@
1
1
  from typing import TYPE_CHECKING, ClassVar, Iterable, cast
2
2
 
3
+ import pydantic
4
+
3
5
  from donna.core import errors as core_errors
4
6
  from donna.core.errors import ErrorsList
5
7
  from donna.core.result import Err, Ok, Result, unwrap_to_error
@@ -8,8 +10,8 @@ from donna.machine.artifacts import Artifact, ArtifactSection, ArtifactSectionCo
8
10
  from donna.machine.errors import ArtifactValidationError
9
11
  from donna.machine.operations import FsmMode, OperationMeta
10
12
  from donna.machine.primitives import Primitive
11
- from donna.world import markdown
12
- from donna.world.sources.markdown import MarkdownSectionMixin
13
+ from donna.workspaces import markdown
14
+ from donna.workspaces.sources.markdown import MarkdownSectionMixin
13
15
 
14
16
  if TYPE_CHECKING:
15
17
  from donna.machine.changes import Change
@@ -97,6 +99,13 @@ def find_workflow_sections(start_operation_id: ArtifactSectionId, artifact: Arti
97
99
  class WorkflowConfig(ArtifactSectionConfig):
98
100
  start_operation_id: ArtifactSectionId
99
101
 
102
+ @pydantic.field_validator("tags", mode="after")
103
+ @classmethod
104
+ def ensure_workflow_tag(cls, value: list[str]) -> list[str]:
105
+ if "workflow" in value:
106
+ return value
107
+ return [*value, "workflow"]
108
+
100
109
 
101
110
  class WorkflowMeta(ArtifactSectionMeta):
102
111
  start_operation_id: ArtifactSectionId
@@ -0,0 +1,86 @@
1
+ from typing import Any
2
+
3
+ from jinja2.runtime import Context
4
+
5
+ from donna.core import errors as core_errors
6
+ from donna.core.errors import ErrorsList
7
+ from donna.core.result import Err, Ok, Result
8
+ from donna.domain.ids import FullArtifactIdPattern
9
+ from donna.machine.templates import Directive, PreparedDirectiveResult
10
+ from donna.protocol.modes import mode
11
+
12
+
13
+ class EnvironmentError(core_errors.EnvironmentError):
14
+ cell_kind: str = "directive_error"
15
+
16
+
17
+ class ListInvalidArguments(EnvironmentError):
18
+ code: str = "donna.directives.list.invalid_arguments"
19
+ message: str = (
20
+ "List directive requires exactly one positional argument: artifact_id_pattern (got {error.provided_count})."
21
+ )
22
+ ways_to_fix: list[str] = ["Provide exactly one argument: artifact_id_pattern."]
23
+ provided_count: int
24
+
25
+
26
+ class ListInvalidKeyword(EnvironmentError):
27
+ code: str = "donna.directives.list.invalid_keyword"
28
+ message: str = "List directive accepts only the `tags` keyword argument (got {error.keyword})."
29
+ ways_to_fix: list[str] = ["Remove unsupported keyword arguments."]
30
+ keyword: str
31
+
32
+
33
+ class ListInvalidTags(EnvironmentError):
34
+ code: str = "donna.directives.list.invalid_tags"
35
+ message: str = "List directive `tags` must be a list of strings."
36
+ ways_to_fix: list[str] = ["Provide tags as a list of strings, e.g. tags=['tag1', 'tag2']."]
37
+
38
+
39
+ class List(Directive):
40
+ def _prepare_arguments( # noqa: CCR001
41
+ self,
42
+ context: Context,
43
+ *argv: Any,
44
+ **kwargs: Any,
45
+ ) -> PreparedDirectiveResult:
46
+ if argv is None or len(argv) != 1:
47
+ return Err([ListInvalidArguments(provided_count=0 if argv is None else len(argv))])
48
+
49
+ for keyword in kwargs:
50
+ if keyword != "tags":
51
+ return Err([ListInvalidKeyword(keyword=keyword)])
52
+
53
+ artifact_pattern_result = FullArtifactIdPattern.parse(str(argv[0]))
54
+ errors = artifact_pattern_result.err()
55
+ if errors is not None:
56
+ return Err(errors)
57
+
58
+ artifact_pattern = artifact_pattern_result.ok()
59
+ assert artifact_pattern is not None
60
+
61
+ tags = kwargs.get("tags")
62
+ if tags is None:
63
+ tags_list: list[str] = []
64
+ elif isinstance(tags, (list, tuple, set)):
65
+ tags_list = [str(tag) for tag in tags]
66
+ else:
67
+ return Err([ListInvalidTags()])
68
+
69
+ return Ok((artifact_pattern, tags_list))
70
+
71
+ def render_view(
72
+ self, context: Context, artifact_pattern: FullArtifactIdPattern, tags: list[str]
73
+ ) -> Result[Any, ErrorsList]:
74
+ protocol = mode().value
75
+ tags_args = " ".join(f"--tag '{tag}'" for tag in tags)
76
+ tag_suffix = f" {tags_args}" if tags_args else ""
77
+ return Ok(f"{artifact_pattern} (donna -p {protocol} artifacts list '{artifact_pattern}'{tag_suffix})")
78
+
79
+ def render_analyze(
80
+ self, context: Context, artifact_pattern: FullArtifactIdPattern, tags: list[str]
81
+ ) -> Result[Any, ErrorsList]:
82
+ if not tags:
83
+ return Ok(f"$$donna {self.analyze_id} {artifact_pattern} donna$$")
84
+
85
+ tags_marker = ",".join(tags)
86
+ return Ok(f"$$donna {self.analyze_id} {artifact_pattern} tags={tags_marker} donna$$")
@@ -5,7 +5,7 @@ from jinja2.runtime import Context
5
5
  from donna.core import errors as core_errors
6
6
  from donna.core.errors import ErrorsList
7
7
  from donna.core.result import Err, Ok, Result
8
- from donna.domain.ids import FullArtifactId
8
+ from donna.domain.ids import FullArtifactIdPattern
9
9
  from donna.machine.templates import Directive, PreparedDirectiveResult
10
10
  from donna.protocol.modes import mode
11
11
 
@@ -16,30 +16,71 @@ class EnvironmentError(core_errors.EnvironmentError):
16
16
 
17
17
  class ViewInvalidArguments(EnvironmentError):
18
18
  code: str = "donna.directives.view.invalid_arguments"
19
- message: str = "View directive requires exactly one argument: specification_id (got {error.provided_count})."
20
- ways_to_fix: list[str] = ["Provide exactly one argument: specification_id."]
19
+ message: str = (
20
+ "View directive requires exactly one positional argument: artifact_id_pattern (got {error.provided_count})."
21
+ )
22
+ ways_to_fix: list[str] = ["Provide exactly one argument: artifact_id_pattern."]
21
23
  provided_count: int
22
24
 
23
25
 
26
+ class ViewInvalidKeyword(EnvironmentError):
27
+ code: str = "donna.directives.view.invalid_keyword"
28
+ message: str = "View directive accepts only the `tags` keyword argument (got {error.keyword})."
29
+ ways_to_fix: list[str] = ["Remove unsupported keyword arguments."]
30
+ keyword: str
31
+
32
+
33
+ class ViewInvalidTags(EnvironmentError):
34
+ code: str = "donna.directives.view.invalid_tags"
35
+ message: str = "View directive `tags` must be a list of strings."
36
+ ways_to_fix: list[str] = ["Provide tags as a list of strings, e.g. tags=['tag1', 'tag2']."]
37
+
38
+
24
39
  class View(Directive):
25
- def _prepare_arguments(
40
+ def _prepare_arguments( # noqa: CCR001
26
41
  self,
27
42
  context: Context,
28
43
  *argv: Any,
44
+ **kwargs: Any,
29
45
  ) -> PreparedDirectiveResult:
30
46
  if argv is None or len(argv) != 1:
31
47
  return Err([ViewInvalidArguments(provided_count=0 if argv is None else len(argv))])
32
48
 
33
- artifact_id_result = FullArtifactId.parse(str(argv[0]))
34
- errors = artifact_id_result.err()
49
+ for keyword in kwargs:
50
+ if keyword != "tags":
51
+ return Err([ViewInvalidKeyword(keyword=keyword)])
52
+
53
+ artifact_pattern_result = FullArtifactIdPattern.parse(str(argv[0]))
54
+ errors = artifact_pattern_result.err()
35
55
  if errors is not None:
36
56
  return Err(errors)
37
57
 
38
- artifact_id = artifact_id_result.ok()
39
- assert artifact_id is not None
58
+ artifact_pattern = artifact_pattern_result.ok()
59
+ assert artifact_pattern is not None
60
+
61
+ tags = kwargs.get("tags")
62
+ if tags is None:
63
+ tags_list: list[str] = []
64
+ elif isinstance(tags, (list, tuple, set)):
65
+ tags_list = [str(tag) for tag in tags]
66
+ else:
67
+ return Err([ViewInvalidTags()])
40
68
 
41
- return Ok((artifact_id,))
69
+ return Ok((artifact_pattern, tags_list))
42
70
 
43
- def render_view(self, context: Context, specification_id: FullArtifactId) -> Result[Any, ErrorsList]:
71
+ def render_view(
72
+ self, context: Context, artifact_pattern: FullArtifactIdPattern, tags: list[str]
73
+ ) -> Result[Any, ErrorsList]:
44
74
  protocol = mode().value
45
- return Ok(f"donna -p {protocol} artifacts view '{specification_id}'")
75
+ tags_args = " ".join(f"--tag '{tag}'" for tag in tags)
76
+ tag_suffix = f" {tags_args}" if tags_args else ""
77
+ return Ok(f"{artifact_pattern} (donna -p {protocol} artifacts view '{artifact_pattern}'{tag_suffix})")
78
+
79
+ def render_analyze(
80
+ self, context: Context, artifact_pattern: FullArtifactIdPattern, tags: list[str]
81
+ ) -> Result[Any, ErrorsList]:
82
+ if not tags:
83
+ return Ok(f"$$donna {self.analyze_id} {artifact_pattern} donna$$")
84
+
85
+ tags_marker = ",".join(tags)
86
+ return Ok(f"$$donna {self.analyze_id} {artifact_pattern} tags={tags_marker} donna$$")
@@ -5,8 +5,10 @@ from donna.core.result import Ok, Result
5
5
  from donna.domain.ids import FullArtifactId
6
6
  from donna.machine.artifacts import ArtifactSection, ArtifactSectionConfig, ArtifactSectionMeta
7
7
  from donna.machine.operations import FsmMode, OperationConfig, OperationKind, OperationMeta
8
- from donna.world import markdown
9
- from donna.world.sources.markdown import MarkdownSectionMixin
8
+ from donna.protocol.cells import Cell
9
+ from donna.protocol.utils import instant_output
10
+ from donna.workspaces import markdown
11
+ from donna.workspaces.sources.markdown import MarkdownSectionMixin
10
12
 
11
13
  if TYPE_CHECKING:
12
14
  from donna.machine.changes import Change
@@ -21,6 +23,15 @@ class FinishWorkflow(MarkdownSectionMixin, OperationKind):
21
23
  def execute_section(self, task: "Task", unit: "WorkUnit", operation: ArtifactSection) -> Iterator["Change"]:
22
24
  from donna.machine.changes import ChangeFinishTask
23
25
 
26
+ output_text = operation.description
27
+
28
+ output_cell = Cell.build_markdown(
29
+ kind="operation_output",
30
+ content=output_text,
31
+ operation_id=str(unit.operation_id),
32
+ )
33
+ instant_output([output_cell])
34
+
24
35
  yield ChangeFinishTask(task_id=task.id)
25
36
 
26
37
  config_class: ClassVar[type[FinishWorkflowConfig]] = FinishWorkflowConfig
@@ -0,0 +1,87 @@
1
+ from typing import TYPE_CHECKING, ClassVar, Iterator, cast
2
+
3
+ from donna.core.errors import ErrorsList
4
+ from donna.core.result import Err, Ok, Result
5
+ from donna.domain.ids import ArtifactSectionId, FullArtifactId
6
+ from donna.machine.artifacts import Artifact, ArtifactSection, ArtifactSectionConfig, ArtifactSectionMeta
7
+ from donna.machine.errors import ArtifactValidationError
8
+ from donna.machine.operations import OperationConfig, OperationKind, OperationMeta
9
+ from donna.protocol.cells import Cell
10
+ from donna.protocol.utils import instant_output
11
+ from donna.workspaces import markdown
12
+ from donna.workspaces.sources.markdown import MarkdownSectionMixin
13
+
14
+ if TYPE_CHECKING:
15
+ from donna.machine.changes import Change
16
+ from donna.machine.tasks import Task, WorkUnit
17
+
18
+
19
+ class OutputMissingNextOperation(ArtifactValidationError):
20
+ code: str = "donna.workflows.output_missing_next_operation_id"
21
+ message: str = "Output operation `{error.section_id}` must define `next_operation_id`."
22
+ ways_to_fix: list[str] = [
23
+ 'Add `next_operation_id = "<next_operation_id>"` to the operation config block.',
24
+ ]
25
+
26
+
27
+ class OutputConfig(OperationConfig):
28
+ next_operation_id: ArtifactSectionId | None = None
29
+
30
+
31
+ class OutputMeta(OperationMeta):
32
+ next_operation_id: ArtifactSectionId | None = None
33
+
34
+
35
+ class Output(MarkdownSectionMixin, OperationKind):
36
+ config_class: ClassVar[type[OutputConfig]] = OutputConfig
37
+
38
+ def markdown_construct_meta(
39
+ self,
40
+ artifact_id: "FullArtifactId",
41
+ source: markdown.SectionSource,
42
+ section_config: ArtifactSectionConfig,
43
+ description: str,
44
+ primary: bool = False,
45
+ ) -> Result[ArtifactSectionMeta, ErrorsList]:
46
+ output_config = cast(OutputConfig, section_config)
47
+
48
+ allowed_transitions: set[ArtifactSectionId] = set()
49
+ if output_config.next_operation_id is not None:
50
+ allowed_transitions.add(output_config.next_operation_id)
51
+
52
+ return Ok(
53
+ OutputMeta(
54
+ fsm_mode=output_config.fsm_mode,
55
+ allowed_transtions=allowed_transitions,
56
+ next_operation_id=output_config.next_operation_id,
57
+ )
58
+ )
59
+
60
+ def execute_section(self, task: "Task", unit: "WorkUnit", operation: ArtifactSection) -> Iterator["Change"]:
61
+ from donna.machine.changes import ChangeAddWorkUnit
62
+
63
+ meta = cast(OutputMeta, operation.meta)
64
+
65
+ output_text = operation.description
66
+
67
+ output_cell = Cell.build_markdown(
68
+ kind="operation_output",
69
+ content=output_text,
70
+ operation_id=str(unit.operation_id),
71
+ )
72
+ instant_output([output_cell])
73
+
74
+ next_operation_id = meta.next_operation_id
75
+ assert next_operation_id is not None
76
+ full_operation_id = unit.operation_id.full_artifact_id.to_full_local(next_operation_id)
77
+
78
+ yield ChangeAddWorkUnit(task_id=task.id, operation_id=full_operation_id)
79
+
80
+ def validate_section(self, artifact: Artifact, section_id: ArtifactSectionId) -> Result[None, ErrorsList]:
81
+ section = artifact.get_section(section_id).unwrap()
82
+ meta = cast(OutputMeta, section.meta)
83
+
84
+ if meta.next_operation_id is None:
85
+ return Err([OutputMissingNextOperation(artifact_id=artifact.id, section_id=section_id)])
86
+
87
+ return Ok(None)
@@ -10,8 +10,8 @@ from donna.domain.ids import ArtifactSectionId, FullArtifactId
10
10
  from donna.machine.action_requests import ActionRequest
11
11
  from donna.machine.artifacts import ArtifactSection, ArtifactSectionConfig, ArtifactSectionMeta
12
12
  from donna.machine.operations import FsmMode, OperationConfig, OperationKind, OperationMeta
13
- from donna.world import markdown
14
- from donna.world.sources.markdown import MarkdownSectionMixin
13
+ from donna.workspaces import markdown
14
+ from donna.workspaces.sources.markdown import MarkdownSectionMixin
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from donna.machine.changes import Change
@@ -74,13 +74,7 @@ class RequestAction(MarkdownSectionMixin, OperationKind):
74
74
  def execute_section(self, task: "Task", unit: "WorkUnit", operation: ArtifactSection) -> Iterator["Change"]:
75
75
  from donna.machine.changes import ChangeAddActionRequest
76
76
 
77
- context: dict[str, object] = {
78
- "scheme": operation,
79
- "task": task,
80
- "work_unit": unit,
81
- }
82
-
83
- request_text = operation.description.format(**context)
77
+ request_text = operation.description
84
78
 
85
79
  full_operation_id = unit.operation_id
86
80
 
@@ -12,8 +12,8 @@ from donna.domain.ids import ArtifactSectionId, FullArtifactId
12
12
  from donna.machine.artifacts import Artifact, ArtifactSection, ArtifactSectionConfig, ArtifactSectionMeta
13
13
  from donna.machine.errors import ArtifactValidationError
14
14
  from donna.machine.operations import OperationConfig, OperationKind, OperationMeta
15
- from donna.world import markdown
16
- from donna.world.sources.markdown import MarkdownSectionMixin
15
+ from donna.workspaces import markdown
16
+ from donna.workspaces.sources.markdown import MarkdownSectionMixin
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from donna.machine.changes import Change
@@ -0,0 +1,22 @@
1
+ import sys
2
+
3
+ from donna.protocol.cells import Cell
4
+ from donna.protocol.modes import get_cell_formatter
5
+
6
+
7
+ def instant_output(cells: list[Cell]) -> None:
8
+ if not cells:
9
+ return
10
+
11
+ formatter = get_cell_formatter()
12
+
13
+ formatted_cells: list[bytes] = []
14
+ for cell in cells:
15
+ # TODO: we should refactor that hardcoded check somehow
16
+ if cell.kind == "donna_log":
17
+ formatted_cells.append(formatter.format_log(cell, single_mode=True))
18
+ else:
19
+ formatted_cells.append(formatter.format_cell(cell, single_mode=False))
20
+
21
+ sys.stdout.buffer.write(b"\n\n".join(formatted_cells) + b"\n\n")
22
+ sys.stdout.buffer.flush()