Z ZPI 文档 v0.3.8
介绍页

源码

packages/coding-agent/src/core/session-state.ts

typescript69 行查看原文
import type { ThinkingLevel } from "@zpi-dev/agent";
import type { ContextBreakdownItem, Model } from "@zpi-dev/ai";
import { thinkingChoices } from "@zpi-dev/ai";
import type { SessionEntry } from "./session-manager.ts";

export interface ContextUsage {
  /** Engine estimate of the current effective context, including trailing messages. */
  estimatedTokens?: number;
  estimateSource?: "local" | "server usage + local";
  compaction?: { enabled: boolean; reserveTokens: number; threshold: number; compacted: boolean };
  contextWindow: number;
  inputTokens: number | null;
  percent: number | null;
  timestamp: number | null;
  source: "server usage" | "unknown";
  breakdown?: ContextBreakdownItem[];
  averageCacheHitRate?: number | null;
}
export function contextUsage(entries: SessionEntry[], model: Model): ContextUsage {
  const result: ContextUsage = {
    contextWindow: model.contextWindow,
    inputTokens: null,
    percent: null,
    timestamp: null,
    source: "unknown",
  };
  let cacheRead = 0,
    totalInput = 0;
  for (const entry of entries) {
    if (entry.type === "compaction" || entry.type === "model_change") {
      cacheRead = 0;
      totalInput = 0;
    }
    if (entry.type !== "message" || entry.message.role !== "assistant") continue;
    const m = entry.message;
    if (
      m.model !== model.id ||
      m.provider !== model.provider ||
      ["error", "aborted"].includes(m.stopReason) ||
      m.usageAvailable === false ||
      m.cacheUsageAvailable !== true
    )
      continue;
    cacheRead += m.usage.cacheRead;
    totalInput += m.usage.input + m.usage.cacheRead + m.usage.cacheWrite;
  }
  for (const entry of [...entries].reverse()) {
    if (entry.type === "compaction") break;
    if (entry.type !== "message" || entry.message.role !== "assistant") continue;
    const m = entry.message;
    if (m.stopReason === "error" || m.stopReason === "aborted") continue;
    if (m.usageAvailable === false || (m.usageAvailable !== true && m.usage.totalTokens === 0)) continue;
    const inputTokens = m.usage.input + m.usage.cacheRead + m.usage.cacheWrite;
    return {
      contextWindow: model.contextWindow,
      inputTokens,
      percent: (inputTokens / model.contextWindow) * 100,
      timestamp: m.timestamp,
      source: "server usage",
      breakdown: m.contextBreakdown,
      averageCacheHitRate: totalInput > 0 ? cacheRead / totalInput : null,
    };
  }
  return result;
}
export function supportedThinkingLevels(model: Model): ThinkingLevel[] {
  return thinkingChoices(model);
}