Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/aldwin/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@
from aldwin.host.in_process import (
BootstrapResult,
ClientBootstrapError,
MemorySummary,
NoteEntry,
PersonaSummary,
PlatformNotSupportedError,
bootstrap_host,
get_memory_summary,
get_persona_summary,
get_persona_text,
pop_profile_truncation_warning,
)

if TYPE_CHECKING:
Expand All @@ -33,7 +40,14 @@ def __getattr__(name: str) -> Any:
"AldwinClient",
"BootstrapResult",
"ClientBootstrapError",
"MemorySummary",
"NoteEntry",
"PersonaSummary",
"PlatformNotSupportedError",
"ProtocolError",
"bootstrap",
"get_memory_summary",
"get_persona_summary",
"get_persona_text",
"pop_profile_truncation_warning",
]
14 changes: 14 additions & 0 deletions src/aldwin/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@
BootstrapResult,
ClientBootstrapError,
ClientTransport,
MemorySummary,
NoteEntry,
PersonaSummary,
PlatformNotSupportedError,
bootstrap_host,
get_memory_summary,
get_persona_summary,
get_persona_text,
pop_profile_truncation_warning,
)
from aldwin.protocol import (
PROTOCOL_VERSION,
Expand Down Expand Up @@ -177,7 +184,14 @@ async def close(self) -> None:
"AldwinClient",
"BootstrapResult",
"ClientBootstrapError",
"MemorySummary",
"NoteEntry",
"PersonaSummary",
"PlatformNotSupportedError",
"ProtocolError",
"bootstrap",
"get_memory_summary",
"get_persona_summary",
"get_persona_text",
"pop_profile_truncation_warning",
]
20 changes: 18 additions & 2 deletions src/aldwin/core/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
load_secrets,
resolve_key,
)
from aldwin.core.tools import build_memory_tools, build_persona_tool

logger = logging.getLogger("aldwin.core.agent")

Expand Down Expand Up @@ -170,10 +171,11 @@ def build_agent(
model: Model | None = None,
tools: Sequence[Tool] | None = None,
on_retry: RetryCallback | None = None,
session_id_getter: Callable[[], str] | None = None,
) -> Agent:
"""Assemble Aldwin's `Agent` from `config`, `secrets`, and `ask` (`FR-1`)."""
del ask # Bound to built-in tools when ENG-381/ENG-382 wire `builtin_tools`.
root = (home if home is not None else home_dir()).expanduser().resolve()
effective_ask = ask or _deny_all_ask

if model is not None:
active_model: Model = model
Expand All @@ -185,12 +187,26 @@ def build_agent(
on_retry=on_retry,
)

if tools is not None:
active_tools: tuple[Tool, ...] = tuple(tools)
else:
remember_tool, recall_tool = build_memory_tools(
root,
session_id_getter=session_id_getter,
)
persona_tool = build_persona_tool(
effective_ask,
root,
cap=config.limits.persona_chars,
)
active_tools = (remember_tool, recall_tool, persona_tool)

skill_result = load_skills(root / SKILLS_SUBDIR)
context_manager = build_context(root, config.limits)

agent = Agent(
model=active_model,
tools=tuple(tools) if tools is not None else (),
tools=active_tools,
skills=skill_result.valid,
instructions=load_base_instructions(),
max_steps=config.limits.max_steps,
Expand Down
64 changes: 6 additions & 58 deletions src/aldwin/core/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,19 @@

import logging
from collections.abc import Callable
from importlib.resources import files
from pathlib import Path
from typing import Final

from agentling import ChatMessage

from aldwin.core.home import read_base_instructions
from aldwin.core.memory import memory_block
from aldwin.core.persona import read_persona
from aldwin.core.settings import LimitsConfig

logger = logging.getLogger("aldwin.core.context")

PERSONA_FILENAME: Final[str] = "persona.md"

_WARNED_PERSONA_CAPS: set[tuple[str, int, int, int]] = set()


def _read_default_persona() -> str:
"""Read the package-shipped default `persona.md` asset."""
return (
files("aldwin.core.assets")
.joinpath(PERSONA_FILENAME)
.read_text(encoding="utf-8")
.strip()
)


def read_persona_stub(home: Path, cap: int) -> str:
"""Read `persona.md` from `home` (falling back to shipped default) capped at `cap`.

Truncates in the prompt only (never on disk) and logs a warning once per
file modification when the file exceeds `cap` characters.
"""
persona_path = home.expanduser().resolve() / PERSONA_FILENAME
mtime_ns = 0
try:
stat = persona_path.stat()
mtime_ns = stat.st_mtime_ns
raw = persona_path.read_text(encoding="utf-8").strip()
except OSError:
raw = ""

if not raw:
raw = _read_default_persona()

if len(raw) > cap:
warn_key = (str(persona_path), mtime_ns, len(raw), cap)
if warn_key not in _WARNED_PERSONA_CAPS:
if len(_WARNED_PERSONA_CAPS) >= 64:
_WARNED_PERSONA_CAPS.clear()
_WARNED_PERSONA_CAPS.add(warn_key)
logger.warning(
"Persona file %s is %d characters (cap %d); truncating in prompt.",
persona_path,
len(raw),
cap,
)
return raw[:cap]

return raw


def memory_block_stub(home: Path, limits: LimitsConfig) -> str:
"""Return the `<memory>` block for the system prompt (stubbed until ENG-381)."""
del home, limits
return ""
read_persona_stub = read_persona
memory_block_stub = memory_block


def _find_matching_assistant_index(
Expand Down Expand Up @@ -139,8 +87,8 @@ def build_context(
never separated from its `tool` result messages.
"""
resolved_home = home.expanduser().resolve()
read_persona_fn = persona_reader or read_persona_stub
build_memory_fn = memory_builder or memory_block_stub
read_persona_fn = persona_reader or read_persona
build_memory_fn = memory_builder or memory_block

def _context_manager(messages: list[ChatMessage]) -> list[ChatMessage]:
if messages and messages[0].role == "system":
Expand Down
Loading
Loading