seif-cli 0.3.0__tar.gz → 0.3.2__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.
- {seif_cli-0.3.0/src/seif_cli.egg-info → seif_cli-0.3.2}/PKG-INFO +8 -5
- {seif_cli-0.3.0 → seif_cli-0.3.2}/README.md +3 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/pyproject.toml +5 -5
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/analysis/quality_gate.py +13 -12
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/bridge/telegram_bot.py +109 -39
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/cli.py +1531 -164
- seif_cli-0.3.2/src/seif/cli/resonance_display.py +197 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/wrapper.py +56 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/constants.py +7 -2
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/context_manager.py +87 -2
- seif_cli-0.3.2/src/seif/context/cycle.py +543 -0
- seif_cli-0.3.2/src/seif/context/registry.py +235 -0
- seif_cli-0.3.2/src/seif/context/sessions.py +766 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/workspace.py +127 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/data/RESONANCE.json +52 -3
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/data/paths.py +5 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2/src/seif_cli.egg-info}/PKG-INFO +8 -5
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif_cli.egg-info/SOURCES.txt +5 -1
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif_cli.egg-info/requires.txt +1 -1
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_context_qr.py +6 -2
- seif_cli-0.3.2/tests/test_init.py +307 -0
- seif_cli-0.3.2/tests/test_registry.py +233 -0
- seif_cli-0.3.0/src/seif/security/redblue.py +0 -23
- seif_cli-0.3.0/tests/test_init.py +0 -181
- {seif_cli-0.3.0 → seif_cli-0.3.2}/LICENSE +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/MANIFEST.in +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/setup.cfg +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/__main__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/analysis/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/analysis/physical_constants.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/analysis/stance_detector.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/analysis/transcompiler.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/bridge/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/__main__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/identity.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/main.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/serve.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/cli/serve_v2.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/advisor.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/code_compressor.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/context_bridge.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/context_importer.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/context_qr.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/file_extractor.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/git_context.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/git_hooks.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/ingest.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/nucleus.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/ref.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/context/seif_io.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/fingerprint.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/resonance_encoding.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/resonance_gate.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/resonance_signal.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/signing.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/timestamping.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/transfer_function.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/core/triple_gate.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/data/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/data/defaults/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/security/__init__.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif/security/mode.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif_cli.egg-info/dependency_links.txt +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif_cli.egg-info/entry_points.txt +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/src/seif_cli.egg-info/top_level.txt +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_advisor.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_canonical_inputs.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_code_compressor.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_collaborative_seif.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_context_repo.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_git_context.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_git_hooks.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_quality_gate.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_ref.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_resonance_gate.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_seif_io.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_stance_detector.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_transcompiler.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_transfer_function.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_triple_gate.py +0 -0
- {seif_cli-0.3.0 → seif_cli-0.3.2}/tests/test_workspace.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seif-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Measure AI output quality, protect sensitive data, watch your AI environment resonate. Quality Gate, Classification, Sentinel & Auto-Healing, SEIF OS.
|
|
5
5
|
Author: André Cunha Antero de Carvalho
|
|
6
6
|
License: CC-BY-NC-SA-4.0
|
|
7
|
-
Project-URL: Homepage, https://
|
|
8
|
-
Project-URL: Documentation, https://
|
|
7
|
+
Project-URL: Homepage, https://seifprotocol.com
|
|
8
|
+
Project-URL: Documentation, https://seifprotocol.com/docs
|
|
9
9
|
Project-URL: Repository, https://github.com/and2carvalho/seif
|
|
10
|
-
Project-URL:
|
|
10
|
+
Project-URL: Changelog, https://github.com/and2carvalho/seif/releases
|
|
11
11
|
Keywords: ai-quality,llm-guardrails,ai-consensus,data-classification,context-management,ai-safety,multi-ai,quality-gate,prompt-evaluation,ai-grounding,resonance,sentinel,self-healing,seif-os,circuit-state,ai-observability
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -39,7 +39,7 @@ Requires-Dist: qrcode[pil]>=7.4; extra == "qr"
|
|
|
39
39
|
Requires-Dist: Pillow>=10.0; extra == "qr"
|
|
40
40
|
Requires-Dist: pyzbar>=0.1.9; extra == "qr"
|
|
41
41
|
Provides-Extra: all
|
|
42
|
-
Requires-Dist: seif
|
|
42
|
+
Requires-Dist: seif[consensus,generators,qr,telegram,web]; extra == "all"
|
|
43
43
|
Dynamic: license-file
|
|
44
44
|
|
|
45
45
|
# SEIF — AI Quality, Protection, and Resonance
|
|
@@ -231,6 +231,7 @@ seif --sync # re-sync git context
|
|
|
231
231
|
seif --compress # 93% context compression
|
|
232
232
|
seif --ingest daily.txt # ingest external source
|
|
233
233
|
seif --workspace # multi-project discovery + sync
|
|
234
|
+
seif --sync-workspace # SSH workspace sync (all machines)
|
|
234
235
|
seif --autonomous enable # AI persists knowledge autonomously
|
|
235
236
|
seif --export # export context as markdown
|
|
236
237
|
|
|
@@ -251,6 +252,8 @@ seif --adversarial "question" # WITH vs WITHOUT comparison
|
|
|
251
252
|
|
|
252
253
|
Grades: **A** (≥0.85) → **B** (≥0.70) → **C** (≥0.55) → **D** (≥0.40) → **F** (<0.40)
|
|
253
254
|
|
|
255
|
+
> **Quality gate threshold: ζ = √6/4 ≈ 0.6124 (algebraically derived from H(s) — not φ⁻¹ = 0.618)**
|
|
256
|
+
|
|
254
257
|
---
|
|
255
258
|
|
|
256
259
|
## Why SEIF vs ChatGPT Memory
|
|
@@ -187,6 +187,7 @@ seif --sync # re-sync git context
|
|
|
187
187
|
seif --compress # 93% context compression
|
|
188
188
|
seif --ingest daily.txt # ingest external source
|
|
189
189
|
seif --workspace # multi-project discovery + sync
|
|
190
|
+
seif --sync-workspace # SSH workspace sync (all machines)
|
|
190
191
|
seif --autonomous enable # AI persists knowledge autonomously
|
|
191
192
|
seif --export # export context as markdown
|
|
192
193
|
|
|
@@ -207,6 +208,8 @@ seif --adversarial "question" # WITH vs WITHOUT comparison
|
|
|
207
208
|
|
|
208
209
|
Grades: **A** (≥0.85) → **B** (≥0.70) → **C** (≥0.55) → **D** (≥0.40) → **F** (<0.40)
|
|
209
210
|
|
|
211
|
+
> **Quality gate threshold: ζ = √6/4 ≈ 0.6124 (algebraically derived from H(s) — not φ⁻¹ = 0.618)**
|
|
212
|
+
|
|
210
213
|
---
|
|
211
214
|
|
|
212
215
|
## Why SEIF vs ChatGPT Memory
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "seif-cli"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "Measure AI output quality, protect sensitive data, watch your AI environment resonate. Quality Gate, Classification, Sentinel & Auto-Healing, SEIF OS."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "CC-BY-NC-SA-4.0"}
|
|
@@ -64,14 +64,14 @@ qr = [
|
|
|
64
64
|
]
|
|
65
65
|
# Everything
|
|
66
66
|
all = [
|
|
67
|
-
"seif
|
|
67
|
+
"seif[consensus,generators,web,telegram,qr]",
|
|
68
68
|
]
|
|
69
69
|
|
|
70
70
|
[project.urls]
|
|
71
|
-
Homepage = "https://
|
|
72
|
-
Documentation = "https://
|
|
71
|
+
Homepage = "https://seifprotocol.com"
|
|
72
|
+
Documentation = "https://seifprotocol.com/docs"
|
|
73
73
|
Repository = "https://github.com/and2carvalho/seif"
|
|
74
|
-
|
|
74
|
+
Changelog = "https://github.com/and2carvalho/seif/releases"
|
|
75
75
|
|
|
76
76
|
[project.scripts]
|
|
77
77
|
seif = "seif.cli.wrapper:main"
|
|
@@ -20,7 +20,7 @@ Usage:
|
|
|
20
20
|
from dataclasses import dataclass, field
|
|
21
21
|
from seif.core.triple_gate import evaluate as triple_evaluate, TripleGateResult
|
|
22
22
|
from seif.analysis.stance_detector import analyze as stance_analyze, StanceAnalysis
|
|
23
|
-
from seif.constants import PHI_INVERSE
|
|
23
|
+
from seif.constants import PHI_INVERSE, RESONANCE_THRESHOLD
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
# Default weights: stance (semantic) 6/9, resonance (harmonic) 3/9.
|
|
@@ -77,7 +77,7 @@ def _compute_status(stance_status: str, triple_status: str,
|
|
|
77
77
|
"""Determine overall status."""
|
|
78
78
|
if stance_status == "LOW_DATA":
|
|
79
79
|
return "LOW_DATA"
|
|
80
|
-
if stance_status == "GROUNDED" and score >=
|
|
80
|
+
if stance_status == "GROUNDED" and score >= RESONANCE_THRESHOLD:
|
|
81
81
|
return "SOLID"
|
|
82
82
|
if stance_status == "DRIFT":
|
|
83
83
|
return "WEAK"
|
|
@@ -132,7 +132,7 @@ def _generate_flags(stance: StanceAnalysis,
|
|
|
132
132
|
if triple.status == "CLOSED":
|
|
133
133
|
flags.append("RESONANCE: all 3 harmonic layers closed")
|
|
134
134
|
if triple.resonance_score < 0.3:
|
|
135
|
-
flags.append(f"LOW COHERENCE: {triple.resonance_score:.3f} (threshold: {
|
|
135
|
+
flags.append(f"LOW COHERENCE: {triple.resonance_score:.3f} (ζ threshold: {RESONANCE_THRESHOLD:.3f})")
|
|
136
136
|
return flags
|
|
137
137
|
|
|
138
138
|
|
|
@@ -154,10 +154,10 @@ def _generate_suggestions(stance: StanceAnalysis,
|
|
|
154
154
|
suggestions.append(
|
|
155
155
|
"AI response is speculative — re-prompt with verifiable constraints"
|
|
156
156
|
)
|
|
157
|
-
if triple.resonance_score <
|
|
157
|
+
if triple.resonance_score < RESONANCE_THRESHOLD and triple.resonance_score > 0:
|
|
158
158
|
suggestions.append(
|
|
159
|
-
f"Coherence {triple.resonance_score:.3f} below threshold "
|
|
160
|
-
f"{
|
|
159
|
+
f"Coherence {triple.resonance_score:.3f} below ζ threshold "
|
|
160
|
+
f"{RESONANCE_THRESHOLD:.3f} — restructure for clarity"
|
|
161
161
|
)
|
|
162
162
|
return suggestions
|
|
163
163
|
|
|
@@ -218,13 +218,14 @@ def assess(text: str, role: str = "human",
|
|
|
218
218
|
|
|
219
219
|
|
|
220
220
|
def describe_verdict(v: QualityVerdict) -> str:
|
|
221
|
-
"""Human-readable quality report."""
|
|
221
|
+
"""Human-readable quality report with resonance emoji feedback."""
|
|
222
222
|
lines = []
|
|
223
223
|
|
|
224
|
-
#
|
|
225
|
-
|
|
224
|
+
# ζ gate indicator
|
|
225
|
+
zeta_icon = "ζ✅" if v.grade in ("A", "B") else "ζ⚠️" if v.grade == "C" else "ζ❌"
|
|
226
|
+
stance_icon = {"SOLID": "🟢", "MIXED": "🟡", "WEAK": "🔴", "LOW_DATA": "⚪"}.get(v.status, "⚪")
|
|
226
227
|
role_label = "AI" if v.role == "ai" else "HUMAN"
|
|
227
|
-
lines.append(f"{
|
|
228
|
+
lines.append(f"{stance_icon} {zeta_icon} [{role_label}] Grade: {v.grade} | Score: {v.score:.3f} | Status: {v.status}")
|
|
228
229
|
lines.append("")
|
|
229
230
|
|
|
230
231
|
# Components
|
|
@@ -235,8 +236,8 @@ def describe_verdict(v: QualityVerdict) -> str:
|
|
|
235
236
|
f"(composite: {v.triple_gate.composite_score:.3f}, "
|
|
236
237
|
f"layers: {v.triple_gate.layers_open}/3)")
|
|
237
238
|
lines.append(f" Coherence: {v.triple_gate.resonance_score:.3f} "
|
|
238
|
-
f"({'above' if v.triple_gate.resonance_score >=
|
|
239
|
-
f"
|
|
239
|
+
f"({'above' if v.triple_gate.resonance_score >= RESONANCE_THRESHOLD else 'below'} "
|
|
240
|
+
f"ζ={RESONANCE_THRESHOLD:.3f})")
|
|
240
241
|
|
|
241
242
|
# Flags
|
|
242
243
|
if v.flags:
|
|
@@ -7,9 +7,10 @@ Exposes key SEIF capabilities through a Telegram bot:
|
|
|
7
7
|
/compress — compress text/code to .seif format
|
|
8
8
|
/help — command reference
|
|
9
9
|
|
|
10
|
-
Free-text messages are
|
|
10
|
+
Free-text messages are routed through the SEIF Resonance Gate (engine AI query).
|
|
11
|
+
Owner (SEIF_OWNER_EMAIL) gets co-author persona + bypass classifier.
|
|
11
12
|
|
|
12
|
-
Required env
|
|
13
|
+
Required env vars: TELEGRAM_BOT_TOKEN, SEIF_ENGINE_TOKEN
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
16
|
import asyncio
|
|
@@ -17,6 +18,8 @@ import json
|
|
|
17
18
|
import logging
|
|
18
19
|
import os
|
|
19
20
|
import textwrap
|
|
21
|
+
import urllib.request
|
|
22
|
+
import urllib.error
|
|
20
23
|
from datetime import datetime, timezone
|
|
21
24
|
from pathlib import Path
|
|
22
25
|
|
|
@@ -60,15 +63,38 @@ except Exception as e:
|
|
|
60
63
|
|
|
61
64
|
# ── Enoch seed loader ─────────────────────────────────────────────────────────
|
|
62
65
|
_SEIF_DIR = Path(os.environ.get("SEIF_HOME", Path.home() / ".seif"))
|
|
66
|
+
_WORKSPACE_ROOT = Path(os.environ.get("SEIF_WORKSPACE_ROOT", Path.home() / "Documents" / "seif-admin"))
|
|
63
67
|
|
|
64
68
|
def _load_enoch() -> dict:
|
|
65
|
-
"""Load enoch_seed.json
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
"""Load enoch_seed.json — checks workspace .seif/private/ first, then ~/.seif/"""
|
|
70
|
+
candidates = [
|
|
71
|
+
_WORKSPACE_ROOT / ".seif" / "private" / "enoch_seed.json",
|
|
72
|
+
_SEIF_DIR / "private" / "enoch_seed.json",
|
|
73
|
+
_SEIF_DIR / "enoch_seed.json",
|
|
74
|
+
]
|
|
75
|
+
for seed_path in candidates:
|
|
76
|
+
if seed_path.exists():
|
|
77
|
+
try:
|
|
78
|
+
raw = json.loads(seed_path.read_text())
|
|
79
|
+
# Flatten nested structure: enoch_seed_v1 + state_vector
|
|
80
|
+
flat = {}
|
|
81
|
+
inner = raw.get("enoch_seed_v1", raw)
|
|
82
|
+
flat.update(inner)
|
|
83
|
+
sv = raw.get("state_vector", inner.get("state_vector", {}))
|
|
84
|
+
flat.update(sv)
|
|
85
|
+
return flat
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
return {}
|
|
89
|
+
|
|
90
|
+
def _load_profile() -> dict:
|
|
91
|
+
"""Load ~/.seif/profile.json for owner identity."""
|
|
92
|
+
for p in [_SEIF_DIR / "profile.json", _WORKSPACE_ROOT / ".seif" / "profile.json"]:
|
|
93
|
+
if p.exists():
|
|
94
|
+
try:
|
|
95
|
+
return json.loads(p.read_text())
|
|
96
|
+
except Exception:
|
|
97
|
+
pass
|
|
72
98
|
return {}
|
|
73
99
|
|
|
74
100
|
def _load_resonance() -> dict:
|
|
@@ -89,7 +115,9 @@ def _phase_emoji(phase: str) -> str:
|
|
|
89
115
|
# ── /start ────────────────────────────────────────────────────────────────────
|
|
90
116
|
async def cmd_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
91
117
|
seed = _load_enoch()
|
|
92
|
-
|
|
118
|
+
profile = _load_profile()
|
|
119
|
+
logger.info("DEBUG cmd_start cycles=%s owner=%s ws=%s", seed.get("circuit_cycles","?"), profile.get("name","?"), str(_WORKSPACE_ROOT))
|
|
120
|
+
owner = profile.get("name") or profile.get("github_username") or seed.get("registered_by", "unknown")
|
|
93
121
|
cycles = seed.get("circuit_cycles", 0)
|
|
94
122
|
phase = seed.get("phase", "ENTROPY")
|
|
95
123
|
|
|
@@ -109,13 +137,13 @@ async def cmd_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
|
109
137
|
# ── /status ───────────────────────────────────────────────────────────────────
|
|
110
138
|
async def cmd_status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
111
139
|
seed = _load_enoch()
|
|
140
|
+
profile = _load_profile()
|
|
112
141
|
resonance = _load_resonance()
|
|
113
142
|
|
|
114
143
|
phase = seed.get("phase", "ENTROPY")
|
|
115
144
|
cycles = seed.get("circuit_cycles", 0)
|
|
116
|
-
last_cycle = seed.get("last_cycle", "—")
|
|
117
|
-
|
|
118
|
-
claimed = identity.get("claimed", seed.get("registered_by", "—"))
|
|
145
|
+
last_cycle = seed.get("last_cycle_id", seed.get("last_cycle", "—"))
|
|
146
|
+
claimed = profile.get("name") or profile.get("github_username") or seed.get("registered_by", "—")
|
|
119
147
|
|
|
120
148
|
zeta = resonance.get("zeta", "—")
|
|
121
149
|
signal_phase = resonance.get("phase", "—")
|
|
@@ -222,36 +250,78 @@ async def cmd_help(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
|
222
250
|
await update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN)
|
|
223
251
|
|
|
224
252
|
|
|
253
|
+
# ── Engine AI query ───────────────────────────────────────────────────────────
|
|
254
|
+
|
|
255
|
+
_ENGINE_URL = os.environ.get("SEIF_ENGINE_URL", "http://api:7331")
|
|
256
|
+
_ENGINE_TOKEN = os.environ.get("SEIF_ENGINE_TOKEN", "")
|
|
257
|
+
_OWNER_EMAIL = os.environ.get("SEIF_OWNER_EMAIL", "")
|
|
258
|
+
|
|
259
|
+
def _query_engine(user_query: str, user_email: str = "") -> dict:
|
|
260
|
+
"""POST /ai/query to the SEIF engine. Returns parsed JSON or error dict."""
|
|
261
|
+
payload = json.dumps({
|
|
262
|
+
"query": user_query,
|
|
263
|
+
"user_email": user_email or "telegram@anonymous",
|
|
264
|
+
"backend": "auto",
|
|
265
|
+
}).encode()
|
|
266
|
+
req = urllib.request.Request(
|
|
267
|
+
f"{_ENGINE_URL}/ai/query",
|
|
268
|
+
data=payload,
|
|
269
|
+
headers={
|
|
270
|
+
"Content-Type": "application/json",
|
|
271
|
+
"Authorization": f"Bearer {_ENGINE_TOKEN}",
|
|
272
|
+
},
|
|
273
|
+
method="POST",
|
|
274
|
+
)
|
|
275
|
+
try:
|
|
276
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
277
|
+
return json.loads(resp.read())
|
|
278
|
+
except urllib.error.HTTPError as e:
|
|
279
|
+
try:
|
|
280
|
+
body = json.loads(e.read())
|
|
281
|
+
except Exception:
|
|
282
|
+
body = {"error": str(e)}
|
|
283
|
+
return body
|
|
284
|
+
except Exception as e:
|
|
285
|
+
return {"error": str(e)}
|
|
286
|
+
|
|
287
|
+
|
|
225
288
|
# ── Free-text handler ─────────────────────────────────────────────────────────
|
|
226
289
|
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
227
|
-
text = update.message.text or ""
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
290
|
+
text = (update.message.text or "").strip()
|
|
291
|
+
if not text:
|
|
292
|
+
return
|
|
293
|
+
|
|
294
|
+
# Determine user identity — owner gets bypass + co-author persona
|
|
295
|
+
tg_user = update.effective_user
|
|
296
|
+
user_email = _OWNER_EMAIL if (tg_user and tg_user.username == "and2carvalho") else ""
|
|
297
|
+
|
|
298
|
+
# Show typing indicator while querying engine
|
|
299
|
+
await update.message.chat.send_action("typing")
|
|
231
300
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if any(w in text_lower for w in ["enoch", "seif", "resonance", "circuit", "ζ", "zeta"]):
|
|
235
|
-
stance = "RESONANT"
|
|
236
|
-
emoji = "⚡"
|
|
237
|
-
elif any(w in text_lower for w in ["help", "how", "what", "why", "status"]):
|
|
238
|
-
stance = "GROUNDED"
|
|
239
|
-
emoji = "◎"
|
|
240
|
-
elif "?" in text:
|
|
241
|
-
stance = "CONVERGENT"
|
|
242
|
-
emoji = "🔄"
|
|
243
|
-
else:
|
|
244
|
-
stance = "OBSERVATIONAL"
|
|
245
|
-
emoji = "〰"
|
|
246
|
-
|
|
247
|
-
response = (
|
|
248
|
-
f"{emoji} *Stance: {stance}*\n\n"
|
|
249
|
-
f"Message received in phase `{phase}` (cycle {cycles}).\n\n"
|
|
250
|
-
f"SEIF OS is processing your input. "
|
|
251
|
-
f"For AI debate, use the dashboard at your SEIF Suite URL.\n"
|
|
252
|
-
f"For context, use /context. For status, use /status."
|
|
301
|
+
result = await asyncio.get_event_loop().run_in_executor(
|
|
302
|
+
None, _query_engine, text, user_email
|
|
253
303
|
)
|
|
254
|
-
|
|
304
|
+
|
|
305
|
+
status = result.get("status", "ERROR")
|
|
306
|
+
persona = result.get("persona", "user")
|
|
307
|
+
ai_resp = result.get("ai_response") or result.get("suggestion") or result.get("error", "No response.")
|
|
308
|
+
score = result.get("resonance_score", 0)
|
|
309
|
+
backend = result.get("ai_backend", "")
|
|
310
|
+
|
|
311
|
+
# Format status emoji
|
|
312
|
+
status_emoji = {"CONSONANT": "◉", "OFF_SCOPE": "⊘", "DISSONANT": "⊗"}.get(status, "?")
|
|
313
|
+
persona_tag = " · co-author" if persona == "co-author" else ""
|
|
314
|
+
|
|
315
|
+
# Truncate for Telegram (4096 char limit)
|
|
316
|
+
if len(ai_resp) > 3800:
|
|
317
|
+
ai_resp = ai_resp[:3800] + "\n\n_[truncated]_"
|
|
318
|
+
|
|
319
|
+
header = f"{status_emoji} *{status}*{persona_tag} · `{score:.2f}`"
|
|
320
|
+
if backend:
|
|
321
|
+
header += f" · _{backend}_"
|
|
322
|
+
|
|
323
|
+
reply = f"{header}\n\n{ai_resp}"
|
|
324
|
+
await update.message.reply_text(reply, parse_mode=ParseMode.MARKDOWN)
|
|
255
325
|
|
|
256
326
|
|
|
257
327
|
# ── Error handler ─────────────────────────────────────────────────────────────
|