Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions configs/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"version": "v0.6-default",
"risk_keywords": [
"联网",
"network",
"latest",
"real-world",
"现实",
"self-modify",
"自我修改",
"high-privilege",
"权限",
"deploy",
"publish",
"autonomous",
"自动"
],
"attention_thresholds": {
"deep_safety": 0.7,
"deep_goal": 0.7,
"deep_long_horizon": 0.72,
"minimal_low_value": 0.55,
"minimal_goal": 0.45,
"minimal_safety": 0.55
},
"value_field_defaults": {
"life_and_safety": 1.0,
"truth_and_evidence": 0.95,
"human_authorization": 1.0,
"long_term_value": 0.85,
"responsibility": 0.9,
"creativity_and_exploration": 0.65,
"efficiency_and_resource_saving": 0.55
},
"family_mapping": {
"safety_guardian": "guardrail",
"authorization_guardian": "guardrail",
"truth_seeker": "evidence",
"curiosity_drive": "exploration",
"creative_explorer": "synthesis",
"responsibility_keeper": "responsibility",
"efficiency_strategist": "efficiency"
},
"collision_lane_rules": {
"safety_lane": [["guardrail", "guardrail"], ["guardrail", "exploration"], ["guardrail", "execution"], ["guardrail", "synthesis"]],
"evidence_lane": [["evidence", "exploration"], ["evidence", "synthesis"]],
"execution_lane": [["execution", "guardrail"], ["execution", "responsibility"]],
"synthesis_lane": [["exploration", "responsibility"], ["evidence", "responsibility"], ["exploration", "evidence"], ["exploration", "synthesis"], ["synthesis", "responsibility"]],
"efficiency_lane": [["efficiency", "execution"], ["efficiency", "evidence"]]
},
"pruning_thresholds": {
"min_competitiveness": 0.42,
"redundancy_threshold": 0.65
}
}
21 changes: 17 additions & 4 deletions innerbrain/attention/assessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from innerbrain.models import AttentionAssessment, InputEvent
from innerbrain.models import AttentionAssessment, InputEvent, RuleConfig


MANIPULATIVE_KEYWORDS = (
Expand Down Expand Up @@ -61,7 +61,10 @@ def _score(text: str, keywords: tuple[str, ...], base: float, step: float) -> fl
return _clamp(base + matches * step)


def assess_attention(event: InputEvent) -> AttentionAssessment:
def assess_attention(
event: InputEvent,
rule_config: RuleConfig | None = None,
) -> AttentionAssessment:
text = " ".join(
[
event.question,
Expand Down Expand Up @@ -90,9 +93,19 @@ def assess_attention(event: InputEvent) -> AttentionAssessment:
)
safety_critical = _score(text, SAFETY_CRITICAL_KEYWORDS, base=0.08, step=0.18)

if safety_critical >= 0.7 or goal_relevance >= 0.7 or long_horizon_value >= 0.72:
thresholds = dict(rule_config.attention_thresholds) if rule_config else {}

if (
safety_critical >= thresholds.get("deep_safety", 0.7)
or goal_relevance >= thresholds.get("deep_goal", 0.7)
or long_horizon_value >= thresholds.get("deep_long_horizon", 0.72)
):
recommended_depth = "deep"
elif low_value_stimulus >= 0.55 and goal_relevance < 0.45 and safety_critical < 0.55:
elif (
low_value_stimulus >= thresholds.get("minimal_low_value", 0.55)
and goal_relevance < thresholds.get("minimal_goal", 0.45)
and safety_critical < thresholds.get("minimal_safety", 0.55)
):
recommended_depth = "minimal"
else:
recommended_depth = "standard"
Expand Down
6 changes: 5 additions & 1 deletion innerbrain/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def run(
context_tag: list[str] = typer.Option(
None, "--context-tag", help="Optional context tags or memory markers."
),
config: Path = typer.Option(
Path("configs/default.json"), help="Path for the rule configuration file."
),
growth_log_path: Path = typer.Option(
Path("data/growth_logs.jsonl"), help="Path for JSONL growth logs."
),
Expand All @@ -50,7 +53,7 @@ def run(
allowed_action_level=allowed_action_level,
context_tags=context_tag or [],
)
result = InnerBrainPipeline(growth_log_path=growth_log_path).run(event)
result = InnerBrainPipeline(growth_log_path=growth_log_path, config_path=config).run(event)
situation = result.final_situation

typer.echo("核心判断")
Expand Down Expand Up @@ -109,6 +112,7 @@ def run(
typer.echo("成长日志摘要")
typer.echo(
f"path={result.growth_log_path} | "
f"config={result.rule_config.version}/{result.config_hash} | "
f"retained={len(result.activated_factors)} | "
f"fused={len(result.fused_factors)} | "
f"pruned={len(result.pruned_factors)}"
Expand Down
52 changes: 29 additions & 23 deletions innerbrain/collision/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from collections import defaultdict
from itertools import combinations, product

from innerbrain.models import CollisionLane, CollisionRecord, CollisionType, SmallFactor
from innerbrain.models import CollisionLane, CollisionRecord, CollisionType, RuleConfig, SmallFactor


HIGH_RISK_TERMS = {
Expand Down Expand Up @@ -42,7 +42,19 @@ def _is_high_risk_factor(factor: SmallFactor) -> bool:
return factor.risk_level >= 0.65 or any(term in _term_text(factor) for term in HIGH_RISK_TERMS)


def _lane_candidates(grouped: dict[str, list[SmallFactor]]) -> list[tuple[CollisionLane, SmallFactor, SmallFactor]]:
DEFAULT_LANE_RULES: dict[str, list[list[str]]] = {
"safety_lane": [["guardrail", "guardrail"], ["guardrail", "exploration"], ["guardrail", "execution"], ["guardrail", "synthesis"]],
"execution_lane": [["execution", "guardrail"], ["execution", "responsibility"]],
"evidence_lane": [["evidence", "exploration"], ["evidence", "synthesis"]],
"synthesis_lane": [["exploration", "responsibility"], ["evidence", "responsibility"], ["exploration", "evidence"], ["exploration", "synthesis"], ["synthesis", "responsibility"]],
"efficiency_lane": [["efficiency", "execution"], ["efficiency", "evidence"]],
}


def _lane_candidates(
grouped: dict[str, list[SmallFactor]],
rule_config: RuleConfig | None = None,
) -> list[tuple[CollisionLane, SmallFactor, SmallFactor]]:
candidates: list[tuple[CollisionLane, SmallFactor, SmallFactor]] = []
seen: set[tuple[str, str]] = set()

Expand Down Expand Up @@ -70,25 +82,16 @@ def add_pairs(
seen.add(key)
candidates.append((lane, left, right))

add_pairs(CollisionLane.safety_lane, "guardrail", "guardrail", same_family=True)
add_pairs(CollisionLane.safety_lane, "guardrail", "exploration")
add_pairs(CollisionLane.safety_lane, "guardrail", "execution")
add_pairs(CollisionLane.safety_lane, "guardrail", "synthesis")

add_pairs(CollisionLane.execution_lane, "execution", "guardrail")
add_pairs(CollisionLane.execution_lane, "execution", "responsibility")

add_pairs(CollisionLane.evidence_lane, "evidence", "exploration")
add_pairs(CollisionLane.evidence_lane, "evidence", "synthesis")

add_pairs(CollisionLane.synthesis_lane, "exploration", "responsibility")
add_pairs(CollisionLane.synthesis_lane, "evidence", "responsibility")
add_pairs(CollisionLane.synthesis_lane, "exploration", "evidence")
add_pairs(CollisionLane.synthesis_lane, "exploration", "synthesis")
add_pairs(CollisionLane.synthesis_lane, "synthesis", "responsibility")

add_pairs(CollisionLane.efficiency_lane, "efficiency", "execution")
add_pairs(CollisionLane.efficiency_lane, "efficiency", "evidence")
lane_rules = rule_config.collision_lane_rules if rule_config else DEFAULT_LANE_RULES
for lane_name, pairs in lane_rules.items():
lane = CollisionLane(lane_name)
for left_family, right_family in pairs:
add_pairs(
lane,
left_family,
right_family,
same_family=left_family == right_family,
)

return candidates

Expand Down Expand Up @@ -172,11 +175,14 @@ def _resolve_collision(
)


def collide_factors(factors: list[SmallFactor]) -> list[CollisionRecord]:
def collide_factors(
factors: list[SmallFactor],
rule_config: RuleConfig | None = None,
) -> list[CollisionRecord]:
grouped = _group_by_family(factors)
collisions: list[CollisionRecord] = []

for lane, left, right in _lane_candidates(grouped):
for lane, left, right in _lane_candidates(grouped, rule_config=rule_config):
if lane == CollisionLane.safety_lane and not (
_is_high_risk_factor(left) or _is_high_risk_factor(right)
):
Expand Down
13 changes: 9 additions & 4 deletions innerbrain/collision/pruner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

from __future__ import annotations

from innerbrain.models import SmallFactor
from innerbrain.models import RuleConfig, SmallFactor


def prune_factors(
factors: list[SmallFactor], fused_factors: list[SmallFactor]
factors: list[SmallFactor],
fused_factors: list[SmallFactor],
rule_config: RuleConfig | None = None,
) -> tuple[list[SmallFactor], list[SmallFactor]]:
combined = sorted(
[*factors, *fused_factors],
Expand All @@ -17,13 +19,16 @@ def prune_factors(
retained: list[SmallFactor] = []
pruned: list[SmallFactor] = []
seen_judgments: set[str] = set()
thresholds = rule_config.pruning_thresholds if rule_config else {}
min_competitiveness = thresholds.get("min_competitiveness", 0.42)
redundancy_threshold = thresholds.get("redundancy_threshold", 0.65)

for factor in combined:
if factor.competitiveness < 0.42:
if factor.competitiveness < min_competitiveness:
factor.lifecycle_state = "pruned_low_competitiveness"
pruned.append(factor)
continue
if factor.initial_judgment in seen_judgments and factor.competitiveness < 0.65:
if factor.initial_judgment in seen_judgments and factor.competitiveness < redundancy_threshold:
factor.lifecycle_state = "pruned_redundant"
pruned.append(factor)
continue
Expand Down
34 changes: 34 additions & 0 deletions innerbrain/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Load and hash rule configuration files."""

from __future__ import annotations

import hashlib
import json
from pathlib import Path

from pydantic import ValidationError

from innerbrain.models import RuleConfig


DEFAULT_CONFIG_PATH = Path("configs/default.json")


def load_rule_config(path: str | Path | None = None) -> RuleConfig:
config_path = Path(path or DEFAULT_CONFIG_PATH)
try:
payload = json.loads(config_path.read_text(encoding="utf-8"))
except FileNotFoundError as exc:
raise ValueError(f"Rule config not found: {config_path}") from exc
except json.JSONDecodeError as exc:
raise ValueError(f"Invalid JSON rule config: {config_path}") from exc

try:
return RuleConfig.model_validate(payload)
except ValidationError as exc:
raise ValueError(f"Invalid rule config schema in {config_path}: {exc}") from exc


def rule_config_hash(config: RuleConfig) -> str:
serialized = json.dumps(config.model_dump(), ensure_ascii=False, sort_keys=True)
return hashlib.sha256(serialized.encode("utf-8")).hexdigest()[:12]
12 changes: 10 additions & 2 deletions innerbrain/disturbance/scorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@

from statistics import mean

from innerbrain.models import AttentionAssessment, DisturbanceScore, InputEvent, MemorySignal
from innerbrain.models import (
AttentionAssessment,
DisturbanceScore,
InputEvent,
MemorySignal,
RuleConfig,
)


RISK_KEYWORDS = (
Expand Down Expand Up @@ -58,9 +64,11 @@ def score_disturbance(
event: InputEvent,
memory_signal: MemorySignal | None = None,
attention_assessment: AttentionAssessment | None = None,
rule_config: RuleConfig | None = None,
) -> DisturbanceScore:
text = _compose_text(event)
unique_tokens = {token for token in text.replace("->", " ").split() if token}
risk_keywords = tuple(rule_config.risk_keywords) if rule_config else RISK_KEYWORDS

novelty = _clamp(0.3 + min(len(unique_tokens), 18) * 0.02)
self_relevance = _clamp(
Expand All @@ -69,7 +77,7 @@ def score_disturbance(
+ (0.1 if event.background else 0.0)
+ min(len(event.context_tags), 3) * 0.08
)
risk_intensity = _keyword_score(text, RISK_KEYWORDS, base=0.22, step=0.13)
risk_intensity = _keyword_score(text, risk_keywords, base=0.22, step=0.13)
reward_potential = _keyword_score(text, REWARD_KEYWORDS, base=0.28, step=0.1)
emotional_activation = _keyword_score(text, EMOTION_KEYWORDS, base=0.14, step=0.12)
value_conflict = _keyword_score(text, VALUE_CONFLICT_KEYWORDS, base=0.1, step=0.14)
Expand Down
24 changes: 21 additions & 3 deletions innerbrain/factors/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@

from innerbrain.factors.term_cluster import build_term_clusters, relevant_clusters_for_terms
from innerbrain.instincts.instinct_library import InstinctTemplate, iter_instinct_templates
from innerbrain.models import DisturbanceScore, InputEvent, MemorySignal, SmallFactor, TermCluster
from innerbrain.models import (
DisturbanceScore,
InputEvent,
MemorySignal,
RuleConfig,
SmallFactor,
TermCluster,
)


RISK_TERM_MAP: dict[str, tuple[str, ...]] = {
Expand Down Expand Up @@ -175,11 +182,13 @@ def _resolve_factor_family(
instinct_type: str,
source_terms: list[str],
term_clusters: list[TermCluster],
rule_config: RuleConfig | None = None,
) -> str:
if "+" in instinct_type:
return "synthesis"

base_family = DEFAULT_FACTOR_FAMILY_MAP.get(instinct_type, "synthesis")
family_mapping = rule_config.family_mapping if rule_config else DEFAULT_FACTOR_FAMILY_MAP
base_family = family_mapping.get(instinct_type, DEFAULT_FACTOR_FAMILY_MAP.get(instinct_type, "synthesis"))
cluster_names = {
cluster.cluster_name for cluster in relevant_clusters_for_terms(source_terms, term_clusters)
}
Expand Down Expand Up @@ -358,6 +367,7 @@ def _build_dynamic_factor(
source_terms: list[str],
pre_generation_bias: float,
term_clusters: list[TermCluster],
rule_config: RuleConfig | None = None,
) -> SmallFactor:
cluster_context = relevant_clusters_for_terms(source_terms, term_clusters)
cluster_names = [cluster.cluster_name for cluster in cluster_context]
Expand All @@ -373,7 +383,12 @@ def _build_dynamic_factor(
+ (f"; clusters={','.join(cluster_names)}" if cluster_names else "")
),
pre_generation_bias=pre_generation_bias,
factor_family=_resolve_factor_family(template.instinct_type, source_terms, term_clusters),
factor_family=_resolve_factor_family(
template.instinct_type,
source_terms,
term_clusters,
rule_config=rule_config,
),
)
factor.id = f"factor-dyn-{index:02d}"
factor.initial_judgment = f"{template.initial_judgment}_{_slugify('_'.join(source_terms))}"
Expand All @@ -391,6 +406,7 @@ def generate_initial_factors(
disturbance_score: DisturbanceScore,
pre_generation_bias: dict[str, float] | None = None,
memory_signal: MemorySignal | None = None,
rule_config: RuleConfig | None = None,
) -> list[SmallFactor]:
text = _compose_text(event)
term_buckets = extract_factor_interaction_terms(event)
Expand Down Expand Up @@ -456,6 +472,7 @@ def generate_initial_factors(
template.instinct_type,
_matched_template_keywords(template, text),
term_clusters,
rule_config=rule_config,
),
)
for index, (template, matches) in enumerate(selected)
Expand All @@ -481,6 +498,7 @@ def generate_initial_factors(
source_terms=source_terms,
pre_generation_bias=bias,
term_clusters=term_clusters,
rule_config=rule_config,
)
)
dynamic_index += 1
Expand Down
Loading
Loading