Skip to content

Commit c7f90b7

Browse files
authored
Handler shape validation guidance (#105)
* Improve handler shape validation guidance Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> * Address PR review: improve handler validation guards and guidance consistency - Gate return-check on has_handler_function && no signature issue to avoid misleading 'MUST return' errors on invalid handler shapes - Expand check_handler_has_return skip logic to also skip arrow function bodies (=> { ... }) and generator declarations (function*) - Fix conflicting guidance in register_handler tool description: use function handler(...) instead of function handler(event) in REQUIRED line - Add zero-parameter form function handler() to system-message signature list Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> * fix: address PR review feedback on handler validation - Skip misnamed-handler check when valid function handler already exists, preventing false positives on nested helpers (e.g. function process()) - Fix inconsistent help text: handler(...) instead of handler(event) to match the zero-parameter guidance - Also skip function( and function*( expression forms in return check so anonymous function expression returns are not counted as handler returns Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> --------- Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
1 parent 98c1e5d commit c7f90b7

2 files changed

Lines changed: 17 additions & 6 deletions

File tree

src/agent/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,9 +2038,10 @@ const executeJavascriptTool = defineTool("execute_javascript", {
20382038
result:
20392039
`Result saved to ${relativePath} (${(fullResultBytes / 1024).toFixed(1)} KB).\n` +
20402040
`Preview (first 500 chars):\n${preview}\n\n` +
2041-
`Use read_output("${relativePath}") to read the full result.\n` +
2042-
`Use read_output("${relativePath}", startLine, endLine) for specific sections.\n` +
2043-
`You can also read this file from handler code via host:fs-read.`,
2041+
`IMPORTANT: Read the full output by writing a handler that reads "${relativePath}" via host:fs-read.\n` +
2042+
`Process the data in handler code — do NOT summarize or propose changes based only on the preview.\n` +
2043+
`Only use read_output("${relativePath}") directly if you need a quick look at a specific section;\n` +
2044+
`read_output("${relativePath}", startLine, endLine) supports line ranges.`,
20442045
...(consoleOutput?.length ? { consoleOutput } : {}),
20452046
_resourceStats: resourceStats,
20462047
_stats: stats ?? undefined,
@@ -2898,7 +2899,7 @@ const HELP_TOPICS: Record<string, string> = {
28982899
"- YOU orchestrate: pass handler A's result as handler B's event",
28992900
"",
29002901
"HANDLER CODE STYLE:",
2901-
"- Every handler must define function handler(event) or async function handler(event)",
2902+
"- Every handler must define function handler(...) or async function handler(...)",
29022903
"- The function name is mandatory; parameter names are flexible, and zero parameters are allowed",
29032904
"- Module-level state persists across execute_javascript calls",
29042905
"",

src/code-validator/guest/runtime/src/validator.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,12 @@ fn check_handler_function(source: &str) -> bool {
10031003
}
10041004

10051005
/// Diagnose handler declarations that look close but are not the required shape.
1006+
/// If a valid `function handler` already exists at the top level, skip the
1007+
/// misnamed-function check so nested helpers (e.g. `function process(...)`) are
1008+
/// not flagged as errors.
10061009
fn check_handler_signature_issue(source: &str) -> Option<(String, Option<u32>)> {
1010+
let has_valid_handler = check_handler_function(source);
1011+
10071012
for (line_index, line) in source.lines().enumerate() {
10081013
let trimmed = line.trim();
10091014
let line_number = Some((line_index + 1) as u32);
@@ -1052,7 +1057,9 @@ fn check_handler_signature_issue(source: &str) -> Option<(String, Option<u32>)>
10521057
let name = &rest[..name_end];
10531058
if name == "handler" {
10541059
continue;
1055-
} else if matches!(name, "Handler" | "handle" | "main" | "run" | "process") {
1060+
} else if !has_valid_handler
1061+
&& matches!(name, "Handler" | "handle" | "main" | "run" | "process")
1062+
{
10561063
return Some((
10571064
alloc::format!(
10581065
"Handler function must be named exactly 'handler'. Found function '{}'. Fix: rename it to function handler(event) {{ ... return result; }}.",
@@ -1101,8 +1108,11 @@ fn check_handler_has_return(source: &str) -> bool {
11011108
}
11021109
}
11031110
b'f' => {
1104-
// Skip nested function and function* declarations
1111+
// Skip nested function declarations, generators, and
1112+
// anonymous function expressions (function(...) { ... })
11051113
if (rest[i..].starts_with("function ")
1114+
|| rest[i..].starts_with("function(")
1115+
|| rest[i..].starts_with("function*(")
11061116
|| rest[i..].starts_with("function*"))
11071117
&& let Some(after_nested) = skip_nested_block(rest, i)
11081118
{

0 commit comments

Comments
 (0)