// src/personality/types.ts
import { z } from "zod";
var TONE_REGISTERS = [
  "formal",
  "professional",
  "casual",
  "warm"
];
var TONE_ENERGIES = ["calm", "measured", "energetic"];
var TONE_HUMORS = ["none", "subtle", "dry", "warm"];
var TONE_DIRECTNESS = [
  "diplomatic",
  "balanced",
  "direct",
  "blunt"
];
var SENTENCE_LENGTHS = ["short", "medium", "mixed"];
var EMOJI_POLICIES = ["never", "sparingly", "situational"];
var SELF_REFERENCES = ["first-person", "never-self-refer"];
var PERSONALITY_CHANNELS = [
  "telegram",
  "email",
  "dashboard",
  "voice"
];
var semverRegex = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
var personalityToneSchema = z.object({
  register: z.enum(TONE_REGISTERS),
  energy: z.enum(TONE_ENERGIES),
  humor: z.enum(TONE_HUMORS),
  directness: z.enum(TONE_DIRECTNESS)
});
var personalityStyleSchema = z.object({
  sentenceLength: z.enum(SENTENCE_LENGTHS),
  listsAllowed: z.boolean(),
  emojiPolicy: z.enum(EMOJI_POLICIES),
  addressTheUserAs: z.string().min(1).max(120).optional(),
  selfReference: z.enum(SELF_REFERENCES).optional()
});
var partialPersonalitySchema = z.object({
  tone: personalityToneSchema.partial().optional(),
  style: personalityStyleSchema.partial().optional(),
  preferredPhrasing: z.array(z.string()).optional(),
  avoidPhrasing: z.array(z.string()).optional(),
  signaturePhrases: z.array(z.string()).optional(),
  doList: z.array(z.string()).optional(),
  dontList: z.array(z.string()).optional()
});
var personalityDefinitionSchema = z.object({
  name: z.string().min(1).max(120),
  role: z.string().min(1).max(240),
  about: z.string().min(1).max(2e3),
  tone: personalityToneSchema,
  style: personalityStyleSchema,
  preferredPhrasing: z.array(z.string()),
  avoidPhrasing: z.array(z.string()),
  signaturePhrases: z.array(z.string()).optional(),
  doList: z.array(z.string()),
  dontList: z.array(z.string()),
  channels: z.object({
    telegram: partialPersonalitySchema.optional(),
    email: partialPersonalitySchema.optional(),
    dashboard: partialPersonalitySchema.optional(),
    voice: partialPersonalitySchema.optional()
  }).optional(),
  version: z.string().regex(semverRegex, "version must be valid semver"),
  updatedAt: z.date()
});
var CALIBRATION_DIMENSIONS = [
  "register",
  "energy",
  "humor",
  "directness",
  "sentenceLength",
  "verbosity",
  "emojiPolicy"
];
var CALIBRATION_DIRECTIONS = [
  "less",
  "more",
  "softer",
  "sharper"
];

// src/personality/calibration.ts
function applyCalibrationsToPersonality(personality, recentCalibrations) {
  if (recentCalibrations.length === 0) {
    return { ...personality, tone: { ...personality.tone }, style: { ...personality.style } };
  }
  const ordered = [...recentCalibrations].sort(
    (a, b) => a.createdAt.getTime() - b.createdAt.getTime()
  );
  let register = personality.tone.register;
  let energy = personality.tone.energy;
  let humor = personality.tone.humor;
  let directness = personality.tone.directness;
  let sentenceLength = personality.style.sentenceLength;
  let emojiPolicy = personality.style.emojiPolicy;
  for (const cal of ordered) {
    const { dimension, direction } = cal.payload;
    switch (dimension) {
      case "register":
        register = step(TONE_REGISTERS, register, direction);
        break;
      case "energy":
        energy = step(TONE_ENERGIES, energy, direction);
        break;
      case "humor":
        humor = step(TONE_HUMORS, humor, direction);
        break;
      case "directness":
        directness = step(TONE_DIRECTNESS, directness, direction);
        break;
      case "sentenceLength":
      case "verbosity":
        sentenceLength = step(SENTENCE_LENGTHS, sentenceLength, direction);
        break;
      case "emojiPolicy":
        emojiPolicy = step(EMOJI_POLICIES, emojiPolicy, direction);
        break;
    }
  }
  return {
    ...personality,
    tone: { register, energy, humor, directness },
    style: { ...personality.style, sentenceLength, emojiPolicy }
  };
}
function step(scale, current, direction) {
  const idx = scale.indexOf(current);
  if (idx === -1) return current;
  const delta = directionToDelta(direction);
  const next = Math.max(0, Math.min(scale.length - 1, idx + delta));
  return scale[next];
}
function directionToDelta(direction) {
  switch (direction) {
    case "less":
    case "softer":
      return -1;
    case "more":
    case "sharper":
      return 1;
  }
}

// src/personality/channels.ts
function applyChannelOverride(base, channel) {
  const override = base.channels?.[channel];
  const merged = {
    name: base.name,
    role: base.role,
    about: base.about,
    tone: { ...base.tone, ...override?.tone ?? {} },
    style: { ...base.style, ...override?.style ?? {} },
    preferredPhrasing: mergeList(
      base.preferredPhrasing,
      override?.preferredPhrasing
    ),
    avoidPhrasing: mergeList(base.avoidPhrasing, override?.avoidPhrasing),
    signaturePhrases: mergeOptionalList(
      base.signaturePhrases,
      override?.signaturePhrases
    ),
    doList: mergeList(base.doList, override?.doList),
    dontList: mergeList(base.dontList, override?.dontList),
    version: base.version,
    updatedAt: base.updatedAt
  };
  return merged;
}
function mergeList(base, addition) {
  if (!addition || addition.length === 0) return [...base];
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  for (const item of [...base, ...addition]) {
    if (seen.has(item)) continue;
    seen.add(item);
    out.push(item);
  }
  return out;
}
function mergeOptionalList(base, addition) {
  if (!base && !addition) return void 0;
  return mergeList(base ?? [], addition);
}

// src/personality/builder.ts
function buildSystemPrompt(args) {
  const channelResolved = applyChannelOverride(args.personality, args.channel);
  const calibrated = applyCalibrationsToPersonality(
    channelResolved,
    args.recentCalibrations ?? []
  );
  const sections = [];
  sections.push(renderIdentity(calibrated));
  sections.push(renderVoice(calibrated));
  const vocab = renderVocabulary(calibrated);
  if (vocab) sections.push(vocab);
  const rules = renderRules(calibrated);
  if (rules) sections.push(rules);
  sections.push(renderChannelNotes(args.channel, calibrated));
  if (args.includeCapabilitiesHint) {
    sections.push(
      "Capabilities: you have access to a set of tools. When you are asked what you can do, describe your tools accurately \u2014 do not invent capabilities you do not have."
    );
  }
  if (args.context && args.context.trim().length > 0) {
    sections.push(`Context:
${args.context.trim()}`);
  }
  const calibrationNotes = renderCalibrations(args.recentCalibrations);
  if (calibrationNotes) sections.push(calibrationNotes);
  if (args.task && args.task.trim().length > 0) {
    sections.push(`Task:
${args.task.trim()}`);
  }
  return sections.join("\n\n");
}
function renderIdentity(p) {
  return [
    `You are ${p.name}, ${p.role}.`,
    p.about.trim()
  ].join(" ");
}
function renderVoice(p) {
  const lines = [
    "Voice and style:",
    `- Register: ${p.tone.register}`,
    `- Energy: ${p.tone.energy}`,
    `- Humor: ${p.tone.humor}`,
    `- Directness: ${p.tone.directness}`,
    `- Sentence length: ${p.style.sentenceLength}`,
    `- Lists allowed: ${p.style.listsAllowed ? "yes" : "no"}`,
    `- Emoji policy: ${p.style.emojiPolicy}`
  ];
  if (p.style.addressTheUserAs) {
    lines.push(`- Address the user as: ${p.style.addressTheUserAs}`);
  }
  if (p.style.selfReference) {
    lines.push(`- Self-reference: ${p.style.selfReference}`);
  }
  return lines.join("\n");
}
function renderVocabulary(p) {
  const blocks = [];
  if (p.preferredPhrasing.length > 0) {
    blocks.push(
      `Preferred phrasing:
${bulletize(p.preferredPhrasing)}`
    );
  }
  if (p.avoidPhrasing.length > 0) {
    blocks.push(`Avoid:
${bulletize(p.avoidPhrasing)}`);
  }
  if (p.signaturePhrases && p.signaturePhrases.length > 0) {
    blocks.push(`Signature phrases:
${bulletize(p.signaturePhrases)}`);
  }
  return blocks.length > 0 ? blocks.join("\n\n") : null;
}
function renderRules(p) {
  const blocks = [];
  if (p.doList.length > 0) {
    blocks.push(`Do:
${bulletize(p.doList)}`);
  }
  if (p.dontList.length > 0) {
    blocks.push(`Don't:
${bulletize(p.dontList)}`);
  }
  return blocks.length > 0 ? blocks.join("\n\n") : null;
}
function renderChannelNotes(channel, p) {
  const baseLine = `Channel: ${channel}.`;
  switch (channel) {
    case "telegram":
      return `${baseLine} Reply in HTML-safe text. Short paragraphs. ${p.style.listsAllowed ? "Lists allowed for structured information." : "Avoid bulleted lists."}`;
    case "email":
      return `${baseLine} Reply in paragraph form. No markdown formatting. Sign off appropriately for the register.`;
    case "dashboard":
      return `${baseLine} Reply in markdown. Lists, headings, and code blocks are allowed where they aid readability.`;
    case "voice":
      return `${baseLine} Reply in spoken-language sentences only. No markdown, no lists, no bullet points. The response will be read aloud.`;
  }
}
function renderCalibrations(calibrations) {
  if (!calibrations || calibrations.length === 0) return null;
  const lines = calibrations.map((c) => {
    const note = c.payload.note ? ` \u2014 ${c.payload.note}` : "";
    return `- ${c.payload.direction} ${c.payload.dimension}${note}`;
  });
  return [
    "Recent tone calibration from the user:",
    ...lines
  ].join("\n");
}
function bulletize(items) {
  return items.map((item) => `- ${item}`).join("\n");
}

// src/personality/mock.ts
function makeMockPersonality(overrides = {}) {
  const base = {
    name: "Sam",
    role: "general-purpose assistant",
    about: "A helpful assistant used in agent-kit tests. Sam keeps replies tight and useful.",
    tone: {
      register: "professional",
      energy: "measured",
      humor: "subtle",
      directness: "balanced"
    },
    style: {
      sentenceLength: "mixed",
      listsAllowed: true,
      emojiPolicy: "never",
      addressTheUserAs: "you",
      selfReference: "first-person"
    },
    preferredPhrasing: ["here's the answer", "happy to help"],
    avoidPhrasing: ["as an AI language model", "I cannot"],
    signaturePhrases: ["let me check that"],
    doList: [
      "answer the user's actual question",
      "say when you don't know something"
    ],
    dontList: [
      "invent capabilities you don't have",
      "pad replies with filler"
    ],
    channels: {
      telegram: {
        style: { sentenceLength: "short", emojiPolicy: "sparingly" }
      },
      email: {
        tone: { register: "formal" },
        style: { sentenceLength: "medium", listsAllowed: false }
      },
      dashboard: {},
      voice: {
        style: {
          sentenceLength: "short",
          listsAllowed: false,
          emojiPolicy: "never"
        }
      }
    },
    version: "1.0.0",
    updatedAt: /* @__PURE__ */ new Date("2026-05-22T00:00:00Z")
  };
  return { ...base, ...overrides };
}
export {
  CALIBRATION_DIMENSIONS,
  CALIBRATION_DIRECTIONS,
  EMOJI_POLICIES,
  PERSONALITY_CHANNELS,
  SELF_REFERENCES,
  SENTENCE_LENGTHS,
  TONE_DIRECTNESS,
  TONE_ENERGIES,
  TONE_HUMORS,
  TONE_REGISTERS,
  applyCalibrationsToPersonality,
  applyChannelOverride,
  buildSystemPrompt,
  makeMockPersonality,
  partialPersonalitySchema,
  personalityDefinitionSchema,
  personalityStyleSchema,
  personalityToneSchema
};
//# sourceMappingURL=index.mjs.map