teragent 0.0.1__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.
- teragent/__init__.py +794 -0
- teragent/agent_loop.py +1065 -0
- teragent/config/__init__.py +151 -0
- teragent/config/agent_loop_config.py +221 -0
- teragent/config/api_key_security.py +751 -0
- teragent/config/circuit_breaker_config.py +102 -0
- teragent/config/context_management_config.py +44 -0
- teragent/config/coordination_config.py +36 -0
- teragent/config/driver_config.py +114 -0
- teragent/config/execution_pipeline_config.py +45 -0
- teragent/config/file_safety_config.py +32 -0
- teragent/config/hooks_config.py +55 -0
- teragent/config/loader.py +616 -0
- teragent/config/model_fallback_config.py +32 -0
- teragent/config/permission_config.py +57 -0
- teragent/config/recovery_config.py +32 -0
- teragent/config/session_config.py +36 -0
- teragent/config/streaming_config.py +32 -0
- teragent/config/teragent_config.py +454 -0
- teragent/config/tools_config.py +40 -0
- teragent/context/__init__.py +109 -0
- teragent/context/auto_compact.py +313 -0
- teragent/context/code_indexer.py +831 -0
- teragent/context/context_window.py +187 -0
- teragent/context/dependency_reporter.py +156 -0
- teragent/context/memory.py +126 -0
- teragent/context/microcompactor.py +279 -0
- teragent/context/reference_graph.py +204 -0
- teragent/context/vector_indexer.py +209 -0
- teragent/coordination/__init__.py +27 -0
- teragent/coordination/message_bus.py +301 -0
- teragent/coordination/sub_agent_manager.py +720 -0
- teragent/core/__init__.py +19 -0
- teragent/core/adapter.py +138 -0
- teragent/core/adapters/__init__.py +32 -0
- teragent/core/adapters/anthropic_native.py +656 -0
- teragent/core/adapters/mock.py +222 -0
- teragent/core/adapters/openai_compatible.py +519 -0
- teragent/core/compiler.py +218 -0
- teragent/core/compilers/__init__.py +32 -0
- teragent/core/compilers/anthropic.py +75 -0
- teragent/core/compilers/deepseek.py +75 -0
- teragent/core/compilers/default.py +57 -0
- teragent/core/compilers/glm.py +122 -0
- teragent/core/prompts/__init__.py +174 -0
- teragent/core/prompts/chat.py +135 -0
- teragent/core/prompts/design.py +102 -0
- teragent/core/prompts/execute.py +18 -0
- teragent/core/prompts/plan.py +131 -0
- teragent/core/prompts/review.py +86 -0
- teragent/core/prompts/sub_agent.py +41 -0
- teragent/core/provider.py +402 -0
- teragent/core/tap.py +170 -0
- teragent/core/types.py +462 -0
- teragent/event_bus.py +352 -0
- teragent/hooks/__init__.py +56 -0
- teragent/hooks/builtin/__init__.py +14 -0
- teragent/hooks/builtin/audit_hook.py +184 -0
- teragent/hooks/builtin/dangerous_command_hook.py +226 -0
- teragent/hooks/manager.py +607 -0
- teragent/intent/__init__.py +15 -0
- teragent/intent/classifier.py +240 -0
- teragent/intent/confirmation.py +205 -0
- teragent/pipeline/__init__.py +26 -0
- teragent/pipeline/checklist.py +411 -0
- teragent/pipeline/extractor.py +206 -0
- teragent/pipeline/prompt_builder.py +168 -0
- teragent/pipeline/retry.py +75 -0
- teragent/pipeline/subagent_worker.py +349 -0
- teragent/pipeline/tracing.py +1026 -0
- teragent/py.typed +0 -0
- teragent/reliability/__init__.py +56 -0
- teragent/reliability/budget.py +70 -0
- teragent/reliability/circuit_breaker.py +1175 -0
- teragent/reliability/recovery.py +371 -0
- teragent/security/__init__.py +37 -0
- teragent/security/ai_permission_classifier.py +746 -0
- teragent/security/audit.py +413 -0
- teragent/security/file_state.py +504 -0
- teragent/security/file_writer.py +413 -0
- teragent/security/firecracker_sandbox.py +279 -0
- teragent/security/permission.py +982 -0
- teragent/security/sandbox.py +567 -0
- teragent/session/__init__.py +31 -0
- teragent/session/persistence.py +715 -0
- teragent/streaming/__init__.py +37 -0
- teragent/streaming/stream_events.py +594 -0
- teragent/streaming/streaming_executor.py +539 -0
- teragent/tools/__init__.py +24 -0
- teragent/tools/base.py +272 -0
- teragent/tools/orchestrator.py +416 -0
- teragent/tools/registry.py +238 -0
- teragent/utils/__init__.py +14 -0
- teragent/utils/exceptions.py +52 -0
- teragent/utils/text.py +46 -0
- teragent/utils/token_counter.py +117 -0
- teragent/utils/tracing.py +183 -0
- teragent-0.0.1.dist-info/METADATA +40 -0
- teragent-0.0.1.dist-info/RECORD +102 -0
- teragent-0.0.1.dist-info/WHEEL +5 -0
- teragent-0.0.1.dist-info/licenses/LICENSE +201 -0
- teragent-0.0.1.dist-info/top_level.txt +1 -0
teragent/__init__.py
ADDED
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
"""teragent — Terminal AI Agent Library
|
|
2
|
+
|
|
3
|
+
TAP IR + Model-Specific Compilation — Apache-2.0 Licensed
|
|
4
|
+
|
|
5
|
+
Quick start:
|
|
6
|
+
import teragent
|
|
7
|
+
|
|
8
|
+
# Method 1: Create a provider from DriverConfig (recommended)
|
|
9
|
+
from teragent.config import DriverConfig
|
|
10
|
+
driver_cfg = DriverConfig(
|
|
11
|
+
adapter="openai_compatible",
|
|
12
|
+
identity="glm",
|
|
13
|
+
base_url="https://open.bigmodel.cn/api/paas/v4",
|
|
14
|
+
api_key_env="GLM_API_KEY",
|
|
15
|
+
model="glm-5.1",
|
|
16
|
+
compiler="glm",
|
|
17
|
+
)
|
|
18
|
+
provider = teragent.create_provider_from_config(driver_cfg)
|
|
19
|
+
|
|
20
|
+
# Method 2: Create a provider manually (Compiler + Adapter auto-combined)
|
|
21
|
+
provider = teragent.create_provider(
|
|
22
|
+
compiler="glm",
|
|
23
|
+
adapter="openai_compatible",
|
|
24
|
+
model="glm-5.1",
|
|
25
|
+
base_url="https://open.bigmodel.cn/api/paas/v4",
|
|
26
|
+
api_key_env="GLM_API_KEY",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Method 3: Load from config file
|
|
30
|
+
full_config = teragent.load_full_config()
|
|
31
|
+
drivers = full_config["drivers"]
|
|
32
|
+
provider = teragent.create_provider_from_config(drivers["openai_compatible.glm"])
|
|
33
|
+
|
|
34
|
+
# Execute a TAP request
|
|
35
|
+
response = await provider.execute_tap(teragent.TAPRequest(
|
|
36
|
+
meta={"task_id": "1.1", "intent": "code_generation"},
|
|
37
|
+
instruction="实现用户登录模块",
|
|
38
|
+
constraints=["Python 3.10+"],
|
|
39
|
+
output_format_hint="<file path='...'>完整代码</file>",
|
|
40
|
+
))
|
|
41
|
+
|
|
42
|
+
# Extract files from response
|
|
43
|
+
files = teragent.extract_files_from_response(response.raw_text, task_id="1.1")
|
|
44
|
+
|
|
45
|
+
# Run deterministic code checks
|
|
46
|
+
task_list = [teragent.TaskInfo(id="1.1", title="Login module", status="completed")]
|
|
47
|
+
report, data = teragent.run_deterministic_checks("/project", task_list)
|
|
48
|
+
|
|
49
|
+
# Build prompt with custom template
|
|
50
|
+
messages = teragent.build_prompt(
|
|
51
|
+
system_template="You are {role}. Task: {task}",
|
|
52
|
+
context={"role": "engineer", "task": "implement login"},
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Retry with exponential backoff
|
|
56
|
+
result = await teragent.retry_with_backoff(
|
|
57
|
+
fn=lambda: provider.chat(messages=[...]),
|
|
58
|
+
max_retries=3,
|
|
59
|
+
validate=lambda r: [] if r else ["empty response"],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Self-RL data constitution — TAP tracing + DPO pairs
|
|
63
|
+
tracer = teragent.TAPTracer(trace_dir="/project/.agent/traces")
|
|
64
|
+
provider.set_tracer(tracer) # Auto-trace all TAP calls
|
|
65
|
+
|
|
66
|
+
# After running deterministic checks, record the result
|
|
67
|
+
await tracer.record_checklist("1.1", checklist_data)
|
|
68
|
+
|
|
69
|
+
# Export DPO preference pairs for fine-tuning
|
|
70
|
+
pairs = tracer.export_dpo_pairs()
|
|
71
|
+
tracer.export_dpo_pairs_jsonl() # Write to file
|
|
72
|
+
|
|
73
|
+
Optional dependencies:
|
|
74
|
+
Some components require extra packages that are not installed by default.
|
|
75
|
+
Install them with pip extras:
|
|
76
|
+
|
|
77
|
+
- teragent[vector] — VectorIndexer (LanceDB + numpy)
|
|
78
|
+
- teragent[ast] — CodeIndexer (tree-sitter)
|
|
79
|
+
- teragent[graph] — ReferenceGraph (networkx)
|
|
80
|
+
- teragent[all] — All optional dependencies
|
|
81
|
+
|
|
82
|
+
These components are lazily imported and will raise ImportError only
|
|
83
|
+
when actually used without the corresponding extra installed.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
from __future__ import annotations
|
|
87
|
+
|
|
88
|
+
import logging
|
|
89
|
+
from typing import Any
|
|
90
|
+
|
|
91
|
+
logger = logging.getLogger(__name__)
|
|
92
|
+
|
|
93
|
+
# ============================================================================
|
|
94
|
+
# Core data types
|
|
95
|
+
# ============================================================================
|
|
96
|
+
|
|
97
|
+
from teragent.core.tap import TAPRequest, TAPResponse, TAPCostRecord, CompiledPrompt
|
|
98
|
+
|
|
99
|
+
# Compiler ABC + Registry
|
|
100
|
+
from teragent.core.compiler import TAPCompiler, TAPCompilerRegistry
|
|
101
|
+
|
|
102
|
+
# Adapter ABC + Registry
|
|
103
|
+
from teragent.core.adapter import TAPAdapter, TAPAdapterRegistry
|
|
104
|
+
|
|
105
|
+
# ModelProvider (Compiler + Adapter composition)
|
|
106
|
+
from teragent.core.provider import ModelProvider
|
|
107
|
+
|
|
108
|
+
# Core types
|
|
109
|
+
from teragent.core.types import ToolSafety
|
|
110
|
+
from teragent.core.types import Message, MessageRole, MessageType, messages_to_api_format, messages_from_dicts
|
|
111
|
+
|
|
112
|
+
# ============================================================================
|
|
113
|
+
# Config layer
|
|
114
|
+
# ============================================================================
|
|
115
|
+
|
|
116
|
+
from teragent.config.driver_config import DriverConfig
|
|
117
|
+
from teragent.config.loader import (
|
|
118
|
+
load_driver_configs,
|
|
119
|
+
load_pipeline_config,
|
|
120
|
+
load_full_config,
|
|
121
|
+
create_provider_from_config,
|
|
122
|
+
get_driver_config,
|
|
123
|
+
resolve_api_key,
|
|
124
|
+
resolve_api_key_detailed,
|
|
125
|
+
infer_compiler,
|
|
126
|
+
load_typed_config,
|
|
127
|
+
audit_config_security,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# API Key security
|
|
131
|
+
from teragent.config.api_key_security import (
|
|
132
|
+
ApiKeyVault,
|
|
133
|
+
ResolvedKey,
|
|
134
|
+
SecurityFinding,
|
|
135
|
+
SecuritySeverity,
|
|
136
|
+
SecurityError,
|
|
137
|
+
mask_api_key,
|
|
138
|
+
detect_api_key_provider,
|
|
139
|
+
audit_config_security as audit_api_key_security,
|
|
140
|
+
audit_env_file,
|
|
141
|
+
get_vault,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Typed configuration dataclasses
|
|
145
|
+
from teragent.config.teragent_config import TerAgentConfig, AgentdSectionConfig
|
|
146
|
+
from teragent.config.agent_loop_config import AgentLoopConfig
|
|
147
|
+
from teragent.config.circuit_breaker_config import (
|
|
148
|
+
CircuitBreakerConfig,
|
|
149
|
+
BudgetConfig,
|
|
150
|
+
FailureBreakerConfig,
|
|
151
|
+
LatencyBreakerConfig,
|
|
152
|
+
ProgressDetectorConfig,
|
|
153
|
+
)
|
|
154
|
+
from teragent.config.context_management_config import ContextManagementConfig
|
|
155
|
+
from teragent.config.tools_config import ToolsConfig
|
|
156
|
+
from teragent.config.file_safety_config import FileSafetyConfig
|
|
157
|
+
from teragent.config.session_config import SessionConfig
|
|
158
|
+
from teragent.config.permission_config import PermissionConfig
|
|
159
|
+
from teragent.config.hooks_config import HooksConfig
|
|
160
|
+
from teragent.config.recovery_config import RecoveryConfig
|
|
161
|
+
from teragent.config.streaming_config import StreamingConfig
|
|
162
|
+
from teragent.config.coordination_config import CoordinationConfig
|
|
163
|
+
from teragent.config.execution_pipeline_config import ExecutionPipelineConfig
|
|
164
|
+
from teragent.config.model_fallback_config import ModelFallbackConfig
|
|
165
|
+
|
|
166
|
+
# ============================================================================
|
|
167
|
+
# Pipeline primitives
|
|
168
|
+
# ============================================================================
|
|
169
|
+
|
|
170
|
+
from teragent.pipeline.extractor import extract_files_from_response
|
|
171
|
+
from teragent.pipeline.prompt_builder import (
|
|
172
|
+
build_prompt,
|
|
173
|
+
build_subagent_prompt,
|
|
174
|
+
validate_prompt_tokens,
|
|
175
|
+
DEFAULT_SYSTEM_TEMPLATE,
|
|
176
|
+
)
|
|
177
|
+
from teragent.pipeline.checklist import (
|
|
178
|
+
run_deterministic_checks,
|
|
179
|
+
TaskInfo,
|
|
180
|
+
check_code_quality,
|
|
181
|
+
check_requirements,
|
|
182
|
+
check_runnable,
|
|
183
|
+
check_file_conflicts,
|
|
184
|
+
check_fallback_files,
|
|
185
|
+
)
|
|
186
|
+
from teragent.pipeline.retry import retry_with_backoff
|
|
187
|
+
|
|
188
|
+
# TAP Tracing + DPO pair generation
|
|
189
|
+
from teragent.pipeline.tracing import (
|
|
190
|
+
TAPTracer,
|
|
191
|
+
TraceRecord,
|
|
192
|
+
DPOPair,
|
|
193
|
+
DataConstitution,
|
|
194
|
+
TraceStats,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# ============================================================================
|
|
198
|
+
# Prompt selection
|
|
199
|
+
# ============================================================================
|
|
200
|
+
|
|
201
|
+
from teragent.core.prompts import get_system_prompt_for_intent as _get_system_prompt_for_intent
|
|
202
|
+
from teragent.core.prompts import list_intents, list_compiler_types
|
|
203
|
+
|
|
204
|
+
def get_system_prompt_for_intent(
|
|
205
|
+
intent: str,
|
|
206
|
+
compiler_type: str = "default",
|
|
207
|
+
) -> str:
|
|
208
|
+
"""Get the system prompt for a given intent and compiler type.
|
|
209
|
+
|
|
210
|
+
Centralized prompt management.
|
|
211
|
+
All prompts are managed through teragent/core/prompts/ and selected
|
|
212
|
+
based on intent (design, plan, replan, execute, review, chat,
|
|
213
|
+
chat_friendly, sub_agent) and compiler type (default, glm,
|
|
214
|
+
anthropic, deepseek).
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
intent: One of: design | plan | replan | execute | review |
|
|
218
|
+
chat | chat_friendly | sub_agent | code_generation
|
|
219
|
+
compiler_type: One of: default | glm | anthropic | deepseek
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
System prompt string for the given intent and compiler type.
|
|
223
|
+
Falls back to "default" compiler if specific one not found.
|
|
224
|
+
Returns empty string if intent is not recognized.
|
|
225
|
+
|
|
226
|
+
Examples:
|
|
227
|
+
# Get GLM-optimized design prompt
|
|
228
|
+
prompt = teragent.get_system_prompt_for_intent("design", "glm")
|
|
229
|
+
|
|
230
|
+
# Get default chat prompt
|
|
231
|
+
prompt = teragent.get_system_prompt_for_intent("chat")
|
|
232
|
+
|
|
233
|
+
# Different compilers produce different prompts for the same intent
|
|
234
|
+
default_prompt = teragent.get_system_prompt_for_intent("review", "default")
|
|
235
|
+
anthropic_prompt = teragent.get_system_prompt_for_intent("review", "anthropic")
|
|
236
|
+
# anthropic_prompt uses XML tags, default_prompt uses plain text
|
|
237
|
+
"""
|
|
238
|
+
return _get_system_prompt_for_intent(intent, compiler_type=compiler_type)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# Prompt templates
|
|
242
|
+
from teragent.core.prompts import (
|
|
243
|
+
DESIGN_PROMPT_DEFAULT, DESIGN_PROMPT_GLM, DESIGN_PROMPT_ANTHROPIC, DESIGN_PROMPT_DEEPSEEK,
|
|
244
|
+
PLAN_PROMPT_DEFAULT, PLAN_PROMPT_GLM, PLAN_PROMPT_ANTHROPIC, PLAN_PROMPT_DEEPSEEK,
|
|
245
|
+
REPLAN_PROMPT_DEFAULT, REPLAN_PROMPT_GLM, REPLAN_PROMPT_ANTHROPIC, REPLAN_PROMPT_DEEPSEEK,
|
|
246
|
+
REVIEW_PROMPT_DEFAULT, REVIEW_PROMPT_GLM, REVIEW_PROMPT_ANTHROPIC, REVIEW_PROMPT_DEEPSEEK,
|
|
247
|
+
AGENT_PROMPT_DEFAULT, AGENT_PROMPT_GLM, AGENT_PROMPT_ANTHROPIC, AGENT_PROMPT_DEEPSEEK,
|
|
248
|
+
CHAT_PROMPT_DEFAULT, CHAT_PROMPT_GLM, CHAT_PROMPT_ANTHROPIC, CHAT_PROMPT_DEEPSEEK,
|
|
249
|
+
SUB_AGENT_PROMPT_DEFAULT, SUB_AGENT_PROMPT_GLM, SUB_AGENT_PROMPT_ANTHROPIC, SUB_AGENT_PROMPT_DEEPSEEK,
|
|
250
|
+
EXECUTE_PROMPT_DEFAULT, EXECUTE_PROMPT_GLM, EXECUTE_PROMPT_ANTHROPIC, EXECUTE_PROMPT_DEEPSEEK,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# ============================================================================
|
|
254
|
+
# Security architecture
|
|
255
|
+
# ============================================================================
|
|
256
|
+
|
|
257
|
+
from teragent.security.permission import (
|
|
258
|
+
PermissionManager,
|
|
259
|
+
PermissionLevel,
|
|
260
|
+
EnhancedPermissionManager,
|
|
261
|
+
PermissionRule,
|
|
262
|
+
PermissionEffect,
|
|
263
|
+
)
|
|
264
|
+
from teragent.security.file_state import FileStateTracker
|
|
265
|
+
from teragent.security.file_writer import write_files_safely, atomic_write_file
|
|
266
|
+
from teragent.security.ai_permission_classifier import AIPermissionClassifier
|
|
267
|
+
from teragent.security.sandbox import execute_in_sandbox, check_command_safety
|
|
268
|
+
from teragent.security.audit import AuditLogger
|
|
269
|
+
from teragent.security.firecracker_sandbox import FirecrackerSandbox
|
|
270
|
+
|
|
271
|
+
# ============================================================================
|
|
272
|
+
# Context management — core components always available
|
|
273
|
+
# ============================================================================
|
|
274
|
+
|
|
275
|
+
from teragent.context.context_window import ContextWindow
|
|
276
|
+
from teragent.context.microcompactor import Microcompactor
|
|
277
|
+
from teragent.context.auto_compact import AutoCompactor
|
|
278
|
+
from teragent.context.memory import (
|
|
279
|
+
load_agent_md,
|
|
280
|
+
save_agent_md,
|
|
281
|
+
merge_agent_md,
|
|
282
|
+
extract_rules,
|
|
283
|
+
)
|
|
284
|
+
# DependencyReporter moved to lazy import (requires optional deps)
|
|
285
|
+
|
|
286
|
+
# ============================================================================
|
|
287
|
+
# Reliability
|
|
288
|
+
# ============================================================================
|
|
289
|
+
|
|
290
|
+
from teragent.reliability.circuit_breaker import (
|
|
291
|
+
CircuitBreakerManager,
|
|
292
|
+
CostBudgetTracker,
|
|
293
|
+
CostBudgetConfig,
|
|
294
|
+
BudgetCheckResult,
|
|
295
|
+
BreakerState,
|
|
296
|
+
ConsecutiveFailureBreaker,
|
|
297
|
+
LatencyBreaker,
|
|
298
|
+
ProgressDetector,
|
|
299
|
+
)
|
|
300
|
+
from teragent.reliability.budget import StepBudget, DEFAULT_MAX_STEPS
|
|
301
|
+
from teragent.reliability.recovery import (
|
|
302
|
+
RecoveryType,
|
|
303
|
+
RecoveryStats,
|
|
304
|
+
RecoveryManagerConfig,
|
|
305
|
+
RecoveryManager,
|
|
306
|
+
is_context_overflow_error,
|
|
307
|
+
is_retryable_error,
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# ============================================================================
|
|
311
|
+
# EventBus
|
|
312
|
+
# ============================================================================
|
|
313
|
+
|
|
314
|
+
from teragent.event_bus import EventBus
|
|
315
|
+
|
|
316
|
+
# ============================================================================
|
|
317
|
+
# Coordination
|
|
318
|
+
# ============================================================================
|
|
319
|
+
|
|
320
|
+
from teragent.coordination.message_bus import AgentMessageBus, AgentMessage
|
|
321
|
+
from teragent.coordination.sub_agent_manager import (
|
|
322
|
+
SubAgentManager,
|
|
323
|
+
AgentMode,
|
|
324
|
+
SubAgentStatus,
|
|
325
|
+
SubAgentInfo,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# ============================================================================
|
|
329
|
+
# Intent
|
|
330
|
+
# ============================================================================
|
|
331
|
+
|
|
332
|
+
from teragent.intent.classifier import IntentClassifier, IntentType
|
|
333
|
+
from teragent.intent.confirmation import ConfirmationGate
|
|
334
|
+
|
|
335
|
+
# ============================================================================
|
|
336
|
+
# Hooks
|
|
337
|
+
# ============================================================================
|
|
338
|
+
|
|
339
|
+
from teragent.hooks.manager import (
|
|
340
|
+
HookEvent,
|
|
341
|
+
HookDecision,
|
|
342
|
+
HookContext,
|
|
343
|
+
HookResult,
|
|
344
|
+
Hook,
|
|
345
|
+
ShellHook,
|
|
346
|
+
PythonHook,
|
|
347
|
+
HookManager,
|
|
348
|
+
)
|
|
349
|
+
from teragent.hooks.builtin.audit_hook import AuditHook
|
|
350
|
+
from teragent.hooks.builtin.dangerous_command_hook import DangerousCommandHook
|
|
351
|
+
|
|
352
|
+
# ============================================================================
|
|
353
|
+
# Session
|
|
354
|
+
# ============================================================================
|
|
355
|
+
|
|
356
|
+
from teragent.session.persistence import SessionPersistence, SessionData, SessionInfo
|
|
357
|
+
|
|
358
|
+
# ============================================================================
|
|
359
|
+
# Streaming
|
|
360
|
+
# ============================================================================
|
|
361
|
+
|
|
362
|
+
from teragent.streaming.stream_events import (
|
|
363
|
+
StreamEventType,
|
|
364
|
+
StreamEvent,
|
|
365
|
+
ToolCallAccumulator,
|
|
366
|
+
StreamingChatResult,
|
|
367
|
+
OpenAIStreamParser,
|
|
368
|
+
AnthropicStreamParser,
|
|
369
|
+
)
|
|
370
|
+
from teragent.streaming.streaming_executor import (
|
|
371
|
+
StreamingToolExecutor,
|
|
372
|
+
StreamingExecutionStats,
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# ============================================================================
|
|
376
|
+
# Tools — base abstractions for tool system
|
|
377
|
+
# ============================================================================
|
|
378
|
+
|
|
379
|
+
from teragent.tools.base import BaseTool, ToolResult
|
|
380
|
+
from teragent.tools.registry import ToolRegistry
|
|
381
|
+
from teragent.tools.orchestrator import ToolOrchestrator, MAX_CONCURRENT_TOOLS
|
|
382
|
+
|
|
383
|
+
# ============================================================================
|
|
384
|
+
# AgentLoop — central orchestration class
|
|
385
|
+
# ============================================================================
|
|
386
|
+
|
|
387
|
+
from teragent.agent_loop import AgentLoop
|
|
388
|
+
|
|
389
|
+
# ============================================================================
|
|
390
|
+
# Trigger compiler/adapter registration
|
|
391
|
+
# ============================================================================
|
|
392
|
+
|
|
393
|
+
import teragent.core.compilers # noqa: F401 — registers: default, glm, anthropic, deepseek
|
|
394
|
+
import teragent.core.adapters # noqa: F401 — registers: openai_compatible, anthropic_native, mock
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
# ============================================================================
|
|
398
|
+
# Lazy imports for optional-dependency components
|
|
399
|
+
# ============================================================================
|
|
400
|
+
|
|
401
|
+
def __getattr__(name: str):
|
|
402
|
+
"""Lazy-load components that require optional dependencies.
|
|
403
|
+
|
|
404
|
+
This allows ``import teragent`` to succeed even when optional
|
|
405
|
+
dependencies (lancedb, tree-sitter, networkx) are not installed.
|
|
406
|
+
The components will only raise ImportError when actually accessed.
|
|
407
|
+
|
|
408
|
+
Optional extras:
|
|
409
|
+
- teragent[vector] — VectorIndexer
|
|
410
|
+
- teragent[ast] — CodeIndexer
|
|
411
|
+
- teragent[graph] — ReferenceGraph
|
|
412
|
+
"""
|
|
413
|
+
if name == "DependencyReporter":
|
|
414
|
+
from teragent.context.dependency_reporter import DependencyReporter
|
|
415
|
+
return DependencyReporter
|
|
416
|
+
if name == "TaskProtocol":
|
|
417
|
+
from teragent.context.dependency_reporter import TaskProtocol
|
|
418
|
+
return TaskProtocol
|
|
419
|
+
if name == "CodeIndexer":
|
|
420
|
+
from teragent.context.code_indexer import CodeIndexer
|
|
421
|
+
return CodeIndexer
|
|
422
|
+
if name == "ReferenceGraph":
|
|
423
|
+
from teragent.context.reference_graph import ReferenceGraph
|
|
424
|
+
return ReferenceGraph
|
|
425
|
+
if name == "VectorIndexer":
|
|
426
|
+
from teragent.context.vector_indexer import VectorIndexer
|
|
427
|
+
return VectorIndexer
|
|
428
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
# ============================================================================
|
|
432
|
+
# Factory function
|
|
433
|
+
# ============================================================================
|
|
434
|
+
|
|
435
|
+
def create_provider(
|
|
436
|
+
compiler: str | TAPCompiler,
|
|
437
|
+
adapter: str | TAPAdapter,
|
|
438
|
+
model: str,
|
|
439
|
+
base_url: str = "",
|
|
440
|
+
api_key: str = "",
|
|
441
|
+
api_key_env: str = "",
|
|
442
|
+
timeout: float = 300.0,
|
|
443
|
+
extra_headers: dict | None = None,
|
|
444
|
+
enable_fake_tools: bool = False,
|
|
445
|
+
fallback: ModelProvider | None = None,
|
|
446
|
+
circuit_breaker: Any | None = None,
|
|
447
|
+
tracer: Any | None = None,
|
|
448
|
+
**kwargs,
|
|
449
|
+
) -> ModelProvider:
|
|
450
|
+
"""Factory function to create a ModelProvider from Registry
|
|
451
|
+
|
|
452
|
+
Automatically creates Compiler and Adapter instances from the registry,
|
|
453
|
+
then combines them into a ModelProvider.
|
|
454
|
+
|
|
455
|
+
API key resolution:
|
|
456
|
+
- If api_key_env is provided, resolves from environment variable
|
|
457
|
+
(with .env file fallback via python-dotenv)
|
|
458
|
+
- If only api_key is provided, uses it directly
|
|
459
|
+
(logs an info message recommending api_key_env instead)
|
|
460
|
+
- Recommended: use api_key_env for security
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
compiler: Compiler name (str) or TAPCompiler instance
|
|
464
|
+
Available names: "default", "glm", "anthropic", "deepseek"
|
|
465
|
+
adapter: Adapter name (str) or TAPAdapter instance
|
|
466
|
+
Available names: "openai_compatible", "anthropic_native", "mock"
|
|
467
|
+
model: Model identifier string (e.g., "glm-5.1", "claude-sonnet-4-20250514")
|
|
468
|
+
base_url: API base URL (required for non-mock adapters)
|
|
469
|
+
api_key: API key string (direct, not recommended for production)
|
|
470
|
+
api_key_env: Environment variable name for API key (recommended)
|
|
471
|
+
timeout: HTTP request timeout in seconds (default 300.0)
|
|
472
|
+
extra_headers: Additional HTTP headers for the adapter
|
|
473
|
+
enable_fake_tools: Whether to inject fake tools for distillation detection
|
|
474
|
+
fallback: Fallback ModelProvider for automatic degradation
|
|
475
|
+
circuit_breaker: CircuitBreakerManager for cost/failure tracking
|
|
476
|
+
tracer: TAPTracer for auto-tracing TAP calls
|
|
477
|
+
**kwargs: Additional arguments passed to Adapter constructor
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
ModelProvider instance with Compiler + Adapter composed
|
|
481
|
+
|
|
482
|
+
Raises:
|
|
483
|
+
ValueError: If compiler or adapter name is not registered
|
|
484
|
+
|
|
485
|
+
Examples:
|
|
486
|
+
# GLM via OpenAI-compatible protocol (recommended: api_key_env)
|
|
487
|
+
provider = create_provider(
|
|
488
|
+
compiler="glm",
|
|
489
|
+
adapter="openai_compatible",
|
|
490
|
+
model="glm-5.1",
|
|
491
|
+
base_url="https://open.bigmodel.cn/api/paas/v4",
|
|
492
|
+
api_key_env="GLM_API_KEY",
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
# Claude via OpenRouter (OpenAI protocol + Anthropic compiler)
|
|
496
|
+
provider = create_provider(
|
|
497
|
+
compiler="anthropic",
|
|
498
|
+
adapter="openai_compatible",
|
|
499
|
+
model="anthropic/claude-sonnet-4-20250514",
|
|
500
|
+
base_url="https://openrouter.ai/api/v1",
|
|
501
|
+
api_key_env="OPENROUTER_API_KEY",
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
# Claude via Anthropic native protocol
|
|
505
|
+
provider = create_provider(
|
|
506
|
+
compiler="anthropic",
|
|
507
|
+
adapter="anthropic_native",
|
|
508
|
+
model="claude-sonnet-4-20250514",
|
|
509
|
+
base_url="https://api.anthropic.com/v1",
|
|
510
|
+
api_key_env="ANTHROPIC_API_KEY",
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Mock for testing
|
|
514
|
+
provider = create_provider(
|
|
515
|
+
compiler="default",
|
|
516
|
+
adapter="mock",
|
|
517
|
+
model="mock-model",
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# From DriverConfig
|
|
521
|
+
from teragent.config import DriverConfig
|
|
522
|
+
cfg = DriverConfig(adapter="openai_compatible", identity="glm",
|
|
523
|
+
model="glm-5.1", compiler="glm",
|
|
524
|
+
base_url="...", api_key_env="GLM_API_KEY")
|
|
525
|
+
provider = create_provider(**cfg.to_create_provider_kwargs())
|
|
526
|
+
"""
|
|
527
|
+
# Resolve Compiler
|
|
528
|
+
if isinstance(compiler, str):
|
|
529
|
+
compiler_instance = TAPCompilerRegistry.create(compiler)
|
|
530
|
+
else:
|
|
531
|
+
compiler_instance = compiler
|
|
532
|
+
|
|
533
|
+
# Resolve API key (centralized via ApiKeyVault)
|
|
534
|
+
from teragent.config.api_key_security import ApiKeyVault, mask_api_key as _mask
|
|
535
|
+
vault = ApiKeyVault()
|
|
536
|
+
|
|
537
|
+
resolved_api_key = ""
|
|
538
|
+
if api_key_env:
|
|
539
|
+
# Preferred path: resolve from environment variable
|
|
540
|
+
resolved = vault.resolve(api_key_env)
|
|
541
|
+
resolved_api_key = resolved.key
|
|
542
|
+
if not resolved.found:
|
|
543
|
+
logger.warning(f"API key not found for env var: {api_key_env}")
|
|
544
|
+
elif api_key:
|
|
545
|
+
# Fallback: direct key (store in vault for tracking, no deprecation
|
|
546
|
+
# warning here since this is a programmatic call, not config)
|
|
547
|
+
resolved = vault.store_direct(api_key, name=f"create_provider:{model}")
|
|
548
|
+
resolved_api_key = resolved.key
|
|
549
|
+
logger.info(
|
|
550
|
+
f"Using directly provided API key for model '{model}' "
|
|
551
|
+
f"(masked: {_mask(resolved_api_key)}). "
|
|
552
|
+
f"Consider using api_key_env for better security."
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
# Resolve Adapter
|
|
556
|
+
if isinstance(adapter, str):
|
|
557
|
+
adapter_kwargs: dict[str, Any] = {}
|
|
558
|
+
if adapter == "openai_compatible":
|
|
559
|
+
adapter_kwargs = {
|
|
560
|
+
"base_url": base_url,
|
|
561
|
+
"api_key": resolved_api_key,
|
|
562
|
+
"timeout": timeout,
|
|
563
|
+
"extra_headers": extra_headers,
|
|
564
|
+
"enable_fake_tools": enable_fake_tools,
|
|
565
|
+
}
|
|
566
|
+
elif adapter == "anthropic_native":
|
|
567
|
+
adapter_kwargs = {
|
|
568
|
+
"base_url": base_url,
|
|
569
|
+
"api_key": resolved_api_key,
|
|
570
|
+
"timeout": timeout,
|
|
571
|
+
"enable_fake_tools": enable_fake_tools,
|
|
572
|
+
}
|
|
573
|
+
elif adapter == "mock":
|
|
574
|
+
adapter_kwargs = {}
|
|
575
|
+
else:
|
|
576
|
+
adapter_kwargs = kwargs
|
|
577
|
+
|
|
578
|
+
adapter_instance = TAPAdapterRegistry.create(adapter, **adapter_kwargs)
|
|
579
|
+
else:
|
|
580
|
+
adapter_instance = adapter
|
|
581
|
+
|
|
582
|
+
return ModelProvider(
|
|
583
|
+
compiler=compiler_instance,
|
|
584
|
+
adapter=adapter_instance,
|
|
585
|
+
model=model,
|
|
586
|
+
fallback=fallback,
|
|
587
|
+
circuit_breaker=circuit_breaker,
|
|
588
|
+
tracer=tracer,
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
# ============================================================================
|
|
593
|
+
# Version
|
|
594
|
+
# ============================================================================
|
|
595
|
+
|
|
596
|
+
__version__ = "0.0.1"
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
# ============================================================================
|
|
600
|
+
# Public API
|
|
601
|
+
# ============================================================================
|
|
602
|
+
|
|
603
|
+
__all__ = [
|
|
604
|
+
# Version
|
|
605
|
+
"__version__",
|
|
606
|
+
# Core types
|
|
607
|
+
"TAPRequest",
|
|
608
|
+
"TAPResponse",
|
|
609
|
+
"TAPCostRecord",
|
|
610
|
+
"CompiledPrompt",
|
|
611
|
+
# ABC + Registry
|
|
612
|
+
"TAPCompiler",
|
|
613
|
+
"TAPCompilerRegistry",
|
|
614
|
+
"TAPAdapter",
|
|
615
|
+
"TAPAdapterRegistry",
|
|
616
|
+
# Provider
|
|
617
|
+
"ModelProvider",
|
|
618
|
+
# Factory
|
|
619
|
+
"create_provider",
|
|
620
|
+
# Core types
|
|
621
|
+
"ToolSafety",
|
|
622
|
+
"Message",
|
|
623
|
+
"MessageRole",
|
|
624
|
+
"MessageType",
|
|
625
|
+
"messages_to_api_format",
|
|
626
|
+
"messages_from_dicts",
|
|
627
|
+
# Config layer
|
|
628
|
+
"DriverConfig",
|
|
629
|
+
"load_driver_configs",
|
|
630
|
+
"load_pipeline_config",
|
|
631
|
+
"load_full_config",
|
|
632
|
+
"create_provider_from_config",
|
|
633
|
+
"get_driver_config",
|
|
634
|
+
"resolve_api_key",
|
|
635
|
+
"resolve_api_key_detailed",
|
|
636
|
+
"infer_compiler",
|
|
637
|
+
"audit_config_security",
|
|
638
|
+
# API Key Security
|
|
639
|
+
"ApiKeyVault",
|
|
640
|
+
"ResolvedKey",
|
|
641
|
+
"SecurityFinding",
|
|
642
|
+
"SecuritySeverity",
|
|
643
|
+
"SecurityError",
|
|
644
|
+
"mask_api_key",
|
|
645
|
+
"detect_api_key_provider",
|
|
646
|
+
"audit_api_key_security",
|
|
647
|
+
"audit_env_file",
|
|
648
|
+
"get_vault",
|
|
649
|
+
# Typed config
|
|
650
|
+
"TerAgentConfig",
|
|
651
|
+
"AgentdSectionConfig",
|
|
652
|
+
"AgentLoopConfig",
|
|
653
|
+
"CircuitBreakerConfig",
|
|
654
|
+
"BudgetConfig",
|
|
655
|
+
"FailureBreakerConfig",
|
|
656
|
+
"LatencyBreakerConfig",
|
|
657
|
+
"ProgressDetectorConfig",
|
|
658
|
+
"ContextManagementConfig",
|
|
659
|
+
"ToolsConfig",
|
|
660
|
+
"FileSafetyConfig",
|
|
661
|
+
"SessionConfig",
|
|
662
|
+
"PermissionConfig",
|
|
663
|
+
"HooksConfig",
|
|
664
|
+
"RecoveryConfig",
|
|
665
|
+
"StreamingConfig",
|
|
666
|
+
"CoordinationConfig",
|
|
667
|
+
"ExecutionPipelineConfig",
|
|
668
|
+
"ModelFallbackConfig",
|
|
669
|
+
"load_typed_config",
|
|
670
|
+
# Pipeline primitives
|
|
671
|
+
"extract_files_from_response",
|
|
672
|
+
"build_prompt",
|
|
673
|
+
"build_subagent_prompt",
|
|
674
|
+
"validate_prompt_tokens",
|
|
675
|
+
"DEFAULT_SYSTEM_TEMPLATE",
|
|
676
|
+
"run_deterministic_checks",
|
|
677
|
+
"TaskInfo",
|
|
678
|
+
"check_code_quality",
|
|
679
|
+
"check_requirements",
|
|
680
|
+
"check_runnable",
|
|
681
|
+
"check_file_conflicts",
|
|
682
|
+
"check_fallback_files",
|
|
683
|
+
"retry_with_backoff",
|
|
684
|
+
# TAP Tracing + DPO pair generation
|
|
685
|
+
"TAPTracer",
|
|
686
|
+
"TraceRecord",
|
|
687
|
+
"DPOPair",
|
|
688
|
+
"DataConstitution",
|
|
689
|
+
"TraceStats",
|
|
690
|
+
# Prompt selection
|
|
691
|
+
"get_system_prompt_for_intent",
|
|
692
|
+
"list_intents",
|
|
693
|
+
"list_compiler_types",
|
|
694
|
+
# Prompt templates
|
|
695
|
+
"DESIGN_PROMPT_DEFAULT", "DESIGN_PROMPT_GLM", "DESIGN_PROMPT_ANTHROPIC", "DESIGN_PROMPT_DEEPSEEK",
|
|
696
|
+
"PLAN_PROMPT_DEFAULT", "PLAN_PROMPT_GLM", "PLAN_PROMPT_ANTHROPIC", "PLAN_PROMPT_DEEPSEEK",
|
|
697
|
+
"REPLAN_PROMPT_DEFAULT", "REPLAN_PROMPT_GLM", "REPLAN_PROMPT_ANTHROPIC", "REPLAN_PROMPT_DEEPSEEK",
|
|
698
|
+
"REVIEW_PROMPT_DEFAULT", "REVIEW_PROMPT_GLM", "REVIEW_PROMPT_ANTHROPIC", "REVIEW_PROMPT_DEEPSEEK",
|
|
699
|
+
"AGENT_PROMPT_DEFAULT", "AGENT_PROMPT_GLM", "AGENT_PROMPT_ANTHROPIC", "AGENT_PROMPT_DEEPSEEK",
|
|
700
|
+
"CHAT_PROMPT_DEFAULT", "CHAT_PROMPT_GLM", "CHAT_PROMPT_ANTHROPIC", "CHAT_PROMPT_DEEPSEEK",
|
|
701
|
+
"SUB_AGENT_PROMPT_DEFAULT", "SUB_AGENT_PROMPT_GLM", "SUB_AGENT_PROMPT_ANTHROPIC", "SUB_AGENT_PROMPT_DEEPSEEK",
|
|
702
|
+
"EXECUTE_PROMPT_DEFAULT", "EXECUTE_PROMPT_GLM", "EXECUTE_PROMPT_ANTHROPIC", "EXECUTE_PROMPT_DEEPSEEK",
|
|
703
|
+
# Security
|
|
704
|
+
"PermissionManager",
|
|
705
|
+
"PermissionLevel",
|
|
706
|
+
"EnhancedPermissionManager",
|
|
707
|
+
"PermissionRule",
|
|
708
|
+
"PermissionEffect",
|
|
709
|
+
"FileStateTracker",
|
|
710
|
+
"write_files_safely",
|
|
711
|
+
"atomic_write_file",
|
|
712
|
+
"AIPermissionClassifier",
|
|
713
|
+
"execute_in_sandbox",
|
|
714
|
+
"check_command_safety",
|
|
715
|
+
"AuditLogger",
|
|
716
|
+
"FirecrackerSandbox",
|
|
717
|
+
# Context management — core always available
|
|
718
|
+
"ContextWindow",
|
|
719
|
+
"Microcompactor",
|
|
720
|
+
"AutoCompactor",
|
|
721
|
+
"DependencyReporter",
|
|
722
|
+
"TaskProtocol",
|
|
723
|
+
"load_agent_md",
|
|
724
|
+
"save_agent_md",
|
|
725
|
+
"merge_agent_md",
|
|
726
|
+
"extract_rules",
|
|
727
|
+
# Context management — optional (lazy-loaded)
|
|
728
|
+
"CodeIndexer",
|
|
729
|
+
"ReferenceGraph",
|
|
730
|
+
"VectorIndexer",
|
|
731
|
+
# Reliability
|
|
732
|
+
"CircuitBreakerManager",
|
|
733
|
+
"CostBudgetTracker",
|
|
734
|
+
"CostBudgetConfig",
|
|
735
|
+
"BudgetCheckResult",
|
|
736
|
+
"BreakerState",
|
|
737
|
+
"ConsecutiveFailureBreaker",
|
|
738
|
+
"LatencyBreaker",
|
|
739
|
+
"ProgressDetector",
|
|
740
|
+
"StepBudget",
|
|
741
|
+
"DEFAULT_MAX_STEPS",
|
|
742
|
+
# Reliability — Recovery
|
|
743
|
+
"RecoveryType",
|
|
744
|
+
"RecoveryStats",
|
|
745
|
+
"RecoveryManagerConfig",
|
|
746
|
+
"RecoveryManager",
|
|
747
|
+
"is_context_overflow_error",
|
|
748
|
+
"is_retryable_error",
|
|
749
|
+
# EventBus
|
|
750
|
+
"EventBus",
|
|
751
|
+
# Coordination
|
|
752
|
+
"AgentMessageBus",
|
|
753
|
+
"AgentMessage",
|
|
754
|
+
"SubAgentManager",
|
|
755
|
+
"AgentMode",
|
|
756
|
+
"SubAgentStatus",
|
|
757
|
+
"SubAgentInfo",
|
|
758
|
+
# Intent
|
|
759
|
+
"IntentClassifier",
|
|
760
|
+
"IntentType",
|
|
761
|
+
"ConfirmationGate",
|
|
762
|
+
# Hooks
|
|
763
|
+
"HookEvent",
|
|
764
|
+
"HookDecision",
|
|
765
|
+
"HookContext",
|
|
766
|
+
"HookResult",
|
|
767
|
+
"Hook",
|
|
768
|
+
"ShellHook",
|
|
769
|
+
"PythonHook",
|
|
770
|
+
"HookManager",
|
|
771
|
+
"AuditHook",
|
|
772
|
+
"DangerousCommandHook",
|
|
773
|
+
# Session
|
|
774
|
+
"SessionPersistence",
|
|
775
|
+
"SessionData",
|
|
776
|
+
"SessionInfo",
|
|
777
|
+
# Streaming
|
|
778
|
+
"StreamEventType",
|
|
779
|
+
"StreamEvent",
|
|
780
|
+
"ToolCallAccumulator",
|
|
781
|
+
"StreamingChatResult",
|
|
782
|
+
"OpenAIStreamParser",
|
|
783
|
+
"AnthropicStreamParser",
|
|
784
|
+
"StreamingToolExecutor",
|
|
785
|
+
"StreamingExecutionStats",
|
|
786
|
+
# Tools — base abstractions
|
|
787
|
+
"BaseTool",
|
|
788
|
+
"ToolResult",
|
|
789
|
+
"ToolRegistry",
|
|
790
|
+
"ToolOrchestrator",
|
|
791
|
+
"MAX_CONCURRENT_TOOLS",
|
|
792
|
+
# AgentLoop — central orchestration
|
|
793
|
+
"AgentLoop",
|
|
794
|
+
]
|