@ziggs-ai/agent-sdk 0.43.2 → 0.43.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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.43.3
6
+
7
+ - An agent no longer retries a wake for an agreement it cannot read. When the server refuses the exact context of an agreement-only wake (403 or 404), for example the consent record of the agent's own access request, the inbox settles that delivery instead of holding the ack. Before, each redelivery spent a wake from the work's budget until the budget ran out and the agent's real task could no longer wake. Task and message wakes with unavailable context are still held for retry.
8
+
5
9
  ## 0.43.2
6
10
 
7
11
  ## 0.43.1
@@ -20,9 +20,9 @@ const emptySnapshot = (agentId) => ({
20
20
  latestSequence: null,
21
21
  });
22
22
  async function buildSnapshot(deps, agentId, opts = {}) {
23
+ const scope = opts.workScope;
24
+ const via = opts.via ?? (scope?.taskId ? `task:${scope.taskId}` : scope?.agreementId ? `agreement:${scope.agreementId}` : scope?.messageId ? `message:${scope.messageId}` : scope?.artifactId ? `artifact:${scope.artifactId}` : undefined);
23
25
  try {
24
- const scope = opts.workScope;
25
- const via = opts.via ?? (scope?.taskId ? `task:${scope.taskId}` : scope?.agreementId ? `agreement:${scope.agreementId}` : scope?.messageId ? `message:${scope.messageId}` : scope?.artifactId ? `artifact:${scope.artifactId}` : undefined);
26
26
  if (!via)
27
27
  throw new Error('Context requires an explicit message, artifact, task or agreement');
28
28
  const agreementId = scope?.agreementId ?? (via.startsWith('agreement:') ? via.slice('agreement:'.length) : undefined);
@@ -71,7 +71,7 @@ async function buildSnapshot(deps, agentId, opts = {}) {
71
71
  // no world to act in. Leaving it as an empty snapshot used to run a
72
72
  // full turn against refusals.
73
73
  if (status === 404 || status === 403) {
74
- return { ...emptySnapshot(agentId), unavailable: true, work: { minimumComplete: false, authorization: { active: false }, instruction: 'Required context is unavailable. Do not start work without verified scope and access.' } };
74
+ return { ...emptySnapshot(agentId), unavailable: true, refused: true, refusedVia: via, work: { minimumComplete: false, authorization: { active: false }, instruction: 'Required context is unavailable. Do not start work without verified scope and access.' } };
75
75
  }
76
76
  runtimeLog.warn('ZiggsEffectHandler', `snapshot fetch failed: ${err?.message ?? err}`);
77
77
  return { ...emptySnapshot(agentId), unavailable: true, work: { minimumComplete: false, authorization: { active: false }, instruction: 'Context read failed. Retry or request access before acting; an empty packet is not permission.' } };
@@ -106,6 +106,13 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
106
106
  return true;
107
107
  }
108
108
  catch (err) {
109
+ // A refused agreement-only wake never recovers by redelivery, and every
110
+ // redelivery spends a wake from the work's budget. Settle it.
111
+ if (err?.code === 'REQUIRED_CONTEXT_UNAVAILABLE'
112
+ && err.settled === true) {
113
+ warn(label, `${what} settled without a turn: this agent cannot read that agreement`);
114
+ return true;
115
+ }
109
116
  failures++;
110
117
  forget?.();
111
118
  warn(label, `${what} was not handled: ${err?.message ?? err} — holding the ack`);
@@ -1,6 +1,15 @@
1
1
  /** A failed required read is retryable work, never a successfully handled wake. */
2
2
  export declare class RequiredContextUnavailable extends Error {
3
3
  readonly code = "REQUIRED_CONTEXT_UNAVAILABLE";
4
- constructor();
4
+ /**
5
+ * The server refused an agreement-only wake outright (403/404): this agent is
6
+ * not on that agreement, e.g. the consent record of its own access request.
7
+ * Redelivery cannot change that, and each retry spends a wake, so the inbox
8
+ * settles it instead of holding the ack. A later grant arrives as its own event.
9
+ */
10
+ readonly settled: boolean;
11
+ constructor(opts?: {
12
+ settled?: boolean;
13
+ });
5
14
  }
6
15
  export declare function assertRequiredContext(snapshot: unknown): void;
@@ -1,9 +1,17 @@
1
1
  /** A failed required read is retryable work, never a successfully handled wake. */
2
2
  export class RequiredContextUnavailable extends Error {
3
3
  code = 'REQUIRED_CONTEXT_UNAVAILABLE';
4
- constructor() {
4
+ /**
5
+ * The server refused an agreement-only wake outright (403/404): this agent is
6
+ * not on that agreement, e.g. the consent record of its own access request.
7
+ * Redelivery cannot change that, and each retry spends a wake, so the inbox
8
+ * settles it instead of holding the ack. A later grant arrives as its own event.
9
+ */
10
+ settled;
11
+ constructor(opts = {}) {
5
12
  super('Required context is unavailable. Leave the responsibility pending until access or the read recovers.');
6
13
  this.name = 'RequiredContextUnavailable';
14
+ this.settled = opts.settled === true;
7
15
  }
8
16
  }
9
17
  export function assertRequiredContext(snapshot) {
@@ -18,6 +26,8 @@ export function assertRequiredContext(snapshot) {
18
26
  // authorization.active=false can be a readable proposal awaiting a decision.
19
27
  // Those packets still support recovery; operation/task policy gates new work.
20
28
  if (snapshot == null || root.unavailable === true || unavailable(root.work)) {
21
- throw new RequiredContextUnavailable();
29
+ const settled = root.refused === true
30
+ && typeof root.refusedVia === 'string' && root.refusedVia.startsWith('agreement:');
31
+ throw new RequiredContextUnavailable({ settled });
22
32
  }
23
33
  }
package/dist/types.d.ts CHANGED
@@ -367,6 +367,10 @@ export interface ContextSnapshot {
367
367
  timelineSummary?: string | null;
368
368
  latestSequence?: string | null;
369
369
  unavailable?: boolean;
370
+ /** The server refused the exact read (403/404), as opposed to a failed read. */
371
+ refused?: boolean;
372
+ /** The selector that was refused, e.g. `agreement:<id>`. */
373
+ refusedVia?: string;
370
374
  /** Index signature so PromptBuilder's `ServerContext` can accept it directly. */
371
375
  [key: string]: unknown;
372
376
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/agent-sdk",
3
- "version": "0.43.2",
3
+ "version": "0.43.3",
4
4
  "description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
5
5
  "homepage": "https://ziggsai.com/docs",
6
6
  "bugs": {