@@ -160,6 +160,30 @@ function hasTaskAugmentation(request: unknown): boolean {
160160 ) ;
161161}
162162
163+ function asTaskAugmentationRecord (
164+ value : JsonValue ,
165+ ) : Record < string , JsonValue > | undefined {
166+ return value !== null && typeof value === "object" && ! Array . isArray ( value )
167+ ? ( value as Record < string , JsonValue > )
168+ : undefined ;
169+ }
170+
171+ function validateTaskAugmentation ( request : unknown ) : void {
172+ const params = paramsOf ( request ) ;
173+ // Absent is fine: without a prior handler, a plain request runs as a task.
174+ // Object.hasOwn, because indexing types absent keys as JsonValue.
175+ if ( ! Object . hasOwn ( params , "task" ) ) return ;
176+ // A present augmentation must be an object (the 2025-11-25 shape);
177+ // `task: true` would leave us guessing at what the requester meant.
178+ const augmentation = asTaskAugmentationRecord ( params . task ) ;
179+ if ( augmentation === undefined )
180+ throw new Error ( "Task augmentation must be a JSON object" ) ;
181+ if ( ! Object . hasOwn ( augmentation , "ttl" ) || augmentation . ttl === null ) return ;
182+ const ttl = augmentation . ttl ;
183+ if ( typeof ttl !== "number" || ! Number . isInteger ( ttl ) || ttl < 0 )
184+ throw new RangeError ( "task.ttl must be a non-negative integer or null" ) ;
185+ }
186+
163187function taskIdOf ( request : unknown ) : string {
164188 const taskId = paramsOf ( request ) . taskId ;
165189 if ( typeof taskId !== "string" )
@@ -328,6 +352,7 @@ export function bindTaskReceiver(
328352 method ,
329353 ( raw ) => {
330354 expire ( ) ;
355+ validateTaskAugmentation ( raw ) ;
331356 const params = paramsOf ( raw ) ;
332357 if ( tasks . size >= maxTasks )
333358 throw new Error (
@@ -439,15 +464,11 @@ export function bindTaskReceiver(
439464 install ( "tasks/get" , ( request ) =>
440465 Promise . resolve ( snapshot ( get ( taskIdOf ( request ) ) ) ) ,
441466 ) ;
442- install ( "tasks/result" , async ( request ) => {
467+ install ( "tasks/result" , ( request ) => {
443468 const record = get ( taskIdOf ( request ) ) ;
444- if (
445- record . task . status === "working" ||
446- record . task . status === "input_required"
447- )
448- throw new Error ( "Task is not terminal" ) ;
449- if ( record . task . status === "cancelled" )
450- throw new Error ( "Task was cancelled" ) ;
469+ // Returning the still-pending promise blocks the response until the task
470+ // settles, because tasks/result is a blocking call per 2025-11-25; the
471+ // promise already rejects on failure, cancellation, expiry, and close.
451472 return record . result ;
452473 } ) ;
453474 install ( "tasks/cancel" , ( request ) => {
0 commit comments