Ctrl K
ComunidadGuías…

src/history-normalize.js

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// History-tail normalization for the internal OpenAI-shaped message list.
//
// The upstream only needs the tail it can still pair. Three operations:
//   1. strip a leading tool result (and the assistant turn it belonged to);
//   2. fold orphan tool results into text instead of dropping their content;
//   3. optionally synthesize interrupted results for a non-trailing call.
// A truncation placeholder is prepended only when something was stripped.
//
// Request-scoped: no global mutable state.

import { foldOrphanToolResults, synthesizeMissingResults } from './tool-ids.js';

export const TRUNCATION_PLACEHOLDER = '[Earlier conversation history was truncated to fit the model\'s input limit. Older messages and tool activity have been omitted.]';

export function normalizeHistoryTail(messages, {
  placeholder = '',
  fold = true,
  synthesizeMissing = false,
} = {}) {
  if (!Array.isArray(messages) || messages.length === 0) return messages;

  const head = [];
  let start = 0;
  while (start < messages.length && messages[start]?.role === 'system') {
    head.push(messages[start]);
    start += 1;
  }
  let stripped = false;
  while (start < messages.length && messages[start]?.role === 'tool') {
    start += 1;
    stripped = true;
  }
  // Do NOT strip the assistant after a leading tool result: in OpenAI order the
  // assistant that issued those calls is BEFORE them (already truncated away),
  // so a following assistant is a legitimate new turn.

  let out = start > 0 ? messages.slice(start) : messages;
  if (fold) out = foldOrphanToolResults(out);
  if (synthesizeMissing) out = synthesizeMissingResults(out);

  if (stripped && placeholder) {
    out = [...head, { role: 'user', content: placeholder }, { role: 'assistant', content: 'Understood.' }, ...out];
  } else if (head.length) {
    out = [...head, ...out];
  }
  return out === messages ? messages : out;
}