ommlds 0.0.0.dev466__py3-none-any.whl → 0.0.0.dev512__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.
- ommlds/.omlish-manifests.json +404 -31
- ommlds/README.md +11 -0
- ommlds/__about__.py +21 -12
- ommlds/_hacks/__init__.py +4 -0
- ommlds/_hacks/funcs.py +110 -0
- ommlds/_hacks/names.py +158 -0
- ommlds/_hacks/params.py +73 -0
- ommlds/_hacks/patches.py +0 -3
- ommlds/backends/anthropic/protocol/__init__.py +13 -1
- ommlds/backends/anthropic/protocol/_dataclasses.py +1625 -0
- ommlds/backends/anthropic/protocol/sse/events.py +2 -0
- ommlds/backends/anthropic/protocol/types.py +5 -7
- ommlds/backends/cerebras/__init__.py +7 -0
- ommlds/backends/cerebras/_dataclasses.py +4254 -0
- ommlds/backends/cerebras/_marshal.py +24 -0
- ommlds/backends/cerebras/clients.py +9 -0
- ommlds/backends/cerebras/protocol.py +310 -0
- ommlds/backends/google/protocol/__init__.py +13 -0
- ommlds/backends/google/protocol/_dataclasses.py +5997 -0
- ommlds/backends/google/protocol/types.py +6 -8
- ommlds/backends/groq/__init__.py +7 -0
- ommlds/backends/groq/_dataclasses.py +3901 -0
- ommlds/backends/groq/_marshal.py +23 -0
- ommlds/backends/groq/clients.py +9 -0
- ommlds/backends/groq/protocol.py +247 -0
- ommlds/{huggingface.py → backends/huggingface/cache.py} +1 -6
- ommlds/backends/huggingface/cli.py +208 -0
- ommlds/backends/llamacpp/logging.py +4 -1
- ommlds/backends/mlx/caching.py +7 -3
- ommlds/backends/mlx/cli.py +10 -7
- ommlds/backends/mlx/generation.py +18 -16
- ommlds/backends/mlx/limits.py +10 -6
- ommlds/backends/mlx/loading.py +7 -4
- ommlds/backends/ollama/__init__.py +7 -0
- ommlds/backends/ollama/_dataclasses.py +3940 -0
- ommlds/backends/ollama/cli.py +36 -0
- ommlds/backends/ollama/protocol.py +201 -0
- ommlds/backends/openai/protocol/__init__.py +15 -1
- ommlds/backends/openai/protocol/_common.py +3 -5
- ommlds/backends/openai/protocol/_dataclasses.py +7708 -0
- ommlds/backends/tavily/__init__.py +7 -0
- ommlds/backends/tavily/_dataclasses.py +1734 -0
- ommlds/backends/tavily/protocol.py +299 -0
- ommlds/backends/tinygrad/models/llama3/__init__.py +22 -14
- ommlds/backends/torch/backends.py +1 -1
- ommlds/backends/transformers/__init__.py +14 -0
- ommlds/backends/transformers/filecache.py +109 -0
- ommlds/backends/transformers/streamers.py +73 -0
- ommlds/cli/__init__.py +7 -0
- ommlds/cli/_dataclasses.py +3835 -0
- ommlds/cli/asyncs.py +30 -0
- ommlds/cli/backends/catalog.py +88 -0
- ommlds/cli/backends/configs.py +9 -0
- ommlds/cli/backends/inject.py +100 -42
- ommlds/cli/{sessions/chat/backends → backends}/injection.py +1 -1
- ommlds/cli/backends/meta.py +82 -0
- ommlds/cli/{sessions/chat/backends → backends}/types.py +11 -1
- ommlds/cli/{sessions/chat/content → content}/messages.py +2 -2
- ommlds/cli/{sessions/chat/content → content}/strings.py +1 -1
- ommlds/cli/inject.py +17 -8
- ommlds/cli/inputs/asyncs.py +32 -0
- ommlds/cli/inputs/sync.py +75 -0
- ommlds/cli/main.py +346 -114
- ommlds/cli/rendering/configs.py +9 -0
- ommlds/cli/{sessions/chat/rendering → rendering}/inject.py +4 -5
- ommlds/cli/{sessions/chat/rendering → rendering}/markdown.py +1 -1
- ommlds/cli/{sessions/chat/rendering → rendering}/raw.py +1 -1
- ommlds/cli/{sessions/chat/rendering → rendering}/types.py +7 -1
- ommlds/cli/secrets.py +22 -0
- ommlds/cli/sessions/base.py +1 -10
- ommlds/cli/sessions/chat/configs.py +13 -30
- ommlds/cli/sessions/chat/drivers/ai/configs.py +13 -0
- ommlds/cli/sessions/chat/drivers/ai/events.py +57 -0
- ommlds/cli/sessions/chat/{chat → drivers}/ai/inject.py +15 -12
- ommlds/cli/sessions/chat/{chat → drivers}/ai/rendering.py +8 -8
- ommlds/cli/sessions/chat/{chat → drivers}/ai/services.py +5 -5
- ommlds/cli/sessions/chat/{chat → drivers}/ai/tools.py +4 -8
- ommlds/cli/sessions/chat/{chat → drivers}/ai/types.py +10 -1
- ommlds/cli/sessions/chat/drivers/configs.py +25 -0
- ommlds/cli/sessions/chat/drivers/events/inject.py +27 -0
- ommlds/cli/sessions/chat/drivers/events/injection.py +14 -0
- ommlds/cli/sessions/chat/drivers/events/manager.py +16 -0
- ommlds/cli/sessions/chat/drivers/events/types.py +44 -0
- ommlds/cli/sessions/chat/drivers/impl.py +50 -0
- ommlds/cli/sessions/chat/drivers/inject.py +70 -0
- ommlds/cli/sessions/chat/drivers/state/configs.py +13 -0
- ommlds/cli/sessions/chat/drivers/state/ids.py +25 -0
- ommlds/cli/sessions/chat/drivers/state/inject.py +83 -0
- ommlds/cli/sessions/chat/{chat → drivers}/state/inmemory.py +1 -6
- ommlds/cli/sessions/chat/{chat → drivers}/state/storage.py +18 -12
- ommlds/cli/sessions/chat/{chat → drivers}/state/types.py +11 -6
- ommlds/cli/sessions/chat/drivers/tools/configs.py +22 -0
- ommlds/cli/sessions/chat/drivers/tools/confirmation.py +44 -0
- ommlds/cli/sessions/chat/drivers/tools/errorhandling.py +39 -0
- ommlds/cli/sessions/chat/{tools → drivers/tools}/execution.py +3 -4
- ommlds/cli/sessions/chat/drivers/tools/fs/__init__.py +0 -0
- ommlds/cli/sessions/chat/drivers/tools/fs/configs.py +12 -0
- ommlds/cli/sessions/chat/drivers/tools/fs/inject.py +35 -0
- ommlds/cli/sessions/chat/drivers/tools/inject.py +83 -0
- ommlds/cli/sessions/chat/{tools → drivers/tools}/injection.py +20 -5
- ommlds/cli/sessions/chat/{tools → drivers/tools}/rendering.py +3 -3
- ommlds/cli/sessions/chat/drivers/tools/todo/__init__.py +0 -0
- ommlds/cli/sessions/chat/drivers/tools/todo/configs.py +12 -0
- ommlds/cli/sessions/chat/drivers/tools/todo/inject.py +31 -0
- ommlds/cli/sessions/chat/drivers/tools/weather/__init__.py +0 -0
- ommlds/cli/sessions/chat/drivers/tools/weather/configs.py +12 -0
- ommlds/cli/sessions/chat/drivers/tools/weather/inject.py +22 -0
- ommlds/cli/sessions/chat/{tools/weather.py → drivers/tools/weather/tools.py} +1 -1
- ommlds/cli/sessions/chat/drivers/types.py +31 -0
- ommlds/cli/sessions/chat/drivers/user/__init__.py +0 -0
- ommlds/cli/sessions/chat/drivers/user/configs.py +14 -0
- ommlds/cli/sessions/chat/drivers/user/inject.py +41 -0
- ommlds/cli/sessions/chat/facades/__init__.py +0 -0
- ommlds/cli/sessions/chat/facades/commands/__init__.py +0 -0
- ommlds/cli/sessions/chat/facades/commands/base.py +83 -0
- ommlds/cli/sessions/chat/facades/commands/configs.py +9 -0
- ommlds/cli/sessions/chat/facades/commands/inject.py +41 -0
- ommlds/cli/sessions/chat/facades/commands/injection.py +15 -0
- ommlds/cli/sessions/chat/facades/commands/manager.py +59 -0
- ommlds/cli/sessions/chat/facades/commands/simple.py +34 -0
- ommlds/cli/sessions/chat/facades/commands/types.py +13 -0
- ommlds/cli/sessions/chat/facades/configs.py +11 -0
- ommlds/cli/sessions/chat/facades/facade.py +26 -0
- ommlds/cli/sessions/chat/facades/inject.py +35 -0
- ommlds/cli/sessions/chat/facades/ui.py +34 -0
- ommlds/cli/sessions/chat/inject.py +10 -49
- ommlds/cli/sessions/chat/interfaces/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/bare/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/bare/configs.py +15 -0
- ommlds/cli/sessions/chat/interfaces/bare/inject.py +69 -0
- ommlds/cli/sessions/chat/interfaces/bare/interactive.py +49 -0
- ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +21 -0
- ommlds/cli/sessions/chat/{tools/confirmation.py → interfaces/bare/tools.py} +3 -22
- ommlds/cli/sessions/chat/interfaces/base.py +13 -0
- ommlds/cli/sessions/chat/interfaces/configs.py +11 -0
- ommlds/cli/sessions/chat/interfaces/inject.py +29 -0
- ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/textual/app.py +429 -0
- ommlds/cli/sessions/chat/interfaces/textual/configs.py +11 -0
- ommlds/cli/sessions/chat/interfaces/textual/facades.py +19 -0
- ommlds/cli/sessions/chat/interfaces/textual/inject.py +111 -0
- ommlds/cli/sessions/chat/interfaces/textual/inputhistory.py +174 -0
- ommlds/cli/sessions/chat/interfaces/textual/interface.py +24 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +29 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +53 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss +7 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +167 -0
- ommlds/cli/sessions/chat/interfaces/textual/tools.py +38 -0
- ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py +70 -0
- ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +207 -0
- ommlds/cli/sessions/chat/session.py +8 -13
- ommlds/cli/sessions/completion/configs.py +5 -6
- ommlds/cli/sessions/completion/inject.py +15 -2
- ommlds/cli/sessions/completion/session.py +10 -18
- ommlds/cli/sessions/configs.py +10 -0
- ommlds/cli/sessions/embedding/configs.py +5 -6
- ommlds/cli/sessions/embedding/inject.py +15 -2
- ommlds/cli/sessions/embedding/session.py +10 -18
- ommlds/cli/sessions/inject.py +15 -15
- ommlds/cli/state/storage.py +8 -2
- ommlds/minichain/__init__.py +217 -60
- ommlds/minichain/_dataclasses.py +20640 -0
- ommlds/minichain/_typedvalues.py +15 -8
- ommlds/minichain/backends/catalogs/base.py +20 -1
- ommlds/minichain/backends/catalogs/simple.py +2 -2
- ommlds/minichain/backends/catalogs/strings.py +13 -10
- ommlds/minichain/backends/impls/anthropic/chat.py +28 -5
- ommlds/minichain/backends/impls/anthropic/names.py +3 -3
- ommlds/minichain/backends/impls/anthropic/protocol.py +2 -2
- ommlds/minichain/backends/impls/anthropic/stream.py +23 -18
- ommlds/minichain/backends/impls/cerebras/__init__.py +0 -0
- ommlds/minichain/backends/impls/cerebras/chat.py +82 -0
- ommlds/minichain/backends/impls/cerebras/names.py +45 -0
- ommlds/minichain/backends/impls/cerebras/protocol.py +143 -0
- ommlds/minichain/backends/impls/cerebras/stream.py +114 -0
- ommlds/minichain/backends/impls/duckduckgo/search.py +5 -1
- ommlds/minichain/backends/impls/dummy/__init__.py +0 -0
- ommlds/minichain/backends/impls/dummy/chat.py +69 -0
- ommlds/minichain/backends/impls/google/chat.py +20 -84
- ommlds/minichain/backends/impls/google/names.py +6 -0
- ommlds/minichain/backends/impls/google/protocol.py +105 -0
- ommlds/minichain/backends/impls/google/search.py +10 -5
- ommlds/minichain/backends/impls/google/stream.py +64 -142
- ommlds/minichain/backends/impls/google/tools.py +2 -2
- ommlds/minichain/backends/impls/groq/__init__.py +0 -0
- ommlds/minichain/backends/impls/groq/chat.py +77 -0
- ommlds/minichain/backends/impls/groq/names.py +48 -0
- ommlds/minichain/backends/impls/groq/protocol.py +143 -0
- ommlds/minichain/backends/impls/groq/stream.py +114 -0
- ommlds/minichain/backends/impls/huggingface/repos.py +1 -5
- ommlds/minichain/backends/impls/llamacpp/chat.py +15 -3
- ommlds/minichain/backends/impls/llamacpp/completion.py +7 -3
- ommlds/minichain/backends/impls/llamacpp/stream.py +38 -19
- ommlds/minichain/backends/impls/mistral.py +9 -2
- ommlds/minichain/backends/impls/mlx/chat.py +100 -23
- ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
- ommlds/minichain/backends/impls/ollama/chat.py +193 -0
- ommlds/minichain/backends/impls/ollama/protocol.py +144 -0
- ommlds/minichain/backends/impls/openai/chat.py +14 -7
- ommlds/minichain/backends/impls/openai/completion.py +9 -2
- ommlds/minichain/backends/impls/openai/embedding.py +9 -2
- ommlds/minichain/backends/impls/openai/format.py +117 -115
- ommlds/minichain/backends/impls/openai/names.py +33 -5
- ommlds/minichain/backends/impls/openai/stream.py +61 -70
- ommlds/minichain/backends/impls/sentencepiece/tokens.py +9 -6
- ommlds/minichain/backends/impls/tavily.py +66 -0
- ommlds/minichain/backends/impls/tinygrad/chat.py +17 -14
- ommlds/minichain/backends/impls/tokenizers/tokens.py +9 -6
- ommlds/minichain/backends/impls/transformers/sentence.py +5 -2
- ommlds/minichain/backends/impls/transformers/tokens.py +9 -6
- ommlds/minichain/backends/impls/transformers/transformers.py +139 -20
- ommlds/minichain/backends/strings/parsing.py +2 -2
- ommlds/minichain/backends/strings/resolving.py +7 -2
- ommlds/minichain/chat/choices/stream/__init__.py +0 -0
- ommlds/minichain/chat/{stream → choices/stream}/adapters.py +7 -7
- ommlds/minichain/chat/choices/stream/joining.py +31 -0
- ommlds/minichain/chat/choices/stream/services.py +45 -0
- ommlds/minichain/chat/choices/stream/types.py +43 -0
- ommlds/minichain/chat/content.py +42 -0
- ommlds/minichain/chat/messages.py +46 -42
- ommlds/minichain/chat/stream/_marshal.py +4 -4
- ommlds/minichain/chat/stream/joining.py +56 -43
- ommlds/minichain/chat/stream/services.py +15 -15
- ommlds/minichain/chat/stream/types.py +17 -24
- ommlds/minichain/chat/templating.py +3 -3
- ommlds/minichain/content/__init__.py +20 -3
- ommlds/minichain/content/_marshal.py +181 -55
- ommlds/minichain/content/code.py +26 -0
- ommlds/minichain/content/composite.py +28 -0
- ommlds/minichain/content/content.py +27 -0
- ommlds/minichain/content/dynamic.py +12 -0
- ommlds/minichain/content/emphasis.py +27 -0
- ommlds/minichain/content/images.py +2 -2
- ommlds/minichain/content/json.py +2 -2
- ommlds/minichain/content/link.py +13 -0
- ommlds/minichain/content/markdown.py +12 -0
- ommlds/minichain/content/metadata.py +10 -0
- ommlds/minichain/content/namespaces.py +8 -0
- ommlds/minichain/content/placeholders.py +10 -9
- ommlds/minichain/content/quote.py +26 -0
- ommlds/minichain/content/raw.py +49 -0
- ommlds/minichain/content/recursive.py +12 -0
- ommlds/minichain/content/resources.py +22 -0
- ommlds/minichain/content/section.py +26 -0
- ommlds/minichain/content/sequence.py +17 -3
- ommlds/minichain/content/standard.py +32 -0
- ommlds/minichain/content/tag.py +28 -0
- ommlds/minichain/content/templates.py +13 -0
- ommlds/minichain/content/text.py +2 -2
- ommlds/minichain/content/transform/__init__.py +0 -0
- ommlds/minichain/content/transform/json.py +55 -0
- ommlds/minichain/content/transform/markdown.py +8 -0
- ommlds/minichain/content/transform/materialize.py +59 -0
- ommlds/minichain/content/transform/metadata.py +16 -0
- ommlds/minichain/content/transform/namespaces.py +20 -0
- ommlds/minichain/content/transform/placeholders.py +60 -0
- ommlds/minichain/content/{prepare.py → transform/prepare.py} +10 -15
- ommlds/minichain/content/transform/recursive.py +54 -0
- ommlds/minichain/content/transform/resources.py +58 -0
- ommlds/minichain/content/transform/standard.py +43 -0
- ommlds/minichain/content/{transforms → transform}/stringify.py +1 -7
- ommlds/minichain/content/transform/strings.py +33 -0
- ommlds/minichain/content/transform/templates.py +25 -0
- ommlds/minichain/content/transform/types.py +18 -0
- ommlds/minichain/content/transform/visitors.py +38 -0
- ommlds/minichain/content/visitors.py +218 -0
- ommlds/minichain/http/__init__.py +0 -0
- ommlds/minichain/http/stream.py +195 -0
- ommlds/minichain/lib/fs/tools/read.py +1 -1
- ommlds/minichain/lib/fs/tools/recursivels/rendering.py +1 -1
- ommlds/minichain/lib/fs/tools/recursivels/running.py +1 -1
- ommlds/minichain/lib/todo/tools/write.py +2 -1
- ommlds/minichain/lib/todo/types.py +1 -1
- ommlds/minichain/llms/types.py +4 -0
- ommlds/minichain/metadata.py +56 -2
- ommlds/minichain/models/configs.py +2 -2
- ommlds/minichain/models/names.py +2 -0
- ommlds/minichain/registries/globals.py +18 -4
- ommlds/minichain/resources.py +49 -3
- ommlds/minichain/search.py +1 -1
- ommlds/minichain/services/README.md +154 -0
- ommlds/minichain/services/__init__.py +6 -2
- ommlds/minichain/services/_marshal.py +46 -10
- ommlds/minichain/services/_origclasses.py +11 -0
- ommlds/minichain/services/_typedvalues.py +8 -3
- ommlds/minichain/services/requests.py +73 -3
- ommlds/minichain/services/responses.py +73 -3
- ommlds/minichain/services/services.py +9 -0
- ommlds/minichain/standard.py +8 -0
- ommlds/minichain/stream/services.py +43 -17
- ommlds/minichain/text/applypatch.py +2 -1
- ommlds/minichain/text/toolparsing/llamacpp/types.py +1 -1
- ommlds/minichain/tokens/specials.py +1 -1
- ommlds/minichain/tools/execution/catalog.py +2 -2
- ommlds/minichain/tools/execution/errorhandling.py +36 -0
- ommlds/minichain/tools/execution/errors.py +2 -2
- ommlds/minichain/tools/execution/executors.py +1 -1
- ommlds/minichain/tools/fns.py +1 -1
- ommlds/minichain/tools/jsonschema.py +2 -2
- ommlds/minichain/tools/reflect.py +11 -7
- ommlds/minichain/tools/types.py +16 -19
- ommlds/minichain/vectors/_marshal.py +1 -1
- ommlds/minichain/vectors/embeddings.py +1 -1
- ommlds/minichain/wrappers/__init__.py +7 -0
- ommlds/minichain/wrappers/firstinwins.py +144 -0
- ommlds/minichain/wrappers/instrument.py +146 -0
- ommlds/minichain/wrappers/retry.py +168 -0
- ommlds/minichain/wrappers/services.py +98 -0
- ommlds/minichain/wrappers/stream.py +57 -0
- ommlds/nanochat/LICENSE +21 -0
- ommlds/nanochat/__init__.py +0 -0
- ommlds/nanochat/rustbpe/LICENSE +21 -0
- ommlds/nanochat/rustbpe/README.md +10 -0
- ommlds/nanochat/tokenizers.py +440 -0
- ommlds/specs/__init__.py +0 -0
- ommlds/specs/mcp/__init__.py +0 -0
- ommlds/specs/mcp/_marshal.py +23 -0
- ommlds/specs/mcp/clients.py +146 -0
- ommlds/specs/mcp/protocol.py +369 -0
- ommlds/tools/git.py +84 -64
- ommlds/tools/ocr.py +1 -1
- ommlds/wiki/analyze.py +2 -2
- ommlds/wiki/models.py +4 -4
- ommlds/wiki/text/mfh.py +9 -9
- ommlds/wiki/utils/xml.py +5 -5
- {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/METADATA +28 -21
- ommlds-0.0.0.dev512.dist-info/RECORD +534 -0
- {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/WHEEL +1 -1
- ommlds/cli/backends/standard.py +0 -20
- ommlds/cli/sessions/chat/backends/catalog.py +0 -56
- ommlds/cli/sessions/chat/backends/inject.py +0 -37
- ommlds/cli/sessions/chat/chat/state/inject.py +0 -40
- ommlds/cli/sessions/chat/chat/user/inject.py +0 -61
- ommlds/cli/sessions/chat/chat/user/interactive.py +0 -29
- ommlds/cli/sessions/chat/chat/user/oneshot.py +0 -25
- ommlds/cli/sessions/chat/chat/user/types.py +0 -15
- ommlds/cli/sessions/chat/driver.py +0 -43
- ommlds/cli/sessions/chat/tools/inject.py +0 -145
- ommlds/minichain/backends/impls/openai/format2.py +0 -210
- ommlds/minichain/content/materialize.py +0 -196
- ommlds/minichain/content/simple.py +0 -47
- ommlds/minichain/content/transforms/base.py +0 -46
- ommlds/minichain/content/transforms/interleave.py +0 -70
- ommlds/minichain/content/transforms/squeeze.py +0 -72
- ommlds/minichain/content/transforms/strings.py +0 -24
- ommlds/minichain/content/types.py +0 -43
- ommlds/minichain/stream/wrap.py +0 -62
- ommlds-0.0.0.dev466.dist-info/RECORD +0 -376
- /ommlds/{cli/sessions/chat/backends → backends/huggingface}/__init__.py +0 -0
- /ommlds/cli/{sessions/chat/chat → content}/__init__.py +0 -0
- /ommlds/cli/{sessions/chat/chat/ai → inputs}/__init__.py +0 -0
- /ommlds/cli/{sessions/chat/chat/state → rendering}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat/user → drivers}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{content → drivers/ai}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat → drivers}/ai/injection.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/events}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{rendering → drivers/phases}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/inject.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/injection.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/manager.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/types.py +0 -0
- /ommlds/cli/sessions/chat/{tools → drivers/state}/__init__.py +0 -0
- /ommlds/{minichain/content/transforms → cli/sessions/chat/drivers/tools}/__init__.py +0 -0
- {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/top_level.txt +0 -0
|
@@ -37,5 +37,5 @@ class ModelRepo(ModelSpecifier):
|
|
|
37
37
|
|
|
38
38
|
_: dc.KW_ONLY
|
|
39
39
|
|
|
40
|
-
tag: str | None = dc.xfield(None, repr_fn=
|
|
41
|
-
path: str | None = dc.xfield(None, repr_fn=
|
|
40
|
+
tag: str | None = dc.xfield(None, repr_fn=lang.opt_repr)
|
|
41
|
+
path: str | None = dc.xfield(None, repr_fn=lang.opt_repr)
|
ommlds/minichain/models/names.py
CHANGED
|
@@ -6,6 +6,7 @@ import typing as ta
|
|
|
6
6
|
|
|
7
7
|
from omlish import cached
|
|
8
8
|
from omlish import dataclasses as dc
|
|
9
|
+
from omlish import lang
|
|
9
10
|
from omlish.algorithm.toposort import mut_toposort
|
|
10
11
|
|
|
11
12
|
|
|
@@ -13,6 +14,7 @@ from omlish.algorithm.toposort import mut_toposort
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@dc.dataclass(frozen=True, kw_only=True)
|
|
17
|
+
@dc.extra_class_params(default_repr_fn=lang.opt_repr)
|
|
16
18
|
class ModelNameCollection:
|
|
17
19
|
default: str | None = None
|
|
18
20
|
|
|
@@ -98,20 +98,34 @@ def register_type(
|
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
@ta.overload
|
|
101
|
-
def
|
|
101
|
+
def get_registry_cls(cls: type[T], name: str) -> type[T]:
|
|
102
102
|
...
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
@ta.overload
|
|
106
|
-
def
|
|
106
|
+
def get_registry_cls(cls: ta.Any, name: str) -> ta.Any:
|
|
107
107
|
...
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
def
|
|
110
|
+
def get_registry_cls(cls, name, *args, **kwargs):
|
|
111
111
|
be_cls = _GlobalRegistry.instance().get_registry_cls(cls, name)
|
|
112
112
|
if isinstance(cls, type):
|
|
113
113
|
be_cls = check.issubclass(be_cls, cls) # noqa
|
|
114
|
-
return be_cls
|
|
114
|
+
return be_cls
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@ta.overload
|
|
118
|
+
def registry_new(cls: type[T], name: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
|
119
|
+
...
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@ta.overload
|
|
123
|
+
def registry_new(cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
|
|
124
|
+
...
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def registry_new(cls, name, *args, **kwargs):
|
|
128
|
+
return get_registry_cls(cls, name)(*args, **kwargs)
|
|
115
129
|
|
|
116
130
|
|
|
117
131
|
#
|
ommlds/minichain/resources.py
CHANGED
|
@@ -31,7 +31,12 @@ class ResourcesRefNotRegisteredError(Exception):
|
|
|
31
31
|
pass
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
@ta.final
|
|
34
35
|
class Resources(lang.Final, lang.NotPicklable):
|
|
36
|
+
"""
|
|
37
|
+
Essentially a reference-tracked AsyncContextManager.
|
|
38
|
+
"""
|
|
39
|
+
|
|
35
40
|
def __init__(
|
|
36
41
|
self,
|
|
37
42
|
*,
|
|
@@ -79,10 +84,14 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
79
84
|
@contextlib.asynccontextmanager
|
|
80
85
|
async def inner():
|
|
81
86
|
init_ref = Resources._InitRef()
|
|
87
|
+
|
|
82
88
|
res = Resources(init_ref=init_ref, **kwargs)
|
|
89
|
+
|
|
83
90
|
await res.init()
|
|
91
|
+
|
|
84
92
|
try:
|
|
85
93
|
yield res
|
|
94
|
+
|
|
86
95
|
finally:
|
|
87
96
|
await res.remove_ref(init_ref)
|
|
88
97
|
|
|
@@ -93,6 +102,7 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
93
102
|
def add_ref(self, ref: ResourcesRef) -> None:
|
|
94
103
|
check.isinstance(ref, ResourcesRef)
|
|
95
104
|
check.state(not self._closed)
|
|
105
|
+
|
|
96
106
|
self._refs.add(ref)
|
|
97
107
|
|
|
98
108
|
def has_ref(self, ref: ResourcesRef) -> bool:
|
|
@@ -100,10 +110,13 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
100
110
|
|
|
101
111
|
async def remove_ref(self, ref: ResourcesRef) -> None:
|
|
102
112
|
check.isinstance(ref, ResourcesRef)
|
|
113
|
+
|
|
103
114
|
try:
|
|
104
115
|
self._refs.remove(ref)
|
|
116
|
+
|
|
105
117
|
except KeyError:
|
|
106
118
|
raise ResourcesRefNotRegisteredError(ref) from None
|
|
119
|
+
|
|
107
120
|
if not self._no_autoclose and not self._refs:
|
|
108
121
|
await self.aclose()
|
|
109
122
|
|
|
@@ -111,10 +124,12 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
111
124
|
|
|
112
125
|
def enter_context(self, cm: ta.ContextManager[T]) -> T:
|
|
113
126
|
check.state(not self._closed)
|
|
127
|
+
|
|
114
128
|
return self._aes.enter_context(cm)
|
|
115
129
|
|
|
116
130
|
async def enter_async_context(self, cm: ta.AsyncContextManager[T]) -> T:
|
|
117
131
|
check.state(not self._closed)
|
|
132
|
+
|
|
118
133
|
return await self._aes.enter_async_context(cm)
|
|
119
134
|
|
|
120
135
|
#
|
|
@@ -145,24 +160,54 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
145
160
|
##
|
|
146
161
|
|
|
147
162
|
|
|
163
|
+
@ta.final
|
|
148
164
|
class ResourceManaged(ResourcesRef, lang.Final, lang.NotPicklable, ta.Generic[T]):
|
|
165
|
+
"""
|
|
166
|
+
A class to 'handoff' a ref to a `Resources`, allowing the `Resources` to temporarily survive being passed from
|
|
167
|
+
instantiation within a callee.
|
|
168
|
+
|
|
169
|
+
This class wraps an arbitrary value, likely an object referencing resources managed by the `Resources`, which is
|
|
170
|
+
accessed by `__aenter__`'ing. However, as the point of this class is handoff of a `Resources`, not necessarily some
|
|
171
|
+
arbitrary value, the value needn't necessarily be related to the `Resources`, or may even be `None`.
|
|
172
|
+
|
|
173
|
+
The ref to the `Resources` is allocated in the ctor, so the contract is that an instance of this must be immediately
|
|
174
|
+
`__aenter__`'d before doing anything else with the return value of the call. Failure to do so leaks the `Resources`.
|
|
175
|
+
"""
|
|
176
|
+
|
|
149
177
|
def __init__(self, v: T, resources: Resources) -> None:
|
|
150
178
|
super().__init__()
|
|
151
179
|
|
|
152
|
-
self.
|
|
180
|
+
self.__v = v
|
|
153
181
|
self.__resources = resources
|
|
154
182
|
|
|
155
183
|
resources.add_ref(self)
|
|
156
184
|
|
|
185
|
+
__state: ta.Literal['new', 'entered', 'exited'] = 'new'
|
|
186
|
+
|
|
157
187
|
def __repr__(self) -> str:
|
|
158
|
-
return f'{self.__class__.__name__}<{self.
|
|
188
|
+
return f'{self.__class__.__name__}<{self.__v!r}, {self.__state}>'
|
|
159
189
|
|
|
160
190
|
async def __aenter__(self) -> T:
|
|
161
|
-
|
|
191
|
+
check.state(self.__state == 'new')
|
|
192
|
+
self.__state = 'entered'
|
|
193
|
+
|
|
194
|
+
return self.__v
|
|
162
195
|
|
|
163
196
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
197
|
+
check.state(self.__state == 'entered')
|
|
198
|
+
self.__state = 'exited'
|
|
199
|
+
|
|
164
200
|
await self.__resources.remove_ref(self)
|
|
165
201
|
|
|
202
|
+
def __del__(self) -> None:
|
|
203
|
+
if self.__state != 'exited':
|
|
204
|
+
log.error(
|
|
205
|
+
f'{__package__}.{self.__class__.__name__}.__del__: ' # noqa
|
|
206
|
+
f'%r deleted without being entered and exited! '
|
|
207
|
+
f'resources: %s',
|
|
208
|
+
repr(self),
|
|
209
|
+
repr(self.__resources),
|
|
210
|
+
)
|
|
166
211
|
|
|
167
212
|
##
|
|
168
213
|
|
|
@@ -178,6 +223,7 @@ class UseResources(tv.UniqueScalarTypedValue[Resources], ResourcesOption, lang.F
|
|
|
178
223
|
if (ur := tv.as_collection(options).get(UseResources)) is not None:
|
|
179
224
|
async with ResourceManaged(ur.v, ur.v) as rs:
|
|
180
225
|
yield rs
|
|
226
|
+
|
|
181
227
|
else:
|
|
182
228
|
async with Resources.new() as rs:
|
|
183
229
|
yield rs
|
ommlds/minichain/search.py
CHANGED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
The core service abstraction. In general, Services are intended to encapsulate non-trivial, resourceful, effectful
|
|
2
|
+
operations, which are likely to have various implementations, each having their own specific capabilities in addition
|
|
3
|
+
to their common interface, and where wrapping, adapting, and transforming them in a uniform manner is desirable.
|
|
4
|
+
|
|
5
|
+
For example:
|
|
6
|
+
- A ChatService is passed a Request with a Chat value and returns a Response with an AiChat value.
|
|
7
|
+
- A ChatChoicesService is passed a Request with a Chat and returns a Response with a list of AiChoices.
|
|
8
|
+
- A ChatChoicesServiceChatService is a simple adapter taking a ChatChoicesService which it will invoke with its given
|
|
9
|
+
Request, expect a single AiChoice value in that Response, and return that single AiChat as its Response - thus acting
|
|
10
|
+
as a ChatService.
|
|
11
|
+
- Thus, all chat backends that return choices can be adapted to code expecting a single chat as output.
|
|
12
|
+
- A ChatStreamService is passed a Request with a Chat value and returns a Response with a value from which AiDeltas
|
|
13
|
+
may be streamed.
|
|
14
|
+
- A ChatChoicesStreamService is passed a Request with a Chat value and returns a Response with a value from which
|
|
15
|
+
AiChoicesDeltas may be streamed.
|
|
16
|
+
- A ChatChoicesStreamServiceChatChoicesService is an adapter taking a ChatChoicesStreamService and aggregating the
|
|
17
|
+
AiChoicesDeltas into joined, non-delta AiChoices.
|
|
18
|
+
- This may then be wrapped in a ChatChoicesServiceChatService to act as a ChatService.
|
|
19
|
+
- In practice however there are usually dedicated streaming and non-streaming implementations if possible as
|
|
20
|
+
non-streaming will usually have less overhead.
|
|
21
|
+
- An OpenaiChatChoicesService can act as a ChatChoicesService, and will accept all generic ChatOptions, in addition to
|
|
22
|
+
any OpenaiChatOptions inapplicable to any other backend. It may also produce all generic ChatOutputs, in addition to
|
|
23
|
+
OpenaiChatOutputs that will not be produced by other backends.
|
|
24
|
+
- Beyond chat, a VectorSearchService is passed a Request with a VectorSearch value and returns a Response with a
|
|
25
|
+
VectorHits value.
|
|
26
|
+
- A RetryService wraps any other Service and will attempt to re-invoke it on failure.
|
|
27
|
+
- A FirstInWinsService wraps any number of other Services and will return the first non-error Response it receives.
|
|
28
|
+
|
|
29
|
+
The service abstraction consists of 3 interrelated generic types:
|
|
30
|
+
- Request, an immutable final generic class containing a single value and any number of options.
|
|
31
|
+
- Response, an immutable final generic class containing a single value and any number of outputs.
|
|
32
|
+
- Service, a generic protocol consisting of a single async method `invoke`, taking a request and returning a response.
|
|
33
|
+
|
|
34
|
+
There are 2 related abstract base classes in the parent package:
|
|
35
|
+
- Option, a non-generic abstract class representing a service option.
|
|
36
|
+
- Output, a non-generic abstract class representing a service output.
|
|
37
|
+
|
|
38
|
+
The purpose of this arrangement is to provide the following:
|
|
39
|
+
- There is only one method - `Service.invoke` - to deal with.
|
|
40
|
+
- There is no base `Service` class - service types are distinguished only by the requests they accept and responses
|
|
41
|
+
they return.
|
|
42
|
+
- It facilitates a clear, introspectable, generally type-safe means for handling 'less-specific' and 'more-specific'
|
|
43
|
+
service types.
|
|
44
|
+
- It facilitates generic wrapper and transformation machinery.
|
|
45
|
+
|
|
46
|
+
The variance of the type parameters of the 3 classes is central:
|
|
47
|
+
- `Request[V_co, OptionT_co]`
|
|
48
|
+
- `Response[V_co, OutputT_contra]`
|
|
49
|
+
- `Service[RequestT_contra, ResponseT_co]`
|
|
50
|
+
|
|
51
|
+
And to understand this, it's important to understand how Option and Output subtypes are intended to be arranged:
|
|
52
|
+
- These types are *not* intended to form a deep type hierarchy:
|
|
53
|
+
- A RemoteChatOption is *not* intended to inherit from a ChatOption: a ChatOption (be it a base class or union alias)
|
|
54
|
+
represents an option that *any* ChatService can accept, whereas a RemoteChatOption represents an option that *only*
|
|
55
|
+
applies to a RemoteChatService.
|
|
56
|
+
- If RemoteChatOption inherited from a base ChatOption, then it would have to apply to *all* ChatService
|
|
57
|
+
implementations.
|
|
58
|
+
- For example: were ApiKey to inherit from ChatOption, then it would have to apply to all ChatServices, including
|
|
59
|
+
LocalChatService, which has no concept of an api key.
|
|
60
|
+
- Similarly, a RemoteChatOutput is *not* intended to inherit from a ChatOutput: a ChatOutput represents an output that
|
|
61
|
+
*any* ChatService can produce, whereas a RemoteChatOutput represents an output that *only* applies to a
|
|
62
|
+
RemoteChatService.
|
|
63
|
+
- These 2 types are intended to form flat, disjoint, unrelated families of subtypes, and Request and Response are
|
|
64
|
+
intended to be parameterized by the unions of all such families they may contain.
|
|
65
|
+
- Because of this, one's visual intuition regarding types and subtypes may be reversed: `int` is effectively a subtype
|
|
66
|
+
of `int | str` despite `int` being a visually shorter, less complex type.
|
|
67
|
+
- `int` is a *MORE SPECIFIC* / *STRICT SUBSET* subtype of `int | str`, the *LESS SPECIFIC* / *STRICT SUPERSET*
|
|
68
|
+
supertype.
|
|
69
|
+
|
|
70
|
+
Regarding type variance:
|
|
71
|
+
- Service has the classic setup of contravariant input and covariant output:
|
|
72
|
+
- A RemoteChatService *is a* ChatService.
|
|
73
|
+
- A RemoteChatService may accept less specific requests than a ChatService.
|
|
74
|
+
- A RemoteChatService may return more specific responses than a ChatService.
|
|
75
|
+
- Request is covariant on its options:
|
|
76
|
+
- Recall, a RemoteChatOption *is not a* ChatOption.
|
|
77
|
+
- A ChatRequest *is a* RemoteChatRequest as it will not contain options RemoteChatService cannot accept.
|
|
78
|
+
- Response is contravariant on its outputs:
|
|
79
|
+
- Recall, a RemoteChatOutput *is not a* ChatOutput.
|
|
80
|
+
- A RemoteChatResponse *is a* ChatResponse even though it may contain additional output variants not produced by
|
|
81
|
+
every ChatService.
|
|
82
|
+
- Code that calls a ChatService and is given a ChatResponse must be prepared to handle (usually by simply ignoring)
|
|
83
|
+
outputs not necessarily produced by a base ChatService.
|
|
84
|
+
|
|
85
|
+
Finally, in addition to a value and either options or outputs, a Request and Response each also contain a collection of
|
|
86
|
+
metadata. Very much unlike the Options and Outputs, the elements of these collections are simply of the types
|
|
87
|
+
`RequestMetadata | CommonMetadata` and `ResponseMetadata | CommonMetadata`, and are not otherwise parameterized. These
|
|
88
|
+
are intended for looser inputs and outputs: a generic unique id, timestamps, metrics, etc., and in general should
|
|
89
|
+
neither affect the behavior of services nor be depended upon by callers.
|
|
90
|
+
|
|
91
|
+
Below is a representative illustration of these types and their relationships. Note how:
|
|
92
|
+
- There is no subclassing of Request, Response, or Service - just type aliasing.
|
|
93
|
+
- There is no deep, shared subclassing of Option or Output.
|
|
94
|
+
- The type args passed to Request and Response are unions of all the Option and Output subtypes they may contain.
|
|
95
|
+
- These unions are kept in pluralized type aliases for convenience.
|
|
96
|
+
- There is no base ChatOption or ChatOutput class - were there, it would not be included in the base classes of any
|
|
97
|
+
local or remote only option or output.
|
|
98
|
+
- The local and remote sections take different but equivalent approaches:
|
|
99
|
+
- There are no base LocalChatOption or LocalChatOutput classes, but there *are* base RemoteChatOption and
|
|
100
|
+
RemoteChatOutput classes.
|
|
101
|
+
- Without any common base classes (besides the lowest level Output and Option classes), the local section treats them
|
|
102
|
+
as each distinct and bespoke, and the pluralized LocalChatOptions and LocalChatOutputs type aliases aggregate them
|
|
103
|
+
by explicitly listing them.
|
|
104
|
+
- With the common RemoteChatOption and RemoteChatOutput base classes, the remote section treats them as a related
|
|
105
|
+
family that any 'RemoteChat'-like service should accept and produce.
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# Common chat
|
|
109
|
+
|
|
110
|
+
class MaxTokens(Option, tv.UniqueScalarTypedValue[int]): pass
|
|
111
|
+
class Temperature(Option, tv.UniqueScalarTypedValue[float]): pass
|
|
112
|
+
|
|
113
|
+
ChatOptions: ta.TypeAlias = MaxTokens | Temperature
|
|
114
|
+
ChatRequest: ta.TypeAlias = Request[Chat, ChatOptions]
|
|
115
|
+
|
|
116
|
+
class TokenUsage(Output, tv.UniqueScalarTypedValue[int]): pass
|
|
117
|
+
class ElapsedTime(Output, tv.UniqueScalarTypedValue[float]): pass
|
|
118
|
+
|
|
119
|
+
ChatOutputs: ta.TypeAlias = TokenUsage | ElapsedTime
|
|
120
|
+
ChatResponse: ta.TypeAlias = Response[Message, ChatOutputs]
|
|
121
|
+
|
|
122
|
+
ChatService: ta.TypeAlias = Service[ChatRequest, ChatResponse]
|
|
123
|
+
|
|
124
|
+
# Local chat
|
|
125
|
+
|
|
126
|
+
class ModelPath(Option, tv.ScalarTypedValue[str]): pass
|
|
127
|
+
|
|
128
|
+
LocalChatOptions: ta.TypeAlias = ChatOptions | ModelPath
|
|
129
|
+
LocalChatRequest: ta.TypeAlias = Request[Chat, LocalChatOptions]
|
|
130
|
+
|
|
131
|
+
class LogPath(Output, tv.ScalarTypedValue[str]): pass
|
|
132
|
+
|
|
133
|
+
LocalChatOutputs: ta.TypeAlias = ChatOutputs | LogPath
|
|
134
|
+
LocalChatResponse: ta.TypeAlias = Response[Message, LocalChatOutputs]
|
|
135
|
+
|
|
136
|
+
LocalChatService: ta.TypeAlias = Service[LocalChatRequest, LocalChatResponse]
|
|
137
|
+
|
|
138
|
+
# Remote chat
|
|
139
|
+
|
|
140
|
+
class RemoteChatOption(Option, lang.Abstract): pass
|
|
141
|
+
class ApiKey(RemoteChatOption, tv.ScalarTypedValue[str]): pass
|
|
142
|
+
|
|
143
|
+
RemoteChatOptions: ta.TypeAlias = ChatOptions | RemoteChatOption
|
|
144
|
+
RemoteChatRequest: ta.TypeAlias = Request[Chat, RemoteChatOptions]
|
|
145
|
+
|
|
146
|
+
class RemoteChatOutput(Output, lang.Abstract): pass
|
|
147
|
+
class BilledCostInUsd(RemoteChatOutput, tv.UniqueScalarTypedValue[float]): pass
|
|
148
|
+
|
|
149
|
+
RemoteChatOutputs: ta.TypeAlias = ChatOutputs | RemoteChatOutput
|
|
150
|
+
RemoteChatResponse: ta.TypeAlias = Response[Message, RemoteChatOutputs]
|
|
151
|
+
|
|
152
|
+
RemoteChatService: ta.TypeAlias = Service[RemoteChatRequest, RemoteChatResponse]
|
|
153
|
+
```
|
|
154
|
+
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
# ruff: noqa: I001
|
|
2
|
-
|
|
3
|
-
|
|
4
2
|
from .facades import ( # noqa
|
|
5
3
|
ServiceFacade,
|
|
6
4
|
|
|
@@ -8,10 +6,16 @@ from .facades import ( # noqa
|
|
|
8
6
|
)
|
|
9
7
|
|
|
10
8
|
from .requests import ( # noqa
|
|
9
|
+
RequestMetadata,
|
|
10
|
+
RequestMetadatas,
|
|
11
|
+
|
|
11
12
|
Request,
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
from .responses import ( # noqa
|
|
16
|
+
ResponseMetadata,
|
|
17
|
+
ResponseMetadatas,
|
|
18
|
+
|
|
15
19
|
Response,
|
|
16
20
|
)
|
|
17
21
|
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FIXME:
|
|
3
|
+
- everything lol
|
|
4
|
+
- can this just do what metadata does
|
|
5
|
+
"""
|
|
1
6
|
import typing as ta
|
|
2
7
|
|
|
3
8
|
from omlish import check
|
|
@@ -22,10 +27,21 @@ def _is_rr_rty(rty: rfl.Type) -> bool:
|
|
|
22
27
|
)
|
|
23
28
|
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
class _RrFlds(ta.NamedTuple):
|
|
31
|
+
v: dc.Field
|
|
32
|
+
tv: dc.Field
|
|
33
|
+
md: dc.Field
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _get_rr_flds(rty: rfl.Type) -> _RrFlds:
|
|
26
37
|
flds = col.make_map_by(lambda f: f.name, dc.fields(check.not_none(rfl.get_concrete_type(rty))), strict=True)
|
|
27
|
-
flds.pop('v')
|
|
28
|
-
|
|
38
|
+
v_fld = flds.pop('v')
|
|
39
|
+
md_fld = flds.pop('_metadata')
|
|
40
|
+
return _RrFlds(
|
|
41
|
+
v=v_fld,
|
|
42
|
+
tv=check.single(flds.values()),
|
|
43
|
+
md=md_fld,
|
|
44
|
+
)
|
|
29
45
|
|
|
30
46
|
|
|
31
47
|
##
|
|
@@ -34,7 +50,7 @@ def _get_tv_fld(rty: rfl.Type) -> dc.Field:
|
|
|
34
50
|
@dc.dataclass(frozen=True)
|
|
35
51
|
class _RequestResponseMarshaler(msh.Marshaler):
|
|
36
52
|
rty: rfl.Type
|
|
37
|
-
|
|
53
|
+
rr_flds: _RrFlds
|
|
38
54
|
v_m: msh.Marshaler | None
|
|
39
55
|
|
|
40
56
|
def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
|
|
@@ -51,9 +67,14 @@ class _RequestResponseMarshaler(msh.Marshaler):
|
|
|
51
67
|
else:
|
|
52
68
|
v_v = self.v_m.marshal(ctx, o.v)
|
|
53
69
|
|
|
70
|
+
md_fmd = self.rr_flds.md.metadata[msh.FieldOptions]
|
|
71
|
+
md_m = md_fmd.marshaler_factory.make_marshaler(ctx.marshal_factory_context, self.rr_flds.md.type)() # FIXME
|
|
72
|
+
md_v = md_m.marshal(ctx, o._metadata) # noqa
|
|
73
|
+
|
|
54
74
|
return {
|
|
55
75
|
'v': v_v,
|
|
56
|
-
**({lang.strip_prefix(self.
|
|
76
|
+
**({lang.strip_prefix(self.rr_flds.tv.name, '_'): tv_v} if tv_v else {}),
|
|
77
|
+
**({'metadata': md_v} if md_v else {}),
|
|
57
78
|
}
|
|
58
79
|
|
|
59
80
|
|
|
@@ -76,7 +97,7 @@ class _RequestResponseMarshalerFactory(msh.MarshalerFactory):
|
|
|
76
97
|
v_m = ctx.make_marshaler(v_rty)
|
|
77
98
|
return _RequestResponseMarshaler(
|
|
78
99
|
rty,
|
|
79
|
-
|
|
100
|
+
_get_rr_flds(rty),
|
|
80
101
|
v_m,
|
|
81
102
|
)
|
|
82
103
|
|
|
@@ -89,9 +110,10 @@ class _RequestResponseMarshalerFactory(msh.MarshalerFactory):
|
|
|
89
110
|
@dc.dataclass(frozen=True)
|
|
90
111
|
class _RequestResponseUnmarshaler(msh.Unmarshaler):
|
|
91
112
|
rty: rfl.Type
|
|
92
|
-
|
|
113
|
+
rr_flds: _RrFlds
|
|
93
114
|
v_u: msh.Unmarshaler
|
|
94
115
|
tv_u: msh.Unmarshaler
|
|
116
|
+
md_u: msh.Unmarshaler
|
|
95
117
|
|
|
96
118
|
def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
|
|
97
119
|
dct = dict(check.isinstance(v, ta.Mapping))
|
|
@@ -99,9 +121,14 @@ class _RequestResponseUnmarshaler(msh.Unmarshaler):
|
|
|
99
121
|
v_v = dct.pop('v')
|
|
100
122
|
v = self.v_u.unmarshal(ctx, v_v)
|
|
101
123
|
|
|
124
|
+
if md_v := dct.pop('metadata', None):
|
|
125
|
+
md = self.md_u.unmarshal(ctx, md_v)
|
|
126
|
+
else:
|
|
127
|
+
md = []
|
|
128
|
+
|
|
102
129
|
tvs: ta.Any
|
|
103
130
|
if dct:
|
|
104
|
-
tv_vs = dct.pop(lang.strip_prefix(self.
|
|
131
|
+
tv_vs = dct.pop(lang.strip_prefix(self.rr_flds.tv.name, '_'))
|
|
105
132
|
tvs = self.tv_u.unmarshal(ctx, tv_vs)
|
|
106
133
|
else:
|
|
107
134
|
tvs = []
|
|
@@ -109,7 +136,7 @@ class _RequestResponseUnmarshaler(msh.Unmarshaler):
|
|
|
109
136
|
check.empty(dct)
|
|
110
137
|
|
|
111
138
|
cty = rfl.get_concrete_type(self.rty)
|
|
112
|
-
return cty(v, tvs) # type: ignore
|
|
139
|
+
return cty(v, tvs, _metadata=md) # type: ignore
|
|
113
140
|
|
|
114
141
|
|
|
115
142
|
class _RequestResponseUnmarshalerFactory(msh.UnmarshalerFactory):
|
|
@@ -123,15 +150,24 @@ class _RequestResponseUnmarshalerFactory(msh.UnmarshalerFactory):
|
|
|
123
150
|
else:
|
|
124
151
|
# FIXME: ...
|
|
125
152
|
raise TypeError(rty)
|
|
153
|
+
|
|
154
|
+
rr_flds = _get_rr_flds(rty)
|
|
155
|
+
|
|
126
156
|
tv_types_set = check.isinstance(tv_rty, rfl.Union).args
|
|
127
157
|
tv_ta = tv.TypedValues[ta.Union[*tv_types_set]] # type: ignore
|
|
128
158
|
tv_u = ctx.make_unmarshaler(tv_ta)
|
|
159
|
+
|
|
129
160
|
v_u = ctx.make_unmarshaler(v_rty)
|
|
161
|
+
|
|
162
|
+
md_fmd = rr_flds.md.metadata[msh.FieldOptions]
|
|
163
|
+
md_u = md_fmd.unmarshaler_factory.make_unmarshaler(ctx, rr_flds.md.type)() # FIXME
|
|
164
|
+
|
|
130
165
|
return _RequestResponseUnmarshaler(
|
|
131
166
|
rty,
|
|
132
|
-
|
|
167
|
+
_get_rr_flds(rty),
|
|
133
168
|
v_u,
|
|
134
169
|
tv_u,
|
|
170
|
+
md_u,
|
|
135
171
|
)
|
|
136
172
|
|
|
137
173
|
return inner
|
|
@@ -43,3 +43,14 @@ class _OrigClassCapture:
|
|
|
43
43
|
"""Enforces that __orig_class__ has only been set once."""
|
|
44
44
|
|
|
45
45
|
return check.single(object.__getattribute__(self, '__captured_orig_classes__'))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def confer_orig_class(src, dst):
|
|
49
|
+
if src is not dst:
|
|
50
|
+
try:
|
|
51
|
+
oc = src.__orig_class__
|
|
52
|
+
except AttributeError:
|
|
53
|
+
pass
|
|
54
|
+
else:
|
|
55
|
+
dst.__orig_class__ = oc
|
|
56
|
+
return dst
|
|
@@ -45,14 +45,19 @@ class _TypedValues(
|
|
|
45
45
|
lang.Abstract,
|
|
46
46
|
ta.Generic[TypedValueT],
|
|
47
47
|
):
|
|
48
|
-
|
|
48
|
+
"""
|
|
49
|
+
The reason this is so complicated compared to any other TypedValues field (like metadata) is that the real set of
|
|
50
|
+
TypedValue types it accepts is known only via __orig_class__.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
__typed_values_base__: ta.ClassVar[type[tv.TypedValue]]
|
|
49
54
|
|
|
50
55
|
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
51
56
|
super().__init_subclass__(**kwargs)
|
|
52
57
|
|
|
53
58
|
tvt = _get_typed_values_type_arg(cls)
|
|
54
59
|
tvct = rfl.get_concrete_type(tvt, use_type_var_bound=True)
|
|
55
|
-
cls.
|
|
60
|
+
cls.__typed_values_base__ = check.issubclass(check.isinstance(tvct, type), tv.TypedValue)
|
|
56
61
|
|
|
57
62
|
#
|
|
58
63
|
|
|
@@ -77,7 +82,7 @@ class _TypedValues(
|
|
|
77
82
|
|
|
78
83
|
tv_types_set = frozenset(tv.reflect_typed_values_impls(tvt))
|
|
79
84
|
tv_types = tuple(sorted(
|
|
80
|
-
[check.issubclass(c, self.
|
|
85
|
+
[check.issubclass(c, self.__typed_values_base__) for c in tv_types_set],
|
|
81
86
|
key=lambda c: c.__qualname__,
|
|
82
87
|
))
|
|
83
88
|
|
|
@@ -6,8 +6,12 @@ from omlish import lang
|
|
|
6
6
|
from omlish import typedvalues as tv
|
|
7
7
|
|
|
8
8
|
from .._typedvalues import _tv_field_metadata
|
|
9
|
+
from ..metadata import CommonMetadata
|
|
10
|
+
from ..metadata import Metadata
|
|
11
|
+
from ..metadata import MetadataContainerDataclass
|
|
9
12
|
from ..types import Option
|
|
10
13
|
from ..types import OptionT_co
|
|
14
|
+
from ._origclasses import confer_orig_class
|
|
11
15
|
from ._typedvalues import _TypedValues
|
|
12
16
|
|
|
13
17
|
|
|
@@ -19,6 +23,17 @@ OptionU = ta.TypeVar('OptionU', bound=Option)
|
|
|
19
23
|
##
|
|
20
24
|
|
|
21
25
|
|
|
26
|
+
class RequestMetadata(Metadata, lang.Abstract):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
RequestMetadatas: ta.TypeAlias = RequestMetadata | CommonMetadata
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@ta.final
|
|
22
37
|
@dc.dataclass(frozen=True)
|
|
23
38
|
@dc.extra_class_params(
|
|
24
39
|
allow_dynamic_dunder_attrs=True,
|
|
@@ -26,11 +41,32 @@ OptionU = ta.TypeVar('OptionU', bound=Option)
|
|
|
26
41
|
)
|
|
27
42
|
class Request( # type: ignore[type-var] # FIXME: _TypedValues param is invariant
|
|
28
43
|
_TypedValues[OptionT_co],
|
|
44
|
+
MetadataContainerDataclass[RequestMetadatas],
|
|
29
45
|
lang.Final,
|
|
30
46
|
ta.Generic[V_co, OptionT_co],
|
|
31
47
|
):
|
|
48
|
+
"""
|
|
49
|
+
Universal service request, comprised of:
|
|
50
|
+
- a value of type `V_co`
|
|
51
|
+
- a sequence of options of type `OptionT_co`
|
|
52
|
+
- metadata of type `RequestMetadatas`
|
|
53
|
+
|
|
54
|
+
Refer to the package README.md for an explanation of its type var variance.
|
|
55
|
+
|
|
56
|
+
This class is final, but each instance's `__orig_class__` (if present) is significant. It is encouraged to construct
|
|
57
|
+
these through a pre-parameterized type alias, and the provided `with_` methods should be used rather than
|
|
58
|
+
`dc.replace` (as they will propagate `__orig_class__`).
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
#
|
|
62
|
+
|
|
32
63
|
v: V_co # type: ignore[misc] # FIXME: Cannot use a covariant type variable as a parameter
|
|
33
64
|
|
|
65
|
+
def with_v(self, v: V_co) -> ta.Self: # type: ignore[misc]
|
|
66
|
+
return confer_orig_class(self, dc.replace(self, v=v))
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
|
|
34
70
|
_options: ta.Sequence[OptionT_co] = dc.field(
|
|
35
71
|
default=(),
|
|
36
72
|
metadata=_tv_field_metadata(
|
|
@@ -43,13 +79,47 @@ class Request( # type: ignore[type-var] # FIXME: _TypedValues param is invaria
|
|
|
43
79
|
def options(self) -> tv.TypedValues[OptionT_co]:
|
|
44
80
|
return check.isinstance(self._options, tv.TypedValues)
|
|
45
81
|
|
|
46
|
-
def with_options(self, *options: OptionU, override: bool = False) -> 'Request[V_co, OptionT_co | OptionU]':
|
|
47
|
-
return dc.replace(self, _options=self.options.update(*options, override=override))
|
|
48
|
-
|
|
49
82
|
@property
|
|
50
83
|
def _typed_values(self) -> tv.TypedValues[OptionT_co]:
|
|
51
84
|
return check.isinstance(self._options, tv.TypedValues)
|
|
52
85
|
|
|
86
|
+
def with_options(
|
|
87
|
+
self,
|
|
88
|
+
*add: OptionU,
|
|
89
|
+
discard: ta.Iterable[type] | None = None,
|
|
90
|
+
override: bool = False,
|
|
91
|
+
) -> 'Request[V_co, OptionT_co | OptionU]':
|
|
92
|
+
new = (old := self.options).update(
|
|
93
|
+
*add,
|
|
94
|
+
discard=discard,
|
|
95
|
+
override=override,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if new is old:
|
|
99
|
+
return self
|
|
100
|
+
|
|
101
|
+
return confer_orig_class(self, dc.replace(self, _options=new))
|
|
102
|
+
|
|
103
|
+
#
|
|
104
|
+
|
|
105
|
+
_metadata: ta.Sequence[RequestMetadatas] = dc.field(
|
|
106
|
+
default=(),
|
|
107
|
+
kw_only=True,
|
|
108
|
+
repr=False,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
MetadataContainerDataclass._configure_metadata_field(_metadata, RequestMetadatas) # noqa
|
|
112
|
+
|
|
113
|
+
def with_metadata(
|
|
114
|
+
self,
|
|
115
|
+
*add: RequestMetadatas,
|
|
116
|
+
discard: ta.Iterable[type] | None = None,
|
|
117
|
+
override: bool = False,
|
|
118
|
+
) -> ta.Self:
|
|
119
|
+
return confer_orig_class(self, super().with_metadata(*add, discard=discard, override=override))
|
|
120
|
+
|
|
121
|
+
#
|
|
122
|
+
|
|
53
123
|
def validate(self) -> ta.Self:
|
|
54
124
|
self._check_typed_values()
|
|
55
125
|
return self
|