@hiper2d/ai-agents 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2025,6 +2025,11 @@ import OpenAI3 from "openai";
2025
2025
  import { zodTextFormat } from "openai/helpers/zod";
2026
2026
  var Gpt5Agent = class extends AbstractAgent {
2027
2027
  client;
2028
+ // Routing hint for OpenAI's prefix cache (same scheme as the Mistral/Grok agents): one
2029
+ // key per agent+instruction, so an agent's own calls group together instead of every
2030
+ // agent that shares a static prefix hashing to the same route. Keys influence routing
2031
+ // only; they do not guarantee a hit.
2032
+ promptCacheKey;
2028
2033
  // Log message templates
2029
2034
  logTemplates = {
2030
2035
  error: (name, error) => `Error in ${name} agent: ${error}`
@@ -2037,6 +2042,8 @@ var Gpt5Agent = class extends AbstractAgent {
2037
2042
  };
2038
2043
  constructor(name, instruction, model, apiKey, temperature, enableThinking = false, agentLoggingConfig = DEFAULT_LOGGING_CONFIG.agents) {
2039
2044
  super(name, instruction, model, temperature, enableThinking, agentLoggingConfig);
2045
+ this.promptCacheKey = stableHashHex(`${name}
2046
+ ${instruction}`);
2040
2047
  this.client = new OpenAI3({
2041
2048
  apiKey
2042
2049
  });
@@ -2051,10 +2058,7 @@ var Gpt5Agent = class extends AbstractAgent {
2051
2058
  try {
2052
2059
  this.logAsking(messages);
2053
2060
  this.logMessages(messages);
2054
- const input = [
2055
- `System: ${this.instruction}`,
2056
- ...this.prepareMessages(messages).map((msg) => `${msg.role === "user" ? "User" : "Assistant"}: ${msg.content}`)
2057
- ].join("\n\n");
2061
+ const input = this.prepareMessages(messages).map((msg) => `${msg.role === "user" ? "User" : "Assistant"}: ${msg.content}`).join("\n\n");
2058
2062
  const schemaToSend = zodSchema;
2059
2063
  let response;
2060
2064
  try {
@@ -2063,6 +2067,7 @@ var Gpt5Agent = class extends AbstractAgent {
2063
2067
  instructions: this.instruction,
2064
2068
  input,
2065
2069
  max_output_tokens: this.maxOutputTokens,
2070
+ prompt_cache_key: this.promptCacheKey,
2066
2071
  text: {
2067
2072
  format: zodTextFormat(schemaToSend, "response_schema")
2068
2073
  }
@@ -2141,15 +2146,13 @@ var Gpt5Agent = class extends AbstractAgent {
2141
2146
  try {
2142
2147
  this.logAsking(messages);
2143
2148
  this.logMessages(messages);
2144
- const input = [
2145
- `System: ${this.instruction}`,
2146
- ...this.prepareMessages(messages).map((msg) => `${msg.role === "user" ? "User" : "Assistant"}: ${msg.content}`)
2147
- ].join("\n\n");
2149
+ const input = this.prepareMessages(messages).map((msg) => `${msg.role === "user" ? "User" : "Assistant"}: ${msg.content}`).join("\n\n");
2148
2150
  const response = await this.client.responses.create({
2149
2151
  model: this.model,
2150
2152
  instructions: this.instruction,
2151
2153
  input,
2152
- max_output_tokens: this.maxOutputTokens
2154
+ max_output_tokens: this.maxOutputTokens,
2155
+ prompt_cache_key: this.promptCacheKey
2153
2156
  });
2154
2157
  const content = response.output_text;
2155
2158
  if (!content) {
@@ -2205,13 +2208,24 @@ var Gpt5Agent = class extends AbstractAgent {
2205
2208
  import { Anthropic } from "@anthropic-ai/sdk";
2206
2209
  var ClaudeAgent = class extends AbstractAgent {
2207
2210
  client;
2211
+ /**
2212
+ * TTL for every breakpoint this agent places (system tiers and the message anchor).
2213
+ * Anthropic bills a 5m write at 1.25x input, a 1h write at 2x, reads at 0.1x, and a read
2214
+ * refreshes the timer on either TTL. Default '1h' because the main consumer runs at human
2215
+ * pace: consecutive calls for one agent measured 12-78 minutes apart, so 5m entries
2216
+ * expired before they were ever read (0-16% hit rate over 30 days, hits only on gaps
2217
+ * under five minutes). Set '5m' for continuous traffic where every call lands inside the
2218
+ * window; there the cheaper write wins. One knob for all breakpoints on purpose: Anthropic
2219
+ * requires 1h entries to precede 5m ones, and a single TTL keeps that trivially true.
2220
+ */
2221
+ cacheTtl = "1h";
2208
2222
  // System-prompt breakpoints, one per cache tier (see CACHE_TIER_MARKER):
2209
- // block 1 shared static rules, byte-identical across all bots and games with the
2210
- // same rule set, so one org-level entry serves everyone and ANY bot's call
2211
- // refreshes its TTL;
2212
- // block 2 per-bot identity + game state + summaries, byte-stable from the start of
2213
- // a game day through the end of its night (deaths/role knowledge/summaries
2214
- // only change in startNewDay), so every call within a day reads it.
2223
+ // block 1 - shared static rules, byte-identical across all bots and games with the
2224
+ // same rule set. Caches are scoped per model, so one entry serves every bot
2225
+ // ON THAT MODEL (not the whole lobby), and any of their calls refreshes it;
2226
+ // block 2 - per-bot identity + game state + summaries, byte-stable between the game's
2227
+ // state writes (a lynch, the night resolution, the summary rewrite, the new
2228
+ // day), so every call inside one of those windows reads it.
2215
2229
  // GM prompts have no marker → single block, same behavior as before. Haiku 4.5 needs a
2216
2230
  // 4096-token cacheable prefix, so tiers below that silently no-op on Haiku — expected.
2217
2231
  // A getter, not a field: `maxOutputTokens` can be raised after construction, and a field
@@ -2219,7 +2233,7 @@ var ClaudeAgent = class extends AbstractAgent {
2219
2233
  get defaultParams() {
2220
2234
  return {
2221
2235
  max_tokens: this.maxOutputTokens,
2222
- system: this.instructionParts.map((part) => ({ type: "text", text: part, cache_control: { type: "ephemeral" } })),
2236
+ system: this.instructionParts.map((part) => ({ type: "text", text: part, cache_control: { type: "ephemeral", ttl: this.cacheTtl } })),
2223
2237
  model: this.model
2224
2238
  };
2225
2239
  }
@@ -2324,14 +2338,14 @@ var ClaudeAgent = class extends AbstractAgent {
2324
2338
  const anchor = messages[messages.length - 2];
2325
2339
  if (typeof anchor.content === "string") {
2326
2340
  if (anchor.content.length > 0) {
2327
- anchor.content = [{ type: "text", text: anchor.content, cache_control: { type: "ephemeral" } }];
2341
+ anchor.content = [{ type: "text", text: anchor.content, cache_control: { type: "ephemeral", ttl: this.cacheTtl } }];
2328
2342
  }
2329
2343
  return;
2330
2344
  }
2331
2345
  for (let i = anchor.content.length - 1; i >= 0; i--) {
2332
2346
  const block = anchor.content[i];
2333
2347
  if (block.type === "text" && block.text.length > 0) {
2334
- block.cache_control = { type: "ephemeral" };
2348
+ block.cache_control = { type: "ephemeral", ttl: this.cacheTtl };
2335
2349
  return;
2336
2350
  }
2337
2351
  }