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,302 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Stream Renderer - CLI Layer for Live Markdown Rendering
|
|
3
|
+
|
|
4
|
+
This module provides the CLI-layer rendering logic for LLM streaming output.
|
|
5
|
+
It is completely separate from the SDK core, allowing the SDK to remain
|
|
6
|
+
agnostic to terminal rendering concerns.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
renderer = LiveStreamRenderer()
|
|
10
|
+
renderer.start()
|
|
11
|
+
async for item in llm_chat_stream(..., on_stream_chunk=renderer.on_chunk):
|
|
12
|
+
...
|
|
13
|
+
renderer.stop()
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Optional, Callable
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _is_fixed_layout_active() -> bool:
|
|
20
|
+
"""Check if we're using the fixed bottom layout (scroll region is active).
|
|
21
|
+
|
|
22
|
+
When fixed layout is active, Rich Live is incompatible and should be disabled.
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
from dolphin.cli.ui.console import _active_status_bar
|
|
26
|
+
# If there's an active status bar with a fixed_row, we're in fixed layout mode
|
|
27
|
+
if _active_status_bar and hasattr(_active_status_bar, 'fixed_row'):
|
|
28
|
+
return _active_status_bar.fixed_row is not None
|
|
29
|
+
except ImportError:
|
|
30
|
+
pass
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class LiveStreamRenderer:
|
|
35
|
+
"""
|
|
36
|
+
Live Markdown renderer for LLM streaming output.
|
|
37
|
+
|
|
38
|
+
This class manages Rich's Live component to provide real-time
|
|
39
|
+
Markdown rendering of LLM responses. If Rich is not available,
|
|
40
|
+
or if fixed layout mode is active, it falls back to simple console output.
|
|
41
|
+
|
|
42
|
+
IMPORTANT: Rich Live is DISABLED when fixed bottom layout is active,
|
|
43
|
+
because Rich Live and ANSI scroll regions are fundamentally incompatible.
|
|
44
|
+
Rich Live takes over terminal control and breaks our scroll region setup.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, verbose: bool = True):
|
|
48
|
+
self._live = None
|
|
49
|
+
self._Markdown = None
|
|
50
|
+
self._verbose = verbose
|
|
51
|
+
self._started = False
|
|
52
|
+
self._rich_available = False
|
|
53
|
+
self._use_simple_mode = False # True when Rich Live is disabled
|
|
54
|
+
self._paused_status_bar = None # Track paused status bar for resume
|
|
55
|
+
self._has_output = False # Track if we've actually output something
|
|
56
|
+
|
|
57
|
+
def start(self) -> "LiveStreamRenderer":
|
|
58
|
+
"""
|
|
59
|
+
Start the Live renderer context.
|
|
60
|
+
|
|
61
|
+
Returns self for method chaining:
|
|
62
|
+
renderer = LiveStreamRenderer().start()
|
|
63
|
+
"""
|
|
64
|
+
if not self._verbose:
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
# Pause the status bar to avoid conflicts with streaming output
|
|
68
|
+
try:
|
|
69
|
+
from dolphin.cli.ui.console import _pause_active_status_bar
|
|
70
|
+
self._paused_status_bar = _pause_active_status_bar()
|
|
71
|
+
except ImportError:
|
|
72
|
+
self._paused_status_bar = None
|
|
73
|
+
|
|
74
|
+
# ALWAYS use simple mode in CLI
|
|
75
|
+
# Rich Live is INCOMPATIBLE with scroll regions and terminal layouts
|
|
76
|
+
# because it takes over terminal control and breaks cursor positioning
|
|
77
|
+
import sys
|
|
78
|
+
if sys.stdout.isatty():
|
|
79
|
+
self._use_simple_mode = True
|
|
80
|
+
self._started = True
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
# Non-TTY fallback: try Rich Live (for notebooks, etc.)
|
|
84
|
+
try:
|
|
85
|
+
from rich.live import Live
|
|
86
|
+
from rich.markdown import Markdown
|
|
87
|
+
|
|
88
|
+
self._Markdown = Markdown
|
|
89
|
+
self._live = Live(
|
|
90
|
+
Markdown(""),
|
|
91
|
+
auto_refresh=True,
|
|
92
|
+
refresh_per_second=10,
|
|
93
|
+
vertical_overflow="visible",
|
|
94
|
+
)
|
|
95
|
+
self._live.start()
|
|
96
|
+
self._rich_available = True
|
|
97
|
+
self._started = True
|
|
98
|
+
except ImportError:
|
|
99
|
+
self._rich_available = False
|
|
100
|
+
self._started = True
|
|
101
|
+
|
|
102
|
+
return self
|
|
103
|
+
|
|
104
|
+
def on_chunk(self, chunk_text: str, full_text: str, is_final: bool = False) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Callback for each streaming chunk.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
chunk_text: The new text in this chunk (delta)
|
|
110
|
+
full_text: The complete accumulated text so far
|
|
111
|
+
is_final: Whether this is the final chunk
|
|
112
|
+
"""
|
|
113
|
+
if not self._verbose:
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
if self._use_simple_mode:
|
|
117
|
+
# Line-buffered output with manual ANSI highlighting
|
|
118
|
+
# This provides basic Markdown formatting without Rich Live
|
|
119
|
+
if not hasattr(self, '_line_buffer'):
|
|
120
|
+
self._line_buffer = ""
|
|
121
|
+
|
|
122
|
+
self._line_buffer += chunk_text
|
|
123
|
+
|
|
124
|
+
# Process complete lines
|
|
125
|
+
while '\n' in self._line_buffer:
|
|
126
|
+
line, self._line_buffer = self._line_buffer.split('\n', 1)
|
|
127
|
+
self._print_highlighted_line(line)
|
|
128
|
+
self._has_output = True # Track that we've output something
|
|
129
|
+
|
|
130
|
+
elif self._rich_available and self._live and self._Markdown:
|
|
131
|
+
# Rich Live mode: update with full Markdown
|
|
132
|
+
self._live.update(self._Markdown(full_text))
|
|
133
|
+
else:
|
|
134
|
+
# Fallback: print incremental text
|
|
135
|
+
print(chunk_text, end="", flush=True)
|
|
136
|
+
|
|
137
|
+
def _print_highlighted_line(self, line: str) -> None:
|
|
138
|
+
"""Print a line with simple ANSI Markdown highlighting."""
|
|
139
|
+
# ANSI codes
|
|
140
|
+
BOLD = "\033[1m"
|
|
141
|
+
RESET = "\033[0m"
|
|
142
|
+
CYAN = "\033[36m"
|
|
143
|
+
GREEN = "\033[32m"
|
|
144
|
+
YELLOW = "\033[33m"
|
|
145
|
+
MAGENTA = "\033[35m"
|
|
146
|
+
BLUE = "\033[34m"
|
|
147
|
+
WHITE = "\033[37m"
|
|
148
|
+
DIM = "\033[2m"
|
|
149
|
+
BG_GRAY = "\033[48;5;236m" # Dark gray background for code
|
|
150
|
+
|
|
151
|
+
stripped = line.lstrip()
|
|
152
|
+
indent = line[:len(line) - len(stripped)]
|
|
153
|
+
|
|
154
|
+
# Track code block state
|
|
155
|
+
if not hasattr(self, '_in_code_block'):
|
|
156
|
+
self._in_code_block = False
|
|
157
|
+
self._code_lang = ""
|
|
158
|
+
|
|
159
|
+
# Code block start/end markers
|
|
160
|
+
if stripped.startswith('```'):
|
|
161
|
+
if not self._in_code_block:
|
|
162
|
+
# Starting a code block
|
|
163
|
+
self._in_code_block = True
|
|
164
|
+
self._code_lang = stripped[3:].strip()
|
|
165
|
+
lang_display = f" {self._code_lang}" if self._code_lang else ""
|
|
166
|
+
print(f"{indent}{DIM}╭───{lang_display}{'─' * max(0, 40 - len(lang_display))}╮{RESET}")
|
|
167
|
+
else:
|
|
168
|
+
# Ending a code block
|
|
169
|
+
self._in_code_block = False
|
|
170
|
+
self._code_lang = ""
|
|
171
|
+
print(f"{indent}{DIM}╰{'─' * 44}╯{RESET}")
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
# Inside code block - render code with special formatting
|
|
175
|
+
if self._in_code_block:
|
|
176
|
+
print(f"{indent}{DIM}│{RESET} {GREEN}{stripped}{RESET}")
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
# Headers (H1-H6) - check longer prefixes first, remove # prefix for cleaner output
|
|
180
|
+
if stripped.startswith('###### '):
|
|
181
|
+
title = stripped[7:] # Remove '###### '
|
|
182
|
+
print(f"{indent}{DIM}{title}{RESET}")
|
|
183
|
+
elif stripped.startswith('##### '):
|
|
184
|
+
title = stripped[6:] # Remove '##### '
|
|
185
|
+
print(f"{indent}{WHITE}{title}{RESET}")
|
|
186
|
+
elif stripped.startswith('#### '):
|
|
187
|
+
title = stripped[5:] # Remove '#### '
|
|
188
|
+
print(f"{indent}{BLUE}{BOLD}{title}{RESET}")
|
|
189
|
+
elif stripped.startswith('### '):
|
|
190
|
+
title = stripped[4:] # Remove '### '
|
|
191
|
+
print(f"{indent}{MAGENTA}{BOLD}{title}{RESET}")
|
|
192
|
+
elif stripped.startswith('## '):
|
|
193
|
+
title = stripped[3:] # Remove '## '
|
|
194
|
+
print(f"{indent}{CYAN}{BOLD}{title}{RESET}")
|
|
195
|
+
elif stripped.startswith('# '):
|
|
196
|
+
title = stripped[2:] # Remove '# '
|
|
197
|
+
print(f"{indent}{YELLOW}{BOLD}{title}{RESET}")
|
|
198
|
+
# Markdown tables - detect lines with | delimiters
|
|
199
|
+
elif stripped.startswith('|') and stripped.endswith('|'):
|
|
200
|
+
# Check if it's a separator row (|---|---|)
|
|
201
|
+
inner = stripped[1:-1]
|
|
202
|
+
if all(c in '-|: ' for c in inner):
|
|
203
|
+
# Table separator row - render as horizontal line
|
|
204
|
+
cells = inner.split('|')
|
|
205
|
+
rendered_cells = [DIM + '─' * max(3, len(cell.strip())) + RESET for cell in cells]
|
|
206
|
+
print(f"{indent}{DIM}├{'┼'.join(rendered_cells)}┤{RESET}")
|
|
207
|
+
else:
|
|
208
|
+
# Table data row - render with nice borders
|
|
209
|
+
cells = inner.split('|')
|
|
210
|
+
rendered_cells = [self._highlight_inline(cell.strip()) for cell in cells]
|
|
211
|
+
print(f"{indent}{DIM}│{RESET} {f' {DIM}│{RESET} '.join(rendered_cells)} {DIM}│{RESET}")
|
|
212
|
+
# Lists
|
|
213
|
+
elif stripped.startswith('- ') or stripped.startswith('* '):
|
|
214
|
+
bullet = stripped[0]
|
|
215
|
+
content = stripped[2:]
|
|
216
|
+
# Handle inline formatting in content
|
|
217
|
+
content = self._highlight_inline(content)
|
|
218
|
+
print(f"{indent}{GREEN}•{RESET} {content}")
|
|
219
|
+
# Numbered lists
|
|
220
|
+
elif len(stripped) > 2 and stripped[0].isdigit() and stripped[1] in '.:)':
|
|
221
|
+
num = stripped[0]
|
|
222
|
+
content = stripped[2:].lstrip()
|
|
223
|
+
content = self._highlight_inline(content)
|
|
224
|
+
print(f"{indent}{GREEN}{num}.{RESET} {content}")
|
|
225
|
+
# Regular text with inline formatting
|
|
226
|
+
else:
|
|
227
|
+
print(f"{indent}{self._highlight_inline(stripped)}")
|
|
228
|
+
|
|
229
|
+
def _highlight_inline(self, text: str) -> str:
|
|
230
|
+
"""Highlight inline Markdown: **bold**, `code`, etc."""
|
|
231
|
+
import re
|
|
232
|
+
BOLD = "\033[1m"
|
|
233
|
+
RESET = "\033[0m"
|
|
234
|
+
CYAN = "\033[36m"
|
|
235
|
+
DIM = "\033[2m"
|
|
236
|
+
|
|
237
|
+
# Replace **text** with bold
|
|
238
|
+
text = re.sub(r'\*\*(.+?)\*\*', f'{BOLD}\\1{RESET}', text)
|
|
239
|
+
# Replace `code` with cyan
|
|
240
|
+
text = re.sub(r'`([^`]+)`', f'{CYAN}\\1{RESET}', text)
|
|
241
|
+
return text
|
|
242
|
+
|
|
243
|
+
def _highlight_inline_bold(self, text: str) -> str:
|
|
244
|
+
"""Highlight **bold** text with ANSI codes. (Legacy, use _highlight_inline instead)"""
|
|
245
|
+
return self._highlight_inline(text)
|
|
246
|
+
|
|
247
|
+
def stop(self) -> None:
|
|
248
|
+
"""Stop the Live renderer and clean up."""
|
|
249
|
+
# Flush any remaining buffer in simple mode
|
|
250
|
+
if self._use_simple_mode and self._started:
|
|
251
|
+
if hasattr(self, '_line_buffer') and self._line_buffer:
|
|
252
|
+
# Print remaining content (may not end with newline)
|
|
253
|
+
self._print_highlighted_line(self._line_buffer)
|
|
254
|
+
self._line_buffer = ""
|
|
255
|
+
# Only add newline if we actually output something
|
|
256
|
+
elif hasattr(self, '_has_output') and self._has_output:
|
|
257
|
+
print() # End the streaming output with a newline
|
|
258
|
+
|
|
259
|
+
if self._live and self._started and not self._use_simple_mode:
|
|
260
|
+
try:
|
|
261
|
+
self._live.stop()
|
|
262
|
+
except Exception:
|
|
263
|
+
pass
|
|
264
|
+
self._started = False
|
|
265
|
+
self._use_simple_mode = False
|
|
266
|
+
self._has_output = False # Reset for next use
|
|
267
|
+
|
|
268
|
+
# Resume the status bar that was paused during streaming
|
|
269
|
+
if hasattr(self, '_paused_status_bar') and self._paused_status_bar:
|
|
270
|
+
try:
|
|
271
|
+
from dolphin.cli.ui.console import _resume_status_bar
|
|
272
|
+
_resume_status_bar(self._paused_status_bar)
|
|
273
|
+
except ImportError:
|
|
274
|
+
pass
|
|
275
|
+
self._paused_status_bar = None
|
|
276
|
+
|
|
277
|
+
def __enter__(self) -> "LiveStreamRenderer":
|
|
278
|
+
"""Context manager support."""
|
|
279
|
+
return self.start()
|
|
280
|
+
|
|
281
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
282
|
+
"""Context manager cleanup."""
|
|
283
|
+
self.stop()
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
# Convenience function for getting a renderer callback
|
|
287
|
+
def create_stream_renderer(verbose: bool = True) -> tuple:
|
|
288
|
+
"""
|
|
289
|
+
Create a stream renderer and return (renderer, callback).
|
|
290
|
+
|
|
291
|
+
Usage:
|
|
292
|
+
renderer, on_chunk = create_stream_renderer()
|
|
293
|
+
renderer.start()
|
|
294
|
+
async for item in llm_chat_stream(..., on_stream_chunk=on_chunk):
|
|
295
|
+
...
|
|
296
|
+
renderer.stop()
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
Tuple of (LiveStreamRenderer instance, on_chunk callback)
|
|
300
|
+
"""
|
|
301
|
+
renderer = LiveStreamRenderer(verbose=verbose)
|
|
302
|
+
return renderer, renderer.on_chunk
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for Dolphin CLI
|
|
3
|
+
|
|
4
|
+
This module contains helper functions used by the CLI.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
from typing import Any, Dict, List
|
|
10
|
+
|
|
11
|
+
from dolphin.core.common.constants import (
|
|
12
|
+
DOLPHIN_VARIABLES_OUTPUT_START,
|
|
13
|
+
DOLPHIN_VARIABLES_OUTPUT_END,
|
|
14
|
+
)
|
|
15
|
+
from dolphin.core.logging.logger import console
|
|
16
|
+
|
|
17
|
+
from dolphin.cli.args.parser import Args
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def readFile(filePath: str) -> str:
|
|
21
|
+
"""Read content from file
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
filePath: Path to the file
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
File content as string
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
with open(filePath, "r", encoding="utf-8") as file:
|
|
31
|
+
return file.read()
|
|
32
|
+
except FileNotFoundError:
|
|
33
|
+
console(f"Error: File not found: {filePath}")
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
except Exception as e:
|
|
36
|
+
console(f"Error reading file {filePath}: {e}")
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def buildVariables(args: Args) -> Dict[str, Any]:
|
|
41
|
+
"""Build variables dictionary from arguments
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
args: Parsed CLI arguments
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Dictionary of variables to pass to the agent
|
|
48
|
+
"""
|
|
49
|
+
variables = {}
|
|
50
|
+
|
|
51
|
+
if args.query is not None:
|
|
52
|
+
variables["query"] = args.query
|
|
53
|
+
|
|
54
|
+
if args.userId is not None:
|
|
55
|
+
variables["user_id"] = args.userId
|
|
56
|
+
|
|
57
|
+
if args.runArgs:
|
|
58
|
+
variables.update(args.runArgs)
|
|
59
|
+
|
|
60
|
+
return variables
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def outputVariablesToJson(context, variableNames: List[str]) -> None:
|
|
64
|
+
"""Output specified variables in JSON format
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
context: Dolphin context object
|
|
68
|
+
variableNames: List of variable names to output (empty = all)
|
|
69
|
+
"""
|
|
70
|
+
if not variableNames:
|
|
71
|
+
allVariables = context.get_all_variables_values()
|
|
72
|
+
else:
|
|
73
|
+
allVariables = {}
|
|
74
|
+
for varName in variableNames:
|
|
75
|
+
try:
|
|
76
|
+
varValue = context.get_var_path_value(varName)
|
|
77
|
+
if varValue is not None:
|
|
78
|
+
allVariables[varName] = varValue
|
|
79
|
+
except Exception:
|
|
80
|
+
allVariables[varName] = None
|
|
81
|
+
|
|
82
|
+
if "_all_stages" not in allVariables:
|
|
83
|
+
allVariables["_all_stages"] = context.get_runtime_graph().get_all_stages()
|
|
84
|
+
|
|
85
|
+
variablesJson = json.dumps(
|
|
86
|
+
allVariables, ensure_ascii=False, default=str, indent=2
|
|
87
|
+
)
|
|
88
|
+
console(f"\n{DOLPHIN_VARIABLES_OUTPUT_START}")
|
|
89
|
+
console(variablesJson)
|
|
90
|
+
console(f"{DOLPHIN_VARIABLES_OUTPUT_END}\n")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def validateArgs(args: Args) -> None:
|
|
94
|
+
"""Validate CLI arguments before execution
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
args: Parsed CLI arguments
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
SystemExit: If validation fails
|
|
101
|
+
"""
|
|
102
|
+
import os
|
|
103
|
+
|
|
104
|
+
if args.folder and not os.path.exists(args.folder):
|
|
105
|
+
console(f"Error: Folder not found: {args.folder}")
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
|
|
108
|
+
if args.skillFolder and not os.path.exists(args.skillFolder):
|
|
109
|
+
console(f"Error: Skill folder not found: {args.skillFolder}")
|
|
110
|
+
sys.exit(1)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def setupFlagsFromArgs(args: Args) -> None:
|
|
114
|
+
"""Set feature flags from CLI arguments
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
args: Parsed CLI arguments
|
|
118
|
+
"""
|
|
119
|
+
from dolphin.core import flags
|
|
120
|
+
|
|
121
|
+
if not args.flagsOverrides:
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
for flagName, flagValue in args.flagsOverrides.items():
|
|
125
|
+
# Convert string "true"/"false" to boolean, handle boolean directly
|
|
126
|
+
if isinstance(flagValue, str):
|
|
127
|
+
boolValue = flagValue.lower() in ('true', '1', 'yes', 'on', 'True')
|
|
128
|
+
else:
|
|
129
|
+
boolValue = bool(flagValue)
|
|
130
|
+
|
|
131
|
+
flags.set_flag(flagName, boolValue)
|
|
132
|
+
# Cleaner flag output
|
|
133
|
+
state = "Enabled" if boolValue else "Disabled"
|
|
134
|
+
console(f"[Flag] {flagName}: {state}")
|
|
135
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Version management for Dolphin CLI
|
|
3
|
+
|
|
4
|
+
Reads version from VERSION file to avoid hardcoding.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from functools import lru_cache
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@lru_cache(maxsize=1)
|
|
12
|
+
def getVersion() -> str:
|
|
13
|
+
"""
|
|
14
|
+
Get version from VERSION file.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Version string (e.g., "0.3.3")
|
|
18
|
+
"""
|
|
19
|
+
# Try multiple paths to find VERSION file
|
|
20
|
+
possiblePaths = [
|
|
21
|
+
# When running from project root
|
|
22
|
+
os.path.join(os.getcwd(), "VERSION"),
|
|
23
|
+
# When running from bin/
|
|
24
|
+
os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "VERSION"),
|
|
25
|
+
# Fallback: relative to this file
|
|
26
|
+
os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..", "VERSION"),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
for versionPath in possiblePaths:
|
|
30
|
+
normalizedPath = os.path.normpath(versionPath)
|
|
31
|
+
if os.path.exists(normalizedPath):
|
|
32
|
+
try:
|
|
33
|
+
with open(normalizedPath, "r", encoding="utf-8") as f:
|
|
34
|
+
return f.read().strip()
|
|
35
|
+
except Exception:
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
return "unknown"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def getFullVersion() -> str:
|
|
42
|
+
"""
|
|
43
|
+
Get full version string for display.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Full version string (e.g., "Dolphin Language v0.3.3")
|
|
47
|
+
"""
|
|
48
|
+
return f"Dolphin Language v{getVersion()}"
|
|
49
|
+
|
dolphin/core/__init__.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Dolphin Core - 核心运行时引擎(内核态)
|
|
4
|
+
|
|
5
|
+
职责:
|
|
6
|
+
- 执行引擎(Executor)
|
|
7
|
+
- 上下文管理(Context)
|
|
8
|
+
- 上下文工程(Context Engineer)
|
|
9
|
+
- 消息压缩(Message Compressor)
|
|
10
|
+
- 变量池(Variable Pool)
|
|
11
|
+
- 语法解析器(Parser)
|
|
12
|
+
- 协程调度(Coroutine)
|
|
13
|
+
- 代码块执行(Code Block)
|
|
14
|
+
- LLM 调用抽象层
|
|
15
|
+
- Skill 核心(Skillkit、skill_function、skill_matcher)
|
|
16
|
+
- 轨迹记录(Trajectory)
|
|
17
|
+
- Agent 核心定义(BaseAgent、AgentState)
|
|
18
|
+
- Runtime 核心(RuntimeInstance、RuntimeGraph)
|
|
19
|
+
|
|
20
|
+
依赖规则:
|
|
21
|
+
- dolphin.core 无内部依赖(仅依赖第三方库)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
# Context
|
|
25
|
+
from dolphin.core.context.context import Context
|
|
26
|
+
from dolphin.core.context_engineer.core.context_manager import ContextManager
|
|
27
|
+
from dolphin.core.context.variable_pool import VariablePool
|
|
28
|
+
|
|
29
|
+
# Executor
|
|
30
|
+
from dolphin.core.executor.executor import Executor
|
|
31
|
+
# DolphinExecutor is available via lazy import from dolphin.core.executor
|
|
32
|
+
from dolphin.core.executor.debug_controller import DebugController
|
|
33
|
+
|
|
34
|
+
# Runtime
|
|
35
|
+
from dolphin.core.runtime.runtime_instance import RuntimeInstance
|
|
36
|
+
from dolphin.core.runtime.runtime_graph import RuntimeGraph
|
|
37
|
+
|
|
38
|
+
# Agent
|
|
39
|
+
from dolphin.core.agent.base_agent import BaseAgent
|
|
40
|
+
from dolphin.core.agent.agent_state import AgentState
|
|
41
|
+
|
|
42
|
+
# Skill
|
|
43
|
+
from dolphin.core.skill.skillkit import Skillkit
|
|
44
|
+
from dolphin.core.skill.skillset import Skillset
|
|
45
|
+
from dolphin.core.skill.skill_function import SkillFunction
|
|
46
|
+
from dolphin.core.skill.skill_matcher import SkillMatcher
|
|
47
|
+
|
|
48
|
+
# LLM
|
|
49
|
+
from dolphin.core.llm.llm import LLM
|
|
50
|
+
from dolphin.core.llm.llm_client import LLMClient
|
|
51
|
+
from dolphin.core.llm.llm_call import LLMCall
|
|
52
|
+
|
|
53
|
+
# Config
|
|
54
|
+
from dolphin.core.config.global_config import GlobalConfig
|
|
55
|
+
|
|
56
|
+
# Common
|
|
57
|
+
from dolphin.core.common.enums import MessageRole, SkillType
|
|
58
|
+
from dolphin.core.common.exceptions import DolphinException
|
|
59
|
+
|
|
60
|
+
# Logging
|
|
61
|
+
from dolphin.core.logging.logger import get_logger
|
|
62
|
+
|
|
63
|
+
# Trajectory
|
|
64
|
+
from dolphin.core.trajectory.trajectory import Trajectory
|
|
65
|
+
from dolphin.core.trajectory.recorder import Recorder
|
|
66
|
+
|
|
67
|
+
# Interfaces
|
|
68
|
+
from dolphin.core.interfaces import IMemoryManager
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
# Context
|
|
72
|
+
"Context",
|
|
73
|
+
"ContextManager",
|
|
74
|
+
"VariablePool",
|
|
75
|
+
# Executor
|
|
76
|
+
"Executor",
|
|
77
|
+
# DolphinExecutor is available via lazy import
|
|
78
|
+
"DebugController",
|
|
79
|
+
# Runtime
|
|
80
|
+
"RuntimeInstance",
|
|
81
|
+
"RuntimeGraph",
|
|
82
|
+
# Agent
|
|
83
|
+
"BaseAgent",
|
|
84
|
+
"AgentState",
|
|
85
|
+
# Skill
|
|
86
|
+
"Skillkit",
|
|
87
|
+
"Skillset",
|
|
88
|
+
"SkillFunction",
|
|
89
|
+
"SkillMatcher",
|
|
90
|
+
# LLM
|
|
91
|
+
"LLM",
|
|
92
|
+
"LLMClient",
|
|
93
|
+
"LLMCall",
|
|
94
|
+
# Config
|
|
95
|
+
"GlobalConfig",
|
|
96
|
+
# Common
|
|
97
|
+
"MessageRole",
|
|
98
|
+
"SkillType",
|
|
99
|
+
"DolphinException",
|
|
100
|
+
# Logging
|
|
101
|
+
"get_logger",
|
|
102
|
+
# Trajectory
|
|
103
|
+
"Trajectory",
|
|
104
|
+
"Recorder",
|
|
105
|
+
# Interfaces
|
|
106
|
+
"IMemoryManager",
|
|
107
|
+
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Agent state enumeration definition"""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AgentState(Enum):
|
|
9
|
+
"""Agent State Enumeration"""
|
|
10
|
+
|
|
11
|
+
CREATED = "created" # Created, not initialized
|
|
12
|
+
INITIALIZED = "initialized" # Initialized
|
|
13
|
+
RUNNING = "running" # Running
|
|
14
|
+
PAUSED = "paused" # Paused
|
|
15
|
+
COMPLETED = "completed" # Completed
|
|
16
|
+
TERMINATED = "terminated" # Terminated
|
|
17
|
+
ERROR = "error" # Error State
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PauseType(Enum):
|
|
21
|
+
"""Type of pause that caused agent to enter PAUSED state.
|
|
22
|
+
|
|
23
|
+
Values:
|
|
24
|
+
MANUAL: User explicitly called pause()
|
|
25
|
+
TOOL_INTERRUPT: Tool requested user input (ToolInterrupt)
|
|
26
|
+
USER_INTERRUPT: User actively interrupted execution (UserInterrupt)
|
|
27
|
+
"""
|
|
28
|
+
MANUAL = "manual"
|
|
29
|
+
TOOL_INTERRUPT = "tool_interrupt"
|
|
30
|
+
USER_INTERRUPT = "user_interrupt"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AgentEvent(Enum):
|
|
34
|
+
"""Agent Event Enumeration"""
|
|
35
|
+
|
|
36
|
+
INIT = "init" # Initialize event
|
|
37
|
+
START = "start" # Start executing event
|
|
38
|
+
PAUSE = "pause" # Pause Event
|
|
39
|
+
RESUME = "resume" # Recover event
|
|
40
|
+
TERMINATE = "terminate" # Termination Event
|
|
41
|
+
COMPLETE = "complete" # Completion Event
|
|
42
|
+
ERROR = "error" # Error Event
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AgentStatus:
|
|
46
|
+
"""Agent State Information Container"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
state: AgentState = AgentState.CREATED,
|
|
51
|
+
message: str = "",
|
|
52
|
+
data: Any = None,
|
|
53
|
+
):
|
|
54
|
+
self.state = state
|
|
55
|
+
self.message = message
|
|
56
|
+
self.data = data
|
|
57
|
+
self.timestamp: datetime = datetime.now()
|
|
58
|
+
|
|
59
|
+
def to_dict(self) -> dict:
|
|
60
|
+
"""Convert to dictionary format"""
|
|
61
|
+
return {
|
|
62
|
+
"state": self.state.value,
|
|
63
|
+
"message": self.message,
|
|
64
|
+
"data": self.data,
|
|
65
|
+
"timestamp": self.timestamp.isoformat() if self.timestamp else None,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
def __str__(self) -> str:
|
|
69
|
+
return f"AgentStatus(state={self.state.value}, message='{self.message}')"
|