ommlds 0.0.0.dev495__py3-none-any.whl → 0.0.0.dev497__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 (60) hide show
  1. ommlds/.omlish-manifests.json +1 -1
  2. ommlds/cli/backends/inject.py +2 -4
  3. ommlds/cli/content/messages.py +1 -1
  4. ommlds/cli/main.py +2 -2
  5. ommlds/cli/secrets.py +1 -1
  6. ommlds/cli/sessions/chat/drivers/user/inject.py +3 -2
  7. ommlds/minichain/__init__.py +67 -31
  8. ommlds/minichain/_dataclasses.py +2234 -1118
  9. ommlds/minichain/backends/impls/anthropic/protocol.py +2 -2
  10. ommlds/minichain/backends/impls/cerebras/protocol.py +2 -2
  11. ommlds/minichain/backends/impls/google/tools.py +2 -2
  12. ommlds/minichain/backends/impls/groq/protocol.py +2 -2
  13. ommlds/minichain/backends/impls/ollama/protocol.py +2 -2
  14. ommlds/minichain/backends/impls/openai/format.py +2 -2
  15. ommlds/minichain/chat/messages.py +22 -25
  16. ommlds/minichain/chat/templating.py +1 -1
  17. ommlds/minichain/content/__init__.py +9 -2
  18. ommlds/minichain/content/_marshal.py +159 -48
  19. ommlds/minichain/content/code.py +17 -0
  20. ommlds/minichain/content/dynamic.py +12 -0
  21. ommlds/minichain/content/images.py +3 -2
  22. ommlds/minichain/content/json.py +3 -2
  23. ommlds/minichain/content/namespaces.py +9 -0
  24. ommlds/minichain/content/placeholders.py +11 -9
  25. ommlds/minichain/content/quote.py +17 -0
  26. ommlds/minichain/content/raw.py +49 -0
  27. ommlds/minichain/content/section.py +14 -0
  28. ommlds/minichain/content/sequence.py +9 -4
  29. ommlds/minichain/content/{simple.py → standard.py} +3 -13
  30. ommlds/minichain/content/tag.py +4 -4
  31. ommlds/minichain/content/templates.py +14 -0
  32. ommlds/minichain/content/text.py +3 -2
  33. ommlds/minichain/content/transform/base.py +63 -0
  34. ommlds/minichain/content/transform/interleave.py +68 -0
  35. ommlds/minichain/content/transform/materialize.py +110 -0
  36. ommlds/minichain/content/{prepare.py → transform/prepare.py} +10 -11
  37. ommlds/minichain/content/transform/squeeze.py +59 -0
  38. ommlds/minichain/content/{transforms → transform}/stringify.py +0 -6
  39. ommlds/minichain/content/types.py +5 -17
  40. ommlds/minichain/lib/todo/tools/write.py +2 -1
  41. ommlds/minichain/tools/execution/errorhandling.py +2 -2
  42. ommlds/minichain/tools/execution/errors.py +2 -2
  43. ommlds/minichain/tools/jsonschema.py +2 -2
  44. ommlds/minichain/tools/reflect.py +3 -3
  45. ommlds/minichain/tools/types.py +11 -14
  46. ommlds/tools/git.py +74 -63
  47. {ommlds-0.0.0.dev495.dist-info → ommlds-0.0.0.dev497.dist-info}/METADATA +4 -4
  48. {ommlds-0.0.0.dev495.dist-info → ommlds-0.0.0.dev497.dist-info}/RECORD +54 -50
  49. ommlds/cli/sessions/chat/interfaces/bare/user.py +0 -31
  50. ommlds/minichain/content/cancontent.py +0 -32
  51. ommlds/minichain/content/materialize.py +0 -173
  52. ommlds/minichain/content/transforms/base.py +0 -46
  53. ommlds/minichain/content/transforms/interleave.py +0 -77
  54. ommlds/minichain/content/transforms/squeeze.py +0 -72
  55. /ommlds/minichain/content/{transforms → transform}/__init__.py +0 -0
  56. /ommlds/minichain/content/{transforms → transform}/strings.py +0 -0
  57. {ommlds-0.0.0.dev495.dist-info → ommlds-0.0.0.dev497.dist-info}/WHEEL +0 -0
  58. {ommlds-0.0.0.dev495.dist-info → ommlds-0.0.0.dev497.dist-info}/entry_points.txt +0 -0
  59. {ommlds-0.0.0.dev495.dist-info → ommlds-0.0.0.dev497.dist-info}/licenses/LICENSE +0 -0
  60. {ommlds-0.0.0.dev495.dist-info → ommlds-0.0.0.dev497.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
  )
@@ -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.cancontent 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
  )
@@ -7,17 +7,24 @@ from omlish import lang
7
7
  from omlish import marshal as msh
8
8
  from omlish import reflect as rfl
9
9
 
10
- from .cancontent import CanContent
11
- from .cancontent import _InnerCanContent
10
+ from .code import CodeContent # noqa
11
+ from .dynamic import DynamicContent # noqa
12
12
  from .images import ImageContent # noqa
13
13
  from .json import JsonContent # noqa
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
16
23
  from .tag import TagContent # noqa
17
24
  from .text import TextContent # noqa
18
- from .types import CONTENT_RUNTIME_TYPES
25
+ from .types import CONTENT_TYPES # noqa
26
+ from .types import BaseContent
19
27
  from .types import Content
20
- from .types import ExtendedContent
21
28
 
22
29
 
23
30
  ##
@@ -30,7 +37,7 @@ class MarshalContent(lang.NotInstantiable, lang.Final):
30
37
 
31
38
  MarshalContentUnion: ta.TypeAlias = ta.Union[ # noqa
32
39
  str,
33
- ExtendedContent,
40
+ BaseContent,
34
41
  ta.Sequence[MarshalContent],
35
42
  ]
36
43
 
@@ -40,15 +47,15 @@ _MARSHAL_CONTENT_UNION_RTY = rfl.type_(MarshalContentUnion)
40
47
 
41
48
  @dc.dataclass(frozen=True)
42
49
  class _ContentMarshaler(msh.Marshaler):
43
- et: msh.Marshaler
50
+ bt: msh.Marshaler
44
51
 
45
52
  def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
46
53
  if isinstance(o, str):
47
54
  return o
48
55
  elif isinstance(o, ta.Sequence):
49
56
  return [self.marshal(ctx, e) for e in o]
50
- elif isinstance(o, ExtendedContent):
51
- return self.et.marshal(ctx, o)
57
+ elif isinstance(o, BaseContent):
58
+ return self.bt.marshal(ctx, o)
52
59
  else:
53
60
  raise TypeError(o)
54
61
 
@@ -57,12 +64,12 @@ class _ContentMarshalerFactory(msh.MarshalerFactory):
57
64
  def make_marshaler(self, ctx: msh.MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Marshaler] | None:
58
65
  if not (rty is MarshalContent or rty == _MARSHAL_CONTENT_UNION_RTY):
59
66
  return None
60
- return lambda: _ContentMarshaler(ctx.make_marshaler(ExtendedContent))
67
+ return lambda: _ContentMarshaler(ctx.make_marshaler(BaseContent))
61
68
 
62
69
 
63
70
  @dc.dataclass(frozen=True)
64
71
  class _ContentUnmarshaler(msh.Unmarshaler):
65
- et: msh.Unmarshaler
72
+ bt: msh.Unmarshaler
66
73
 
67
74
  def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
68
75
  if isinstance(v, str):
@@ -70,7 +77,7 @@ class _ContentUnmarshaler(msh.Unmarshaler):
70
77
  elif isinstance(v, ta.Sequence):
71
78
  return [self.unmarshal(ctx, e) for e in v]
72
79
  elif isinstance(v, collections.abc.Mapping):
73
- return self.et.unmarshal(ctx, v) # noqa
80
+ return self.bt.unmarshal(ctx, v) # noqa
74
81
  else:
75
82
  raise TypeError(v)
76
83
 
@@ -79,53 +86,117 @@ class _ContentUnmarshalerFactory(msh.UnmarshalerFactory):
79
86
  def make_unmarshaler(self, ctx: msh.UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Unmarshaler] | None: # noqa
80
87
  if not (rty is MarshalContent or rty == _MARSHAL_CONTENT_UNION_RTY):
81
88
  return None
82
- return lambda: _ContentUnmarshaler(ctx.make_unmarshaler(ExtendedContent))
89
+ return lambda: _ContentUnmarshaler(ctx.make_unmarshaler(BaseContent))
83
90
 
84
91
 
85
92
  ##
86
93
 
87
94
 
88
- class MarshalCanContent(lang.NotInstantiable, lang.Final):
95
+ class MarshalSingleRawContent(lang.NotInstantiable, lang.Final):
89
96
  pass
90
97
 
91
98
 
92
- MarshalCanContentUnion: ta.TypeAlias = ta.Union[ # noqa
93
- ta.Iterable[MarshalCanContent],
94
- _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],
95
152
  ]
96
153
 
97
154
 
98
- _MARSHAL_CAN_CONTENT_UNION_RTY = rfl.type_(MarshalCanContentUnion)
155
+ _MARSHAL_RAW_CONTENT_UNION_RTY = rfl.type_(MarshalRawContentUnion)
99
156
 
100
157
 
101
158
  @dc.dataclass(frozen=True)
102
- class _CanContentMarshaler(msh.Marshaler):
103
- c: msh.Marshaler
159
+ class _RawContentMarshaler(msh.Marshaler):
160
+ nst: msh.Marshaler
104
161
 
105
162
  def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
106
- 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)
107
171
 
108
172
 
109
- class _CanContentMarshalerFactory(msh.MarshalerFactory):
173
+ class _RawContentMarshalerFactory(msh.MarshalerFactory):
110
174
  def make_marshaler(self, ctx: msh.MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Marshaler] | None:
111
- 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):
112
176
  return None
113
- return lambda: _CanContentMarshaler(ctx.make_marshaler(Content))
177
+ return lambda: _RawContentMarshaler(ctx.make_marshaler(NonStrSingleRawContent))
114
178
 
115
179
 
116
180
  @dc.dataclass(frozen=True)
117
- class _CanContentUnmarshaler(msh.Unmarshaler):
118
- c: msh.Unmarshaler
181
+ class _RawContentUnmarshaler(msh.Unmarshaler):
182
+ nst: msh.Unmarshaler
119
183
 
120
184
  def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
121
- 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)
122
193
 
123
194
 
124
- class _CanContentUnmarshalerFactory(msh.UnmarshalerFactory):
195
+ class _RawContentUnmarshalerFactory(msh.UnmarshalerFactory):
125
196
  def make_unmarshaler(self, ctx: msh.UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Unmarshaler] | None: # noqa
126
- 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):
127
198
  return None
128
- return lambda: _CanContentUnmarshaler(ctx.make_unmarshaler(Content))
199
+ return lambda: _RawContentUnmarshaler(ctx.make_unmarshaler(NonStrSingleRawContent))
129
200
 
130
201
 
131
202
  ##
@@ -159,36 +230,43 @@ class _JsonContentUnmarshaler(msh.Unmarshaler):
159
230
 
160
231
  @lang.static_init
161
232
  def _install_standard_marshaling() -> None:
162
- extended_content_poly = msh.Polymorphism(
163
- ExtendedContent,
233
+ base_content_poly = msh.Polymorphism(
234
+ BaseContent,
164
235
  [
165
- msh.Impl(BlockContent, 'block'),
236
+
237
+ msh.Impl(CodeContent, 'code'),
238
+
166
239
  msh.Impl(ImageContent, 'image'),
167
- msh.Impl(InlineContent, 'inline'),
240
+
168
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
+
169
251
  msh.Impl(TagContent, 'tag'),
252
+
170
253
  msh.Impl(TextContent, 'text'),
254
+
171
255
  ],
172
256
  )
173
257
 
174
258
  msh.install_standard_factories(
175
- msh.PolymorphismMarshalerFactory(extended_content_poly),
176
- msh.TypeMapMarshalerFactory({
177
- ImageContent: _ImageContentMarshaler(),
178
- JsonContent: _JsonContentMarshaler(),
179
- }),
180
- _ContentMarshalerFactory(),
181
- _CanContentMarshalerFactory(),
259
+ *msh.standard_polymorphism_factories(
260
+ base_content_poly,
261
+ unions='partial',
262
+ ),
182
263
  )
183
264
 
265
+ #
266
+
184
267
  msh.install_standard_factories(
185
- msh.PolymorphismUnmarshalerFactory(extended_content_poly),
186
- msh.TypeMapUnmarshalerFactory({
187
- ImageContent: _ImageContentUnmarshaler(),
188
- JsonContent: _JsonContentUnmarshaler(),
189
- }),
268
+ _ContentMarshalerFactory(),
190
269
  _ContentUnmarshalerFactory(),
191
- _CanContentUnmarshalerFactory(),
192
270
  )
193
271
 
194
272
  msh.register_global_config(
@@ -197,8 +275,41 @@ def _install_standard_marshaling() -> None:
197
275
  identity=True,
198
276
  )
199
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
+
200
298
  msh.register_global_config(
201
- CanContent,
202
- msh.ReflectOverride(MarshalCanContent),
299
+ RawContent,
300
+ msh.ReflectOverride(MarshalRawContent),
203
301
  identity=True,
204
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
@@ -0,0 +1,17 @@
1
+ """
2
+ TODO:
3
+ - attribution
4
+ """
5
+ from omlish import dataclasses as dc
6
+ from omlish import lang
7
+
8
+ from .standard import StandardContent
9
+ from .types import Content
10
+
11
+
12
+ ##
13
+
14
+
15
+ @dc.dataclass(frozen=True)
16
+ class QuoteContent(StandardContent, lang.Final):
17
+ body: Content