@ziggs-ai/agent-sdk 0.38.0 → 0.38.2

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/Agent.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { SERVER_EVENTS } from '@ziggs-ai/contracts';
1
2
  import { withAgreementContext } from './runtime/agreementContext.js';
2
3
  import { agreementLaneId, agreementIdFromLane, isContextAccessRequest } from '@ziggs-ai/api-client';
3
4
  import { createDeclaredPollRunner } from './platform/polls/declaredPollRunner.js';
@@ -556,7 +557,7 @@ export class Agent {
556
557
  : undefined);
557
558
  const actorId = typeof event.actorId === 'string' && event.actorId ? event.actorId : undefined;
558
559
  return this.eventQueue.enqueue({
559
- type: 'resource_changed',
560
+ type: SERVER_EVENTS.resourceChanged,
560
561
  resource: event,
561
562
  chatId: event.chatId,
562
563
  taskId: event.taskId,
@@ -1,16 +1,3 @@
1
- /**
2
- * Shared Claude-Agent-SDK cognition pieces.
3
- *
4
- * Everything a Claude-brain agent needs to turn a Ziggs wake into a `query()`
5
- * call, EXCEPT the loop itself. `ClaudeBrain` owns the loop (drive `query()`,
6
- * collect metrics); this module owns the periphery so it lives in one place and
7
- * is unit-testable without spinning up the SDK.
8
- *
9
- * The lockdown option set (`tools: []`, `strictMcpConfig`, `settingSources: []`,
10
- * bypass permissions, no local settings) is a security boundary, not a default —
11
- * it MUST be applied on every Claude-brain wake. Centralizing it here means a
12
- * caller cannot silently drift from it.
13
- */
14
1
  import { type Options, type SDKAssistantMessage } from '@anthropic-ai/claude-agent-sdk';
15
2
  import type { RawEvent } from '../runtime/buildOutcome.js';
16
3
  export interface ClaudeQueryOptionsParams {
@@ -11,6 +11,7 @@
11
11
  * it MUST be applied on every Claude-brain wake. Centralizing it here means a
12
12
  * caller cannot silently drift from it.
13
13
  */
14
+ import { SERVER_EVENTS } from '@ziggs-ai/contracts';
14
15
  import { SYSTEM_PROMPT_DYNAMIC_BOUNDARY, } from '@anthropic-ai/claude-agent-sdk';
15
16
  import { decisionWords } from '@ziggs-ai/api-client';
16
17
  import { getBatchEvents } from '../context/batch.js';
@@ -215,7 +216,7 @@ function renderEventLines(event, lines, now) {
215
216
  // store claim wakes as resource_changed (no chat, reason
216
217
  // proposal_approved). Distinct from the lifecycle hire path above: open the
217
218
  // buyer chat first, then greet and serve terms.
218
- if (event?.type === 'resource_changed') {
219
+ if (event?.type === SERVER_EVENTS.resourceChanged) {
219
220
  const resource = (event.resource ?? event);
220
221
  const reason = (typeof resource.reason === 'string' && resource.reason) ||
221
222
  (typeof event.reason === 'string' && event.reason) ||
@@ -27,7 +27,7 @@ Your prose and final summary are private host notes, not messages to the people
27
27
  - Closing a task closes the TASK, and only the task. It stores your result where the next agent reads it, queues a wake for whoever the platform addresses, and on an agreement that bills per completed task it meters that one execution. It does not end the hire — a standing agreement stays active for the next task — it does not prove anyone has read you, and it does not prove you were paid. The reply tells you which of those actually happened: report that and nothing beyond it. A completion whose reply you never saw is recovered by READING the task back, never by completing it a second time; your retry carries the same write key, so a redelivered completion no-ops instead of doubling the result, the wake and the charge.
28
28
  - Enumerate open work with \`task_list\` (use assignedToMe for your own active tasks).
29
29
  - Chat is where you talk to whoever you are working with, and where a human reads what you delivered — sending it to them there is delivery, not duplication. It is not where another AGENT collects a deliverable: that one reads the task result, so a chat message never stands in for closing the task. Deliver into the working conversation the hire already has; do not repeat it into every room you can reach.
30
- - Use any room you can write in, or open one (newChat for a separate subject). The server refuses what you are not allowed to do, and the refusal says why.
30
+ - For replies and follow-ups, send into the original conversation (its chatId). Sending to a person without a chatId selects the main pair room, which may be a different conversation. Missing access is a reason to request the scoped permission, not to silently move the exchange. Use another writable room, or open one with newChat, only for a separate subject. The server refuses what you are not allowed to do, and the refusal says why.
31
31
  - When a store listing of yours is claimed (\`resource_changed\` with reason \`proposal_approved\`), call \`chat_open\` with the buyer (actorId / Sender) AND the claimed agreementId. That returns the hire's room, which the server usually made at claim, or opens one when there is none. Greet them only when the agreement accepts messages, then serve the agreement terms. A task-only agreement needs no chat or greeting: wait for assigned tasks and deliver results through tasks. Do not \`chat_send\` to an \`agrn-*\` session id — open a real chat first.
32
32
  - When a task you hold carries a deadline or a reminder rule, they are part of the job, not decoration. Never remind the same person sooner than the stated interval or more times than the budget; use \`wake_at\` to come back rather than waiting in place, and re-arm it each time you wake. When the budget is spent, stop asking and say what you have. At the deadline, post what you got and where you are stuck in the room where the question was asked, close the task, and stop — whether or not you got the answer. Nothing stops you from breaking this, which is exactly why it is on you: over-reminding is a breach of the task, not diligence, and every reminder costs a wake.
33
33
  - Hand off by completing your task — the platform notifies the next agent.
@@ -74,7 +74,7 @@ export const chatSendTool = defineTool('chat_send', {
74
74
  underAgreementId: { type: 'string', description: 'Your run authority, defaulting to the current run in every destination room.' },
75
75
  chatId: { type: 'string', description: 'Omit this to send in the chat you were woken in — that is the usual case. Only pass a chatId to send in a DIFFERENT chat, such as one you just opened with chat_open. When chatId is set it wins over `to`.' },
76
76
  to: { type: 'string', description: 'User or agent id of someone you already have a conversation with. Sends in that pair room. Naming the person whose message woke you sends in the room that woke you instead, addressed to them. Does not open contact — first contact still needs chat_open. Ignored when chatId is set (chatId wins; `to` is used as receiverId if receiverId is omitted).' },
77
- receiverId: { type: 'string', description: 'Name someone only when you mean them. Leave it out to write back in this room: one other participant is the recipient, and with several Jev may select one. Otherwise the message stays in the room with no specific wake. To name a masked party, pass its rpb_ ref as it came. Pass human to address the people in the room.' },
77
+ receiverId: { type: 'string', description: 'Name someone only when you mean them. Leave it out to write back in this room: one other participant is the recipient, and with several Jev may select one. Otherwise the message stays in the room with no specific wake. To name a masked party, pass its rpb_ ref as it came. Pass human only for a broadcast to the people in the room; it does not wake assistants or stand-ins. For a reply from a person or their assistant, name that person\'s returned participant id. This does not grant their assistant access or guarantee a reply.' },
78
78
  text: { type: 'string', required: true },
79
79
  idempotencyKey: { type: 'string', description: 'Reuse for retry-safe resend of the same logical message.' },
80
80
  }, async (args, ctx) => {
@@ -7,6 +7,7 @@
7
7
  * manifest opts in. A hire a person formed (store claim) still wakes
8
8
  * so the provider can open the room and greet.
9
9
  */
10
+ import { SERVER_EVENTS } from '@ziggs-ai/contracts';
10
11
  const ACTIVATION_LIFECYCLE_OPS = new Set([
11
12
  'proposal_approved',
12
13
  'proposal_approved_execute',
@@ -62,7 +63,7 @@ export function isHireActivationNotice(event) {
62
63
  if (type === 'agreement_lifecycle' && operation && ACTIVATION_LIFECYCLE_OPS.has(operation)) {
63
64
  return true;
64
65
  }
65
- if (type !== 'resource_changed')
66
+ if (type !== SERVER_EVENTS.resourceChanged)
66
67
  return false;
67
68
  const resource = asRecord(ev.resource) ?? ev;
68
69
  const reason = typeof resource.reason === 'string' ? resource.reason : undefined;
@@ -1,3 +1,4 @@
1
+ import { SERVER_EVENTS } from '@ziggs-ai/contracts';
1
2
  import { isAgreementId, isBroadcastTarget } from '@ziggs-ai/api-client';
2
3
  import { getBatchEvents } from '../context/batch.js';
3
4
  function record(value) {
@@ -46,7 +47,7 @@ export async function filterStandingOfferNotices(event, agentId, readAgreement)
46
47
  const resource = record(item?.resource);
47
48
  const reason = resource?.reason ?? item?.reason;
48
49
  const id = agreementEventId(item);
49
- if (item?.type === 'resource_changed' && resource?.kind === 'agreement' &&
50
+ if (item?.type === SERVER_EVENTS.resourceChanged && resource?.kind === 'agreement' &&
50
51
  (reason === 'approval:approved' || reason === 'proposal_approved') && id) {
51
52
  // Inconclusive reads preserve the wake. An unavailable read must not eat
52
53
  // a legitimate customer hire or the answer to an agent's own request.
@@ -314,9 +314,6 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
314
314
  handledSoFar.add(request.agreementId);
315
315
  }
316
316
  }
317
- if (envelope.truncatedRequests) {
318
- warn(label, `inbox truncatedRequests=${envelope.truncatedRequests} (more requests than one pass surfaces — the tail follows on the next pass)`);
319
- }
320
317
  // Pending decisions are standing state, not deliveries: they keep appearing
321
318
  // until answered, so dedup them the same way tasks are deduped.
322
319
  for (const proposal of envelope.proposalsAwaitingMe) {
@@ -1,3 +1,4 @@
1
+ import { AGREEMENT_TERMINAL_STATES } from '@ziggs-ai/contracts';
1
2
  import { isBroadcastTarget, partyActorIds, presentClaimResult, } from '@ziggs-ai/api-client';
2
3
  // the link-summary rule lives in AgreementClient, at the point the
3
4
  // document is parsed. Every verb here inherits it through the client instead of
@@ -300,7 +301,7 @@ async function proposeAgreement(services, payload, chatId, writeKeys = null) {
300
301
  // party — instead of under that worker's sub-agreement, which the backend
301
302
  // rejects with 400 "assignee is not a party". Both are made deterministic here
302
303
  // using the chat's existing agreements.
303
- const TERMINAL_STATUS = new Set(['fulfilled', 'cancelled', 'refunded', 'rejected']);
304
+ const TERMINAL_STATUS = new Set(AGREEMENT_TERMINAL_STATES);
304
305
  async function agreementsInChat(services, chatId, cachedAgreements) {
305
306
  if (!chatId)
306
307
  return [];
@@ -1,3 +1,4 @@
1
+ import { SERVER_EVENTS } from '@ziggs-ai/contracts';
1
2
  import { isProtocolToolName, mapProtocolToolToOperation } from '../tasks/protocolRegistry.js';
2
3
  import { getBatchEvents, isTaskResultRelevantToAgent } from '../context/batch.js';
3
4
  import { bookForDelegation, ensureTaskBook, findBookHoldingPending, removeTaskBook, } from './taskBookkeeping.js';
@@ -108,7 +109,7 @@ function singleEventToOutcome(ev, ownAgentId) {
108
109
  }
109
110
  return { kind: 'subtask-finished', status: 'completed', task, result };
110
111
  }
111
- if (ev.type === 'resource_changed') {
112
+ if (ev.type === SERVER_EVENTS.resourceChanged) {
112
113
  const resource = (ev.resource ?? ev);
113
114
  const reason = resource.reason;
114
115
  if (resource.kind === 'agreement' &&
@@ -1,3 +1,6 @@
1
+ import { ContentTypes, type ContentType } from '@ziggs-ai/api-client';
2
+ export { ContentTypes, type ContentType };
3
+ /** Entry kinds. `task_history` is a legacy alias the wire still accepts. */
1
4
  export declare const EntryTypes: {
2
5
  readonly MESSAGE: "message";
3
6
  readonly NOTIFICATION: "notification";
@@ -5,15 +8,6 @@ export declare const EntryTypes: {
5
8
  readonly TASK_HISTORY: "task_history";
6
9
  };
7
10
  export type EntryType = (typeof EntryTypes)[keyof typeof EntryTypes];
8
- export declare const ContentTypes: {
9
- readonly TEXT: "text";
10
- readonly OPERATION: "operation";
11
- readonly CONTEXT: "context";
12
- readonly RESULT: "result";
13
- readonly TASK_UPDATE: "task_update";
14
- readonly THOUGHT: "thought";
15
- };
16
- export type ContentType = (typeof ContentTypes)[keyof typeof ContentTypes];
17
11
  export declare const ContextProperties: {
18
12
  readonly HISTORY: "history";
19
13
  readonly AGREEMENTS: "agreements";
@@ -1,20 +1,12 @@
1
- // Inlined from `@ziggs-ai/api-client` so the pure SDK doesn't depend on the
2
- // Ziggs HTTP client. Both client and server agree on these string constants
3
- // because the protocol is the same — they're just two views of one schema.
1
+ import { ContentTypes } from '@ziggs-ai/api-client';
2
+ export { ContentTypes };
3
+ /** Entry kinds. `task_history` is a legacy alias the wire still accepts. */
4
4
  export const EntryTypes = {
5
5
  MESSAGE: 'message',
6
6
  NOTIFICATION: 'notification',
7
7
  ARTIFACT: 'artifact',
8
8
  TASK_HISTORY: 'task_history',
9
9
  };
10
- export const ContentTypes = {
11
- TEXT: 'text',
12
- OPERATION: 'operation',
13
- CONTEXT: 'context',
14
- RESULT: 'result',
15
- TASK_UPDATE: 'task_update',
16
- THOUGHT: 'thought',
17
- };
18
10
  export const ContextProperties = {
19
11
  HISTORY: 'history',
20
12
  AGREEMENTS: 'agreements',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/agent-sdk",
3
- "version": "0.38.0",
3
+ "version": "0.38.2",
4
4
  "description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,7 +26,8 @@
26
26
  "@anthropic-ai/claude-agent-sdk": "^0.3.284",
27
27
  "@anthropic-ai/sdk": "^0.110.0",
28
28
  "@modelcontextprotocol/sdk": "^1.29.0",
29
- "@ziggs-ai/api-client": "0.37.0",
29
+ "@ziggs-ai/api-client": "0.37.4",
30
+ "@ziggs-ai/contracts": "^0.23.3",
30
31
  "ajv": "^8.17.1",
31
32
  "dotenv": "^17.2.3",
32
33
  "openai": "^4.0.0",