From 91e97e19053e447fffec0c1fa19be9a60841ea42 Mon Sep 17 00:00:00 2001 From: "mark a. foltz" Date: Wed, 7 Oct 2026 09:48:28 -0700 Subject: [PATCH 1/4] Replace UnknownError with specific DOMException types in tool execution (#323) --- index.bs | 63 +++++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/index.bs b/index.bs index da8b99a..438eeba 100644 --- a/index.bs +++ b/index.bs @@ -179,7 +179,8 @@ A tool definition is a [=struct=] with the following [=struct/items=] : execute steps :: an algorithm that takes a {{Document}} targetDocument, a [=string=] inputArguments, an algorithm completionSteps that takes a - [=string=]-or-null and a [=boolean=], and a [=unique internal value=] uuid. + [=string=]-or-null and a [=string=]-or-null, and a [=unique internal value=] uuid. Note: For tools registered imperatively, these steps will simply invoke the [=imperative execute steps=]. For tools registered @@ -321,7 +322,7 @@ follows: 1.

If |document| is |execution|'s [=pending tool execution/target document=] and is not |execution|'s [=pending tool execution/caller document=], then run |execution|'s [=pending tool execution/completion steps=] given null - and false.

+ and "{{AbortError}}".

Note: This removes |execution| from the [=traversable navigable/pending tool executions map=]. @@ -409,7 +410,7 @@ a [=list=] of [=origins=] |exposed origins|, and an [=origin=] |accessing origin The tool execute steps, given a [=string=] |toolName|, a {{Document}} |targetDocument|, a [=string=] |inputArguments|, an algorithm |completionSteps|, and a [=unique internal value=] |uuid|, are as follows. The |completionSteps| algorithm takes a [=string=]-or-null result -and a [=boolean=] success. +and a [=string=]-or-null errorName. 1. [=Assert=]: these steps are running on |targetDocument|'s [=relevant agent=]'s [=agent/event loop=]. @@ -417,11 +418,8 @@ and a [=boolean=] success. 1. Let |toolMap| be |targetDocument|'s [=Document/associated ModelContext|associated ModelContext=]'s [=ModelContext/internal context=]'s [=model context/tool map=]. -1. If |toolMap|[|toolName|] does not [=map/exist=], then run |completionSteps| given null and false, - and abort these steps. - - Issue: Support the plumbing of more granular errors back to the invoker; this should result in a - "{{NotFoundError}}" in the calling document. +1. If |toolMap|[|toolName|] does not [=map/exist=], then run |completionSteps| given null and + "{{NotFoundError}}", and abort these steps.

This protects us against a race between tool unregistration and execution. While tool @@ -476,14 +474,11 @@ internal value=] |uuid|, are as follows: 1. Let |inputObject| be the result of [=parse a JSON string to a JavaScript value=] given |inputArguments| and |targetDocument|'s [=relevant realm=]. If exception was thrown, then run |completionSteps| given null and false, and abort - these steps. - - Issue: Support more granular errors; here we should return something that prompts the caller to - reject its {{Promise}} with a "{{DataError}}" {{DOMException}}. + thrown">exception was thrown, then run |completionSteps| given null and "{{DataError}}", and + abort these steps. 1. If |inputObject| [=Object type|is not an Object=], then run |completionSteps| given null - and false, and abort these steps. + and "{{DataError}}", and abort these steps. 1. [=Fire an event=] named {{ModelContext/toolactivated}} at |targetDocument|'s [=Document/associated ModelContext|associated ModelContext=], using {{ToolActivatedEvent}}, with its @@ -526,9 +521,9 @@ internal value=] |uuid|, are as follows: 1. Let |serializedResult| be the result of [=serializing a JavaScript value to a JSON string=] given |v|. If this throws an exception, run |completionSteps| given null and - false, and abort these steps. + "{{OperationError}}", and abort these steps. - 1. Run |completionSteps| given |serializedResult| and true. + 1. Run |completionSteps| given |serializedResult| and null. - If |toolPromise| was rejected with reason |r|, then: @@ -542,7 +537,7 @@ internal value=] |uuid|, are as follows: 1. [=map/Remove=] |localExecutions|[|uuid|]. - 1. Run |completionSteps| given null and false. + 1. Run |completionSteps| given null and "{{OperationError}}".

@@ -982,23 +977,19 @@ The executeTool(tool, inputObjectModelContext=]'s [=ModelContext/internal context=]'s [=model context/tool map=]. @@ -1007,21 +998,23 @@ The executeTool(tool, inputObjectexecuteTool(tool, inputObject Date: Wed, 7 Oct 2026 20:08:37 -0230 Subject: [PATCH 2/4] Add a centralized editorial mechanism to track platform-defined failures --- index.bs | 82 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/index.bs b/index.bs index 438eeba..81213ce 100644 --- a/index.bs +++ b/index.bs @@ -179,8 +179,8 @@ A tool definition is a [=struct=] with the following [=struct/items=] : execute steps :: an algorithm that takes a {{Document}} targetDocument, a [=string=] inputArguments, an algorithm completionSteps that takes a - [=string=]-or-null and a [=string=]-or-null, and a [=unique internal value=] uuid. + [=string=]-or-null and a [=tool execution error=]-or-null, and a [=unique internal value=] + uuid. Note: For tools registered imperatively, these steps will simply invoke the [=imperative execute steps=]. For tools registered @@ -218,6 +218,50 @@ An annotations is a [=struct=] with the following [=struct/items=]: :: a [=boolean=], initially false. +A tool execution error represents the reason that a tool execution failed. It is one of +the values in the following table, each of which has a corresponding +exception name. + + + + + + + + + + +
Value + Description + [=tool execution error/Corresponding exception name=] +
tool not found + The tool being executed is not registered in the target {{Document}}. + "{{NotFoundError}}" +
invalid input + The input arguments could not be parsed into a JavaScript Object. + "{{DataError}}" +
tool rejected + The tool's {{ModelContextTool/execute}} callback returned a rejected {{Promise}}. + "{{OperationError}}" +
unserializable result + The tool's result could not be serialized to a JSON string. + "{{OperationError}}" +
target document unloaded + The target {{Document}} was unloaded before the execution completed. + "{{AbortError}}" +
+ +
+

[=Tool execution errors=] are not exposed to the web. They exist as a spec concept to give tool + execution algorithms a realm-agnostic set of failure reasons that correspond to {{DOMException}} + types that do get exposed to the caller; the caller only ever observes the [=tool + execution error/corresponding exception name=].

+ +

Also note that this table only tracks the list of platform-defined failures. Tool + execution failures defined in userland by web developers that write tools can come in any + shape or format in the response JSON string.

+
+

Pending tool executions

A pending tool execution is a [=struct=] with the following [=struct/items=]: @@ -233,7 +277,7 @@ A pending tool execution is a [=struct=] with the following [=struct/ :: a [=string=]. : completion steps - :: an algorithm that takes a [=string=]-or-null and a [=boolean=]. + :: an algorithm that takes a [=string=]-or-null and a [=tool execution error=]-or-null. A [=traversable navigable=] has a pending tool executions @@ -322,7 +366,7 @@ follows: 1.

If |document| is |execution|'s [=pending tool execution/target document=] and is not |execution|'s [=pending tool execution/caller document=], then run |execution|'s [=pending tool execution/completion steps=] given null - and "{{AbortError}}".

+ and [=tool execution error/target document unloaded=].

Note: This removes |execution| from the [=traversable navigable/pending tool executions map=]. @@ -410,7 +454,7 @@ a [=list=] of [=origins=] |exposed origins|, and an [=origin=] |accessing origin The tool execute steps, given a [=string=] |toolName|, a {{Document}} |targetDocument|, a [=string=] |inputArguments|, an algorithm |completionSteps|, and a [=unique internal value=] |uuid|, are as follows. The |completionSteps| algorithm takes a [=string=]-or-null result -and a [=string=]-or-null errorName. +and a [=tool execution error=]-or-null error. 1. [=Assert=]: these steps are running on |targetDocument|'s [=relevant agent=]'s [=agent/event loop=]. @@ -419,7 +463,7 @@ and a [=string=]-or-null errorName. ModelContext=]'s [=ModelContext/internal context=]'s [=model context/tool map=]. 1. If |toolMap|[|toolName|] does not [=map/exist=], then run |completionSteps| given null and - "{{NotFoundError}}", and abort these steps. + [=tool execution error/tool not found=], and abort these steps.

This protects us against a race between tool unregistration and execution. While tool @@ -474,11 +518,11 @@ internal value=] |uuid|, are as follows: 1. Let |inputObject| be the result of [=parse a JSON string to a JavaScript value=] given |inputArguments| and |targetDocument|'s [=relevant realm=]. If exception was thrown, then run |completionSteps| given null and "{{DataError}}", and - abort these steps. + thrown">exception was thrown, then run |completionSteps| given null and [=tool execution + error/invalid input=], and abort these steps. 1. If |inputObject| [=Object type|is not an Object=], then run |completionSteps| given null - and "{{DataError}}", and abort these steps. + and [=tool execution error/invalid input=], and abort these steps. 1. [=Fire an event=] named {{ModelContext/toolactivated}} at |targetDocument|'s [=Document/associated ModelContext|associated ModelContext=], using {{ToolActivatedEvent}}, with its @@ -521,7 +565,7 @@ internal value=] |uuid|, are as follows: 1. Let |serializedResult| be the result of [=serializing a JavaScript value to a JSON string=] given |v|. If this throws an exception, run |completionSteps| given null and - "{{OperationError}}", and abort these steps. + [=tool execution error/unserializable result=], and abort these steps. 1. Run |completionSteps| given |serializedResult| and null. @@ -537,7 +581,7 @@ internal value=] |uuid|, are as follows: 1. [=map/Remove=] |localExecutions|[|uuid|]. - 1. Run |completionSteps| given null and "{{OperationError}}". + 1. Run |completionSteps| given null and [=tool execution error/tool rejected=].

@@ -1014,7 +1058,9 @@ The executeTool(tool, inputObjectexecuteTool(tool, inputObject Date: Thu, 8 Oct 2026 10:42:03 -0700 Subject: [PATCH 3/4] Tighten the wording of the note. --- index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 81213ce..0ad27ce 100644 --- a/index.bs +++ b/index.bs @@ -257,10 +257,10 @@ exception name. types that do get exposed to the caller; the caller only ever observes the [=tool execution error/corresponding exception name=].

-

Also note that this table only tracks the list of platform-defined failures. Tool - execution failures defined in userland by web developers that write tools can come in any - shape or format in the response JSON string.

- +

Also note that this table only tracks the list of platform-defined + failures. Tool execution failures defined by tool authors may also be reported + to the tool caller in the response JSON string.

+

Pending tool executions

From d3a75a065c6855f18a3504793cc3e9eb4c1a382e Mon Sep 17 00:00:00 2001 From: "mark a. foltz" Date: Thu, 8 Oct 2026 10:50:54 -0700 Subject: [PATCH 4/4] Avoid RFC2119 keyword in non-normative note --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index bf304ab..8cd4180 100644 --- a/index.bs +++ b/index.bs @@ -249,7 +249,7 @@ exception name
. execution error/corresponding exception name=].

Also note that this table only tracks the list of platform-defined - failures. Tool execution failures defined by tool authors may also be reported + failures. Tool execution failures defined by tool authors can also be reported to the tool caller in the response JSON string.