Skip to content

Commit f412754

Browse files
MorabbinCopilot
andcommitted
Pass structured tool results via RPC instead of stringifying
In both the Node and Go SDKs, _executeToolAndRespond / executeToolAndRespond was converting structured ToolResultObject values into plain JSON strings before sending them over RPC. This destroyed the object shape, causing toolTelemetry (and other structured fields like resultType) to be silently lost on the server side. Node SDK: detect ToolResultObject by checking for textResultForLlm + resultType properties and pass it directly to handlePendingToolCall, which already accepts the union type (string | object) in its RPC schema. Go SDK: send a ResultUnion with ResultResult populated (preserving TextResultForLlm, ResultType, Error, and ToolTelemetry) instead of extracting only the text and sending ResultUnion with String. Fixes the SDK side of github/copilot-agent-runtime#5574. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4d26e30 commit f412754

2 files changed

Lines changed: 32 additions & 5 deletions

File tree

go/session.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,21 @@ func (s *Session) executeToolAndRespond(requestID, toolName, toolCallID string,
620620
return
621621
}
622622

623-
resultStr := result.TextResultForLLM
624-
if resultStr == "" {
625-
resultStr = fmt.Sprintf("%v", result)
623+
rpcResult := rpc.ResultUnion{
624+
ResultResult: &rpc.ResultResult{
625+
TextResultForLlm: result.TextResultForLLM,
626+
ToolTelemetry: result.ToolTelemetry,
627+
},
628+
}
629+
if result.ResultType != "" {
630+
rpcResult.ResultResult.ResultType = &result.ResultType
631+
}
632+
if result.Error != "" {
633+
rpcResult.ResultResult.Error = &result.Error
626634
}
627635
s.RPC.Tools.HandlePendingToolCall(ctx, &rpc.SessionToolsHandlePendingToolCallParams{
628636
RequestID: requestID,
629-
Result: &rpc.ResultUnion{String: &resultStr},
637+
Result: &rpcResult,
630638
})
631639
}
632640

nodejs/src/session.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import type {
3333
SessionUiApi,
3434
Tool,
3535
ToolHandler,
36+
ToolResult,
37+
ToolResultObject,
3638
TraceContextProvider,
3739
TypedSessionEventHandler,
3840
UserInputHandler,
@@ -459,11 +461,13 @@ export class CopilotSession {
459461
traceparent,
460462
tracestate,
461463
});
462-
let result: string;
464+
let result: ToolResult;
463465
if (rawResult == null) {
464466
result = "";
465467
} else if (typeof rawResult === "string") {
466468
result = rawResult;
469+
} else if (isToolResultObject(rawResult)) {
470+
result = rawResult;
467471
} else {
468472
result = JSON.stringify(rawResult);
469473
}
@@ -1043,3 +1047,18 @@ export class CopilotSession {
10431047
await this.rpc.log({ message, ...options });
10441048
}
10451049
}
1050+
1051+
/**
1052+
* Type guard that checks whether a value is a {@link ToolResultObject}.
1053+
* A valid object must have a string `textResultForLlm` and a string `resultType`.
1054+
*/
1055+
function isToolResultObject(value: unknown): value is ToolResultObject {
1056+
return (
1057+
typeof value === "object" &&
1058+
value !== null &&
1059+
"textResultForLlm" in value &&
1060+
typeof (value as ToolResultObject).textResultForLlm === "string" &&
1061+
"resultType" in value &&
1062+
typeof (value as ToolResultObject).resultType === "string"
1063+
);
1064+
}

0 commit comments

Comments
 (0)