ommlds 0.0.0.dev426__py3-none-any.whl → 0.0.0.dev485__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 +336 -39
- ommlds/__about__.py +16 -10
- 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/_marshal.py +2 -2
- ommlds/backends/anthropic/protocol/sse/_marshal.py +1 -1
- ommlds/backends/anthropic/protocol/sse/assemble.py +23 -7
- ommlds/backends/anthropic/protocol/sse/events.py +13 -0
- ommlds/backends/anthropic/protocol/types.py +40 -8
- ommlds/backends/google/protocol/__init__.py +16 -0
- ommlds/backends/google/protocol/_dataclasses.py +5997 -0
- ommlds/backends/google/protocol/_marshal.py +16 -0
- ommlds/backends/google/protocol/types.py +626 -0
- ommlds/backends/groq/__init__.py +7 -0
- ommlds/backends/groq/_dataclasses.py +3901 -0
- ommlds/backends/groq/_marshal.py +23 -0
- ommlds/backends/groq/protocol.py +249 -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 +19 -17
- ommlds/backends/mlx/limits.py +10 -6
- ommlds/backends/mlx/loading.py +65 -5
- ommlds/backends/ollama/__init__.py +7 -0
- ommlds/backends/ollama/_dataclasses.py +3458 -0
- ommlds/backends/ollama/protocol.py +170 -0
- ommlds/backends/openai/protocol/__init__.py +24 -29
- ommlds/backends/openai/protocol/_common.py +18 -0
- ommlds/backends/openai/protocol/_dataclasses.py +7708 -0
- ommlds/backends/openai/protocol/_marshal.py +27 -0
- ommlds/backends/openai/protocol/chatcompletion/chunk.py +58 -31
- ommlds/backends/openai/protocol/chatcompletion/contentpart.py +49 -44
- ommlds/backends/openai/protocol/chatcompletion/message.py +55 -43
- ommlds/backends/openai/protocol/chatcompletion/request.py +114 -66
- ommlds/backends/openai/protocol/chatcompletion/response.py +71 -45
- ommlds/backends/openai/protocol/chatcompletion/responseformat.py +27 -20
- ommlds/backends/openai/protocol/chatcompletion/tokenlogprob.py +16 -7
- ommlds/backends/openai/protocol/completionusage.py +24 -15
- ommlds/backends/tavily/__init__.py +7 -0
- ommlds/backends/tavily/_dataclasses.py +1734 -0
- ommlds/backends/tavily/protocol.py +301 -0
- ommlds/backends/tinygrad/models/llama3/__init__.py +22 -14
- 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 +2562 -0
- ommlds/cli/asyncs.py +30 -0
- ommlds/cli/backends/catalog.py +93 -0
- ommlds/cli/backends/configs.py +9 -0
- ommlds/cli/backends/inject.py +31 -36
- ommlds/cli/backends/injection.py +16 -0
- ommlds/cli/backends/types.py +46 -0
- ommlds/cli/content/messages.py +34 -0
- ommlds/cli/content/strings.py +42 -0
- ommlds/cli/inject.py +17 -32
- ommlds/cli/inputs/__init__.py +0 -0
- ommlds/cli/inputs/asyncs.py +32 -0
- ommlds/cli/inputs/sync.py +75 -0
- ommlds/cli/main.py +270 -110
- ommlds/cli/rendering/__init__.py +0 -0
- ommlds/cli/rendering/configs.py +9 -0
- ommlds/cli/rendering/inject.py +31 -0
- ommlds/cli/rendering/markdown.py +52 -0
- ommlds/cli/rendering/raw.py +73 -0
- ommlds/cli/rendering/types.py +21 -0
- ommlds/cli/secrets.py +21 -0
- ommlds/cli/sessions/base.py +1 -1
- ommlds/cli/sessions/chat/chat/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/ai/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/ai/configs.py +11 -0
- ommlds/cli/sessions/chat/chat/ai/inject.py +74 -0
- ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
- ommlds/cli/sessions/chat/chat/ai/rendering.py +70 -0
- ommlds/cli/sessions/chat/chat/ai/services.py +79 -0
- ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
- ommlds/cli/sessions/chat/chat/ai/types.py +28 -0
- ommlds/cli/sessions/chat/chat/state/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/state/configs.py +11 -0
- ommlds/cli/sessions/chat/chat/state/inject.py +36 -0
- ommlds/cli/sessions/chat/chat/state/inmemory.py +33 -0
- ommlds/cli/sessions/chat/chat/state/storage.py +52 -0
- ommlds/cli/sessions/chat/chat/state/types.py +38 -0
- ommlds/cli/sessions/chat/chat/user/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/user/configs.py +17 -0
- ommlds/cli/sessions/chat/chat/user/inject.py +62 -0
- ommlds/cli/sessions/chat/chat/user/interactive.py +31 -0
- ommlds/cli/sessions/chat/chat/user/oneshot.py +25 -0
- ommlds/cli/sessions/chat/chat/user/types.py +15 -0
- ommlds/cli/sessions/chat/configs.py +27 -0
- ommlds/cli/sessions/chat/driver.py +43 -0
- ommlds/cli/sessions/chat/inject.py +33 -65
- ommlds/cli/sessions/chat/phases/__init__.py +0 -0
- ommlds/cli/sessions/chat/phases/inject.py +27 -0
- ommlds/cli/sessions/chat/phases/injection.py +14 -0
- ommlds/cli/sessions/chat/phases/manager.py +29 -0
- ommlds/cli/sessions/chat/phases/types.py +29 -0
- ommlds/cli/sessions/chat/session.py +27 -0
- ommlds/cli/sessions/chat/tools/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/configs.py +22 -0
- ommlds/cli/sessions/chat/tools/confirmation.py +46 -0
- ommlds/cli/sessions/chat/tools/execution.py +66 -0
- ommlds/cli/sessions/chat/tools/fs/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/fs/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/fs/inject.py +35 -0
- ommlds/cli/sessions/chat/tools/inject.py +88 -0
- ommlds/cli/sessions/chat/tools/injection.py +44 -0
- ommlds/cli/sessions/chat/tools/rendering.py +58 -0
- ommlds/cli/sessions/chat/tools/todo/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/todo/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/todo/inject.py +31 -0
- ommlds/cli/sessions/chat/tools/weather/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/weather/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/weather/inject.py +22 -0
- ommlds/cli/{tools/weather.py → sessions/chat/tools/weather/tools.py} +1 -1
- ommlds/cli/sessions/completion/configs.py +21 -0
- ommlds/cli/sessions/completion/inject.py +42 -0
- ommlds/cli/sessions/completion/session.py +35 -0
- ommlds/cli/sessions/embedding/configs.py +21 -0
- ommlds/cli/sessions/embedding/inject.py +42 -0
- ommlds/cli/sessions/embedding/session.py +33 -0
- ommlds/cli/sessions/inject.py +28 -11
- ommlds/cli/state/__init__.py +0 -0
- ommlds/cli/state/inject.py +28 -0
- ommlds/cli/{state.py → state/storage.py} +41 -24
- ommlds/minichain/__init__.py +84 -24
- ommlds/minichain/_dataclasses.py +15401 -0
- ommlds/minichain/_marshal.py +49 -9
- ommlds/minichain/_typedvalues.py +2 -4
- ommlds/minichain/backends/catalogs/base.py +20 -1
- ommlds/minichain/backends/catalogs/simple.py +2 -2
- ommlds/minichain/backends/catalogs/strings.py +10 -8
- ommlds/minichain/backends/impls/anthropic/chat.py +65 -27
- ommlds/minichain/backends/impls/anthropic/names.py +10 -8
- ommlds/minichain/backends/impls/anthropic/protocol.py +109 -0
- ommlds/minichain/backends/impls/anthropic/stream.py +111 -43
- ommlds/minichain/backends/impls/duckduckgo/search.py +6 -2
- 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 +114 -22
- ommlds/minichain/backends/impls/google/search.py +7 -2
- ommlds/minichain/backends/impls/google/stream.py +219 -0
- ommlds/minichain/backends/impls/google/tools.py +149 -0
- ommlds/minichain/backends/impls/groq/__init__.py +0 -0
- ommlds/minichain/backends/impls/groq/chat.py +75 -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 +125 -0
- ommlds/minichain/backends/impls/huggingface/repos.py +1 -5
- ommlds/minichain/backends/impls/llamacpp/chat.py +40 -22
- ommlds/minichain/backends/impls/llamacpp/completion.py +9 -5
- ommlds/minichain/backends/impls/llamacpp/format.py +4 -2
- ommlds/minichain/backends/impls/llamacpp/stream.py +43 -23
- ommlds/minichain/backends/impls/mistral.py +20 -5
- ommlds/minichain/backends/impls/mlx/chat.py +101 -24
- ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
- ommlds/minichain/backends/impls/ollama/chat.py +199 -0
- ommlds/minichain/backends/impls/openai/chat.py +18 -8
- ommlds/minichain/backends/impls/openai/completion.py +10 -3
- ommlds/minichain/backends/impls/openai/embedding.py +10 -3
- ommlds/minichain/backends/impls/openai/format.py +131 -106
- ommlds/minichain/backends/impls/openai/names.py +31 -5
- ommlds/minichain/backends/impls/openai/stream.py +43 -25
- ommlds/minichain/backends/impls/sentencepiece/tokens.py +9 -6
- ommlds/minichain/backends/impls/tavily.py +66 -0
- ommlds/minichain/backends/impls/tinygrad/chat.py +30 -20
- ommlds/minichain/backends/impls/tokenizers/tokens.py +9 -6
- ommlds/minichain/backends/impls/transformers/sentence.py +6 -3
- ommlds/minichain/backends/impls/transformers/tokens.py +10 -7
- ommlds/minichain/backends/impls/transformers/transformers.py +160 -37
- ommlds/minichain/backends/strings/parsing.py +1 -1
- ommlds/minichain/backends/strings/resolving.py +4 -1
- ommlds/minichain/chat/_marshal.py +16 -9
- ommlds/minichain/chat/choices/adapters.py +4 -4
- ommlds/minichain/chat/choices/services.py +1 -1
- ommlds/minichain/chat/choices/stream/__init__.py +0 -0
- ommlds/minichain/chat/choices/stream/adapters.py +35 -0
- 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/choices/types.py +2 -2
- ommlds/minichain/chat/history.py +3 -3
- ommlds/minichain/chat/messages.py +55 -19
- ommlds/minichain/chat/services.py +3 -3
- ommlds/minichain/chat/stream/_marshal.py +16 -0
- ommlds/minichain/chat/stream/joining.py +85 -0
- ommlds/minichain/chat/stream/services.py +15 -21
- ommlds/minichain/chat/stream/types.py +32 -19
- ommlds/minichain/chat/tools/execution.py +8 -7
- ommlds/minichain/chat/tools/ids.py +9 -15
- ommlds/minichain/chat/tools/parsing.py +17 -26
- ommlds/minichain/chat/transforms/base.py +29 -38
- ommlds/minichain/chat/transforms/metadata.py +30 -4
- ommlds/minichain/chat/transforms/services.py +9 -11
- ommlds/minichain/content/_marshal.py +44 -20
- ommlds/minichain/content/json.py +13 -0
- ommlds/minichain/content/materialize.py +14 -21
- ommlds/minichain/content/prepare.py +4 -0
- ommlds/minichain/content/transforms/interleave.py +1 -1
- ommlds/minichain/content/transforms/squeeze.py +1 -1
- ommlds/minichain/content/transforms/stringify.py +1 -1
- ommlds/minichain/json.py +20 -0
- ommlds/minichain/lib/code/__init__.py +0 -0
- ommlds/minichain/lib/code/prompts.py +6 -0
- ommlds/minichain/lib/fs/binfiles.py +108 -0
- ommlds/minichain/lib/fs/context.py +126 -0
- ommlds/minichain/lib/fs/errors.py +101 -0
- ommlds/minichain/lib/fs/suggestions.py +36 -0
- ommlds/minichain/lib/fs/tools/__init__.py +0 -0
- ommlds/minichain/lib/fs/tools/edit.py +104 -0
- ommlds/minichain/lib/fs/tools/ls.py +38 -0
- ommlds/minichain/lib/fs/tools/read.py +115 -0
- ommlds/minichain/lib/fs/tools/recursivels/__init__.py +0 -0
- ommlds/minichain/lib/fs/tools/recursivels/execution.py +40 -0
- ommlds/minichain/lib/todo/__init__.py +0 -0
- ommlds/minichain/lib/todo/context.py +54 -0
- ommlds/minichain/lib/todo/tools/__init__.py +0 -0
- ommlds/minichain/lib/todo/tools/read.py +44 -0
- ommlds/minichain/lib/todo/tools/write.py +335 -0
- ommlds/minichain/lib/todo/types.py +60 -0
- ommlds/minichain/llms/_marshal.py +25 -17
- ommlds/minichain/llms/types.py +4 -0
- ommlds/minichain/registries/globals.py +18 -4
- ommlds/minichain/resources.py +68 -45
- ommlds/minichain/search.py +1 -1
- ommlds/minichain/services/_marshal.py +46 -39
- ommlds/minichain/services/facades.py +3 -3
- ommlds/minichain/services/services.py +1 -1
- ommlds/minichain/standard.py +8 -0
- ommlds/minichain/stream/services.py +152 -38
- ommlds/minichain/stream/wrap.py +22 -24
- ommlds/minichain/text/toolparsing/llamacpp/hermes2.py +3 -2
- ommlds/minichain/text/toolparsing/llamacpp/llama31.py +3 -2
- ommlds/minichain/text/toolparsing/llamacpp/utils.py +3 -2
- ommlds/minichain/tools/_marshal.py +1 -1
- ommlds/minichain/tools/execution/catalog.py +2 -1
- ommlds/minichain/tools/execution/context.py +34 -14
- ommlds/minichain/tools/execution/errors.py +15 -0
- ommlds/minichain/tools/execution/executors.py +8 -3
- ommlds/minichain/tools/execution/reflect.py +40 -5
- ommlds/minichain/tools/fns.py +46 -9
- ommlds/minichain/tools/jsonschema.py +14 -5
- ommlds/minichain/tools/reflect.py +54 -18
- ommlds/minichain/tools/types.py +33 -1
- ommlds/minichain/utils.py +27 -0
- ommlds/minichain/vectors/_marshal.py +11 -10
- ommlds/minichain/vectors/types.py +1 -1
- ommlds/nanochat/LICENSE +21 -0
- ommlds/nanochat/__init__.py +0 -0
- ommlds/nanochat/rustbpe/LICENSE +21 -0
- ommlds/nanochat/tokenizers.py +406 -0
- ommlds/server/cli.py +1 -2
- ommlds/server/server.py +5 -5
- ommlds/server/service.py +1 -1
- 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 +371 -0
- ommlds/tools/git.py +35 -12
- ommlds/tools/ocr.py +8 -9
- ommlds/wiki/analyze.py +6 -7
- ommlds/wiki/text/mfh.py +1 -5
- ommlds/wiki/text/wtp.py +1 -3
- ommlds/wiki/utils/xml.py +5 -5
- {ommlds-0.0.0.dev426.dist-info → ommlds-0.0.0.dev485.dist-info}/METADATA +24 -21
- ommlds-0.0.0.dev485.dist-info/RECORD +436 -0
- ommlds/cli/backends/standard.py +0 -20
- ommlds/cli/sessions/chat/base.py +0 -42
- ommlds/cli/sessions/chat/interactive.py +0 -73
- ommlds/cli/sessions/chat/printing.py +0 -96
- ommlds/cli/sessions/chat/prompt.py +0 -143
- ommlds/cli/sessions/chat/state.py +0 -109
- ommlds/cli/sessions/chat/tools.py +0 -91
- ommlds/cli/sessions/completion/completion.py +0 -44
- ommlds/cli/sessions/embedding/embedding.py +0 -42
- ommlds/cli/tools/config.py +0 -13
- ommlds/cli/tools/inject.py +0 -64
- ommlds/minichain/chat/stream/adapters.py +0 -69
- ommlds/minichain/lib/fs/ls/execution.py +0 -32
- ommlds-0.0.0.dev426.dist-info/RECORD +0 -303
- /ommlds/{cli/tools → backends/google}/__init__.py +0 -0
- /ommlds/{huggingface.py → backends/huggingface.py} +0 -0
- /ommlds/{minichain/lib/fs/ls → cli/content}/__init__.py +0 -0
- /ommlds/minichain/lib/fs/{ls → tools/recursivels}/rendering.py +0 -0
- /ommlds/minichain/lib/fs/{ls → tools/recursivels}/running.py +0 -0
- {ommlds-0.0.0.dev426.dist-info → ommlds-0.0.0.dev485.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev426.dist-info → ommlds-0.0.0.dev485.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev426.dist-info → ommlds-0.0.0.dev485.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev426.dist-info → ommlds-0.0.0.dev485.dist-info}/top_level.txt +0 -0
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
3
|
from omlish import check
|
|
4
|
-
from omlish import
|
|
4
|
+
from omlish import marshal as msh
|
|
5
5
|
from omlish import typedvalues as tv
|
|
6
6
|
from omlish.formats import json
|
|
7
7
|
from omlish.http import all as http
|
|
8
8
|
from omlish.http import sse
|
|
9
9
|
from omlish.io.buffers import DelimitingBuffer
|
|
10
10
|
|
|
11
|
+
from .....backends.anthropic.protocol import types as pt
|
|
12
|
+
from .....backends.anthropic.protocol.sse.events import AnthropicSseDecoderEvents
|
|
11
13
|
from ....chat.choices.services import ChatChoicesOutputs
|
|
12
|
-
from ....chat.
|
|
13
|
-
from ....chat.stream.services import
|
|
14
|
-
from ....chat.stream.services import
|
|
15
|
-
from ....chat.stream.
|
|
16
|
-
from ....chat.stream.types import
|
|
17
|
-
from ....chat.stream.types import
|
|
14
|
+
from ....chat.choices.stream.services import ChatChoicesStreamRequest
|
|
15
|
+
from ....chat.choices.stream.services import ChatChoicesStreamResponse
|
|
16
|
+
from ....chat.choices.stream.services import static_check_is_chat_choices_stream_service
|
|
17
|
+
from ....chat.choices.stream.types import AiChoiceDeltas
|
|
18
|
+
from ....chat.choices.stream.types import AiChoicesDeltas
|
|
19
|
+
from ....chat.stream.types import ContentAiDelta
|
|
20
|
+
from ....chat.stream.types import PartialToolUseAiDelta
|
|
21
|
+
from ....chat.tools.types import Tool
|
|
18
22
|
from ....configs import Config
|
|
19
23
|
from ....resources import UseResources
|
|
20
24
|
from ....standard import ApiKey
|
|
25
|
+
from ....stream.services import StreamResponseSink
|
|
21
26
|
from ....stream.services import new_stream_response
|
|
22
27
|
from .chat import AnthropicChatChoicesService
|
|
23
28
|
from .names import MODEL_NAMES
|
|
29
|
+
from .protocol import build_protocol_chat_messages
|
|
30
|
+
from .protocol import build_protocol_tool
|
|
24
31
|
|
|
25
32
|
|
|
26
33
|
##
|
|
@@ -32,42 +39,46 @@ from .names import MODEL_NAMES
|
|
|
32
39
|
# )
|
|
33
40
|
@static_check_is_chat_choices_stream_service
|
|
34
41
|
class AnthropicChatChoicesStreamService:
|
|
35
|
-
def __init__(
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
*configs: Config,
|
|
45
|
+
http_client: http.AsyncHttpClient | None = None,
|
|
46
|
+
) -> None:
|
|
36
47
|
super().__init__()
|
|
37
48
|
|
|
49
|
+
self._http_client = http_client
|
|
50
|
+
|
|
38
51
|
with tv.consume(*configs) as cc:
|
|
39
52
|
self._model_name = cc.pop(AnthropicChatChoicesService.DEFAULT_MODEL_NAME)
|
|
40
53
|
self._api_key = check.not_none(ApiKey.pop_secret(cc, env='ANTHROPIC_API_KEY'))
|
|
41
54
|
|
|
42
|
-
READ_CHUNK_SIZE =
|
|
55
|
+
READ_CHUNK_SIZE: ta.ClassVar[int] = -1
|
|
43
56
|
|
|
44
|
-
def invoke(
|
|
57
|
+
async def invoke(
|
|
45
58
|
self,
|
|
46
59
|
request: ChatChoicesStreamRequest,
|
|
47
60
|
*,
|
|
48
61
|
max_tokens: int = 4096, # FIXME: ChatOption
|
|
49
62
|
) -> ChatChoicesStreamResponse:
|
|
50
|
-
messages =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
role=AnthropicChatChoicesService.ROLES_MAP[type(m)], # noqa
|
|
60
|
-
content=check.isinstance(AnthropicChatChoicesService._get_msg_content(m), str), # noqa
|
|
61
|
-
))
|
|
62
|
-
|
|
63
|
-
raw_request = dict(
|
|
63
|
+
messages, system = build_protocol_chat_messages(request.v)
|
|
64
|
+
|
|
65
|
+
tools: list[pt.ToolSpec] = []
|
|
66
|
+
with tv.TypedValues(*request.options).consume() as oc:
|
|
67
|
+
t: Tool
|
|
68
|
+
for t in oc.pop(Tool, []):
|
|
69
|
+
tools.append(build_protocol_tool(t))
|
|
70
|
+
|
|
71
|
+
a_req = pt.MessagesRequest(
|
|
64
72
|
model=MODEL_NAMES.resolve(self._model_name.v),
|
|
65
|
-
|
|
73
|
+
system=system,
|
|
66
74
|
messages=messages,
|
|
75
|
+
tools=tools or None,
|
|
67
76
|
max_tokens=max_tokens,
|
|
68
77
|
stream=True,
|
|
69
78
|
)
|
|
70
79
|
|
|
80
|
+
raw_request = msh.marshal(a_req)
|
|
81
|
+
|
|
71
82
|
http_request = http.HttpRequest(
|
|
72
83
|
'https://api.anthropic.com/v1/messages',
|
|
73
84
|
headers={
|
|
@@ -78,16 +89,19 @@ class AnthropicChatChoicesStreamService:
|
|
|
78
89
|
data=json.dumps(raw_request).encode('utf-8'),
|
|
79
90
|
)
|
|
80
91
|
|
|
81
|
-
with UseResources.or_new(request.options) as rs:
|
|
82
|
-
http_client = rs.
|
|
83
|
-
http_response = rs.
|
|
92
|
+
async with UseResources.or_new(request.options) as rs:
|
|
93
|
+
http_client = await rs.enter_async_context(http.manage_async_client(self._http_client))
|
|
94
|
+
http_response = await rs.enter_async_context(await http_client.stream_request(http_request))
|
|
95
|
+
|
|
96
|
+
async def inner(sink: StreamResponseSink[AiChoicesDeltas]) -> ta.Sequence[ChatChoicesOutputs] | None:
|
|
97
|
+
msg_start: AnthropicSseDecoderEvents.MessageStart | None = None
|
|
98
|
+
cbk_start: AnthropicSseDecoderEvents.ContentBlockStart | None = None
|
|
99
|
+
msg_stop: AnthropicSseDecoderEvents.MessageStop | None = None
|
|
84
100
|
|
|
85
|
-
def yield_choices() -> ta.Generator[AiChoiceDeltas, None, ta.Sequence[ChatChoicesOutputs] | None]:
|
|
86
101
|
db = DelimitingBuffer([b'\r', b'\n', b'\r\n'])
|
|
87
102
|
sd = sse.SseDecoder()
|
|
88
103
|
while True:
|
|
89
|
-
|
|
90
|
-
b = http_response.stream.read1(self.READ_CHUNK_SIZE) # type: ignore[attr-defined]
|
|
104
|
+
b = await http_response.stream.read1(self.READ_CHUNK_SIZE)
|
|
91
105
|
for l in db.feed(b):
|
|
92
106
|
if isinstance(l, DelimitingBuffer.Incomplete):
|
|
93
107
|
# FIXME: handle
|
|
@@ -95,29 +109,83 @@ class AnthropicChatChoicesStreamService:
|
|
|
95
109
|
|
|
96
110
|
# FIXME: https://docs.anthropic.com/en/docs/build-with-claude/streaming
|
|
97
111
|
for so in sd.process_line(l):
|
|
98
|
-
|
|
99
|
-
if isinstance(so, sse.SseEvent) and so.type == b'message':
|
|
112
|
+
if isinstance(so, sse.SseEvent):
|
|
100
113
|
ss = so.data.decode('utf-8')
|
|
101
114
|
if ss == '[DONE]':
|
|
102
115
|
return []
|
|
103
116
|
|
|
104
|
-
|
|
117
|
+
dct = json.loads(ss)
|
|
118
|
+
check.equal(dct['type'], so.type.decode('utf-8'))
|
|
119
|
+
ae = msh.unmarshal(dct, AnthropicSseDecoderEvents.Event)
|
|
120
|
+
|
|
121
|
+
match ae:
|
|
122
|
+
case AnthropicSseDecoderEvents.MessageStart():
|
|
123
|
+
check.none(msg_start)
|
|
124
|
+
msg_start = ae
|
|
125
|
+
if msg_start.message.content:
|
|
126
|
+
raise NotImplementedError
|
|
127
|
+
|
|
128
|
+
case AnthropicSseDecoderEvents.ContentBlockStart():
|
|
129
|
+
check.not_none(msg_start)
|
|
130
|
+
check.none(cbk_start)
|
|
131
|
+
cbk_start = ae
|
|
132
|
+
|
|
133
|
+
if isinstance(ae.content_block, AnthropicSseDecoderEvents.ContentBlockStart.Text): # noqa
|
|
134
|
+
await sink.emit(AiChoicesDeltas([AiChoiceDeltas([ContentAiDelta(
|
|
135
|
+
ae.content_block.text,
|
|
136
|
+
)])]))
|
|
137
|
+
|
|
138
|
+
elif isinstance(ae.content_block, AnthropicSseDecoderEvents.ContentBlockStart.ToolUse): # noqa
|
|
139
|
+
await sink.emit(AiChoicesDeltas([AiChoiceDeltas([PartialToolUseAiDelta( # noqa
|
|
140
|
+
id=ae.content_block.id,
|
|
141
|
+
name=ae.content_block.name,
|
|
142
|
+
raw_args=ae.content_block.input,
|
|
143
|
+
)])]))
|
|
144
|
+
|
|
145
|
+
else:
|
|
146
|
+
raise TypeError(ae.content_block)
|
|
147
|
+
|
|
148
|
+
case AnthropicSseDecoderEvents.ContentBlockDelta():
|
|
149
|
+
check.not_none(cbk_start)
|
|
150
|
+
|
|
151
|
+
if isinstance(ae.delta, AnthropicSseDecoderEvents.ContentBlockDelta.TextDelta):
|
|
152
|
+
await sink.emit(AiChoicesDeltas([AiChoiceDeltas([ContentAiDelta(
|
|
153
|
+
ae.delta.text,
|
|
154
|
+
)])]))
|
|
155
|
+
|
|
156
|
+
elif isinstance(ae.delta, AnthropicSseDecoderEvents.ContentBlockDelta.InputJsonDelta): # noqa
|
|
157
|
+
await sink.emit(AiChoicesDeltas([AiChoiceDeltas([PartialToolUseAiDelta( # noqa
|
|
158
|
+
raw_args=ae.delta.partial_json,
|
|
159
|
+
)])]))
|
|
160
|
+
|
|
161
|
+
else:
|
|
162
|
+
raise TypeError(ae.delta)
|
|
163
|
+
|
|
164
|
+
case AnthropicSseDecoderEvents.ContentBlockStop():
|
|
165
|
+
check.not_none(cbk_start)
|
|
166
|
+
cbk_start = None
|
|
167
|
+
|
|
168
|
+
case AnthropicSseDecoderEvents.MessageDelta():
|
|
169
|
+
check.not_none(msg_start)
|
|
170
|
+
check.none(cbk_start)
|
|
105
171
|
|
|
106
|
-
|
|
172
|
+
case AnthropicSseDecoderEvents.MessageStop():
|
|
173
|
+
check.not_none(msg_start)
|
|
174
|
+
check.none(msg_stop)
|
|
175
|
+
msg_stop = ae
|
|
107
176
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
continue
|
|
177
|
+
case AnthropicSseDecoderEvents.Ping():
|
|
178
|
+
pass
|
|
111
179
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
for choice in sj['choices']
|
|
115
|
-
]
|
|
180
|
+
case _:
|
|
181
|
+
raise TypeError(ae)
|
|
116
182
|
|
|
117
183
|
if not b:
|
|
184
|
+
check.not_none(msg_stop)
|
|
185
|
+
check.none(cbk_start)
|
|
118
186
|
return []
|
|
119
187
|
|
|
120
188
|
# raw_response = json.loads(check.not_none(http_response.data).decode('utf-8'))
|
|
121
189
|
# return rh.build_response(raw_response)
|
|
122
190
|
|
|
123
|
-
return new_stream_response(rs,
|
|
191
|
+
return await new_stream_response(rs, inner)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
from omlish import lang
|
|
2
2
|
|
|
3
3
|
from ....search import SearchHit
|
|
4
4
|
from ....search import SearchHits
|
|
@@ -7,6 +7,10 @@ from ....search import SearchResponse
|
|
|
7
7
|
from ....search import static_check_is_search_service
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
with lang.auto_proxy_import(globals()):
|
|
11
|
+
import ddgs
|
|
12
|
+
|
|
13
|
+
|
|
10
14
|
##
|
|
11
15
|
|
|
12
16
|
|
|
@@ -17,7 +21,7 @@ from ....search import static_check_is_search_service
|
|
|
17
21
|
# )
|
|
18
22
|
@static_check_is_search_service
|
|
19
23
|
class DuckduckgoSearchService:
|
|
20
|
-
def invoke(self, request: SearchRequest) -> SearchResponse:
|
|
24
|
+
async def invoke(self, request: SearchRequest) -> SearchResponse:
|
|
21
25
|
dsch = ddgs.DDGS()
|
|
22
26
|
res = dsch.text(request.v)
|
|
23
27
|
return SearchResponse(SearchHits(
|
|
File without changes
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# ruff: noqa: PERF402
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from omlish.text.lorem import LOREM
|
|
5
|
+
|
|
6
|
+
from ....chat.choices.services import ChatChoicesRequest
|
|
7
|
+
from ....chat.choices.services import ChatChoicesResponse
|
|
8
|
+
from ....chat.choices.services import static_check_is_chat_choices_service
|
|
9
|
+
from ....chat.choices.stream.services import ChatChoicesStreamRequest
|
|
10
|
+
from ....chat.choices.stream.services import ChatChoicesStreamResponse
|
|
11
|
+
from ....chat.choices.stream.services import static_check_is_chat_choices_stream_service
|
|
12
|
+
from ....chat.choices.stream.types import AiChoiceDeltas
|
|
13
|
+
from ....chat.choices.stream.types import AiChoicesDeltas
|
|
14
|
+
from ....chat.choices.types import AiChoice
|
|
15
|
+
from ....chat.choices.types import ChatChoicesOutputs
|
|
16
|
+
from ....chat.messages import AiMessage
|
|
17
|
+
from ....chat.stream.types import ContentAiDelta
|
|
18
|
+
from ....resources import UseResources
|
|
19
|
+
from ....stream.services import StreamResponseSink
|
|
20
|
+
from ....stream.services import new_stream_response
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# @omlish-manifest $.minichain.registries.manifests.RegistryManifest(
|
|
27
|
+
# name='dummy',
|
|
28
|
+
# type='ChatChoicesService',
|
|
29
|
+
# )
|
|
30
|
+
@static_check_is_chat_choices_service
|
|
31
|
+
class DummyChatChoicesService:
|
|
32
|
+
async def invoke(self, request: ChatChoicesRequest) -> ChatChoicesResponse:
|
|
33
|
+
return ChatChoicesResponse([AiChoice([AiMessage(LOREM)])])
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# @omlish-manifest $.minichain.registries.manifests.RegistryManifest(
|
|
40
|
+
# name='dummy',
|
|
41
|
+
# type='ChatChoicesStreamService',
|
|
42
|
+
# )
|
|
43
|
+
@static_check_is_chat_choices_stream_service
|
|
44
|
+
class DummyChatChoicesStreamService:
|
|
45
|
+
async def invoke(self, request: ChatChoicesStreamRequest) -> ChatChoicesStreamResponse:
|
|
46
|
+
async with UseResources.or_new(request.options) as rs:
|
|
47
|
+
async def inner(sink: StreamResponseSink[AiChoicesDeltas]) -> ta.Sequence[ChatChoicesOutputs]:
|
|
48
|
+
for s in LOREM:
|
|
49
|
+
await sink.emit(AiChoicesDeltas([
|
|
50
|
+
AiChoiceDeltas([
|
|
51
|
+
ContentAiDelta(s),
|
|
52
|
+
]),
|
|
53
|
+
]))
|
|
54
|
+
|
|
55
|
+
return []
|
|
56
|
+
|
|
57
|
+
return await new_stream_response(rs, inner)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
##
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# @omlish-manifest $.minichain.backends.strings.manifests.BackendStringsManifest(
|
|
64
|
+
# [
|
|
65
|
+
# 'ChatChoicesService',
|
|
66
|
+
# 'ChatChoicesStreamService',
|
|
67
|
+
# ],
|
|
68
|
+
# 'dummy',
|
|
69
|
+
# )
|
|
@@ -4,21 +4,29 @@ https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models
|
|
|
4
4
|
import typing as ta
|
|
5
5
|
|
|
6
6
|
from omlish import check
|
|
7
|
+
from omlish import marshal as msh
|
|
7
8
|
from omlish import typedvalues as tv
|
|
8
9
|
from omlish.formats import json
|
|
9
10
|
from omlish.http import all as http
|
|
10
11
|
|
|
12
|
+
from .....backends.google.protocol import types as pt
|
|
11
13
|
from ....chat.choices.services import ChatChoicesRequest
|
|
12
14
|
from ....chat.choices.services import ChatChoicesResponse
|
|
13
15
|
from ....chat.choices.services import static_check_is_chat_choices_service
|
|
14
16
|
from ....chat.choices.types import AiChoice
|
|
15
17
|
from ....chat.messages import AiMessage
|
|
18
|
+
from ....chat.messages import AnyAiMessage
|
|
16
19
|
from ....chat.messages import Message
|
|
17
20
|
from ....chat.messages import SystemMessage
|
|
21
|
+
from ....chat.messages import ToolUseMessage
|
|
22
|
+
from ....chat.messages import ToolUseResultMessage
|
|
18
23
|
from ....chat.messages import UserMessage
|
|
24
|
+
from ....chat.tools.types import Tool
|
|
19
25
|
from ....models.configs import ModelName
|
|
20
26
|
from ....standard import ApiKey
|
|
27
|
+
from ....tools.types import ToolUse
|
|
21
28
|
from .names import MODEL_NAMES
|
|
29
|
+
from .tools import build_tool_spec_schema
|
|
22
30
|
|
|
23
31
|
|
|
24
32
|
##
|
|
@@ -32,9 +40,15 @@ from .names import MODEL_NAMES
|
|
|
32
40
|
class GoogleChatChoicesService:
|
|
33
41
|
DEFAULT_MODEL_NAME: ta.ClassVar[ModelName] = ModelName(check.not_none(MODEL_NAMES.default))
|
|
34
42
|
|
|
35
|
-
def __init__(
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
*configs: ApiKey | ModelName,
|
|
46
|
+
http_client: http.AsyncHttpClient | None = None,
|
|
47
|
+
) -> None:
|
|
36
48
|
super().__init__()
|
|
37
49
|
|
|
50
|
+
self._http_client = http_client
|
|
51
|
+
|
|
38
52
|
with tv.consume(*configs) as cc:
|
|
39
53
|
self._model_name = cc.pop(self.DEFAULT_MODEL_NAME)
|
|
40
54
|
self._api_key = ApiKey.pop_secret(cc, env='GEMINI_API_KEY')
|
|
@@ -52,43 +66,121 @@ class GoogleChatChoicesService:
|
|
|
52
66
|
BASE_URL: ta.ClassVar[str] = 'https://generativelanguage.googleapis.com/v1beta/models'
|
|
53
67
|
|
|
54
68
|
ROLES_MAP: ta.ClassVar[ta.Mapping[type[Message], str]] = {
|
|
55
|
-
SystemMessage: 'system',
|
|
56
69
|
UserMessage: 'user',
|
|
57
|
-
AiMessage: '
|
|
70
|
+
AiMessage: 'model',
|
|
71
|
+
ToolUseMessage: 'model',
|
|
58
72
|
}
|
|
59
73
|
|
|
60
|
-
def invoke(
|
|
74
|
+
async def invoke(
|
|
61
75
|
self,
|
|
62
76
|
request: ChatChoicesRequest,
|
|
63
77
|
) -> ChatChoicesResponse:
|
|
64
78
|
key = check.not_none(self._api_key).reveal()
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
g_sys_content: pt.Content | None = None
|
|
81
|
+
g_contents: list[pt.Content] = []
|
|
82
|
+
for i, m in enumerate(request.v):
|
|
83
|
+
if isinstance(m, SystemMessage):
|
|
84
|
+
check.arg(i == 0)
|
|
85
|
+
check.none(g_sys_content)
|
|
86
|
+
g_sys_content = pt.Content(
|
|
87
|
+
parts=[pt.Part(
|
|
88
|
+
text=check.not_none(self._get_msg_content(m)),
|
|
89
|
+
)],
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
elif isinstance(m, ToolUseResultMessage):
|
|
93
|
+
tr_resp_val: pt.Value
|
|
94
|
+
if m.tur.c is None:
|
|
95
|
+
tr_resp_val = pt.NullValue() # type: ignore[unreachable]
|
|
96
|
+
elif isinstance(m.tur.c, str):
|
|
97
|
+
tr_resp_val = pt.StringValue(m.tur.c)
|
|
98
|
+
else:
|
|
99
|
+
raise TypeError(m.tur.c)
|
|
100
|
+
g_contents.append(pt.Content(
|
|
101
|
+
parts=[pt.Part(
|
|
102
|
+
function_response=pt.FunctionResponse(
|
|
103
|
+
id=m.tur.id,
|
|
104
|
+
name=m.tur.name,
|
|
105
|
+
response={
|
|
106
|
+
'value': tr_resp_val,
|
|
107
|
+
},
|
|
108
|
+
),
|
|
109
|
+
)],
|
|
110
|
+
))
|
|
111
|
+
|
|
112
|
+
elif isinstance(m, AiMessage):
|
|
113
|
+
g_contents.append(pt.Content(
|
|
114
|
+
parts=[pt.Part(
|
|
115
|
+
text=check.not_none(self._get_msg_content(m)),
|
|
116
|
+
)],
|
|
117
|
+
role='model',
|
|
118
|
+
))
|
|
119
|
+
|
|
120
|
+
elif isinstance(m, ToolUseMessage):
|
|
121
|
+
g_contents.append(pt.Content(
|
|
122
|
+
parts=[pt.Part(
|
|
123
|
+
function_call=pt.FunctionCall(
|
|
124
|
+
id=m.tu.id,
|
|
125
|
+
name=m.tu.name,
|
|
126
|
+
args=m.tu.args,
|
|
127
|
+
),
|
|
128
|
+
)],
|
|
129
|
+
role='model',
|
|
130
|
+
))
|
|
131
|
+
|
|
132
|
+
else:
|
|
133
|
+
g_contents.append(pt.Content(
|
|
134
|
+
parts=[pt.Part(
|
|
135
|
+
text=check.not_none(self._get_msg_content(m)),
|
|
136
|
+
)],
|
|
137
|
+
role=self.ROLES_MAP[type(m)], # type: ignore[arg-type]
|
|
138
|
+
))
|
|
139
|
+
|
|
140
|
+
g_tools: list[pt.Tool] = []
|
|
141
|
+
with tv.TypedValues(*request.options).consume() as oc:
|
|
142
|
+
t: Tool
|
|
143
|
+
for t in oc.pop(Tool, []):
|
|
144
|
+
g_tools.append(pt.Tool(
|
|
145
|
+
function_declarations=[build_tool_spec_schema(t.spec)],
|
|
146
|
+
))
|
|
147
|
+
|
|
148
|
+
g_req = pt.GenerateContentRequest(
|
|
149
|
+
contents=g_contents or None,
|
|
150
|
+
tools=g_tools or None,
|
|
151
|
+
system_instruction=g_sys_content,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
req_dct = msh.marshal(g_req)
|
|
79
155
|
|
|
80
156
|
model_name = MODEL_NAMES.resolve(self._model_name.v)
|
|
81
157
|
|
|
82
|
-
resp = http.
|
|
158
|
+
resp = await http.async_request(
|
|
83
159
|
f'{self.BASE_URL.rstrip("/")}/{model_name}:generateContent?key={key}',
|
|
84
160
|
headers={'Content-Type': 'application/json'},
|
|
85
161
|
data=json.dumps_compact(req_dct).encode('utf-8'),
|
|
86
162
|
method='POST',
|
|
163
|
+
client=self._http_client,
|
|
87
164
|
)
|
|
88
165
|
|
|
89
166
|
resp_dct = json.loads(check.not_none(resp.data).decode('utf-8'))
|
|
90
167
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
]
|
|
168
|
+
g_resp = msh.unmarshal(resp_dct, pt.GenerateContentResponse)
|
|
169
|
+
|
|
170
|
+
ai_choices: list[AiChoice] = []
|
|
171
|
+
for c in g_resp.candidates or []:
|
|
172
|
+
out: list[AnyAiMessage] = []
|
|
173
|
+
for g_resp_part in check.not_none(check.not_none(c.content).parts):
|
|
174
|
+
if (g_txt := g_resp_part.text) is not None:
|
|
175
|
+
out.append(AiMessage(g_txt))
|
|
176
|
+
elif (g_fc := g_resp_part.function_call) is not None:
|
|
177
|
+
out.append(ToolUseMessage(ToolUse(
|
|
178
|
+
id=g_fc.id,
|
|
179
|
+
name=g_fc.name,
|
|
180
|
+
args=g_fc.args or {},
|
|
181
|
+
)))
|
|
182
|
+
else:
|
|
183
|
+
raise TypeError(g_resp_part)
|
|
184
|
+
ai_choices.append(AiChoice(out))
|
|
185
|
+
|
|
186
|
+
return ChatChoicesResponse(ai_choices)
|
|
@@ -82,13 +82,17 @@ class CseSearchService:
|
|
|
82
82
|
self,
|
|
83
83
|
cse_id: str | None = None,
|
|
84
84
|
cse_api_key: str | None = None,
|
|
85
|
+
*,
|
|
86
|
+
http_client: http.AsyncHttpClient | None = None,
|
|
85
87
|
) -> None:
|
|
86
88
|
super().__init__()
|
|
87
89
|
|
|
88
90
|
self._cse_id = cse_id
|
|
89
91
|
self._cse_api_key = cse_api_key
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
self._http_client = http_client
|
|
94
|
+
|
|
95
|
+
async def invoke(
|
|
92
96
|
self,
|
|
93
97
|
request: SearchRequest,
|
|
94
98
|
) -> SearchResponse:
|
|
@@ -97,8 +101,9 @@ class CseSearchService:
|
|
|
97
101
|
cx=check.non_empty_str(self._cse_id),
|
|
98
102
|
q=request.v,
|
|
99
103
|
))
|
|
100
|
-
resp = http.
|
|
104
|
+
resp = await http.async_request(
|
|
101
105
|
f'https://www.googleapis.com/customsearch/v1?{qs}',
|
|
106
|
+
client=self._http_client,
|
|
102
107
|
)
|
|
103
108
|
out = check.not_none(resp.data)
|
|
104
109
|
|