Skip to content

Commit 8941883

Browse files
committed
Release v4.4.3
1 parent 0ffcd84 commit 8941883

21 files changed

+234
-274
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,5 @@ issue_details.json
8484
.mcpregistry_*
8585

8686
*.log
87-
.internal
87+
.internal
88+
.praisonai

docker/Dockerfile.chat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=4.4.2" \
19+
"praisonai>=4.4.3" \
2020
"praisonai[chat]" \
2121
"embedchain[github,youtube]"
2222

docker/Dockerfile.dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
2020
# Install Python packages (using latest versions)
2121
RUN pip install --no-cache-dir \
2222
praisonai_tools \
23-
"praisonai>=4.4.2" \
23+
"praisonai>=4.4.3" \
2424
"praisonai[ui]" \
2525
"praisonai[chat]" \
2626
"praisonai[realtime]" \

docker/Dockerfile.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=4.4.2" \
19+
"praisonai>=4.4.3" \
2020
"praisonai[ui]" \
2121
"praisonai[crewai]"
2222

src/praisonai-agents/praisonaiagents/config/feature_configs.py

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
from typing import Dict, List, Any, Optional, Callable, Tuple, Union
3434
from enum import Enum
3535

36+
# Import AutonomyConfig from canonical location (no circular dep)
37+
from ..agent.autonomy import AutonomyConfig
38+
3639

3740
class MemoryBackend(str, Enum):
3841
"""Memory storage backends."""
@@ -953,54 +956,6 @@ class AutonomyLevel(str, Enum):
953956
AUTO_EDIT = "auto_edit"
954957
FULL_AUTO = "full_auto"
955958

956-
957-
@dataclass
958-
class AutonomyConfig:
959-
"""
960-
Configuration for agent autonomy behavior.
961-
962-
Controls escalation, doom-loop detection, and approval policies.
963-
964-
Usage:
965-
# Simple enable
966-
Agent(autonomy=True)
967-
968-
# With config
969-
Agent(autonomy=AutonomyConfig(
970-
level="auto_edit",
971-
escalation_enabled=True,
972-
doom_loop_detection=True,
973-
max_consecutive_failures=3,
974-
))
975-
"""
976-
# Autonomy level
977-
level: Union[str, AutonomyLevel] = AutonomyLevel.SUGGEST
978-
979-
# Escalation pipeline
980-
escalation_enabled: bool = True
981-
escalation_threshold: int = 3
982-
983-
# Doom loop detection
984-
doom_loop_detection: bool = True
985-
max_consecutive_failures: int = 3
986-
987-
# Approval policies
988-
require_approval_for_writes: bool = True
989-
require_approval_for_shell: bool = True
990-
991-
def to_dict(self) -> Dict[str, Any]:
992-
"""Convert to dictionary."""
993-
return {
994-
"level": self.level.value if isinstance(self.level, AutonomyLevel) else self.level,
995-
"escalation_enabled": self.escalation_enabled,
996-
"escalation_threshold": self.escalation_threshold,
997-
"doom_loop_detection": self.doom_loop_detection,
998-
"max_consecutive_failures": self.max_consecutive_failures,
999-
"require_approval_for_writes": self.require_approval_for_writes,
1000-
"require_approval_for_shell": self.require_approval_for_shell,
1001-
}
1002-
1003-
1004959
# Type aliases for Union types used in Agent.__init__
1005960
MemoryParam = Union[bool, MemoryConfig, Any] # Any = MemoryManager instance
1006961
KnowledgeParam = Union[bool, List[str], KnowledgeConfig, Any] # Any = KnowledgeBase instance
@@ -1014,7 +969,7 @@ def to_dict(self) -> Dict[str, Any]:
1014969
CachingParam = Union[bool, CachingConfig]
1015970
HooksParam = Union[List[Any], HooksConfig]
1016971
SkillsParam = Union[List[str], SkillsConfig]
1017-
AutonomyParam = Union[bool, Dict[str, Any], AutonomyConfig]
972+
AutonomyParam = Union[bool, Dict[str, Any], "AutonomyConfig"]
1018973

1019974

1020975
# =============================================================================

src/praisonai-agents/praisonaiagents/context/manager.py

Lines changed: 2 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
from enum import Enum
2525

2626
from .models import (
27-
ContextLedger, BudgetAllocation, OptimizerStrategy, OptimizationResult
27+
ContextLedger, BudgetAllocation, OptimizerStrategy, OptimizationResult,
28+
ContextConfig as ManagerConfig # Deprecated alias for backward compatibility
2829
)
2930
from .tokens import estimate_tokens_heuristic, estimate_messages_tokens, estimate_message_tokens
3031
from .budgeter import ContextBudgeter
@@ -288,180 +289,6 @@ def to_dict(self) -> Dict[str, Any]:
288289
"budget": self.budget.to_dict() if self.budget else None,
289290
}
290291

291-
292-
@dataclass
293-
class ManagerConfig:
294-
"""
295-
Complete configuration for ContextManager.
296-
297-
Consolidates all context management settings with proper precedence.
298-
"""
299-
# Auto-compaction
300-
auto_compact: bool = True
301-
compact_threshold: float = 0.8
302-
strategy: OptimizerStrategy = OptimizerStrategy.SMART
303-
304-
# Compression benefit check
305-
compression_min_gain_pct: float = 5.0
306-
compression_max_attempts: int = 3
307-
308-
# Budget
309-
output_reserve: int = 8000
310-
history_ratio: float = 0.6
311-
default_tool_output_max: int = 10000
312-
313-
# Per-tool budgets
314-
tool_budgets: Dict[str, PerToolBudget] = field(default_factory=dict)
315-
protected_tools: List[str] = field(default_factory=list)
316-
317-
# LLM-powered summarization
318-
llm_summarize: bool = False # Enable LLM-powered summarization
319-
320-
# Smart tool output summarization
321-
smart_tool_summarize: bool = True # Summarize large tool outputs using LLM before truncating
322-
tool_summarize_limits: Dict[str, int] = field(default_factory=dict) # Per-tool min_chars_to_summarize
323-
324-
# Estimation
325-
estimation_mode: EstimationMode = EstimationMode.HEURISTIC
326-
log_estimation_mismatch: bool = False
327-
mismatch_threshold_pct: float = 15.0
328-
329-
# Monitoring
330-
monitor_enabled: bool = False
331-
monitor_path: str = "./context.txt"
332-
monitor_format: Literal["human", "json"] = "human"
333-
monitor_frequency: Literal["turn", "tool_call", "manual", "overflow"] = "turn"
334-
monitor_write_mode: Literal["sync", "async"] = "sync"
335-
redact_sensitive: bool = True
336-
snapshot_timing: Literal["pre_optimization", "post_optimization", "both"] = "post_optimization"
337-
338-
# Path validation
339-
allow_absolute_paths: bool = False
340-
341-
# Pruning
342-
prune_after_tokens: int = 40000
343-
keep_recent_turns: int = 5
344-
345-
# Source tracking
346-
source: str = "defaults" # defaults, env, config_file, cli
347-
348-
def to_dict(self) -> Dict[str, Any]:
349-
result = {
350-
"auto_compact": self.auto_compact,
351-
"compact_threshold": self.compact_threshold,
352-
"strategy": self.strategy.value,
353-
"compression_min_gain_pct": self.compression_min_gain_pct,
354-
"compression_max_attempts": self.compression_max_attempts,
355-
"output_reserve": self.output_reserve,
356-
"history_ratio": self.history_ratio,
357-
"default_tool_output_max": self.default_tool_output_max,
358-
"tool_budgets": {k: v.to_dict() for k, v in self.tool_budgets.items()},
359-
"protected_tools": self.protected_tools,
360-
"estimation_mode": self.estimation_mode.value,
361-
"log_estimation_mismatch": self.log_estimation_mismatch,
362-
"mismatch_threshold_pct": self.mismatch_threshold_pct,
363-
"monitor_enabled": self.monitor_enabled,
364-
"monitor_path": self.monitor_path,
365-
"monitor_format": self.monitor_format,
366-
"monitor_frequency": self.monitor_frequency,
367-
"monitor_write_mode": self.monitor_write_mode,
368-
"redact_sensitive": self.redact_sensitive,
369-
"snapshot_timing": self.snapshot_timing,
370-
"allow_absolute_paths": self.allow_absolute_paths,
371-
"prune_after_tokens": self.prune_after_tokens,
372-
"keep_recent_turns": self.keep_recent_turns,
373-
"llm_summarize": self.llm_summarize,
374-
"smart_tool_summarize": self.smart_tool_summarize,
375-
"tool_summarize_limits": self.tool_summarize_limits,
376-
"source": self.source,
377-
}
378-
return result
379-
380-
@classmethod
381-
def from_env(cls) -> "ManagerConfig":
382-
"""Load config from environment variables."""
383-
import os
384-
385-
def get_bool(key: str, default: bool) -> bool:
386-
val = os.getenv(key, str(default)).lower()
387-
return val in ("true", "1", "yes", "on")
388-
389-
def get_float(key: str, default: float) -> float:
390-
try:
391-
return float(os.getenv(key, str(default)))
392-
except ValueError:
393-
return default
394-
395-
def get_int(key: str, default: int) -> int:
396-
try:
397-
return int(os.getenv(key, str(default)))
398-
except ValueError:
399-
return default
400-
401-
strategy_str = os.getenv("PRAISONAI_CONTEXT_STRATEGY", "smart")
402-
try:
403-
strategy = OptimizerStrategy(strategy_str)
404-
except ValueError:
405-
strategy = OptimizerStrategy.SMART
406-
407-
estimation_str = os.getenv("PRAISONAI_CONTEXT_ESTIMATION_MODE", "heuristic")
408-
try:
409-
estimation_mode = EstimationMode(estimation_str)
410-
except ValueError:
411-
estimation_mode = EstimationMode.HEURISTIC
412-
413-
return cls(
414-
auto_compact=get_bool("PRAISONAI_CONTEXT_AUTO_COMPACT", True),
415-
compact_threshold=get_float("PRAISONAI_CONTEXT_THRESHOLD", 0.8),
416-
strategy=strategy,
417-
compression_min_gain_pct=get_float("PRAISONAI_CONTEXT_COMPRESSION_MIN_GAIN", 5.0),
418-
compression_max_attempts=get_int("PRAISONAI_CONTEXT_COMPRESSION_MAX_ATTEMPTS", 3),
419-
output_reserve=get_int("PRAISONAI_CONTEXT_OUTPUT_RESERVE", 8000),
420-
default_tool_output_max=get_int("PRAISONAI_CONTEXT_TOOL_OUTPUT_MAX", 10000),
421-
estimation_mode=estimation_mode,
422-
log_estimation_mismatch=get_bool("PRAISONAI_CONTEXT_LOG_MISMATCH", False),
423-
monitor_enabled=get_bool("PRAISONAI_CONTEXT_MONITOR", False),
424-
monitor_path=os.getenv("PRAISONAI_CONTEXT_MONITOR_PATH", "./context.txt"),
425-
monitor_format=os.getenv("PRAISONAI_CONTEXT_MONITOR_FORMAT", "human"),
426-
monitor_frequency=os.getenv("PRAISONAI_CONTEXT_MONITOR_FREQUENCY", "turn"),
427-
monitor_write_mode=os.getenv("PRAISONAI_CONTEXT_MONITOR_WRITE_MODE", "sync"),
428-
redact_sensitive=get_bool("PRAISONAI_CONTEXT_REDACT", True),
429-
source="env",
430-
)
431-
432-
def merge(self, **overrides) -> "ManagerConfig":
433-
"""Create new config with overrides applied."""
434-
current = self.to_dict()
435-
436-
for key, value in overrides.items():
437-
if value is not None and key in current:
438-
current[key] = value
439-
440-
# Handle enum conversions
441-
if isinstance(current.get("strategy"), str):
442-
try:
443-
current["strategy"] = OptimizerStrategy(current["strategy"])
444-
except ValueError:
445-
current["strategy"] = OptimizerStrategy.SMART
446-
447-
if isinstance(current.get("estimation_mode"), str):
448-
try:
449-
current["estimation_mode"] = EstimationMode(current["estimation_mode"])
450-
except ValueError:
451-
current["estimation_mode"] = EstimationMode.HEURISTIC
452-
453-
# Reconstruct tool budgets
454-
tool_budgets = {}
455-
for name, budget_dict in current.get("tool_budgets", {}).items():
456-
if isinstance(budget_dict, dict):
457-
tool_budgets[name] = PerToolBudget(**budget_dict)
458-
elif isinstance(budget_dict, PerToolBudget):
459-
tool_budgets[name] = budget_dict
460-
current["tool_budgets"] = tool_budgets
461-
462-
return ManagerConfig(**current)
463-
464-
465292
class ContextManager:
466293
"""
467294
Unified facade for context management.

0 commit comments

Comments
 (0)