@cognipeer/agent-sdk 0.10.2 → 0.10.3

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.d.cts CHANGED
@@ -1522,6 +1522,13 @@ type SummaryFactItem = {
1522
1522
  source?: string;
1523
1523
  };
1524
1524
  type StructuredSummary = {
1525
+ /**
1526
+ * Standing instructions the user gave that still apply ("answer in Turkish",
1527
+ * "never restart prod"). Kept verbatim across summaries: a directive dropped
1528
+ * by a later summary counts as critical loss and is merged forward, unless
1529
+ * the user explicitly revoked it (listed in `discarded_obsolete`).
1530
+ */
1531
+ user_directives?: string[];
1525
1532
  stable_facts: SummaryFactItem[];
1526
1533
  active_goals: string[];
1527
1534
  open_questions: string[];
package/dist/index.d.ts CHANGED
@@ -1522,6 +1522,13 @@ type SummaryFactItem = {
1522
1522
  source?: string;
1523
1523
  };
1524
1524
  type StructuredSummary = {
1525
+ /**
1526
+ * Standing instructions the user gave that still apply ("answer in Turkish",
1527
+ * "never restart prod"). Kept verbatim across summaries: a directive dropped
1528
+ * by a later summary counts as critical loss and is merged forward, unless
1529
+ * the user explicitly revoked it (listed in `discarded_obsolete`).
1530
+ */
1531
+ user_directives?: string[];
1525
1532
  stable_facts: SummaryFactItem[];
1526
1533
  active_goals: string[];
1527
1534
  open_questions: string[];
package/dist/index.mjs CHANGED
@@ -6146,6 +6146,9 @@ function isSyntheticSummaryMessage(message) {
6146
6146
  }
6147
6147
  return false;
6148
6148
  }
6149
+ function isCompactedToolContent(content) {
6150
+ return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE") || content.startsWith("ARCHIVED_TOOL_RESPONSE") || content.startsWith("STRUCTURED_TOOL_RESPONSE") || content.startsWith("DROPPED_TOOL_RESPONSE"));
6151
+ }
6149
6152
 
6150
6153
  // src/structuredOutput/manager.ts
6151
6154
  var StructuredOutputManager = class {
@@ -8062,6 +8065,10 @@ function collectRecentTurns(messages, lastTurnsToKeep) {
8062
8065
  function renderStructuredSummary(summary) {
8063
8066
  if (!summary) return "";
8064
8067
  const lines = ["Context summary:"];
8068
+ if (summary.user_directives && summary.user_directives.length > 0) {
8069
+ lines.push("User directives (still in force \u2014 follow them):");
8070
+ lines.push(...summary.user_directives.map((directive) => `- ${directive}`));
8071
+ }
8065
8072
  if (summary.stable_facts.length > 0) {
8066
8073
  lines.push("Stable facts:");
8067
8074
  lines.push(...summary.stable_facts.map((fact) => `- ${fact.key}: ${fact.value}`));
@@ -8137,17 +8144,46 @@ function clampToBudget(messages, maxContextTokens) {
8137
8144
  }
8138
8145
  return working;
8139
8146
  }
8147
+ function collectSummaryOnlyBody(body, hasSummary, lastTurnsToKeep) {
8148
+ if (!hasSummary) {
8149
+ return collectRecentTurns(body, Math.max(1, lastTurnsToKeep));
8150
+ }
8151
+ let boundary = -1;
8152
+ for (let index = body.length - 1; index >= 0; index -= 1) {
8153
+ if (isSyntheticSummaryMessage(body[index])) {
8154
+ boundary = index;
8155
+ break;
8156
+ }
8157
+ }
8158
+ let lastUserIndex = -1;
8159
+ for (let index = body.length - 1; index >= 0; index -= 1) {
8160
+ if (body[index].role === "user") {
8161
+ lastUserIndex = index;
8162
+ break;
8163
+ }
8164
+ }
8165
+ const keep = /* @__PURE__ */ new Set();
8166
+ const firstUserIndex = body.findIndex((message) => message.role === "user");
8167
+ if (firstUserIndex >= 0) keep.add(firstUserIndex);
8168
+ const verbatimFrom = Math.min(lastUserIndex >= 0 ? lastUserIndex : body.length, boundary + 1);
8169
+ for (let index = Math.max(0, verbatimFrom); index < body.length; index += 1) {
8170
+ if (!isSyntheticSummaryMessage(body[index])) keep.add(index);
8171
+ }
8172
+ return body.filter((_, index) => keep.has(index));
8173
+ }
8140
8174
  function buildModelMessages(state, config) {
8141
8175
  const rawMessages = state.messages || [];
8142
8176
  if (config.context.policy === "raw") {
8143
8177
  return clampToBudget(rawMessages, config.limits.maxContextTokens);
8144
8178
  }
8145
- const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
8146
8179
  const latestSummary = state.summaryRecords?.[state.summaryRecords.length - 1];
8147
8180
  const summaryText = renderStructuredSummary(latestSummary);
8148
8181
  const memoryText = renderMemoryBlock(state.memoryFacts);
8149
- const systemMessage2 = recentMessages[0]?.role === "system" ? recentMessages[0] : void 0;
8150
- const body = systemMessage2 ? recentMessages.slice(1) : recentMessages;
8182
+ const systemMessage2 = rawMessages[0]?.role === "system" ? rawMessages[0] : void 0;
8183
+ const body = config.context.policy === "summary_only" ? collectSummaryOnlyBody(systemMessage2 ? rawMessages.slice(1) : rawMessages, Boolean(summaryText), config.context.lastTurnsToKeep) : (() => {
8184
+ const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
8185
+ return recentMessages[0]?.role === "system" ? recentMessages.slice(1) : recentMessages;
8186
+ })();
8151
8187
  const syntheticContextMessages = [];
8152
8188
  if (summaryText) {
8153
8189
  syntheticContextMessages.push({ role: "system", name: "context_summary", content: summaryText });
@@ -8158,7 +8194,7 @@ function buildModelMessages(state, config) {
8158
8194
  const assembled = [
8159
8195
  ...systemMessage2 ? [systemMessage2] : [],
8160
8196
  ...syntheticContextMessages,
8161
- ...config.context.policy === "summary_only" ? body.filter((message) => message.role === "user" || message.role === "assistant").slice(-2) : body
8197
+ ...body
8162
8198
  ];
8163
8199
  return clampToBudget(assembled, config.limits.maxContextTokens);
8164
8200
  }
@@ -8203,6 +8239,7 @@ function extractJsonObject(text) {
8203
8239
  }
8204
8240
  function normalizeStructuredSummary(input, fallbackText) {
8205
8241
  const summary = {
8242
+ user_directives: Array.isArray(input?.user_directives) ? input.user_directives.map((directive) => String(directive ?? "").trim()).filter(Boolean) : [],
8206
8243
  stable_facts: Array.isArray(input?.stable_facts) ? input.stable_facts.filter((fact) => fact && typeof fact === "object").map((fact) => ({
8207
8244
  key: String(fact.key || "unknown"),
8208
8245
  value: String(fact.value || ""),
@@ -8263,7 +8300,7 @@ function extractCanonicalFacts(messages) {
8263
8300
  return [...facts.values()];
8264
8301
  }
8265
8302
  function isSummarizedToolPlaceholder(content) {
8266
- return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE") || content.startsWith("ARCHIVED_TOOL_RESPONSE") || content.startsWith("STRUCTURED_TOOL_RESPONSE") || content.startsWith("DROPPED_TOOL_RESPONSE"));
8303
+ return isCompactedToolContent(content);
8267
8304
  }
8268
8305
  function collectLatestTurnToolCallIds(messages) {
8269
8306
  const ids = /* @__PURE__ */ new Set();
@@ -8322,11 +8359,16 @@ function runIntegrityCheck(previous, current) {
8322
8359
  const previousKeys = new Set((previous?.stable_facts || []).map((fact) => fact.key));
8323
8360
  const currentKeys = new Set(current.stable_facts.map((fact) => fact.key));
8324
8361
  const obsoleteKeys = new Set(current.discarded_obsolete);
8325
- const criticalFactLoss = [...previousKeys].some((key) => !obsoleteKeys.has(key) && !currentKeys.has(key));
8362
+ const currentDirectives = new Set(current.user_directives || []);
8363
+ const lostDirectives = (previous?.user_directives || []).filter((directive) => !currentDirectives.has(directive) && !obsoleteKeys.has(directive));
8364
+ const criticalFactLoss = [...previousKeys].some((key) => !obsoleteKeys.has(key) && !currentKeys.has(key)) || lostDirectives.length > 0;
8326
8365
  const obsoleteFactRevived = current.stable_facts.some((fact) => obsoleteKeys.has(fact.key));
8327
8366
  if (criticalFactLoss) {
8328
8367
  notes.push("Missing previously retained facts; merged forward during integrity repair.");
8329
8368
  }
8369
+ if (lostDirectives.length > 0) {
8370
+ notes.push(`Dropped ${lostDirectives.length} user directive(s); merged forward during integrity repair.`);
8371
+ }
8330
8372
  if (obsoleteFactRevived) {
8331
8373
  notes.push("Obsolete facts reappeared; removed during integrity repair.");
8332
8374
  }
@@ -8349,7 +8391,13 @@ function repairStructuredSummary(previous, current, integrity) {
8349
8391
  }
8350
8392
  }
8351
8393
  const filteredFacts = integrity.obsoleteFactRevived ? nextFacts.filter((fact) => !current.discarded_obsolete.includes(fact.key)) : nextFacts;
8352
- return { ...current, stable_facts: filteredFacts };
8394
+ const directives = [...current.user_directives || []];
8395
+ for (const directive of previous.user_directives || []) {
8396
+ if (!directives.includes(directive) && !current.discarded_obsolete.includes(directive)) {
8397
+ directives.push(directive);
8398
+ }
8399
+ }
8400
+ return { ...current, user_directives: directives, stable_facts: filteredFacts };
8353
8401
  }
8354
8402
  function createContextSummarizeNode(opts) {
8355
8403
  return async (state) => {
@@ -8423,6 +8471,7 @@ function createContextSummarizeNode(opts) {
8423
8471
 
8424
8472
  Return exactly one JSON object with this schema:
8425
8473
  {
8474
+ "user_directives": [string],
8426
8475
  "stable_facts": [{ "key": string, "value": string, "confidence": number }],
8427
8476
  "active_goals": [string],
8428
8477
  "open_questions": [string],
@@ -8431,6 +8480,7 @@ Return exactly one JSON object with this schema:
8431
8480
  }
8432
8481
 
8433
8482
  Rules:
8483
+ - user_directives: standing instructions the user gave about HOW to work or answer for the rest of the conversation (language, format, tone, scope, things to always or never do) that still apply. NOT the tasks or questions themselves \u2014 "read the logs" is a task (an active goal), "always answer in Turkish" is a directive. Copy each directive close to verbatim; never merge, soften or drop one. Carry forward every directive from the previous structured summary unless the user explicitly revoked it \u2014 then put its exact text in discarded_obsolete.
8434
8484
  - Keep stable_facts only for facts that future turns must remember.
8435
8485
  - Put invalidated or superseded fact keys in discarded_obsolete.
8436
8486
  - Preserve active_goals still relevant to the user.
@@ -8498,6 +8548,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
8498
8548
  durationMs = Date.now() - startTime;
8499
8549
  structuredSummary = normalizeStructuredSummary(void 0, previousSummary || conversationText.slice(0, 800));
8500
8550
  structuredSummary = mergeStableFacts(structuredSummary, canonicalFacts);
8551
+ structuredSummary.user_directives = [...previousStructuredSummary?.user_directives || []];
8501
8552
  integrity = { passed: true, criticalFactLoss: false, obsoleteFactRevived: false, notes: ["Fallback summary generated locally."] };
8502
8553
  summaryText = renderStructuredSummary(structuredSummary);
8503
8554
  const errorEvent = {