generic-ml-cache-core 0.2.0__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.
- generic_ml_cache_core/__init__.py +64 -0
- generic_ml_cache_core/adapter/__init__.py +1 -0
- generic_ml_cache_core/adapter/inbound/__init__.py +1 -0
- generic_ml_cache_core/adapter/inbound/composition.py +96 -0
- generic_ml_cache_core/adapter/out/__init__.py +1 -0
- generic_ml_cache_core/adapter/out/api/__init__.py +1 -0
- generic_ml_cache_core/adapter/out/api/stub_api_client_adapter.py +30 -0
- generic_ml_cache_core/adapter/out/client/__init__.py +28 -0
- generic_ml_cache_core/adapter/out/client/claude.py +214 -0
- generic_ml_cache_core/adapter/out/client/codex.py +171 -0
- generic_ml_cache_core/adapter/out/client/cursor.py +208 -0
- generic_ml_cache_core/adapter/out/client/discover.py +121 -0
- generic_ml_cache_core/adapter/out/client/isolation.py +396 -0
- generic_ml_cache_core/adapter/out/client/local_client_runner.py +54 -0
- generic_ml_cache_core/adapter/out/client/passthrough_client_runner.py +47 -0
- generic_ml_cache_core/adapter/out/client/prime_directive.py +53 -0
- generic_ml_cache_core/adapter/out/client/registry.py +34 -0
- generic_ml_cache_core/adapter/out/clock/__init__.py +1 -0
- generic_ml_cache_core/adapter/out/clock/system_clock.py +16 -0
- generic_ml_cache_core/adapter/out/fingerprint/__init__.py +1 -0
- generic_ml_cache_core/adapter/out/fingerprint/filesystem_file_fingerprint.py +30 -0
- generic_ml_cache_core/adapter/out/metrics/__init__.py +1 -0
- generic_ml_cache_core/adapter/out/metrics/access_registry.py +147 -0
- generic_ml_cache_core/adapter/out/metrics/journal_metrics.py +45 -0
- generic_ml_cache_core/adapter/out/persistence/__init__.py +1 -0
- generic_ml_cache_core/adapter/out/persistence/call_identity_serialization.py +100 -0
- generic_ml_cache_core/adapter/out/persistence/in_memory_execution_repository.py +69 -0
- generic_ml_cache_core/adapter/out/persistence/sqlite_execution_repository.py +398 -0
- generic_ml_cache_core/adapter/out/storage/__init__.py +1 -0
- generic_ml_cache_core/adapter/out/storage/filesystem_blob_store.py +47 -0
- generic_ml_cache_core/application/__init__.py +1 -0
- generic_ml_cache_core/application/domain/__init__.py +1 -0
- generic_ml_cache_core/application/domain/model/__init__.py +1 -0
- generic_ml_cache_core/application/domain/model/client_status.py +17 -0
- generic_ml_cache_core/application/domain/model/execution/__init__.py +1 -0
- generic_ml_cache_core/application/domain/model/execution/artifact.py +78 -0
- generic_ml_cache_core/application/domain/model/execution/execution_failure.py +32 -0
- generic_ml_cache_core/application/domain/model/execution/execution_kind.py +26 -0
- generic_ml_cache_core/application/domain/model/execution/execution_state.py +21 -0
- generic_ml_cache_core/application/domain/model/execution/ml_execution.py +41 -0
- generic_ml_cache_core/application/domain/model/identity/__init__.py +1 -0
- generic_ml_cache_core/application/domain/model/identity/api_call_identity.py +36 -0
- generic_ml_cache_core/application/domain/model/identity/call_identity.py +25 -0
- generic_ml_cache_core/application/domain/model/identity/managed_call_identity.py +54 -0
- generic_ml_cache_core/application/domain/model/identity/passthrough_call_identity.py +35 -0
- generic_ml_cache_core/application/domain/model/model_info.py +20 -0
- generic_ml_cache_core/application/domain/model/model_listing.py +29 -0
- generic_ml_cache_core/application/domain/model/parsed_output.py +23 -0
- generic_ml_cache_core/application/domain/model/probe/__init__.py +1 -0
- generic_ml_cache_core/application/domain/model/probe/probe_report.py +26 -0
- generic_ml_cache_core/application/domain/model/probe/probe_status.py +13 -0
- generic_ml_cache_core/application/domain/model/run/__init__.py +1 -0
- generic_ml_cache_core/application/domain/model/run/cache_mode.py +21 -0
- generic_ml_cache_core/application/domain/model/run/client_run_request.py +35 -0
- generic_ml_cache_core/application/domain/model/run/client_run_result.py +65 -0
- generic_ml_cache_core/application/domain/model/run/message.py +20 -0
- generic_ml_cache_core/application/domain/model/usage/__init__.py +1 -0
- generic_ml_cache_core/application/domain/model/usage/token_usage.py +53 -0
- generic_ml_cache_core/application/domain/model/usage/usage.py +108 -0
- generic_ml_cache_core/application/domain/service/__init__.py +1 -0
- generic_ml_cache_core/application/domain/service/cacheability.py +19 -0
- generic_ml_cache_core/application/domain/service/message_fingerprinting.py +25 -0
- generic_ml_cache_core/application/port/__init__.py +1 -0
- generic_ml_cache_core/application/port/inbound/__init__.py +1 -0
- generic_ml_cache_core/application/port/inbound/probe_command.py +35 -0
- generic_ml_cache_core/application/port/inbound/probe_use_case.py +19 -0
- generic_ml_cache_core/application/port/inbound/run_api_execution_command.py +40 -0
- generic_ml_cache_core/application/port/inbound/run_api_execution_use_case.py +20 -0
- generic_ml_cache_core/application/port/inbound/run_managed_local_execution_command.py +48 -0
- generic_ml_cache_core/application/port/inbound/run_managed_local_execution_use_case.py +25 -0
- generic_ml_cache_core/application/port/inbound/run_passthrough_execution_command.py +35 -0
- generic_ml_cache_core/application/port/inbound/run_passthrough_execution_use_case.py +20 -0
- generic_ml_cache_core/application/port/out/__init__.py +1 -0
- generic_ml_cache_core/application/port/out/api_client_port.py +26 -0
- generic_ml_cache_core/application/port/out/base.py +272 -0
- generic_ml_cache_core/application/port/out/blob_store_port.py +37 -0
- generic_ml_cache_core/application/port/out/client_runner_port.py +26 -0
- generic_ml_cache_core/application/port/out/clock_port.py +22 -0
- generic_ml_cache_core/application/port/out/execution_repository_port.py +40 -0
- generic_ml_cache_core/application/port/out/file_fingerprint_port.py +25 -0
- generic_ml_cache_core/application/port/out/metrics_port.py +54 -0
- generic_ml_cache_core/application/port/out/passthrough_runner_port.py +25 -0
- generic_ml_cache_core/application/usecase/__init__.py +1 -0
- generic_ml_cache_core/application/usecase/cached_ml_execution_service.py +198 -0
- generic_ml_cache_core/application/usecase/call_identity_building.py +60 -0
- generic_ml_cache_core/application/usecase/journal_events.py +19 -0
- generic_ml_cache_core/application/usecase/probe_service.py +44 -0
- generic_ml_cache_core/application/usecase/run_api_execution_service.py +69 -0
- generic_ml_cache_core/application/usecase/run_managed_local_execution_service.py +84 -0
- generic_ml_cache_core/application/usecase/run_passthrough_execution_service.py +67 -0
- generic_ml_cache_core/common/__init__.py +1 -0
- generic_ml_cache_core/common/checksum.py +82 -0
- generic_ml_cache_core/common/errors.py +76 -0
- generic_ml_cache_core/stream.py +65 -0
- generic_ml_cache_core-0.2.0.dist-info/METADATA +104 -0
- generic_ml_cache_core-0.2.0.dist-info/RECORD +99 -0
- generic_ml_cache_core-0.2.0.dist-info/WHEEL +4 -0
- generic_ml_cache_core-0.2.0.dist-info/licenses/LICENSE +201 -0
- generic_ml_cache_core-0.2.0.dist-info/licenses/NOTICE +8 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Daniel Slobozian
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""RunPassthroughExecutionService."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Tuple
|
|
8
|
+
|
|
9
|
+
from generic_ml_cache_core.application.domain.model.identity.call_identity import CallIdentity
|
|
10
|
+
from generic_ml_cache_core.application.domain.model.run.client_run_result import ClientRunResult
|
|
11
|
+
from generic_ml_cache_core.application.domain.model.execution.execution_kind import ExecutionKind
|
|
12
|
+
from generic_ml_cache_core.application.domain.model.identity.passthrough_call_identity import (
|
|
13
|
+
PassthroughCallIdentity,
|
|
14
|
+
)
|
|
15
|
+
from generic_ml_cache_core.application.port.inbound.run_passthrough_execution_command import (
|
|
16
|
+
RunPassthroughExecutionCommand,
|
|
17
|
+
)
|
|
18
|
+
from generic_ml_cache_core.application.port.inbound.run_passthrough_execution_use_case import (
|
|
19
|
+
RunPassthroughExecutionUseCase,
|
|
20
|
+
)
|
|
21
|
+
from generic_ml_cache_core.application.port.out.blob_store_port import BlobStorePort
|
|
22
|
+
from generic_ml_cache_core.application.port.out.execution_repository_port import (
|
|
23
|
+
ExecutionRepositoryPort,
|
|
24
|
+
)
|
|
25
|
+
from generic_ml_cache_core.application.port.out.metrics_port import MetricsPort
|
|
26
|
+
from generic_ml_cache_core.application.port.out.passthrough_runner_port import PassthroughRunnerPort
|
|
27
|
+
from generic_ml_cache_core.application.usecase.cached_ml_execution_service import (
|
|
28
|
+
CachedMlExecutionService,
|
|
29
|
+
)
|
|
30
|
+
from generic_ml_cache_core.common.checksum import fingerprint_arguments
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RunPassthroughExecutionService(CachedMlExecutionService, RunPassthroughExecutionUseCase):
|
|
34
|
+
"""Record-or-replay a passthrough (alias) client call.
|
|
35
|
+
|
|
36
|
+
Implements the inbound port over the shared cached-execution flow, supplying
|
|
37
|
+
the passthrough specifics: the identity is the client plus a fingerprint of
|
|
38
|
+
the opaque native args, the client runs via the passthrough runner (no
|
|
39
|
+
isolation, no file capture), and executions are tagged LOCAL_PASSTHROUGH. A
|
|
40
|
+
passthrough is always cacheable, so it keeps the base's default.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
passthrough_runner: PassthroughRunnerPort,
|
|
46
|
+
blob_store: BlobStorePort,
|
|
47
|
+
repository: ExecutionRepositoryPort,
|
|
48
|
+
metrics: MetricsPort,
|
|
49
|
+
) -> None:
|
|
50
|
+
super().__init__(blob_store, repository, metrics)
|
|
51
|
+
self._passthrough_runner = passthrough_runner
|
|
52
|
+
|
|
53
|
+
def _build_identity(self, command: RunPassthroughExecutionCommand) -> CallIdentity:
|
|
54
|
+
return PassthroughCallIdentity(
|
|
55
|
+
client=command.client,
|
|
56
|
+
native_args_fingerprint=fingerprint_arguments(command.native_args),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def _run_client(self, command: RunPassthroughExecutionCommand) -> ClientRunResult:
|
|
60
|
+
return self._passthrough_runner.run(command.client, command.native_args)
|
|
61
|
+
|
|
62
|
+
def _execution_kind(self) -> ExecutionKind:
|
|
63
|
+
return ExecutionKind.LOCAL_PASSTHROUGH
|
|
64
|
+
|
|
65
|
+
def _journal_fields(self, command: RunPassthroughExecutionCommand) -> Tuple[str, str, str]:
|
|
66
|
+
# A passthrough has no modelled model/effort — only the client is known.
|
|
67
|
+
return command.client, "", ""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Cross-cutting leaves shared across the package (errors, checksums, constants)."""
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Daniel Slobozian
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Container-independent checksumming of cache inputs.
|
|
4
|
+
|
|
5
|
+
The whole point of this module is one invariant:
|
|
6
|
+
|
|
7
|
+
The same *text* must yield the same checksum regardless of how that text
|
|
8
|
+
happened to be stored -- whether it lived in a standalone file on disk or
|
|
9
|
+
inside a JSON string field.
|
|
10
|
+
|
|
11
|
+
We achieve that by hashing the *decoded* UTF-8 text of each field, never the
|
|
12
|
+
bytes of whatever container (file, JSON document) carried it. Newlines, tabs
|
|
13
|
+
and other whitespace are meaningful and are never stripped.
|
|
14
|
+
|
|
15
|
+
Each field is length-prefixed before hashing so that, e.g., ``{"context": "ab",
|
|
16
|
+
"prompt": "c"}`` can never collide with ``{"context": "a", "prompt": "bc"}``.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import hashlib
|
|
22
|
+
from typing import Mapping, Sequence
|
|
23
|
+
|
|
24
|
+
# Control characters used purely as internal framing while hashing. They never
|
|
25
|
+
# touch user data and never appear in the stored record on disk.
|
|
26
|
+
_FIELD_SEP = b"\x1f" # unit separator
|
|
27
|
+
_RECORD_SEP = b"\x1e" # record separator
|
|
28
|
+
# Separates ordered arguments before hashing; order is significant (CLI flags
|
|
29
|
+
# are positional), so the join preserves it.
|
|
30
|
+
_ARGUMENT_SEP = "\x00"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def text_checksum(text: str) -> str:
|
|
34
|
+
"""SHA-256 of a single decoded string's UTF-8 bytes."""
|
|
35
|
+
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def file_content_fingerprint(data: bytes) -> str:
|
|
39
|
+
"""The one shared rule for fingerprinting a declared input file's content.
|
|
40
|
+
|
|
41
|
+
SHA-256 of the raw bytes -- binary-safe, so any file type fingerprints the
|
|
42
|
+
same way regardless of encoding. This is the single function every front
|
|
43
|
+
door (CLI, daemon, library consumer) must call; it is imported directly,
|
|
44
|
+
never reimplemented, so two front doors can never derive different keys for
|
|
45
|
+
the same file and silently miss each other's cache.
|
|
46
|
+
"""
|
|
47
|
+
return hashlib.sha256(data).hexdigest()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def fingerprint_arguments(arguments: Sequence[str]) -> str:
|
|
51
|
+
"""Fingerprint an ordered argument list into the key.
|
|
52
|
+
|
|
53
|
+
The raw arguments may carry secrets, so only their digest is ever keyed or
|
|
54
|
+
stored. Order is significant; the join with a control separator preserves it.
|
|
55
|
+
"""
|
|
56
|
+
return text_checksum(_ARGUMENT_SEP.join(arguments))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def checksum_input_data(input_data: Mapping[str, str]) -> str:
|
|
60
|
+
"""Return the container-independent SHA-256 checksum of ``input_data``.
|
|
61
|
+
|
|
62
|
+
``input_data`` is the cache input mapping, e.g. ``{"context": ..., "prompt":
|
|
63
|
+
...}``. Keys are hashed in sorted order so the result does not depend on dict
|
|
64
|
+
ordering. Values must be ``str`` -- the cache is deliberately *dumb*, so it is
|
|
65
|
+
the caller's job to make the text deterministic.
|
|
66
|
+
"""
|
|
67
|
+
digest = hashlib.sha256()
|
|
68
|
+
for key in sorted(input_data):
|
|
69
|
+
value = input_data[key]
|
|
70
|
+
if not isinstance(value, str):
|
|
71
|
+
raise TypeError(
|
|
72
|
+
f"input_data[{key!r}] must be str (the cache hashes decoded text, "
|
|
73
|
+
f"not bytes or objects); got {type(value).__name__}"
|
|
74
|
+
)
|
|
75
|
+
encoded = value.encode("utf-8")
|
|
76
|
+
digest.update(key.encode("utf-8"))
|
|
77
|
+
digest.update(_FIELD_SEP)
|
|
78
|
+
digest.update(str(len(encoded)).encode("ascii"))
|
|
79
|
+
digest.update(_FIELD_SEP)
|
|
80
|
+
digest.update(encoded)
|
|
81
|
+
digest.update(_RECORD_SEP)
|
|
82
|
+
return digest.hexdigest()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Daniel Slobozian
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Exception types raised by generic-ml-cache."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CacheError(Exception):
|
|
9
|
+
"""Base class for all generic-ml-cache errors."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CacheMiss(CacheError):
|
|
13
|
+
"""Raised in offline mode when no stored execution matches the request.
|
|
14
|
+
|
|
15
|
+
Offline mode is a *knowing* switch to replay-only: a miss is an error, never
|
|
16
|
+
a silent fall-through to a real call.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class UnknownClient(CacheError):
|
|
21
|
+
"""Raised when no adapter is registered for the requested client name."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ConfigError(CacheError):
|
|
25
|
+
"""Raised when the optional config file or a config env var is invalid.
|
|
26
|
+
|
|
27
|
+
A missing config file is never an error -- it just means built-in defaults
|
|
28
|
+
apply. This is only for a file that exists but cannot be parsed, or a value
|
|
29
|
+
(mode, timeout) that is not understood.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ClientNotFound(CacheError):
|
|
34
|
+
"""Raised when the client executable cannot be located on the system."""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class CommandLineTooLong(CacheError):
|
|
38
|
+
"""Raised before launch when the assembled command line would exceed the
|
|
39
|
+
operating system's argument-size limit.
|
|
40
|
+
|
|
41
|
+
Only a client that receives the prompt as a command-line argument
|
|
42
|
+
(cursor-agent, which has no stdin path) can hit this; claude and codex take the
|
|
43
|
+
prompt on stdin and are unaffected. Raising it up front turns an opaque OS
|
|
44
|
+
"argument list too long" error (or a silent Windows failure) into a clear
|
|
45
|
+
message that names the size, the limit, and the remedy.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class InputFileError(CacheError):
|
|
50
|
+
"""Raised when a declared input file cannot be read for fingerprinting.
|
|
51
|
+
|
|
52
|
+
The path does not point to a regular file, or the bytes could not be read.
|
|
53
|
+
The filesystem fingerprint adapter translates the foreign ``OSError`` into
|
|
54
|
+
this cause-named exception so the core never sees a library error type.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ArtifactBlobMissing(CacheError):
|
|
59
|
+
"""Raised when hydrating an execution whose artifact references a blob that
|
|
60
|
+
the blob store no longer holds.
|
|
61
|
+
|
|
62
|
+
The structured record says the output was persisted, but the bytes are gone
|
|
63
|
+
(an out-of-band deletion, a half-completed prune). The engine fails loud
|
|
64
|
+
rather than returning a silently empty result.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class RunInterrupted(Exception):
|
|
69
|
+
"""Raised when a real client run is stopped by a signal from the caller (the
|
|
70
|
+
workflow engine) before it finished.
|
|
71
|
+
|
|
72
|
+
Deliberately **not** a ``CacheError``: it is not a fault but a requested stop,
|
|
73
|
+
and it must never be recorded as an execution -- an interrupted call is not a
|
|
74
|
+
result. The CLI maps it to a distinct exit code so a stop is distinguishable
|
|
75
|
+
from a failure.
|
|
76
|
+
"""
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 Daniel Slobozian
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Live progress stream: an opt-in NDJSON event file written as a call runs.
|
|
4
|
+
|
|
5
|
+
The cache is the one running the client, so it is the right place to surface what
|
|
6
|
+
the client is doing *right now* -- for a human watching a long call, and (later)
|
|
7
|
+
for the workflow engine relaying progress to its own user.
|
|
8
|
+
|
|
9
|
+
Design:
|
|
10
|
+
|
|
11
|
+
* **Display-only.** The stream never changes what the cache records or the cache
|
|
12
|
+
key. It is a *view* of the run, not a second source of truth.
|
|
13
|
+
* **A regular file** is the transport. It is the one streaming channel that
|
|
14
|
+
behaves identically on Linux, macOS and Windows -- no sockets, no named pipes
|
|
15
|
+
(POSIX-only), no ``select``. A consumer (a human ``tail -f``, or a parent
|
|
16
|
+
process reading line by line) just opens it read-only and reads new lines.
|
|
17
|
+
* **NDJSON / JSON Lines.** One self-contained JSON object per line, ``\\n``
|
|
18
|
+
separated, flushed as written, so each event is readable the moment it lands
|
|
19
|
+
and the file is appendable without parsing what came before.
|
|
20
|
+
* **Best-effort.** A write that fails (full disk, bad path) is dropped, never
|
|
21
|
+
raised -- a progress view must not be able to break the real call.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
import time
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import Any, Optional
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class StreamWriter:
|
|
33
|
+
"""Append NDJSON progress events to ``path``. Safe to construct even if the
|
|
34
|
+
path is unwritable: streaming is then silently disabled and the call runs
|
|
35
|
+
unaffected."""
|
|
36
|
+
|
|
37
|
+
def __init__(self, path: Path) -> None:
|
|
38
|
+
self._fh: Optional[Any] = None
|
|
39
|
+
try:
|
|
40
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
# Text append; newline="\n" writes bare line feeds on every OS (no
|
|
42
|
+
# CRLF translation), which is what NDJSON consumers expect.
|
|
43
|
+
self._fh = open(path, "a", encoding="utf-8", newline="\n")
|
|
44
|
+
except OSError:
|
|
45
|
+
self._fh = None # streaming disabled; the run still proceeds
|
|
46
|
+
|
|
47
|
+
def event(self, kind: str, **fields: Any) -> None:
|
|
48
|
+
"""Write one event line: ``{"ts": <epoch>, "kind": <kind>, ...}``.
|
|
49
|
+
Fields that are ``None`` are omitted so the line stays compact."""
|
|
50
|
+
if self._fh is None:
|
|
51
|
+
return
|
|
52
|
+
record = {"ts": round(time.time(), 3), "kind": kind}
|
|
53
|
+
record.update({k: v for k, v in fields.items() if v is not None})
|
|
54
|
+
try:
|
|
55
|
+
self._fh.write(json.dumps(record, ensure_ascii=False) + "\n")
|
|
56
|
+
self._fh.flush()
|
|
57
|
+
except (OSError, ValueError, TypeError):
|
|
58
|
+
pass # drop the event rather than fail the run
|
|
59
|
+
|
|
60
|
+
def close(self) -> None:
|
|
61
|
+
if self._fh is not None:
|
|
62
|
+
try:
|
|
63
|
+
self._fh.close()
|
|
64
|
+
finally:
|
|
65
|
+
self._fh = None
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: generic-ml-cache-core
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Hexagonal core library for generic-ml-cache: domain, use cases, ports, and the default outbound adapters (SQLite repo, blob store, local clients, API). Stateless; inject the data source. Zero runtime deps.
|
|
5
|
+
Project-URL: Homepage, https://github.com/danielslobozian/generic-ml-cache
|
|
6
|
+
Project-URL: Repository, https://github.com/danielslobozian/generic-ml-cache
|
|
7
|
+
Project-URL: Issues, https://github.com/danielslobozian/generic-ml-cache/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/danielslobozian/generic-ml-cache/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Daniel Slobozian
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: NOTICE
|
|
13
|
+
Keywords: ai,cache,hexagonal,library,llm,ports-and-adapters,replay
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: coverage>=7; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.15; extra == 'dev'
|
|
31
|
+
Requires-Dist: vulture>=2; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# generic-ml-cache-core
|
|
35
|
+
|
|
36
|
+
#### The hexagonal engine behind gmlcache — embeddable, stateless, dependency-free
|
|
37
|
+
|
|
38
|
+
[](https://github.com/danielslobozian/generic-ml-cache/blob/main/LICENSE)
|
|
39
|
+
[](https://github.com/danielslobozian/generic-ml-cache/blob/main/docs/ROADMAP.md)
|
|
40
|
+
|
|
41
|
+
The reusable **engine** behind
|
|
42
|
+
[`gmlcache`](https://github.com/danielslobozian/generic-ml-cache/tree/main/packages/cli):
|
|
43
|
+
record a real ML client (or API) call once, replay it by its content key. It contains
|
|
44
|
+
the domain model, the use cases, the port contracts, **and the default outbound
|
|
45
|
+
adapters** (SQLite execution repository, filesystem blob store, the
|
|
46
|
+
claude/codex/cursor client runner, the API client, metrics, clock, fingerprinting) —
|
|
47
|
+
plus the `build_use_cases` composition factory.
|
|
48
|
+
|
|
49
|
+
Pure Python, **zero runtime dependencies**, and **stateless**: it bakes in *structure*
|
|
50
|
+
(table names, blob naming, schema) but no *location* — you inject the data source.
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install generic-ml-cache-core
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Embed it
|
|
59
|
+
|
|
60
|
+
Hand the library a data source and it wires the engine for you:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from generic_ml_cache_core import build_use_cases
|
|
64
|
+
from generic_ml_cache_core.application.port.inbound.run_managed_local_execution_command import (
|
|
65
|
+
RunManagedLocalExecutionCommand,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
wired = build_use_cases(store_root="/path/you/choose") # you provide the data source
|
|
69
|
+
command = RunManagedLocalExecutionCommand(
|
|
70
|
+
client="claude", model="sonnet", effort="", context="", prompt="…",
|
|
71
|
+
)
|
|
72
|
+
execution = wired.run_managed.execute(command) # records on a miss, replays on a hit
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
You reuse the shipped adapters by injecting a data source — you never reimplement them
|
|
76
|
+
(the **Spring Batch** model: the framework ships the writers, you provide the
|
|
77
|
+
connection). Need a different store? Construct the use cases yourself against the
|
|
78
|
+
ports and pass your own adapter.
|
|
79
|
+
|
|
80
|
+
## What's inside
|
|
81
|
+
|
|
82
|
+
- **Domain model** — executions, polymorphic call identities, artifacts, usage.
|
|
83
|
+
- **Use cases** — managed-local / passthrough / API runs, and probe (check).
|
|
84
|
+
- **Ports** (`application/port/...`) — client runner, blob store, execution repository,
|
|
85
|
+
metrics, clock, fingerprint, API client.
|
|
86
|
+
- **Default adapters** (`adapter/out/...`) + the `build_use_cases` composition factory.
|
|
87
|
+
- **`generic_ml_cache_core.testing.InMemoryExecutionRepository`** — a dependency-free
|
|
88
|
+
reference adapter to test your code against the ports.
|
|
89
|
+
|
|
90
|
+
Inbound drivers —
|
|
91
|
+
[`gmlcache`](https://github.com/danielslobozian/generic-ml-cache/tree/main/packages/cli)
|
|
92
|
+
today, a daemon later — map their surface (a terminal, a REST API) onto these public
|
|
93
|
+
APIs; the core itself has no UI and reads no config file.
|
|
94
|
+
|
|
95
|
+
## Links
|
|
96
|
+
|
|
97
|
+
- **Repository & docs:** <https://github.com/danielslobozian/generic-ml-cache>
|
|
98
|
+
- **Changelog** (both packages, versioned in lockstep): [`CHANGELOG.md`](https://github.com/danielslobozian/generic-ml-cache/blob/main/CHANGELOG.md)
|
|
99
|
+
- **Security policy:** [`SECURITY.md`](https://github.com/danielslobozian/generic-ml-cache/blob/main/SECURITY.md)
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
Apache-2.0 — see [`LICENSE`](https://github.com/danielslobozian/generic-ml-cache/blob/main/LICENSE)
|
|
104
|
+
and [`NOTICE`](https://github.com/danielslobozian/generic-ml-cache/blob/main/NOTICE).
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
generic_ml_cache_core/__init__.py,sha256=YFP5MttqlFpwig_h08W_a3QqbwyCD3Jhac60HbFeSbo,2053
|
|
2
|
+
generic_ml_cache_core/stream.py,sha256=a2hIsedn7zqywkBe5cMw-nV5rU02CkTfyEYOJ_ypWIc,2793
|
|
3
|
+
generic_ml_cache_core/adapter/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
4
|
+
generic_ml_cache_core/adapter/inbound/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
5
|
+
generic_ml_cache_core/adapter/inbound/composition.py,sha256=gVmHhSsMtf2D_PHpm5pxJZudnVsXLVexTvfTRQbgm3g,4017
|
|
6
|
+
generic_ml_cache_core/adapter/out/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
7
|
+
generic_ml_cache_core/adapter/out/api/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
8
|
+
generic_ml_cache_core/adapter/out/api/stub_api_client_adapter.py,sha256=KPlpGue5V64XBcZCmZy_NQjowdCajkcTA2rz6VFpugU,1521
|
|
9
|
+
generic_ml_cache_core/adapter/out/client/__init__.py,sha256=54Rt2Fjo_46yhXAM-Xu_TeszJVXvvMRwXJtQq8bbVRQ,978
|
|
10
|
+
generic_ml_cache_core/adapter/out/client/claude.py,sha256=upoXwuzopFIfLimLQCt1CrFhpe6a08-AWdfLgUzZYrY,9310
|
|
11
|
+
generic_ml_cache_core/adapter/out/client/codex.py,sha256=T4uey-iC4AIbKGJMvEfl6mOPgQkR9osBxh9M-m4tgCU,7400
|
|
12
|
+
generic_ml_cache_core/adapter/out/client/cursor.py,sha256=9cstycJXAGm0DfmrmaKCyTPs0aExq1NkBtO1AAIGiZM,9590
|
|
13
|
+
generic_ml_cache_core/adapter/out/client/discover.py,sha256=TUeQQP5M8y8VKUJqCI6Cshvrh1pmTVUwIQrshZpjzFU,4882
|
|
14
|
+
generic_ml_cache_core/adapter/out/client/isolation.py,sha256=q2ON_VOTBPZKnK-CFRuPyr4uSYQYpMoypm1R68-N0Cg,15851
|
|
15
|
+
generic_ml_cache_core/adapter/out/client/local_client_runner.py,sha256=JmNlDFHeFowEfSWFeAyPM6f5X40fzo4H7eXZN222chc,2435
|
|
16
|
+
generic_ml_cache_core/adapter/out/client/passthrough_client_runner.py,sha256=ae7v0AJc2PXTY0vOMPd2gXDU73qcTxVEbAAkgg8APlw,1919
|
|
17
|
+
generic_ml_cache_core/adapter/out/client/prime_directive.py,sha256=S5O8ggEQJWe61QI1IQhFot4qlTsQbuyF7nOgWWVBGms,2525
|
|
18
|
+
generic_ml_cache_core/adapter/out/client/registry.py,sha256=kqKoTxaUbPKcbn3izXdbqSgCbni9ElI0x43ZUhY0KkU,1011
|
|
19
|
+
generic_ml_cache_core/adapter/out/clock/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
20
|
+
generic_ml_cache_core/adapter/out/clock/system_clock.py,sha256=wOhuOmWKF4VAo-7X2ZKOOebhNo2QZJATatmWuwt15MA,466
|
|
21
|
+
generic_ml_cache_core/adapter/out/fingerprint/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
22
|
+
generic_ml_cache_core/adapter/out/fingerprint/filesystem_file_fingerprint.py,sha256=_TErnfPykePUULxXm-uF6AIKJtfVt-pD1d-8BtSCltU,1235
|
|
23
|
+
generic_ml_cache_core/adapter/out/metrics/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
24
|
+
generic_ml_cache_core/adapter/out/metrics/access_registry.py,sha256=oUfI3tzokgohq-irsGhpLdc8wXBZkjQmzkz_qyWz_BU,5286
|
|
25
|
+
generic_ml_cache_core/adapter/out/metrics/journal_metrics.py,sha256=ypP0JAo42sbvtlv2nXGSjE7lAygmONt6tiNuEanudJE,1503
|
|
26
|
+
generic_ml_cache_core/adapter/out/persistence/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
27
|
+
generic_ml_cache_core/adapter/out/persistence/call_identity_serialization.py,sha256=tto1R0n4hy2Tgbvhrs4ugZao44Gvvj47a0FHxDEMJN8,4069
|
|
28
|
+
generic_ml_cache_core/adapter/out/persistence/in_memory_execution_repository.py,sha256=yJ_1CoNU5iLq42kvYTxbEeFMIBIJf9AiFSOlAvH7JsY,3033
|
|
29
|
+
generic_ml_cache_core/adapter/out/persistence/sqlite_execution_repository.py,sha256=sdInMD93fXvdcYSM6NtVHCRk0hS6TtGaS6fz9p_7qt4,15356
|
|
30
|
+
generic_ml_cache_core/adapter/out/storage/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
31
|
+
generic_ml_cache_core/adapter/out/storage/filesystem_blob_store.py,sha256=KcvDtLkRc8kv04nH_HnmBqjx5hVchW-J3XqCM0Oarcc,1565
|
|
32
|
+
generic_ml_cache_core/application/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
33
|
+
generic_ml_cache_core/application/domain/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
34
|
+
generic_ml_cache_core/application/domain/model/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
35
|
+
generic_ml_cache_core/application/domain/model/client_status.py,sha256=uSNwPAqvCyit7jknjts_hf6Oq5N5EbbpvanqRQCjFkQ,477
|
|
36
|
+
generic_ml_cache_core/application/domain/model/model_info.py,sha256=Rzyl0WB7Us1ZrEbHOV6tTksQsAu64J2rIf58aiOtMgI,511
|
|
37
|
+
generic_ml_cache_core/application/domain/model/model_listing.py,sha256=fz54OyNNwQZ1yXOsO-U5Z_Sm7fED5tZDeaSNSaPKXgo,860
|
|
38
|
+
generic_ml_cache_core/application/domain/model/parsed_output.py,sha256=kfxYCLtkdMLr4mAv0YSe8rDOOqeIH-mFmHOdS8tm1Bk,738
|
|
39
|
+
generic_ml_cache_core/application/domain/model/execution/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
40
|
+
generic_ml_cache_core/application/domain/model/execution/artifact.py,sha256=b1lXMoDxhJIzOiex2u1F5Q9jHGpf9hDMUpF4bugCkBM,2262
|
|
41
|
+
generic_ml_cache_core/application/domain/model/execution/execution_failure.py,sha256=KvUZyLivH6YsjJd5eaZitE21sRW0UJhrFuq_-ulU4-E,931
|
|
42
|
+
generic_ml_cache_core/application/domain/model/execution/execution_kind.py,sha256=_fBpNKWQS8AmcgcTglFzDCIyma9bmalJJteAw__QjbI,1033
|
|
43
|
+
generic_ml_cache_core/application/domain/model/execution/execution_state.py,sha256=N4TNnuRuusr0ROMiHdiOAn-r1zibhznGv2fJOnxGNkg,516
|
|
44
|
+
generic_ml_cache_core/application/domain/model/execution/ml_execution.py,sha256=3GYdv2_mZ36ZYdKMCZK-KhJKHguKDt5heWB3ajSd8Bc,1775
|
|
45
|
+
generic_ml_cache_core/application/domain/model/identity/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
46
|
+
generic_ml_cache_core/application/domain/model/identity/api_call_identity.py,sha256=A-RRECEr0B2KxokgOi-iwKCJU3bIQkVggAcIjhX9KAk,1212
|
|
47
|
+
generic_ml_cache_core/application/domain/model/identity/call_identity.py,sha256=Y_XI0mEvhmVaQD51jClgS1nZI8RV4PDoiDK8zEcHcjw,887
|
|
48
|
+
generic_ml_cache_core/application/domain/model/identity/managed_call_identity.py,sha256=3nIqidUEwPxI5WzgFD0x-ZDIzo1wC9yLboxhz6v-UkI,2300
|
|
49
|
+
generic_ml_cache_core/application/domain/model/identity/passthrough_call_identity.py,sha256=oSyRvuukrQRqdG2wf1HTB_TM0f9a8Kcuq8wcO0HxOXo,1285
|
|
50
|
+
generic_ml_cache_core/application/domain/model/probe/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
51
|
+
generic_ml_cache_core/application/domain/model/probe/probe_report.py,sha256=JkK1dcY_D2Q7to087Sk5I1Aa1nOf29aFizac5TeSXI8,868
|
|
52
|
+
generic_ml_cache_core/application/domain/model/probe/probe_status.py,sha256=CEDX4hGAEZL36HlKxzOYb08YygFCLwhdZqmSfUwyx2k,381
|
|
53
|
+
generic_ml_cache_core/application/domain/model/run/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
54
|
+
generic_ml_cache_core/application/domain/model/run/cache_mode.py,sha256=_DnxIzowMTiZl3gWiuFXWtNI02vayXlOYdfm9iqela4,557
|
|
55
|
+
generic_ml_cache_core/application/domain/model/run/client_run_request.py,sha256=ymp_azgY9D3eU8W-VjP5FiQKHhRtPg980Fi7s-I2AmE,1285
|
|
56
|
+
generic_ml_cache_core/application/domain/model/run/client_run_result.py,sha256=3PwE5rzftECOOhiyq6TdyoRpKIdjY98WKsqWnTNXH_c,2311
|
|
57
|
+
generic_ml_cache_core/application/domain/model/run/message.py,sha256=wqCwlvJAlzE-1R7XXMmIyshj8aJLB21f6x864Td_cLE,562
|
|
58
|
+
generic_ml_cache_core/application/domain/model/usage/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
59
|
+
generic_ml_cache_core/application/domain/model/usage/token_usage.py,sha256=r1XTjyBzfoWtg_ZnoNza23YQQm4BBPbgj93L0X6An2E,2186
|
|
60
|
+
generic_ml_cache_core/application/domain/model/usage/usage.py,sha256=A-KZRE0A7rIj0o5VjOVqDFfaJeUpgWUl4EMJ4MBkWao,5037
|
|
61
|
+
generic_ml_cache_core/application/domain/service/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
62
|
+
generic_ml_cache_core/application/domain/service/cacheability.py,sha256=59YHGtzle-VEUyXsv79pHwp5qQ3dFoxr2HYM9lXTG8Q,806
|
|
63
|
+
generic_ml_cache_core/application/domain/service/message_fingerprinting.py,sha256=XhnFmvXky2F7eqfYVsGyQo2uGskIv7Jr3_FRjUyBp88,971
|
|
64
|
+
generic_ml_cache_core/application/port/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
65
|
+
generic_ml_cache_core/application/port/inbound/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
66
|
+
generic_ml_cache_core/application/port/inbound/probe_command.py,sha256=YTz0CFqY-tDIrJFLdItGGdGMNpyGViXSpAzpbpMpqBk,1123
|
|
67
|
+
generic_ml_cache_core/application/port/inbound/probe_use_case.py,sha256=iA1ljXweAz-TArbsmGA6TXmszc-sC1Brfeg59rey9j8,726
|
|
68
|
+
generic_ml_cache_core/application/port/inbound/run_api_execution_command.py,sha256=Le1eIyrSiKQIpV0rHtjoI_9eh5M_pZMPuS5cvAQqzlA,1491
|
|
69
|
+
generic_ml_cache_core/application/port/inbound/run_api_execution_use_case.py,sha256=IipBD4plrpHZTafWaHkSOATxvOJgQ4gDGDSAjZogffc,697
|
|
70
|
+
generic_ml_cache_core/application/port/inbound/run_managed_local_execution_command.py,sha256=ILuvQ5R-HMmL0RMByPkj0GRrmPOQjpFMBmNq5GNAjGM,1760
|
|
71
|
+
generic_ml_cache_core/application/port/inbound/run_managed_local_execution_use_case.py,sha256=xDLfF-02weweXlQRXimZPJUplF5tNtAhabQuN2hW39c,923
|
|
72
|
+
generic_ml_cache_core/application/port/inbound/run_passthrough_execution_command.py,sha256=GtAoe5UXCGPS3_PcJ-PPNQ-upFMMSb-AdrkB7kBdDM0,1239
|
|
73
|
+
generic_ml_cache_core/application/port/inbound/run_passthrough_execution_use_case.py,sha256=T_I7IpB-Qwia6MGg17IJ7kQ-m1bjmhrQjODW_cyiJek,749
|
|
74
|
+
generic_ml_cache_core/application/port/out/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
75
|
+
generic_ml_cache_core/application/port/out/api_client_port.py,sha256=16CjfOFjEXFabsVpQq_Gk7X7-MF2qMz2DuKVCsgTNWc,1047
|
|
76
|
+
generic_ml_cache_core/application/port/out/base.py,sha256=_YXmS2xcIJL8U3lzJswAKOM8QrQkY34GP8OnUhGy_Zc,12958
|
|
77
|
+
generic_ml_cache_core/application/port/out/blob_store_port.py,sha256=llWgt3Fsl55MlJGDGoOxHDijDfPHivVqzPqGBbgxA9g,1336
|
|
78
|
+
generic_ml_cache_core/application/port/out/client_runner_port.py,sha256=ZJxMrAcrEtLgdK3yTJe3Cv6bqjI2OjcfIcOMxfQZKKM,1081
|
|
79
|
+
generic_ml_cache_core/application/port/out/clock_port.py,sha256=Ai5JxLlvIaQ8JXKbCWJ_QtZZjkucy6sK25nSddxk7Zw,699
|
|
80
|
+
generic_ml_cache_core/application/port/out/execution_repository_port.py,sha256=j86EyxbzHSaMubFJ3cg1xdx4Vpj3c5blq7oRhhUFYoo,1708
|
|
81
|
+
generic_ml_cache_core/application/port/out/file_fingerprint_port.py,sha256=ZXyJq7LFRVWfgpvYFTraAl5k5iU9vozckEciQ-hDs2U,907
|
|
82
|
+
generic_ml_cache_core/application/port/out/metrics_port.py,sha256=DxHL2eTKa7jd4UV846qcXP9fV8MZjEzo01j5Ja_-QbA,1634
|
|
83
|
+
generic_ml_cache_core/application/port/out/passthrough_runner_port.py,sha256=8wxsdJ3Lj65m0QPjOhm4inf8QqeEFhIZus8Do7cQTMI,968
|
|
84
|
+
generic_ml_cache_core/application/usecase/__init__.py,sha256=nuehNF41p14kRWK8rgjE0dNwDo6-Jqqa4M2wTMTx8Z4,31
|
|
85
|
+
generic_ml_cache_core/application/usecase/cached_ml_execution_service.py,sha256=ZEdtMoYAzOfVFqmNFfZrjIkzHnJtlCNxEtvDQ0aPGCI,8880
|
|
86
|
+
generic_ml_cache_core/application/usecase/call_identity_building.py,sha256=1giUpsOEp_zRuJbhMvvn11f6xvkK_-RJNNif1rNzZZY,2217
|
|
87
|
+
generic_ml_cache_core/application/usecase/journal_events.py,sha256=UrEVD-4hGQxTXQ9btjaazh_zuEqW0wJMjksA9civaRs,710
|
|
88
|
+
generic_ml_cache_core/application/usecase/probe_service.py,sha256=HgiXc6_PFnJF-mXN126h0VnJZleQUMcQGq1j1UaTw80,2040
|
|
89
|
+
generic_ml_cache_core/application/usecase/run_api_execution_service.py,sha256=XoLLpgKR0Sf9-FXKNrUF78__2VkGXMoLA22zLkpLoNM,2907
|
|
90
|
+
generic_ml_cache_core/application/usecase/run_managed_local_execution_service.py,sha256=QCCS3EWfye2pns0YbSfwpwRDSjX49CsScOWIldyoGHQ,3862
|
|
91
|
+
generic_ml_cache_core/application/usecase/run_passthrough_execution_service.py,sha256=x0hI_VE8Cp3cZBWiU7AVZeSJAD4AZ9y6rCZlR7epJEA,3048
|
|
92
|
+
generic_ml_cache_core/common/__init__.py,sha256=joTT8UX3dPEgh1e2GC8gq3crhw0i7C6J-HfS2vnP88Y,85
|
|
93
|
+
generic_ml_cache_core/common/checksum.py,sha256=1p9Yhsh3WmB7r0H5x5zUABMyg7_0D_TwgvxzUtZU-HM,3361
|
|
94
|
+
generic_ml_cache_core/common/errors.py,sha256=aP3Udm7ftusGdQQsrzgXFM9_GHc37Dd60dZy0vMz-XM,2745
|
|
95
|
+
generic_ml_cache_core-0.2.0.dist-info/METADATA,sha256=fGNRAlf4jHyImexYTqQtw99pq3WByCr7PaMn1DzA2Zg,5015
|
|
96
|
+
generic_ml_cache_core-0.2.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
97
|
+
generic_ml_cache_core-0.2.0.dist-info/licenses/LICENSE,sha256=de-gfE0q-xTYImzwC3dj3S7BxVhanf6RmIGjo_7y3aw,11357
|
|
98
|
+
generic_ml_cache_core-0.2.0.dist-info/licenses/NOTICE,sha256=hQoAdw5YSwg3GmeY8hmy9nyOh20La-Qc6mre-TKpn5M,329
|
|
99
|
+
generic_ml_cache_core-0.2.0.dist-info/RECORD,,
|