@anuma/sdk 6.24.0 → 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.
@@ -19459,6 +19459,7 @@ function createDurableAutoExtractor(options) {
19459
19459
  }
19460
19460
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
19461
19461
  let watchdog;
19462
+ const model = options.modelForScope?.(jobScope) ?? options.extract.model;
19462
19463
  try {
19463
19464
  return await Promise.race([
19464
19465
  new Promise((resolve, reject) => {
@@ -19471,6 +19472,8 @@ function createDurableAutoExtractor(options) {
19471
19472
  canWrite: async () => !disposed && await storage.conversationsCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb12.Q.where("conversation_id", conversationId), import_watermelondb12.Q.where("id", import_watermelondb12.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
19472
19473
  }
19473
19474
  },
19475
+ // The model follows the job's scope, not the mode alive at drain time.
19476
+ extract: { ...options.extract, ...model !== void 0 && { model } },
19474
19477
  // Never publish a private queued observation after a mode flip.
19475
19478
  scope: jobScope,
19476
19479
  folderId: jobFolderId,
@@ -9459,6 +9459,16 @@ interface DurableAutoExtractorOptions extends Omit<CreateAutoExtractorOptions, "
9459
9459
  * as `"private"` — the direction that cannot publish.
9460
9460
  */
9461
9461
  scope?: string | (() => string);
9462
+ /**
9463
+ * Extraction model for a batch, chosen from the scope that batch will be
9464
+ * retained under. A queued job keeps its scope across a privacy-mode flip but
9465
+ * `extract.model` is whatever this instance was built with, so without this a
9466
+ * turn queued in private mode is drained by a public-mode extractor on that
9467
+ * extractor's model. Returning `undefined` keeps `extract.model`. A resolver
9468
+ * that throws fails the batch, which stays queued for retry: guessing a model
9469
+ * is exactly the mistake this exists to prevent.
9470
+ */
9471
+ modelForScope?: (scope: string) => string | undefined;
9462
9472
  /** Coalesce arrivals after durably recording them. Defaults to 20 seconds. */
9463
9473
  debounceMs?: number;
9464
9474
  /** Retry delay for a failed batch. Defaults to 30 seconds; max three attempts
@@ -9459,6 +9459,16 @@ interface DurableAutoExtractorOptions extends Omit<CreateAutoExtractorOptions, "
9459
9459
  * as `"private"` — the direction that cannot publish.
9460
9460
  */
9461
9461
  scope?: string | (() => string);
9462
+ /**
9463
+ * Extraction model for a batch, chosen from the scope that batch will be
9464
+ * retained under. A queued job keeps its scope across a privacy-mode flip but
9465
+ * `extract.model` is whatever this instance was built with, so without this a
9466
+ * turn queued in private mode is drained by a public-mode extractor on that
9467
+ * extractor's model. Returning `undefined` keeps `extract.model`. A resolver
9468
+ * that throws fails the batch, which stays queued for retry: guessing a model
9469
+ * is exactly the mistake this exists to prevent.
9470
+ */
9471
+ modelForScope?: (scope: string) => string | undefined;
9462
9472
  /** Coalesce arrivals after durably recording them. Defaults to 20 seconds. */
9463
9473
  debounceMs?: number;
9464
9474
  /** Retry delay for a failed batch. Defaults to 30 seconds; max three attempts
@@ -9529,6 +9529,7 @@ function createDurableAutoExtractor(options) {
9529
9529
  }
9530
9530
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
9531
9531
  let watchdog;
9532
+ const model = options.modelForScope?.(jobScope) ?? options.extract.model;
9532
9533
  try {
9533
9534
  return await Promise.race([
9534
9535
  new Promise((resolve, reject) => {
@@ -9541,6 +9542,8 @@ function createDurableAutoExtractor(options) {
9541
9542
  canWrite: async () => !disposed && await storage.conversationsCollection.query(Q4.where("conversation_id", conversationId), Q4.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q4.where("conversation_id", conversationId), Q4.where("id", Q4.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
9542
9543
  }
9543
9544
  },
9545
+ // The model follows the job's scope, not the mode alive at drain time.
9546
+ extract: { ...options.extract, ...model !== void 0 && { model } },
9544
9547
  // Never publish a private queued observation after a mode flip.
9545
9548
  scope: jobScope,
9546
9549
  folderId: jobFolderId,
@@ -20763,6 +20763,7 @@ function createDurableAutoExtractor(options) {
20763
20763
  }
20764
20764
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
20765
20765
  let watchdog;
20766
+ const model = options.modelForScope?.(jobScope) ?? options.extract.model;
20766
20767
  try {
20767
20768
  return await Promise.race([
20768
20769
  new Promise((resolve, reject) => {
@@ -20775,6 +20776,8 @@ function createDurableAutoExtractor(options) {
20775
20776
  canWrite: async () => !disposed && await storage.conversationsCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb13.Q.where("conversation_id", conversationId), import_watermelondb13.Q.where("id", import_watermelondb13.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
20776
20777
  }
20777
20778
  },
20779
+ // The model follows the job's scope, not the mode alive at drain time.
20780
+ extract: { ...options.extract, ...model !== void 0 && { model } },
20778
20781
  // Never publish a private queued observation after a mode flip.
20779
20782
  scope: jobScope,
20780
20783
  folderId: jobFolderId,
@@ -10694,6 +10694,16 @@ interface DurableAutoExtractorOptions extends Omit<CreateAutoExtractorOptions, "
10694
10694
  * as `"private"` — the direction that cannot publish.
10695
10695
  */
10696
10696
  scope?: string | (() => string);
10697
+ /**
10698
+ * Extraction model for a batch, chosen from the scope that batch will be
10699
+ * retained under. A queued job keeps its scope across a privacy-mode flip but
10700
+ * `extract.model` is whatever this instance was built with, so without this a
10701
+ * turn queued in private mode is drained by a public-mode extractor on that
10702
+ * extractor's model. Returning `undefined` keeps `extract.model`. A resolver
10703
+ * that throws fails the batch, which stays queued for retry: guessing a model
10704
+ * is exactly the mistake this exists to prevent.
10705
+ */
10706
+ modelForScope?: (scope: string) => string | undefined;
10697
10707
  /** Coalesce arrivals after durably recording them. Defaults to 20 seconds. */
10698
10708
  debounceMs?: number;
10699
10709
  /** Retry delay for a failed batch. Defaults to 30 seconds; max three attempts
@@ -10694,6 +10694,16 @@ interface DurableAutoExtractorOptions extends Omit<CreateAutoExtractorOptions, "
10694
10694
  * as `"private"` — the direction that cannot publish.
10695
10695
  */
10696
10696
  scope?: string | (() => string);
10697
+ /**
10698
+ * Extraction model for a batch, chosen from the scope that batch will be
10699
+ * retained under. A queued job keeps its scope across a privacy-mode flip but
10700
+ * `extract.model` is whatever this instance was built with, so without this a
10701
+ * turn queued in private mode is drained by a public-mode extractor on that
10702
+ * extractor's model. Returning `undefined` keeps `extract.model`. A resolver
10703
+ * that throws fails the batch, which stays queued for retry: guessing a model
10704
+ * is exactly the mistake this exists to prevent.
10705
+ */
10706
+ modelForScope?: (scope: string) => string | undefined;
10697
10707
  /** Coalesce arrivals after durably recording them. Defaults to 20 seconds. */
10698
10708
  debounceMs?: number;
10699
10709
  /** Retry delay for a failed batch. Defaults to 30 seconds; max three attempts
@@ -10347,6 +10347,7 @@ function createDurableAutoExtractor(options) {
10347
10347
  }
10348
10348
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
10349
10349
  let watchdog;
10350
+ const model = options.modelForScope?.(jobScope) ?? options.extract.model;
10350
10351
  try {
10351
10352
  return await Promise.race([
10352
10353
  new Promise((resolve, reject) => {
@@ -10359,6 +10360,8 @@ function createDurableAutoExtractor(options) {
10359
10360
  canWrite: async () => !disposed && await storage.conversationsCollection.query(Q5.where("conversation_id", conversationId), Q5.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(Q5.where("conversation_id", conversationId), Q5.where("id", Q5.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
10360
10361
  }
10361
10362
  },
10363
+ // The model follows the job's scope, not the mode alive at drain time.
10364
+ extract: { ...options.extract, ...model !== void 0 && { model } },
10362
10365
  // Never publish a private queued observation after a mode flip.
10363
10366
  scope: jobScope,
10364
10367
  folderId: jobFolderId,
@@ -32401,6 +32401,7 @@ function createDurableAutoExtractor(options) {
32401
32401
  }
32402
32402
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
32403
32403
  let watchdog;
32404
+ const model = options.modelForScope?.(jobScope) ?? options.extract.model;
32404
32405
  try {
32405
32406
  return await Promise.race([
32406
32407
  new Promise((resolve, reject) => {
@@ -32413,6 +32414,8 @@ function createDurableAutoExtractor(options) {
32413
32414
  canWrite: async () => !disposed && await storage.conversationsCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb24.Q.where("conversation_id", conversationId), import_watermelondb24.Q.where("id", import_watermelondb24.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
32414
32415
  }
32415
32416
  },
32417
+ // The model follows the job's scope, not the mode alive at drain time.
32418
+ extract: { ...options.extract, ...model !== void 0 && { model } },
32416
32419
  // Never publish a private queued observation after a mode flip.
32417
32420
  scope: jobScope,
32418
32421
  folderId: jobFolderId,
@@ -10031,6 +10031,16 @@ interface DurableAutoExtractorOptions extends Omit<CreateAutoExtractorOptions, "
10031
10031
  * as `"private"` — the direction that cannot publish.
10032
10032
  */
10033
10033
  scope?: string | (() => string);
10034
+ /**
10035
+ * Extraction model for a batch, chosen from the scope that batch will be
10036
+ * retained under. A queued job keeps its scope across a privacy-mode flip but
10037
+ * `extract.model` is whatever this instance was built with, so without this a
10038
+ * turn queued in private mode is drained by a public-mode extractor on that
10039
+ * extractor's model. Returning `undefined` keeps `extract.model`. A resolver
10040
+ * that throws fails the batch, which stays queued for retry: guessing a model
10041
+ * is exactly the mistake this exists to prevent.
10042
+ */
10043
+ modelForScope?: (scope: string) => string | undefined;
10034
10044
  /** Coalesce arrivals after durably recording them. Defaults to 20 seconds. */
10035
10045
  debounceMs?: number;
10036
10046
  /** Retry delay for a failed batch. Defaults to 30 seconds; max three attempts
@@ -10031,6 +10031,16 @@ interface DurableAutoExtractorOptions extends Omit<CreateAutoExtractorOptions, "
10031
10031
  * as `"private"` — the direction that cannot publish.
10032
10032
  */
10033
10033
  scope?: string | (() => string);
10034
+ /**
10035
+ * Extraction model for a batch, chosen from the scope that batch will be
10036
+ * retained under. A queued job keeps its scope across a privacy-mode flip but
10037
+ * `extract.model` is whatever this instance was built with, so without this a
10038
+ * turn queued in private mode is drained by a public-mode extractor on that
10039
+ * extractor's model. Returning `undefined` keeps `extract.model`. A resolver
10040
+ * that throws fails the batch, which stays queued for retry: guessing a model
10041
+ * is exactly the mistake this exists to prevent.
10042
+ */
10043
+ modelForScope?: (scope: string) => string | undefined;
10034
10044
  /** Coalesce arrivals after durably recording them. Defaults to 20 seconds. */
10035
10045
  debounceMs?: number;
10036
10046
  /** Retry delay for a failed batch. Defaults to 30 seconds; max three attempts
@@ -8412,6 +8412,7 @@ function createDurableAutoExtractor(options) {
8412
8412
  }
8413
8413
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
8414
8414
  let watchdog;
8415
+ const model = options.modelForScope?.(jobScope) ?? options.extract.model;
8415
8416
  try {
8416
8417
  return await Promise.race([
8417
8418
  new Promise((resolve, reject) => {
@@ -8424,6 +8425,8 @@ function createDurableAutoExtractor(options) {
8424
8425
  canWrite: async () => !disposed && await storage.conversationsCollection.query(import_watermelondb20.Q.where("conversation_id", conversationId), import_watermelondb20.Q.where("is_deleted", false)).fetchCount() > 0 && await storage.messagesCollection.query(import_watermelondb20.Q.where("conversation_id", conversationId), import_watermelondb20.Q.where("id", import_watermelondb20.Q.oneOf(ids))).fetchCount() === ids.length && (!vault.canWrite || await vault.canWrite()) && !disposed
8425
8426
  }
8426
8427
  },
8428
+ // The model follows the job's scope, not the mode alive at drain time.
8429
+ extract: { ...options.extract, ...model !== void 0 && { model } },
8427
8430
  // Never publish a private queued observation after a mode flip.
8428
8431
  scope: jobScope,
8429
8432
  folderId: jobFolderId,
@@ -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.0",
3
+ "version": "6.25.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",