@ziggs-ai/api-client 0.36.4 → 0.37.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.
@@ -3,20 +3,12 @@ export declare const agreementBuyCapability: CapabilityDefinition;
3
3
  export declare const agreementBidCapability: CapabilityDefinition;
4
4
  export declare const agreementBrokerCapability: CapabilityDefinition;
5
5
  export declare const agreementRequestCapability: CapabilityDefinition;
6
- export declare const agreementOfferCapability: CapabilityDefinition;
7
- /**
8
- * Pause and resume act on a listing that already exists and form nothing. A
9
- * pause keeps the same row, id and sold hires; revoke is the verb that ends a
10
- * listing for good.
11
- */
12
- export declare const listingPauseCapability: CapabilityDefinition;
13
- export declare const listingResumeCapability: CapabilityDefinition;
14
6
  export declare const agreementHandoffCapability: CapabilityDefinition;
15
7
  export declare const AGREEMENT_VERB_CAPABILITIES: CapabilityDefinition[];
16
8
  /**
17
- * The door verbs. Not in {@link AGREEMENT_VERB_CAPABILITIES}: those six form an
18
- * agreement, while pause and resume open and close the door on a listing that
19
- * already exists.
9
+ * Pause and resume left the agent surface. A person or the deploy
10
+ * opens and closes a listing. The array stays so registration has one place
11
+ * to look and finds nothing.
20
12
  */
21
13
  export declare const LISTING_DOOR_CAPABILITIES: CapabilityDefinition[];
22
14
  /**
@@ -1,5 +1,4 @@
1
1
  import { delegateAgreement, getAgreement, proposeBroadcast, proposeDirectTo, } from '../http/AgreementClient.js';
2
- import { pauseOffer, publishOffer, resumeOffer } from '../http/MarketplaceClient.js';
3
2
  import { fullCreds } from './types.js';
4
3
  import { nextCall } from './nextCall.js';
5
4
  /**
@@ -193,7 +192,7 @@ export const agreementBidCapability = {
193
192
  names: { sdk: 'agreement_bid', mcp: 'ziggs_agreement_bid' },
194
193
  title: 'You work, they pay (named counterparty)',
195
194
  descriptions: {
196
- sdk: 'Offer to do work for a named counterparty, who pays. You provide. To publish the same offer to whoever wants it rather than one named party, use agreement_offer.',
195
+ sdk: 'Offer to do work for a named counterparty, who pays. You provide. A standing listing for whoever claims it is published by a person or the deploy, not by this verb.',
197
196
  },
198
197
  annotation: 'destructive',
199
198
  params: {
@@ -262,7 +261,7 @@ export const agreementRequestCapability = {
262
261
  names: { sdk: 'agreement_request', mcp: 'ziggs_agreement_request' },
263
262
  title: 'They work, you pay (open to anyone)',
264
263
  descriptions: {
265
- sdk: 'Post work you want done and will pay for, for whoever claims it. Whoever claims does the work. To offer work you would do instead, use agreement_offer.',
264
+ sdk: 'Post work you want done and will pay for, for whoever claims it. Whoever claims does the work. A standing listing of work you would do is published by a person or the deploy.',
266
265
  },
267
266
  annotation: 'destructive',
268
267
  params: {
@@ -286,103 +285,6 @@ export const agreementRequestCapability = {
286
285
  },
287
286
  sdkOptions: { isAgreementCreation: true },
288
287
  };
289
- /**
290
- * No mandate param here, deliberately: a listing is formed inside no job. It is
291
- * a standing invitation to the world that outlives whatever the agent happens
292
- * to be doing today, and the publish path says so at its own end
293
- * (`POST /marketplace/offers/publish`). Hanging one under a job would kill the
294
- * listing when the job ended.
295
- *
296
- * No price default here on purpose: an unstated price is a free hire, and the
297
- * publish path is the one place that says so. Stating a price publishes a paid
298
- * listing.
299
- *
300
- * No replay key either, and that one has a cost worth knowing: each call
301
- * publishes a fresh row rather than replaying, and the previous listing is
302
- * retired as it goes, so an agent that republishes leaves dead rows behind it.
303
- * One listing per agent still holds; the churn does not.
304
- */
305
- /**
306
- * Seats on a listing: how many customers may hold a live hire from it at once.
307
- * A hire that ends gives its seat back, so this is a capacity, not a lifetime
308
- * count. Only the listing verb takes it; a direct proposal has one customer.
309
- */
310
- const MAX_CLAIMS_PARAM = {
311
- type: 'number',
312
- description: 'How many customers may hold a live hire from this listing at once. A hire that ends gives its seat back. While every seat is taken, new claims are refused as full until one frees. Omit for unlimited. Set it when your attention is limited: every customer who hires you can wake you.',
313
- };
314
- export const agreementOfferCapability = {
315
- key: 'agreement_offer',
316
- names: { sdk: 'agreement_offer', mcp: 'ziggs_agreement_offer' },
317
- title: 'You work, they pay (open to anyone)',
318
- descriptions: {
319
- sdk: 'Publish work you will do, for whoever claims it and pays. You provide. This is your listing: it stands until revoked or exhausted. To offer one named counterparty instead, use agreement_bid.',
320
- },
321
- annotation: 'destructive',
322
- params: { audience: AUDIENCE_PARAM, ...TERMS_PARAMS, maxClaims: MAX_CLAIMS_PARAM },
323
- needsAgentId: true,
324
- handler: async (args, env) => {
325
- const terms = termsFrom(args);
326
- const agreement = await publishOffer({
327
- description: terms.description ?? '',
328
- price: terms.price,
329
- lifecycle: terms.lifecycle,
330
- expiresAt: terms.expiresAt,
331
- maxExecutions: terms.maxExecutions,
332
- conversationAllowance: terms.conversationAllowance,
333
- conversationAllowanceScope: terms.conversationAllowanceScope,
334
- interactionMode: terms.interactionMode,
335
- billing: terms.billing,
336
- engagementKind: engagementKindFrom(args),
337
- audience: args['audience'],
338
- ...(typeof args['maxClaims'] === 'number' ? { maxClaims: args['maxClaims'] } : {}),
339
- }, fullCreds(env));
340
- return { agreement, readPlan: publishedNext(env) };
341
- },
342
- sdkOptions: { isAgreementCreation: true },
343
- };
344
- /* ───────────────────────── the door on your own listing ──────────────────── */
345
- /** The listing the pause and resume verbs act on. */
346
- const LISTING_ID_PARAM = {
347
- type: 'string',
348
- required: true,
349
- description: 'Your listing: the agreement id your offer was published under (what ziggs_agreement_offer answered with). On your own profile it is doors.listingAgreementId.',
350
- };
351
- /**
352
- * Pause and resume act on a listing that already exists and form nothing. A
353
- * pause keeps the same row, id and sold hires; revoke is the verb that ends a
354
- * listing for good.
355
- */
356
- export const listingPauseCapability = {
357
- key: 'listing_pause',
358
- names: { sdk: 'listing_pause', mcp: 'ziggs_listing_pause' },
359
- title: 'Pause your listing',
360
- descriptions: {
361
- sdk: 'Stop taking new customers on a listing you publish, without deleting it. New claims on it are refused until you resume it with listing_resume. Same listing, same id; hires already sold keep running. To end a listing for good, use agreement_revoke.',
362
- },
363
- annotation: 'destructive',
364
- params: { agreementId: LISTING_ID_PARAM },
365
- needsAgentId: true,
366
- handler: async (args, env) => {
367
- const agreement = await pauseOffer(args['agreementId'], fullCreds(env));
368
- return { status: 'paused', agreement };
369
- },
370
- };
371
- export const listingResumeCapability = {
372
- key: 'listing_resume',
373
- names: { sdk: 'listing_resume', mcp: 'ziggs_listing_resume' },
374
- title: 'Resume your listing',
375
- descriptions: {
376
- sdk: 'Reopen a listing you paused with listing_pause: same listing, same id, taking new customers again. A listing closed because every seat is taken, or because its agent stopped answering, reopens on its own and needs no resume.',
377
- },
378
- annotation: 'destructive',
379
- params: { agreementId: LISTING_ID_PARAM },
380
- needsAgentId: true,
381
- handler: async (args, env) => {
382
- const agreement = await resumeOffer(args['agreementId'], fullCreds(env));
383
- return { status: 'resumed', agreement };
384
- },
385
- };
386
288
  /* ──────────────────────────────── hand-off ───────────────────────────────── */
387
289
  export const agreementHandoffCapability = {
388
290
  key: 'agreement_handoff',
@@ -441,18 +343,14 @@ export const AGREEMENT_VERB_CAPABILITIES = [
441
343
  agreementBidCapability,
442
344
  agreementBrokerCapability,
443
345
  agreementRequestCapability,
444
- agreementOfferCapability,
445
346
  agreementHandoffCapability,
446
347
  ];
447
348
  /**
448
- * The door verbs. Not in {@link AGREEMENT_VERB_CAPABILITIES}: those six form an
449
- * agreement, while pause and resume open and close the door on a listing that
450
- * already exists.
349
+ * Pause and resume left the agent surface. A person or the deploy
350
+ * opens and closes a listing. The array stays so registration has one place
351
+ * to look and finds nothing.
451
352
  */
452
- export const LISTING_DOOR_CAPABILITIES = [
453
- listingPauseCapability,
454
- listingResumeCapability,
455
- ];
353
+ export const LISTING_DOOR_CAPABILITIES = [];
456
354
  /**
457
355
  * Subcontract sits next to the propose verbs, not inside them: the parent
458
356
  * already exists, and the conversation is optional. The server uses the
@@ -33,6 +33,8 @@ export const agentSearchCapability = {
33
33
  }
34
34
  const chatOpen = env.surface === 'mcp' ? 'ziggs_chat_open' : 'chat_open';
35
35
  const linkList = env.surface === 'mcp' ? 'ziggs_link_list' : 'link_list';
36
+ const marketplace = env.surface === 'mcp' ? 'ziggs_marketplace_view' : 'marketplace_view';
37
+ const request = env.surface === 'mcp' ? 'ziggs_agreement_request' : 'agreement_request';
36
38
  const people = result.people ?? [];
37
39
  const messageThem = people.length
38
40
  ? {
@@ -53,6 +55,10 @@ export const agentSearchCapability = {
53
55
  'your org: people by name (returned under people, to message as people)',
54
56
  ],
55
57
  hint: 'Zero agents means no agent matched these terms; discovery itself is up. ' +
58
+ // An agent given work to farm out stopped here with it undone. The
59
+ // next rungs of the hiring ladder belong at the moment the search
60
+ // comes back empty, not in a skill loaded every session.
61
+ `To get work done, open listings and requests are in ${marketplace}; when nothing fits, post the work with ${request} so whoever can do it claims it. ` +
56
62
  "People are not agents: a teammate is found by their name and comes back under people, never as their agents. " +
57
63
  `To reach them, open a chat with that user id (${chatOpen} participantId). ` +
58
64
  'Matching is lexical, so try shorter or different keywords. ' +
@@ -1,7 +1,7 @@
1
1
  export { type CapabilitySurface, type CapabilityAnnotation, type CapabilityParam, type CapabilityEnv, type CapabilityDefinition, fullCreds, rethrowWithContext, } from './types.js';
2
2
  export { type McpBrief, type McpDoor, hasMcpBrief, mcpBriefNames, mcpDescription, } from './mcpBriefs.js';
3
3
  export { nextCall, nextCallsFromUntrustedContent, isStaleAdvertisedAction, peerPrincipalId, isPersonaFace, workContextFromEnv, type NextCall, type NextCallOutcome, type NextCallEffects, type NextCallHold, type NextCallOptions, type WorkContext, } from './nextCall.js';
4
- export { AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, listingPauseCapability, listingResumeCapability, agreementBuyCapability, agreementBidCapability, agreementBrokerCapability, agreementRequestCapability, agreementOfferCapability, agreementHandoffCapability, agreementSubcontractCapability, } from './agreementVerbs.js';
4
+ export { AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, agreementBuyCapability, agreementBidCapability, agreementBrokerCapability, agreementRequestCapability, agreementHandoffCapability, agreementSubcontractCapability, } from './agreementVerbs.js';
5
5
  export { PAYMENT_CAPABILITIES, paymentBalanceCapability } from './payments.js';
6
6
  export { LINK_CAPABILITIES, listLinksCapability, proposeLinkCapability, linkIsReachOnly, } from './links.js';
7
7
  export { INTRODUCTION_CAPABILITIES, mintIntroductionCapability, redeemIntroductionCapability, listIntroductionsCapability, revokeIntroductionCapability, } from './introductions.js';
@@ -1,7 +1,7 @@
1
1
  export { fullCreds, rethrowWithContext, } from './types.js';
2
2
  export { hasMcpBrief, mcpBriefNames, mcpDescription, } from './mcpBriefs.js';
3
3
  export { nextCall, nextCallsFromUntrustedContent, isStaleAdvertisedAction, peerPrincipalId, isPersonaFace, workContextFromEnv, } from './nextCall.js';
4
- export { AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, listingPauseCapability, listingResumeCapability, agreementBuyCapability, agreementBidCapability, agreementBrokerCapability, agreementRequestCapability, agreementOfferCapability, agreementHandoffCapability, agreementSubcontractCapability, } from './agreementVerbs.js';
4
+ export { AGREEMENT_VERB_CAPABILITIES, LISTING_DOOR_CAPABILITIES, agreementBuyCapability, agreementBidCapability, agreementBrokerCapability, agreementRequestCapability, agreementHandoffCapability, agreementSubcontractCapability, } from './agreementVerbs.js';
5
5
  export { PAYMENT_CAPABILITIES, paymentBalanceCapability } from './payments.js';
6
6
  export { LINK_CAPABILITIES, listLinksCapability, proposeLinkCapability, linkIsReachOnly, } from './links.js';
7
7
  export { INTRODUCTION_CAPABILITIES, mintIntroductionCapability, redeemIntroductionCapability, listIntroductionsCapability, revokeIntroductionCapability, } from './introductions.js';
@@ -7,8 +7,8 @@ const VIEW_KINDS = ['all', 'requests', 'offers'];
7
7
  function publishHint(env) {
8
8
  const claim = env.surface === 'mcp' ? 'ziggs_agreement_claim' : 'agreement_claim';
9
9
  const publish = env.surface === 'mcp'
10
- ? 'Publish a request with ziggs_agreement_request (claimer works, you pay) or a standing offer with ziggs_agreement_offer (you work, claimer pays).'
11
- : 'Publish your own via agreement_propose with proposedTo "everyone"/"org" (providerId = your id for an offer, omitted for a request).';
10
+ ? 'Post a request with ziggs_agreement_request (claimer works, you pay). A standing listing is published by a person or the deploy.'
11
+ : 'Post a request via agreement_propose with proposedTo "everyone"/"org" and no providerId. A standing listing is published by a person or the deploy.';
12
12
  return (`Reuse an active agreement that already covers the work. Otherwise claim any row with ${claim} ` +
13
13
  `(agreementId) — listings are take-it-or-leave-it, never counter one. ${publish}`);
14
14
  }
@@ -62,10 +62,6 @@ const BRIEFS = {
62
62
  does: 'Posts work you want done and will pay for: whoever claims it does the work.',
63
63
  changes: 'publishes a request others can claim',
64
64
  },
65
- ziggs_agreement_offer: {
66
- does: 'Publishes your listing: you provide, whoever claims it pays. Claimers take it as posted.',
67
- changes: 'publishes it until revoked or sold out',
68
- },
69
65
  ziggs_agreement_buy: {
70
66
  does: 'Proposes work to a named counterparty: they provide, you pay. Most published agents accept only claims of their listing.',
71
67
  changes: 'sends a proposal they approve, reject or counter',
@@ -102,14 +98,6 @@ const BRIEFS = {
102
98
  does: 'Ends an agreement you provide, for good, once its whole scope is delivered. A finished task closes with ziggs_task_set_result instead.',
103
99
  changes: 'revokes every grant it conferred; it cannot be reopened',
104
100
  },
105
- ziggs_listing_pause: {
106
- does: 'Stops new claims on a listing you publish; hires already sold keep running.',
107
- changes: 'pauses it until ziggs_listing_resume',
108
- },
109
- ziggs_listing_resume: {
110
- does: 'Reopens a listing you paused.',
111
- changes: 'it takes new claims again',
112
- },
113
101
  // Rooms
114
102
  ziggs_chat_list: {
115
103
  does: 'Lists rooms you hold a grant on, with last message and unread count. fields adds members or rosterSummary.',
@@ -3,4 +3,4 @@
3
3
  * tools. Stated on the schema so a fresh agent does not burn a turn learning
4
4
  * the rule from the validation error.
5
5
  */
6
- export declare const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = "REQUIRED on a direct proposal: name who does the work \u2014 your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a request (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.";
6
+ export declare const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = "REQUIRED on a direct proposal: name who does the work \u2014 your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit providerId to post a request (claimer works). A person or the deploy publishes a standing listing; this agent does not. Payer is always the non-providing side.";
@@ -3,4 +3,4 @@
3
3
  * tools. Stated on the schema so a fresh agent does not burn a turn learning
4
4
  * the rule from the validation error.
5
5
  */
6
- export const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = 'REQUIRED on a direct proposal: name who does the work — your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a request (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.';
6
+ export const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = 'REQUIRED on a direct proposal: name who does the work — your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit providerId to post a request (claimer works). A person or the deploy publishes a standing listing; this agent does not. Payer is always the non-providing side.';
@@ -1,6 +1,11 @@
1
1
  type AssistantHints = {
2
2
  orgId?: string;
3
3
  resource?: string;
4
+ clientSessionId?: string;
5
+ instanceId?: string;
6
+ workspaceIds?: string;
7
+ app?: string;
8
+ sessionName?: string;
4
9
  };
5
10
  /** Node-only, opt-in request context. Ordinary HTTP clients remain browser-safe. */
6
11
  export declare function withAssistantRequest<T>(hints: AssistantHints, run: () => T): Promise<Awaited<T>>;
@@ -6,11 +6,22 @@ export async function withAssistantRequest(hints, run) {
6
6
  assistantRequest = new AsyncLocalStorage();
7
7
  return assistantRequest;
8
8
  });
9
- return await (await assistantContextLoading).run(hints, run);
9
+ const context = await assistantContextLoading;
10
+ // A workspace router adds its per-operation target inside the caller's
11
+ // session. Preserve that session without sharing it between concurrent calls.
12
+ return await context.run({ ...context.getStore(), ...hints, orgId: hints.orgId, resource: hints.resource }, run);
10
13
  }
11
14
  export function assistantRequestHeaders() {
12
15
  const hints = assistantRequest?.getStore();
13
- return { ...(hints?.orgId ? { 'X-Workspace-Id': hints.orgId } : {}), ...(hints?.resource ? { 'X-Ziggs-Resource': hints.resource } : {}) };
16
+ return {
17
+ ...(hints?.orgId ? { 'X-Workspace-Id': hints.orgId } : {}),
18
+ ...(hints?.resource ? { 'X-Ziggs-Resource': hints.resource } : {}),
19
+ ...(hints?.clientSessionId ? { 'X-Ziggs-Session': hints.clientSessionId } : {}),
20
+ ...(hints?.instanceId ? { 'X-Ziggs-Instance': hints.instanceId } : {}),
21
+ ...(hints?.workspaceIds ? { 'X-Ziggs-Workspaces': hints.workspaceIds } : {}),
22
+ ...(hints?.app ? { 'X-Ziggs-App': hints.app } : {}),
23
+ ...(hints?.sessionName ? { 'X-Ziggs-Session-Name': hints.sessionName } : {}),
24
+ };
14
25
  }
15
26
  /**
16
27
  * Auth headers for operator-key HTTP clients.
package/dist/index.d.ts CHANGED
@@ -7,6 +7,9 @@ export { getBackendUrl } from './utils/urlUtils.js';
7
7
  export { configureApiClient, apiClientConfig } from './config.js';
8
8
  export type { ApiClientConfig, ApiClientLogLevel } from './config.js';
9
9
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
10
+ export type { RuntimeLogLevel } from './shared/runtimeLog.js';
11
+ export { resolveDelegateCreds, resolveDelegateHttpUrl, } from './shared/delegateCreds.js';
12
+ export type { DelegateEnv, ResolvedDelegateCreds, } from './shared/delegateCreds.js';
10
13
  export { RateLimitedError, isRateLimited, parseRetryAfterMs, pollSurfaceError, } from './shared/rateLimit.js';
11
14
  export { parseErrorMessage, parseErrorCode, throwApiError, } from './shared/apiError.js';
12
15
  export { ApiError } from './types.js';
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ export { getBackendUrl } from './utils/urlUtils.js';
6
6
  // the host injects the environment; this package never reads it.
7
7
  export { configureApiClient, apiClientConfig } from './config.js';
8
8
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
9
+ export { resolveDelegateCreds, resolveDelegateHttpUrl, } from './shared/delegateCreds.js';
9
10
  // one ApiError shape; 429s carry the server's wait.
10
11
  export { RateLimitedError, isRateLimited, parseRetryAfterMs, pollSurfaceError, } from './shared/rateLimit.js';
11
12
  // One reader for the one error shape the API answers in — exported so nothing has
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The environment a delegate process was handed. Callers read the process;
3
+ * this module does not.
4
+ */
5
+ export interface DelegateEnv {
6
+ ZIGGS_API_URL?: string;
7
+ HTTP_URL?: string;
8
+ ZIGGS_OPERATOR_KEY?: string;
9
+ ZIGGS_AGENT_ID?: string;
10
+ }
11
+ export interface ResolvedDelegateCreds {
12
+ /** `ZIGGS_API_URL` wins over `HTTP_URL`. Absent when neither is set. */
13
+ httpUrl?: string;
14
+ operatorKey: string;
15
+ /** Empty when the key is a directory connection (`connectionClientId`). */
16
+ agentId: string;
17
+ }
18
+ /** Which base URL this process was told to use. The specific name wins. */
19
+ export declare function resolveDelegateHttpUrl(env: DelegateEnv): string | undefined;
20
+ /**
21
+ * One reading of a delegate's key, agent, and base URL.
22
+ * An agent-scoped key supplies the agent id. A session JWT is refused.
23
+ */
24
+ export declare function resolveDelegateCreds(env: DelegateEnv): ResolvedDelegateCreds;
@@ -0,0 +1,44 @@
1
+ import { decodeOperatorKeyClaims, isOperatorKeyExpired } from './operatorKey.js';
2
+ const MINT = 'An MCP client that supports OAuth signs in at https://mcp.ziggsai.com/mcp. ' +
3
+ 'To run with a key, issue one in the Ziggs app (Agent-only access, or Agents > Access keys). ' +
4
+ 'Docs: https://ziggsai.com/docs#connect-assistant';
5
+ /** Which base URL this process was told to use. The specific name wins. */
6
+ export function resolveDelegateHttpUrl(env) {
7
+ const specific = env.ZIGGS_API_URL?.trim();
8
+ if (specific)
9
+ return specific;
10
+ const generic = env.HTTP_URL?.trim();
11
+ return generic || undefined;
12
+ }
13
+ /**
14
+ * One reading of a delegate's key, agent, and base URL.
15
+ * An agent-scoped key supplies the agent id. A session JWT is refused.
16
+ */
17
+ export function resolveDelegateCreds(env) {
18
+ const operatorKey = env.ZIGGS_OPERATOR_KEY?.trim() ?? '';
19
+ if (!operatorKey) {
20
+ throw new Error(`ZIGGS_OPERATOR_KEY is required. ${MINT}`);
21
+ }
22
+ const claims = decodeOperatorKeyClaims(operatorKey);
23
+ if (claims?.type && claims.type !== 'operator') {
24
+ throw new Error(`ZIGGS_OPERATOR_KEY must be an operator token (not a session JWT). ${MINT}`);
25
+ }
26
+ if (isOperatorKeyExpired(claims)) {
27
+ throw new Error(`operator key expired (keyId=${claims?.keyId ?? 'unknown'}). ${MINT}`);
28
+ }
29
+ const httpUrl = resolveDelegateHttpUrl(env);
30
+ if (claims?.connectionClientId) {
31
+ return { httpUrl, operatorKey, agentId: '' };
32
+ }
33
+ const bound = claims?.boundAgentId?.trim() || '';
34
+ const fromEnv = env.ZIGGS_AGENT_ID?.trim() || '';
35
+ if (bound && fromEnv && bound !== fromEnv) {
36
+ throw new Error(`ZIGGS_AGENT_ID (${fromEnv}) conflicts with agent-scoped key bound to "${bound}". ` +
37
+ 'Remove ZIGGS_AGENT_ID or use a fleet impersonation key instead.');
38
+ }
39
+ const agentId = bound || fromEnv;
40
+ if (!agentId) {
41
+ throw new Error(`set ZIGGS_AGENT_ID, or mint an agent-scoped operator key (boundAgentId in token). ${MINT}`);
42
+ }
43
+ return { httpUrl, operatorKey, agentId };
44
+ }
@@ -1,8 +1,7 @@
1
1
  /**
2
- * Same semantics as `@ziggs-ai/agent-sdk` `shared/runtimeLog.ts` (duplicated
3
- * here so this package stays dependency-free).
4
- *
5
- * @see agent-sdk/src/shared/runtimeLog.ts
2
+ * Process-wide log level for every package that imports this. The host sets it
3
+ * with `configureApiClient({ logLevel })`; this package does not read the
4
+ * environment. The SDK re-exports these names.
6
5
  */
7
6
  import { apiClientConfig, apiClientConfigVersion } from '../config.js';
8
7
  const SEVERITY = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.36.4",
3
+ "version": "0.37.0",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",