Add Ikario Architecture v2 - Phases 1-8 complete
Implements the processual architecture based on Whitehead's Process Philosophy and Peirce's Semiotics. Core paradigm: "L'espace latent pense. Le LLM traduit." (The latent space thinks. The LLM translates.) Phase 1-4: Core semiotic cycle - StateTensor 8x1024 (8 Peircean dimensions) - Dissonance computation with hard negatives - Fixation via 4 Peircean methods (Tenacity, Authority, A Priori, Science) - LatentEngine orchestrating the full cycle Phase 5: StateToLanguage - LLM as pure translator (zero-reasoning, T=0) - Projection on interpretable directions - Reasoning markers detection (Amendment #4) Phase 6: Vigilance - x_ref (David) as guard-rail, NOT attractor - Drift detection per dimension and globally - Alerts: ok, warning, critical Phase 7: Autonomous Daemon - Two modes: CONVERSATION (always verbalize), AUTONOMOUS (~1000 cycles/day) - Amendment #5: 50% probability on unresolved impacts - TriggerGenerator with weighted random selection Phase 8: Integration & Metrics - ProcessMetrics for daily/weekly reports - Health status monitoring - Integration tests validating all modules 297 tests passing, version 0.7.0 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
605
ikario_processual/tests/test_state_to_language.py
Normal file
605
ikario_processual/tests/test_state_to_language.py
Normal file
@@ -0,0 +1,605 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests pour le module state_to_language - Phase 5.
|
||||
|
||||
Le cycle de traduction :
|
||||
1. Projeter StateTensor sur directions interpretables
|
||||
2. Construire prompt de traduction
|
||||
3. LLM en mode ZERO-REASONING
|
||||
4. Valider absence de raisonnement
|
||||
|
||||
Executer: pytest ikario_processual/tests/test_state_to_language.py -v
|
||||
"""
|
||||
|
||||
import json
|
||||
import numpy as np
|
||||
import pytest
|
||||
import asyncio
|
||||
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock, AsyncMock, patch
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
|
||||
from ikario_processual.state_tensor import StateTensor, DIMENSION_NAMES, EMBEDDING_DIM
|
||||
from ikario_processual.state_to_language import (
|
||||
ProjectionDirection,
|
||||
TranslationResult,
|
||||
StateToLanguage,
|
||||
REASONING_MARKERS,
|
||||
CATEGORY_TO_DIMENSION,
|
||||
create_directions_from_config,
|
||||
)
|
||||
|
||||
|
||||
def create_random_tensor(state_id: int = 0) -> StateTensor:
|
||||
"""Cree un tenseur avec des vecteurs aleatoires normalises."""
|
||||
tensor = StateTensor(
|
||||
state_id=state_id,
|
||||
timestamp=datetime.now().isoformat(),
|
||||
)
|
||||
for dim_name in DIMENSION_NAMES:
|
||||
v = np.random.randn(EMBEDDING_DIM)
|
||||
v = v / np.linalg.norm(v)
|
||||
setattr(tensor, dim_name, v)
|
||||
return tensor
|
||||
|
||||
|
||||
def create_random_direction(name: str, category: str) -> ProjectionDirection:
|
||||
"""Cree une direction aleatoire normalisee."""
|
||||
v = np.random.randn(EMBEDDING_DIM)
|
||||
v = v / np.linalg.norm(v)
|
||||
return ProjectionDirection(
|
||||
name=name,
|
||||
category=category,
|
||||
pole_positive="positive",
|
||||
pole_negative="negative",
|
||||
description=f"Direction {name}",
|
||||
vector=v,
|
||||
)
|
||||
|
||||
|
||||
class TestProjectionDirection:
|
||||
"""Tests pour la classe ProjectionDirection."""
|
||||
|
||||
def test_create_direction(self):
|
||||
"""Creer une direction."""
|
||||
v = np.random.randn(EMBEDDING_DIM)
|
||||
v = v / np.linalg.norm(v)
|
||||
|
||||
direction = ProjectionDirection(
|
||||
name="curiosity",
|
||||
category="epistemic",
|
||||
pole_positive="curieux",
|
||||
pole_negative="desinteresse",
|
||||
description="Degre de curiosite",
|
||||
vector=v,
|
||||
)
|
||||
|
||||
assert direction.name == "curiosity"
|
||||
assert direction.category == "epistemic"
|
||||
assert direction.vector.shape == (EMBEDDING_DIM,)
|
||||
|
||||
def test_project_on_direction(self):
|
||||
"""Projection sur une direction."""
|
||||
v = np.random.randn(EMBEDDING_DIM)
|
||||
v = v / np.linalg.norm(v)
|
||||
|
||||
direction = ProjectionDirection(
|
||||
name="test",
|
||||
category="test",
|
||||
pole_positive="",
|
||||
pole_negative="",
|
||||
description="",
|
||||
vector=v,
|
||||
)
|
||||
|
||||
# Projeter le meme vecteur
|
||||
projection = direction.project(v)
|
||||
assert np.isclose(projection, 1.0)
|
||||
|
||||
# Projeter un vecteur oppose
|
||||
projection_neg = direction.project(-v)
|
||||
assert np.isclose(projection_neg, -1.0)
|
||||
|
||||
def test_projection_range(self):
|
||||
"""Les projections sont entre -1 et 1."""
|
||||
direction = create_random_direction("test", "test")
|
||||
|
||||
for _ in range(10):
|
||||
random_vec = np.random.randn(EMBEDDING_DIM)
|
||||
random_vec = random_vec / np.linalg.norm(random_vec)
|
||||
|
||||
projection = direction.project(random_vec)
|
||||
assert -1.0 <= projection <= 1.0
|
||||
|
||||
|
||||
class TestTranslationResult:
|
||||
"""Tests pour TranslationResult."""
|
||||
|
||||
def test_create_result(self):
|
||||
"""Creer un resultat de traduction."""
|
||||
result = TranslationResult(
|
||||
text="Je suis curieux.",
|
||||
projections={'epistemic': {'curiosity': 0.72}},
|
||||
output_type="response",
|
||||
reasoning_detected=False,
|
||||
json_valid=True,
|
||||
processing_time_ms=50,
|
||||
)
|
||||
|
||||
assert result.text == "Je suis curieux."
|
||||
assert result.reasoning_detected is False
|
||||
|
||||
def test_to_dict(self):
|
||||
"""to_dict() fonctionne."""
|
||||
result = TranslationResult(
|
||||
text="Test",
|
||||
projections={'test': {'test': 0.5}},
|
||||
output_type="response",
|
||||
reasoning_detected=True,
|
||||
json_valid=False,
|
||||
processing_time_ms=100,
|
||||
)
|
||||
|
||||
d = result.to_dict()
|
||||
assert 'text' in d
|
||||
assert 'projections' in d
|
||||
assert d['reasoning_detected'] is True
|
||||
assert d['json_valid'] is False
|
||||
|
||||
|
||||
class TestStateToLanguage:
|
||||
"""Tests pour la classe StateToLanguage."""
|
||||
|
||||
def test_create_translator(self):
|
||||
"""Creer un traducteur."""
|
||||
translator = StateToLanguage()
|
||||
assert translator.directions == []
|
||||
assert translator._translations_count == 0
|
||||
|
||||
def test_add_direction(self):
|
||||
"""Ajouter des directions."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
direction1 = create_random_direction("curiosity", "epistemic")
|
||||
direction2 = create_random_direction("enthusiasm", "affective")
|
||||
|
||||
translator.add_direction(direction1)
|
||||
translator.add_direction(direction2)
|
||||
|
||||
assert len(translator.directions) == 2
|
||||
|
||||
def test_project_state(self):
|
||||
"""Projeter un etat sur les directions."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
# Ajouter des directions de categories differentes
|
||||
translator.add_direction(create_random_direction("curiosity", "epistemic"))
|
||||
translator.add_direction(create_random_direction("certainty", "epistemic"))
|
||||
translator.add_direction(create_random_direction("enthusiasm", "affective"))
|
||||
|
||||
X_t = create_random_tensor()
|
||||
projections = translator.project_state(X_t)
|
||||
|
||||
# Verifier structure
|
||||
assert 'epistemic' in projections
|
||||
assert 'affective' in projections
|
||||
assert 'curiosity' in projections['epistemic']
|
||||
assert 'enthusiasm' in projections['affective']
|
||||
|
||||
# Verifier valeurs dans [-1, 1]
|
||||
for category, components in projections.items():
|
||||
for name, value in components.items():
|
||||
assert -1.0 <= value <= 1.0
|
||||
|
||||
def test_project_state_flat(self):
|
||||
"""Projection aplatie."""
|
||||
translator = StateToLanguage()
|
||||
translator.add_direction(create_random_direction("curiosity", "epistemic"))
|
||||
translator.add_direction(create_random_direction("enthusiasm", "affective"))
|
||||
|
||||
X_t = create_random_tensor()
|
||||
flat = translator.project_state_flat(X_t)
|
||||
|
||||
assert 'curiosity' in flat
|
||||
assert 'enthusiasm' in flat
|
||||
assert isinstance(flat['curiosity'], float)
|
||||
|
||||
|
||||
class TestInterpretValue:
|
||||
"""Tests pour interpret_value."""
|
||||
|
||||
def test_very_positive(self):
|
||||
"""Valeur tres positive."""
|
||||
assert StateToLanguage.interpret_value(0.8) == "tres"
|
||||
|
||||
def test_moderately_positive(self):
|
||||
"""Valeur moderement positive."""
|
||||
assert StateToLanguage.interpret_value(0.35) == "moderement"
|
||||
|
||||
def test_neutral(self):
|
||||
"""Valeur neutre."""
|
||||
assert StateToLanguage.interpret_value(0.0) == "neutre"
|
||||
assert StateToLanguage.interpret_value(-0.1) == "neutre"
|
||||
|
||||
def test_moderately_negative(self):
|
||||
"""Valeur moderement negative."""
|
||||
assert StateToLanguage.interpret_value(-0.35) == "peu"
|
||||
|
||||
def test_very_negative(self):
|
||||
"""Valeur tres negative."""
|
||||
assert StateToLanguage.interpret_value(-0.8) == "pas du tout"
|
||||
|
||||
|
||||
class TestBuildTranslationPrompt:
|
||||
"""Tests pour build_translation_prompt."""
|
||||
|
||||
def test_prompt_structure(self):
|
||||
"""Le prompt a la bonne structure."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
projections = {
|
||||
'epistemic': {'curiosity': 0.72, 'certainty': -0.18},
|
||||
'affective': {'enthusiasm': 0.45},
|
||||
}
|
||||
|
||||
prompt = translator.build_translation_prompt(projections, "response")
|
||||
|
||||
assert "ETAT COGNITIF" in prompt
|
||||
assert "EPISTEMIC:" in prompt
|
||||
assert "AFFECTIVE:" in prompt
|
||||
assert "curiosity" in prompt
|
||||
assert "0.72" in prompt
|
||||
assert "INSTRUCTION" in prompt
|
||||
assert "NE REFLECHIS PAS" in prompt
|
||||
|
||||
def test_prompt_output_type(self):
|
||||
"""Le type de sortie est inclus."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
prompt = translator.build_translation_prompt({}, "question")
|
||||
assert "question" in prompt
|
||||
|
||||
|
||||
class TestZeroReasoningSystemPrompt:
|
||||
"""Tests pour le system prompt zero-reasoning."""
|
||||
|
||||
def test_strict_instructions(self):
|
||||
"""Le prompt contient des instructions strictes."""
|
||||
translator = StateToLanguage()
|
||||
prompt = translator.build_zero_reasoning_system_prompt()
|
||||
|
||||
assert "NE DOIS PAS" in prompt.upper()
|
||||
assert "RAISONNER" in prompt.upper()
|
||||
assert "CODEC" in prompt.upper()
|
||||
assert "STRICT" in prompt.upper()
|
||||
|
||||
def test_no_thinking_instruction(self):
|
||||
"""Instruction explicite de ne pas generer de thinking."""
|
||||
translator = StateToLanguage()
|
||||
prompt = translator.build_zero_reasoning_system_prompt()
|
||||
|
||||
assert "<thinking>" in prompt.lower()
|
||||
|
||||
|
||||
class TestJsonSystemPrompt:
|
||||
"""Tests pour le system prompt JSON."""
|
||||
|
||||
def test_json_schema_included(self):
|
||||
"""Le schema JSON est inclus dans le prompt."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
schema = {
|
||||
"type": "object",
|
||||
"required": ["verbalization"],
|
||||
"properties": {"verbalization": {"type": "string"}},
|
||||
}
|
||||
|
||||
prompt = translator.build_json_system_prompt(schema)
|
||||
|
||||
assert "JSON" in prompt
|
||||
assert "verbalization" in prompt
|
||||
assert "UNIQUEMENT" in prompt
|
||||
|
||||
|
||||
class TestCheckReasoningMarkers:
|
||||
"""Tests pour check_reasoning_markers."""
|
||||
|
||||
def test_no_markers(self):
|
||||
"""Texte sans marqueurs."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
text = "Je suis curieux. Explorons cette idee."
|
||||
has_reasoning, markers = translator.check_reasoning_markers(text)
|
||||
|
||||
assert has_reasoning is False
|
||||
assert markers == []
|
||||
|
||||
def test_with_markers(self):
|
||||
"""Texte avec marqueurs de raisonnement."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
text = "Je pense que cette approche est interessante. Apres reflexion, je suggere..."
|
||||
has_reasoning, markers = translator.check_reasoning_markers(text)
|
||||
|
||||
assert has_reasoning is True
|
||||
assert "je pense que" in markers
|
||||
assert "apres reflexion" in markers
|
||||
|
||||
def test_case_insensitive(self):
|
||||
"""Detection insensible a la casse."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
text = "IL ME SEMBLE que c'est correct."
|
||||
has_reasoning, markers = translator.check_reasoning_markers(text)
|
||||
|
||||
assert has_reasoning is True
|
||||
assert "il me semble" in markers
|
||||
|
||||
|
||||
class TestTranslateSyncNoApi:
|
||||
"""Tests pour translate_sync (mode test sans API)."""
|
||||
|
||||
def test_translate_sync_returns_result(self):
|
||||
"""translate_sync retourne un resultat."""
|
||||
translator = StateToLanguage()
|
||||
translator.add_direction(create_random_direction("curiosity", "epistemic"))
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = translator.translate_sync(X_t, output_type="response")
|
||||
|
||||
assert isinstance(result, TranslationResult)
|
||||
assert "[RESPONSE]" in result.text.upper()
|
||||
assert result.output_type == "response"
|
||||
|
||||
def test_translate_sync_increments_count(self):
|
||||
"""translate_sync incremente le compteur."""
|
||||
translator = StateToLanguage()
|
||||
|
||||
initial_count = translator._translations_count
|
||||
|
||||
translator.translate_sync(create_random_tensor())
|
||||
translator.translate_sync(create_random_tensor())
|
||||
|
||||
assert translator._translations_count == initial_count + 2
|
||||
|
||||
|
||||
class TestTranslateAsync:
|
||||
"""Tests pour translate async avec mock."""
|
||||
|
||||
def test_translate_without_client(self):
|
||||
"""translate sans client retourne mock."""
|
||||
async def run_test():
|
||||
translator = StateToLanguage()
|
||||
translator.add_direction(create_random_direction("curiosity", "epistemic"))
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = await translator.translate(X_t)
|
||||
|
||||
assert "[MOCK TRANSLATION]" in result.text
|
||||
assert result.reasoning_detected is False
|
||||
|
||||
asyncio.run(run_test())
|
||||
|
||||
def test_translate_with_mock_client(self):
|
||||
"""translate avec client mock."""
|
||||
async def run_test():
|
||||
# Mock du client Anthropic
|
||||
mock_client = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = [MagicMock(text="Je suis curieux.")]
|
||||
mock_client.messages.create = AsyncMock(return_value=mock_response)
|
||||
|
||||
translator = StateToLanguage(anthropic_client=mock_client)
|
||||
translator.add_direction(create_random_direction("curiosity", "epistemic"))
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = await translator.translate(X_t)
|
||||
|
||||
assert result.text == "Je suis curieux."
|
||||
assert mock_client.messages.create.called
|
||||
|
||||
# Verifier les parametres d'appel
|
||||
call_kwargs = mock_client.messages.create.call_args.kwargs
|
||||
assert call_kwargs['temperature'] == 0.0
|
||||
assert call_kwargs['max_tokens'] == 500
|
||||
|
||||
asyncio.run(run_test())
|
||||
|
||||
def test_translate_detects_reasoning(self):
|
||||
"""translate detecte le raisonnement."""
|
||||
async def run_test():
|
||||
# Mock avec texte contenant du raisonnement
|
||||
mock_client = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = [MagicMock(text="Je pense que c'est interessant.")]
|
||||
mock_client.messages.create = AsyncMock(return_value=mock_response)
|
||||
|
||||
translator = StateToLanguage(anthropic_client=mock_client)
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = await translator.translate(X_t, force_zero_reasoning=True)
|
||||
|
||||
assert result.reasoning_detected is True
|
||||
|
||||
asyncio.run(run_test())
|
||||
|
||||
|
||||
class TestTranslateStructured:
|
||||
"""Tests pour translate_structured (Amendment #14)."""
|
||||
|
||||
def test_translate_structured_without_client(self):
|
||||
"""translate_structured sans client retourne mock."""
|
||||
async def run_test():
|
||||
translator = StateToLanguage()
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = await translator.translate_structured(X_t)
|
||||
|
||||
assert "[MOCK JSON TRANSLATION]" in result.text
|
||||
|
||||
asyncio.run(run_test())
|
||||
|
||||
def test_translate_structured_valid_json(self):
|
||||
"""translate_structured avec JSON valide."""
|
||||
async def run_test():
|
||||
mock_client = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = [MagicMock(text='{"verbalization": "Je suis curieux."}')]
|
||||
mock_client.messages.create = AsyncMock(return_value=mock_response)
|
||||
|
||||
translator = StateToLanguage(anthropic_client=mock_client)
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = await translator.translate_structured(X_t)
|
||||
|
||||
assert result.text == "Je suis curieux."
|
||||
assert result.json_valid is True
|
||||
|
||||
asyncio.run(run_test())
|
||||
|
||||
def test_translate_structured_extra_fields(self):
|
||||
"""translate_structured detecte les champs supplementaires."""
|
||||
async def run_test():
|
||||
mock_client = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = [MagicMock(
|
||||
text='{"verbalization": "Texte", "extra": "pas autorise"}'
|
||||
)]
|
||||
mock_client.messages.create = AsyncMock(return_value=mock_response)
|
||||
|
||||
translator = StateToLanguage(anthropic_client=mock_client)
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = await translator.translate_structured(X_t)
|
||||
|
||||
assert result.text == "Texte"
|
||||
assert result.json_valid is False
|
||||
|
||||
asyncio.run(run_test())
|
||||
|
||||
def test_translate_structured_invalid_json(self):
|
||||
"""translate_structured gere le JSON invalide."""
|
||||
async def run_test():
|
||||
mock_client = MagicMock()
|
||||
mock_response = MagicMock()
|
||||
mock_response.content = [MagicMock(text="Ceci n'est pas du JSON")]
|
||||
mock_client.messages.create = AsyncMock(return_value=mock_response)
|
||||
|
||||
translator = StateToLanguage(anthropic_client=mock_client)
|
||||
|
||||
X_t = create_random_tensor()
|
||||
result = await translator.translate_structured(X_t)
|
||||
|
||||
assert result.json_valid is False
|
||||
assert "Ceci n'est pas du JSON" in result.text
|
||||
|
||||
asyncio.run(run_test())
|
||||
|
||||
|
||||
class TestGetStats:
|
||||
"""Tests pour get_stats."""
|
||||
|
||||
def test_initial_stats(self):
|
||||
"""Stats initiales."""
|
||||
translator = StateToLanguage()
|
||||
stats = translator.get_stats()
|
||||
|
||||
assert stats['directions_count'] == 0
|
||||
assert stats['translations_count'] == 0
|
||||
assert stats['reasoning_warnings'] == 0
|
||||
|
||||
def test_stats_with_directions(self):
|
||||
"""Stats avec directions."""
|
||||
translator = StateToLanguage()
|
||||
translator.add_direction(create_random_direction("curiosity", "epistemic"))
|
||||
translator.add_direction(create_random_direction("enthusiasm", "affective"))
|
||||
|
||||
stats = translator.get_stats()
|
||||
|
||||
assert stats['directions_count'] == 2
|
||||
assert 'epistemic' in stats['categories']
|
||||
assert 'affective' in stats['categories']
|
||||
|
||||
|
||||
class TestCategoryToDimension:
|
||||
"""Tests pour le mapping category -> dimension."""
|
||||
|
||||
def test_epistemic_maps_to_firstness(self):
|
||||
"""epistemic -> firstness."""
|
||||
assert CATEGORY_TO_DIMENSION['epistemic'] == 'firstness'
|
||||
|
||||
def test_affective_maps_to_dispositions(self):
|
||||
"""affective -> dispositions."""
|
||||
assert CATEGORY_TO_DIMENSION['affective'] == 'dispositions'
|
||||
|
||||
def test_ethical_maps_to_valeurs(self):
|
||||
"""ethical -> valeurs."""
|
||||
assert CATEGORY_TO_DIMENSION['ethical'] == 'valeurs'
|
||||
|
||||
def test_all_categories_mapped(self):
|
||||
"""Toutes les categories principales sont mappees."""
|
||||
expected_categories = [
|
||||
'epistemic', 'affective', 'cognitive', 'relational',
|
||||
'ethical', 'temporal', 'thematic', 'metacognitive',
|
||||
'vital', 'ecosystemic', 'philosophical'
|
||||
]
|
||||
|
||||
for cat in expected_categories:
|
||||
assert cat in CATEGORY_TO_DIMENSION
|
||||
assert CATEGORY_TO_DIMENSION[cat] in DIMENSION_NAMES
|
||||
|
||||
|
||||
class TestReasoningMarkers:
|
||||
"""Tests pour les marqueurs de raisonnement."""
|
||||
|
||||
def test_markers_exist(self):
|
||||
"""Les marqueurs existent."""
|
||||
assert len(REASONING_MARKERS) > 0
|
||||
|
||||
def test_markers_are_lowercase(self):
|
||||
"""Les marqueurs sont en minuscules."""
|
||||
for marker in REASONING_MARKERS:
|
||||
assert marker == marker.lower()
|
||||
|
||||
|
||||
class TestCreateDirectionsFromConfig:
|
||||
"""Tests pour create_directions_from_config."""
|
||||
|
||||
def test_create_from_config(self):
|
||||
"""Creer des directions depuis une config."""
|
||||
# Mock du modele d'embedding avec embeddings distincts
|
||||
np.random.seed(42) # Pour reproductibilite
|
||||
pos_embeddings = np.random.randn(5, EMBEDDING_DIM)
|
||||
neg_embeddings = np.random.randn(5, EMBEDDING_DIM) + 1.0 # Decalage pour etre distincts
|
||||
|
||||
mock_model = MagicMock()
|
||||
# Retourner des embeddings differents pour positifs et negatifs
|
||||
mock_model.encode = MagicMock(side_effect=[pos_embeddings, neg_embeddings])
|
||||
|
||||
config = {
|
||||
"curiosity": {
|
||||
"category": "epistemic",
|
||||
"pole_positive": "curieux",
|
||||
"pole_negative": "desinteresse",
|
||||
"description": "Degre de curiosite",
|
||||
"positive_examples": ["a", "b", "c", "d", "e"],
|
||||
"negative_examples": ["f", "g", "h", "i", "j"],
|
||||
}
|
||||
}
|
||||
|
||||
directions = create_directions_from_config(config, mock_model)
|
||||
|
||||
assert len(directions) == 1
|
||||
assert directions[0].name == "curiosity"
|
||||
assert directions[0].category == "epistemic"
|
||||
assert directions[0].vector.shape == (EMBEDDING_DIM,)
|
||||
# Vecteur doit etre normalise
|
||||
assert np.isclose(np.linalg.norm(directions[0].vector), 1.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
Reference in New Issue
Block a user