krons 0.2.2__py3-none-any.whl → 0.2.3__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.
- krons/core/base/__init__.py +0 -4
- krons/core/base/flow.py +7 -0
- krons/session/session.py +54 -49
- {krons-0.2.2.dist-info → krons-0.2.3.dist-info}/METADATA +1 -1
- {krons-0.2.2.dist-info → krons-0.2.3.dist-info}/RECORD +7 -8
- krons/core/base/log.py +0 -32
- {krons-0.2.2.dist-info → krons-0.2.3.dist-info}/WHEEL +0 -0
- {krons-0.2.2.dist-info → krons-0.2.3.dist-info}/licenses/LICENSE +0 -0
krons/core/base/__init__.py
CHANGED
|
@@ -26,8 +26,6 @@ _LAZY_IMPORTS: dict[str, tuple[str, str]] = {
|
|
|
26
26
|
"Edge": ("krons.core.base.graph", "Edge"),
|
|
27
27
|
"EdgeCondition": ("krons.core.base.graph", "EdgeCondition"),
|
|
28
28
|
"Graph": ("krons.core.base.graph", "Graph"),
|
|
29
|
-
# log
|
|
30
|
-
"DataLoggerConfig": ("krons.core.base.log", "DataLoggerConfig"),
|
|
31
29
|
# node
|
|
32
30
|
"NODE_REGISTRY": ("krons.core.base.node", "NODE_REGISTRY"),
|
|
33
31
|
"PERSISTABLE_NODE_REGISTRY": ("krons.core.base.node", "PERSISTABLE_NODE_REGISTRY"),
|
|
@@ -79,7 +77,6 @@ if TYPE_CHECKING:
|
|
|
79
77
|
from .eventbus import EventBus, Handler
|
|
80
78
|
from .flow import Flow
|
|
81
79
|
from .graph import Edge, EdgeCondition, Graph
|
|
82
|
-
from .log import DataLoggerConfig
|
|
83
80
|
from .node import (
|
|
84
81
|
NODE_REGISTRY,
|
|
85
82
|
PERSISTABLE_NODE_REGISTRY,
|
|
@@ -100,7 +97,6 @@ __all__ = [
|
|
|
100
97
|
"PERSISTABLE_NODE_REGISTRY",
|
|
101
98
|
# classes
|
|
102
99
|
"Broadcaster",
|
|
103
|
-
"DataLoggerConfig",
|
|
104
100
|
"Edge",
|
|
105
101
|
"EdgeCondition",
|
|
106
102
|
"Element",
|
krons/core/base/flow.py
CHANGED
|
@@ -321,6 +321,13 @@ class Flow(Element, Generic[E, P]):
|
|
|
321
321
|
|
|
322
322
|
return self.items.remove(uid)
|
|
323
323
|
|
|
324
|
+
@synchronized
|
|
325
|
+
def clear(self) -> None:
|
|
326
|
+
"""Clear all items and progressions."""
|
|
327
|
+
self.items.clear()
|
|
328
|
+
self.progressions.clear()
|
|
329
|
+
self._progression_names.clear()
|
|
330
|
+
|
|
324
331
|
def __repr__(self) -> str:
|
|
325
332
|
name_str = f", name='{self.name}'" if self.name else ""
|
|
326
333
|
return f"Flow(items={len(self.items)}, progressions={len(self.progressions)}{name_str})"
|
krons/session/session.py
CHANGED
|
@@ -14,11 +14,9 @@ import contextlib
|
|
|
14
14
|
from collections.abc import AsyncGenerator, Iterable
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
from typing import Any, Literal
|
|
17
|
-
|
|
18
|
-
from krons.core.base.log import DataLoggerConfig
|
|
19
17
|
from uuid import UUID
|
|
20
18
|
|
|
21
|
-
from pydantic import Field, PrivateAttr, model_validator
|
|
19
|
+
from pydantic import Field, PrivateAttr, field_serializer, model_validator
|
|
22
20
|
|
|
23
21
|
from krons.core import Element, Flow, Pile, Progression
|
|
24
22
|
from krons.core.types import HashableModel, Unset, UnsetType, not_sentinel
|
|
@@ -63,25 +61,41 @@ class SessionConfig(HashableModel):
|
|
|
63
61
|
default_gen_model: str | None = None
|
|
64
62
|
default_parse_model: str | None = None
|
|
65
63
|
auto_create_default_branch: bool = True
|
|
66
|
-
|
|
64
|
+
|
|
65
|
+
# Logging configuration
|
|
66
|
+
log_persist_dir: str | Path | None = Field(
|
|
67
67
|
default=None,
|
|
68
|
-
description="
|
|
68
|
+
description="Directory for session dumps. None disables logging.",
|
|
69
|
+
)
|
|
70
|
+
log_auto_save_on_exit: bool = Field(
|
|
71
|
+
default=True,
|
|
72
|
+
description="Register atexit handler on Session creation.",
|
|
69
73
|
)
|
|
70
74
|
|
|
75
|
+
@property
|
|
76
|
+
def logging_enabled(self) -> bool:
|
|
77
|
+
"""True if logging is configured (log_persist_dir is set)."""
|
|
78
|
+
return self.log_persist_dir is not None
|
|
79
|
+
|
|
71
80
|
|
|
72
81
|
class Session(Element):
|
|
73
82
|
user: str | None = None
|
|
74
83
|
communications: Flow[Message, Branch] = Field(
|
|
75
84
|
default_factory=lambda: Flow(item_type=Message)
|
|
76
85
|
)
|
|
77
|
-
resources: ResourceRegistry = Field(default_factory=ResourceRegistry)
|
|
78
|
-
operations: OperationRegistry = Field(default_factory=OperationRegistry)
|
|
86
|
+
resources: ResourceRegistry = Field(default_factory=ResourceRegistry, exclude=True)
|
|
87
|
+
operations: OperationRegistry = Field(default_factory=OperationRegistry, exclude=True)
|
|
79
88
|
config: SessionConfig = Field(default_factory=SessionConfig)
|
|
80
89
|
default_branch_id: UUID | None = None
|
|
81
90
|
|
|
82
91
|
_registered_atexit: bool = PrivateAttr(default=False)
|
|
83
92
|
_dump_count: int = PrivateAttr(default=0)
|
|
84
93
|
|
|
94
|
+
@field_serializer("communications")
|
|
95
|
+
def _serialize_communications(self, flow: Flow) -> dict:
|
|
96
|
+
"""Use Flow's custom to_dict for proper nested serialization."""
|
|
97
|
+
return flow.to_dict(mode="json")
|
|
98
|
+
|
|
85
99
|
@model_validator(mode="after")
|
|
86
100
|
def _validate_default_branch(self) -> Session:
|
|
87
101
|
"""Auto-create default branch and register built-in operations."""
|
|
@@ -96,8 +110,8 @@ class Session(Element):
|
|
|
96
110
|
|
|
97
111
|
# Register atexit handler if configured
|
|
98
112
|
if (
|
|
99
|
-
self.config.
|
|
100
|
-
and self.config.
|
|
113
|
+
self.config.logging_enabled
|
|
114
|
+
and self.config.log_auto_save_on_exit
|
|
101
115
|
and not self._registered_atexit
|
|
102
116
|
):
|
|
103
117
|
atexit.register(self._save_at_exit)
|
|
@@ -406,96 +420,87 @@ class Session(Element):
|
|
|
406
420
|
async for result in handler(params, ctx):
|
|
407
421
|
yield result
|
|
408
422
|
|
|
409
|
-
def
|
|
410
|
-
"""Sync dump
|
|
423
|
+
def dump(self, clear: bool = False) -> Path | None:
|
|
424
|
+
"""Sync dump entire session state for replay.
|
|
425
|
+
|
|
426
|
+
Serializes session (messages, branches, config) to JSON.
|
|
427
|
+
Resources and operations are excluded (re-register on restore).
|
|
428
|
+
To restore: Session.from_dict(data), then re-register resources.
|
|
411
429
|
|
|
412
430
|
Args:
|
|
413
|
-
clear: Clear
|
|
431
|
+
clear: Clear communications after dump (default False).
|
|
414
432
|
|
|
415
433
|
Returns:
|
|
416
|
-
Path to
|
|
434
|
+
Path to session file, or None if logging disabled or empty.
|
|
417
435
|
"""
|
|
418
|
-
from krons.utils import create_path, json_dumpb
|
|
436
|
+
from krons.utils import create_path, json_dumpb
|
|
419
437
|
from krons.utils.concurrency import run_async
|
|
420
438
|
|
|
421
|
-
if self.config.
|
|
439
|
+
if not self.config.logging_enabled or len(self.messages) == 0:
|
|
422
440
|
return None
|
|
423
441
|
|
|
424
|
-
cfg = self.config.log_config
|
|
425
442
|
self._dump_count += 1
|
|
426
443
|
|
|
427
444
|
filepath = run_async(
|
|
428
445
|
create_path(
|
|
429
|
-
directory=
|
|
446
|
+
directory=self.config.log_persist_dir,
|
|
430
447
|
filename=f"session_{str(self.id)[:8]}_{self._dump_count}",
|
|
431
|
-
extension=
|
|
448
|
+
extension=".json",
|
|
432
449
|
timestamp=True,
|
|
433
450
|
file_exist_ok=True,
|
|
434
451
|
)
|
|
435
452
|
)
|
|
436
453
|
|
|
437
|
-
|
|
438
|
-
|
|
454
|
+
data = json_dumpb(self.to_dict(mode="json"), safe_fallback=True)
|
|
439
455
|
std_path = Path(filepath)
|
|
440
|
-
|
|
441
|
-
with std_path.open("wb") as f:
|
|
442
|
-
for chunk in json_lines_iter(items, safe_fallback=True):
|
|
443
|
-
f.write(chunk)
|
|
444
|
-
else:
|
|
445
|
-
data = json_dumpb(items, safe_fallback=True)
|
|
446
|
-
std_path.write_bytes(data)
|
|
456
|
+
std_path.write_bytes(data)
|
|
447
457
|
|
|
448
458
|
if clear:
|
|
449
|
-
self.communications.
|
|
459
|
+
self.communications.clear()
|
|
450
460
|
|
|
451
461
|
return std_path
|
|
452
462
|
|
|
453
|
-
async def
|
|
454
|
-
"""Async dump
|
|
463
|
+
async def adump(self, clear: bool = False) -> Path | None:
|
|
464
|
+
"""Async dump entire session state for replay.
|
|
465
|
+
|
|
466
|
+
Serializes the full session (messages, branches, config) to JSON.
|
|
467
|
+
To restore: Session.from_dict(data), then re-register resources.
|
|
455
468
|
|
|
456
469
|
Args:
|
|
457
|
-
clear: Clear
|
|
470
|
+
clear: Clear communications after dump (default False).
|
|
458
471
|
|
|
459
472
|
Returns:
|
|
460
|
-
Path to
|
|
473
|
+
Path to session file, or None if logging disabled or empty.
|
|
461
474
|
"""
|
|
462
|
-
from krons.utils import create_path, json_dumpb
|
|
475
|
+
from krons.utils import create_path, json_dumpb
|
|
463
476
|
|
|
464
|
-
if self.config.
|
|
477
|
+
if not self.config.logging_enabled or len(self.messages) == 0:
|
|
465
478
|
return None
|
|
466
479
|
|
|
467
|
-
cfg = self.config.log_config
|
|
468
|
-
|
|
469
480
|
async with self.messages:
|
|
470
481
|
self._dump_count += 1
|
|
471
482
|
|
|
472
483
|
filepath = await create_path(
|
|
473
|
-
directory=
|
|
484
|
+
directory=self.config.log_persist_dir,
|
|
474
485
|
filename=f"session_{str(self.id)[:8]}_{self._dump_count}",
|
|
475
|
-
extension=
|
|
486
|
+
extension=".json",
|
|
476
487
|
timestamp=True,
|
|
477
488
|
file_exist_ok=True,
|
|
478
489
|
)
|
|
479
490
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if cfg.extension == ".jsonl":
|
|
483
|
-
content = b"".join(json_lines_iter(items, safe_fallback=True))
|
|
484
|
-
await filepath.write_bytes(content)
|
|
485
|
-
else:
|
|
486
|
-
data = json_dumpb(items, safe_fallback=True)
|
|
487
|
-
await filepath.write_bytes(data)
|
|
491
|
+
data = json_dumpb(self.to_dict(mode="json"), safe_fallback=True)
|
|
492
|
+
await filepath.write_bytes(data)
|
|
488
493
|
|
|
489
494
|
if clear:
|
|
490
|
-
self.communications.
|
|
495
|
+
self.communications.clear()
|
|
491
496
|
|
|
492
497
|
return Path(filepath)
|
|
493
498
|
|
|
494
499
|
def _save_at_exit(self) -> None:
|
|
495
|
-
"""atexit callback. Dumps
|
|
500
|
+
"""atexit callback. Dumps session synchronously. Errors are suppressed."""
|
|
496
501
|
if len(self.messages) > 0:
|
|
497
502
|
try:
|
|
498
|
-
self.
|
|
503
|
+
self.dump(clear=False)
|
|
499
504
|
except Exception:
|
|
500
505
|
pass # Silent failure during interpreter shutdown
|
|
501
506
|
|
|
@@ -37,14 +37,13 @@ krons/agent/third_party/claude_code.py,sha256=NBYMsdPheb0PqGgTO2_aUAR2XoGDsPUwsB
|
|
|
37
37
|
krons/agent/third_party/gemini_models.py,sha256=2dag2WbSTKLBd8t0F7t_TXCcl7aqsTFgDI6XLkhsZwM,17416
|
|
38
38
|
krons/agent/third_party/openai_models.py,sha256=L-GkJ-bBW5zwPbgCWEYHMNqRiZfFTAUJE96AVZoDAkQ,8040
|
|
39
39
|
krons/core/__init__.py,sha256=TKi3toVRYybyjUwUJlng--pfWzWihUWQBCNh0UTfTSQ,3611
|
|
40
|
-
krons/core/base/__init__.py,sha256=
|
|
40
|
+
krons/core/base/__init__.py,sha256=Edl_HH2F1l0SMHMzuEPU_IFjkigRR1vtqVXcPm-mr1o,3614
|
|
41
41
|
krons/core/base/broadcaster.py,sha256=Es__WfL-j2h5NS6aU18fgaFkZsJIL-zDe86Qvlea-io,4013
|
|
42
42
|
krons/core/base/element.py,sha256=LqBbmPttXoDAFy56JzWhSJ4sBw_LW7hMGxZUog85N8g,7642
|
|
43
43
|
krons/core/base/event.py,sha256=iZQ65Xg3a8eaCEl4Hca-pxPNtckhrHkydEqYyppbuo0,11524
|
|
44
44
|
krons/core/base/eventbus.py,sha256=z45ORtGey5A1N9hdyEPOhlX1whaTTdqdk7g3XEDL-_8,3761
|
|
45
|
-
krons/core/base/flow.py,sha256=
|
|
45
|
+
krons/core/base/flow.py,sha256=bFG5x7PEbWApsD24GTgpD5VsedLO6364scaAxvYw6LM,12561
|
|
46
46
|
krons/core/base/graph.py,sha256=FiTMArxuz6At3oYPEoamES3FtBM-AM6QnA7EQ8G18mo,15972
|
|
47
|
-
krons/core/base/log.py,sha256=SMJlruIG4YHk6Ls45jQ9SrPxFCcnypUmTGaWd90wiwM,923
|
|
48
47
|
krons/core/base/node.py,sha256=0_-R6uNe6-LF3adQRZowSIICdy6ep3cQIQRdF0oosoQ,34699
|
|
49
48
|
krons/core/base/pile.py,sha256=ZKvnX3BjMsrH989TLNZII1dDWv4yPhSRzLKXx2yzyKQ,21108
|
|
50
49
|
krons/core/base/processor.py,sha256=GrdNZa5YD0tXle847ttnxuWe4Ego1MhULzWHmSz5RqQ,18768
|
|
@@ -87,7 +86,7 @@ krons/session/constraints.py,sha256=DvmLKyf5eYUX2nxCDcco1-uDipGjiIJwoUxWVtX2w84,
|
|
|
87
86
|
krons/session/exchange.py,sha256=QChEqK5NFZJpHWxPrXd8LkGBCFg6LNONd1ZEy0MufpI,9165
|
|
88
87
|
krons/session/message.py,sha256=mtZ-PYCCoyWLy7BSB5TL5a0hIt0aQX2zdckOCIl6NZ0,2007
|
|
89
88
|
krons/session/registry.py,sha256=13pPKmDZJaj9q27oUOdtH6-jrHP_HDFF8lCdcNF--EE,999
|
|
90
|
-
krons/session/session.py,sha256=
|
|
89
|
+
krons/session/session.py,sha256=2dykFkdK0DUu3kdv1v8RIevtuD3P50w_0vNIE3qs3D0,17204
|
|
91
90
|
krons/utils/__init__.py,sha256=V-jTKULdofjJXxcEHygefKV_v6XE4H3poCdxPLjvf_4,1718
|
|
92
91
|
krons/utils/_function_arg_parser.py,sha256=H5JVLBVY8W9ZNkZ4_YVtVVY1rFYvnIRhSrAhKEdj2Qc,3479
|
|
93
92
|
krons/utils/_hash.py,sha256=W2Ma9v8-INPaGkur7GTtbF8KwuXSJNSwk8DCNPRvx8Q,6859
|
|
@@ -146,7 +145,7 @@ krons/work/rules/common/mapping.py,sha256=Loq54MNEtwpnHN0aypTjFOqwoOKLEysddHh-JE
|
|
|
146
145
|
krons/work/rules/common/model.py,sha256=xmM6coEThf_fgIiqJiyDgvdfib_FpVeY6LgWPVcWSwU,3026
|
|
147
146
|
krons/work/rules/common/number.py,sha256=cCukgMSpQu5RdYK5rXAUyop9qXgDRfLCioMvE8kIzHg,3162
|
|
148
147
|
krons/work/rules/common/string.py,sha256=zHp_OLh0FL4PvmSlyDTEzb2I97-DBSEyI2zcMo10voA,5090
|
|
149
|
-
krons-0.2.
|
|
150
|
-
krons-0.2.
|
|
151
|
-
krons-0.2.
|
|
152
|
-
krons-0.2.
|
|
148
|
+
krons-0.2.3.dist-info/METADATA,sha256=5VYw8_rlpQ5Q9W8EGwy8XZ19F--f_URzcmVAiG9WIqY,2527
|
|
149
|
+
krons-0.2.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
150
|
+
krons-0.2.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
151
|
+
krons-0.2.3.dist-info/RECORD,,
|
krons/core/base/log.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 - 2026, HaiyangLi <quantocean.li at gmail dot com>
|
|
2
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
"""Logging configuration for Session message persistence.
|
|
5
|
-
|
|
6
|
-
Provides DataLoggerConfig for configuring automatic message dumps.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import Literal
|
|
13
|
-
|
|
14
|
-
from pydantic import Field
|
|
15
|
-
|
|
16
|
-
from krons.core.types import HashableModel
|
|
17
|
-
|
|
18
|
-
__all__ = ("DataLoggerConfig",)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class DataLoggerConfig(HashableModel):
|
|
22
|
-
"""Configuration for Session message persistence.
|
|
23
|
-
|
|
24
|
-
Attributes:
|
|
25
|
-
persist_dir: Directory for dump files.
|
|
26
|
-
extension: Output format (.json array or .jsonl newline-delimited).
|
|
27
|
-
auto_save_on_exit: Register atexit handler on Session creation.
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
persist_dir: str | Path = Field(default="./logs")
|
|
31
|
-
extension: Literal[".json", ".jsonl"] = Field(default=".jsonl")
|
|
32
|
-
auto_save_on_exit: bool = Field(default=True)
|
|
File without changes
|
|
File without changes
|