import {
  readChainIndex,
  resolveChainsDir
} from "./chunk-XMHBH5H6.js";
import "./chunk-URB2WSKZ.js";
import {
  normalizeRecallTokens
} from "./chunk-DT5TVLJE.js";
import {
  log
} from "./chunk-2ODBA7MQ.js";
import {
  isRecord
} from "./chunk-DGXUHMOV.js";
import {
  listJsonFiles,
  readJsonFile
} from "./chunk-LPSF4OQH.js";
import "./chunk-PZ5AY32C.js";

// src/causal-behavior.ts
import path from "path";
function detectTopicRevisitation(trajectories, config) {
  const goalGroups = /* @__PURE__ */ new Map();
  for (const t of trajectories) {
    const tokens = normalizeRecallTokens(t.goal, []).sort().join(" ");
    if (!tokens) continue;
    const group = goalGroups.get(tokens) ?? { sessions: /* @__PURE__ */ new Set(), trajectoryIds: [], goal: t.goal };
    group.sessions.add(t.sessionKey);
    group.trajectoryIds.push(t.trajectoryId);
    goalGroups.set(tokens, group);
  }
  const signals = [];
  for (const [_key, group] of goalGroups) {
    if (group.trajectoryIds.length < config.minFrequency) continue;
    if (group.sessions.size < config.minSessions) continue;
    signals.push({
      signalType: "topic_revisitation",
      pattern: group.goal,
      frequency: group.trajectoryIds.length,
      sessionCount: group.sessions.size,
      confidence: Math.min(1, 0.5 + group.sessions.size / 10),
      trajectoryIds: group.trajectoryIds.slice(0, 10)
    });
  }
  return signals;
}
function detectActionPatterns(trajectories, config) {
  const actionGroups = /* @__PURE__ */ new Map();
  for (const t of trajectories) {
    const tokens = normalizeRecallTokens(t.actionSummary, []).sort().join(" ");
    if (!tokens) continue;
    const group = actionGroups.get(tokens) ?? {
      sessions: /* @__PURE__ */ new Set(),
      trajectoryIds: [],
      action: t.actionSummary,
      successCount: 0,
      totalCount: 0
    };
    group.sessions.add(t.sessionKey);
    group.trajectoryIds.push(t.trajectoryId);
    group.totalCount++;
    if (t.outcomeKind === "success") group.successCount++;
    actionGroups.set(tokens, group);
  }
  const signals = [];
  for (const [_key, group] of actionGroups) {
    if (group.totalCount < Math.max(config.minFrequency, 4)) continue;
    if (group.sessions.size < config.minSessions) continue;
    const successRate = group.successCount / group.totalCount;
    if (successRate < 0.8) continue;
    signals.push({
      signalType: "action_pattern",
      pattern: group.action,
      frequency: group.totalCount,
      sessionCount: group.sessions.size,
      confidence: Math.min(1, 0.6 + successRate * 0.3),
      trajectoryIds: group.trajectoryIds.slice(0, 10)
    });
  }
  return signals;
}
function detectOutcomePreferences(trajectories, chainIndex, config) {
  const retrySuccesses = /* @__PURE__ */ new Map();
  const trajectoryMap = new Map(trajectories.map((t) => [t.trajectoryId, t]));
  for (const [edgeId, edge] of Object.entries(chainIndex.edges)) {
    if (edge.edgeType !== "retry") continue;
    const from = trajectoryMap.get(edge.fromTrajectoryId);
    const to = trajectoryMap.get(edge.toTrajectoryId);
    if (!from || !to) continue;
    if (from.outcomeKind !== "failure" || to.outcomeKind !== "success") continue;
    const goalTokens = normalizeRecallTokens(from.goal, []).sort().join(" ");
    const group = retrySuccesses.get(goalTokens) ?? {
      sessions: /* @__PURE__ */ new Set(),
      trajectoryIds: [],
      goal: from.goal,
      count: 0
    };
    group.sessions.add(from.sessionKey);
    group.sessions.add(to.sessionKey);
    group.trajectoryIds.push(from.trajectoryId, to.trajectoryId);
    group.count++;
    retrySuccesses.set(goalTokens, group);
  }
  const signals = [];
  for (const [_key, group] of retrySuccesses) {
    if (group.count < config.minFrequency) continue;
    if (group.sessions.size < config.minSessions) continue;
    signals.push({
      signalType: "outcome_preference",
      pattern: group.goal,
      frequency: group.count,
      sessionCount: group.sessions.size,
      confidence: Math.min(1, 0.7 + group.count / 20),
      trajectoryIds: [...new Set(group.trajectoryIds)].slice(0, 10)
    });
  }
  return signals;
}
function synthesizeCausalPreferences(signals, confidenceThreshold) {
  const preferences = [];
  for (const signal of signals) {
    if (signal.confidence < confidenceThreshold) continue;
    let statement;
    switch (signal.signalType) {
      case "topic_revisitation":
        statement = `The user frequently works on: ${signal.pattern}. This topic has been revisited across ${signal.sessionCount} sessions.`;
        break;
      case "action_pattern":
        statement = `The user prefers this approach: ${signal.pattern}. This action pattern has been successful ${signal.frequency} times.`;
        break;
      case "outcome_preference":
        statement = `The user persistently pursues: ${signal.pattern}. They retry until successful, indicating strong preference.`;
        break;
      case "phrasing_style":
        statement = `The user's phrasing pattern: ${signal.pattern}`;
        break;
    }
    preferences.push({
      statement,
      sourceIds: signal.trajectoryIds.slice(0, 5),
      category: "preference",
      confidence: signal.confidence,
      keywords: normalizeRecallTokens(signal.pattern, []).slice(0, 10)
    });
  }
  return preferences;
}
function computeCausalImpactScore(memoryId, chainIndex) {
  const incoming = chainIndex.incoming[memoryId]?.length ?? 0;
  const outgoing = chainIndex.outgoing[memoryId]?.length ?? 0;
  const raw = 0.1 * incoming + 0.15 * outgoing;
  return Math.min(0.3, Math.max(0, raw));
}
async function extractCausalBehaviorSignals(options) {
  try {
    const { memoryDir, causalTrajectoryStoreDir, config: behaviorConfig } = options;
    const root = causalTrajectoryStoreDir ? path.join(memoryDir, causalTrajectoryStoreDir) : path.join(memoryDir, "state", "causal-trajectories");
    const trajectoriesDir = path.join(root, "trajectories");
    const files = await listJsonFiles(trajectoriesDir).catch(() => []);
    const trajectories = [];
    for (const filePath of files) {
      try {
        const raw = await readJsonFile(filePath);
        if (isRecord(raw) && typeof raw.trajectoryId === "string") {
          trajectories.push(raw);
        }
      } catch {
      }
    }
    if (trajectories.length === 0) return [];
    const chainsDir = resolveChainsDir(memoryDir, causalTrajectoryStoreDir);
    const chainIndex = await readChainIndex(chainsDir);
    const signals = [
      ...detectTopicRevisitation(trajectories, behaviorConfig),
      ...detectActionPatterns(trajectories, behaviorConfig),
      ...detectOutcomePreferences(trajectories, chainIndex, behaviorConfig)
    ];
    log.debug(`[cmc] extracted ${signals.length} behavioral signal(s) from ${trajectories.length} trajectories`);
    return signals;
  } catch (error) {
    log.warn(`[cmc] behavioral signal extraction failed (non-fatal): ${error instanceof Error ? error.message : String(error)}`);
    return [];
  }
}
export {
  computeCausalImpactScore,
  extractCausalBehaviorSignals,
  synthesizeCausalPreferences
};
//# sourceMappingURL=causal-behavior.js.map