kweaver-dolphin 0.1.0__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.
- DolphinLanguageSDK/__init__.py +58 -0
- dolphin/__init__.py +62 -0
- dolphin/cli/__init__.py +20 -0
- dolphin/cli/args/__init__.py +9 -0
- dolphin/cli/args/parser.py +567 -0
- dolphin/cli/builtin_agents/__init__.py +22 -0
- dolphin/cli/commands/__init__.py +4 -0
- dolphin/cli/interrupt/__init__.py +8 -0
- dolphin/cli/interrupt/handler.py +205 -0
- dolphin/cli/interrupt/keyboard.py +82 -0
- dolphin/cli/main.py +49 -0
- dolphin/cli/multimodal/__init__.py +34 -0
- dolphin/cli/multimodal/clipboard.py +327 -0
- dolphin/cli/multimodal/handler.py +249 -0
- dolphin/cli/multimodal/image_processor.py +214 -0
- dolphin/cli/multimodal/input_parser.py +149 -0
- dolphin/cli/runner/__init__.py +8 -0
- dolphin/cli/runner/runner.py +989 -0
- dolphin/cli/ui/__init__.py +10 -0
- dolphin/cli/ui/console.py +2795 -0
- dolphin/cli/ui/input.py +340 -0
- dolphin/cli/ui/layout.py +425 -0
- dolphin/cli/ui/stream_renderer.py +302 -0
- dolphin/cli/utils/__init__.py +8 -0
- dolphin/cli/utils/helpers.py +135 -0
- dolphin/cli/utils/version.py +49 -0
- dolphin/core/__init__.py +107 -0
- dolphin/core/agent/__init__.py +10 -0
- dolphin/core/agent/agent_state.py +69 -0
- dolphin/core/agent/base_agent.py +970 -0
- dolphin/core/code_block/__init__.py +0 -0
- dolphin/core/code_block/agent_init_block.py +0 -0
- dolphin/core/code_block/assign_block.py +98 -0
- dolphin/core/code_block/basic_code_block.py +1865 -0
- dolphin/core/code_block/explore_block.py +1327 -0
- dolphin/core/code_block/explore_block_v2.py +712 -0
- dolphin/core/code_block/explore_strategy.py +672 -0
- dolphin/core/code_block/judge_block.py +220 -0
- dolphin/core/code_block/prompt_block.py +32 -0
- dolphin/core/code_block/skill_call_deduplicator.py +291 -0
- dolphin/core/code_block/tool_block.py +129 -0
- dolphin/core/common/__init__.py +17 -0
- dolphin/core/common/constants.py +176 -0
- dolphin/core/common/enums.py +1173 -0
- dolphin/core/common/exceptions.py +133 -0
- dolphin/core/common/multimodal.py +539 -0
- dolphin/core/common/object_type.py +165 -0
- dolphin/core/common/output_format.py +432 -0
- dolphin/core/common/types.py +36 -0
- dolphin/core/config/__init__.py +16 -0
- dolphin/core/config/global_config.py +1289 -0
- dolphin/core/config/ontology_config.py +133 -0
- dolphin/core/context/__init__.py +12 -0
- dolphin/core/context/context.py +1580 -0
- dolphin/core/context/context_manager.py +161 -0
- dolphin/core/context/var_output.py +82 -0
- dolphin/core/context/variable_pool.py +356 -0
- dolphin/core/context_engineer/__init__.py +41 -0
- dolphin/core/context_engineer/config/__init__.py +5 -0
- dolphin/core/context_engineer/config/settings.py +402 -0
- dolphin/core/context_engineer/core/__init__.py +7 -0
- dolphin/core/context_engineer/core/budget_manager.py +327 -0
- dolphin/core/context_engineer/core/context_assembler.py +583 -0
- dolphin/core/context_engineer/core/context_manager.py +637 -0
- dolphin/core/context_engineer/core/tokenizer_service.py +260 -0
- dolphin/core/context_engineer/example/incremental_example.py +267 -0
- dolphin/core/context_engineer/example/traditional_example.py +334 -0
- dolphin/core/context_engineer/services/__init__.py +5 -0
- dolphin/core/context_engineer/services/compressor.py +399 -0
- dolphin/core/context_engineer/utils/__init__.py +6 -0
- dolphin/core/context_engineer/utils/context_utils.py +441 -0
- dolphin/core/context_engineer/utils/message_formatter.py +270 -0
- dolphin/core/context_engineer/utils/token_utils.py +139 -0
- dolphin/core/coroutine/__init__.py +15 -0
- dolphin/core/coroutine/context_snapshot.py +154 -0
- dolphin/core/coroutine/context_snapshot_profile.py +922 -0
- dolphin/core/coroutine/context_snapshot_store.py +268 -0
- dolphin/core/coroutine/execution_frame.py +145 -0
- dolphin/core/coroutine/execution_state_registry.py +161 -0
- dolphin/core/coroutine/resume_handle.py +101 -0
- dolphin/core/coroutine/step_result.py +101 -0
- dolphin/core/executor/__init__.py +18 -0
- dolphin/core/executor/debug_controller.py +630 -0
- dolphin/core/executor/dolphin_executor.py +1063 -0
- dolphin/core/executor/executor.py +624 -0
- dolphin/core/flags/__init__.py +27 -0
- dolphin/core/flags/definitions.py +49 -0
- dolphin/core/flags/manager.py +113 -0
- dolphin/core/hook/__init__.py +95 -0
- dolphin/core/hook/expression_evaluator.py +499 -0
- dolphin/core/hook/hook_dispatcher.py +380 -0
- dolphin/core/hook/hook_types.py +248 -0
- dolphin/core/hook/isolated_variable_pool.py +284 -0
- dolphin/core/interfaces.py +53 -0
- dolphin/core/llm/__init__.py +0 -0
- dolphin/core/llm/llm.py +495 -0
- dolphin/core/llm/llm_call.py +100 -0
- dolphin/core/llm/llm_client.py +1285 -0
- dolphin/core/llm/message_sanitizer.py +120 -0
- dolphin/core/logging/__init__.py +20 -0
- dolphin/core/logging/logger.py +526 -0
- dolphin/core/message/__init__.py +8 -0
- dolphin/core/message/compressor.py +749 -0
- dolphin/core/parser/__init__.py +8 -0
- dolphin/core/parser/parser.py +405 -0
- dolphin/core/runtime/__init__.py +10 -0
- dolphin/core/runtime/runtime_graph.py +926 -0
- dolphin/core/runtime/runtime_instance.py +446 -0
- dolphin/core/skill/__init__.py +14 -0
- dolphin/core/skill/context_retention.py +157 -0
- dolphin/core/skill/skill_function.py +686 -0
- dolphin/core/skill/skill_matcher.py +282 -0
- dolphin/core/skill/skillkit.py +700 -0
- dolphin/core/skill/skillset.py +72 -0
- dolphin/core/trajectory/__init__.py +10 -0
- dolphin/core/trajectory/recorder.py +189 -0
- dolphin/core/trajectory/trajectory.py +522 -0
- dolphin/core/utils/__init__.py +9 -0
- dolphin/core/utils/cache_kv.py +212 -0
- dolphin/core/utils/tools.py +340 -0
- dolphin/lib/__init__.py +93 -0
- dolphin/lib/debug/__init__.py +8 -0
- dolphin/lib/debug/visualizer.py +409 -0
- dolphin/lib/memory/__init__.py +28 -0
- dolphin/lib/memory/async_processor.py +220 -0
- dolphin/lib/memory/llm_calls.py +195 -0
- dolphin/lib/memory/manager.py +78 -0
- dolphin/lib/memory/sandbox.py +46 -0
- dolphin/lib/memory/storage.py +245 -0
- dolphin/lib/memory/utils.py +51 -0
- dolphin/lib/ontology/__init__.py +12 -0
- dolphin/lib/ontology/basic/__init__.py +0 -0
- dolphin/lib/ontology/basic/base.py +102 -0
- dolphin/lib/ontology/basic/concept.py +130 -0
- dolphin/lib/ontology/basic/object.py +11 -0
- dolphin/lib/ontology/basic/relation.py +63 -0
- dolphin/lib/ontology/datasource/__init__.py +27 -0
- dolphin/lib/ontology/datasource/datasource.py +66 -0
- dolphin/lib/ontology/datasource/oracle_datasource.py +338 -0
- dolphin/lib/ontology/datasource/sql.py +845 -0
- dolphin/lib/ontology/mapping.py +177 -0
- dolphin/lib/ontology/ontology.py +733 -0
- dolphin/lib/ontology/ontology_context.py +16 -0
- dolphin/lib/ontology/ontology_manager.py +107 -0
- dolphin/lib/skill_results/__init__.py +31 -0
- dolphin/lib/skill_results/cache_backend.py +559 -0
- dolphin/lib/skill_results/result_processor.py +181 -0
- dolphin/lib/skill_results/result_reference.py +179 -0
- dolphin/lib/skill_results/skillkit_hook.py +324 -0
- dolphin/lib/skill_results/strategies.py +328 -0
- dolphin/lib/skill_results/strategy_registry.py +150 -0
- dolphin/lib/skillkits/__init__.py +44 -0
- dolphin/lib/skillkits/agent_skillkit.py +155 -0
- dolphin/lib/skillkits/cognitive_skillkit.py +82 -0
- dolphin/lib/skillkits/env_skillkit.py +250 -0
- dolphin/lib/skillkits/mcp_adapter.py +616 -0
- dolphin/lib/skillkits/mcp_skillkit.py +771 -0
- dolphin/lib/skillkits/memory_skillkit.py +650 -0
- dolphin/lib/skillkits/noop_skillkit.py +31 -0
- dolphin/lib/skillkits/ontology_skillkit.py +89 -0
- dolphin/lib/skillkits/plan_act_skillkit.py +452 -0
- dolphin/lib/skillkits/resource/__init__.py +52 -0
- dolphin/lib/skillkits/resource/models/__init__.py +6 -0
- dolphin/lib/skillkits/resource/models/skill_config.py +109 -0
- dolphin/lib/skillkits/resource/models/skill_meta.py +127 -0
- dolphin/lib/skillkits/resource/resource_skillkit.py +393 -0
- dolphin/lib/skillkits/resource/skill_cache.py +215 -0
- dolphin/lib/skillkits/resource/skill_loader.py +395 -0
- dolphin/lib/skillkits/resource/skill_validator.py +406 -0
- dolphin/lib/skillkits/resource_skillkit.py +11 -0
- dolphin/lib/skillkits/search_skillkit.py +163 -0
- dolphin/lib/skillkits/sql_skillkit.py +274 -0
- dolphin/lib/skillkits/system_skillkit.py +509 -0
- dolphin/lib/skillkits/vm_skillkit.py +65 -0
- dolphin/lib/utils/__init__.py +9 -0
- dolphin/lib/utils/data_process.py +207 -0
- dolphin/lib/utils/handle_progress.py +178 -0
- dolphin/lib/utils/security.py +139 -0
- dolphin/lib/utils/text_retrieval.py +462 -0
- dolphin/lib/vm/__init__.py +11 -0
- dolphin/lib/vm/env_executor.py +895 -0
- dolphin/lib/vm/python_session_manager.py +453 -0
- dolphin/lib/vm/vm.py +610 -0
- dolphin/sdk/__init__.py +60 -0
- dolphin/sdk/agent/__init__.py +12 -0
- dolphin/sdk/agent/agent_factory.py +236 -0
- dolphin/sdk/agent/dolphin_agent.py +1106 -0
- dolphin/sdk/api/__init__.py +4 -0
- dolphin/sdk/runtime/__init__.py +8 -0
- dolphin/sdk/runtime/env.py +363 -0
- dolphin/sdk/skill/__init__.py +10 -0
- dolphin/sdk/skill/global_skills.py +706 -0
- dolphin/sdk/skill/traditional_toolkit.py +260 -0
- kweaver_dolphin-0.1.0.dist-info/METADATA +521 -0
- kweaver_dolphin-0.1.0.dist-info/RECORD +199 -0
- kweaver_dolphin-0.1.0.dist-info/WHEEL +5 -0
- kweaver_dolphin-0.1.0.dist-info/entry_points.txt +27 -0
- kweaver_dolphin-0.1.0.dist-info/licenses/LICENSE.txt +201 -0
- kweaver_dolphin-0.1.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Context Manager module for backward compatibility.
|
|
3
|
+
|
|
4
|
+
This module provides the ContextEngineer class which is an alias/wrapper
|
|
5
|
+
around MessageCompressor for SDK compatibility.
|
|
6
|
+
|
|
7
|
+
Note: The compression strategies (TruncationStrategy, SlidingWindowStrategy,
|
|
8
|
+
LevelStrategy) are now defined in dolphin.core.message.compressor.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from typing import List, Dict, Optional, TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
from dolphin.core.common.enums import Messages
|
|
14
|
+
from dolphin.core.config.global_config import ContextEngineerConfig
|
|
15
|
+
|
|
16
|
+
# Import compression classes from the canonical location
|
|
17
|
+
from dolphin.core.message.compressor import (
|
|
18
|
+
CompressionResult,
|
|
19
|
+
CompressionStrategy,
|
|
20
|
+
TruncationStrategy,
|
|
21
|
+
SlidingWindowStrategy,
|
|
22
|
+
LevelStrategy,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from dolphin.core.config.global_config import (
|
|
27
|
+
ContextConstraints,
|
|
28
|
+
LLMInstanceConfig,
|
|
29
|
+
)
|
|
30
|
+
from dolphin.core.context.context import Context
|
|
31
|
+
|
|
32
|
+
from dolphin.core.logging.logger import get_logger
|
|
33
|
+
|
|
34
|
+
logger = get_logger("context_engineer")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Re-export for backward compatibility
|
|
38
|
+
__all__ = [
|
|
39
|
+
"CompressionResult",
|
|
40
|
+
"CompressionStrategy",
|
|
41
|
+
"TruncationStrategy",
|
|
42
|
+
"SlidingWindowStrategy",
|
|
43
|
+
"LevelStrategy",
|
|
44
|
+
"ContextEngineer",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ContextEngineer:
|
|
49
|
+
"""Context Engineer: Responsible for optimizing message context to meet model constraints.
|
|
50
|
+
|
|
51
|
+
This class is maintained for backward compatibility with the SDK.
|
|
52
|
+
New code should use MessageCompressor from dolphin.core.message.compressor instead.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, config: "ContextEngineerConfig" = None, context: "Context" = None):
|
|
56
|
+
self.config = config or ContextEngineerConfig()
|
|
57
|
+
self.context = context
|
|
58
|
+
self.strategies = self._register_default_strategies()
|
|
59
|
+
logger.debug(
|
|
60
|
+
f"ContextEngineer initialized with strategy: {self.config.default_strategy}"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def _register_default_strategies(self) -> Dict[str, CompressionStrategy]:
|
|
64
|
+
"""Register default compression strategy"""
|
|
65
|
+
strategies = {
|
|
66
|
+
"level": LevelStrategy(),
|
|
67
|
+
"truncation": TruncationStrategy(),
|
|
68
|
+
"sliding_window_5": SlidingWindowStrategy(5),
|
|
69
|
+
"sliding_window_10": SlidingWindowStrategy(10),
|
|
70
|
+
"sliding_window_20": SlidingWindowStrategy(20),
|
|
71
|
+
}
|
|
72
|
+
# Merge user-defined policy configurations
|
|
73
|
+
for name, strategy_config in self.config.strategy_configs.items():
|
|
74
|
+
# Here, corresponding strategy instances can be created based on strategy_config
|
|
75
|
+
# Skip temporarily, keep extension interface
|
|
76
|
+
pass
|
|
77
|
+
return strategies
|
|
78
|
+
|
|
79
|
+
def engineer_context(
|
|
80
|
+
self,
|
|
81
|
+
messages: Messages,
|
|
82
|
+
strategy_name: Optional[str] = None,
|
|
83
|
+
constraints: Optional["ContextConstraints"] = None,
|
|
84
|
+
model_config: Optional["LLMInstanceConfig"] = None,
|
|
85
|
+
**kwargs,
|
|
86
|
+
) -> CompressionResult:
|
|
87
|
+
"""Engineering processing of context
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
messages: List of original messages
|
|
91
|
+
strategy_name: Name of the compression strategy to use, default uses the default strategy from configuration
|
|
92
|
+
constraints: Compression constraints, default uses constraints from configuration
|
|
93
|
+
model_config: Model configuration, used to automatically adjust constraints
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
CompressionResult: Compression result
|
|
97
|
+
"""
|
|
98
|
+
# Select Strategy
|
|
99
|
+
strategy_name = strategy_name or self.config.default_strategy
|
|
100
|
+
if strategy_name not in self.strategies:
|
|
101
|
+
logger.warning(f"Strategy '{strategy_name}' not found, using 'truncation'")
|
|
102
|
+
strategy_name = "truncation"
|
|
103
|
+
if strategy_name not in self.strategies:
|
|
104
|
+
# If there is no truncation at all, create a default one.
|
|
105
|
+
self.strategies["truncation"] = TruncationStrategy()
|
|
106
|
+
|
|
107
|
+
strategy = self.strategies[strategy_name]
|
|
108
|
+
|
|
109
|
+
# Select constraint conditions; if model_config is provided, adjust constraints according to model capabilities.
|
|
110
|
+
if constraints is None:
|
|
111
|
+
constraints = self.config.constraints
|
|
112
|
+
|
|
113
|
+
# Automatically adjust constraints according to model_config
|
|
114
|
+
if model_config is not None:
|
|
115
|
+
from dolphin.core.config.global_config import ContextConstraints
|
|
116
|
+
|
|
117
|
+
# Dynamically create constraints suitable for the current model
|
|
118
|
+
adjusted_constraints = ContextConstraints(
|
|
119
|
+
max_input_tokens=constraints.max_input_tokens,
|
|
120
|
+
reserve_output_tokens=model_config.max_tokens, # Use the model's max_tokens as reserved output
|
|
121
|
+
preserve_system=constraints.preserve_system,
|
|
122
|
+
)
|
|
123
|
+
constraints = adjusted_constraints
|
|
124
|
+
|
|
125
|
+
logger.debug(
|
|
126
|
+
f"Adjusted constraints for model {model_config.model_name}: "
|
|
127
|
+
f"max_input={constraints.max_input_tokens}, "
|
|
128
|
+
f"reserve_output={constraints.reserve_output_tokens}"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Perform compression
|
|
132
|
+
result = strategy.compress(
|
|
133
|
+
context=self.context, messages=messages, constraints=constraints, **kwargs
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Log records
|
|
137
|
+
if result.compression_ratio < 1.0:
|
|
138
|
+
self.context.info(
|
|
139
|
+
f"Context compressed using {strategy_name}: "
|
|
140
|
+
f"{result.original_token_count} -> {result.compressed_token_count} tokens "
|
|
141
|
+
f"(ratio: {result.compression_ratio:.2f})"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
def register_strategy(self, name: str, strategy: CompressionStrategy):
|
|
147
|
+
"""Register a new compression strategy"""
|
|
148
|
+
self.strategies[name] = strategy
|
|
149
|
+
logger.debug(f"Registered new compression strategy: {name}")
|
|
150
|
+
|
|
151
|
+
def get_available_strategies(self) -> List[str]:
|
|
152
|
+
"""Get the list of available compression strategies"""
|
|
153
|
+
return list(self.strategies.keys())
|
|
154
|
+
|
|
155
|
+
def estimate_tokens(self, messages: Messages) -> int:
|
|
156
|
+
"""Estimate the number of tokens in a message"""
|
|
157
|
+
# Token estimation method using default strategy
|
|
158
|
+
default_strategy = self.strategies.get(
|
|
159
|
+
self.config.default_strategy, TruncationStrategy()
|
|
160
|
+
)
|
|
161
|
+
return default_strategy.estimate_tokens(messages)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from dolphin.core.common.types import SourceType, Var
|
|
2
|
+
from dolphin.core.common.enums import SkillInfo
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class VarOutput(Var):
|
|
6
|
+
def __init__(self, name, value, source_type=SourceType.OTHER, skill_info=None):
|
|
7
|
+
super().__init__(value)
|
|
8
|
+
|
|
9
|
+
self.name = name
|
|
10
|
+
self.source_type = source_type
|
|
11
|
+
self.skill_info = skill_info
|
|
12
|
+
|
|
13
|
+
def add(self, var: Var):
|
|
14
|
+
if self.source_type == SourceType.LIST:
|
|
15
|
+
self.val.append(var)
|
|
16
|
+
return self
|
|
17
|
+
|
|
18
|
+
return VarOutput(name=self.name, value=[self, var], source_type=SourceType.LIST)
|
|
19
|
+
|
|
20
|
+
def set_last(self, var: Var):
|
|
21
|
+
if self.source_type == SourceType.LIST:
|
|
22
|
+
self.val[-1] = var
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
def to_dict(self):
|
|
26
|
+
# Processing the serialization of value
|
|
27
|
+
if self.source_type == SourceType.LIST:
|
|
28
|
+
# LIST type: recursively serialize each VarOutput item
|
|
29
|
+
value = [item.to_dict() for item in self.val]
|
|
30
|
+
elif self.source_type == SourceType.EXPLORE:
|
|
31
|
+
# EXPLORE type: value is already a list of dictionaries, use directly
|
|
32
|
+
value = self.val
|
|
33
|
+
else:
|
|
34
|
+
value = self.val
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
"__type__": "VarOutput", # Type identifier for deserialization
|
|
38
|
+
"name": self.name,
|
|
39
|
+
"value": value,
|
|
40
|
+
"source_type": self.source_type.value,
|
|
41
|
+
"skill_info": self.skill_info.to_dict() if self.skill_info else {},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def is_serialized_dict(data) -> bool:
|
|
46
|
+
"""Check if data is a serialized VarOutput dictionary"""
|
|
47
|
+
return isinstance(data, dict) and data.get("__type__") == "VarOutput"
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def from_dict(dict_data: dict) -> "VarOutput":
|
|
51
|
+
source_type = SourceType(dict_data.get("source_type"))
|
|
52
|
+
if source_type == SourceType.LIST:
|
|
53
|
+
# LIST type: recursively deserialize each VarOutput item
|
|
54
|
+
value = [VarOutput.from_dict(item) for item in dict_data["value"]]
|
|
55
|
+
elif source_type == SourceType.EXPLORE:
|
|
56
|
+
# EXPLORE type: value is a regular dictionary list (exploration results), no recursive deserialization needed
|
|
57
|
+
value = dict_data["value"]
|
|
58
|
+
else:
|
|
59
|
+
value = dict_data["value"]
|
|
60
|
+
|
|
61
|
+
return VarOutput(
|
|
62
|
+
name=dict_data["name"],
|
|
63
|
+
value=value,
|
|
64
|
+
source_type=source_type,
|
|
65
|
+
skill_info=(
|
|
66
|
+
SkillInfo.from_dict(dict_data["skill_info"])
|
|
67
|
+
if dict_data["skill_info"]
|
|
68
|
+
else None
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def value(self):
|
|
74
|
+
if self.source_type == SourceType.LIST:
|
|
75
|
+
return [item.value for item in self.val]
|
|
76
|
+
return self.val
|
|
77
|
+
|
|
78
|
+
def __str__(self):
|
|
79
|
+
return f"{self.name}: {self.val}"
|
|
80
|
+
|
|
81
|
+
def __repr__(self):
|
|
82
|
+
return self.__str__()
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"""Dolphin Language SDK - Variable Pool Module
|
|
2
|
+
|
|
3
|
+
Variable Classification Description:
|
|
4
|
+
==============
|
|
5
|
+
|
|
6
|
+
1. User Variables
|
|
7
|
+
- Variables defined by user scripts
|
|
8
|
+
- Returned when retrieved via the get_user_variables() method
|
|
9
|
+
- Example: result, user_input, calculation, etc.
|
|
10
|
+
|
|
11
|
+
2. Internal Variables
|
|
12
|
+
- Automatically recognized: All variables starting with an underscore (_) are automatically treated as internal variables
|
|
13
|
+
- Special internal variables: props, usage
|
|
14
|
+
- Automatically excluded when retrieved via the get_user_variables() method
|
|
15
|
+
|
|
16
|
+
List of internal variables:
|
|
17
|
+
- _progress: Execution progress details
|
|
18
|
+
- _user_id: User ID (optionally included)
|
|
19
|
+
- _session_id: Session ID (optionally included)
|
|
20
|
+
- _max_answer_len: Maximum answer length (optionally included)
|
|
21
|
+
- _status: Current execution status
|
|
22
|
+
- _previous_status: Previous execution status
|
|
23
|
+
- props: Execution properties
|
|
24
|
+
- usage: Usage statistics
|
|
25
|
+
|
|
26
|
+
Methods to retrieve variables:
|
|
27
|
+
- get_user_variables(): Get user variables, excluding all internal variables
|
|
28
|
+
- get_user_variables(include_system_context_vars=True): Get user variables, including system context variables
|
|
29
|
+
- get_all_variables(): Get all variables (including internal variables)
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import re
|
|
33
|
+
|
|
34
|
+
from dolphin.core.common.constants import KEY_STATUS, KEY_PREVIOUS_STATUS
|
|
35
|
+
from dolphin.core.common.types import SourceType, Var
|
|
36
|
+
from dolphin.core.context.var_output import VarOutput
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class VariablePool:
|
|
40
|
+
def __init__(self):
|
|
41
|
+
self.variable_pool = {}
|
|
42
|
+
|
|
43
|
+
def copy(self):
|
|
44
|
+
new_variable_pool = VariablePool()
|
|
45
|
+
new_variable_pool.variable_pool = self.variable_pool.copy()
|
|
46
|
+
return new_variable_pool
|
|
47
|
+
|
|
48
|
+
def init_variables(self, variables):
|
|
49
|
+
self.variable_pool = {name: Var(value) for name, value in variables.items()}
|
|
50
|
+
|
|
51
|
+
def contain_var(self, name):
|
|
52
|
+
return name in self.variable_pool
|
|
53
|
+
|
|
54
|
+
def get_var(self, name):
|
|
55
|
+
return self.variable_pool.get(name)
|
|
56
|
+
|
|
57
|
+
def get_var_value(self, name, default_value=None):
|
|
58
|
+
var = self.variable_pool.get(name)
|
|
59
|
+
if not var:
|
|
60
|
+
return default_value
|
|
61
|
+
|
|
62
|
+
val = var.value
|
|
63
|
+
# Compatibility with dictionary structure after restoration from snapshot (VarOutput.to_dict format)
|
|
64
|
+
if isinstance(val, dict) and "value" in val and "source_type" in val:
|
|
65
|
+
inner = val.get("value")
|
|
66
|
+
# List scenario: extract the value of each element
|
|
67
|
+
if isinstance(inner, list):
|
|
68
|
+
return [
|
|
69
|
+
(
|
|
70
|
+
item.get("value")
|
|
71
|
+
if isinstance(item, dict) and "value" in item
|
|
72
|
+
else item
|
|
73
|
+
)
|
|
74
|
+
for item in inner
|
|
75
|
+
]
|
|
76
|
+
# Normal scenario: return the value field directly
|
|
77
|
+
return inner
|
|
78
|
+
|
|
79
|
+
return val
|
|
80
|
+
|
|
81
|
+
def get_var_path_value(self, varpath, default_value=None):
|
|
82
|
+
"""
|
|
83
|
+
Get value from variable pool using dot notation path
|
|
84
|
+
Example: get_var_path_value('user.profile.name')
|
|
85
|
+
:param varpath: Variable path with dot notation
|
|
86
|
+
:return: Value at the specified path
|
|
87
|
+
:raises: AttributeError if variable or path not found
|
|
88
|
+
"""
|
|
89
|
+
if not varpath:
|
|
90
|
+
return default_value
|
|
91
|
+
|
|
92
|
+
parts = varpath.split(".")
|
|
93
|
+
base_var = parts[0]
|
|
94
|
+
|
|
95
|
+
# Get base variable
|
|
96
|
+
var = self.get_var(base_var)
|
|
97
|
+
if var is None:
|
|
98
|
+
return default_value
|
|
99
|
+
|
|
100
|
+
value = var.value
|
|
101
|
+
|
|
102
|
+
# Navigate through the path
|
|
103
|
+
for part in parts[1:]:
|
|
104
|
+
if isinstance(value, dict):
|
|
105
|
+
if part not in value:
|
|
106
|
+
return default_value
|
|
107
|
+
value = value[part]
|
|
108
|
+
else:
|
|
109
|
+
return default_value
|
|
110
|
+
|
|
111
|
+
return value
|
|
112
|
+
|
|
113
|
+
def get_all_variables(self):
|
|
114
|
+
return {name: var.to_dict() for name, var in self.variable_pool.items()}
|
|
115
|
+
|
|
116
|
+
def get_user_variables(self, include_system_context_vars=False):
|
|
117
|
+
"""Get user-defined variables, excluding internal variables.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
include_system_context_vars: Whether to include system context variables (e.g., _user_id, _session_id, etc.)
|
|
121
|
+
Default is False for backward compatibility
|
|
122
|
+
|
|
123
|
+
Internal variable rules:
|
|
124
|
+
- All variables starting with an underscore (_) are automatically considered internal variables (unless explicitly included)
|
|
125
|
+
- Special internal variables: props, usage
|
|
126
|
+
|
|
127
|
+
If include_system_context_vars=True, the following system context variables will be included:
|
|
128
|
+
- _user_id: User ID
|
|
129
|
+
- _session_id: Session ID
|
|
130
|
+
- _max_answer_len: Maximum answer length
|
|
131
|
+
"""
|
|
132
|
+
# Automatically recognize all variables starting with an underscore as built-in variables
|
|
133
|
+
underscore_vars = {
|
|
134
|
+
name for name in self.variable_pool.keys() if name.startswith("_")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
# Extra internal variables (not starting with underscore)
|
|
138
|
+
additional_internal_vars = {"props", KEY_PREVIOUS_STATUS, KEY_STATUS, "usage"}
|
|
139
|
+
|
|
140
|
+
# System context variables (if requested by the user, these variables are not excluded)
|
|
141
|
+
system_context_vars = {"_user_id", "_session_id", "_max_answer_len"}
|
|
142
|
+
|
|
143
|
+
# Set of variables that need to be excluded in the end
|
|
144
|
+
if include_system_context_vars:
|
|
145
|
+
# Include system context variables: exclude all variables starting with underscores and additional internal variables, except for system context variables
|
|
146
|
+
internal_vars = (
|
|
147
|
+
underscore_vars - system_context_vars
|
|
148
|
+
) | additional_internal_vars
|
|
149
|
+
else:
|
|
150
|
+
# Default behavior: exclude all underscore variables and additional internal variables
|
|
151
|
+
internal_vars = underscore_vars | additional_internal_vars
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
name: var.to_dict()
|
|
155
|
+
for name, var in self.variable_pool.items()
|
|
156
|
+
if name not in internal_vars
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
def get_all_variables_values(self):
|
|
160
|
+
result = {}
|
|
161
|
+
for name, var in self.variable_pool.items():
|
|
162
|
+
val = var.value
|
|
163
|
+
if isinstance(val, dict) and "value" in val and "source_type" in val:
|
|
164
|
+
inner = val.get("value")
|
|
165
|
+
if isinstance(inner, list):
|
|
166
|
+
result[name] = [
|
|
167
|
+
(
|
|
168
|
+
item.get("value")
|
|
169
|
+
if isinstance(item, dict) and "value" in item
|
|
170
|
+
else item
|
|
171
|
+
)
|
|
172
|
+
for item in inner
|
|
173
|
+
]
|
|
174
|
+
else:
|
|
175
|
+
result[name] = inner
|
|
176
|
+
else:
|
|
177
|
+
result[name] = val
|
|
178
|
+
return result
|
|
179
|
+
|
|
180
|
+
def keys(self):
|
|
181
|
+
return self.variable_pool.keys()
|
|
182
|
+
|
|
183
|
+
def set_var(self, name, value):
|
|
184
|
+
if isinstance(value, Var):
|
|
185
|
+
self.variable_pool[name] = value
|
|
186
|
+
else:
|
|
187
|
+
self.variable_pool[name] = Var(value)
|
|
188
|
+
|
|
189
|
+
def set_var_output(
|
|
190
|
+
self, name, value, source_type=SourceType.OTHER, skill_info=None
|
|
191
|
+
):
|
|
192
|
+
# Create VarOutput with all parameters
|
|
193
|
+
self.variable_pool[name] = VarOutput(name, value, source_type, skill_info)
|
|
194
|
+
|
|
195
|
+
def delete_var(self, name):
|
|
196
|
+
if name in self.variable_pool:
|
|
197
|
+
del self.variable_pool[name]
|
|
198
|
+
|
|
199
|
+
def sync_variables(self, variable_pool: "VariablePool"):
|
|
200
|
+
for name, var in variable_pool.variable_pool.items():
|
|
201
|
+
self.variable_pool[name] = var
|
|
202
|
+
|
|
203
|
+
def clear(self):
|
|
204
|
+
self.variable_pool.clear()
|
|
205
|
+
|
|
206
|
+
def get_variable_type(self, variable_str):
|
|
207
|
+
"""Get variable value from string, including simple variables, array indices, and nested attributes
|
|
208
|
+
:param variable_str: Variable string, for example '$var', '$arr[0]', '$obj.attr'
|
|
209
|
+
:return: Variable value
|
|
210
|
+
"""
|
|
211
|
+
variable_name = variable_str[1:]
|
|
212
|
+
variable_name = convert_object_to_dict_access(variable_name)
|
|
213
|
+
if "." not in variable_str and "[" not in variable_str:
|
|
214
|
+
var = self.get_var(variable_name)
|
|
215
|
+
if var is None:
|
|
216
|
+
raise AttributeError(
|
|
217
|
+
f"Variable '{variable_name}' not found in variable pool"
|
|
218
|
+
)
|
|
219
|
+
value = var.value
|
|
220
|
+
else:
|
|
221
|
+
while "[0" in variable_name and "[0]" not in variable_name:
|
|
222
|
+
variable_name = variable_name.replace("[0", "[")
|
|
223
|
+
|
|
224
|
+
variable_first_name = (
|
|
225
|
+
variable_name.split(".")[0].strip().split("[")[0].strip()
|
|
226
|
+
)
|
|
227
|
+
var = self.get_var(variable_first_name)
|
|
228
|
+
if var is None:
|
|
229
|
+
raise AttributeError(
|
|
230
|
+
f"Variable '{variable_first_name}' not found in variable pool"
|
|
231
|
+
)
|
|
232
|
+
variable_value = var.value
|
|
233
|
+
variable_full_index = variable_name.replace(
|
|
234
|
+
variable_first_name, str(variable_value), 1
|
|
235
|
+
)
|
|
236
|
+
try:
|
|
237
|
+
value = eval(variable_full_index)
|
|
238
|
+
except Exception:
|
|
239
|
+
raise AttributeError(f"failed to eval '{variable_full_index}'")
|
|
240
|
+
|
|
241
|
+
if (
|
|
242
|
+
isinstance(value, list)
|
|
243
|
+
and len(value) > 0
|
|
244
|
+
and isinstance(value[0], dict)
|
|
245
|
+
and "agent_name" in value[0]
|
|
246
|
+
):
|
|
247
|
+
result = ""
|
|
248
|
+
for item in value:
|
|
249
|
+
if (
|
|
250
|
+
isinstance(item, dict)
|
|
251
|
+
and item.get("agent_name") == "main"
|
|
252
|
+
and "answer" in item
|
|
253
|
+
):
|
|
254
|
+
result += item["answer"]
|
|
255
|
+
value = result
|
|
256
|
+
return value
|
|
257
|
+
|
|
258
|
+
@staticmethod
|
|
259
|
+
def find_substring_positions(main_string, substring):
|
|
260
|
+
positions = []
|
|
261
|
+
start = 0
|
|
262
|
+
|
|
263
|
+
while True:
|
|
264
|
+
# Find the position of a substring
|
|
265
|
+
pos = main_string.find(substring, start)
|
|
266
|
+
if pos == -1:
|
|
267
|
+
break
|
|
268
|
+
positions.append(pos)
|
|
269
|
+
# Update the starting position to avoid infinite loops
|
|
270
|
+
start = pos + 1
|
|
271
|
+
return positions
|
|
272
|
+
|
|
273
|
+
def recognize_variable(self, dolphin_str):
|
|
274
|
+
# Identify the positions of all variables in the string - Simple variables: `$variableName` - Array indices: `$variableName[index]` - Nested properties: `$variableName.key1.key2`
|
|
275
|
+
"""Identify the positions of all variables in a string
|
|
276
|
+
:param dolphin_str: The string to be identified
|
|
277
|
+
:return: A list of tuples containing variable names and their positions [('variable name', (start position, end position)), ...]
|
|
278
|
+
"""
|
|
279
|
+
prompt_variable_pattern = re.compile(
|
|
280
|
+
r"\$[a-zA-Z_][a-zA-Z0-9_]*(?:(?:\.[a-zA-Z_][a-zA-Z0-9_]*)|(?:\[\d+\]))*"
|
|
281
|
+
)
|
|
282
|
+
matches = prompt_variable_pattern.findall(dolphin_str)
|
|
283
|
+
|
|
284
|
+
result = []
|
|
285
|
+
|
|
286
|
+
# Sort by length, with the longest variable names first
|
|
287
|
+
matches.sort(key=len, reverse=True)
|
|
288
|
+
|
|
289
|
+
# Record processed positions to avoid overlap
|
|
290
|
+
processed_positions = set()
|
|
291
|
+
|
|
292
|
+
for match in matches:
|
|
293
|
+
index_list = VariablePool.find_substring_positions(dolphin_str, match)
|
|
294
|
+
|
|
295
|
+
for start_pos in index_list:
|
|
296
|
+
end_pos = start_pos + len(match)
|
|
297
|
+
|
|
298
|
+
# Check whether this position has already been processed
|
|
299
|
+
if any(
|
|
300
|
+
start_pos >= existing_start and end_pos <= existing_end
|
|
301
|
+
for existing_start, existing_end in processed_positions
|
|
302
|
+
):
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
# Check whether a variable exists in the variable pool
|
|
306
|
+
variable_base_name = match[1:].split(".")[0].split("[")[0].strip()
|
|
307
|
+
if variable_base_name in self.variable_pool.keys():
|
|
308
|
+
result.append((match, (start_pos, end_pos)))
|
|
309
|
+
processed_positions.add((start_pos, end_pos))
|
|
310
|
+
|
|
311
|
+
return result
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def convert_object_to_dict_access(access_str):
|
|
315
|
+
"""
|
|
316
|
+
Convert object attribute access to dictionary access format
|
|
317
|
+
Example: "result.text[0].content[0].answer" -> "result['text'][0]['content'][0]['answer']"
|
|
318
|
+
"""
|
|
319
|
+
parts = []
|
|
320
|
+
current = ""
|
|
321
|
+
i = 0
|
|
322
|
+
while i < len(access_str):
|
|
323
|
+
if access_str[i] == ".":
|
|
324
|
+
if current:
|
|
325
|
+
parts.append(current)
|
|
326
|
+
current = ""
|
|
327
|
+
i += 1
|
|
328
|
+
elif access_str[i] == "[":
|
|
329
|
+
if current:
|
|
330
|
+
parts.append(current)
|
|
331
|
+
current = ""
|
|
332
|
+
# Find matching closing bracket
|
|
333
|
+
bracket_count = 1
|
|
334
|
+
j = i + 1
|
|
335
|
+
while j < len(access_str) and bracket_count > 0:
|
|
336
|
+
if access_str[j] == "[":
|
|
337
|
+
bracket_count += 1
|
|
338
|
+
elif access_str[j] == "]":
|
|
339
|
+
bracket_count -= 1
|
|
340
|
+
j += 1
|
|
341
|
+
parts.append(access_str[i:j])
|
|
342
|
+
i = j
|
|
343
|
+
else:
|
|
344
|
+
current += access_str[i]
|
|
345
|
+
i += 1
|
|
346
|
+
if current:
|
|
347
|
+
parts.append(current)
|
|
348
|
+
|
|
349
|
+
result = parts[0]
|
|
350
|
+
for i, part in enumerate(parts[1:], 1):
|
|
351
|
+
if part.startswith("["):
|
|
352
|
+
result += part
|
|
353
|
+
else:
|
|
354
|
+
result += f"['{part}']"
|
|
355
|
+
|
|
356
|
+
return result
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ContextEngineer: A system for optimizing context management in large language models.
|
|
3
|
+
|
|
4
|
+
This package provides tools for token budgeting, context optimization, and dynamic
|
|
5
|
+
information retrieval to maximize signal density while minimizing noise in LLM contexts.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
__author__ = "ContextEngineer Team"
|
|
10
|
+
|
|
11
|
+
from .core.budget_manager import BudgetManager
|
|
12
|
+
from .core.tokenizer_service import TokenizerService
|
|
13
|
+
from .core.context_assembler import ContextAssembler
|
|
14
|
+
from .services.compressor import Compressor
|
|
15
|
+
from .config.settings import ContextConfig, BucketConfig
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"BudgetManager",
|
|
19
|
+
"TokenizerService",
|
|
20
|
+
"ContextAssembler",
|
|
21
|
+
"Compressor",
|
|
22
|
+
"ContextConfig",
|
|
23
|
+
"BucketConfig",
|
|
24
|
+
"ContextEngineer",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def __getattr__(name: str):
|
|
29
|
+
"""Lazy import for ContextEngineer to avoid naming conflict with package."""
|
|
30
|
+
if name == "ContextEngineer":
|
|
31
|
+
import importlib.util
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
|
|
34
|
+
module_file = Path(__file__).resolve().parent.parent / "context_engineer.py"
|
|
35
|
+
if module_file.exists():
|
|
36
|
+
spec = importlib.util.spec_from_file_location("_context_engineer_module", module_file)
|
|
37
|
+
if spec and spec.loader:
|
|
38
|
+
module = importlib.util.module_from_spec(spec)
|
|
39
|
+
spec.loader.exec_module(module)
|
|
40
|
+
return module.ContextEngineer
|
|
41
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|