Skip to content

Microsoft Agent Framework guide: the Node.js streaming example reads a nonexistent delta field #2104

Description

@examon

Summary

In docs/integrations/microsoft-agent-framework.md, the "Node.js / TypeScript (standalone SDK)" example under Streaming responses registers an assistant.message_delta handler that reads event.data.delta:

session.on("assistant.message_delta", (event) => {
    process.stdout.write(event.data.delta ?? "");
});

The payload type for that event declares deltaContent, not delta. AssistantMessageDeltaData in nodejs/src/generated/session-events.ts has exactly three members:

export interface AssistantMessageDeltaData {
  deltaContent: string;
  messageId: string;
  parentToolCallId?: string;
}

So event.data.delta evaluates to undefined, the ?? "" fallback turns that into an empty string, and the handler writes nothing for each delta event. Someone copying this example sees no streamed output.

Reproduction

Against the published package (@github/copilot-sdk@1.0.8), in an ESM project. This is an instrumented version of the documented handler, not the doc block verbatim: it accumulates both the documented accessor and deltaContent side by side so the difference is visible, and it uses a deny-all permission handler and a one-word prompt.

import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
const session = await client.createSession({
    streaming: true,
    onPermissionRequest: async () => ({ kind: "reject" }),
});

let asDocumented = "";
let actual = "";
let keys = null;

session.on("assistant.message_delta", (event) => {
    keys ??= Object.keys(event.data);
    asDocumented += event.data.delta ?? "";
    actual += event.data.deltaContent ?? "";
});

await session.sendAndWait({ prompt: "Reply with exactly one word: pong" });

console.log("payload keys:          ", JSON.stringify(keys));
console.log("event.data.delta:      ", JSON.stringify(asDocumented));
console.log("event.data.deltaContent:", JSON.stringify(actual));

await client.stop();
process.exit(0);

Output:

payload keys:           ["messageId","deltaContent"]
event.data.delta:       ""
event.data.deltaContent: "pong"

The behaviour is not model-specific; model is omitted here so the session uses the default.

Expected

The example writes the streamed text, as the equivalent examples elsewhere in the docs do.

Notes

deltaContent is the accessor used consistently everywhere else:

  • The Java example in the same "Streaming responses" section of the same guide calls event.getData().deltaContent().
  • docs/features/streaming-events.md and docs/getting-started.md use event.data.deltaContent in their TypeScript snippets, event.data.delta_content in Python, and deltaContent in Rust and Java.
  • The event reference table in docs/features/streaming-events.md lists messageId and deltaContent as the fields of assistant.message_delta.
  • The generated types agree across bindings: deltaContent in Node.js, DeltaContent/deltaContent in Go, .NET and Java, and delta_content (deserialised from deltaContent) in Python.

event.data.delta appears exactly once in the repository, on this line.

The fix is a one-token change on that line.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions