Duibonduil commited on
Commit
c721553
·
verified ·
1 Parent(s): 6eb9183

Upload 5 files

Browse files
aworld/core/context/README.md ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AWorld Context Management
2
+
3
+ Core context management system in the AWorld architecture, providing hierarchical state management through Context and AgentContext components for complete Agent state information storage and coordination.
4
+
5
+ ## Architecture Overview
6
+
7
+ ![Context Management](../../../readme_assets/context_management.png)
8
+
9
+ The Context Management system implements intelligent context processing with multiple optimization strategies based on context length analysis and configuration parameters.
10
+
11
+ ## Features
12
+
13
+ - Hierarchical context management with global and agent-specific scopes
14
+ - Complete Agent state management with support for state restoration and recovery
15
+ - Immutable configuration management and mutable runtime state tracking
16
+ - Intelligent LLM Prompt management and context optimization
17
+ - Complete LLM call intervention and control mechanisms
18
+ - Hook system support for extensible processing workflows
19
+ - Content compression and context window management
20
+
21
+ ## Core Components
22
+
23
+ - `Context`: Global singleton context manager spanning the entire AWorld Runner lifecycle
24
+ - `AgentContext`: Agent-specific context container for individual Agent execution periods
25
+ - `PromptProcessor`: Intelligent context processor supporting content compression and truncate
26
+ - `Hook System`: Extensible hook system supporting full-process LLM call intervention
27
+
28
+
29
+ ## Multi-Level Context
30
+
31
+ ![Context Lifecycle](../../../readme_assets/context_lifecycle.png)
32
+
33
+ The AWorld framework implements a hierarchical context management system with distinct lifecycles:
34
+
35
+ ### Context Lifecycle (Session)
36
+ Context is a singleton object that spans the entire AWorld Runner execution lifecycle, enabling global state sharing and coordination between multiple Agents in the AWorld framework.
37
+
38
+ - **Scope**: Spans the entire AWorld Runner execution period
39
+ - **Responsibility**: Global state management, task coordination, and resource allocation
40
+ - **Dictionary Interface**: Supports simple key-value state storage using `context['key'] = value` syntax
41
+ - **Function**: Manages multiple AgentContext instances and enables cross-agent data exchange
42
+ - **Multi-Agent Coordination**: Manages multiple AgentContext instances and enables seamless data exchange between different Agents
43
+ - **Session Management**: Provides (Session)Context API for cross-agent state management
44
+ - **Task Coordination**: Handles task management, agent coordination, and resource allocation
45
+
46
+ ### AgentContext Lifecycle (Agent-Specific)
47
+ - **Scope**: Spans individual Agent execution period
48
+ - **Responsibility**: Agent-specific state management and runtime tracking
49
+ - **Function**:
50
+ - **Configuration Management**: Maintains immutable Agent configuration (agent_id, agent_name, agent_desc, system_prompt, agent_prompt, tool_names, context_rule)
51
+ - **Runtime State Tracking**: Manages mutable runtime state (tools, step, messages, context_usage)
52
+ - **Dynamic Prompt Management**: Supports runtime modification of system_prompt and agent_prompt based on execution context
53
+ - **Tool Lifecycle Management**: Handles tool object initialization, execution, and state management
54
+ - **Conversation History**: Maintains complete message history throughout Agent execution
55
+ - **Step-by-Step Execution**: Tracks current execution step and manages step transitions
56
+ - **Context Optimization**: Monitors context usage statistics and applies context processing rules
57
+ - **State Persistence**: Preserves Agent state across multiple LLM calls and tool invocations within a single execution period
58
+
59
+ ### Example: State Management and Recovery
60
+
61
+ > **📋 Test Implementation**: See complete test implementation at [`tests/test_context_management.py::TestContextManagement::test_state_management_and_recovery()`](../../../tests/test_context_management.py)
62
+
63
+ ```python
64
+ class StateModifyAgent(Agent):
65
+ async def async_policy(self, observation, info=None, **kwargs):
66
+ result = await super().async_policy(observation, info, **kwargs)
67
+ self.context.state['policy_executed'] = True
68
+ return result
69
+
70
+ class StateTrackingAgent(Agent):
71
+ async def async_policy(self, observation, info=None, **kwargs):
72
+ result = await super().async_policy(observation, info, **kwargs)
73
+ assert self.context.state['policy_executed'] == True
74
+ return result
75
+
76
+ # Create custom agent instance
77
+ custom_agent = StateModifyAgent(
78
+ conf=AgentConfig(
79
+ llm_model_name=mock_model_name,
80
+ llm_base_url=mock_base_url,
81
+ llm_api_key=mock_api_key
82
+ ),
83
+ name="state_modify_agent",
84
+ system_prompt="You are a Python expert who provides detailed and practical answers.",
85
+ agent_prompt="You are a Python expert who provides detailed and practical answers.",
86
+ )
87
+
88
+ # Create a second agent for multi-agent testing
89
+ second_agent = StateTrackingAgent(
90
+ conf=AgentConfig(
91
+ llm_model_name=mock_model_name,
92
+ llm_base_url=mock_base_url,
93
+ llm_api_key=mock_api_key
94
+ ),
95
+ name="state_tracking_agent",
96
+ system_prompt="You are a helpful assistant.",
97
+ agent_prompt="You are a helpful assistant.",
98
+ )
99
+
100
+ # Run multi-agent scenario
101
+ response = run_multi_agent(
102
+ input="What is an agent. describe within 20 words",
103
+ agent1=custom_agent,
104
+ agent2=second_agent
105
+ )
106
+
107
+ # Verify state changes after execution
108
+ assert custom_agent.context.state.get('policy_executed', True)
109
+ assert second_agent.agent_context.state.get('policy_executed', True)
110
+ ```
111
+
112
+ ### Example: Hook System, LLM Call Intervention and Agent state sharing
113
+
114
+ > **📋 Test Implementation**: See complete Hook system test implementations at:
115
+ > - [`tests/test_context_management.py::TestHookSystem::test_hook_registration()`](../../../tests/test_context_management.py) - Hook registration test
116
+ > - [`tests/test_context_management.py::TestHookSystem::test_hook_execution()`](../../../tests/test_context_management.py) - Hook execution test
117
+
118
+ ```python
119
+ from aworld.runners.hook.hooks import PreLLMCallHook, PostLLMCallHook
120
+ from aworld.runners.hook.hook_factory import HookFactory
121
+ from aworld.utils.common import convert_to_snake
122
+ from aworld.core.event.base import Message
123
+ from aworld.core.context.base import Context
124
+
125
+ # Test Hook System functionality
126
+ @HookFactory.register(name="TestPreLLMHook", desc="Test pre-LLM hook")
127
+ class TestPreLLMHook(PreLLMCallHook):
128
+ """Test hook for pre-LLM processing"""
129
+
130
+ def name(self):
131
+ return convert_to_snake("TestPreLLMHook")
132
+
133
+ async def exec(self, message: Message, context: Context = None) -> Message:
134
+ """Test hook execution"""
135
+ agent_context = context.get_agent_context(message.sender)
136
+ if agent_context is not None:
137
+ agent_context.step = 1
138
+
139
+ assert agent_context.step == 1 or agent_context.step == 2
140
+ return message
141
+
142
+
143
+ @HookFactory.register(name="TestPostLLMHook", desc="Test post-LLM hook")
144
+ class TestPostLLMHook(PostLLMCallHook):
145
+ """Test hook for post-LLM processing"""
146
+
147
+ def name(self):
148
+ return convert_to_snake("TestPostLLMHook")
149
+
150
+ async def exec(self, message: Message, context: Context = None) -> Message:
151
+ """Test hook execution with llm_output processing"""
152
+ agent_context = context.get_agent_context(message.sender)
153
+ if agent_context is not None and agent_context.llm_output is not None:
154
+ # Test dynamic prompt adjustment based on LLM output
155
+ if hasattr(agent_context.llm_output, 'content'):
156
+ content = agent_context.llm_output.content.lower()
157
+ if content is not None:
158
+ agent_context.agent_prompt = "Success mode activated"
159
+
160
+ assert agent_context.agent_prompt == "Success mode activated"
161
+ return message
162
+
163
+ # Test hook registration and retrieval
164
+ assert "TestPreLLMHook" in HookFactory._cls
165
+ assert "TestPostLLMHook" in HookFactory._cls
166
+
167
+ # Test hook creation using __call__ method
168
+ pre_hook = HookFactory("TestPreLLMHook")
169
+ post_hook = HookFactory("TestPostLLMHook")
170
+
171
+ assert isinstance(pre_hook, TestPreLLMHook)
172
+ assert isinstance(post_hook, TestPostLLMHook)
173
+
174
+ # Test hook execution
175
+ response = agent.run("What is an agent. describe within 20 words")
176
+ assert response.answer is not None
177
+ ```
178
+
179
+ ## Context Rule Configuration
180
+
181
+ `ContextRuleConfig` provides comprehensive context management through two main configuration components:
182
+
183
+ ### OptimizationConfig
184
+
185
+ Controls context optimization behavior:
186
+
187
+ - `enabled`: Whether to enable context optimization (default: `False`)
188
+ - `max_token_budget_ratio`: Maximum token budget ratio for context window usage (default: `0.5`, range: 0.0-1.0)
189
+
190
+ ### LlmCompressionConfig (Beta Feature)
191
+
192
+ **⚠️ Beta Feature**: This configuration is currently in beta and may undergo changes in future versions.
193
+
194
+ Controls intelligent context compression:
195
+
196
+ - `enabled`: Whether to enable LLM-based compression (default: `False`)
197
+ - `trigger_compress_token_length`: Token threshold to trigger basic compression (default: `10000`)
198
+ - `trigger_mapreduce_compress_token_length`: Token threshold to trigger map-reduce compression (default: `100000`)
199
+ - `compress_model`: ModelConfig for compression LLM calls (optional)
200
+
201
+
202
+ ### Example: Using Default Context Configuration (Recommended)
203
+
204
+ > **📋 Test Implementation**: See default configuration test at [`tests/test_context_management.py::TestContextManagement::test_default_context_configuration()`](../../../tests/test_context_management.py)
205
+
206
+ ```python
207
+ from aworld.agents.llm_agent import Agent
208
+ from aworld.config.conf import AgentConfig
209
+
210
+ # No need to explicitly configure context_rule, system automatically uses default configuration
211
+ # Default configuration is equivalent to:
212
+ # context_rule=ContextRuleConfig(
213
+ # optimization_config=OptimizationConfig(
214
+ # enabled=True,
215
+ # max_token_budget_ratio=1.0 # Use 100% of context window
216
+ # ),
217
+ # llm_compression_config=LlmCompressionConfig(
218
+ # enabled=False # Compression disabled by default
219
+ # )
220
+ # )
221
+ response = agent.run("What is an agent. describe within 20 words")
222
+
223
+ assert response.answer is not None
224
+ assert agent.agent_context.model_config.llm_model_name == "llama-2-7b-chat-hf-function-calling-v2"
225
+
226
+ # Test default context rule behavior
227
+ assert agent.agent_context.context_rule is not None
228
+ assert agent.agent_context.context_rule.optimization_config is not None
229
+ ```
230
+
231
+ ### Example: Custom Context Configuration
232
+
233
+ > **📋 Test Implementation**: See custom configuration test at [`tests/test_context_management.py::TestContextManagement::test_custom_context_configuration()`](../../../tests/test_context_management.py)
234
+
235
+ ```python
236
+ from aworld.config.conf import AgentConfig, ContextRuleConfig, OptimizationConfig, LlmCompressionConfig, ModelConfig
237
+
238
+ # Create custom context rules
239
+ context_rule = ContextRuleConfig(
240
+ optimization_config=OptimizationConfig(
241
+ enabled=True,
242
+ max_token_budget_ratio=0.8 # Use 80% of context window
243
+ ),
244
+ llm_compression_config=LlmCompressionConfig(
245
+ enabled=True, # Enable beta compression feature
246
+ trigger_compress_token_length=100,
247
+ trigger_mapreduce_compress_token_length=1000,
248
+ compress_model=ModelConfig(
249
+ llm_model_name="llama-2-7b-chat-hf-function-calling-v2",
250
+ llm_base_url="http://localhost:1234/v1",
251
+ llm_api_key="lm-studio",
252
+ )
253
+ )
254
+ )
255
+
256
+ # Save original rule for restoration
257
+ origin_rule = agent.agent_context.context_rule
258
+ agent.update_context_rule(context_rule)
259
+
260
+ # Test the agent with custom configuration
261
+ response = agent.run("What is an agent. describe within 20 words")
262
+ assert response.answer is not None
263
+
264
+ # Test configuration values
265
+ assert agent.agent_context.context_rule.optimization_config.enabled == True
266
+ assert agent.agent_context.context_rule.llm_compression_config.enabled == True
267
+
268
+ # Restore original rule
269
+ agent.update_context_rule(origin_rule)
270
+ ```
271
+
272
+ ## Notes
273
+
274
+ 1. **Hierarchical Lifecycle**: Context spans the entire AWorld Runner execution while AgentContext spans individual Agent executions, as illustrated in the context lifecycle diagram.
275
+ 2. **Beta Features**: The `llm_compression_config` is currently in beta. Use with caution in production environments.
276
+ 3. **Performance Trade-offs**: Enabling compression can save token usage but increases processing time. Adjust configuration based on actual needs.
277
+ 4. **Model Compatibility**: Different models have different context length limitations. The system automatically adapts to model capabilities.
278
+ 5. **Default Configuration**: The system provides reasonable default configuration. Manual configuration is unnecessary for most scenarios.
279
+ 6. **State Management**: Context and AgentContext support state sharing between multiple Agents and ensures state consistency. State persistence functionality is currently under development.
280
+
281
+ Through proper configuration of Context and AgentContext with context processors, you can significantly improve Agent performance in long conversations and complex tasks while optimizing token usage efficiency.
aworld/core/context/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # coding: utf-8
2
+ # Copyright (c) 2025 inclusionAI.
aworld/core/context/base.py ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+ # Copyright (c) 2025 inclusionAI.
3
+ from collections import OrderedDict
4
+ from dataclasses import dataclass
5
+ from typing import Dict, List, Any, Optional, TYPE_CHECKING
6
+
7
+ from aworld.config import ConfigDict
8
+ from aworld.config.conf import ContextRuleConfig, ModelConfig
9
+ from aworld.core.context.context_state import ContextState
10
+ from aworld.core.context.session import Session
11
+ from aworld.core.singleton import InheritanceSingleton
12
+ from aworld.models.model_response import ModelResponse
13
+ from aworld.utils.common import nest_dict_counter
14
+
15
+ if TYPE_CHECKING:
16
+ from aworld.core.task import Task
17
+
18
+ @dataclass
19
+ class ContextUsage:
20
+ total_context_length: int = 128000
21
+ used_context_length: int = 0
22
+ def __init__(self, total_context_length: int = 128000, used_context_length: int = 0):
23
+ self.total_context_length = total_context_length
24
+ self.used_context_length = used_context_length
25
+
26
+ class Context(InheritanceSingleton):
27
+ """Single instance, can use construction or `instance` static method to create or get `Context` instance.
28
+
29
+ Examples:
30
+ >>> context = Context()
31
+ or
32
+ >>> context = Context.instance()
33
+ """
34
+
35
+ def __init__(self,
36
+ user: str = None,
37
+ task_id: str = None,
38
+ trace_id: str = None,
39
+ session: Session = None,
40
+ engine: str = None,
41
+ **kwargs):
42
+
43
+ super().__init__()
44
+ self._user = user
45
+ self._init(task_id=task_id, trace_id=trace_id, session=session, engine=engine, **kwargs)
46
+
47
+ def _init(self, *, task_id: str = None, trace_id: str = None, session: Session = None, engine: str = None):
48
+ self._task_id = task_id
49
+ self._task = None
50
+ self._engine = engine
51
+ self._trace_id = trace_id
52
+ self._session: Session = session
53
+ self.context_info = ConfigDict()
54
+ self.agent_info = ConfigDict()
55
+ self.trajectories = OrderedDict()
56
+ self._token_usage = {
57
+ "completion_tokens": 0,
58
+ "prompt_tokens": 0,
59
+ "total_tokens": 0,
60
+ }
61
+ self.state = ContextState()
62
+ # TODO swarm topology
63
+ # TODO workspace
64
+
65
+ self._swarm = None
66
+ self._event_manager = None
67
+
68
+ def add_token(self, usage: Dict[str, int]):
69
+ self._token_usage = nest_dict_counter(self._token_usage, usage)
70
+
71
+ def reset(self, **kwargs):
72
+ self._init(**kwargs)
73
+
74
+ def set_task(self, task: 'Task'):
75
+ self._task = task
76
+
77
+ def get_task(self) -> 'Task':
78
+ return self._task
79
+
80
+ @property
81
+ def trace_id(self):
82
+ return self._trace_id
83
+
84
+ @trace_id.setter
85
+ def trace_id(self, trace_id):
86
+ self._trace_id = trace_id
87
+
88
+ @property
89
+ def token_usage(self):
90
+ return self._token_usage
91
+
92
+ @property
93
+ def engine(self):
94
+ return self._engine
95
+
96
+ @engine.setter
97
+ def engine(self, engine: str):
98
+ self._engine = engine
99
+
100
+ @property
101
+ def user(self):
102
+ return self._user
103
+
104
+ @user.setter
105
+ def user(self, user):
106
+ if user is not None:
107
+ self._user = user
108
+
109
+ @property
110
+ def task_id(self):
111
+ return self._task_id
112
+
113
+ @task_id.setter
114
+ def task_id(self, task_id):
115
+ if task_id is not None:
116
+ self._task_id = task_id
117
+
118
+ @property
119
+ def session_id(self):
120
+ if self.session:
121
+ return self.session.session_id
122
+ else:
123
+ return None
124
+
125
+ @property
126
+ def session(self):
127
+ return self._session
128
+
129
+ @session.setter
130
+ def session(self, session: Session):
131
+ self._session = session
132
+
133
+ @property
134
+ def swarm(self):
135
+ return self._swarm
136
+
137
+ @swarm.setter
138
+ def swarm(self, swarm: 'Swarm'):
139
+ self._swarm = swarm
140
+
141
+ @property
142
+ def event_manager(self):
143
+ return self._event_manager
144
+
145
+ @event_manager.setter
146
+ def event_manager(self, event_manager: 'EventManager'):
147
+ self._event_manager = event_manager
148
+
149
+ @property
150
+ def record_path(self):
151
+ return "."
152
+
153
+ @property
154
+ def is_task(self):
155
+ return True
156
+
157
+ @property
158
+ def enable_visible(self):
159
+ return False
160
+
161
+ @property
162
+ def enable_failover(self):
163
+ return False
164
+
165
+ @property
166
+ def enable_cluster(self):
167
+ return False
168
+
169
+ def get_state(self, key: str, default: Any = None) -> Any:
170
+ return self.state.get(key, default)
171
+
172
+ def set_state(self, key: str, value: Any):
173
+ self.state[key] = value
174
+
175
+
176
+
177
+ @dataclass
178
+ class AgentContext:
179
+ """Agent context containing both configuration and runtime state.
180
+
181
+ AgentContext is the core context management class in the AWorld architecture, used to store and manage
182
+ the complete state information of an Agent, including configuration data and runtime state. Its main functions are:
183
+
184
+ 1. **State Restoration**: Save all state information during Agent execution, supporting Agent state restoration and recovery
185
+ 2. **Configuration Management**: Store Agent's immutable configuration information (such as agent_id, system_prompt, etc.)
186
+ 3. **Runtime State Tracking**: Manage Agent's mutable state during execution (such as messages, step, tools, etc.)
187
+ 4. **LLM Prompt Management**: Manage and maintain the complete prompt context required for LLM calls, including system prompts, historical messages, etc.
188
+ 5. **LLM Call Intervention**: Provide complete control over the LLM call process through Hook and ContextProcessor
189
+
190
+ ## Lifecycle
191
+ The lifecycle of AgentContext is completely consistent with the Agent instance:
192
+ - **Creation**: Created during Agent initialization, containing initial configuration
193
+ - **Runtime**: Continuously update runtime state during Agent execution
194
+ - **Destruction**: Destroyed along with Agent instance destruction
195
+ ```
196
+ ┌─────────────────────── AWorld Runner ─────────────────────────┐
197
+ | ┌──────────────────── Agent Execution ────────────────────┐ │
198
+ │ │ ┌────────────── Step 1 ─────────────┐ ┌── Step 2 ──┐ │ │
199
+ │ │ │ [LLM Call] [Tool Call(s)] │
200
+ │ │ │ [ Context Update ] │
201
+ ```
202
+
203
+ ## Field Classification
204
+ - **Immutable Configuration Fields**: agent_id, agent_name, agent_desc, system_prompt,
205
+ agent_prompt, tool_names, context_rule
206
+ - **Mutable Runtime Fields**: tools, step, messages, context_usage, llm_output
207
+
208
+ ## LLM Call Intervention Mechanism
209
+ AgentContext implements complete control over LLM calls through the following mechanisms:
210
+
211
+ 1. **Hook System**:
212
+ - pre_llm_call_hook: Context preprocessing before LLM call
213
+ - post_llm_call_hook: Result post-processing after LLM call
214
+ - pre_tool_call_hook: Context adjustment before tool call
215
+ - post_tool_call_hook: State update after tool call
216
+
217
+ 2. **PromptProcessor**:
218
+ - Prompt Optimization: Optimize prompt content based on context length limitations
219
+ - Message Compression: Intelligently compress historical messages to fit model context window
220
+ - Context Rules: Apply context_rule for customized context processing
221
+
222
+ ## Usage Scenarios
223
+ 1. **Agent Initialization**: Create AgentContext containing configuration information
224
+ 2. **LLM Call Control**: Pass as info parameter in policy(), async_policy() methods to control LLM behavior
225
+ 3. **Hook Callbacks**: Access and modify LLM call context in various Hooks, use PromptProcessor for prompt optimization and context processing
226
+ 4. **State Recovery**: Recover Agent's complete state from persistent storage
227
+ """
228
+
229
+ # ===== Immutable Configuration Fields =====
230
+ agent_id: str = None
231
+ agent_name: str = None
232
+ agent_desc: str = None
233
+ system_prompt: str = None
234
+ agent_prompt: str = None
235
+ tool_names: List[str] = None
236
+ model_config: ModelConfig = None
237
+ context_rule: ContextRuleConfig = None
238
+ _context: Context = None
239
+ state: ContextState = None
240
+
241
+ # ===== Mutable Configuration Fields =====
242
+ tools: List[str] = None
243
+ step: int = 0
244
+ messages: List[Dict[str, Any]] = None
245
+ context_usage: ContextUsage = None
246
+ llm_output: ModelResponse = None
247
+
248
+ def __init__(self,
249
+ agent_id: str = None,
250
+ agent_name: str = None,
251
+ agent_desc: str = None,
252
+ system_prompt: str = None,
253
+ agent_prompt: str = None,
254
+ tool_names: List[str] = None,
255
+ model_config: ModelConfig = None,
256
+ context_rule: ContextRuleConfig = None,
257
+ tools: List[str] = None,
258
+ step: int = 0,
259
+ messages: List[Dict[str, Any]] = None,
260
+ context_usage: ContextUsage = None,
261
+ llm_output: ModelResponse = None,
262
+ context: Context = None,
263
+ parent_state: ContextState = None,
264
+ **kwargs):
265
+ # Configuration fields
266
+ self.agent_id = agent_id
267
+ self.agent_name = agent_name
268
+ self.agent_desc = agent_desc
269
+ self.system_prompt = system_prompt
270
+ self.agent_prompt = agent_prompt
271
+ self.tool_names = tool_names if tool_names is not None else []
272
+ self.model_config = model_config
273
+ self.context_rule = context_rule
274
+
275
+ # Runtime state fields
276
+ self.tools = tools if tools is not None else []
277
+ self.step = step
278
+ self.messages = messages if messages is not None else []
279
+ self.context_usage = context_usage if context_usage is not None else ContextUsage()
280
+ self.llm_output = llm_output
281
+
282
+ # Initialize Context with runner(session) level context
283
+ self._context = context
284
+ # Initialize ContextState with parent state (Context's state)
285
+ # If context_state is provided, use it as parent; otherwise will be set later
286
+ self.state = ContextState(parent_state=parent_state)
287
+
288
+ # Additional fields for backward compatibility
289
+ self._init(**kwargs)
290
+
291
+ def _init(self, **kwargs):
292
+ self._task_id = kwargs.get('task_id')
293
+
294
+ def set_model_config(self, model_config: ModelConfig):
295
+ self.model_config = model_config
296
+
297
+ def set_messages(self, messages: List[Dict[str, Any]]):
298
+ self.messages = messages
299
+
300
+ def set_tools(self, tools: List[str]):
301
+ self.tools = tools
302
+
303
+ def set_llm_output(self, llm_output: ModelResponse):
304
+ self.llm_output = llm_output
305
+
306
+ def increment_step(self) -> int:
307
+ self.step += 1
308
+ return self.step
309
+
310
+ def set_step(self, step: int):
311
+ self.step = step
312
+
313
+ def get_step(self) -> int:
314
+ return self.step
315
+
316
+ def update_context_usage(self, used_context_length: int = None, total_context_length: int = None):
317
+ if used_context_length is not None:
318
+ self.context_usage.used_context_length = used_context_length
319
+ if total_context_length is not None:
320
+ self.context_usage.total_context_length = total_context_length
321
+
322
+ def get_context_usage_ratio(self) -> float:
323
+ """Get context usage ratio"""
324
+ if self.context_usage.total_context_length <= 0:
325
+ return 0.0
326
+ return self.context_usage.used_context_length / self.context_usage.total_context_length
327
+
328
+ def set_parent_state(self, parent_state: ContextState):
329
+ self.state._parent_state = parent_state
330
+
331
+ def get_state(self, key: str, default: Any = None) -> Any:
332
+ return self.state.get(key, default)
333
+
334
+ def set_state(self, key: str, value: Any):
335
+ self.state[key] = value
336
+
337
+ def get_task(self) -> 'Task':
338
+ return self._context.get_task()
339
+
340
+ def get_session(self) -> Session:
341
+ return self._context.get_session()
342
+
343
+ def get_engine(self) -> str:
344
+ return self._context.get_engine()
345
+
346
+ def get_user(self) -> str:
347
+ return self._context.get_user()
aworld/core/context/context_state.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+
4
+ """
5
+ Context State Management System
6
+ Provides hierarchical state management with parent-child state inheritance
7
+ """
8
+
9
+ from typing import Any, Dict, List, Optional, Union
10
+
11
+
12
+ class ContextState:
13
+ """
14
+ Hierarchical state management class
15
+
16
+ Supports the following features:
17
+ - Parent-child state inheritance: Child states can access parent state data
18
+ - State priority: Local state takes precedence over parent state
19
+ - State isolation: Write operations only affect local state
20
+ - Flexible lookup: Supports multi-level state lookup
21
+ """
22
+
23
+ def __init__(self, parent_state: Optional['ContextState'] = None):
24
+ """
25
+ Initialize ContextState
26
+
27
+ Args:
28
+ parent_state: Parent state object for implementing state inheritance
29
+ """
30
+ self._data: Dict[str, Any] = {}
31
+ self._parent_state: Optional['ContextState'] = parent_state
32
+
33
+ def __getitem__(self, key: str) -> Any:
34
+ """Get state value with parent state inheritance support"""
35
+ if key in self._data:
36
+ return self._data[key]
37
+ elif self._parent_state is not None:
38
+ return self._parent_state[key]
39
+ else:
40
+ raise KeyError(f"Key '{key}' not found in state")
41
+
42
+ def __setitem__(self, key: str, value: Any) -> None:
43
+ """Set state value, only writes to local state"""
44
+ self._data[key] = value
45
+
46
+ def __delitem__(self, key: str) -> None:
47
+ """Delete state value, only deletes from local state"""
48
+ if key in self._data:
49
+ del self._data[key]
50
+ else:
51
+ raise KeyError(f"Key '{key}' not found in local state")
52
+
53
+ def __contains__(self, key: str) -> bool:
54
+ """Check if contains specified key, including parent state"""
55
+ return key in self._data or (self._parent_state is not None and key in self._parent_state)
56
+
57
+ def __len__(self) -> int:
58
+ """Return the count of all accessible states (including parent state)"""
59
+ keys = set(self._data.keys())
60
+ if self._parent_state is not None:
61
+ keys.update(self._parent_state.keys())
62
+ return len(keys)
63
+
64
+ def __iter__(self):
65
+ """Iterate over all accessible keys (including parent state)"""
66
+ keys = set(self._data.keys())
67
+ if self._parent_state is not None:
68
+ keys.update(self._parent_state.keys())
69
+ return iter(keys)
70
+
71
+ def get(self, key: str, default: Any = None) -> Any:
72
+ """
73
+ Get state value, return default value if not exists
74
+
75
+ Args:
76
+ key: The key to get
77
+ default: Default value
78
+
79
+ Returns:
80
+ Value corresponding to key or default value
81
+ """
82
+ try:
83
+ return self[key]
84
+ except KeyError:
85
+ return default
86
+
87
+ def update(self, other: Union[Dict[str, Any], 'ContextState']) -> None:
88
+ """
89
+ Batch update state
90
+
91
+ Args:
92
+ other: Data to update, can be dict or another ContextState
93
+ """
94
+ if isinstance(other, dict):
95
+ self._data.update(other)
96
+ elif isinstance(other, ContextState):
97
+ self._data.update(other._data)
98
+ else:
99
+ raise TypeError("update() argument must be dict or ContextState")
100
+
101
+ def pop(self, key: str, default: Any = None) -> Any:
102
+ """
103
+ Delete and return value of specified key, only operates on local state
104
+
105
+ Args:
106
+ key: The key to delete
107
+ default: Default value to return if key doesn't exist
108
+
109
+ Returns:
110
+ The deleted value or default value
111
+ """
112
+ return self._data.pop(key, default)
113
+
114
+ def clear(self) -> None:
115
+ """Clear local state (does not affect parent state)"""
116
+ self._data.clear()
117
+
118
+ def keys(self) -> List[str]:
119
+ """Return list of all accessible keys (including parent state)"""
120
+ keys = set(self._data.keys())
121
+ if self._parent_state is not None:
122
+ keys.update(self._parent_state.keys())
123
+ return list(keys)
124
+
125
+ def values(self) -> List[Any]:
126
+ """Return list of all accessible values (including parent state)"""
127
+ return [self[key] for key in self.keys()]
128
+
129
+ def items(self) -> List[tuple]:
130
+ """Return list of all accessible (key, value) pairs (including parent state)"""
131
+ return [(key, self[key]) for key in self.keys()]
132
+
133
+ def to_dict(self) -> Dict[str, Any]:
134
+ """
135
+ Convert to dictionary, including inherited parent state
136
+
137
+ Returns:
138
+ Dictionary containing all accessible states
139
+ """
140
+ result = {}
141
+ if self._parent_state is not None:
142
+ result.update(self._parent_state.to_dict())
143
+ result.update(self._data)
144
+ return result
145
+
146
+ def local_dict(self) -> Dict[str, Any]:
147
+ """
148
+ Get local state dictionary (excluding parent state)
149
+
150
+ Returns:
151
+ Dictionary containing only local state
152
+ """
153
+ return self._data.copy()
154
+
155
+ def set_parent(self, parent_state: Optional['ContextState']) -> None:
156
+ """
157
+ Set parent state
158
+
159
+ Args:
160
+ parent_state: New parent state object
161
+ """
162
+ self._parent_state = parent_state
163
+
164
+ def get_parent(self) -> Optional['ContextState']:
165
+ """
166
+ Get parent state object
167
+
168
+ Returns:
169
+ Parent state object or None
170
+ """
171
+ return self._parent_state
172
+
173
+ def has_parent(self) -> bool:
174
+ """
175
+ Check if has parent state
176
+
177
+ Returns:
178
+ True if has parent state, False otherwise
179
+ """
180
+ return self._parent_state is not None
181
+
182
+ def __repr__(self) -> str:
183
+ """Return string representation of state"""
184
+ local_count = len(self._data)
185
+ total_count = len(self)
186
+ parent_info = f" (with parent: {total_count - local_count} inherited)" if self._parent_state else ""
187
+ return f"ContextState(local: {local_count}{parent_info})"
188
+
189
+ def __str__(self) -> str:
190
+ """Return detailed string representation of state"""
191
+ return f"ContextState({self.to_dict()})"
aworld/core/context/session.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding: utf-8
2
+ # Copyright (c) 2025 inclusionAI.
3
+ import time
4
+ import uuid
5
+ from typing import List
6
+
7
+ from pydantic import BaseModel
8
+
9
+
10
+ class Session(BaseModel):
11
+ session_id: str = str(uuid.uuid1().hex)
12
+ last_update_time: float = time.time()
13
+ trajectories: List = []