Skip to content

Commit 8ca879e

Browse files
dgp1130atscott
authored andcommitted
refactor(forms): expose consequentialHint annotation
Unlike `readOnlyHint` and `untrustedContentHint`, Angular cannot infer any reasonable default value for `consequentialHint` and simply exposes it to users to specify as appropriate. See: https://groups.google.com/a/chromium.org/g/chrome-ai-dev-preview/c/uHu5kfclbKw/m/dgorjfHPDgAJ
1 parent 96dbae5 commit 8ca879e

4 files changed

Lines changed: 22 additions & 2 deletions

File tree

goldens/public-api/forms/signals/index.api.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ export interface FormOptions<TModel> {
213213
experimentalWebMcpTool?: {
214214
name: string;
215215
description: string;
216+
annotations?: {
217+
consequentialHint?: boolean;
218+
};
216219
};
217220
injector?: Injector;
218221
name?: string;

packages/forms/signals/src/api/structure.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ export interface FormOptions<TModel> {
6969

7070
/** A description of the tool's purpose and usage information. */
7171
description: string;
72+
73+
/**
74+
* Set of configuration values extending the core tool behavior.
75+
*/
76+
annotations?: {
77+
// `readOnlyHint` and `untrustedContentHint` are intentionally omitted as they have
78+
// hard-coded values.
79+
80+
/**
81+
* A hint that the tool will have consequential effects like mutating state or interacting
82+
* with the external world.
83+
*/
84+
consequentialHint?: boolean;
85+
};
7286
};
7387

7488
/** Options that define how to handle form submission. */
@@ -232,6 +246,7 @@ export function form<TModel>(...args: any[]): FieldTree<TModel> {
232246
registerWebMcpForm(fieldRoot.fieldTree, {
233247
name: experimentalWebMcpTool.name,
234248
description: experimentalWebMcpTool.description,
249+
annotations: experimentalWebMcpTool.annotations,
235250
}),
236251
);
237252
} else {

packages/forms/signals/src/webmcp/registration.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const registerWebMcpForm: RegisterWebMcpForm = (formTree, options) => {
3737

3838
async function initWebMcpForm(
3939
formTree: FieldTree<unknown>,
40-
options: {name: string; description: string},
40+
options: {name: string; description: string; annotations?: {consequentialHint?: boolean}},
4141
injector: Injector,
4242
) {
4343
const node = formTree() as FieldNode;
@@ -56,6 +56,8 @@ async function initWebMcpForm(
5656
description: options.description,
5757
inputSchema,
5858
annotations: {
59+
...options.annotations,
60+
5961
// Forms are assumed to implicitly mutate the DOM (otherwise how would a user interact with them?)
6062
// and therefore are _never_ read-only.
6163
readOnlyHint: false,

packages/forms/signals/src/webmcp/tokens.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ export const REGISTER_WEBMCP_FORM = new InjectionToken<RegisterWebMcpForm>(
2222
*/
2323
export type RegisterWebMcpForm = (
2424
form: FieldTree<unknown>,
25-
options: {name: string; description: string},
25+
options: {name: string; description: string; annotations?: {consequentialHint?: boolean}},
2626
) => Promise<void>;

0 commit comments

Comments
 (0)