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
@@ -22,7 +22,7 @@ s3 buckets, git repositories, databases, etc.
22
22
  Default worlds and there locations are:
23
23
 
24
24
  - `donna` — `donna.artifacts` — the subpackage with artifacts provided by Donna itself.
25
- - `home` — `~/.donna/home` — the user-level donna artifacts, i.e. those that should be visible to all projects on this machine.
25
+ - `home` — `~/.donna/home` — the user-level donna artifacts, i.e. those that should be visible for all workspaces on this machine.
26
26
  - `project` — `<project-root>/.donna/project` — the project-level donna artifacts, i.e. those that are specific to this project.
27
27
  - `session` — `<project-root>/.donna/session` — the session world that contains the current state of work performed by Donna.
28
28
 
@@ -33,4 +33,10 @@ All worlds have a free layout, defined by developers who own the particular worl
33
33
  By default, worlds are read-only. Besides the next exceptions:
34
34
 
35
35
  - `session` in the project world is read-write, Donna stores its current state of work here.
36
- - `<project-root>/.donna` is read-write when the developer explicitly asks Donna to change it. For example, to add the result of performed work into project usage docs.
36
+ - `project` is read-write when the developer explicitly asks Donna to change it. For example, to add the result of performed work into docs.
37
+
38
+ ## `<world>:intro` artifact
39
+
40
+ It is a recommended practice to provide a short introductory artifact `intro.md` at the root of each world.
41
+
42
+ So, the agent can load descriptions of all worlds in a single command like `donna -p llm artifacts view "*:intro"`.
donna/cli/__main__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from donna.cli.application import app # noqa: F401
2
2
  from donna.cli.commands import artifacts # noqa: F401
3
- from donna.cli.commands import projects # noqa: F401
4
3
  from donna.cli.commands import sessions # noqa: F401
4
+ from donna.cli.commands import workspaces # noqa: F401
5
5
 
6
6
  app()
@@ -1,18 +1,42 @@
1
+ import builtins
1
2
  from collections.abc import Iterable
2
3
 
3
4
  import typer
4
5
 
6
+ from donna.cli import errors as cli_errors
5
7
  from donna.cli.application import app
6
- from donna.cli.types import FullArtifactIdArgument, FullArtifactIdPatternOption, InputPathArgument, OutputPathOption
8
+ from donna.cli.types import (
9
+ FullArtifactIdArgument,
10
+ FullArtifactIdPatternArgument,
11
+ InputPathArgument,
12
+ OutputPathOption,
13
+ TagOption,
14
+ )
7
15
  from donna.cli.utils import cells_cli, try_initialize_donna
16
+ from donna.core.errors import ErrorsList
17
+ from donna.core.result import Err, Ok, Result
8
18
  from donna.domain.ids import FullArtifactIdPattern
9
19
  from donna.protocol.cell_shortcuts import operation_succeeded
10
20
  from donna.protocol.cells import Cell
11
- from donna.world import artifacts as world_artifacts
12
- from donna.world import tmp as world_tmp
21
+ from donna.workspaces import artifacts as world_artifacts
22
+ from donna.workspaces import tmp as world_tmp
13
23
 
14
24
  artifacts_cli = typer.Typer()
15
25
 
26
+ DEFAULT_ARTIFACT_PATTERN = FullArtifactIdPattern.parse("**").unwrap()
27
+
28
+
29
+ def _parse_slug_with_extension(value: str) -> Result[tuple[str, str], ErrorsList]:
30
+ normalized = value.strip()
31
+ if "." not in normalized:
32
+ return Err([cli_errors.InvalidSlugWithExtension(value=normalized)])
33
+
34
+ slug, extension = normalized.rsplit(".", 1)
35
+ if not slug or not extension:
36
+ return Err([cli_errors.InvalidSlugWithExtension(value=normalized)])
37
+
38
+ return Ok((slug, extension))
39
+
16
40
 
17
41
  @artifacts_cli.callback(invoke_without_command=True)
18
42
  def initialize(ctx: typer.Context) -> None:
@@ -28,20 +52,23 @@ def initialize(ctx: typer.Context) -> None:
28
52
  help="List artifacts matching a pattern and show their status summaries. Lists all all artifacts by default."
29
53
  )
30
54
  @cells_cli
31
- def list(pattern: FullArtifactIdPatternOption = None) -> Iterable[Cell]:
32
- if pattern is None:
33
- pattern = FullArtifactIdPattern.parse("**").unwrap()
34
-
35
- artifacts = world_artifacts.list_artifacts(pattern).unwrap()
55
+ def list(
56
+ pattern: FullArtifactIdPatternArgument = DEFAULT_ARTIFACT_PATTERN,
57
+ tags: TagOption = None,
58
+ ) -> Iterable[Cell]:
59
+ artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
36
60
 
37
61
  return [artifact.node().status() for artifact in artifacts]
38
62
 
39
63
 
40
- @artifacts_cli.command(help="Displays a single artifact.")
64
+ @artifacts_cli.command(help="Displays artifacts matching a pattern or a specific id")
41
65
  @cells_cli
42
- def view(id: FullArtifactIdArgument) -> Iterable[Cell]:
43
- artifact = world_artifacts.load_artifact(id).unwrap()
44
- return [artifact.node().info()]
66
+ def view(
67
+ pattern: FullArtifactIdPatternArgument,
68
+ tags: TagOption = None,
69
+ ) -> Iterable[Cell]:
70
+ artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
71
+ return [artifact.node().info() for artifact in artifacts]
45
72
 
46
73
 
47
74
  @artifacts_cli.command(
@@ -63,6 +90,24 @@ def fetch(id: FullArtifactIdArgument, output: OutputPathOption = None) -> Iterab
63
90
  ]
64
91
 
65
92
 
93
+ @artifacts_cli.command(
94
+ help="Create a temporary file for artifact-related work and print its path. Use it to create new artifacts"
95
+ )
96
+ @cells_cli
97
+ def tmp(
98
+ slug_with_extension: str = typer.Argument(..., help="Temporary file slug with extension (example: 'draft.md').")
99
+ ) -> Iterable[Cell]:
100
+ slug, extension = _parse_slug_with_extension(slug_with_extension).unwrap()
101
+ output = world_tmp.create_file_for_slug(slug, extension)
102
+
103
+ return [
104
+ operation_succeeded(
105
+ f"Temporary file created at '{output}'",
106
+ output_path=str(output),
107
+ )
108
+ ]
109
+
110
+
66
111
  @artifacts_cli.command(help="Create or replace the artifact with the contents of a file.")
67
112
  @cells_cli
68
113
  def update(id: FullArtifactIdArgument, input: InputPathArgument) -> Iterable[Cell]:
@@ -70,6 +115,48 @@ def update(id: FullArtifactIdArgument, input: InputPathArgument) -> Iterable[Cel
70
115
  return [operation_succeeded(f"Artifact `{id}` updated from '{input}'", artifact_id=str(id), input_path=str(input))]
71
116
 
72
117
 
118
+ @artifacts_cli.command(help="Copy an artifact to another artifact ID (possibly across worlds).")
119
+ @cells_cli
120
+ def copy(source_id: FullArtifactIdArgument, target_id: FullArtifactIdArgument) -> Iterable[Cell]:
121
+ world_artifacts.copy_artifact(source_id, target_id).unwrap()
122
+ return [
123
+ operation_succeeded(
124
+ f"Artifact `{source_id}` copied to `{target_id}`",
125
+ source_id=str(source_id),
126
+ target_id=str(target_id),
127
+ )
128
+ ]
129
+
130
+
131
+ @artifacts_cli.command(help="Move an artifact to another artifact ID (possibly across worlds).")
132
+ @cells_cli
133
+ def move(source_id: FullArtifactIdArgument, target_id: FullArtifactIdArgument) -> Iterable[Cell]:
134
+ world_artifacts.move_artifact(source_id, target_id).unwrap()
135
+ return [
136
+ operation_succeeded(
137
+ f"Artifact `{source_id}` moved to `{target_id}`",
138
+ source_id=str(source_id),
139
+ target_id=str(target_id),
140
+ )
141
+ ]
142
+
143
+
144
+ @artifacts_cli.command(help="Remove artifacts matching a pattern.")
145
+ @cells_cli
146
+ def remove(
147
+ pattern: FullArtifactIdPatternArgument,
148
+ tags: TagOption = None,
149
+ ) -> Iterable[Cell]:
150
+ artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
151
+
152
+ cells: builtins.list[Cell] = []
153
+ for artifact in artifacts:
154
+ world_artifacts.remove_artifact(artifact.id).unwrap()
155
+ cells.append(operation_succeeded(f"Artifact `{artifact.id}` removed", artifact_id=str(artifact.id)))
156
+
157
+ return cells
158
+
159
+
73
160
  @artifacts_cli.command(help="Validate an artifact and return any validation errors.")
74
161
  @cells_cli
75
162
  def validate(id: FullArtifactIdArgument) -> Iterable[Cell]:
@@ -84,11 +171,11 @@ def validate(id: FullArtifactIdArgument) -> Iterable[Cell]:
84
171
  help="Validate all artifacts matching a pattern (defaults to all artifacts) and return any errors."
85
172
  )
86
173
  @cells_cli
87
- def validate_all(pattern: FullArtifactIdPatternOption = None) -> Iterable[Cell]: # noqa: CCR001
88
- if pattern is None:
89
- pattern = FullArtifactIdPattern.parse("**").unwrap()
90
-
91
- artifacts = world_artifacts.list_artifacts(pattern).unwrap()
174
+ def validate_all(
175
+ pattern: FullArtifactIdPatternArgument = DEFAULT_ARTIFACT_PATTERN,
176
+ tags: TagOption = None,
177
+ ) -> Iterable[Cell]: # noqa: CCR001
178
+ artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
92
179
 
93
180
  errors = []
94
181
 
@@ -21,12 +21,18 @@ def initialize(ctx: typer.Context) -> None:
21
21
  try_initialize_donna()
22
22
 
23
23
 
24
- @sessions_cli.command(help="Start a new session and emit the initial session status and action requests.")
24
+ @sessions_cli.command(help="Start a new session, reset session state, remove all session artifacts.")
25
25
  @cells_cli
26
26
  def start() -> Iterable[Cell]:
27
27
  return sessions.start()
28
28
 
29
29
 
30
+ @sessions_cli.command(help="Reset the current session state, keeps session artifacts.")
31
+ @cells_cli
32
+ def reset() -> Iterable[Cell]:
33
+ return sessions.reset()
34
+
35
+
30
36
  @sessions_cli.command(
31
37
  name="continue",
32
38
  help="Continue the current session and emit the next queued action request(s).",
@@ -48,7 +54,7 @@ def details() -> Iterable[Cell]:
48
54
  return sessions.details()
49
55
 
50
56
 
51
- @sessions_cli.command(help="Run a workflow fron an artifact to drive the current session forward.")
57
+ @sessions_cli.command(help="Run a workflow from an artifact to drive the current session forward.")
52
58
  @cells_cli
53
59
  def run(workflow_id: FullArtifactIdArgument) -> Iterable[Cell]:
54
60
  return sessions.start_workflow(workflow_id)
@@ -64,12 +70,6 @@ def action_request_completed(
64
70
  return sessions.complete_action_request(request_id, next_operation_id)
65
71
 
66
72
 
67
- @sessions_cli.command(help="Clear the current session state.")
68
- @cells_cli
69
- def clear() -> Iterable[Cell]:
70
- return sessions.clear()
71
-
72
-
73
73
  app.add_typer(
74
74
  sessions_cli,
75
75
  name="sessions",
@@ -0,0 +1,42 @@
1
+ import pathlib
2
+ from collections.abc import Iterable
3
+
4
+ import typer
5
+
6
+ from donna.cli.application import app
7
+ from donna.cli.types import ProjectDirArgument
8
+ from donna.cli.utils import cells_cli, try_initialize_donna
9
+ from donna.protocol.cell_shortcuts import operation_succeeded
10
+ from donna.protocol.cells import Cell
11
+ from donna.workspaces.initialization import initialize_workspace
12
+
13
+ workspaces_cli = typer.Typer()
14
+
15
+
16
+ @workspaces_cli.callback(invoke_without_command=True)
17
+ def initialize_callback(ctx: typer.Context) -> None:
18
+ cmd = ctx.invoked_subcommand
19
+
20
+ if cmd is None:
21
+ return
22
+
23
+ if cmd in {"init"}:
24
+ return
25
+
26
+ try_initialize_donna()
27
+
28
+
29
+ @workspaces_cli.command(help="Initialize Donna workspace.")
30
+ @cells_cli
31
+ def init(project_dir: ProjectDirArgument = None) -> Iterable[Cell]:
32
+ target_dir = project_dir or pathlib.Path.cwd()
33
+ initialize_workspace(target_dir).unwrap()
34
+
35
+ return [operation_succeeded("Workspace initialized successfully")]
36
+
37
+
38
+ app.add_typer(
39
+ workspaces_cli,
40
+ name="workspaces",
41
+ help="Initialize and manage Donna workspace.",
42
+ )
donna/cli/errors.py ADDED
@@ -0,0 +1,18 @@
1
+ from donna.core import errors as core_errors
2
+
3
+
4
+ class InternalError(core_errors.InternalError):
5
+ """Base class for internal errors in donna.cli."""
6
+
7
+
8
+ class CliError(core_errors.EnvironmentError):
9
+ cell_kind: str = "cli_error"
10
+
11
+
12
+ class InvalidSlugWithExtension(CliError):
13
+ code: str = "donna.cli.invalid_slug_with_extension"
14
+ message: str = "Invalid slug with extension: '{error.value}'."
15
+ ways_to_fix: list[str] = [
16
+ "Use the format '<slug>.<extension>' (for example: 'draft.md').",
17
+ ]
18
+ value: str
donna/cli/types.py CHANGED
@@ -73,14 +73,22 @@ FullArtifactIdArgument = Annotated[
73
73
  ]
74
74
 
75
75
 
76
- FullArtifactIdPatternOption = Annotated[
77
- FullArtifactIdPattern | None,
78
- typer.Option(
76
+ FullArtifactIdPatternArgument = Annotated[
77
+ FullArtifactIdPattern,
78
+ typer.Argument(
79
79
  parser=_parse_full_artifact_id_pattern,
80
80
  help="Artifact pattern (supports '*' and '**', e.g. 'project:*' or '**:intro').",
81
81
  ),
82
82
  ]
83
83
 
84
+ TagOption = Annotated[
85
+ list[str] | None,
86
+ typer.Option(
87
+ "--tag",
88
+ help="Filter artifacts by tag. Repeatable.",
89
+ ),
90
+ ]
91
+
84
92
 
85
93
  FullArtifactSectionIdArgument = Annotated[
86
94
  FullArtifactSectionId,
@@ -125,14 +133,13 @@ OutputPathOption = Annotated[
125
133
  ),
126
134
  ]
127
135
 
128
-
129
- WorkdirOption = Annotated[
130
- pathlib.Path,
131
- typer.Option(
132
- resolve_path=True,
136
+ ProjectDirArgument = Annotated[
137
+ pathlib.Path | None,
138
+ typer.Argument(
133
139
  exists=True,
134
140
  file_okay=False,
135
141
  dir_okay=True,
136
- help="Project root directory to initialize (defaults to current working directory).",
142
+ resolve_path=True,
143
+ help="Optional project directory. Defaults to the current working directory.",
137
144
  ),
138
145
  ]
donna/cli/utils.py CHANGED
@@ -9,7 +9,7 @@ from donna.core.errors import EnvironmentError
9
9
  from donna.core.result import UnwrapError
10
10
  from donna.protocol.cells import Cell
11
11
  from donna.protocol.modes import get_cell_formatter
12
- from donna.world.initialization import initialize_environment
12
+ from donna.workspaces.initialization import initialize_runtime
13
13
 
14
14
 
15
15
  def output_cells(cells: Iterable[Cell]) -> None:
@@ -43,7 +43,7 @@ def cells_cli(func: Callable[P, Iterable[Cell]]) -> Callable[P, None]:
43
43
 
44
44
 
45
45
  def try_initialize_donna() -> None:
46
- result = initialize_environment()
46
+ result = initialize_runtime()
47
47
 
48
48
  if result.is_ok():
49
49
  return
donna/core/errors.py CHANGED
@@ -53,17 +53,7 @@ class ProjectDirNotFound(CoreEnvironmentError):
53
53
  message: str = "Could not find a project directory containing `{error.donna_dir_name}`."
54
54
  ways_to_fix: list[str] = [
55
55
  "Run Donna from within a project directory that contains the donna directory.",
56
- "Create the donna directory in the project root if it is missing.",
57
- ]
58
- donna_dir_name: str
59
-
60
-
61
- class ProjectDirIsHome(CoreEnvironmentError):
62
- code: str = "donna.core.project_dir_is_home"
63
- message: str = "The discovered `{error.donna_dir_name}` directory is the home directory, not a project directory."
64
- ways_to_fix: list[str] = [
65
- "Run Donna from within a project directory that contains the donna directory.",
66
- "Move the donna directory out of the home folder into the project root if appropriate.",
56
+ "Create the donna workspace via CLI command if it does not exist yet.",
67
57
  ]
68
58
  donna_dir_name: str
69
59
 
donna/core/result.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import functools
4
- from dataclasses import dataclass
5
4
  from typing import Callable, Generic, ParamSpec, TypeVar, cast
6
5
 
7
6
  from donna.core.errors import InternalError
@@ -25,10 +24,12 @@ class UnwrapErrError(ResultError):
25
24
  message: str = "Called unwrap_err on an Ok value."
26
25
 
27
26
 
28
- @dataclass(frozen=True, slots=True)
29
27
  class Result(Generic[T, E]):
30
- _is_ok: bool
31
- _value: T | E
28
+ __slots__ = ("_is_ok", "_value")
29
+
30
+ def __init__(self, is_ok: bool, value: T | E) -> None:
31
+ self._is_ok = is_ok
32
+ self._value = value
32
33
 
33
34
  def is_ok(self) -> bool:
34
35
  return self._is_ok
@@ -82,10 +83,6 @@ def Err(error: E) -> Result[T, E]:
82
83
  return Result(False, error)
83
84
 
84
85
 
85
- def ok(result: Result[T, E]) -> bool:
86
- return result.is_ok()
87
-
88
-
89
86
  def unwrap_to_error(func: Callable[P, Result[T, E]]) -> Callable[P, Result[T, E]]:
90
87
 
91
88
  @functools.wraps(func)
donna/core/utils.py CHANGED
@@ -31,7 +31,4 @@ def discover_project_dir(donna_dir_name: str) -> Result[pathlib.Path, core_error
31
31
  if donna_dir is None:
32
32
  return Err([core_errors.ProjectDirNotFound(donna_dir_name=donna_dir_name)])
33
33
 
34
- if donna_dir == donna_home_dir(donna_dir_name):
35
- return Err([core_errors.ProjectDirIsHome(donna_dir_name=donna_dir_name)])
36
-
37
34
  return Ok(donna_dir)
donna/lib/__init__.py CHANGED
@@ -3,9 +3,11 @@
3
3
  from donna.primitives.artifacts.specification import Specification, Text
4
4
  from donna.primitives.artifacts.workflow import Workflow
5
5
  from donna.primitives.directives.goto import GoTo
6
+ from donna.primitives.directives.list import List
6
7
  from donna.primitives.directives.task_variable import TaskVariable
7
8
  from donna.primitives.directives.view import View
8
9
  from donna.primitives.operations.finish_workflow import FinishWorkflow
10
+ from donna.primitives.operations.output import Output
9
11
  from donna.primitives.operations.request_action import RequestAction
10
12
  from donna.primitives.operations.run_script import RunScript
11
13
 
@@ -14,8 +16,10 @@ workflow = Workflow()
14
16
  text = Text()
15
17
  request_action = RequestAction()
16
18
  finish = FinishWorkflow()
19
+ output = Output()
17
20
  run_script = RunScript()
18
21
 
19
22
  view = View(analyze_id="view")
23
+ list = List(analyze_id="list")
20
24
  goto = GoTo(analyze_id="goto")
21
25
  task_variable = TaskVariable(analyze_id="task_variable")
donna/lib/sources.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """Shared source constructor instances for default configuration."""
2
2
 
3
- from donna.world.sources.markdown import MarkdownSourceConstructor
3
+ from donna.workspaces.sources.markdown import MarkdownSourceConstructor
4
4
 
5
5
  markdown = MarkdownSourceConstructor()
donna/lib/worlds.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Shared world constructor instances for default configuration."""
2
2
 
3
- from donna.world.worlds.filesystem import FilesystemWorldConstructor
4
- from donna.world.worlds.python import PythonWorldConstructor
3
+ from donna.workspaces.worlds.filesystem import FilesystemWorldConstructor
4
+ from donna.workspaces.worlds.python import PythonWorldConstructor
5
5
 
6
6
  filesystem = FilesystemWorldConstructor()
7
7
  python = PythonWorldConstructor()
@@ -1,7 +1,5 @@
1
1
  import textwrap
2
2
 
3
- import pydantic
4
-
5
3
  from donna.core.entities import BaseEntity
6
4
  from donna.domain.ids import ActionRequestId, FullArtifactSectionId
7
5
  from donna.protocol.cells import Cell
@@ -13,9 +11,6 @@ class ActionRequest(BaseEntity):
13
11
  request: str
14
12
  operation_id: FullArtifactSectionId
15
13
 
16
- # TODO: we may want to make queue items frozen later
17
- model_config = pydantic.ConfigDict(frozen=False)
18
-
19
14
  @classmethod
20
15
  def build(cls, request: str, operation_id: FullArtifactSectionId) -> "ActionRequest":
21
16
  return cls(
@@ -1,5 +1,7 @@
1
1
  from typing import TYPE_CHECKING, Any
2
2
 
3
+ import pydantic
4
+
3
5
  from donna.core.entities import BaseEntity
4
6
  from donna.core.errors import ErrorsList
5
7
  from donna.core.result import Err, Ok, Result, unwrap_to_error
@@ -13,12 +15,13 @@ from donna.protocol.cells import Cell
13
15
  from donna.protocol.nodes import Node
14
16
 
15
17
  if TYPE_CHECKING:
16
- from donna.world.artifacts import ArtifactRenderContext
18
+ from donna.workspaces.artifacts import ArtifactRenderContext
17
19
 
18
20
 
19
21
  class ArtifactSectionConfig(BaseEntity):
20
22
  id: ArtifactSectionId
21
23
  kind: PythonImportPath
24
+ tags: list[str] = pydantic.Field(default_factory=list)
22
25
 
23
26
 
24
27
  class ArtifactSectionMeta(BaseEntity):
@@ -32,6 +35,7 @@ class ArtifactSection(BaseEntity):
32
35
  kind: PythonImportPath
33
36
  title: str
34
37
  description: str
38
+ tags: list[str] = pydantic.Field(default_factory=list)
35
39
  primary: bool = False
36
40
 
37
41
  meta: ArtifactSectionMeta
@@ -138,12 +142,12 @@ class ArtifactNode(Node):
138
142
  return primary_section_result.unwrap_err()[0].node().status()
139
143
 
140
144
  primary_section = primary_section_result.unwrap()
141
- return Cell.build_meta(
145
+ return Cell.build_markdown(
142
146
  kind="artifact_status",
143
147
  artifact_id=str(self._artifact.id),
144
148
  artifact_kind=str(primary_section.kind),
145
149
  artifact_title=primary_section.title,
146
- artifact_description=primary_section.description,
150
+ content=primary_section.description,
147
151
  )
148
152
 
149
153
  def info(self) -> Cell:
@@ -161,8 +165,6 @@ class ArtifactNode(Node):
161
165
  content="\n".join(blocks_result.unwrap()),
162
166
  artifact_id=str(self._artifact.id),
163
167
  artifact_kind=str(primary_section.kind),
164
- artifact_title=primary_section.title,
165
- artifact_description=primary_section.description,
166
168
  )
167
169
 
168
170
  def components(self) -> list["Node"]:
@@ -191,7 +193,7 @@ class ArtifactSectionNode(Node):
191
193
  def resolve(
192
194
  target_id: FullArtifactSectionId, render_context: "ArtifactRenderContext"
193
195
  ) -> Result[ArtifactSection, ErrorsList]:
194
- from donna.world import artifacts as world_artifacts
196
+ from donna.workspaces import artifacts as world_artifacts
195
197
 
196
198
  artifact = world_artifacts.load_artifact(target_id.full_artifact_id, render_context).unwrap()
197
199
 
@@ -14,13 +14,13 @@ if TYPE_CHECKING:
14
14
  from donna.machine.artifacts import Artifact, ArtifactSection
15
15
  from donna.machine.changes import Change
16
16
  from donna.machine.tasks import Task, WorkUnit
17
- from donna.world.config import SourceConfig as SourceConfigModel
18
- from donna.world.config import WorldConfig
19
- from donna.world.sources.base import SourceConfig as SourceConfigValue
20
- from donna.world.worlds.base import World
17
+ from donna.workspaces.config import SourceConfig as SourceConfigModel
18
+ from donna.workspaces.config import WorldConfig
19
+ from donna.workspaces.sources.base import SourceConfig as SourceConfigValue
20
+ from donna.workspaces.worlds.base import World
21
21
 
22
22
 
23
- # TODO: Currently is is a kind of God interface. It is convinient for now.
23
+ # TODO: Currently it is a kind of God interface. It is convenient for now.
24
24
  # However, in future we should move these methods into specific subclasses.
25
25
  class Primitive(BaseEntity):
26
26
  config_class: ClassVar[type[ArtifactSectionConfig]] = ArtifactSectionConfig
donna/machine/sessions.py CHANGED
@@ -9,10 +9,10 @@ from donna.machine.operations import OperationMeta
9
9
  from donna.machine.state import ConsistentState, MutableState
10
10
  from donna.protocol.cell_shortcuts import operation_succeeded
11
11
  from donna.protocol.cells import Cell
12
- from donna.world import artifacts
13
- from donna.world import tmp as world_tmp
14
- from donna.world.config import config
15
- from donna.world.worlds.base import World
12
+ from donna.workspaces import artifacts
13
+ from donna.workspaces import tmp as world_tmp
14
+ from donna.workspaces.config import config
15
+ from donna.workspaces.worlds.base import World
16
16
 
17
17
 
18
18
  def _errors_to_cells(errors: ErrorsList) -> list[Cell]:
@@ -47,7 +47,7 @@ def _save_state(state: ConsistentState) -> Result[None, ErrorsList]:
47
47
  @unwrap_to_error
48
48
  def _state_run(mutator: MutableState) -> Result[None, ErrorsList]:
49
49
  while mutator.has_work():
50
- mutator.exectute_next_work_unit().unwrap()
50
+ mutator.execute_next_work_unit().unwrap()
51
51
  _save_state(mutator.freeze()).unwrap()
52
52
 
53
53
  return Ok(None)
@@ -90,6 +90,14 @@ def start() -> list[Cell]:
90
90
  return [operation_succeeded("Started new session.")]
91
91
 
92
92
 
93
+ def reset() -> list[Cell]:
94
+ save_result = _save_state(MutableState.build().freeze())
95
+ if save_result.is_err():
96
+ return _errors_to_cells(save_result.unwrap_err())
97
+
98
+ return [operation_succeeded("Session state reset.")]
99
+
100
+
93
101
  def clear() -> list[Cell]:
94
102
  world_tmp.clear()
95
103
  session_result = _session()
donna/machine/state.py CHANGED
@@ -118,8 +118,8 @@ class MutableState(BaseState):
118
118
  self.started = True
119
119
 
120
120
  def add_action_request(self, action_request: ActionRequest) -> None:
121
- action_request.id = self.next_action_request_id()
122
- self.action_requests.append(action_request)
121
+ full_request = action_request.replace(id=self.next_action_request_id())
122
+ self.action_requests.append(full_request)
123
123
 
124
124
  def add_work_unit(self, work_unit: WorkUnit) -> None:
125
125
  self.work_units.append(work_unit)
@@ -160,7 +160,7 @@ class MutableState(BaseState):
160
160
  self.apply_changes(changes)
161
161
 
162
162
  @unwrap_to_error
163
- def exectute_next_work_unit(self) -> Result[None, ErrorsList]:
163
+ def execute_next_work_unit(self) -> Result[None, ErrorsList]:
164
164
  next_work_unit = self.get_next_work_unit()
165
165
  assert next_work_unit is not None
166
166
 
@@ -190,7 +190,7 @@ class StateNode(Node):
190
190
  """
191
191
  The session is IDLE. There are no active tasks.
192
192
 
193
- - If the developer asked you to start working on a new task, you can do so by initiating a new workflow.
193
+ - If the developer asked you to start working on a new task, you can do so by running a new workflow.
194
194
  - If you have been working on a task, consider it completed and REPORT THE RESULTS TO THE DEVELOPER.
195
195
  """
196
196
  )