Add LLMCompress subsystem - sandbox for symbolic compression of LLM behavior
New subsystem fully self-contained: Components: - LLMCompress/llm_adapter.py: LLMAdapter + LLMResponse (abstract over LLM backends) - LLMCompress/compression_report.py: CompressionReport (symbolic analysis results) - LLMCompress/llm_compressor.py: compress_interaction() and compress_session() - LLMCompress/tests/test_llm_compress.py: 5 comprehensive tests Integration: - Uses GlyphOS Cognitive Kernel for symbolic analysis - Integrates with GlyphOS Event System - Emits cognition.started and cognition.completed events - Supports in-memory GX execution via execute_symbolic() Test Coverage: - LLMCompress tests: 5/5 PASS - All existing tests still pass (52/52) - Total: 57 tests passing Bug fixes in cognitive_kernel.py: - Fixed execute_symbolic() method calls to use correct function signatures - normalize_segments(manifest, segments, payload) - map_lanes(segments) - build_envelope(manifest, lanes, payload, context) - execute_with_lain(envelope) Constraints: - No modifications to gx_compiler/* - No modifications to glyphs/super_registry.py - Self-contained subsystem with proper isolation - Full backward compatibility maintained
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""LLM Adapter
|
||||
|
||||
Thin abstraction over a concrete LLM backend (local or remote).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Dict, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class LLMResponse:
|
||||
"""Container for a single LLM interaction."""
|
||||
|
||||
prompt: str
|
||||
response: str
|
||||
tokens_prompt: Optional[int] = None
|
||||
tokens_response: Optional[int] = None
|
||||
model_name: Optional[str] = None
|
||||
metadata: Dict[str, Any] = None
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"prompt": self.prompt,
|
||||
"response": self.response,
|
||||
"tokens_prompt": self.tokens_prompt,
|
||||
"tokens_response": self.tokens_response,
|
||||
"model_name": self.model_name,
|
||||
"metadata": self.metadata or {},
|
||||
}
|
||||
|
||||
|
||||
class LLMAdapter:
|
||||
"""Adapter around a concrete LLM backend.
|
||||
|
||||
backend: Callable that takes (prompt, **kwargs) and returns:
|
||||
- str
|
||||
- or dict with keys like:
|
||||
- response
|
||||
- tokens_prompt
|
||||
- tokens_response
|
||||
- model_name
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
backend: Callable[..., Any],
|
||||
model_name: Optional[str] = None,
|
||||
) -> None:
|
||||
self._backend = backend
|
||||
self._model_name = model_name or "unknown"
|
||||
|
||||
def run(self, prompt: str, **kwargs: Any) -> LLMResponse:
|
||||
"""Run the underlying LLM on a prompt and normalize the result."""
|
||||
raw = self._backend(prompt, **kwargs)
|
||||
|
||||
if isinstance(raw, str):
|
||||
return LLMResponse(
|
||||
prompt=prompt,
|
||||
response=raw,
|
||||
model_name=self._model_name,
|
||||
metadata={},
|
||||
)
|
||||
|
||||
if isinstance(raw, dict):
|
||||
return LLMResponse(
|
||||
prompt=prompt,
|
||||
response=str(raw.get("response", "")),
|
||||
tokens_prompt=raw.get("tokens_prompt"),
|
||||
tokens_response=raw.get("tokens_response"),
|
||||
model_name=raw.get("model_name", self._model_name),
|
||||
metadata={
|
||||
k: v
|
||||
for k, v in raw.items()
|
||||
if k
|
||||
not in {
|
||||
"response",
|
||||
"tokens_prompt",
|
||||
"tokens_response",
|
||||
"model_name",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Fallback: best-effort stringification
|
||||
return LLMResponse(
|
||||
prompt=prompt,
|
||||
response=str(raw),
|
||||
model_name=self._model_name,
|
||||
metadata={"raw_type": type(raw).__name__},
|
||||
)
|
||||
Reference in New Issue
Block a user