seif-cli 0.3.2__tar.gz → 0.3.4__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.2/src/seif_cli.egg-info → seif_cli-0.3.4}/PKG-INFO +1 -1
- {seif_cli-0.3.2 → seif_cli-0.3.4}/pyproject.toml +1 -1
- seif_cli-0.3.4/src/seif/bridge/native_client.py +163 -0
- seif_cli-0.3.4/src/seif/cli/chat.py +11 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4/src/seif_cli.egg-info}/PKG-INFO +1 -1
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif_cli.egg-info/SOURCES.txt +2 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/LICENSE +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/MANIFEST.in +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/README.md +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/setup.cfg +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/__main__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/analysis/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/analysis/physical_constants.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/analysis/quality_gate.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/analysis/stance_detector.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/analysis/transcompiler.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/bridge/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/bridge/telegram_bot.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/__main__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/cli.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/identity.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/main.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/resonance_display.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/serve.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/serve_v2.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/cli/wrapper.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/constants.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/advisor.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/code_compressor.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/context_bridge.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/context_importer.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/context_manager.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/context_qr.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/cycle.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/file_extractor.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/git_context.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/git_hooks.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/ingest.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/nucleus.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/ref.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/registry.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/seif_io.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/sessions.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/context/workspace.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/fingerprint.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/resonance_encoding.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/resonance_gate.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/resonance_signal.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/signing.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/timestamping.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/transfer_function.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/core/triple_gate.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/data/RESONANCE.json +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/data/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/data/defaults/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/data/paths.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/security/__init__.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif/security/mode.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif_cli.egg-info/dependency_links.txt +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif_cli.egg-info/entry_points.txt +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif_cli.egg-info/requires.txt +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/src/seif_cli.egg-info/top_level.txt +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_advisor.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_canonical_inputs.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_code_compressor.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_collaborative_seif.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_context_qr.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_context_repo.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_git_context.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_git_hooks.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_init.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_quality_gate.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_ref.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_registry.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_resonance_gate.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_seif_io.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_stance_detector.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_transcompiler.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_transfer_function.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_triple_gate.py +0 -0
- {seif_cli-0.3.2 → seif_cli-0.3.4}/tests/test_workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seif-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
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
|
|
@@ -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.4"
|
|
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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Native AI Client — Direct SDK integration replacing CLI wrapper.
|
|
3
|
+
|
|
4
|
+
Supports streaming, multi-backend routing, and context injection from
|
|
5
|
+
the personal nucleus. Falls back to CLI subprocess if SDK unavailable.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Iterator, Optional
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class ChatConfig:
|
|
15
|
+
backend: str = "auto" # claude, gemini, local, auto
|
|
16
|
+
model: str = "" # model override (empty = use default)
|
|
17
|
+
stream: bool = True # streaming responses
|
|
18
|
+
quality_gate: bool = True # measure every response
|
|
19
|
+
max_tokens: int = 4096
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Default models per backend
|
|
23
|
+
_DEFAULT_MODELS = {
|
|
24
|
+
"claude": "claude-sonnet-4-6",
|
|
25
|
+
"gemini": "gemini-2.5-flash",
|
|
26
|
+
"grok": "grok-4-1-fast",
|
|
27
|
+
"local": "llama3",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NativeClient:
|
|
32
|
+
"""Multi-backend AI client with streaming support."""
|
|
33
|
+
|
|
34
|
+
def __init__(self, config: Optional[ChatConfig] = None,
|
|
35
|
+
profile: Optional[dict] = None):
|
|
36
|
+
self.config = config or ChatConfig()
|
|
37
|
+
self.profile = profile or {}
|
|
38
|
+
self._backend = self._resolve_backend()
|
|
39
|
+
self._model = self.config.model or _DEFAULT_MODELS.get(self._backend, "")
|
|
40
|
+
self._client = None
|
|
41
|
+
|
|
42
|
+
def _resolve_backend(self) -> str:
|
|
43
|
+
"""Resolve 'auto' to the best available backend."""
|
|
44
|
+
if self.config.backend != "auto":
|
|
45
|
+
return self.config.backend
|
|
46
|
+
|
|
47
|
+
profile_default = self.profile.get("default_backend", "")
|
|
48
|
+
if profile_default and profile_default != "auto":
|
|
49
|
+
return profile_default
|
|
50
|
+
|
|
51
|
+
if os.environ.get("ANTHROPIC_API_KEY"):
|
|
52
|
+
return "claude"
|
|
53
|
+
if os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY"):
|
|
54
|
+
return "gemini"
|
|
55
|
+
return "claude"
|
|
56
|
+
|
|
57
|
+
def _get_anthropic_client(self):
|
|
58
|
+
"""Lazy-init Anthropic client."""
|
|
59
|
+
if self._client is None:
|
|
60
|
+
import anthropic
|
|
61
|
+
self._client = anthropic.Anthropic()
|
|
62
|
+
return self._client
|
|
63
|
+
|
|
64
|
+
def send(self, message: str, history: list[dict] = None,
|
|
65
|
+
system: str = "") -> str:
|
|
66
|
+
"""Send message and return complete response."""
|
|
67
|
+
if self._backend == "claude":
|
|
68
|
+
return self._send_claude(message, history or [], system)
|
|
69
|
+
elif self._backend == "gemini":
|
|
70
|
+
return self._send_gemini(message, history or [], system)
|
|
71
|
+
elif self._backend == "local":
|
|
72
|
+
return self._send_local(message, history or [], system)
|
|
73
|
+
else:
|
|
74
|
+
return f"Backend '{self._backend}' not supported."
|
|
75
|
+
|
|
76
|
+
def stream(self, message: str, history: list[dict] = None,
|
|
77
|
+
system: str = "") -> Iterator[str]:
|
|
78
|
+
"""Stream response tokens. Falls back to send() if streaming unavailable."""
|
|
79
|
+
if self._backend == "claude":
|
|
80
|
+
yield from self._stream_claude(message, history or [], system)
|
|
81
|
+
else:
|
|
82
|
+
yield self.send(message, history, system)
|
|
83
|
+
|
|
84
|
+
def _send_claude(self, message: str, history: list[dict],
|
|
85
|
+
system: str) -> str:
|
|
86
|
+
try:
|
|
87
|
+
client = self._get_anthropic_client()
|
|
88
|
+
messages = history + [{"role": "user", "content": message}]
|
|
89
|
+
response = client.messages.create(
|
|
90
|
+
model=self._model,
|
|
91
|
+
max_tokens=self.config.max_tokens,
|
|
92
|
+
system=system,
|
|
93
|
+
messages=messages,
|
|
94
|
+
)
|
|
95
|
+
return response.content[0].text
|
|
96
|
+
except ImportError:
|
|
97
|
+
return self._fallback_cli(message, system)
|
|
98
|
+
except Exception as e:
|
|
99
|
+
return f"Error: {e}"
|
|
100
|
+
|
|
101
|
+
def _stream_claude(self, message: str, history: list[dict],
|
|
102
|
+
system: str) -> Iterator[str]:
|
|
103
|
+
try:
|
|
104
|
+
client = self._get_anthropic_client()
|
|
105
|
+
messages = history + [{"role": "user", "content": message}]
|
|
106
|
+
with client.messages.stream(
|
|
107
|
+
model=self._model,
|
|
108
|
+
max_tokens=self.config.max_tokens,
|
|
109
|
+
system=system,
|
|
110
|
+
messages=messages,
|
|
111
|
+
) as stream:
|
|
112
|
+
for text in stream.text_stream:
|
|
113
|
+
yield text
|
|
114
|
+
except ImportError:
|
|
115
|
+
yield self._fallback_cli(message, system)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
yield f"Error: {e}"
|
|
118
|
+
|
|
119
|
+
def _send_gemini(self, message: str, history: list[dict],
|
|
120
|
+
system: str) -> str:
|
|
121
|
+
try:
|
|
122
|
+
import google.generativeai as genai
|
|
123
|
+
genai.configure()
|
|
124
|
+
model = genai.GenerativeModel(self._model,
|
|
125
|
+
system_instruction=system)
|
|
126
|
+
chat = model.start_chat(history=[
|
|
127
|
+
{"role": h["role"], "parts": [h["content"]]}
|
|
128
|
+
for h in history
|
|
129
|
+
] if history else [])
|
|
130
|
+
response = chat.send_message(message)
|
|
131
|
+
return response.text
|
|
132
|
+
except ImportError:
|
|
133
|
+
return "Gemini SDK not installed. pip install google-generativeai"
|
|
134
|
+
except Exception as e:
|
|
135
|
+
return f"Gemini error: {e}"
|
|
136
|
+
|
|
137
|
+
def _send_local(self, message: str, history: list[dict],
|
|
138
|
+
system: str) -> str:
|
|
139
|
+
try:
|
|
140
|
+
import subprocess
|
|
141
|
+
result = subprocess.run(
|
|
142
|
+
["ollama", "run", self._model, message],
|
|
143
|
+
capture_output=True, text=True, timeout=120,
|
|
144
|
+
)
|
|
145
|
+
return result.stdout.strip() if result.returncode == 0 else f"Error: {result.stderr}"
|
|
146
|
+
except FileNotFoundError:
|
|
147
|
+
return "Ollama not installed. https://ollama.ai"
|
|
148
|
+
except Exception as e:
|
|
149
|
+
return f"Local error: {e}"
|
|
150
|
+
|
|
151
|
+
def _fallback_cli(self, message: str, system: str) -> str:
|
|
152
|
+
"""Fall back to Claude CLI subprocess."""
|
|
153
|
+
import subprocess
|
|
154
|
+
try:
|
|
155
|
+
cmd = ["claude", "--print", "--output-format", "text",
|
|
156
|
+
"--no-session-persistence"]
|
|
157
|
+
if system:
|
|
158
|
+
cmd.extend(["--append-system-prompt", system])
|
|
159
|
+
cmd.append(message)
|
|
160
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
|
161
|
+
return result.stdout.strip() if result.returncode == 0 else f"CLI error: {result.stderr}"
|
|
162
|
+
except FileNotFoundError:
|
|
163
|
+
return "No AI backend available. Set ANTHROPIC_API_KEY or install claude CLI."
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bridge to seif-engine native chat.
|
|
3
|
+
|
|
4
|
+
This module exists in seif-cli so that
|
|
5
|
+
works when seif-engine is installed. The actual implementation lives in
|
|
6
|
+
seif_engine.api.chat (proprietary / Pro tier).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from seif_engine.api.chat import run_chat # noqa: F401
|
|
10
|
+
|
|
11
|
+
__all__ = ["run_chat"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seif-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
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
|
|
@@ -11,9 +11,11 @@ src/seif/analysis/quality_gate.py
|
|
|
11
11
|
src/seif/analysis/stance_detector.py
|
|
12
12
|
src/seif/analysis/transcompiler.py
|
|
13
13
|
src/seif/bridge/__init__.py
|
|
14
|
+
src/seif/bridge/native_client.py
|
|
14
15
|
src/seif/bridge/telegram_bot.py
|
|
15
16
|
src/seif/cli/__init__.py
|
|
16
17
|
src/seif/cli/__main__.py
|
|
18
|
+
src/seif/cli/chat.py
|
|
17
19
|
src/seif/cli/cli.py
|
|
18
20
|
src/seif/cli/identity.py
|
|
19
21
|
src/seif/cli/main.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|