feat: make dreamer and dialectic actually respect settings around using peer card
This commit is contained in:
parent
0eb0d6d427
commit
4b01f8754d
|
|
@ -197,7 +197,7 @@ class ConclusionScope:
|
|||
],
|
||||
)
|
||||
|
||||
def representation(
|
||||
def get_representation(
|
||||
self,
|
||||
search_query: str | None = None,
|
||||
search_top_k: int | None = None,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from src import crud
|
|||
from src.config import ReasoningLevel
|
||||
from src.dependencies import tracked_db
|
||||
from src.dialectic.core import DialecticAgent
|
||||
from src.utils.config_helpers import get_configuration
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -39,15 +40,26 @@ async def agentic_chat(
|
|||
The synthesized answer string
|
||||
"""
|
||||
async with tracked_db("dialectic.agentic_chat") as db:
|
||||
# Get peer cards for context
|
||||
observer_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observer
|
||||
)
|
||||
observed_peer_card = None
|
||||
if observer != observed:
|
||||
observed_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observed
|
||||
# Resolve configuration to check if peer cards should be used
|
||||
session = None
|
||||
if session_name:
|
||||
session = await crud.get_session(
|
||||
db, workspace_name=workspace_name, session_name=session_name
|
||||
)
|
||||
workspace = await crud.get_workspace(db, workspace_name=workspace_name)
|
||||
configuration = get_configuration(None, session, workspace)
|
||||
|
||||
# Get peer cards for context (if enabled)
|
||||
observer_peer_card = None
|
||||
observed_peer_card = None
|
||||
if configuration.peer_card.use:
|
||||
observer_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observer
|
||||
)
|
||||
if observer != observed:
|
||||
observed_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observed
|
||||
)
|
||||
|
||||
# Create and run the dialectic agent
|
||||
agent = DialecticAgent(
|
||||
|
|
@ -89,15 +101,26 @@ async def agentic_chat_stream(
|
|||
Chunks of the response text as they are generated
|
||||
"""
|
||||
async with tracked_db("dialectic.agentic_chat_stream") as db:
|
||||
# Get peer cards for context
|
||||
observer_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observer
|
||||
)
|
||||
observed_peer_card = None
|
||||
if observer != observed:
|
||||
observed_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observed
|
||||
# Resolve configuration to check if peer cards should be used
|
||||
session = None
|
||||
if session_name:
|
||||
session = await crud.get_session(
|
||||
db, workspace_name=workspace_name, session_name=session_name
|
||||
)
|
||||
workspace = await crud.get_workspace(db, workspace_name=workspace_name)
|
||||
configuration = get_configuration(None, session, workspace)
|
||||
|
||||
# Get peer cards for context (if enabled)
|
||||
observer_peer_card = None
|
||||
observed_peer_card = None
|
||||
if configuration.peer_card.use:
|
||||
observer_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observer
|
||||
)
|
||||
if observer != observed:
|
||||
observed_peer_card = await crud.get_peer_card(
|
||||
db, workspace_name, observer=observer, observed=observed
|
||||
)
|
||||
|
||||
# Create and run the dialectic agent
|
||||
agent = DialecticAgent(
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ def agent_system_prompt(
|
|||
Returns:
|
||||
Formatted system prompt string for the agent
|
||||
"""
|
||||
# Determine if we have any peer card data
|
||||
peer_cards_enabled = (
|
||||
observer_peer_card is not None or observed_peer_card is not None
|
||||
)
|
||||
# Build peer card sections
|
||||
if observer != observed:
|
||||
# Directional query: observer asking about observed
|
||||
|
|
@ -64,6 +68,15 @@ Known biographical information about {observed}:
|
|||
You are answering queries about '{observed}'.
|
||||
|
||||
{peer_card_section}
|
||||
"""
|
||||
|
||||
# Build peer card explanation section (only if peer cards are being used)
|
||||
peer_card_explanation = ""
|
||||
if peer_cards_enabled:
|
||||
peer_card_explanation = """
|
||||
Peer cards are **constructed summaries** - they are synthesized from the same observations stored in memory. This means:
|
||||
- Information in a peer card originates from observations you can also find via `search_memory`
|
||||
- The peer card is a convenience summary, not a separate source of truth
|
||||
"""
|
||||
|
||||
return f"""
|
||||
|
|
@ -72,11 +85,7 @@ You are a helpful and concise context synthesis agent that answers questions abo
|
|||
Always give users the answer *they expect* based on the message history -- the goal is to help recall and *reason through* insights that the memory system has already gathered. You have many tools for gathering context. Search wisely.
|
||||
|
||||
{perspective_section}
|
||||
|
||||
Peer cards are **constructed summaries** - they are synthesized from the same observations stored in memory. This means:
|
||||
- Information in a peer card originates from observations you can also find via `search_memory`
|
||||
- The peer card is a convenience summary, not a separate source of truth
|
||||
|
||||
{peer_card_explanation}
|
||||
## AVAILABLE TOOLS
|
||||
|
||||
**Observation Tools (read):**
|
||||
|
|
|
|||
|
|
@ -200,7 +200,9 @@ class DreamScheduler:
|
|||
) -> None:
|
||||
"""Execute the dream by enqueueing it and updating collection metadata."""
|
||||
# Import here to avoid circular dependency
|
||||
from src import crud
|
||||
from src.deriver.enqueue import enqueue_dream
|
||||
from src.utils.config_helpers import get_configuration
|
||||
|
||||
# Find the most recent session for this observer/observed pair
|
||||
async with tracked_db("dream_session_lookup") as db:
|
||||
|
|
@ -216,11 +218,24 @@ class DreamScheduler:
|
|||
)
|
||||
session_name = await db.scalar(stmt)
|
||||
|
||||
if not session_name:
|
||||
logger.warning(
|
||||
f"No documents found for {workspace_name}/{observer}/{observed}, skipping dream"
|
||||
if not session_name:
|
||||
logger.warning(
|
||||
f"No documents found for {workspace_name}/{observer}/{observed}, skipping dream"
|
||||
)
|
||||
return
|
||||
|
||||
session = await crud.get_session(
|
||||
db, workspace_name=workspace_name, session_name=session_name
|
||||
)
|
||||
return
|
||||
workspace = await crud.get_workspace(db, workspace_name=workspace_name)
|
||||
|
||||
configuration = get_configuration(None, session, workspace)
|
||||
|
||||
if not configuration.dream.enabled:
|
||||
logger.info(
|
||||
f"Dreams disabled for {workspace_name}/{session_name}, skipping dream"
|
||||
)
|
||||
return
|
||||
|
||||
await enqueue_dream(
|
||||
workspace_name,
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@ from typing import Any
|
|||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src import crud
|
||||
from src.config import settings
|
||||
from src.dreamer.specialists import SPECIALISTS
|
||||
from src.dreamer.surprisal import SurprisalScore # type: ignore
|
||||
from src.exceptions import SpecialistExecutionError, SurprisalError
|
||||
from src.utils.config_helpers import get_configuration
|
||||
from src.utils.logging import (
|
||||
accumulate_metric,
|
||||
log_performance_metrics,
|
||||
|
|
@ -80,6 +82,13 @@ async def run_dream(
|
|||
f"[{run_id}] Starting dream cycle for {workspace_name}/{observer}/{observed}"
|
||||
)
|
||||
|
||||
session = await crud.get_session(
|
||||
db, workspace_name=workspace_name, session_name=session_name
|
||||
)
|
||||
workspace = await crud.get_workspace(db, workspace_name=workspace_name)
|
||||
|
||||
configuration = get_configuration(None, session, workspace)
|
||||
|
||||
# Phase 0: Surprisal-based sampling (if enabled)
|
||||
probing_questions = PROBING_QUESTIONS # Default
|
||||
|
||||
|
|
@ -149,6 +158,7 @@ async def run_dream(
|
|||
observed=observed,
|
||||
session_name=session_name,
|
||||
probing_questions=probing_questions,
|
||||
configuration=configuration,
|
||||
)
|
||||
logger.info(f"[{run_id}] Deduction completed: {deduction_result[:200]}...")
|
||||
accumulate_metric(task_name, "deduction_result", deduction_result, "blob")
|
||||
|
|
@ -167,6 +177,7 @@ async def run_dream(
|
|||
observed=observed,
|
||||
session_name=session_name,
|
||||
probing_questions=probing_questions,
|
||||
configuration=configuration,
|
||||
)
|
||||
logger.info(f"[{run_id}] Induction completed: {induction_result[:200]}...")
|
||||
accumulate_metric(task_name, "induction_result", induction_result, "blob")
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||
|
||||
from src import prometheus
|
||||
from src.config import settings
|
||||
from src.schemas import ResolvedConfiguration
|
||||
from src.utils.agent_tools import (
|
||||
DEDUCTION_SPECIALIST_TOOLS,
|
||||
INDUCTION_SPECIALIST_TOOLS,
|
||||
|
|
@ -32,13 +33,17 @@ from src.utils.logging import accumulate_metric, log_performance_metrics
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Tool names to exclude when peer card creation is disabled
|
||||
PEER_CARD_TOOL_NAMES = {"update_peer_card", "get_peer_card"}
|
||||
|
||||
|
||||
class BaseSpecialist(ABC):
|
||||
"""Base class for agentic specialists."""
|
||||
|
||||
name: str = "base"
|
||||
|
||||
@abstractmethod
|
||||
def get_tools(self) -> list[dict[str, Any]]:
|
||||
def get_tools(self, *, peer_card_enabled: bool = True) -> list[dict[str, Any]]:
|
||||
"""Get the tools available to this specialist."""
|
||||
...
|
||||
|
||||
|
|
@ -56,7 +61,9 @@ class BaseSpecialist(ABC):
|
|||
return 15
|
||||
|
||||
@abstractmethod
|
||||
def build_system_prompt(self, observed: str) -> str:
|
||||
def build_system_prompt(
|
||||
self, observed: str, *, peer_card_enabled: bool = True
|
||||
) -> str:
|
||||
"""Build the system prompt for this specialist."""
|
||||
...
|
||||
|
||||
|
|
@ -73,6 +80,7 @@ class BaseSpecialist(ABC):
|
|||
observed: str,
|
||||
session_name: str,
|
||||
probing_questions: list[str],
|
||||
configuration: ResolvedConfiguration | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Run the specialist agent.
|
||||
|
|
@ -84,6 +92,7 @@ class BaseSpecialist(ABC):
|
|||
observed: The peer being observed
|
||||
session_name: Session identifier
|
||||
probing_questions: Entry point questions to guide exploration
|
||||
configuration: Resolved configuration for checking feature flags (optional)
|
||||
|
||||
Returns:
|
||||
Summary of work done
|
||||
|
|
@ -92,9 +101,17 @@ class BaseSpecialist(ABC):
|
|||
task_name = f"dreamer_{self.name}_{run_id}"
|
||||
start_time = time.perf_counter()
|
||||
|
||||
# Determine if peer card tools should be included
|
||||
peer_card_enabled = configuration is None or configuration.peer_card.create
|
||||
|
||||
# Build messages
|
||||
messages: list[dict[str, str]] = [
|
||||
{"role": "system", "content": self.build_system_prompt(observed)},
|
||||
{
|
||||
"role": "system",
|
||||
"content": self.build_system_prompt(
|
||||
observed, peer_card_enabled=peer_card_enabled
|
||||
),
|
||||
},
|
||||
{"role": "user", "content": self.build_user_prompt(probing_questions)},
|
||||
]
|
||||
|
||||
|
|
@ -109,6 +126,7 @@ class BaseSpecialist(ABC):
|
|||
session_name=session_name,
|
||||
include_observation_ids=True,
|
||||
history_token_limit=settings.DREAM.HISTORY_TOKEN_LIMIT,
|
||||
configuration=configuration,
|
||||
)
|
||||
|
||||
# Get model with potential override
|
||||
|
|
@ -120,7 +138,7 @@ class BaseSpecialist(ABC):
|
|||
llm_settings=llm_settings,
|
||||
prompt="", # Ignored since we pass messages
|
||||
max_tokens=self.get_max_tokens(),
|
||||
tools=self.get_tools(),
|
||||
tools=self.get_tools(peer_card_enabled=peer_card_enabled),
|
||||
tool_choice=None,
|
||||
tool_executor=tool_executor,
|
||||
max_tool_iterations=self.get_max_iterations(),
|
||||
|
|
@ -172,8 +190,14 @@ class DeductionSpecialist(BaseSpecialist):
|
|||
|
||||
name: str = "deduction"
|
||||
|
||||
def get_tools(self) -> list[dict[str, Any]]:
|
||||
return DEDUCTION_SPECIALIST_TOOLS
|
||||
def get_tools(self, *, peer_card_enabled: bool = True) -> list[dict[str, Any]]:
|
||||
if peer_card_enabled:
|
||||
return DEDUCTION_SPECIALIST_TOOLS
|
||||
return [
|
||||
t
|
||||
for t in DEDUCTION_SPECIALIST_TOOLS
|
||||
if t["name"] not in PEER_CARD_TOOL_NAMES
|
||||
]
|
||||
|
||||
def get_model(self) -> str:
|
||||
return settings.DREAM.DEDUCTION_MODEL
|
||||
|
|
@ -184,7 +208,50 @@ class DeductionSpecialist(BaseSpecialist):
|
|||
def get_max_iterations(self) -> int:
|
||||
return 12
|
||||
|
||||
def build_system_prompt(self, observed: str) -> str:
|
||||
def build_system_prompt(
|
||||
self, observed: str, *, peer_card_enabled: bool = True
|
||||
) -> str:
|
||||
# Base tools list
|
||||
tools_section = """## TOOLS
|
||||
|
||||
- `search_memory`: Find observations by semantic query
|
||||
- `create_observations`: Create new deductive OR contradiction observations (USE THIS!)
|
||||
- `delete_observations`: Remove outdated observations (USE AFTER KNOWLEDGE UPDATES!)
|
||||
- `get_recent_observations`: See recent activity"""
|
||||
|
||||
if peer_card_enabled:
|
||||
tools_section += """
|
||||
- `get_peer_card`: Retrieve current peer card contents
|
||||
- `update_peer_card`: Update the peer card with key facts"""
|
||||
|
||||
# Peer card section (only if enabled)
|
||||
peer_card_section = ""
|
||||
if peer_card_enabled:
|
||||
peer_card_section = """
|
||||
|
||||
## PEER CARD UPDATES
|
||||
|
||||
The peer card is a concise summary of permanent, stable information about the peer. Update it when you discover important facts that should be easily accessible.
|
||||
|
||||
**Peer card format** - Use these prefixes to organize entries:
|
||||
- Plain facts for biographical info: "Name: Alice", "Works at Google", "Lives in NYC"
|
||||
- `INSTRUCTION: ...` for standing instructions: "INSTRUCTION: Always call me Al", "INSTRUCTION: Send meeting agendas 24h in advance"
|
||||
- `PREFERENCE: ...` for preferences: "PREFERENCE: Prefers morning meetings", "PREFERENCE: Likes detailed explanations"
|
||||
- `TRAIT: ...` for personality traits: "TRAIT: Analytical thinker", "TRAIT: Detail-oriented"
|
||||
|
||||
Call `get_peer_card` first to see current contents, then `update_peer_card` with the complete updated list."""
|
||||
|
||||
# Remember section
|
||||
remember_section = """
|
||||
|
||||
REMEMBER:
|
||||
1. Knowledge updates are your #1 priority. When the same fact has different values at different times, CREATE an update observation AND DELETE the outdated observation.
|
||||
2. Flag contradictions when statements are logically incompatible (can't both be true)."""
|
||||
|
||||
if peer_card_enabled:
|
||||
remember_section += """
|
||||
3. Update the peer card with permanent biographical facts and key insights."""
|
||||
|
||||
return f"""You are a deductive reasoning specialist for {observed}. Your ONLY job is to create deductive observations by calling tools. Do NOT explain your reasoning - just make tool calls.
|
||||
|
||||
## MANDATORY WORKFLOW - YOU MUST FOLLOW THIS PATTERN
|
||||
|
|
@ -290,31 +357,7 @@ Create deductions that make implicit information explicit:
|
|||
}}
|
||||
```
|
||||
|
||||
## TOOLS
|
||||
|
||||
- `search_memory`: Find observations by semantic query
|
||||
- `create_observations`: Create new deductive OR contradiction observations (USE THIS!)
|
||||
- `delete_observations`: Remove outdated observations (USE AFTER KNOWLEDGE UPDATES!)
|
||||
- `get_recent_observations`: See recent activity
|
||||
- `get_peer_card`: Retrieve current peer card contents
|
||||
- `update_peer_card`: Update the peer card with key facts
|
||||
|
||||
## PEER CARD UPDATES
|
||||
|
||||
The peer card is a concise summary of permanent, stable information about the peer. Update it when you discover important facts that should be easily accessible.
|
||||
|
||||
**Peer card format** - Use these prefixes to organize entries:
|
||||
- Plain facts for biographical info: "Name: Alice", "Works at Google", "Lives in NYC"
|
||||
- `INSTRUCTION: ...` for standing instructions: "INSTRUCTION: Always call me Al", "INSTRUCTION: Send meeting agendas 24h in advance"
|
||||
- `PREFERENCE: ...` for preferences: "PREFERENCE: Prefers morning meetings", "PREFERENCE: Likes detailed explanations"
|
||||
- `TRAIT: ...` for personality traits: "TRAIT: Analytical thinker", "TRAIT: Detail-oriented"
|
||||
|
||||
Call `get_peer_card` first to see current contents, then `update_peer_card` with the complete updated list.
|
||||
|
||||
REMEMBER:
|
||||
1. Knowledge updates are your #1 priority. When the same fact has different values at different times, CREATE an update observation AND DELETE the outdated observation.
|
||||
2. Flag contradictions when statements are logically incompatible (can't both be true).
|
||||
3. Update the peer card with permanent biographical facts and key insights."""
|
||||
{tools_section}{peer_card_section}{remember_section}"""
|
||||
|
||||
def build_user_prompt(self, probing_questions: list[str]) -> str:
|
||||
questions_text = "\n".join(f"- {q}" for q in probing_questions)
|
||||
|
|
@ -342,8 +385,14 @@ class InductionSpecialist(BaseSpecialist):
|
|||
|
||||
name: str = "induction"
|
||||
|
||||
def get_tools(self) -> list[dict[str, Any]]:
|
||||
return INDUCTION_SPECIALIST_TOOLS
|
||||
def get_tools(self, *, peer_card_enabled: bool = True) -> list[dict[str, Any]]:
|
||||
if peer_card_enabled:
|
||||
return INDUCTION_SPECIALIST_TOOLS
|
||||
return [
|
||||
t
|
||||
for t in INDUCTION_SPECIALIST_TOOLS
|
||||
if t["name"] not in PEER_CARD_TOOL_NAMES
|
||||
]
|
||||
|
||||
def get_model(self) -> str:
|
||||
return settings.DREAM.INDUCTION_MODEL
|
||||
|
|
@ -354,7 +403,48 @@ class InductionSpecialist(BaseSpecialist):
|
|||
def get_max_iterations(self) -> int:
|
||||
return 10
|
||||
|
||||
def build_system_prompt(self, observed: str) -> str:
|
||||
def build_system_prompt(
|
||||
self, observed: str, *, peer_card_enabled: bool = True
|
||||
) -> str:
|
||||
# Base tools list
|
||||
tools_section = """## TOOLS
|
||||
|
||||
- `search_memory`: Find observations by semantic query
|
||||
- `create_observations`: Create new inductive observations (USE THIS!)
|
||||
- `get_recent_observations`: See recent activity"""
|
||||
|
||||
if peer_card_enabled:
|
||||
tools_section += """
|
||||
- `get_peer_card`: Retrieve current peer card contents
|
||||
- `update_peer_card`: Update the peer card with key facts"""
|
||||
|
||||
# Peer card section (only if enabled)
|
||||
peer_card_section = ""
|
||||
if peer_card_enabled:
|
||||
peer_card_section = """
|
||||
|
||||
## PEER CARD UPDATES
|
||||
|
||||
The peer card is a concise summary of permanent, stable information about the peer. After identifying high-confidence patterns, update the peer card.
|
||||
|
||||
**Peer card format** - Use these prefixes to organize entries:
|
||||
- Plain facts for biographical info: "Name: Alice", "Works at Google", "Lives in NYC"
|
||||
- `INSTRUCTION: ...` for standing instructions: "INSTRUCTION: Always call me Al"
|
||||
- `PREFERENCE: ...` for preferences: "PREFERENCE: Prefers morning meetings"
|
||||
- `TRAIT: ...` for personality/behavioral traits: "TRAIT: Analytical thinker", "TRAIT: Tends to reschedule when stressed"
|
||||
|
||||
Call `get_peer_card` first to see current contents, then `update_peer_card` with the complete updated list."""
|
||||
|
||||
# Remember section
|
||||
remember_section = """
|
||||
|
||||
REMEMBER: Focus on temporal patterns and how things change. Create observations, don't just search."""
|
||||
|
||||
if peer_card_enabled:
|
||||
remember_section += (
|
||||
" Update the peer card with high-confidence patterns and traits."
|
||||
)
|
||||
|
||||
return f"""You are an inductive reasoning specialist for {observed}. Your ONLY job is to create inductive observations by calling tools. Do NOT explain your reasoning - just make tool calls.
|
||||
|
||||
## MANDATORY WORKFLOW - YOU MUST FOLLOW THIS PATTERN
|
||||
|
|
@ -432,27 +522,7 @@ REQUIREMENTS:
|
|||
- Confidence based on source count: low=2, medium=3-4, high=5+
|
||||
- Pattern must generalize, not just restate one fact
|
||||
|
||||
## TOOLS
|
||||
|
||||
- `search_memory`: Find observations by semantic query
|
||||
- `create_observations`: Create new inductive observations (USE THIS!)
|
||||
- `get_recent_observations`: See recent activity
|
||||
- `get_peer_card`: Retrieve current peer card contents
|
||||
- `update_peer_card`: Update the peer card with key facts
|
||||
|
||||
## PEER CARD UPDATES
|
||||
|
||||
The peer card is a concise summary of permanent, stable information about the peer. After identifying high-confidence patterns, update the peer card.
|
||||
|
||||
**Peer card format** - Use these prefixes to organize entries:
|
||||
- Plain facts for biographical info: "Name: Alice", "Works at Google", "Lives in NYC"
|
||||
- `INSTRUCTION: ...` for standing instructions: "INSTRUCTION: Always call me Al"
|
||||
- `PREFERENCE: ...` for preferences: "PREFERENCE: Prefers morning meetings"
|
||||
- `TRAIT: ...` for personality/behavioral traits: "TRAIT: Analytical thinker", "TRAIT: Tends to reschedule when stressed"
|
||||
|
||||
Call `get_peer_card` first to see current contents, then `update_peer_card` with the complete updated list.
|
||||
|
||||
REMEMBER: Focus on temporal patterns and how things change. Create observations, don't just search. Update the peer card with high-confidence patterns and traits."""
|
||||
{tools_section}{peer_card_section}{remember_section}"""
|
||||
|
||||
def build_user_prompt(self, probing_questions: list[str]) -> str:
|
||||
questions_text = "\n".join(f"- {q}" for q in probing_questions)
|
||||
|
|
|
|||
|
|
@ -134,10 +134,6 @@ class MessageConfiguration(BaseModel):
|
|||
default=None,
|
||||
description="Configuration for reasoning functionality.",
|
||||
)
|
||||
peer_card: PeerCardConfiguration | None = Field(
|
||||
default=None,
|
||||
description="Configuration for peer card functionality. If reasoning is disabled, peer cards will also be disabled and these settings will be ignored.",
|
||||
)
|
||||
|
||||
|
||||
class ResolvedReasoningConfiguration(BaseModel):
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from src import crud, models, schemas
|
|||
from src.config import settings
|
||||
from src.embedding_client import embedding_client
|
||||
from src.models import Document
|
||||
from src.schemas import ResolvedConfiguration
|
||||
from src.utils import summarizer
|
||||
from src.utils.formatting import format_new_turn_with_timestamp, utc_now_iso
|
||||
from src.utils.representation import Representation
|
||||
|
|
@ -884,6 +885,8 @@ class ToolContext:
|
|||
# This lock is obtained from the module-level registry to ensure all concurrent
|
||||
# tool executors for the same data share the same lock.
|
||||
db_lock: asyncio.Lock
|
||||
# Optional resolved configuration for checking feature flags
|
||||
configuration: ResolvedConfiguration | None = None
|
||||
|
||||
|
||||
async def _handle_create_observations(
|
||||
|
|
@ -998,6 +1001,15 @@ async def _handle_create_observations(
|
|||
|
||||
async def _handle_update_peer_card(ctx: ToolContext, tool_input: dict[str, Any]) -> str:
|
||||
"""Handle update_peer_card tool."""
|
||||
# Check if peer card creation is disabled via configuration
|
||||
if ctx.configuration is not None and not ctx.configuration.peer_card.create:
|
||||
logger.info(
|
||||
f"Peer card creation disabled for {ctx.workspace_name}, skipping update"
|
||||
)
|
||||
return (
|
||||
"Peer card creation is disabled for this workspace/session configuration."
|
||||
)
|
||||
|
||||
async with ctx.db_lock:
|
||||
await crud.set_peer_card(
|
||||
ctx.db,
|
||||
|
|
@ -1544,6 +1556,7 @@ async def create_tool_executor(
|
|||
current_messages: list[models.Message] | None = None,
|
||||
include_observation_ids: bool = False,
|
||||
history_token_limit: int = 8192,
|
||||
configuration: ResolvedConfiguration | None = None,
|
||||
) -> Callable[[str, dict[str, Any]], Any]:
|
||||
"""
|
||||
Create a unified tool executor function for all agent operations.
|
||||
|
|
@ -1560,6 +1573,7 @@ async def create_tool_executor(
|
|||
current_messages: List of current messages being processed (optional, for deriver)
|
||||
include_observation_ids: If True, include observation IDs in output (for dreamer agent)
|
||||
history_token_limit: Maximum tokens for get_recent_history (default: 8192)
|
||||
configuration: Resolved configuration for checking feature flags (optional)
|
||||
|
||||
Returns:
|
||||
An async callable that executes tools with the captured context
|
||||
|
|
@ -1578,6 +1592,7 @@ async def create_tool_executor(
|
|||
include_observation_ids=include_observation_ids,
|
||||
history_token_limit=history_token_limit,
|
||||
db_lock=shared_lock,
|
||||
configuration=configuration,
|
||||
)
|
||||
|
||||
async def execute_tool(tool_name: str, tool_input: dict[str, Any]) -> str:
|
||||
|
|
|
|||
Loading…
Reference in New Issue