ommlds 0.0.0.dev494__py3-none-any.whl → 0.0.0.dev496__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 (85) hide show
  1. ommlds/cli/_dataclasses.py +7 -7
  2. ommlds/cli/backends/inject.py +49 -8
  3. ommlds/cli/backends/meta.py +35 -0
  4. ommlds/cli/content/messages.py +1 -1
  5. ommlds/cli/inject.py +1 -1
  6. ommlds/cli/sessions/chat/drivers/{driver.py → impl.py} +2 -9
  7. ommlds/cli/sessions/chat/drivers/inject.py +5 -3
  8. ommlds/cli/sessions/chat/drivers/state/inject.py +2 -3
  9. ommlds/cli/sessions/chat/drivers/tools/injection.py +4 -4
  10. ommlds/cli/sessions/chat/drivers/types.py +21 -0
  11. ommlds/cli/sessions/chat/drivers/user/inject.py +4 -3
  12. ommlds/cli/sessions/chat/facades/commands/inject.py +0 -2
  13. ommlds/cli/sessions/chat/facades/commands/simple.py +2 -8
  14. ommlds/cli/sessions/chat/facades/facade.py +1 -1
  15. ommlds/cli/sessions/chat/facades/inject.py +5 -0
  16. ommlds/cli/sessions/chat/facades/ui.py +11 -0
  17. ommlds/cli/sessions/chat/interfaces/bare/interactive.py +1 -1
  18. ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +1 -1
  19. ommlds/cli/sessions/chat/interfaces/textual/app.py +21 -3
  20. ommlds/cli/sessions/chat/interfaces/textual/inject.py +2 -5
  21. ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +2 -0
  22. ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +12 -5
  23. ommlds/minichain/__init__.py +81 -35
  24. ommlds/minichain/_dataclasses.py +7688 -3344
  25. ommlds/minichain/backends/impls/anthropic/protocol.py +2 -2
  26. ommlds/minichain/backends/impls/cerebras/protocol.py +2 -2
  27. ommlds/minichain/backends/impls/google/tools.py +2 -2
  28. ommlds/minichain/backends/impls/groq/protocol.py +2 -2
  29. ommlds/minichain/backends/impls/ollama/protocol.py +2 -2
  30. ommlds/minichain/backends/impls/openai/format.py +2 -2
  31. ommlds/minichain/backends/strings/resolving.py +1 -1
  32. ommlds/minichain/chat/messages.py +22 -25
  33. ommlds/minichain/chat/templating.py +1 -1
  34. ommlds/minichain/content/__init__.py +9 -2
  35. ommlds/minichain/content/_marshal.py +162 -49
  36. ommlds/minichain/content/code.py +17 -0
  37. ommlds/minichain/content/dynamic.py +12 -0
  38. ommlds/minichain/content/images.py +3 -2
  39. ommlds/minichain/content/json.py +3 -2
  40. ommlds/minichain/content/namespaces.py +9 -0
  41. ommlds/minichain/content/placeholders.py +11 -9
  42. ommlds/minichain/content/quote.py +17 -0
  43. ommlds/minichain/content/raw.py +49 -0
  44. ommlds/minichain/content/section.py +14 -0
  45. ommlds/minichain/content/sequence.py +7 -2
  46. ommlds/minichain/content/{simple.py → standard.py} +3 -13
  47. ommlds/minichain/content/tag.py +19 -0
  48. ommlds/minichain/content/templates.py +14 -0
  49. ommlds/minichain/content/text.py +3 -2
  50. ommlds/minichain/content/transform/base.py +63 -0
  51. ommlds/minichain/content/transform/interleave.py +68 -0
  52. ommlds/minichain/content/transform/materialize.py +110 -0
  53. ommlds/minichain/content/{prepare.py → transform/prepare.py} +12 -13
  54. ommlds/minichain/content/transform/squeeze.py +59 -0
  55. ommlds/minichain/content/{transforms → transform}/stringify.py +0 -6
  56. ommlds/minichain/content/types.py +5 -17
  57. ommlds/minichain/lib/fs/tools/read.py +1 -1
  58. ommlds/minichain/lib/fs/tools/recursivels/rendering.py +1 -1
  59. ommlds/minichain/lib/fs/tools/recursivels/running.py +1 -1
  60. ommlds/minichain/lib/todo/tools/write.py +2 -1
  61. ommlds/minichain/lib/todo/types.py +1 -1
  62. ommlds/minichain/meta/__init__.py +0 -0
  63. ommlds/minichain/meta/firstinwins.py +131 -0
  64. ommlds/minichain/text/applypatch.py +2 -1
  65. ommlds/minichain/text/toolparsing/llamacpp/types.py +1 -1
  66. ommlds/minichain/tokens/specials.py +1 -1
  67. ommlds/minichain/tools/execution/errorhandling.py +35 -0
  68. ommlds/minichain/tools/execution/errors.py +2 -2
  69. ommlds/minichain/tools/jsonschema.py +2 -2
  70. ommlds/minichain/tools/reflect.py +3 -3
  71. ommlds/minichain/tools/types.py +11 -14
  72. ommlds/minichain/vectors/_marshal.py +1 -1
  73. {ommlds-0.0.0.dev494.dist-info → ommlds-0.0.0.dev496.dist-info}/METADATA +4 -4
  74. {ommlds-0.0.0.dev494.dist-info → ommlds-0.0.0.dev496.dist-info}/RECORD +80 -70
  75. ommlds/cli/sessions/chat/interfaces/bare/user.py +0 -31
  76. ommlds/minichain/content/materialize.py +0 -196
  77. ommlds/minichain/content/transforms/base.py +0 -46
  78. ommlds/minichain/content/transforms/interleave.py +0 -70
  79. ommlds/minichain/content/transforms/squeeze.py +0 -72
  80. /ommlds/minichain/content/{transforms → transform}/__init__.py +0 -0
  81. /ommlds/minichain/content/{transforms → transform}/strings.py +0 -0
  82. {ommlds-0.0.0.dev494.dist-info → ommlds-0.0.0.dev496.dist-info}/WHEEL +0 -0
  83. {ommlds-0.0.0.dev494.dist-info → ommlds-0.0.0.dev496.dist-info}/entry_points.txt +0 -0
  84. {ommlds-0.0.0.dev494.dist-info → ommlds-0.0.0.dev496.dist-info}/licenses/LICENSE +0 -0
  85. {ommlds-0.0.0.dev494.dist-info → ommlds-0.0.0.dev496.dist-info}/top_level.txt +0 -0
@@ -12,7 +12,7 @@ from ....chat.messages import ToolUseMessage
12
12
  from ....chat.messages import ToolUseResultMessage
13
13
  from ....chat.messages import UserMessage
14
14
  from ....chat.tools.types import Tool
15
- from ....content.prepare import prepare_content_str
15
+ from ....content.transform.prepare import prepare_content_str
16
16
  from ....tools.jsonschema import build_tool_spec_params_json_schema
17
17
 
18
18
 
@@ -104,6 +104,6 @@ def build_protocol_chat_messages(msgs: ta.Iterable[Message]) -> BuiltChatMessage
104
104
  def build_protocol_tool(t: Tool) -> pt.ToolSpec:
105
105
  return pt.ToolSpec(
106
106
  name=check.not_none(t.spec.name),
107
- description=prepare_content_str(t.spec.desc),
107
+ description=prepare_content_str(t.spec.desc) if t.spec.desc is not None else '',
108
108
  input_schema=build_tool_spec_params_json_schema(t.spec),
109
109
  )
@@ -18,7 +18,7 @@ from ....chat.stream.types import AiDelta
18
18
  from ....chat.stream.types import ContentAiDelta
19
19
  from ....chat.stream.types import PartialToolUseAiDelta
20
20
  from ....chat.tools.types import Tool
21
- from ....content.prepare import prepare_content_str
21
+ from ....content.transform.prepare import prepare_content_str
22
22
  from ....tools.jsonschema import build_tool_spec_params_json_schema
23
23
  from ....tools.types import ToolUse
24
24
 
@@ -89,7 +89,7 @@ def build_cer_request_tool(t: Tool) -> pt.ChatCompletionRequest.Tool:
89
89
  return pt.ChatCompletionRequest.Tool(
90
90
  function=pt.ChatCompletionRequest.Tool.Function(
91
91
  name=check.not_none(t.spec.name),
92
- description=prepare_content_str(t.spec.desc),
92
+ description=prepare_content_str(t.spec.desc) if t.spec.desc is not None else None,
93
93
  parameters=build_tool_spec_params_json_schema(t.spec),
94
94
  ),
95
95
  )
@@ -7,8 +7,8 @@ from omlish import check
7
7
  from omlish import dataclasses as dc
8
8
 
9
9
  from .....backends.google.protocol import types as pt
10
- from ....content.prepare import ContentStrPreparer
11
- from ....content.prepare import default_content_str_preparer
10
+ from ....content.transform.prepare import ContentStrPreparer
11
+ from ....content.transform.prepare import default_content_str_preparer
12
12
  from ....tools.types import EnumToolDtype
13
13
  from ....tools.types import MappingToolDtype
14
14
  from ....tools.types import NullableToolDtype
@@ -18,7 +18,7 @@ from ....chat.stream.types import AiDelta
18
18
  from ....chat.stream.types import ContentAiDelta
19
19
  from ....chat.stream.types import ToolUseAiDelta
20
20
  from ....chat.tools.types import Tool
21
- from ....content.prepare import prepare_content_str
21
+ from ....content.transform.prepare import prepare_content_str
22
22
  from ....tools.jsonschema import build_tool_spec_params_json_schema
23
23
  from ....tools.types import ToolUse
24
24
 
@@ -89,7 +89,7 @@ def build_gq_request_tool(t: Tool) -> pt.ChatCompletionRequest.Tool:
89
89
  return pt.ChatCompletionRequest.Tool(
90
90
  function=pt.ChatCompletionRequest.Tool.Function(
91
91
  name=check.not_none(t.spec.name),
92
- description=prepare_content_str(t.spec.desc),
92
+ description=prepare_content_str(t.spec.desc) if t.spec.desc is not None else None,
93
93
  parameters=build_tool_spec_params_json_schema(t.spec),
94
94
  ),
95
95
  )
@@ -17,7 +17,7 @@ from ....chat.stream.types import AiDelta
17
17
  from ....chat.stream.types import ContentAiDelta
18
18
  from ....chat.stream.types import ToolUseAiDelta
19
19
  from ....chat.tools.types import Tool
20
- from ....content.prepare import prepare_content_str
20
+ from ....content.transform.prepare import prepare_content_str
21
21
  from ....tools.jsonschema import build_tool_spec_params_json_schema
22
22
  from ....tools.types import ToolUse
23
23
 
@@ -92,7 +92,7 @@ def build_ol_request_tool(t: Tool) -> pt.Tool:
92
92
  return pt.Tool(
93
93
  function=pt.Tool.Function(
94
94
  name=check.not_none(t.spec.name),
95
- description=prepare_content_str(t.spec.desc),
95
+ description=prepare_content_str(t.spec.desc) if t.spec.desc is not None else None,
96
96
  parameters=build_tool_spec_params_json_schema(t.spec),
97
97
  ),
98
98
  )
@@ -22,7 +22,7 @@ from ....chat.stream.types import ContentAiDelta
22
22
  from ....chat.stream.types import PartialToolUseAiDelta
23
23
  from ....chat.tools.types import Tool
24
24
  from ....content.json import JsonContent
25
- from ....content.prepare import prepare_content_str
25
+ from ....content.transform.prepare import prepare_content_str
26
26
  from ....llms.types import MaxCompletionTokens
27
27
  from ....llms.types import MaxTokens
28
28
  from ....llms.types import Temperature
@@ -216,7 +216,7 @@ class OpenaiChatRequestHandler:
216
216
  pt.ChatCompletionRequestTool(
217
217
  function=pt.ChatCompletionRequestTool.Function(
218
218
  name=check.not_none(ts.name),
219
- description=prepare_content_str(ts.desc),
219
+ description=prepare_content_str(ts.desc) if ts.desc is not None else None,
220
220
  parameters=build_tool_spec_params_json_schema(ts),
221
221
  ),
222
222
  )
@@ -4,9 +4,9 @@ TODO:
4
4
  - interop with registry somehow, probably? or is it strictly a different concern?
5
5
  """
6
6
  import abc
7
- import dataclasses as dc
8
7
  import typing as ta
9
8
 
9
+ from omlish import dataclasses as dc
10
10
  from omlish import lang
11
11
  from omlish.manifests.globals import GlobalManifestLoader
12
12
 
@@ -3,14 +3,11 @@ import typing as ta
3
3
 
4
4
  from omlish import check
5
5
  from omlish import dataclasses as dc
6
- from omlish import dispatch
7
6
  from omlish import lang
8
7
  from omlish import marshal as msh
9
8
  from omlish import typedvalues as tv
10
9
 
11
10
  from .._typedvalues import _tv_field_metadata
12
- from ..content.materialize import CanContent
13
- from ..content.transforms.base import ContentTransform
14
11
  from ..content.types import Content
15
12
  from ..metadata import MetadataContainer
16
13
  from ..tools.types import ToolUse
@@ -90,7 +87,7 @@ def check_ai_chat(chat: Chat) -> AiChat:
90
87
 
91
88
  @dc.dataclass(frozen=True)
92
89
  class SystemMessage(AnyUserMessage, lang.Final):
93
- c: CanContent
90
+ c: Content
94
91
 
95
92
 
96
93
  #
@@ -99,7 +96,7 @@ class SystemMessage(AnyUserMessage, lang.Final):
99
96
  @dc.dataclass(frozen=True)
100
97
  @msh.update_fields_metadata(['name'], omit_if=operator.not_)
101
98
  class UserMessage(AnyUserMessage, lang.Final):
102
- c: CanContent
99
+ c: Content
103
100
 
104
101
  name: str | None = dc.xfield(None, repr_fn=dc.opt_repr)
105
102
 
@@ -128,23 +125,23 @@ class ToolUseResultMessage(AnyUserMessage, lang.Final):
128
125
  ##
129
126
 
130
127
 
131
- class _MessageContentTransform(ContentTransform, lang.Final, lang.NotInstantiable):
132
- @dispatch.install_method(ContentTransform.apply)
133
- def apply_system_message(self, m: SystemMessage) -> SystemMessage:
134
- return dc.replace(m, c=self.apply(m.c))
135
-
136
- @dispatch.install_method(ContentTransform.apply)
137
- def apply_user_message(self, m: UserMessage) -> UserMessage:
138
- return dc.replace(m, c=self.apply(m.c))
139
-
140
- @dispatch.install_method(ContentTransform.apply)
141
- def apply_ai_message(self, m: AiMessage) -> AiMessage:
142
- return dc.replace(m, c=self.apply(m.c))
143
-
144
- @dispatch.install_method(ContentTransform.apply)
145
- def apply_tool_use_message(self, m: ToolUseMessage) -> ToolUseMessage:
146
- return dc.replace(m, tu=self.apply(m.tu))
147
-
148
- @dispatch.install_method(ContentTransform.apply)
149
- def apply_tool_use_result_message(self, m: ToolUseResultMessage) -> ToolUseResultMessage:
150
- return dc.replace(m, tur=self.apply(m.tur))
128
+ # class _MessageContentTransform(ContentTransform, lang.Final, lang.NotInstantiable):
129
+ # @dispatch.install_method(ContentTransform.apply)
130
+ # def apply_system_message(self, m: SystemMessage) -> SystemMessage:
131
+ # return dc.replace(m, c=self.apply(m.c))
132
+ #
133
+ # @dispatch.install_method(ContentTransform.apply)
134
+ # def apply_user_message(self, m: UserMessage) -> UserMessage:
135
+ # return dc.replace(m, c=self.apply(m.c))
136
+ #
137
+ # @dispatch.install_method(ContentTransform.apply)
138
+ # def apply_ai_message(self, m: AiMessage) -> AiMessage:
139
+ # return dc.replace(m, c=self.apply(m.c))
140
+ #
141
+ # @dispatch.install_method(ContentTransform.apply)
142
+ # def apply_tool_use_message(self, m: ToolUseMessage) -> ToolUseMessage:
143
+ # return dc.replace(m, tu=self.apply(m.tu))
144
+ #
145
+ # @dispatch.install_method(ContentTransform.apply)
146
+ # def apply_tool_use_result_message(self, m: ToolUseResultMessage) -> ToolUseResultMessage:
147
+ # return dc.replace(m, tur=self.apply(m.tur))
@@ -10,7 +10,7 @@ from omlish import dataclasses as dc
10
10
  from omlish import lang
11
11
  from omlish.text import templating as tpl
12
12
 
13
- from ..content.transforms.strings import transform_content_strings
13
+ from ..content.transform.strings import transform_content_strings
14
14
  from ..envs import Env
15
15
  from ..envs import EnvKey
16
16
  from .messages import Chat
@@ -9,10 +9,17 @@ _msh.register_global_module_import('._marshal', __package__)
9
9
 
10
10
 
11
11
  # This is everything _marshal.py references - it must all be imported before the conditional import.
12
+
12
13
  from . import ( # noqa
14
+ code as _code,
15
+ dynamic as _dynamic,
13
16
  images as _images,
14
- materialize as _materialize,
17
+ json as _json,
18
+ quote as _quote,
19
+ raw as _raw,
20
+ section as _section,
15
21
  sequence as _sequence,
22
+ tag as _tag,
23
+ templates as _templates,
16
24
  text as _text,
17
- types as _types,
18
25
  )
@@ -1,22 +1,30 @@
1
1
  import collections.abc
2
- import dataclasses as dc
3
2
  import typing as ta
4
3
 
5
4
  from omlish import check
5
+ from omlish import dataclasses as dc
6
6
  from omlish import lang
7
7
  from omlish import marshal as msh
8
8
  from omlish import reflect as rfl
9
9
 
10
+ from .code import CodeContent # noqa
11
+ from .dynamic import DynamicContent # noqa
10
12
  from .images import ImageContent # noqa
11
13
  from .json import JsonContent # noqa
12
- from .materialize import CanContent
13
- from .materialize import _InnerCanContent
14
+ from .quote import QuoteContent # noqa
15
+ from .raw import NON_STR_SINGLE_RAW_CONTENT_TYPES
16
+ from .raw import NonStrSingleRawContent
17
+ from .raw import RawContent # noqa
18
+ from .raw import SingleRawContent # noqa
19
+ from .section import SectionContent # noqa
14
20
  from .sequence import BlockContent # noqa
15
21
  from .sequence import InlineContent # noqa
22
+ from .sequence import ItemListContent # noqa
23
+ from .tag import TagContent # noqa
16
24
  from .text import TextContent # noqa
17
- from .types import CONTENT_RUNTIME_TYPES
25
+ from .types import CONTENT_TYPES # noqa
26
+ from .types import BaseContent
18
27
  from .types import Content
19
- from .types import ExtendedContent
20
28
 
21
29
 
22
30
  ##
@@ -29,7 +37,7 @@ class MarshalContent(lang.NotInstantiable, lang.Final):
29
37
 
30
38
  MarshalContentUnion: ta.TypeAlias = ta.Union[ # noqa
31
39
  str,
32
- ExtendedContent,
40
+ BaseContent,
33
41
  ta.Sequence[MarshalContent],
34
42
  ]
35
43
 
@@ -39,15 +47,15 @@ _MARSHAL_CONTENT_UNION_RTY = rfl.type_(MarshalContentUnion)
39
47
 
40
48
  @dc.dataclass(frozen=True)
41
49
  class _ContentMarshaler(msh.Marshaler):
42
- et: msh.Marshaler
50
+ bt: msh.Marshaler
43
51
 
44
52
  def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
45
53
  if isinstance(o, str):
46
54
  return o
47
55
  elif isinstance(o, ta.Sequence):
48
56
  return [self.marshal(ctx, e) for e in o]
49
- elif isinstance(o, ExtendedContent):
50
- return self.et.marshal(ctx, o)
57
+ elif isinstance(o, BaseContent):
58
+ return self.bt.marshal(ctx, o)
51
59
  else:
52
60
  raise TypeError(o)
53
61
 
@@ -56,12 +64,12 @@ class _ContentMarshalerFactory(msh.MarshalerFactory):
56
64
  def make_marshaler(self, ctx: msh.MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Marshaler] | None:
57
65
  if not (rty is MarshalContent or rty == _MARSHAL_CONTENT_UNION_RTY):
58
66
  return None
59
- return lambda: _ContentMarshaler(ctx.make_marshaler(ExtendedContent))
67
+ return lambda: _ContentMarshaler(ctx.make_marshaler(BaseContent))
60
68
 
61
69
 
62
70
  @dc.dataclass(frozen=True)
63
71
  class _ContentUnmarshaler(msh.Unmarshaler):
64
- et: msh.Unmarshaler
72
+ bt: msh.Unmarshaler
65
73
 
66
74
  def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
67
75
  if isinstance(v, str):
@@ -69,7 +77,7 @@ class _ContentUnmarshaler(msh.Unmarshaler):
69
77
  elif isinstance(v, ta.Sequence):
70
78
  return [self.unmarshal(ctx, e) for e in v]
71
79
  elif isinstance(v, collections.abc.Mapping):
72
- return self.et.unmarshal(ctx, v) # noqa
80
+ return self.bt.unmarshal(ctx, v) # noqa
73
81
  else:
74
82
  raise TypeError(v)
75
83
 
@@ -78,53 +86,117 @@ class _ContentUnmarshalerFactory(msh.UnmarshalerFactory):
78
86
  def make_unmarshaler(self, ctx: msh.UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Unmarshaler] | None: # noqa
79
87
  if not (rty is MarshalContent or rty == _MARSHAL_CONTENT_UNION_RTY):
80
88
  return None
81
- return lambda: _ContentUnmarshaler(ctx.make_unmarshaler(ExtendedContent))
89
+ return lambda: _ContentUnmarshaler(ctx.make_unmarshaler(BaseContent))
82
90
 
83
91
 
84
92
  ##
85
93
 
86
94
 
87
- class MarshalCanContent(lang.NotInstantiable, lang.Final):
95
+ class MarshalSingleRawContent(lang.NotInstantiable, lang.Final):
88
96
  pass
89
97
 
90
98
 
91
- MarshalCanContentUnion: ta.TypeAlias = ta.Union[ # noqa
92
- ta.Iterable[MarshalCanContent],
93
- _InnerCanContent,
99
+ _SINGLE_RAW_CONTENT_UNION_RTY = rfl.type_(SingleRawContent)
100
+
101
+
102
+ @dc.dataclass(frozen=True)
103
+ class _SingleRawContentMarshaler(msh.Marshaler):
104
+ nst: msh.Marshaler
105
+
106
+ def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
107
+ if isinstance(o, str):
108
+ return o
109
+ elif isinstance(o, NON_STR_SINGLE_RAW_CONTENT_TYPES):
110
+ return self.nst.marshal(ctx, o)
111
+ else:
112
+ raise TypeError(o)
113
+
114
+
115
+ class _SingleRawContentMarshalerFactory(msh.MarshalerFactory):
116
+ def make_marshaler(self, ctx: msh.MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Marshaler] | None:
117
+ if not (rty is MarshalSingleRawContent or rty == _SINGLE_RAW_CONTENT_UNION_RTY):
118
+ return None
119
+ return lambda: _SingleRawContentMarshaler(ctx.make_marshaler(NonStrSingleRawContent))
120
+
121
+
122
+ @dc.dataclass(frozen=True)
123
+ class _SingleRawContentUnmarshaler(msh.Unmarshaler):
124
+ nst: msh.Unmarshaler
125
+
126
+ def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
127
+ if isinstance(v, str):
128
+ return v
129
+ elif isinstance(v, collections.abc.Mapping):
130
+ return self.nst.unmarshal(ctx, v) # noqa
131
+ else:
132
+ raise TypeError(v)
133
+
134
+
135
+ class _SingleRawContentUnmarshalerFactory(msh.UnmarshalerFactory):
136
+ def make_unmarshaler(self, ctx: msh.UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Unmarshaler] | None: # noqa
137
+ if not (rty is MarshalSingleRawContent or rty == _SINGLE_RAW_CONTENT_UNION_RTY):
138
+ return None
139
+ return lambda: _SingleRawContentUnmarshaler(ctx.make_unmarshaler(NonStrSingleRawContent))
140
+
141
+
142
+ ##
143
+
144
+
145
+ class MarshalRawContent(lang.NotInstantiable, lang.Final):
146
+ pass
147
+
148
+
149
+ MarshalRawContentUnion: ta.TypeAlias = ta.Union[ # noqa
150
+ SingleRawContent,
151
+ ta.Sequence[MarshalRawContent],
94
152
  ]
95
153
 
96
154
 
97
- _MARSHAL_CAN_CONTENT_UNION_RTY = rfl.type_(MarshalCanContentUnion)
155
+ _MARSHAL_RAW_CONTENT_UNION_RTY = rfl.type_(MarshalRawContentUnion)
98
156
 
99
157
 
100
158
  @dc.dataclass(frozen=True)
101
- class _CanContentMarshaler(msh.Marshaler):
102
- c: msh.Marshaler
159
+ class _RawContentMarshaler(msh.Marshaler):
160
+ nst: msh.Marshaler
103
161
 
104
162
  def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
105
- return self.c.marshal(ctx, check.isinstance(o, CONTENT_RUNTIME_TYPES))
163
+ if isinstance(o, str):
164
+ return o
165
+ elif isinstance(o, ta.Sequence):
166
+ return [self.marshal(ctx, e) for e in o]
167
+ elif isinstance(o, NON_STR_SINGLE_RAW_CONTENT_TYPES):
168
+ return self.nst.marshal(ctx, o)
169
+ else:
170
+ raise TypeError(o)
106
171
 
107
172
 
108
- class _CanContentMarshalerFactory(msh.MarshalerFactory):
173
+ class _RawContentMarshalerFactory(msh.MarshalerFactory):
109
174
  def make_marshaler(self, ctx: msh.MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Marshaler] | None:
110
- if not (rty is MarshalCanContent or rty == _MARSHAL_CAN_CONTENT_UNION_RTY):
175
+ if not (rty is MarshalRawContent or rty == _MARSHAL_RAW_CONTENT_UNION_RTY):
111
176
  return None
112
- return lambda: _CanContentMarshaler(ctx.make_marshaler(Content))
177
+ return lambda: _RawContentMarshaler(ctx.make_marshaler(NonStrSingleRawContent))
113
178
 
114
179
 
115
180
  @dc.dataclass(frozen=True)
116
- class _CanContentUnmarshaler(msh.Unmarshaler):
117
- c: msh.Unmarshaler
181
+ class _RawContentUnmarshaler(msh.Unmarshaler):
182
+ nst: msh.Unmarshaler
118
183
 
119
184
  def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
120
- return self.c.unmarshal(ctx, v)
185
+ if isinstance(v, str):
186
+ return v
187
+ elif isinstance(v, ta.Sequence):
188
+ return [self.unmarshal(ctx, e) for e in v]
189
+ elif isinstance(v, collections.abc.Mapping):
190
+ return self.nst.unmarshal(ctx, v) # noqa
191
+ else:
192
+ raise TypeError(v)
121
193
 
122
194
 
123
- class _CanContentUnmarshalerFactory(msh.UnmarshalerFactory):
195
+ class _RawContentUnmarshalerFactory(msh.UnmarshalerFactory):
124
196
  def make_unmarshaler(self, ctx: msh.UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Unmarshaler] | None: # noqa
125
- if not (rty is MarshalCanContent or rty == _MARSHAL_CAN_CONTENT_UNION_RTY):
197
+ if not (rty is MarshalRawContent or rty == _MARSHAL_RAW_CONTENT_UNION_RTY):
126
198
  return None
127
- return lambda: _CanContentUnmarshaler(ctx.make_unmarshaler(Content))
199
+ return lambda: _RawContentUnmarshaler(ctx.make_unmarshaler(NonStrSingleRawContent))
128
200
 
129
201
 
130
202
  ##
@@ -158,35 +230,43 @@ class _JsonContentUnmarshaler(msh.Unmarshaler):
158
230
 
159
231
  @lang.static_init
160
232
  def _install_standard_marshaling() -> None:
161
- extended_content_poly = msh.Polymorphism(
162
- ExtendedContent,
233
+ base_content_poly = msh.Polymorphism(
234
+ BaseContent,
163
235
  [
164
- msh.Impl(InlineContent, 'inline'),
165
- msh.Impl(BlockContent, 'block'),
236
+
237
+ msh.Impl(CodeContent, 'code'),
238
+
166
239
  msh.Impl(ImageContent, 'image'),
240
+
167
241
  msh.Impl(JsonContent, 'json'),
242
+
243
+ msh.Impl(QuoteContent, 'quote'),
244
+
245
+ msh.Impl(SectionContent, 'section'),
246
+
247
+ msh.Impl(BlockContent, 'block'),
248
+ msh.Impl(InlineContent, 'inline'),
249
+ msh.Impl(ItemListContent, 'item_list'),
250
+
251
+ msh.Impl(TagContent, 'tag'),
252
+
168
253
  msh.Impl(TextContent, 'text'),
254
+
169
255
  ],
170
256
  )
171
257
 
172
258
  msh.install_standard_factories(
173
- msh.PolymorphismMarshalerFactory(extended_content_poly),
174
- msh.TypeMapMarshalerFactory({
175
- ImageContent: _ImageContentMarshaler(),
176
- JsonContent: _JsonContentMarshaler(),
177
- }),
178
- _ContentMarshalerFactory(),
179
- _CanContentMarshalerFactory(),
259
+ *msh.standard_polymorphism_factories(
260
+ base_content_poly,
261
+ unions='partial',
262
+ ),
180
263
  )
181
264
 
265
+ #
266
+
182
267
  msh.install_standard_factories(
183
- msh.PolymorphismUnmarshalerFactory(extended_content_poly),
184
- msh.TypeMapUnmarshalerFactory({
185
- ImageContent: _ImageContentUnmarshaler(),
186
- JsonContent: _JsonContentUnmarshaler(),
187
- }),
268
+ _ContentMarshalerFactory(),
188
269
  _ContentUnmarshalerFactory(),
189
- _CanContentUnmarshalerFactory(),
190
270
  )
191
271
 
192
272
  msh.register_global_config(
@@ -195,8 +275,41 @@ def _install_standard_marshaling() -> None:
195
275
  identity=True,
196
276
  )
197
277
 
278
+ #
279
+
280
+ msh.install_standard_factories(
281
+ _SingleRawContentMarshalerFactory(),
282
+ _SingleRawContentUnmarshalerFactory(),
283
+ )
284
+
285
+ msh.register_global_config(
286
+ SingleRawContent,
287
+ msh.ReflectOverride(MarshalSingleRawContent),
288
+ identity=True,
289
+ )
290
+
291
+ #
292
+
293
+ msh.install_standard_factories(
294
+ _RawContentMarshalerFactory(),
295
+ _RawContentUnmarshalerFactory(),
296
+ )
297
+
198
298
  msh.register_global_config(
199
- CanContent,
200
- msh.ReflectOverride(MarshalCanContent),
299
+ RawContent,
300
+ msh.ReflectOverride(MarshalRawContent),
201
301
  identity=True,
202
302
  )
303
+
304
+ #
305
+
306
+ msh.install_standard_factories(
307
+ msh.TypeMapMarshalerFactory({
308
+ ImageContent: _ImageContentMarshaler(),
309
+ JsonContent: _JsonContentMarshaler(),
310
+ }),
311
+ msh.TypeMapUnmarshalerFactory({
312
+ ImageContent: _ImageContentUnmarshaler(),
313
+ JsonContent: _JsonContentUnmarshaler(),
314
+ }),
315
+ )
@@ -0,0 +1,17 @@
1
+ from omlish import dataclasses as dc
2
+ from omlish import lang
3
+
4
+ from .standard import StandardContent
5
+ from .types import LeafContent
6
+
7
+
8
+ ##
9
+
10
+
11
+ @dc.dataclass(frozen=True)
12
+ class CodeContent(StandardContent, LeafContent, lang.Final):
13
+ s: str
14
+
15
+ _: dc.KW_ONLY
16
+
17
+ lang: str | None = None
@@ -0,0 +1,12 @@
1
+ from omlish import dataclasses as dc
2
+ from omlish import lang
3
+
4
+ from .standard import StandardContent
5
+
6
+
7
+ ##
8
+
9
+
10
+ @dc.dataclass(frozen=True)
11
+ class DynamicContent(StandardContent, lang.Abstract):
12
+ pass
@@ -8,7 +8,8 @@ import typing as ta
8
8
  from omlish import dataclasses as dc
9
9
  from omlish import lang
10
10
 
11
- from .simple import SimpleSingleExtendedContent
11
+ from .standard import StandardContent
12
+ from .types import LeafContent
12
13
 
13
14
 
14
15
  if ta.TYPE_CHECKING:
@@ -21,5 +22,5 @@ else:
21
22
 
22
23
 
23
24
  @dc.dataclass(frozen=True)
24
- class ImageContent(SimpleSingleExtendedContent, lang.Final):
25
+ class ImageContent(StandardContent, LeafContent, lang.Final):
25
26
  i: 'pimg.Image' = dc.field()
@@ -2,12 +2,13 @@ from omlish import dataclasses as dc
2
2
  from omlish import lang
3
3
 
4
4
  from ..json import JsonValue
5
- from .simple import SimpleSingleExtendedContent
5
+ from .standard import StandardContent
6
+ from .types import LeafContent
6
7
 
7
8
 
8
9
  ##
9
10
 
10
11
 
11
12
  @dc.dataclass(frozen=True)
12
- class JsonContent(SimpleSingleExtendedContent, lang.Final):
13
+ class JsonContent(StandardContent, LeafContent, lang.Final):
13
14
  v: JsonValue
@@ -1,8 +1,17 @@
1
+ from omlish import dataclasses as dc
1
2
  from omlish import lang
2
3
 
4
+ from .dynamic import DynamicContent
5
+ from .types import LeafContent
6
+
3
7
 
4
8
  ##
5
9
 
6
10
 
7
11
  class ContentNamespace(lang.Namespace, lang.Abstract):
8
12
  pass
13
+
14
+
15
+ @dc.dataclass(frozen=True)
16
+ class NamespaceContent(DynamicContent, LeafContent, lang.Final):
17
+ ns: type[ContentNamespace]
@@ -1,20 +1,22 @@
1
+ import typing as ta
2
+
1
3
  from omlish import dataclasses as dc
2
4
  from omlish import lang
3
5
 
6
+ from .dynamic import DynamicContent
7
+ from .types import LeafContent
8
+
4
9
 
5
10
  ##
6
11
 
7
12
 
8
- @dc.dataclass(frozen=True, eq=False)
9
- @dc.extra_class_params(repr_id=True)
10
- class ContentPlaceholder(lang.Final):
11
- # kw_only to prevent misuse - the string passed to this class is not the Content itself, just the name of the
12
- # placeholder
13
- name: str | None = dc.field(default=None, kw_only=True, metadata=dc.extra_field_params(repr_fn=lang.opt_repr))
13
+ class ContentPlaceholder(lang.Marker, lang.Abstract):
14
+ pass
14
15
 
15
16
 
16
- content_placeholder = ContentPlaceholder
17
+ PlaceholderContentKey: ta.TypeAlias = str | type[ContentPlaceholder]
17
18
 
18
19
 
19
- class ContentPlaceholderMarker(lang.Marker):
20
- pass
20
+ @dc.dataclass(frozen=True)
21
+ class PlaceholderContent(DynamicContent, LeafContent, lang.Final):
22
+ k: PlaceholderContentKey