nisse-core: group modules into packages by architecture section
A pure move; behaviour unchanged. - models (L9, L7): llm, catalog, probe, render, render_anthropic, context - log (L7, L6): canonical, views - state (L8): store (was state), reconcile, worker, cancel, dump - knowledge (L10, L6.4): vault, memory - conversation (L5): transport, matrix - execution (L13): ssh (was execution), testing - authority (P3, P4, L4): actions - gitea, oplog, envfile stay at the top until each gains a second module. Every import, monkeypatch target, script and doc reference rewritten. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
1 parent
06759d5d70
commit
e351d0a74e
117 files changed
+291
-265
No files matched your search
+19
-17
@@ -1,22 +1,24 @@
|
||||
# nisse-core
|
||||
|
||||
The shared library the Nisse agents sit on (Part L of the architecture). It
|
||||
never imports an agent.
|
||||
never imports an agent. Packages follow the architecture's sections:
|
||||
|
||||
- **Transcript and models:** `canonical` (the log's events, L7), `render` and
|
||||
`render_anthropic`, `llm` (the one client, L9), `catalog` and `probe` (what
|
||||
the models are), `context` (fitting a request to its window, L6), `views`
|
||||
(what each role is shown of the others).
|
||||
- **Durability:** `state` (the store, L8; an agent subclasses it for its own
|
||||
tables, roles and views), `reconcile`, `worker`, `cancel`, `dump`.
|
||||
- **Conversation:** `transport`, `matrix` (L5).
|
||||
- **Execution:** `execution` (SSH to a tool VM, L13); `testing` (a throwaway
|
||||
sshd for tests).
|
||||
- **Knowledge:** `vault` (L10), `memory` (L6.4).
|
||||
- **Operations:** `oplog`, `envfile` (L12); `gitea` (the tracker and forge, L1).
|
||||
- **Authority:** `actions` (P3, P4, L4): `Action`, `Verdict`, and static
|
||||
reading of shell commands, which each agent's fast-path rules build on
|
||||
(`nisse-dev`'s are in `nisse_dev.loop.actions`).
|
||||
- `models` (L9, L7): `llm` (the one client), `catalog` and `probe` (what the
|
||||
models are), `render` and `render_anthropic` (request bodies from the log),
|
||||
`context` (fitting a request to its window, L6).
|
||||
- `log` (L7, L6): `canonical` (the log's events), `views` (what each role is
|
||||
shown of the others).
|
||||
- `state` (L8): `store` (an agent subclasses `StateStore` for its own tables,
|
||||
roles and views), `reconcile`, `worker`, `cancel`, `dump`.
|
||||
- `knowledge` (L10, L6.4): `vault`, `memory`.
|
||||
- `conversation` (L5): `transport`, `matrix`.
|
||||
- `execution` (L13): `ssh` (SSH to a tool VM); `testing` (a throwaway sshd for
|
||||
tests).
|
||||
- `authority` (P3, P4, L4): `actions` (`Action`, `Verdict`, and static reading of
|
||||
shell commands, which each agent's fast-path rules build on; `nisse-dev`'s are
|
||||
in `nisse_dev.loop.actions`).
|
||||
- At the top, until each gains a second module: `gitea` (the tracker and forge,
|
||||
L1), `oplog` and `envfile` (L12).
|
||||
|
||||
The loop is still `nisse-dev`'s, until `nisse-ops` has one to share it with
|
||||
(Development Plan M7.2).
|
||||
The parts of a loop (`loop`) and shared configuration arrive with Development
|
||||
Plan M7.2; each agent keeps its own scheduler.
|
||||
@@ -0,0 +1 @@
|
||||
"""Actions by their effects (architecture P3, P4, L3, L4)."""
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
"""Conversation with the operator (architecture L5)."""
|
||||
+1
-1
@@ -27,7 +27,7 @@ from urllib.parse import unquote
|
||||
|
||||
import httpx
|
||||
|
||||
from nisse_core.transport import InboundMessage
|
||||
from nisse_core.conversation.transport import InboundMessage
|
||||
|
||||
# A mention pill at the start of an HTML body: the link holds the user ID,
|
||||
# the link text is what the plain body starts with.
|
||||
File renamed without changes.
@@ -0,0 +1 @@
|
||||
"""Running commands on tool VMs over SSH (architecture L13)."""
|
||||
File renamed without changes.
+1
-1
@@ -14,7 +14,7 @@ from collections.abc import Iterator
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from nisse_core.execution import SSHHost
|
||||
from nisse_core.execution.ssh import SSHHost
|
||||
|
||||
SSHD = "/usr/sbin/sshd"
|
||||
|
||||
@@ -16,8 +16,8 @@ from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
from nisse_core.reconcile import Reconciler
|
||||
from nisse_core.state import Intent
|
||||
from nisse_core.state.reconcile import Reconciler
|
||||
from nisse_core.state.store import Intent
|
||||
|
||||
PR_PAGE_SIZE = 50
|
||||
MAX_PR_PAGES = 40 # 2000 PRs; beyond that, say so rather than guess
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
"""The knowledge vault (architecture L10) and agent memory (L6.4)."""
|
||||
@@ -14,7 +14,7 @@ from dataclasses import dataclass
|
||||
|
||||
import yaml
|
||||
|
||||
from nisse_core.vault import Vault, VaultError, split_frontmatter
|
||||
from nisse_core.knowledge.vault import Vault, VaultError, split_frontmatter
|
||||
|
||||
INDEX = "index" # the note the harness keeps; never the model's
|
||||
_NAME = re.compile(r"[a-z0-9][a-z0-9-]{0,63}")
|
||||
File renamed without changes.
@@ -0,0 +1,2 @@
|
||||
"""The canonical log (architecture L7) and what each role is shown of it
|
||||
(L6)."""
|
||||
File renamed without changes.
@@ -20,7 +20,7 @@ ranges still line up with the log. Everything not the viewer's own becomes a
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import replace
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
ActionVerdict,
|
||||
AssistantText,
|
||||
DelegationCompleted,
|
||||
@@ -0,0 +1,2 @@
|
||||
"""Talking to models (architecture L9): the client, what the models are, and
|
||||
the request bodies built from the log (L7)."""
|
||||
@@ -19,7 +19,7 @@ from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
from nisse_core.llm import LLMClient, LLMError
|
||||
from nisse_core.models.llm import LLMClient, LLMError
|
||||
|
||||
# LiteLLM's provider name for models we have a vendor-native adapter for.
|
||||
ANTHROPIC_PROVIDER = "anthropic"
|
||||
@@ -28,7 +28,7 @@ from collections.abc import Callable, Sequence
|
||||
from dataclasses import dataclass, replace
|
||||
from typing import Any
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
CanonicalEvent,
|
||||
DelegationStarted,
|
||||
@@ -38,7 +38,7 @@ from nisse_core.canonical import (
|
||||
ToolResult,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.llm import DEFAULT_MAX_OUTPUT_TOKENS, LLMError
|
||||
from nisse_core.models.llm import DEFAULT_MAX_OUTPUT_TOKENS, LLMError
|
||||
|
||||
# English and code run at about four characters a token. Three is deliberately
|
||||
# pessimistic, before any correction from what the server reports.
|
||||
@@ -17,15 +17,15 @@ from typing import Any, ClassVar, Protocol
|
||||
|
||||
import httpx
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
CanonicalEvent,
|
||||
StoredEvent,
|
||||
ToolCall,
|
||||
mint_call_id,
|
||||
)
|
||||
from nisse_core.render import OpenAIChatRenderer
|
||||
from nisse_core.render_anthropic import AnthropicMessagesRenderer
|
||||
from nisse_core.models.render import OpenAIChatRenderer
|
||||
from nisse_core.models.render_anthropic import AnthropicMessagesRenderer
|
||||
|
||||
|
||||
class LLMError(RuntimeError):
|
||||
@@ -24,7 +24,7 @@ from dataclasses import dataclass
|
||||
|
||||
import httpx
|
||||
|
||||
from nisse_core.catalog import ModelFacts
|
||||
from nisse_core.models.catalog import ModelFacts
|
||||
|
||||
# Of a probe's size, how much must come back for it to count as uncut. A
|
||||
# chat template adds a little, and a tokenizer counts a little differently.
|
||||
@@ -11,7 +11,7 @@ this skeleton.
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
Compaction,
|
||||
DelegationCompleted,
|
||||
+2
-2
@@ -18,7 +18,7 @@ route and this renderer builds the vendor-native body.
|
||||
|
||||
from typing import Any
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
Compaction,
|
||||
DelegationCompleted,
|
||||
@@ -31,7 +31,7 @@ from nisse_core.canonical import (
|
||||
ToolResult,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.render import effective_events
|
||||
from nisse_core.models.render import effective_events
|
||||
|
||||
DEFAULT_MAX_TOKENS = 4096
|
||||
NO_RESULT_PLACEHOLDER = "[no result recorded]"
|
||||
@@ -0,0 +1,2 @@
|
||||
"""Durability (architecture L8): the state store, reconciliation, the worker
|
||||
thread and the kill switch."""
|
||||
@@ -8,8 +8,8 @@ record of a stop is written by the worker when the stopped work returns.
|
||||
|
||||
import threading
|
||||
|
||||
from nisse_core.canonical import ToolCall, ToolResult
|
||||
from nisse_core.state import Transcript
|
||||
from nisse_core.log.canonical import ToolCall, ToolResult
|
||||
from nisse_core.state.store import Transcript
|
||||
|
||||
STOPPED_RESULT = "not run: the operator stopped the agent"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""A readable dump of a state store, for bring-up runs and debugging.
|
||||
|
||||
python -m nisse_core.dump STATE_DB [--full]
|
||||
python -m nisse_core.state.dump STATE_DB [--full]
|
||||
|
||||
Opens the store read-only (SQLite `mode=ro`), so it is safe to run against a
|
||||
live agent's database: it never migrates, writes or locks it. Prints the work
|
||||
+1
-1
@@ -11,7 +11,7 @@ from collections.abc import Callable, Mapping
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
from nisse_core.state import Intent, StateStore
|
||||
from nisse_core.state.store import Intent, StateStore
|
||||
|
||||
# Returns True if the intent's external effect verifiably happened (do not
|
||||
# repeat it), False if it verifiably never started (safe to discard), or
|
||||
@@ -6,7 +6,7 @@ intent-log write is a single immediately-committed statement — in-memory state
|
||||
that hasn't hit disk is assumed lost.
|
||||
|
||||
The intent log records a unit of work *before* it starts, so a restart knows
|
||||
what was in flight (see ``nisse_core.reconcile`` for how pending intents are
|
||||
what was in flight (see ``nisse_core.state.reconcile`` for how pending intents are
|
||||
resolved against external truth on boot).
|
||||
"""
|
||||
|
||||
@@ -18,7 +18,7 @@ from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Self
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
CanonicalEvent,
|
||||
StoredEvent,
|
||||
UserMessage,
|
||||
@@ -26,8 +26,8 @@ from nisse_core.canonical import (
|
||||
from_payload,
|
||||
to_payload,
|
||||
)
|
||||
from nisse_core.log.views import project
|
||||
from nisse_core.oplog import OpLog
|
||||
from nisse_core.views import project
|
||||
|
||||
# The tables every agent has. An agent's own tables come on top: a subclass
|
||||
# names them, the version they bring, and the migrations to it.
|
||||
File renamed without changes.
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from nisse_core.actions import (
|
||||
from nisse_core.authority.actions import (
|
||||
CONTAINED,
|
||||
DANGEROUS,
|
||||
HARMLESS,
|
||||
|
||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
Compaction,
|
||||
DelegationCompleted,
|
||||
@@ -16,7 +16,7 @@ from nisse_core.canonical import (
|
||||
from_payload,
|
||||
mint_call_id,
|
||||
)
|
||||
from nisse_core.state import StateSchemaError, StateStore
|
||||
from nisse_core.state.store import StateSchemaError, StateStore
|
||||
|
||||
ALL_EVENTS = [
|
||||
UserMessage(text="use demo", source="matrix:$abc"),
|
||||
|
||||
@@ -8,7 +8,7 @@ route has to come from what LiteLLM says the model is.
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from nisse_core.catalog import (
|
||||
from nisse_core.models.catalog import (
|
||||
CatalogUnavailable,
|
||||
ModelCatalog,
|
||||
UnknownModel,
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
CanonicalEvent,
|
||||
StoredEvent,
|
||||
@@ -14,8 +14,8 @@ from nisse_core.canonical import (
|
||||
ToolResult,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.catalog import ModelCatalog, UnknownLimits
|
||||
from nisse_core.context import (
|
||||
from nisse_core.models.catalog import ModelCatalog, UnknownLimits
|
||||
from nisse_core.models.context import (
|
||||
Budget,
|
||||
BudgetedClient,
|
||||
ContextOverflow,
|
||||
@@ -24,7 +24,7 @@ from nisse_core.context import (
|
||||
head_and_tail,
|
||||
)
|
||||
from nisse_core.oplog import OpLog
|
||||
from nisse_core.state import StateStore
|
||||
from nisse_core.state.store import StateStore
|
||||
from nisse_dev.loop.driver import Driver
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import io
|
||||
from pathlib import Path
|
||||
|
||||
from nisse_core.canonical import Fact, PlanSubmitted, ToolCall, ToolResult, UserMessage
|
||||
from nisse_core.dump import main, render
|
||||
from nisse_core.log.canonical import (
|
||||
Fact,
|
||||
PlanSubmitted,
|
||||
ToolCall,
|
||||
ToolResult,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.oplog import OpLog
|
||||
from nisse_core.state import StateStore
|
||||
from nisse_core.state.dump import main, render
|
||||
from nisse_core.state.store import StateStore
|
||||
|
||||
|
||||
def store_with_a_run(path: Path) -> None:
|
||||
|
||||
@@ -5,7 +5,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from nisse_core.execution import REDACTED, HostUnavailable, SSHHost, redact
|
||||
from nisse_core.execution.ssh import REDACTED, HostUnavailable, SSHHost, redact
|
||||
|
||||
|
||||
def test_exit_codes_and_streams_come_back(ssh_host: SSHHost) -> None:
|
||||
@@ -82,7 +82,7 @@ def test_a_changed_host_key_is_its_own_failure_and_only_forgetting_clears_it(
|
||||
) -> None:
|
||||
import subprocess
|
||||
|
||||
from nisse_core.execution import HostKeyChanged
|
||||
from nisse_core.execution.ssh import HostKeyChanged
|
||||
|
||||
host = SSHHost(
|
||||
ssh_host.address,
|
||||
|
||||
@@ -10,7 +10,7 @@ from nisse_core.gitea import (
|
||||
GiteaError,
|
||||
pull_request_reconciler,
|
||||
)
|
||||
from nisse_core.state import Intent
|
||||
from nisse_core.state.store import Intent
|
||||
|
||||
INTENT = Intent(
|
||||
id=1,
|
||||
|
||||
@@ -5,14 +5,14 @@ from typing import Any
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.envfile import load_env_file
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
StoredEvent,
|
||||
ToolCall,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.envfile import load_env_file
|
||||
from nisse_core.llm import (
|
||||
from nisse_core.models.llm import (
|
||||
DEFAULT_MAX_OUTPUT_TOKENS,
|
||||
OUTAGE_BACKOFF_S,
|
||||
RATE_LIMIT_RETRY_S,
|
||||
|
||||
@@ -4,8 +4,8 @@ import threading
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from nisse_core.matrix import MatrixConfig, MatrixTransport, TransportError
|
||||
from nisse_core.transport import InboundMessage
|
||||
from nisse_core.conversation.matrix import MatrixConfig, MatrixTransport, TransportError
|
||||
from nisse_core.conversation.transport import InboundMessage
|
||||
|
||||
CONFIG = MatrixConfig(
|
||||
homeserver="https://matrix.test",
|
||||
@@ -349,7 +349,7 @@ def test_a_reply_to_the_operators_own_threaded_message_joins_the_thread() -> Non
|
||||
|
||||
|
||||
def test_in_memory_transport_plays_threads() -> None:
|
||||
from nisse_core.transport import InMemoryTransport
|
||||
from nisse_core.conversation.transport import InMemoryTransport
|
||||
|
||||
transport = InMemoryTransport()
|
||||
seen: list[InboundMessage] = []
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from nisse_core.memory import Memory
|
||||
from nisse_core.vault import Vault, VaultError, split_frontmatter
|
||||
from nisse_core.knowledge.memory import Memory
|
||||
from nisse_core.knowledge.vault import Vault, VaultError, split_frontmatter
|
||||
|
||||
FOLDER = "memory/nisse-dev"
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from nisse_core.oplog import OpLog
|
||||
from nisse_core.reconcile import reconcile_on_boot
|
||||
from nisse_core.state import StateStore
|
||||
from nisse_core.state.reconcile import reconcile_on_boot
|
||||
from nisse_core.state.store import StateStore
|
||||
|
||||
ENVELOPE_FIELDS = {"ts", "agent", "event", "task_id", "cause"}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
|
||||
import httpx
|
||||
|
||||
from nisse_core.probe import interpret, probe
|
||||
from nisse_core.models.probe import interpret, probe
|
||||
|
||||
|
||||
def test_a_cut_at_the_declared_window_matches() -> None:
|
||||
|
||||
@@ -2,8 +2,8 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from nisse_core.reconcile import reconcile_on_boot
|
||||
from nisse_core.state import Intent, StateStore
|
||||
from nisse_core.state.reconcile import reconcile_on_boot
|
||||
from nisse_core.state.store import Intent, StateStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import json
|
||||
from itertools import pairwise
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
Compaction,
|
||||
GateOpened,
|
||||
@@ -10,7 +10,7 @@ from nisse_core.canonical import (
|
||||
ToolResult,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.render import OpenAIChatRenderer, effective_events
|
||||
from nisse_core.models.render import OpenAIChatRenderer, effective_events
|
||||
|
||||
|
||||
def stored(events: list) -> list[StoredEvent]:
|
||||
|
||||
@@ -4,7 +4,7 @@ these tests pin the differences that a normalising middlebox would blur."""
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
Compaction,
|
||||
StoredEvent,
|
||||
@@ -12,8 +12,8 @@ from nisse_core.canonical import (
|
||||
ToolResult,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.llm import AnthropicPassthroughClient, LLMError
|
||||
from nisse_core.render_anthropic import (
|
||||
from nisse_core.models.llm import AnthropicPassthroughClient, LLMError
|
||||
from nisse_core.models.render_anthropic import (
|
||||
AnthropicMessagesRenderer,
|
||||
to_anthropic_tools,
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from nisse_core.state import StateSchemaError, StateStore
|
||||
from nisse_core.state.store import StateSchemaError, StateStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -9,8 +9,8 @@ from pathlib import Path
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from nisse_core import vault as vault_module
|
||||
from nisse_core.vault import Vault, VaultError, split_frontmatter
|
||||
from nisse_core.knowledge import vault as vault_module
|
||||
from nisse_core.knowledge.vault import Vault, VaultError, split_frontmatter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -4,7 +4,7 @@ import io
|
||||
from collections.abc import Mapping
|
||||
from pathlib import Path
|
||||
|
||||
from nisse_core.canonical import (
|
||||
from nisse_core.log.canonical import (
|
||||
AssistantText,
|
||||
DelegationCompleted,
|
||||
DelegationStarted,
|
||||
@@ -15,10 +15,10 @@ from nisse_core.canonical import (
|
||||
ToolResult,
|
||||
UserMessage,
|
||||
)
|
||||
from nisse_core.models.render import OpenAIChatRenderer
|
||||
from nisse_core.models.render_anthropic import AnthropicMessagesRenderer
|
||||
from nisse_core.oplog import OpLog
|
||||
from nisse_core.render import OpenAIChatRenderer
|
||||
from nisse_core.render_anthropic import AnthropicMessagesRenderer
|
||||
from nisse_core.state import StateStore
|
||||
from nisse_core.state.store import StateStore
|
||||
|
||||
|
||||
class Store(StateStore):
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from nisse_core.oplog import OpLog
|
||||
from nisse_core.state import StateStore
|
||||
from nisse_core.worker import InlineWorker, SerialWorker
|
||||
from nisse_core.state.store import StateStore
|
||||
from nisse_core.state.worker import InlineWorker, SerialWorker
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
Reference in new issue
Block a user