Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions js/src/instrumentation/core/stream-patcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ export interface StreamPatchOptions<TChunk = unknown, TFinal = unknown> {
* Called for each chunk as it's yielded.
* Optional - if not provided, chunks are just collected.
*/
onChunk?: (chunk: TChunk) => void;
onChunk?: (chunk: TChunk) => void | Promise<void>;

/**
* Called when the stream completes successfully.
* Receives all collected chunks.
*/
onComplete: (chunks: TChunk[]) => TFinal | void;
onComplete: (chunks: TChunk[]) => TFinal | void | Promise<TFinal | void>;

/**
* Called if the stream errors.
* If not provided, errors are re-thrown after collection stops.
*/
onError?: (error: Error, chunks: TChunk[]) => void;
onError?: (error: Error, chunks: TChunk[]) => void | Promise<void>;

/**
* Filter to decide whether to collect a chunk.
Expand Down Expand Up @@ -135,7 +135,7 @@ export function patchStreamIfNeeded<TChunk = unknown, TFinal = unknown>(
if (!completed) {
completed = true;
try {
options.onComplete(chunks);
await options.onComplete(chunks);
} catch (error) {
console.error("Error in stream onComplete handler:", error);
}
Expand All @@ -155,7 +155,7 @@ export function patchStreamIfNeeded<TChunk = unknown, TFinal = unknown>(
// Call onChunk handler if provided
if (options.onChunk) {
try {
options.onChunk(chunk);
await options.onChunk(chunk);
} catch (error) {
console.error("Error in stream onChunk handler:", error);
}
Expand All @@ -170,7 +170,7 @@ export function patchStreamIfNeeded<TChunk = unknown, TFinal = unknown>(
completed = true;
if (options.onError) {
try {
options.onError(
await options.onError(
error instanceof Error ? error : new Error(String(error)),
chunks,
);
Expand All @@ -191,7 +191,7 @@ export function patchStreamIfNeeded<TChunk = unknown, TFinal = unknown>(
completed = true;
// Stream was cancelled/returned early
try {
options.onComplete(chunks);
await options.onComplete(chunks);
} catch (error) {
console.error("Error in stream onComplete handler:", error);
}
Expand All @@ -213,7 +213,7 @@ export function patchStreamIfNeeded<TChunk = unknown, TFinal = unknown>(
: new Error(String(rawError));
if (options.onError) {
try {
options.onError(error, chunks);
await options.onError(error, chunks);
} catch (handlerError) {
console.error("Error in stream onError handler:", handlerError);
}
Expand Down
14 changes: 6 additions & 8 deletions js/src/instrumentation/plugins/claude-agent-sdk-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -834,15 +834,14 @@ export class ClaudeAgentSDKPlugin extends BasePlugin {
);
});
},
onComplete: () => {
void state.processing
onComplete: () =>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stylistic nit, but personally I generally only allow arrow functions with body bracing for single-line functions in my own code. Honestly a bit surprised this isn't flagged by the linter. Do we want to allow multi-line arrow functions without braces?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is prettier's default config. I don't care much about how to format things. The only thing I don't like is having red lines via LSP for formatting.

Would you have minded it here if the state.proce... were in the same line as the onComplete:?

Copy link
Copy Markdown
Collaborator

@Qard Stephen Belanger (Qard) Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest would not be though. My personal rule I use for my own projects is if the entire body fits on one line comfortably it can use expression form rather than block form. Otherwise, just stick to block form. I find it's too easy to not notice the missing braces and make future changes which need multiple lines then have it blow up because it's not valid anymore.

It's especially bad when you're assigning an arrow function to a variable because rather than invalid syntax errors like you'd get in this case when writing multiple lines, you might accidentally have statements added to the enclosing function unexpectedly.

function foo(cb) {
  const wrap = () =>
    cb(123)
    cb(456) // This is actually in foo, not cb.

  queueMicrotask(wrap)
}

That will call cb in the opposite order of what you might expect at first glance, because the code is technically valid, but the second cb call gets raised to the enclosing function and so actually gets called first.

Copy link
Copy Markdown
Member Author

@lforst Luca Forstner (lforst) Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok idk, we don't have this problem in this PR though. This is nothing new. Feel free to update prettier to wrap things in curlys! I personally have not knowingly run into this issue in the past 5 years or so.

I have a feeling this may look off to you here specifically because we're in in an object and there is no proper delimiting with ;.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine. It's not important we address this, just thought I should bring it up as it was unexpected to me that the linter allowed this. 😅

state.processing
.then(() => finalizeQuerySpan(state))
.finally(() => {
spans.delete(event);
});
},
onError: (error: Error) => {
void state.processing
}),
onError: (error: Error) =>
state.processing
.then(() => {
state.span.log({
error: error.message,
Expand All @@ -851,8 +850,7 @@ export class ClaudeAgentSDKPlugin extends BasePlugin {
.then(() => finalizeQuerySpan(state))
.finally(() => {
spans.delete(event);
});
},
}),
});

return;
Expand Down
Loading
Loading