(options: any)
| 144 | TReturn, |
| 145 | >(options: DefineActionWithParams<TParams, TReturn>): any; |
| 146 | export function defineAction(options: any) { |
| 147 | const hasSchema = options.schema && "~standard" in options.schema; |
| 148 | |
| 149 | // Build tool definition for the Claude API |
| 150 | let toolParameters: ActionTool["parameters"]; |
| 151 | if (hasSchema) { |
| 152 | // Convert Standard Schema to JSON Schema for Claude |
| 153 | toolParameters = schemaToJsonSchema(options.schema, options.description); |
| 154 | } else if (options.parameters) { |
| 155 | toolParameters = { |
| 156 | type: "object" as const, |
| 157 | properties: options.parameters, |
| 158 | }; |
| 159 | } |
| 160 | |
| 161 | // Wrap run() with validation when schema is provided. |
| 162 | // Pass toolParameters so the validation error can echo the expected signature |
| 163 | // (required vs optional fields) and help the caller self-correct. |
| 164 | const run = hasSchema |
| 165 | ? wrapWithValidation(options.schema, options.run, toolParameters) |
| 166 | : options.run; |
| 167 | |
| 168 | // Auto-infer readOnly from http.method === "GET" unless explicitly set. |
| 169 | // GET actions are idempotent reads; their completion should NOT trigger a |
| 170 | // screen refresh. Everything else is assumed to mutate — the dispatcher |
| 171 | // emits a poll event on success so the UI auto-refetches its queries. |
| 172 | const httpConfig = options.http as ActionHttpConfig | false | undefined; |
| 173 | const inferredReadOnly = |
| 174 | httpConfig !== false && |
| 175 | httpConfig !== undefined && |
| 176 | httpConfig.method === "GET"; |
| 177 | // Explicit `readOnly` (true OR false) wins. Otherwise infer from http.method. |
| 178 | // We store the resolved boolean so downstream checks can trust entry.readOnly |
| 179 | // without re-running method inference — including when a caller explicitly |
| 180 | // passes readOnly:false to override a GET (rare but valid). |
| 181 | const readOnly: boolean | undefined = |
| 182 | typeof options.readOnly === "boolean" |
| 183 | ? options.readOnly |
| 184 | : inferredReadOnly |
| 185 | ? true |
| 186 | : undefined; |
| 187 | |
| 188 | // toolCallable: thread through whatever the caller declared. We DO NOT |
| 189 | // default to `true` here — the absence of an explicit field is meaningful |
| 190 | // to the tools bridge: it lets us emit a one-shot warning when an action |
| 191 | // without a declared `toolCallable` flag is invoked from a tool, so the |
| 192 | // ecosystem can migrate over time. The bridge treats `undefined` as |
| 193 | // "implicit allow with a deprecation warning"; only an explicit `false` |
| 194 | // refuses the call. See `tools/routes.ts` and audit H5. |
| 195 | const toolCallable: boolean | undefined = |
| 196 | typeof options.toolCallable === "boolean" |
| 197 | ? options.toolCallable |
| 198 | : undefined; |
| 199 | const parallelSafe: boolean | undefined = |
| 200 | typeof options.parallelSafe === "boolean" |
| 201 | ? options.parallelSafe |
| 202 | : undefined; |
| 203 |
no test coverage detected