spl-agent-engine 0.2.0__tar.gz → 0.4.0__tar.gz
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.
- {spl_agent_engine-0.2.0/spl_agent_engine.egg-info → spl_agent_engine-0.4.0}/PKG-INFO +1 -1
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/pyproject.toml +1 -1
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/__init__.py +19 -3
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/core.py +243 -11
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0/spl_agent_engine.egg-info}/PKG-INFO +1 -1
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/LICENSE +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/README.md +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/setup.cfg +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/__init__.py +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/bias.py +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/goal.py +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/identity.py +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/language_style.py +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/value.py +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/world.py +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/py.typed +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine.egg-info/SOURCES.txt +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine.egg-info/dependency_links.txt +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine.egg-info/requires.txt +0 -0
- {spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spl-agent-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Anthropomorphic psychology engine built on SPL Pure Core V8.0 — deterministic emotion, trauma, memory, trust, and defense mechanisms.
|
|
5
5
|
Author-email: NOHN-AI <ai@nohnlins.com>
|
|
6
6
|
Maintainer-email: NOHN-AI <ai@nohnlins.com>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "spl-agent-engine"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Anthropomorphic psychology engine built on SPL Pure Core V8.0 — deterministic emotion, trauma, memory, trust, and defense mechanisms."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -19,10 +19,26 @@ Usage:
|
|
|
19
19
|
print(core.fluid)
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
from .core import
|
|
22
|
+
from .core import (
|
|
23
|
+
AuditLogger,
|
|
24
|
+
SPLPureCoreV7_3,
|
|
25
|
+
NarrativeMapper,
|
|
26
|
+
TokenUsage,
|
|
27
|
+
TokenStats,
|
|
28
|
+
LLMAdapter,
|
|
29
|
+
OpenAIAdapter,
|
|
30
|
+
ClaudeAdapter,
|
|
31
|
+
ChainAdapter,
|
|
32
|
+
generate_line_with_llm,
|
|
33
|
+
)
|
|
23
34
|
|
|
24
35
|
# Canonical name for V8.0 (class name kept for backward compatibility)
|
|
25
36
|
SPLPureCore = SPLPureCoreV7_3
|
|
26
37
|
|
|
27
|
-
__version__ = "0.
|
|
28
|
-
__all__ = [
|
|
38
|
+
__version__ = "0.4.0"
|
|
39
|
+
__all__ = [
|
|
40
|
+
"SPLPureCore", "SPLPureCoreV7_3", "NarrativeMapper", "AuditLogger",
|
|
41
|
+
"TokenUsage", "TokenStats",
|
|
42
|
+
"LLMAdapter", "OpenAIAdapter", "ClaudeAdapter", "ChainAdapter",
|
|
43
|
+
"generate_line_with_llm",
|
|
44
|
+
]
|
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
import os
|
|
5
5
|
import datetime
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
|
-
from typing import Dict, Any, List, Optional
|
|
7
|
+
from typing import Dict, Any, List, Optional, Tuple, Union
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# ================================================================
|
|
@@ -75,10 +75,162 @@ class AuditLogger:
|
|
|
75
75
|
"memory_count", "expected_count")
|
|
76
76
|
return {k: snap.get(k) for k in keys if k in snap}
|
|
77
77
|
|
|
78
|
+
def log_llm_call(self, model: str, prompt_preview: str,
|
|
79
|
+
usage: Optional["TokenUsage"] = None,
|
|
80
|
+
duration_ms: float = 0.0,
|
|
81
|
+
success: bool = True,
|
|
82
|
+
error: str = "") -> None:
|
|
83
|
+
"""记录一次 LLM 调用(token 用量、耗时、成功/失败)。
|
|
84
|
+
|
|
85
|
+
写入失败静默跳过,绝不阻断引擎核心。
|
|
86
|
+
"""
|
|
87
|
+
if not self.enabled:
|
|
88
|
+
return
|
|
89
|
+
try:
|
|
90
|
+
entry = {
|
|
91
|
+
"seq": self._entry_count,
|
|
92
|
+
"ts": datetime.datetime.now().isoformat(timespec="milliseconds"),
|
|
93
|
+
"engine": self.ENGINE_VERSION,
|
|
94
|
+
"session": self.session_id,
|
|
95
|
+
"event": "llm_call",
|
|
96
|
+
"model": model,
|
|
97
|
+
"prompt_preview": prompt_preview[:200],
|
|
98
|
+
"success": success,
|
|
99
|
+
"duration_ms": round(duration_ms, 2),
|
|
100
|
+
"usage": {
|
|
101
|
+
"prompt_tokens": usage.prompt_tokens if usage else 0,
|
|
102
|
+
"completion_tokens": usage.completion_tokens if usage else 0,
|
|
103
|
+
"total_tokens": usage.total_tokens if usage else 0,
|
|
104
|
+
} if usage else None,
|
|
105
|
+
"error": error or None,
|
|
106
|
+
}
|
|
107
|
+
with open(self.log_file, "a", encoding="utf-8") as f:
|
|
108
|
+
f.write(json.dumps(entry, ensure_ascii=False, default=str) + "\n")
|
|
109
|
+
self._entry_count += 1
|
|
110
|
+
except Exception:
|
|
111
|
+
pass
|
|
112
|
+
|
|
78
113
|
def export_path(self) -> Optional[str]:
|
|
79
114
|
return self.log_file if os.path.exists(self.log_file) else None
|
|
80
115
|
|
|
81
116
|
|
|
117
|
+
@dataclass
|
|
118
|
+
class TokenUsage:
|
|
119
|
+
"""LLM 调用 token 用量统计。"""
|
|
120
|
+
prompt_tokens: int = 0
|
|
121
|
+
completion_tokens: int = 0
|
|
122
|
+
total_tokens: int = 0
|
|
123
|
+
model: str = ""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# ================================================================
|
|
127
|
+
# Token 累计统计器 — 跨调用汇总 token 用量
|
|
128
|
+
# ================================================================
|
|
129
|
+
class TokenStats:
|
|
130
|
+
"""跨多次 LLM 调用累计统计 token 用量。
|
|
131
|
+
|
|
132
|
+
功能:
|
|
133
|
+
- 累计 prompt / completion / total tokens
|
|
134
|
+
- 按模型分别统计
|
|
135
|
+
- 记录每次调用明细
|
|
136
|
+
- 导出 JSON 汇总报告
|
|
137
|
+
|
|
138
|
+
用法:
|
|
139
|
+
stats = TokenStats()
|
|
140
|
+
stats.record(usage) # 传入 TokenUsage
|
|
141
|
+
stats.record(usage2)
|
|
142
|
+
stats.summary() # 汇总 dict
|
|
143
|
+
stats.export_json("stats.json") # 导出文件
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
def __init__(self):
|
|
147
|
+
self._total_prompt: int = 0
|
|
148
|
+
self._total_completion: int = 0
|
|
149
|
+
self._total_tokens: int = 0
|
|
150
|
+
self._call_count: int = 0
|
|
151
|
+
self._by_model: Dict[str, Dict[str, int]] = {}
|
|
152
|
+
self._history: List[Dict[str, Any]] = []
|
|
153
|
+
|
|
154
|
+
def record(self, usage: TokenUsage) -> None:
|
|
155
|
+
"""记录一次 LLM 调用的 token 用量。"""
|
|
156
|
+
if usage is None:
|
|
157
|
+
return
|
|
158
|
+
self._total_prompt += usage.prompt_tokens
|
|
159
|
+
self._total_completion += usage.completion_tokens
|
|
160
|
+
self._total_tokens += usage.total_tokens
|
|
161
|
+
self._call_count += 1
|
|
162
|
+
|
|
163
|
+
model = usage.model or "unknown"
|
|
164
|
+
if model not in self._by_model:
|
|
165
|
+
self._by_model[model] = {
|
|
166
|
+
"prompt_tokens": 0,
|
|
167
|
+
"completion_tokens": 0,
|
|
168
|
+
"total_tokens": 0,
|
|
169
|
+
"call_count": 0,
|
|
170
|
+
}
|
|
171
|
+
m = self._by_model[model]
|
|
172
|
+
m["prompt_tokens"] += usage.prompt_tokens
|
|
173
|
+
m["completion_tokens"] += usage.completion_tokens
|
|
174
|
+
m["total_tokens"] += usage.total_tokens
|
|
175
|
+
m["call_count"] += 1
|
|
176
|
+
|
|
177
|
+
self._history.append({
|
|
178
|
+
"seq": self._call_count,
|
|
179
|
+
"model": model,
|
|
180
|
+
"prompt_tokens": usage.prompt_tokens,
|
|
181
|
+
"completion_tokens": usage.completion_tokens,
|
|
182
|
+
"total_tokens": usage.total_tokens,
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
def summary(self) -> Dict[str, Any]:
|
|
186
|
+
"""返回累计统计汇总。"""
|
|
187
|
+
return {
|
|
188
|
+
"call_count": self._call_count,
|
|
189
|
+
"total_prompt_tokens": self._total_prompt,
|
|
190
|
+
"total_completion_tokens": self._total_completion,
|
|
191
|
+
"total_tokens": self._total_tokens,
|
|
192
|
+
"by_model": dict(self._by_model),
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
def history(self) -> List[Dict[str, Any]]:
|
|
196
|
+
"""返回每次调用的明细记录。"""
|
|
197
|
+
return list(self._history)
|
|
198
|
+
|
|
199
|
+
def reset(self) -> None:
|
|
200
|
+
"""清空所有统计。"""
|
|
201
|
+
self._total_prompt = 0
|
|
202
|
+
self._total_completion = 0
|
|
203
|
+
self._total_tokens = 0
|
|
204
|
+
self._call_count = 0
|
|
205
|
+
self._by_model.clear()
|
|
206
|
+
self._history.clear()
|
|
207
|
+
|
|
208
|
+
def export_json(self, path: str) -> None:
|
|
209
|
+
"""将统计汇总 + 明细导出为 JSON 文件。"""
|
|
210
|
+
data = {
|
|
211
|
+
"summary": self.summary(),
|
|
212
|
+
"history": self.history(),
|
|
213
|
+
}
|
|
214
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
215
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def total_tokens(self) -> int:
|
|
219
|
+
return self._total_tokens
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def total_prompt_tokens(self) -> int:
|
|
223
|
+
return self._total_prompt
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def total_completion_tokens(self) -> int:
|
|
227
|
+
return self._total_completion
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def call_count(self) -> int:
|
|
231
|
+
return self._call_count
|
|
232
|
+
|
|
233
|
+
|
|
82
234
|
# ================================================================
|
|
83
235
|
# 1. 外部叙事映射器("自设:偏见/世界观/价值观"——纯外部策略)
|
|
84
236
|
# 用户可随意替换,无需修改核心代码。
|
|
@@ -1309,7 +1461,9 @@ class LLMAdapter(ABC):
|
|
|
1309
1461
|
style_example: str = "",
|
|
1310
1462
|
system_prompt: str = "",
|
|
1311
1463
|
temperature: float = 0.7,
|
|
1312
|
-
max_tokens: int = 500
|
|
1464
|
+
max_tokens: int = 500,
|
|
1465
|
+
return_usage: bool = False
|
|
1466
|
+
) -> Union[Optional[str], Tuple[Optional[str], Optional["TokenUsage"]]]:
|
|
1313
1467
|
"""
|
|
1314
1468
|
根据 prompt_injection 生成台词。
|
|
1315
1469
|
|
|
@@ -1319,9 +1473,11 @@ class LLMAdapter(ABC):
|
|
|
1319
1473
|
system_prompt: 可选系统提示词,覆盖默认
|
|
1320
1474
|
temperature: 采样温度
|
|
1321
1475
|
max_tokens: 最大生成 token 数
|
|
1476
|
+
return_usage: True 时返回 (台词, TokenUsage) 元组
|
|
1322
1477
|
|
|
1323
1478
|
Returns:
|
|
1324
|
-
生成的台词字符串,失败返回 None
|
|
1479
|
+
return_usage=False: 生成的台词字符串,失败返回 None
|
|
1480
|
+
return_usage=True: (台词, TokenUsage) 元组
|
|
1325
1481
|
"""
|
|
1326
1482
|
...
|
|
1327
1483
|
|
|
@@ -1350,7 +1506,9 @@ class OpenAIAdapter(LLMAdapter):
|
|
|
1350
1506
|
style_example: str = "",
|
|
1351
1507
|
system_prompt: str = "",
|
|
1352
1508
|
temperature: float = 0.7,
|
|
1353
|
-
max_tokens: int = 500
|
|
1509
|
+
max_tokens: int = 500,
|
|
1510
|
+
return_usage: bool = False
|
|
1511
|
+
) -> Union[Optional[str], Tuple[Optional[str], Optional[TokenUsage]]]:
|
|
1354
1512
|
import urllib.request
|
|
1355
1513
|
import urllib.error
|
|
1356
1514
|
|
|
@@ -1383,8 +1541,22 @@ class OpenAIAdapter(LLMAdapter):
|
|
|
1383
1541
|
body = json.loads(resp.read().decode("utf-8"))
|
|
1384
1542
|
choice = body.get("choices", [{}])[0]
|
|
1385
1543
|
content = choice.get("message", {}).get("content", "")
|
|
1386
|
-
|
|
1544
|
+
result = content.strip() if content else None
|
|
1545
|
+
|
|
1546
|
+
usage_data = body.get("usage", {}) or {}
|
|
1547
|
+
usage = TokenUsage(
|
|
1548
|
+
prompt_tokens=usage_data.get("prompt_tokens", 0),
|
|
1549
|
+
completion_tokens=usage_data.get("completion_tokens", 0),
|
|
1550
|
+
total_tokens=usage_data.get("total_tokens", 0),
|
|
1551
|
+
model=body.get("model", self.model),
|
|
1552
|
+
) if usage_data else None
|
|
1553
|
+
|
|
1554
|
+
if return_usage:
|
|
1555
|
+
return result, usage
|
|
1556
|
+
return result
|
|
1387
1557
|
except (urllib.error.URLError, json.JSONDecodeError, KeyError) as e:
|
|
1558
|
+
if return_usage:
|
|
1559
|
+
return None, None
|
|
1388
1560
|
return None
|
|
1389
1561
|
|
|
1390
1562
|
|
|
@@ -1412,7 +1584,9 @@ class ClaudeAdapter(LLMAdapter):
|
|
|
1412
1584
|
style_example: str = "",
|
|
1413
1585
|
system_prompt: str = "",
|
|
1414
1586
|
temperature: float = 0.7,
|
|
1415
|
-
max_tokens: int = 500
|
|
1587
|
+
max_tokens: int = 500,
|
|
1588
|
+
return_usage: bool = False
|
|
1589
|
+
) -> Union[Optional[str], Tuple[Optional[str], Optional[TokenUsage]]]:
|
|
1416
1590
|
import urllib.request
|
|
1417
1591
|
import urllib.error
|
|
1418
1592
|
|
|
@@ -1445,8 +1619,24 @@ class ClaudeAdapter(LLMAdapter):
|
|
|
1445
1619
|
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
1446
1620
|
body = json.loads(resp.read().decode("utf-8"))
|
|
1447
1621
|
content = body.get("content", [{}])[0].get("text", "")
|
|
1448
|
-
|
|
1622
|
+
result = content.strip() if content else None
|
|
1623
|
+
|
|
1624
|
+
usage_data = body.get("usage", {}) or {}
|
|
1625
|
+
prompt_tok = usage_data.get("input_tokens", 0)
|
|
1626
|
+
completion_tok = usage_data.get("output_tokens", 0)
|
|
1627
|
+
usage = TokenUsage(
|
|
1628
|
+
prompt_tokens=prompt_tok,
|
|
1629
|
+
completion_tokens=completion_tok,
|
|
1630
|
+
total_tokens=prompt_tok + completion_tok,
|
|
1631
|
+
model=body.get("model", self.model),
|
|
1632
|
+
) if usage_data else None
|
|
1633
|
+
|
|
1634
|
+
if return_usage:
|
|
1635
|
+
return result, usage
|
|
1636
|
+
return result
|
|
1449
1637
|
except (urllib.error.URLError, json.JSONDecodeError, KeyError) as e:
|
|
1638
|
+
if return_usage:
|
|
1639
|
+
return None, None
|
|
1450
1640
|
return None
|
|
1451
1641
|
|
|
1452
1642
|
|
|
@@ -1472,24 +1662,45 @@ class ChainAdapter(LLMAdapter):
|
|
|
1472
1662
|
style_example: str = "",
|
|
1473
1663
|
system_prompt: str = "",
|
|
1474
1664
|
temperature: float = 0.7,
|
|
1475
|
-
max_tokens: int = 500
|
|
1476
|
-
|
|
1665
|
+
max_tokens: int = 500,
|
|
1666
|
+
return_usage: bool = False
|
|
1667
|
+
) -> Union[Optional[str], Tuple[Optional[str], Optional[TokenUsage]]]:
|
|
1668
|
+
result, usage = self.primary.generate(
|
|
1477
1669
|
prompt_injection=prompt_injection,
|
|
1478
1670
|
style_example=style_example,
|
|
1479
1671
|
system_prompt=system_prompt,
|
|
1480
1672
|
temperature=temperature,
|
|
1481
1673
|
max_tokens=max_tokens,
|
|
1674
|
+
return_usage=True,
|
|
1482
1675
|
)
|
|
1483
1676
|
if result is not None:
|
|
1677
|
+
if return_usage:
|
|
1678
|
+
return result, usage
|
|
1484
1679
|
return result
|
|
1485
1680
|
if self.fallback is not None:
|
|
1486
|
-
|
|
1681
|
+
result2, usage2 = self.fallback.generate(
|
|
1487
1682
|
prompt_injection=prompt_injection,
|
|
1488
1683
|
style_example=style_example,
|
|
1489
1684
|
system_prompt=system_prompt,
|
|
1490
1685
|
temperature=temperature,
|
|
1491
1686
|
max_tokens=max_tokens,
|
|
1687
|
+
return_usage=True,
|
|
1492
1688
|
)
|
|
1689
|
+
if return_usage:
|
|
1690
|
+
# 合并两次调用的 token 用量
|
|
1691
|
+
if usage and usage2:
|
|
1692
|
+
merged = TokenUsage(
|
|
1693
|
+
prompt_tokens=usage.prompt_tokens + usage2.prompt_tokens,
|
|
1694
|
+
completion_tokens=usage.completion_tokens + usage2.completion_tokens,
|
|
1695
|
+
total_tokens=usage.total_tokens + usage2.total_tokens,
|
|
1696
|
+
model=f"{usage.model}->{usage2.model}",
|
|
1697
|
+
)
|
|
1698
|
+
else:
|
|
1699
|
+
merged = usage2 or usage
|
|
1700
|
+
return result2, merged
|
|
1701
|
+
return result2
|
|
1702
|
+
if return_usage:
|
|
1703
|
+
return None, usage
|
|
1493
1704
|
return None
|
|
1494
1705
|
|
|
1495
1706
|
|
|
@@ -1501,6 +1712,7 @@ def generate_line_with_llm(
|
|
|
1501
1712
|
core_snapshot: dict,
|
|
1502
1713
|
expression,
|
|
1503
1714
|
adapter: LLMAdapter,
|
|
1715
|
+
audit_logger: Optional["AuditLogger"] = None,
|
|
1504
1716
|
) -> str:
|
|
1505
1717
|
"""
|
|
1506
1718
|
便利函数:引擎渲染风格 → LLM 生成台词 → 失败回退到确定性生成。
|
|
@@ -1510,18 +1722,38 @@ def generate_line_with_llm(
|
|
|
1510
1722
|
core_snapshot: SPL 核心快照(含 fluid/mood/self_esteem 等)
|
|
1511
1723
|
expression: 表达意图对象(含 expression_mode / emotion_hidden / silence 等)
|
|
1512
1724
|
adapter: LLMAdapter 实例
|
|
1725
|
+
audit_logger: 可选 AuditLogger,传入则记录 LLM 调用与 token 用量
|
|
1513
1726
|
|
|
1514
1727
|
Returns:
|
|
1515
1728
|
台词字符串(LLM 成功=LLM 产出,失败=引擎确定性产出)
|
|
1516
1729
|
"""
|
|
1730
|
+
import time as _time
|
|
1731
|
+
|
|
1517
1732
|
rendered = engine.render_style(core_snapshot, expression)
|
|
1518
1733
|
if rendered.silence_hint:
|
|
1519
1734
|
return rendered.silence_hint
|
|
1520
1735
|
|
|
1521
|
-
|
|
1736
|
+
t0 = _time.perf_counter()
|
|
1737
|
+
line, usage = adapter.generate(
|
|
1522
1738
|
prompt_injection=rendered.prompt_injection,
|
|
1523
1739
|
style_example=rendered.style_example,
|
|
1740
|
+
return_usage=True,
|
|
1524
1741
|
)
|
|
1742
|
+
duration_ms = (_time.perf_counter() - t0) * 1000
|
|
1743
|
+
|
|
1744
|
+
if audit_logger is not None:
|
|
1745
|
+
model = getattr(adapter, "model", "") or (
|
|
1746
|
+
usage.model if usage else ""
|
|
1747
|
+
)
|
|
1748
|
+
audit_logger.log_llm_call(
|
|
1749
|
+
model=model,
|
|
1750
|
+
prompt_preview=rendered.prompt_injection,
|
|
1751
|
+
usage=usage,
|
|
1752
|
+
duration_ms=duration_ms,
|
|
1753
|
+
success=line is not None,
|
|
1754
|
+
error="" if line is not None else "llm_failed",
|
|
1755
|
+
)
|
|
1756
|
+
|
|
1525
1757
|
if line is not None:
|
|
1526
1758
|
return line
|
|
1527
1759
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spl-agent-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Anthropomorphic psychology engine built on SPL Pure Core V8.0 — deterministic emotion, trauma, memory, trust, and defense mechanisms.
|
|
5
5
|
Author-email: NOHN-AI <ai@nohnlins.com>
|
|
6
6
|
Maintainer-email: NOHN-AI <ai@nohnlins.com>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine/feature/language_style.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spl_agent_engine-0.2.0 → spl_agent_engine-0.4.0}/spl_agent_engine.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|