@gajae-code/agent-core 0.14.2 → 0.15.0

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/src/agent.ts CHANGED
@@ -19,13 +19,14 @@ import {
19
19
  type ThinkingBudgets,
20
20
  type ToolChoice,
21
21
  type ToolResultMessage,
22
+ type UserMessage,
22
23
  } from "@gajae-code/ai";
23
24
  import {
24
25
  CURSOR_COMPOSER_BASH_POLICY_RECOVERY_PROMPT,
25
26
  isCurrentComposerBashPolicyBlockedError,
26
27
  } from "@gajae-code/ai/providers/composer-discipline";
27
28
  import { extractHttpStatusFromError } from "@gajae-code/utils";
28
- import { agentLoop, agentLoopContinue } from "./agent-loop";
29
+ import { agentLoop, agentLoopContinue, managedLocalErrorDiagnostic } from "./agent-loop";
29
30
  import type { AppendOnlyContextManager } from "./append-only-context";
30
31
  import type { AttemptRunHandle, AttemptScope } from "./attempt-scope";
31
32
  import { createAttemptScopeAuthority } from "./attempt-scope";
@@ -318,6 +319,8 @@ export interface AgentOptions {
318
319
  }
319
320
 
320
321
  export interface AgentPromptOptions {
322
+ /** One-shot transient recovery instruction sent only to the provider for the next assistant request; never committed to durable history. */
323
+ transientRecoveryMessage?: UserMessage;
321
324
  toolChoice?: ToolChoice;
322
325
  /** Disable transport replay; fallback accounting is owned by the caller. */
323
326
  fallbackManaged?: boolean;
@@ -1867,6 +1870,7 @@ export class Agent {
1867
1870
  return (await this.#maintainContext?.(context, lifecycle)) ?? "not-needed";
1868
1871
  }
1869
1872
  : undefined,
1873
+ transientRecoveryMessage: options?.transientRecoveryMessage,
1870
1874
  telemetry: this.#telemetry,
1871
1875
  };
1872
1876
 
@@ -2005,9 +2009,12 @@ export class Agent {
2005
2009
  stopReason: abortController.signal.aborted ? "aborted" : "error",
2006
2010
  errorMessage: err?.message || String(err),
2007
2011
  errorStatus: extractHttpStatusFromError({ status: err?.errorStatus }) ?? extractHttpStatusFromError(err),
2008
- ...(err?.errorKind === "local_snapshot_failure" || err?.errorKind === "local_buffer_overflow"
2009
- ? { errorKind: err.errorKind as "local_snapshot_failure" | "local_buffer_overflow" }
2010
- : {}),
2012
+ // Local-diagnostic authority (`errorKind` + structured
2013
+ // `bufferOverflow`) comes from ONE identity check: a foreign error
2014
+ // that self-declares a local kind gets neither field, so the parent
2015
+ // receipt never misattributes a provider/stream failure to the local
2016
+ // staging machinery (#4618).
2017
+ ...(managedLocalErrorDiagnostic(err) ?? {}),
2011
2018
  timestamp: Date.now(),
2012
2019
  } as AgentMessage;
2013
2020
 
@@ -0,0 +1,3 @@
1
+ Your previous response was discarded before execution: its tool-call arguments spelled non-ASCII text as `\uXXXX` escape sequences instead of literal UTF-8 characters. Escaped text cannot be verified — a single mistyped hex digit silently becomes a different, equally valid character — so such calls are never executed.
2
+
3
+ Re-issue the same tool call now, writing every non-ASCII character literally (for example 한글, 日本語, émoji — never `\uXXXX`). Do not change the intent or content of the call; only the spelling of the text.
package/src/types.ts CHANGED
@@ -186,6 +186,14 @@ export type ManagedAttemptOutcome =
186
186
  type: "escaped_arguments_discarded";
187
187
  /** The defective assistant turn; already removed from usable history by the loop. */
188
188
  message: AssistantMessage;
189
+ /**
190
+ * True when this discarded attempt had no transient steering instruction
191
+ * attached yet. A managed retry continuation should carry the escaped
192
+ * non-ASCII recovery instruction exactly once, so a deterministic
193
+ * escaper has a reason to change its spelling; the instruction never
194
+ * lands in durable history. Absent/false means steering already ran.
195
+ */
196
+ steeringPending?: boolean;
189
197
  scope?: AttemptScope;
190
198
  }
191
199
  | { type: "context_overflow_discarded"; message: AssistantMessage; scope?: AttemptScope }
@@ -346,10 +354,17 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
346
354
  /**
347
355
  * Invoked with the follow-up messages the loop dequeues for the next turn
348
356
  * (right after {@link getFollowUpMessages}). The consumer may use this to
349
- * attach per-turn state (e.g. a fresh owned-completion lineage) at actual
357
+ * attach per-turn state (e.g., a fresh owned-completion lineage) at actual
350
358
  * resume admission rather than when the message was merely queued.
351
359
  */
352
360
  onFollowUpConsumed?: (messages: AgentMessage[]) => void;
361
+ /**
362
+ * One-shot transient recovery instruction attached to the first assistant
363
+ * request of this loop invocation. Sent only to the provider (never committed
364
+ * to durable agent message history) so a caller-owned retry of a discarded
365
+ * attempt can name the defect it is retrying around.
366
+ */
367
+ transientRecoveryMessage?: UserMessage;
353
368
  /**
354
369
  * Supplies one bounded synthetic recovery instruction before the loop would
355
370
  * otherwise yield. Unlike a follow-up, it is sent only to the provider and