@anuma/sdk 6.24.1 → 6.25.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.
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  APP_PREVIEW_BASELINE_CSS: () => APP_PREVIEW_BASELINE_CSS,
34
34
  AUDIT_DESIGN_SCHEMA: () => AUDIT_DESIGN_SCHEMA,
35
35
  AgentresError: () => AgentresError,
36
+ AgentresPathError: () => AgentresPathError,
36
37
  AnumaJsxError: () => AnumaJsxError,
37
38
  CONNECTOR_ERROR_MARKER: () => CONNECTOR_ERROR_MARKER,
38
39
  CREATE_DOCUMENT_SCHEMA: () => CREATE_DOCUMENT_SCHEMA,
@@ -83,6 +84,7 @@ __export(index_exports, {
83
84
  createChartTool: () => createChartTool,
84
85
  createChatTools: () => createChatTools,
85
86
  createChoiceTool: () => createChoiceTool,
87
+ createConfirmTool: () => createConfirmTool,
86
88
  createConnectorOfferTool: () => createConnectorOfferTool,
87
89
  createConnectorTokenGetter: () => createConnectorTokenGetter,
88
90
  createDisplayTool: () => createDisplayTool,
@@ -833,6 +835,76 @@ function createChoiceTool(options) {
833
835
  });
834
836
  }
835
837
 
838
+ // src/tools/confirm.ts
839
+ function createConfirmTool(options) {
840
+ return createInteractiveTool(options, {
841
+ name: "prompt_user_confirm",
842
+ description: "Ask the user to approve a specific action before it happens. Use before anything that spends money or is hard to undo, such as booking a restaurant table or placing an order. List every parameter of the action, with the exact values you are about to use \u2014 the user approves what this card shows, and nothing else. Returns whether they confirmed. Do not use for ordinary yes/no questions; use prompt_user_choice for those.",
843
+ parameters: {
844
+ type: "object",
845
+ properties: {
846
+ title: {
847
+ type: "string",
848
+ description: "Short heading naming the action, e.g. 'Confirm your reservation'"
849
+ },
850
+ description: {
851
+ type: "string",
852
+ description: "Optional extra context, e.g. the cancellation policy"
853
+ },
854
+ action: {
855
+ type: "string",
856
+ description: "Machine-readable id of the action being confirmed, matching the tool that will carry it out, e.g. 'book_restaurant'"
857
+ },
858
+ parameters: {
859
+ type: "array",
860
+ items: {
861
+ type: "object",
862
+ properties: {
863
+ name: {
864
+ type: "string",
865
+ description: "Argument name of the acting tool, e.g. 'party_size'"
866
+ },
867
+ label: {
868
+ type: "string",
869
+ description: "Display label shown to the user, e.g. 'Party size'"
870
+ },
871
+ value: {
872
+ type: "string",
873
+ description: "The exact value you will use, as a string. Not a paraphrase \u2014 this is what the user is agreeing to."
874
+ }
875
+ },
876
+ required: ["name", "label", "value"]
877
+ },
878
+ description: "Every parameter of the action, with the exact values. The user sees these and nothing else."
879
+ }
880
+ },
881
+ required: ["title", "action", "parameters"]
882
+ },
883
+ interactionType: "confirm",
884
+ validate: (args) => {
885
+ const { title, action, parameters } = args;
886
+ if (typeof title !== "string" || !title) return false;
887
+ if (typeof action !== "string" || !action) return false;
888
+ if (!Array.isArray(parameters) || parameters.length === 0) return false;
889
+ return parameters.every((parameter) => {
890
+ return typeof parameter?.name === "string" && !!parameter.name && typeof parameter.label === "string" && !!parameter.label && typeof parameter.value === "string";
891
+ });
892
+ },
893
+ mapResult: (result, args) => {
894
+ if (typeof result.confirmed !== "boolean") return { cancelled: true };
895
+ return {
896
+ confirmed: result.confirmed,
897
+ // From the arguments rather than from the card's reply. The card was
898
+ // handed these to render, so echoing them back would only create a
899
+ // second copy that could disagree with what was on screen.
900
+ action: args.action,
901
+ parameters: args.parameters,
902
+ answeredAt: (/* @__PURE__ */ new Date()).toISOString()
903
+ };
904
+ }
905
+ });
906
+ }
907
+
836
908
  // src/tools/form.ts
837
909
  var VALID_FIELD_TYPES = [
838
910
  "text",
@@ -2571,6 +2643,12 @@ var SiwxUnsupportedError = class extends Error {
2571
2643
  this.name = "SiwxUnsupportedError";
2572
2644
  }
2573
2645
  };
2646
+ var AgentresPathError = class extends Error {
2647
+ constructor(message) {
2648
+ super(message);
2649
+ this.name = "AgentresPathError";
2650
+ }
2651
+ };
2574
2652
  var SiwxChallengeError = class extends Error {
2575
2653
  constructor(message, options) {
2576
2654
  super(message);
@@ -2648,6 +2726,7 @@ var PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED";
2648
2726
  var SIWX_HEADER = "SIGN-IN-WITH-X";
2649
2727
  var SIWX_EXTENSION = "sign-in-with-x";
2650
2728
  var SOLANA_NAMESPACE = "solana:";
2729
+ var ED25519_SIGNATURE_BYTES = 64;
2651
2730
  function parseChallenge(paymentRequiredHeader, expectedOrigin) {
2652
2731
  const decoded = decodeHeader(paymentRequiredHeader);
2653
2732
  const extensions = asRecord(decoded.extensions);
@@ -2719,6 +2798,11 @@ Resources:
2719
2798
  ${resources}`;
2720
2799
  }
2721
2800
  function buildPayload(challenge, address, signature) {
2801
+ if (signature.length !== ED25519_SIGNATURE_BYTES) {
2802
+ throw new SiwxChallengeError(
2803
+ `expected a ${ED25519_SIGNATURE_BYTES}-byte ed25519 signature, got ${signature.length} bytes`
2804
+ );
2805
+ }
2722
2806
  const payload = {
2723
2807
  domain: challenge.domain,
2724
2808
  address,
@@ -2821,7 +2905,7 @@ function createAgentresClient(options) {
2821
2905
  const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
2822
2906
  const { address, signMessage } = options;
2823
2907
  async function withSiwx(request) {
2824
- const url = `${baseUrl}${request.path}`;
2908
+ const url = resolveUrl(baseUrl, request.path);
2825
2909
  const init = requestInit(request);
2826
2910
  const challenged = await fetchImpl(url, init);
2827
2911
  if (challenged.status !== 402) {
@@ -2876,6 +2960,21 @@ function createAgentresClient(options) {
2876
2960
  }
2877
2961
  };
2878
2962
  }
2963
+ function resolveUrl(baseUrl, path) {
2964
+ if (!path.startsWith("/") || path.startsWith("//")) {
2965
+ throw new AgentresPathError(
2966
+ `"${path}" is not a path on ${baseUrl} \u2014 it must start with a single "/"`
2967
+ );
2968
+ }
2969
+ const base = new URL(baseUrl);
2970
+ const resolved = new URL(path, base);
2971
+ if (resolved.origin !== base.origin) {
2972
+ throw new AgentresPathError(
2973
+ `"${path}" resolves to ${resolved.origin} but this client talks to ${base.origin} \u2014 refusing to send it`
2974
+ );
2975
+ }
2976
+ return resolved.toString();
2977
+ }
2879
2978
  function requestInit(request) {
2880
2979
  const headers = { Accept: "application/json" };
2881
2980
  if (request.body === void 0) {
@@ -2889,7 +2988,16 @@ async function readBody(response) {
2889
2988
  if (!response.ok) {
2890
2989
  throw parseAgentresError(response.status, body);
2891
2990
  }
2892
- return JSON.parse(body);
2991
+ try {
2992
+ return JSON.parse(body);
2993
+ } catch {
2994
+ throw new AgentresError(
2995
+ response.status,
2996
+ "INVALID_JSON",
2997
+ `agentres answered ${response.status} with a body that is not JSON`,
2998
+ response.status >= 500
2999
+ );
3000
+ }
2893
3001
  }
2894
3002
 
2895
3003
  // src/lib/connectors/client.ts
@@ -14019,6 +14127,7 @@ function createDocumentTools({
14019
14127
  APP_PREVIEW_BASELINE_CSS,
14020
14128
  AUDIT_DESIGN_SCHEMA,
14021
14129
  AgentresError,
14130
+ AgentresPathError,
14022
14131
  AnumaJsxError,
14023
14132
  CONNECTOR_ERROR_MARKER,
14024
14133
  CREATE_DOCUMENT_SCHEMA,
@@ -14069,6 +14178,7 @@ function createDocumentTools({
14069
14178
  createChartTool,
14070
14179
  createChatTools,
14071
14180
  createChoiceTool,
14181
+ createConfirmTool,
14072
14182
  createConnectorOfferTool,
14073
14183
  createConnectorTokenGetter,
14074
14184
  createDisplayTool,
@@ -366,6 +366,99 @@ type ChoiceOption = {
366
366
  */
367
367
  declare function createChoiceTool(options: CreateUIToolsOptions): ToolConfig;
368
368
 
369
+ /**
370
+ * Confirmation interaction tool factory.
371
+ *
372
+ * Creates a client-side tool that shows the user exactly what is about to
373
+ * happen and blocks until they answer. Built for actions that are expensive to
374
+ * undo — spending money, holding a table against someone's card — where the
375
+ * model's own belief that the user agreed is not good enough.
376
+ *
377
+ * ## What the result is for
378
+ *
379
+ * The portal gates the action on this tool's result: it refuses the acting tool
380
+ * unless a completed confirmation for the same thing is already in the turn. A
381
+ * bare `{ confirmed: true }` would not survive that, because the model writes
382
+ * the acting tool's arguments and could equally write a boolean that says the
383
+ * user agreed. So the result carries **the parameters themselves**, and the
384
+ * portal compares them against the acting tool's arguments field by field.
385
+ *
386
+ * The chain that makes it verifiable:
387
+ *
388
+ * 1. The model writes `action` and `parameters` as tool arguments.
389
+ * 2. The card renders those same values — not a paraphrase of them.
390
+ * 3. The user answers the card, and the SDK (not the model) builds the result.
391
+ * 4. The portal compares the result's `parameters` to the acting tool's
392
+ * arguments, and refuses on any mismatch.
393
+ *
394
+ * A model that wants to book something other than what the user saw has to get
395
+ * step 4 past a field-by-field comparison, which is why the values are plain
396
+ * strings: two renderings of the same number must not read as a disagreement.
397
+ *
398
+ * ## The three outcomes
399
+ *
400
+ * | Outcome | Result |
401
+ * |---|---|
402
+ * | The user confirmed | `{ confirmed: true, action, parameters, answeredAt }` |
403
+ * | The user declined | `{ confirmed: false, action, parameters, answeredAt }` |
404
+ * | Timed out, cleared, never shown, or a malformed reply | `{ cancelled: true }` |
405
+ *
406
+ * A decline is an ordinary answer, not a failure — the model should say so and
407
+ * move on. Only the third row means nobody answered, and it is the shape every
408
+ * interactive tool in this module already produces for that case. A reply
409
+ * whose `confirmed` is not a boolean is not an answer either, so it lands there
410
+ * too rather than being reported as the user saying no.
411
+ *
412
+ * **The card must resolve the interaction for a decline, with
413
+ * `{ confirmed: false }` — not cancel it.** Cancelling rejects the underlying
414
+ * promise, which is indistinguishable from a timeout by the time it reaches
415
+ * here, and a decline would then be reported as nobody having answered.
416
+ */
417
+
418
+ /** One field of the action being confirmed, as the card shows it. */
419
+ type ConfirmParameter = {
420
+ /** Machine-readable key, matched against the acting tool's argument name. */
421
+ name: string;
422
+ /** Display label for the field, e.g. "Party size". */
423
+ label: string;
424
+ /** The exact value being confirmed. A string, so comparison is unambiguous. */
425
+ value: string;
426
+ };
427
+ /**
428
+ * What the tool returns: the user's answer, or `{ cancelled: true }` when
429
+ * nobody answered.
430
+ */
431
+ type ConfirmToolResult = {
432
+ /** True when the user agreed, false when they declined. */
433
+ confirmed: boolean;
434
+ /** The action that was confirmed, e.g. `book_restaurant`. */
435
+ action: string;
436
+ /** The parameters the card showed, verbatim — what the portal verifies. */
437
+ parameters: ConfirmParameter[];
438
+ /** ISO-8601 timestamp of the answer, for a server-side freshness window. */
439
+ answeredAt: string;
440
+ } | {
441
+ /** Timed out, cleared, never shown, or the card replied without a decision. */
442
+ cancelled: true;
443
+ };
444
+ /**
445
+ * Create a prompt_user_confirm tool that asks the user to approve an action.
446
+ *
447
+ * When the LLM calls this tool, it shows a summary card of exactly what is
448
+ * about to happen. Execution blocks until the user confirms or declines.
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * import { createConfirmTool } from "@anuma/sdk/tools";
453
+ *
454
+ * const confirmTool = createConfirmTool({
455
+ * getContext: () => uiInteraction,
456
+ * getLastMessageId: () => lastMsgId,
457
+ * });
458
+ * ```
459
+ */
460
+ declare function createConfirmTool(options: CreateUIToolsOptions): ToolConfig;
461
+
369
462
  /**
370
463
  * Form interaction tool factory.
371
464
  *
@@ -830,6 +923,8 @@ declare function createAgentresClient(options: AgentresClientOptions): AgentresC
830
923
  *
831
924
  * The SIWX errors are separate because they are ours, not the provider's: they
832
925
  * mean the challenge never became a usable proof, so no request was authorized.
926
+ * {@link AgentresPathError} is ours too, and earlier still — it means the call
927
+ * was refused before it was ever made.
833
928
  *
834
929
  * @module lib/connectors/agentres/errors
835
930
  */
@@ -863,6 +958,16 @@ declare class AgentresError extends Error {
863
958
  declare class SiwxUnsupportedError extends Error {
864
959
  constructor(message: string);
865
960
  }
961
+ /**
962
+ * The request path would have sent the call somewhere other than agentres.
963
+ *
964
+ * Thrown before the first fetch, because the first fetch is already the damage:
965
+ * it carries the caller's headers to whatever host the path resolved to, and
966
+ * the 402 that comes back is the challenge we are about to sign.
967
+ */
968
+ declare class AgentresPathError extends Error {
969
+ constructor(message: string);
970
+ }
866
971
  /** The challenge could not be read, or is missing something the proof needs. */
867
972
  declare class SiwxChallengeError extends Error {
868
973
  /** The underlying decode failure, when there was one. */
@@ -3015,4 +3120,4 @@ declare const DEFAULT_MAX_DOCUMENT_CONVERSATIONS = 1000;
3015
3120
  */
3016
3121
  declare function createDocumentTools({ getConversationId, storage, logError, displayDocument, maxConversations, }: CreateDocumentToolsOptions): ToolConfig[];
3017
3122
 
3018
- export { ADD_SLIDE_SCHEMA, APP_BUILDER_PROMPT, APP_COMPLETE_CONNECT_ACK_TYPE, APP_COMPLETE_CONNECT_TYPE, APP_COMPLETE_DEFAULT_TIMEOUT_MS, APP_COMPLETE_IFRAME_SHIM_SCRIPT, APP_COMPLETE_REQUEST_TYPE, APP_COMPLETE_RESPONSE_TYPE, APP_COMPLETE_STUB_SCRIPT, APP_FILE_TOOL_NAMES, APP_PREVIEW_BASELINE_CSS, AUDIT_DESIGN_SCHEMA, type AgentresAccount, type AgentresClient, type AgentresClientOptions, AgentresError, type AgentresErrorCode, type AgentresLinkStatus, type AgentresLinkStep, type AnchorMatch, type AnumaChild, AnumaJsxError, type AnumaNode, type AppCompleteBridge, type AppCompleteBridgeOptions, type AppFileRecord, type AppFileStorage, type AttrValue, type AuditIssue, type AuditIssueType, type AuditResult, type AuditSeverity, type AuditTokens, type BuildSlideSystemPromptOptions, CONNECTOR_ERROR_MARKER, CREATE_DOCUMENT_SCHEMA, CREATE_FILE_SCHEMA, CRITIQUE_DESIGN_SCHEMA, type CalendarEvent, type ChartDataPoint, type ChoiceOption, type ConnectorErrorCode, type ConnectorMintError, type ConnectorMintResult, type ConnectorTokenGetterOpts, type ConnectorTokenSource, type CreateAppGenerationToolsOptions, type CreateDocumentToolsOptions, type CreateEventArgs, type CreateFileArgs, type CreateSlideToolsOptions, type CreateUIToolsOptions, type CreateWeatherToolOptions, DEFAULT_DESIGN_CRITIQUE_RUBRIC, DEFAULT_DOCUMENT_ID, DEFAULT_MAX_CONVERSATIONS, DEFAULT_MAX_DOCUMENT_CONVERSATIONS, DELETE_FILE_SCHEMA, DOCUMENT_BUILDER_PROMPT, DOCUMENT_TOOL_NAMES, type DisplayChartResult, type DisplayConnectorResult, type DisplayPhoneCallOfferResult, type DisplayToolConfig, type DisplayToolMigrations, type DisplayWeatherResult, type DocAttrValue, type DocChild, DocDslError, type DocNode, type DriveFile, type DropboxRequestAccess, type DropboxTokenGetter, type ExportAppOptions, FONT_LIBRARY, FONT_PRESETS, type FileChangeEvent, type FileSnippet, type FontCategory, type FontPreset, type FontSpec, type ForecastDay, type FormField, type FormFieldOption, type FormFieldType, type GetFileContentArgs, type GmailGetMessageArgs, type GmailMessageDetail, type GmailMessageSummary, type GmailRequestAccess, type GmailSearchArgs, type GmailSendMessageArgs, type GmailTokenGetter, type InteractiveToolConfig, type KnownTag, LAYOUT_MODES, LIST_FILES_SCHEMA, type LayoutMode, type LegacyDeckJson, type ListEventsArgs, type ListRecentFilesArgs, MapFileStorage, type NotionCreatePagesArgs, type NotionFetchArgs, type NotionMovePagesArgs, type NotionSearchArgs, type NotionUpdatePageArgs, PATCH_DOCUMENT_SCHEMA, PATCH_FILE_SCHEMA, PATCH_SLIDES_SCHEMA, PLAN_DECK_SCHEMA, type PatchFailure, type PatchFailureReason, type PdfTag, READ_DOCUMENT_SCHEMA, READ_FILE_SCHEMA, READ_SLIDES_SCHEMA, RUNTIME_ERROR_OVERLAY_SCRIPT, SLIDES_FILE_PATH, SLIDE_CANVAS_HEIGHT, SLIDE_CANVAS_WIDTH, type SearchFilesArgs, SiwxChallengeError, SiwxUnsupportedError, type SlackGetChannelHistoryArgs, type SlackGetThreadRepliesArgs, type SlackListChannelsArgs, type SlackListDmsArgs, type SlackListUsersArgs, type SlackPostMessageArgs, type SlackProxyCaller, type SlackSearchMessagesArgs, type SlideToolSet, type SolanaSignMessageFn, THEME_ATTRS, type ThemeAttr, type ToolConfig, type ToolExecutionErrorType, type ToolExecutionResult, type UIInteractionContext, type UpdateEventArgs, type UpdateFileArgs, VERIFY_APP_SCHEMA, type VerifyAppResult, type XGetMeArgs, type XGetMyPostsArgs, type XProxyCaller, applyPatches, auditDesign, buildAppFileManifest, buildAppSystemPrompt, buildConnectorErrorResult, buildDocumentSystemPrompt, buildFontsUrl, buildSlideSystemPrompt, callNotionMCPTool, connectorMintErrorToToolResult, convertLegacyDeckJson, createAgentresClient, createAppCompleteBridge, createAppGenerationTools, createChartTool, createChatTools, createChoiceTool, createConnectorOfferTool, createConnectorTokenGetter, createDisplayTool, createDocumentTools, createDriveTools, createDropboxTools, createFormTool, createGitHubTools, createGmailTools, createGoogleCalendarCreateEventTool, createGoogleCalendarTool, createGoogleCalendarUpdateEventTool, createGoogleDriveCreateFileTool, createGoogleDriveGetContentTool, createGoogleDriveListRecentTool, createGoogleDriveSearchTool, createGoogleDriveUpdateFileTool, createInteractiveTool, createNotionCreateCommentTool, createNotionCreateDatabaseTool, createNotionCreatePagesTool, createNotionDuplicatePageTool, createNotionFetchTool, createNotionGetCommentsTool, createNotionGetTeamsTool, createNotionGetUsersTool, createNotionMovePagesTool, createNotionSearchTool, createNotionTools, createNotionUpdateDataSourceTool, createNotionUpdatePageTool, createPhoneCallOfferTool, createSlackTools, createSlideTools, createWeatherTool, createXTools, documentPath, exportAppToHtml, findById, findParentOfId, getFontByName, getId, getMCPEndpoints, getNumberAttr, getStringAttr, insertAfterId, insertChild, installAppCompleteIframeShim, isAnumaTag, isHtmlTag, isKnownFont, isLegacyDeckJson, isPdfTag, migrateDisplayResult, normalizePath, parseDocumentDsl, parseJsx, pdfStyleKeys, pdfTags, removeById, replaceById, serializeJsx, truncateContent, updateAttrs, walk };
3123
+ export { ADD_SLIDE_SCHEMA, APP_BUILDER_PROMPT, APP_COMPLETE_CONNECT_ACK_TYPE, APP_COMPLETE_CONNECT_TYPE, APP_COMPLETE_DEFAULT_TIMEOUT_MS, APP_COMPLETE_IFRAME_SHIM_SCRIPT, APP_COMPLETE_REQUEST_TYPE, APP_COMPLETE_RESPONSE_TYPE, APP_COMPLETE_STUB_SCRIPT, APP_FILE_TOOL_NAMES, APP_PREVIEW_BASELINE_CSS, AUDIT_DESIGN_SCHEMA, type AgentresAccount, type AgentresClient, type AgentresClientOptions, AgentresError, type AgentresErrorCode, type AgentresLinkStatus, type AgentresLinkStep, AgentresPathError, type AnchorMatch, type AnumaChild, AnumaJsxError, type AnumaNode, type AppCompleteBridge, type AppCompleteBridgeOptions, type AppFileRecord, type AppFileStorage, type AttrValue, type AuditIssue, type AuditIssueType, type AuditResult, type AuditSeverity, type AuditTokens, type BuildSlideSystemPromptOptions, CONNECTOR_ERROR_MARKER, CREATE_DOCUMENT_SCHEMA, CREATE_FILE_SCHEMA, CRITIQUE_DESIGN_SCHEMA, type CalendarEvent, type ChartDataPoint, type ChoiceOption, type ConfirmParameter, type ConfirmToolResult, type ConnectorErrorCode, type ConnectorMintError, type ConnectorMintResult, type ConnectorTokenGetterOpts, type ConnectorTokenSource, type CreateAppGenerationToolsOptions, type CreateDocumentToolsOptions, type CreateEventArgs, type CreateFileArgs, type CreateSlideToolsOptions, type CreateUIToolsOptions, type CreateWeatherToolOptions, DEFAULT_DESIGN_CRITIQUE_RUBRIC, DEFAULT_DOCUMENT_ID, DEFAULT_MAX_CONVERSATIONS, DEFAULT_MAX_DOCUMENT_CONVERSATIONS, DELETE_FILE_SCHEMA, DOCUMENT_BUILDER_PROMPT, DOCUMENT_TOOL_NAMES, type DisplayChartResult, type DisplayConnectorResult, type DisplayPhoneCallOfferResult, type DisplayToolConfig, type DisplayToolMigrations, type DisplayWeatherResult, type DocAttrValue, type DocChild, DocDslError, type DocNode, type DriveFile, type DropboxRequestAccess, type DropboxTokenGetter, type ExportAppOptions, FONT_LIBRARY, FONT_PRESETS, type FileChangeEvent, type FileSnippet, type FontCategory, type FontPreset, type FontSpec, type ForecastDay, type FormField, type FormFieldOption, type FormFieldType, type GetFileContentArgs, type GmailGetMessageArgs, type GmailMessageDetail, type GmailMessageSummary, type GmailRequestAccess, type GmailSearchArgs, type GmailSendMessageArgs, type GmailTokenGetter, type InteractiveToolConfig, type KnownTag, LAYOUT_MODES, LIST_FILES_SCHEMA, type LayoutMode, type LegacyDeckJson, type ListEventsArgs, type ListRecentFilesArgs, MapFileStorage, type NotionCreatePagesArgs, type NotionFetchArgs, type NotionMovePagesArgs, type NotionSearchArgs, type NotionUpdatePageArgs, PATCH_DOCUMENT_SCHEMA, PATCH_FILE_SCHEMA, PATCH_SLIDES_SCHEMA, PLAN_DECK_SCHEMA, type PatchFailure, type PatchFailureReason, type PdfTag, READ_DOCUMENT_SCHEMA, READ_FILE_SCHEMA, READ_SLIDES_SCHEMA, RUNTIME_ERROR_OVERLAY_SCRIPT, SLIDES_FILE_PATH, SLIDE_CANVAS_HEIGHT, SLIDE_CANVAS_WIDTH, type SearchFilesArgs, SiwxChallengeError, SiwxUnsupportedError, type SlackGetChannelHistoryArgs, type SlackGetThreadRepliesArgs, type SlackListChannelsArgs, type SlackListDmsArgs, type SlackListUsersArgs, type SlackPostMessageArgs, type SlackProxyCaller, type SlackSearchMessagesArgs, type SlideToolSet, type SolanaSignMessageFn, THEME_ATTRS, type ThemeAttr, type ToolConfig, type ToolExecutionErrorType, type ToolExecutionResult, type UIInteractionContext, type UpdateEventArgs, type UpdateFileArgs, VERIFY_APP_SCHEMA, type VerifyAppResult, type XGetMeArgs, type XGetMyPostsArgs, type XProxyCaller, applyPatches, auditDesign, buildAppFileManifest, buildAppSystemPrompt, buildConnectorErrorResult, buildDocumentSystemPrompt, buildFontsUrl, buildSlideSystemPrompt, callNotionMCPTool, connectorMintErrorToToolResult, convertLegacyDeckJson, createAgentresClient, createAppCompleteBridge, createAppGenerationTools, createChartTool, createChatTools, createChoiceTool, createConfirmTool, createConnectorOfferTool, createConnectorTokenGetter, createDisplayTool, createDocumentTools, createDriveTools, createDropboxTools, createFormTool, createGitHubTools, createGmailTools, createGoogleCalendarCreateEventTool, createGoogleCalendarTool, createGoogleCalendarUpdateEventTool, createGoogleDriveCreateFileTool, createGoogleDriveGetContentTool, createGoogleDriveListRecentTool, createGoogleDriveSearchTool, createGoogleDriveUpdateFileTool, createInteractiveTool, createNotionCreateCommentTool, createNotionCreateDatabaseTool, createNotionCreatePagesTool, createNotionDuplicatePageTool, createNotionFetchTool, createNotionGetCommentsTool, createNotionGetTeamsTool, createNotionGetUsersTool, createNotionMovePagesTool, createNotionSearchTool, createNotionTools, createNotionUpdateDataSourceTool, createNotionUpdatePageTool, createPhoneCallOfferTool, createSlackTools, createSlideTools, createWeatherTool, createXTools, documentPath, exportAppToHtml, findById, findParentOfId, getFontByName, getId, getMCPEndpoints, getNumberAttr, getStringAttr, insertAfterId, insertChild, installAppCompleteIframeShim, isAnumaTag, isHtmlTag, isKnownFont, isLegacyDeckJson, isPdfTag, migrateDisplayResult, normalizePath, parseDocumentDsl, parseJsx, pdfStyleKeys, pdfTags, removeById, replaceById, serializeJsx, truncateContent, updateAttrs, walk };
@@ -366,6 +366,99 @@ type ChoiceOption = {
366
366
  */
367
367
  declare function createChoiceTool(options: CreateUIToolsOptions): ToolConfig;
368
368
 
369
+ /**
370
+ * Confirmation interaction tool factory.
371
+ *
372
+ * Creates a client-side tool that shows the user exactly what is about to
373
+ * happen and blocks until they answer. Built for actions that are expensive to
374
+ * undo — spending money, holding a table against someone's card — where the
375
+ * model's own belief that the user agreed is not good enough.
376
+ *
377
+ * ## What the result is for
378
+ *
379
+ * The portal gates the action on this tool's result: it refuses the acting tool
380
+ * unless a completed confirmation for the same thing is already in the turn. A
381
+ * bare `{ confirmed: true }` would not survive that, because the model writes
382
+ * the acting tool's arguments and could equally write a boolean that says the
383
+ * user agreed. So the result carries **the parameters themselves**, and the
384
+ * portal compares them against the acting tool's arguments field by field.
385
+ *
386
+ * The chain that makes it verifiable:
387
+ *
388
+ * 1. The model writes `action` and `parameters` as tool arguments.
389
+ * 2. The card renders those same values — not a paraphrase of them.
390
+ * 3. The user answers the card, and the SDK (not the model) builds the result.
391
+ * 4. The portal compares the result's `parameters` to the acting tool's
392
+ * arguments, and refuses on any mismatch.
393
+ *
394
+ * A model that wants to book something other than what the user saw has to get
395
+ * step 4 past a field-by-field comparison, which is why the values are plain
396
+ * strings: two renderings of the same number must not read as a disagreement.
397
+ *
398
+ * ## The three outcomes
399
+ *
400
+ * | Outcome | Result |
401
+ * |---|---|
402
+ * | The user confirmed | `{ confirmed: true, action, parameters, answeredAt }` |
403
+ * | The user declined | `{ confirmed: false, action, parameters, answeredAt }` |
404
+ * | Timed out, cleared, never shown, or a malformed reply | `{ cancelled: true }` |
405
+ *
406
+ * A decline is an ordinary answer, not a failure — the model should say so and
407
+ * move on. Only the third row means nobody answered, and it is the shape every
408
+ * interactive tool in this module already produces for that case. A reply
409
+ * whose `confirmed` is not a boolean is not an answer either, so it lands there
410
+ * too rather than being reported as the user saying no.
411
+ *
412
+ * **The card must resolve the interaction for a decline, with
413
+ * `{ confirmed: false }` — not cancel it.** Cancelling rejects the underlying
414
+ * promise, which is indistinguishable from a timeout by the time it reaches
415
+ * here, and a decline would then be reported as nobody having answered.
416
+ */
417
+
418
+ /** One field of the action being confirmed, as the card shows it. */
419
+ type ConfirmParameter = {
420
+ /** Machine-readable key, matched against the acting tool's argument name. */
421
+ name: string;
422
+ /** Display label for the field, e.g. "Party size". */
423
+ label: string;
424
+ /** The exact value being confirmed. A string, so comparison is unambiguous. */
425
+ value: string;
426
+ };
427
+ /**
428
+ * What the tool returns: the user's answer, or `{ cancelled: true }` when
429
+ * nobody answered.
430
+ */
431
+ type ConfirmToolResult = {
432
+ /** True when the user agreed, false when they declined. */
433
+ confirmed: boolean;
434
+ /** The action that was confirmed, e.g. `book_restaurant`. */
435
+ action: string;
436
+ /** The parameters the card showed, verbatim — what the portal verifies. */
437
+ parameters: ConfirmParameter[];
438
+ /** ISO-8601 timestamp of the answer, for a server-side freshness window. */
439
+ answeredAt: string;
440
+ } | {
441
+ /** Timed out, cleared, never shown, or the card replied without a decision. */
442
+ cancelled: true;
443
+ };
444
+ /**
445
+ * Create a prompt_user_confirm tool that asks the user to approve an action.
446
+ *
447
+ * When the LLM calls this tool, it shows a summary card of exactly what is
448
+ * about to happen. Execution blocks until the user confirms or declines.
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * import { createConfirmTool } from "@anuma/sdk/tools";
453
+ *
454
+ * const confirmTool = createConfirmTool({
455
+ * getContext: () => uiInteraction,
456
+ * getLastMessageId: () => lastMsgId,
457
+ * });
458
+ * ```
459
+ */
460
+ declare function createConfirmTool(options: CreateUIToolsOptions): ToolConfig;
461
+
369
462
  /**
370
463
  * Form interaction tool factory.
371
464
  *
@@ -830,6 +923,8 @@ declare function createAgentresClient(options: AgentresClientOptions): AgentresC
830
923
  *
831
924
  * The SIWX errors are separate because they are ours, not the provider's: they
832
925
  * mean the challenge never became a usable proof, so no request was authorized.
926
+ * {@link AgentresPathError} is ours too, and earlier still — it means the call
927
+ * was refused before it was ever made.
833
928
  *
834
929
  * @module lib/connectors/agentres/errors
835
930
  */
@@ -863,6 +958,16 @@ declare class AgentresError extends Error {
863
958
  declare class SiwxUnsupportedError extends Error {
864
959
  constructor(message: string);
865
960
  }
961
+ /**
962
+ * The request path would have sent the call somewhere other than agentres.
963
+ *
964
+ * Thrown before the first fetch, because the first fetch is already the damage:
965
+ * it carries the caller's headers to whatever host the path resolved to, and
966
+ * the 402 that comes back is the challenge we are about to sign.
967
+ */
968
+ declare class AgentresPathError extends Error {
969
+ constructor(message: string);
970
+ }
866
971
  /** The challenge could not be read, or is missing something the proof needs. */
867
972
  declare class SiwxChallengeError extends Error {
868
973
  /** The underlying decode failure, when there was one. */
@@ -3015,4 +3120,4 @@ declare const DEFAULT_MAX_DOCUMENT_CONVERSATIONS = 1000;
3015
3120
  */
3016
3121
  declare function createDocumentTools({ getConversationId, storage, logError, displayDocument, maxConversations, }: CreateDocumentToolsOptions): ToolConfig[];
3017
3122
 
3018
- export { ADD_SLIDE_SCHEMA, APP_BUILDER_PROMPT, APP_COMPLETE_CONNECT_ACK_TYPE, APP_COMPLETE_CONNECT_TYPE, APP_COMPLETE_DEFAULT_TIMEOUT_MS, APP_COMPLETE_IFRAME_SHIM_SCRIPT, APP_COMPLETE_REQUEST_TYPE, APP_COMPLETE_RESPONSE_TYPE, APP_COMPLETE_STUB_SCRIPT, APP_FILE_TOOL_NAMES, APP_PREVIEW_BASELINE_CSS, AUDIT_DESIGN_SCHEMA, type AgentresAccount, type AgentresClient, type AgentresClientOptions, AgentresError, type AgentresErrorCode, type AgentresLinkStatus, type AgentresLinkStep, type AnchorMatch, type AnumaChild, AnumaJsxError, type AnumaNode, type AppCompleteBridge, type AppCompleteBridgeOptions, type AppFileRecord, type AppFileStorage, type AttrValue, type AuditIssue, type AuditIssueType, type AuditResult, type AuditSeverity, type AuditTokens, type BuildSlideSystemPromptOptions, CONNECTOR_ERROR_MARKER, CREATE_DOCUMENT_SCHEMA, CREATE_FILE_SCHEMA, CRITIQUE_DESIGN_SCHEMA, type CalendarEvent, type ChartDataPoint, type ChoiceOption, type ConnectorErrorCode, type ConnectorMintError, type ConnectorMintResult, type ConnectorTokenGetterOpts, type ConnectorTokenSource, type CreateAppGenerationToolsOptions, type CreateDocumentToolsOptions, type CreateEventArgs, type CreateFileArgs, type CreateSlideToolsOptions, type CreateUIToolsOptions, type CreateWeatherToolOptions, DEFAULT_DESIGN_CRITIQUE_RUBRIC, DEFAULT_DOCUMENT_ID, DEFAULT_MAX_CONVERSATIONS, DEFAULT_MAX_DOCUMENT_CONVERSATIONS, DELETE_FILE_SCHEMA, DOCUMENT_BUILDER_PROMPT, DOCUMENT_TOOL_NAMES, type DisplayChartResult, type DisplayConnectorResult, type DisplayPhoneCallOfferResult, type DisplayToolConfig, type DisplayToolMigrations, type DisplayWeatherResult, type DocAttrValue, type DocChild, DocDslError, type DocNode, type DriveFile, type DropboxRequestAccess, type DropboxTokenGetter, type ExportAppOptions, FONT_LIBRARY, FONT_PRESETS, type FileChangeEvent, type FileSnippet, type FontCategory, type FontPreset, type FontSpec, type ForecastDay, type FormField, type FormFieldOption, type FormFieldType, type GetFileContentArgs, type GmailGetMessageArgs, type GmailMessageDetail, type GmailMessageSummary, type GmailRequestAccess, type GmailSearchArgs, type GmailSendMessageArgs, type GmailTokenGetter, type InteractiveToolConfig, type KnownTag, LAYOUT_MODES, LIST_FILES_SCHEMA, type LayoutMode, type LegacyDeckJson, type ListEventsArgs, type ListRecentFilesArgs, MapFileStorage, type NotionCreatePagesArgs, type NotionFetchArgs, type NotionMovePagesArgs, type NotionSearchArgs, type NotionUpdatePageArgs, PATCH_DOCUMENT_SCHEMA, PATCH_FILE_SCHEMA, PATCH_SLIDES_SCHEMA, PLAN_DECK_SCHEMA, type PatchFailure, type PatchFailureReason, type PdfTag, READ_DOCUMENT_SCHEMA, READ_FILE_SCHEMA, READ_SLIDES_SCHEMA, RUNTIME_ERROR_OVERLAY_SCRIPT, SLIDES_FILE_PATH, SLIDE_CANVAS_HEIGHT, SLIDE_CANVAS_WIDTH, type SearchFilesArgs, SiwxChallengeError, SiwxUnsupportedError, type SlackGetChannelHistoryArgs, type SlackGetThreadRepliesArgs, type SlackListChannelsArgs, type SlackListDmsArgs, type SlackListUsersArgs, type SlackPostMessageArgs, type SlackProxyCaller, type SlackSearchMessagesArgs, type SlideToolSet, type SolanaSignMessageFn, THEME_ATTRS, type ThemeAttr, type ToolConfig, type ToolExecutionErrorType, type ToolExecutionResult, type UIInteractionContext, type UpdateEventArgs, type UpdateFileArgs, VERIFY_APP_SCHEMA, type VerifyAppResult, type XGetMeArgs, type XGetMyPostsArgs, type XProxyCaller, applyPatches, auditDesign, buildAppFileManifest, buildAppSystemPrompt, buildConnectorErrorResult, buildDocumentSystemPrompt, buildFontsUrl, buildSlideSystemPrompt, callNotionMCPTool, connectorMintErrorToToolResult, convertLegacyDeckJson, createAgentresClient, createAppCompleteBridge, createAppGenerationTools, createChartTool, createChatTools, createChoiceTool, createConnectorOfferTool, createConnectorTokenGetter, createDisplayTool, createDocumentTools, createDriveTools, createDropboxTools, createFormTool, createGitHubTools, createGmailTools, createGoogleCalendarCreateEventTool, createGoogleCalendarTool, createGoogleCalendarUpdateEventTool, createGoogleDriveCreateFileTool, createGoogleDriveGetContentTool, createGoogleDriveListRecentTool, createGoogleDriveSearchTool, createGoogleDriveUpdateFileTool, createInteractiveTool, createNotionCreateCommentTool, createNotionCreateDatabaseTool, createNotionCreatePagesTool, createNotionDuplicatePageTool, createNotionFetchTool, createNotionGetCommentsTool, createNotionGetTeamsTool, createNotionGetUsersTool, createNotionMovePagesTool, createNotionSearchTool, createNotionTools, createNotionUpdateDataSourceTool, createNotionUpdatePageTool, createPhoneCallOfferTool, createSlackTools, createSlideTools, createWeatherTool, createXTools, documentPath, exportAppToHtml, findById, findParentOfId, getFontByName, getId, getMCPEndpoints, getNumberAttr, getStringAttr, insertAfterId, insertChild, installAppCompleteIframeShim, isAnumaTag, isHtmlTag, isKnownFont, isLegacyDeckJson, isPdfTag, migrateDisplayResult, normalizePath, parseDocumentDsl, parseJsx, pdfStyleKeys, pdfTags, removeById, replaceById, serializeJsx, truncateContent, updateAttrs, walk };
3123
+ export { ADD_SLIDE_SCHEMA, APP_BUILDER_PROMPT, APP_COMPLETE_CONNECT_ACK_TYPE, APP_COMPLETE_CONNECT_TYPE, APP_COMPLETE_DEFAULT_TIMEOUT_MS, APP_COMPLETE_IFRAME_SHIM_SCRIPT, APP_COMPLETE_REQUEST_TYPE, APP_COMPLETE_RESPONSE_TYPE, APP_COMPLETE_STUB_SCRIPT, APP_FILE_TOOL_NAMES, APP_PREVIEW_BASELINE_CSS, AUDIT_DESIGN_SCHEMA, type AgentresAccount, type AgentresClient, type AgentresClientOptions, AgentresError, type AgentresErrorCode, type AgentresLinkStatus, type AgentresLinkStep, AgentresPathError, type AnchorMatch, type AnumaChild, AnumaJsxError, type AnumaNode, type AppCompleteBridge, type AppCompleteBridgeOptions, type AppFileRecord, type AppFileStorage, type AttrValue, type AuditIssue, type AuditIssueType, type AuditResult, type AuditSeverity, type AuditTokens, type BuildSlideSystemPromptOptions, CONNECTOR_ERROR_MARKER, CREATE_DOCUMENT_SCHEMA, CREATE_FILE_SCHEMA, CRITIQUE_DESIGN_SCHEMA, type CalendarEvent, type ChartDataPoint, type ChoiceOption, type ConfirmParameter, type ConfirmToolResult, type ConnectorErrorCode, type ConnectorMintError, type ConnectorMintResult, type ConnectorTokenGetterOpts, type ConnectorTokenSource, type CreateAppGenerationToolsOptions, type CreateDocumentToolsOptions, type CreateEventArgs, type CreateFileArgs, type CreateSlideToolsOptions, type CreateUIToolsOptions, type CreateWeatherToolOptions, DEFAULT_DESIGN_CRITIQUE_RUBRIC, DEFAULT_DOCUMENT_ID, DEFAULT_MAX_CONVERSATIONS, DEFAULT_MAX_DOCUMENT_CONVERSATIONS, DELETE_FILE_SCHEMA, DOCUMENT_BUILDER_PROMPT, DOCUMENT_TOOL_NAMES, type DisplayChartResult, type DisplayConnectorResult, type DisplayPhoneCallOfferResult, type DisplayToolConfig, type DisplayToolMigrations, type DisplayWeatherResult, type DocAttrValue, type DocChild, DocDslError, type DocNode, type DriveFile, type DropboxRequestAccess, type DropboxTokenGetter, type ExportAppOptions, FONT_LIBRARY, FONT_PRESETS, type FileChangeEvent, type FileSnippet, type FontCategory, type FontPreset, type FontSpec, type ForecastDay, type FormField, type FormFieldOption, type FormFieldType, type GetFileContentArgs, type GmailGetMessageArgs, type GmailMessageDetail, type GmailMessageSummary, type GmailRequestAccess, type GmailSearchArgs, type GmailSendMessageArgs, type GmailTokenGetter, type InteractiveToolConfig, type KnownTag, LAYOUT_MODES, LIST_FILES_SCHEMA, type LayoutMode, type LegacyDeckJson, type ListEventsArgs, type ListRecentFilesArgs, MapFileStorage, type NotionCreatePagesArgs, type NotionFetchArgs, type NotionMovePagesArgs, type NotionSearchArgs, type NotionUpdatePageArgs, PATCH_DOCUMENT_SCHEMA, PATCH_FILE_SCHEMA, PATCH_SLIDES_SCHEMA, PLAN_DECK_SCHEMA, type PatchFailure, type PatchFailureReason, type PdfTag, READ_DOCUMENT_SCHEMA, READ_FILE_SCHEMA, READ_SLIDES_SCHEMA, RUNTIME_ERROR_OVERLAY_SCRIPT, SLIDES_FILE_PATH, SLIDE_CANVAS_HEIGHT, SLIDE_CANVAS_WIDTH, type SearchFilesArgs, SiwxChallengeError, SiwxUnsupportedError, type SlackGetChannelHistoryArgs, type SlackGetThreadRepliesArgs, type SlackListChannelsArgs, type SlackListDmsArgs, type SlackListUsersArgs, type SlackPostMessageArgs, type SlackProxyCaller, type SlackSearchMessagesArgs, type SlideToolSet, type SolanaSignMessageFn, THEME_ATTRS, type ThemeAttr, type ToolConfig, type ToolExecutionErrorType, type ToolExecutionResult, type UIInteractionContext, type UpdateEventArgs, type UpdateFileArgs, VERIFY_APP_SCHEMA, type VerifyAppResult, type XGetMeArgs, type XGetMyPostsArgs, type XProxyCaller, applyPatches, auditDesign, buildAppFileManifest, buildAppSystemPrompt, buildConnectorErrorResult, buildDocumentSystemPrompt, buildFontsUrl, buildSlideSystemPrompt, callNotionMCPTool, connectorMintErrorToToolResult, convertLegacyDeckJson, createAgentresClient, createAppCompleteBridge, createAppGenerationTools, createChartTool, createChatTools, createChoiceTool, createConfirmTool, createConnectorOfferTool, createConnectorTokenGetter, createDisplayTool, createDocumentTools, createDriveTools, createDropboxTools, createFormTool, createGitHubTools, createGmailTools, createGoogleCalendarCreateEventTool, createGoogleCalendarTool, createGoogleCalendarUpdateEventTool, createGoogleDriveCreateFileTool, createGoogleDriveGetContentTool, createGoogleDriveListRecentTool, createGoogleDriveSearchTool, createGoogleDriveUpdateFileTool, createInteractiveTool, createNotionCreateCommentTool, createNotionCreateDatabaseTool, createNotionCreatePagesTool, createNotionDuplicatePageTool, createNotionFetchTool, createNotionGetCommentsTool, createNotionGetTeamsTool, createNotionGetUsersTool, createNotionMovePagesTool, createNotionSearchTool, createNotionTools, createNotionUpdateDataSourceTool, createNotionUpdatePageTool, createPhoneCallOfferTool, createSlackTools, createSlideTools, createWeatherTool, createXTools, documentPath, exportAppToHtml, findById, findParentOfId, getFontByName, getId, getMCPEndpoints, getNumberAttr, getStringAttr, insertAfterId, insertChild, installAppCompleteIframeShim, isAnumaTag, isHtmlTag, isKnownFont, isLegacyDeckJson, isPdfTag, migrateDisplayResult, normalizePath, parseDocumentDsl, parseJsx, pdfStyleKeys, pdfTags, removeById, replaceById, serializeJsx, truncateContent, updateAttrs, walk };
@@ -680,6 +680,76 @@ function createChoiceTool(options) {
680
680
  });
681
681
  }
682
682
 
683
+ // src/tools/confirm.ts
684
+ function createConfirmTool(options) {
685
+ return createInteractiveTool(options, {
686
+ name: "prompt_user_confirm",
687
+ description: "Ask the user to approve a specific action before it happens. Use before anything that spends money or is hard to undo, such as booking a restaurant table or placing an order. List every parameter of the action, with the exact values you are about to use \u2014 the user approves what this card shows, and nothing else. Returns whether they confirmed. Do not use for ordinary yes/no questions; use prompt_user_choice for those.",
688
+ parameters: {
689
+ type: "object",
690
+ properties: {
691
+ title: {
692
+ type: "string",
693
+ description: "Short heading naming the action, e.g. 'Confirm your reservation'"
694
+ },
695
+ description: {
696
+ type: "string",
697
+ description: "Optional extra context, e.g. the cancellation policy"
698
+ },
699
+ action: {
700
+ type: "string",
701
+ description: "Machine-readable id of the action being confirmed, matching the tool that will carry it out, e.g. 'book_restaurant'"
702
+ },
703
+ parameters: {
704
+ type: "array",
705
+ items: {
706
+ type: "object",
707
+ properties: {
708
+ name: {
709
+ type: "string",
710
+ description: "Argument name of the acting tool, e.g. 'party_size'"
711
+ },
712
+ label: {
713
+ type: "string",
714
+ description: "Display label shown to the user, e.g. 'Party size'"
715
+ },
716
+ value: {
717
+ type: "string",
718
+ description: "The exact value you will use, as a string. Not a paraphrase \u2014 this is what the user is agreeing to."
719
+ }
720
+ },
721
+ required: ["name", "label", "value"]
722
+ },
723
+ description: "Every parameter of the action, with the exact values. The user sees these and nothing else."
724
+ }
725
+ },
726
+ required: ["title", "action", "parameters"]
727
+ },
728
+ interactionType: "confirm",
729
+ validate: (args) => {
730
+ const { title, action, parameters } = args;
731
+ if (typeof title !== "string" || !title) return false;
732
+ if (typeof action !== "string" || !action) return false;
733
+ if (!Array.isArray(parameters) || parameters.length === 0) return false;
734
+ return parameters.every((parameter) => {
735
+ return typeof parameter?.name === "string" && !!parameter.name && typeof parameter.label === "string" && !!parameter.label && typeof parameter.value === "string";
736
+ });
737
+ },
738
+ mapResult: (result, args) => {
739
+ if (typeof result.confirmed !== "boolean") return { cancelled: true };
740
+ return {
741
+ confirmed: result.confirmed,
742
+ // From the arguments rather than from the card's reply. The card was
743
+ // handed these to render, so echoing them back would only create a
744
+ // second copy that could disagree with what was on screen.
745
+ action: args.action,
746
+ parameters: args.parameters,
747
+ answeredAt: (/* @__PURE__ */ new Date()).toISOString()
748
+ };
749
+ }
750
+ });
751
+ }
752
+
683
753
  // src/tools/form.ts
684
754
  var VALID_FIELD_TYPES = [
685
755
  "text",
@@ -2418,6 +2488,12 @@ var SiwxUnsupportedError = class extends Error {
2418
2488
  this.name = "SiwxUnsupportedError";
2419
2489
  }
2420
2490
  };
2491
+ var AgentresPathError = class extends Error {
2492
+ constructor(message) {
2493
+ super(message);
2494
+ this.name = "AgentresPathError";
2495
+ }
2496
+ };
2421
2497
  var SiwxChallengeError = class extends Error {
2422
2498
  constructor(message, options) {
2423
2499
  super(message);
@@ -2495,6 +2571,7 @@ var PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED";
2495
2571
  var SIWX_HEADER = "SIGN-IN-WITH-X";
2496
2572
  var SIWX_EXTENSION = "sign-in-with-x";
2497
2573
  var SOLANA_NAMESPACE = "solana:";
2574
+ var ED25519_SIGNATURE_BYTES = 64;
2498
2575
  function parseChallenge(paymentRequiredHeader, expectedOrigin) {
2499
2576
  const decoded = decodeHeader(paymentRequiredHeader);
2500
2577
  const extensions = asRecord(decoded.extensions);
@@ -2566,6 +2643,11 @@ Resources:
2566
2643
  ${resources}`;
2567
2644
  }
2568
2645
  function buildPayload(challenge, address, signature) {
2646
+ if (signature.length !== ED25519_SIGNATURE_BYTES) {
2647
+ throw new SiwxChallengeError(
2648
+ `expected a ${ED25519_SIGNATURE_BYTES}-byte ed25519 signature, got ${signature.length} bytes`
2649
+ );
2650
+ }
2569
2651
  const payload = {
2570
2652
  domain: challenge.domain,
2571
2653
  address,
@@ -2668,7 +2750,7 @@ function createAgentresClient(options) {
2668
2750
  const fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
2669
2751
  const { address, signMessage } = options;
2670
2752
  async function withSiwx(request) {
2671
- const url = `${baseUrl}${request.path}`;
2753
+ const url = resolveUrl(baseUrl, request.path);
2672
2754
  const init = requestInit(request);
2673
2755
  const challenged = await fetchImpl(url, init);
2674
2756
  if (challenged.status !== 402) {
@@ -2723,6 +2805,21 @@ function createAgentresClient(options) {
2723
2805
  }
2724
2806
  };
2725
2807
  }
2808
+ function resolveUrl(baseUrl, path) {
2809
+ if (!path.startsWith("/") || path.startsWith("//")) {
2810
+ throw new AgentresPathError(
2811
+ `"${path}" is not a path on ${baseUrl} \u2014 it must start with a single "/"`
2812
+ );
2813
+ }
2814
+ const base = new URL(baseUrl);
2815
+ const resolved = new URL(path, base);
2816
+ if (resolved.origin !== base.origin) {
2817
+ throw new AgentresPathError(
2818
+ `"${path}" resolves to ${resolved.origin} but this client talks to ${base.origin} \u2014 refusing to send it`
2819
+ );
2820
+ }
2821
+ return resolved.toString();
2822
+ }
2726
2823
  function requestInit(request) {
2727
2824
  const headers = { Accept: "application/json" };
2728
2825
  if (request.body === void 0) {
@@ -2736,7 +2833,16 @@ async function readBody(response) {
2736
2833
  if (!response.ok) {
2737
2834
  throw parseAgentresError(response.status, body);
2738
2835
  }
2739
- return JSON.parse(body);
2836
+ try {
2837
+ return JSON.parse(body);
2838
+ } catch {
2839
+ throw new AgentresError(
2840
+ response.status,
2841
+ "INVALID_JSON",
2842
+ `agentres answered ${response.status} with a body that is not JSON`,
2843
+ response.status >= 500
2844
+ );
2845
+ }
2740
2846
  }
2741
2847
 
2742
2848
  // src/lib/connectors/client.ts
@@ -13865,6 +13971,7 @@ export {
13865
13971
  APP_PREVIEW_BASELINE_CSS,
13866
13972
  AUDIT_DESIGN_SCHEMA,
13867
13973
  AgentresError,
13974
+ AgentresPathError,
13868
13975
  AnumaJsxError,
13869
13976
  CONNECTOR_ERROR_MARKER,
13870
13977
  CREATE_DOCUMENT_SCHEMA,
@@ -13915,6 +14022,7 @@ export {
13915
14022
  createChartTool,
13916
14023
  createChatTools,
13917
14024
  createChoiceTool,
14025
+ createConfirmTool,
13918
14026
  createConnectorOfferTool,
13919
14027
  createConnectorTokenGetter,
13920
14028
  createDisplayTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "6.24.1",
3
+ "version": "6.25.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",