Skip to content

Add structured object support for Tool call arguments/responses for OutputScope and ToolScope and truncation #228

Merged
fpfp100 merged 5 commits intomainfrom
users/pefan/toolupdate
Apr 9, 2026
Merged

Add structured object support for Tool call arguments/responses for OutputScope and ToolScope and truncation #228
fpfp100 merged 5 commits intomainfrom
users/pefan/toolupdate

Conversation

@fpfp100
Copy link
Copy Markdown
Contributor

@fpfp100 fpfp100 commented Apr 7, 2026

Summary

  • Add structured object support for tool call arguments/responses with auto-serialization, introduce ResponseMessagesParam for raw dict tool results in OutputScope, align with Python implementation.
  • Delete ExecutionType enum and TenantDetails interface (align with Python SDK)
  • Remove getExecutionTypePair, setExecutionTypeBaggage, deriveTenantDetails from hosting
  • Remove GEN_AI_EXECUTION_TYPE_KEY usage from OpenAI extensions
  • Handle raw dict JSON in span truncation: one-shot OVERLIMIT_SENTINEL replacement (preserves JSON integrity)
  • Add null-safety guards and safe JSON serialization (non-throwing)

Sample Console Output (from basic-agent-sdk-sample)

1. Inference span ("Chat gpt-4o")

{
  resource: {
    attributes: {
      'service.name': 'TypeScript Sample Agent-1.0.0'
    }
  },
  instrumentationScope: { name: 'Agent365Sdk', version: undefined, schemaUrl: undefined },
  traceId: 'd0ce510cea41a15d8ac70760d1536763',
  parentSpanContext: {
    traceId: 'd0ce510cea41a15d8ac70760d1536763',
    spanId: 'c2c3fd3594693e80',
    traceFlags: 1,
    traceState: undefined
  },
  traceState: undefined,
  name: 'Chat gpt-4o',
  id: 'c3f785301c9aae1c',
  kind: 2,
  timestamp: 1775523521264000,
  duration: 109818.4,
  attributes: {
    'gen_ai.operation.name': 'Chat',
    'telemetry.sdk.name': 'A365ObservabilitySDK',
    'telemetry.sdk.language': 'nodejs',
    'telemetry.sdk.version': '0.0.0-placeholder',
    'microsoft.tenant.id': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    'microsoft.session.id': 'session-abc',
    'gen_ai.agent.id': '30ed5699-b157-4e87-bb45-9b0cfb13b8e5',
    'gen_ai.agent.name': 'ComplianceAssistant',
    'gen_ai.request.model': 'gpt-4o',
    'gen_ai.provider.name': 'openai',
    'gen_ai.usage.input_tokens': 152,
    'gen_ai.usage.output_tokens': 287,
    'gen_ai.response.finish_reasons': [ 'stop' ],
    'gen_ai.conversation.id': 'conv-001',
    'microsoft.channel.name': 'msteams',
    'server.address': 'api.openai.com',
    'gen_ai.input.messages': '{"version":"0.1.0","messages":[{"role":"system","parts":[{"type":"text","content":"You are a compliance assistant."}]},{"role":"user","parts":[{"type":"text","content":"What are the data retention policies?"}]}]}',
    'gen_ai.output.messages': '{"version":"0.1.0","messages":[{"role":"assistant","parts":[{"type":"reasoning","content":"Checking GDPR Article 5(1)(e)."},{"type":"text","content":"Personal data must be kept no longer than necessary."}],"finish_reason":"stop"}]}'
  },
  status: { code: 0 },
  events: [],
  links: []
}

2. ExecuteTool span — object arguments + object response (auto-serialized)

{
  resource: {
    attributes: {
      'service.name': 'TypeScript Sample Agent-1.0.0'
    }
  },
  instrumentationScope: { name: 'Agent365Sdk', version: undefined, schemaUrl: undefined },
  traceId: 'd0ce510cea41a15d8ac70760d1536763',
  parentSpanContext: {
    traceId: 'd0ce510cea41a15d8ac70760d1536763',
    spanId: 'c2c3fd3594693e80',
    traceFlags: 1,
    traceState: undefined
  },
  traceState: undefined,
  name: 'execute_tool search-policy-documents',
  id: '27c13bf1a23a0732',
  kind: 0,
  timestamp: 1775523521376000,
  duration: 63314.1,
  attributes: {
    'gen_ai.operation.name': 'execute_tool',
    'telemetry.sdk.name': 'A365ObservabilitySDK',
    'telemetry.sdk.language': 'nodejs',
    'telemetry.sdk.version': '0.0.0-placeholder',
    'microsoft.tenant.id': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    'microsoft.session.id': 'session-abc',
    'gen_ai.agent.id': '30ed5699-b157-4e87-bb45-9b0cfb13b8e5',
    'gen_ai.agent.name': 'ComplianceAssistant',
    'gen_ai.tool.name': 'search-policy-documents',
    'gen_ai.tool.call.arguments': '{"query":"GDPR data retention","maxResults":5,"filters":{"region":"EU"}}',
    'gen_ai.tool.type': 'function',
    'gen_ai.tool.call.id': 'call_abc123',
    'gen_ai.conversation.id': 'conv-001',
    'microsoft.channel.name': 'msteams',
    'server.address': 'policy-search.contoso.com',
    'server.port': 9443,
    'gen_ai.tool.call.result': '{"results":[{"title":"GDPR Data Retention Policy v2.1","relevance":0.95}]}'
  },
  status: { code: 0 },
  events: [],
  links: []
}

3. OutputScope — string[] input (auto-wrapped, overwrite semantics)

{
  resource: {
    attributes: {
      'service.name': 'TypeScript Sample Agent-1.0.0'
    }
  },
  instrumentationScope: { name: 'Agent365Sdk', version: undefined, schemaUrl: undefined },
  traceId: 'd0ce510cea41a15d8ac70760d1536763',
  parentSpanContext: {
    traceId: 'd0ce510cea41a15d8ac70760d1536763',
    spanId: 'c2c3fd3594693e80',
    traceFlags: 1,
    traceState: undefined
  },
  traceState: undefined,
  name: 'output_messages ComplianceAssistant',
  id: '23150b4d5a06efb6',
  kind: 2,
  timestamp: 1775523521440000,
  duration: 559.8,
  attributes: {
    'gen_ai.operation.name': 'output_messages',
    'telemetry.sdk.name': 'A365ObservabilitySDK',
    'telemetry.sdk.language': 'nodejs',
    'telemetry.sdk.version': '0.0.0-placeholder',
    'microsoft.tenant.id': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    'microsoft.session.id': 'session-abc',
    'gen_ai.agent.id': '30ed5699-b157-4e87-bb45-9b0cfb13b8e5',
    'gen_ai.agent.name': 'ComplianceAssistant',
    'gen_ai.output.messages': '{"version":"0.1.0","messages":[{"role":"assistant","parts":[{"type":"text","content":"GDPR requires 3-year retention for customer data."}]}]}',
    'gen_ai.conversation.id': 'conv-001',
    'microsoft.channel.name': 'msteams'
  },
  status: { code: 0 },
  events: [],
  links: []
}

4. OutputScope — structured OutputMessages (overwrite semantics)

{
  resource: {
    attributes: {
      'service.name': 'TypeScript Sample Agent-1.0.0'
    }
  },
  instrumentationScope: { name: 'Agent365Sdk', version: undefined, schemaUrl: undefined },
  traceId: 'd0ce510cea41a15d8ac70760d1536763',
  parentSpanContext: {
    traceId: 'd0ce510cea41a15d8ac70760d1536763',
    spanId: 'c2c3fd3594693e80',
    traceFlags: 1,
    traceState: undefined
  },
  traceState: undefined,
  name: 'output_messages ComplianceAssistant',
  id: '2aefcaa754078e49',
  kind: 2,
  timestamp: 1775523521440000,
  duration: 252.2,
  attributes: {
    'gen_ai.operation.name': 'output_messages',
    'telemetry.sdk.name': 'A365ObservabilitySDK',
    'telemetry.sdk.language': 'nodejs',
    'telemetry.sdk.version': '0.0.0-placeholder',
    'microsoft.tenant.id': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    'microsoft.session.id': 'session-abc',
    'gen_ai.agent.id': '30ed5699-b157-4e87-bb45-9b0cfb13b8e5',
    'gen_ai.agent.name': 'ComplianceAssistant',
    'gen_ai.output.messages': '{"version":"0.1.0","messages":[{"role":"assistant","parts":[{"type":"text","content":"7-year retention for financial records."}],"finish_reason":"stop"}]}',
    'gen_ai.conversation.id': 'conv-001',
    'microsoft.channel.name': 'msteams'
  },
  status: { code: 0 },
  events: [],
  links: []
}

5. InvokeAgent span (root)

{
  resource: {
    attributes: {
      'service.name': 'TypeScript Sample Agent-1.0.0'
    }
  },
  instrumentationScope: { name: 'Agent365Sdk', version: undefined, schemaUrl: undefined },
  traceId: 'd0ce510cea41a15d8ac70760d1536763',
  parentSpanContext: undefined,
  traceState: undefined,
  name: 'invoke_agent ComplianceAssistant',
  id: 'c2c3fd3594693e80',
  kind: 2,
  timestamp: 1775523521262000,
  duration: 178961.8,
  attributes: {
    'gen_ai.operation.name': 'invoke_agent',
    'telemetry.sdk.name': 'A365ObservabilitySDK',
    'telemetry.sdk.language': 'nodejs',
    'telemetry.sdk.version': '0.0.0-placeholder',
    'microsoft.tenant.id': 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    'microsoft.session.id': 'session-abc',
    'gen_ai.agent.id': '30ed5699-b157-4e87-bb45-9b0cfb13b8e5',
    'gen_ai.agent.name': 'ComplianceAssistant',
    'gen_ai.provider.name': 'openai',
    'server.address': 'agent365.contoso.com',
    'server.port': 8443,
    'microsoft.channel.name': 'msteams',
    'gen_ai.conversation.id': 'conv-001',
    'gen_ai.input.messages': '{"version":"0.1.0","messages":[{"role":"user","parts":[{"type":"text","content":"What are the data retention policies?"}]}]}',
    'gen_ai.output.messages': '{"version":"0.1.0","messages":[{"role":"assistant","parts":[{"type":"text","content":"Personal data: no longer than necessary. Customer data: 3 years. Financial: 7 years."}],"finish_reason":"stop"}]}'
  },
  status: { code: 0 },
  events: [],
  links: [
    {
      context: {
        traceId: '0aa4621e5ae09963a3de354f3d18aa65',
        spanId: 'c1aaa519600b1bf0',
        traceFlags: 1
      },
      attributes: { 'link.type': 'causal' }
    }
  ]
}

Test plan

  • All 1173 unit tests pass (60 suites)
  • New tests for object args/response serialization in ExecuteToolScope (4 tests)
  • New tests for OutputScope overwrite semantics (3 tests)
  • New tests for raw dict in OutputScope (2 tests)
  • New tests for raw dict truncation — OVERLIMIT_SENTINEL, version check, small dict preserved, versioned wrapper still uses message-aware shrinking (4 tests)
  • Basic sample runs locally and produces correct span output with both string[] and structured OutputMessages
  • PR lint error fixed (unused import)

🤖 Generated with Claude Code

jsl517 and others added 2 commits April 6, 2026 14:52
- Widen ToolCallDetails.arguments to accept Record<string, unknown> | string
- Widen ExecuteToolScope.recordResponse to accept Record<string, unknown> | string
- Change OutputScope from accumulate to overwrite semantics
- Add ResponseMessagesParam type (OutputMessagesParam | Record<string, unknown>) for tool call results
- Delete ExecutionType enum and TenantDetails interface (align with Python SDK)
- Remove getExecutionTypePair, setExecutionTypeBaggage, deriveTenantDetails from hosting
- Remove GEN_AI_EXECUTION_TYPE_KEY usage from OpenAI extensions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…leanup

- Add null guards for typeof === 'object' checks in ExecuteToolScope
- Handle raw dict JSON in truncation: one-shot OVERLIMIT_SENTINEL (not string trim)
- Tighten version check in collectShrinkActions to distinguish versioned wrappers from raw dicts
- Simplify _isRawDict to check for absence of version key
- Add test coverage for raw dict in OutputScope and truncation (4 new truncation tests, 2 OutputScope tests)
- Remove stale ExecutionType/TenantDetails references from design docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 7, 2026 00:24
@fpfp100 fpfp100 requested a review from a team as a code owner April 7, 2026 00:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Aligns Node.js observability tool/message telemetry behavior with the Python SDK changes (PR #221), including broader tool arg/response typing, updated output message semantics, and safer span truncation behavior for raw JSON dict payloads.

Changes:

  • Widen tool call arguments and tool responses to support Record<string, unknown> | string with automatic JSON serialization.
  • Change OutputScope output recording from append/accumulate to overwrite semantics, and allow raw dict output payloads.
  • Remove legacy execution-type and tenant-details helpers/usages; update span truncation to handle raw dict JSON via one-shot [overlimit] replacement.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/observability/extension/hosting/TurnContextUtils.test.ts Removes execution-type baggage tests.
tests/observability/extension/hosting/scope-utils.test.ts Removes tenant-details derivation tests.
tests/observability/core/scopes.test.ts Adds coverage for object/string tool args + tool responses serialization in ExecuteToolScope.
tests/observability/core/output-scope.test.ts Updates tests for overwrite semantics and adds raw-dict output coverage.
tests/observability/core/agent365-exporter.test.ts Adds truncation tests for raw dict JSON in message attributes.
packages/agents-a365-observability/src/tracing/scopes/OutputScope.ts Implements overwrite semantics + raw-dict output support.
packages/agents-a365-observability/src/tracing/scopes/ExecuteToolScope.ts Serializes object tool args/response payloads to JSON.
packages/agents-a365-observability/src/tracing/exporter/utils.ts Distinguishes versioned wrappers vs raw JSON and applies [overlimit] sentinel appropriately.
packages/agents-a365-observability/src/tracing/contracts.ts Updates public contract types: tool args widening and new ResponseMessagesParam.
packages/agents-a365-observability/src/tracing/constants.ts Removes GEN_AI_EXECUTION_TYPE_KEY.
packages/agents-a365-observability/src/index.ts Removes ExecutionType/TenantDetails exports and exports ResponseMessagesParam.
packages/agents-a365-observability/docs/design.md Removes ExecutionType from documented enums.
packages/agents-a365-observability-hosting/src/utils/TurnContextUtils.ts Removes execution-type baggage extraction helper.
packages/agents-a365-observability-hosting/src/utils/ScopeUtils.ts Removes tenant-details derivation helper.
packages/agents-a365-observability-hosting/src/utils/BaggageBuilderUtils.ts Stops adding execution-type baggage.
packages/agents-a365-observability-hosting/src/middleware/BaggageMiddleware.ts Stops attaching execution-type baggage.
packages/agents-a365-observability-hosting/docs/design.md Updates docs to remove execution-type APIs/mentions.
packages/agents-a365-observability-extensions-openai/src/Utils.ts Removes setting execution-type attribute from OpenAI span attribute extraction.
packages/agents-a365-observability-extensions-openai/src/OpenAIAgentsTraceProcessor.ts Removes execution-type key exclusion logic (since key is removed).

Comment thread packages/agents-a365-observability/src/tracing/scopes/OutputScope.ts Outdated
Comment thread packages/agents-a365-observability/src/tracing/scopes/OutputScope.ts Outdated
@fpfp100 fpfp100 changed the title Align tool-related changes with Python PR #221 Update OutputScope and related interfaces to accept record type and adding supporting in truncation method. Apr 7, 2026
- Remove unused OutputMessagesParam import from OutputScope (lint fix)
- Add null guard to _isRawDict (typeof null === 'object' safety)
- Wrap JSON.stringify in try/catch in ExecuteToolScope and OutputScope raw dict path
- Add safeJsonStringify helper for non-throwing telemetry serialization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fpfp100 fpfp100 changed the title Update OutputScope and related interfaces to accept record type and adding supporting in truncation method. Add structured object support for Tool call arguments/responses for OutputScope and ToolScope and truncation Apr 7, 2026
Comment thread packages/agents-a365-observability/src/tracing/contracts.ts
Comment thread packages/agents-a365-observability/src/tracing/contracts.ts Outdated
Comment thread packages/agents-a365-observability/src/tracing/contracts.ts
Comment thread packages/agents-a365-observability/src/tracing/contracts.ts Outdated
Comment thread packages/agents-a365-observability/src/tracing/contracts.ts Outdated
…string (not just string[] or wrapper). Request.content changed from string to InputMessagesParam. InvokeAgentScope.start() automatically records request.content as input messages. Tool record response and argument changed to provide proper serialized format for single string input.
Copilot AI review requested due to automatic review settings April 8, 2026 23:46
@fpfp100 fpfp100 requested a review from a team as a code owner April 8, 2026 23:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.

Comment thread packages/agents-a365-observability/src/tracing/util.ts Outdated
Comment thread tests/observability/core/scopes.test.ts Outdated
Comment thread packages/agents-a365-observability/src/tracing/scopes/OutputScope.ts Outdated
…rd, remove .codereviews

- Change serialization failure fallback from plain string to JSON.stringify({ error: 'serialization failed' }) so downstream processors don't need special-casing for non-JSON attributes.
- Apply global tracer provider guard pattern in scopes.test.ts to match other test files and avoid flaky test ordering.
- Remove .codereviews file from tracked files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fpfp100 fpfp100 merged commit c3803eb into main Apr 9, 2026
7 checks passed
@fpfp100 fpfp100 deleted the users/pefan/toolupdate branch April 9, 2026 18:43
fpfp100 pushed a commit that referenced this pull request Apr 9, 2026
…tensions, align tool serialization

- Remove isContentRecordingEnabled toggle: content recording is now ON by default
  (aligned with Python/.NET SDKs). suppressInvokeAgentInput remains.
- Remove truncateValue from both extensions: truncation now happens at the
  span/exporter level in core, not pre-truncated in extensions.
- Use safeSerializeToJson for tool arguments/results in both extensions,
  matching the core ExecuteToolScope pattern from PR #228.
- Export safeSerializeToJson from core index.ts.
- Add tool argument validation tests for both OpenAI and LangChain extensions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fpfp100 pushed a commit that referenced this pull request Apr 9, 2026
…tensions, align tool serialization

- Remove isContentRecordingEnabled toggle: content recording is now ON by default
  (aligned with Python/.NET SDKs). suppressInvokeAgentInput remains.
- Remove truncateValue from both extensions: truncation now happens at the
  span/exporter level in core, not pre-truncated in extensions.
- Use safeSerializeToJson for tool arguments/results in both extensions,
  matching the core ExecuteToolScope pattern from PR #228.
- Export safeSerializeToJson from core index.ts.
- Add tool argument validation tests for both OpenAI and LangChain extensions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fpfp100 pushed a commit that referenced this pull request Apr 9, 2026
…tensions, align tool serialization

- Remove isContentRecordingEnabled toggle: content recording is now ON by default
  (aligned with Python/.NET SDKs). suppressInvokeAgentInput remains.
- Remove truncateValue from both extensions: truncation now happens at the
  span/exporter level in core, not pre-truncated in extensions.
- Use safeSerializeToJson for tool arguments/results in both extensions,
  matching the core ExecuteToolScope pattern from PR #228.
- Export safeSerializeToJson from core index.ts.
- Add tool argument validation tests for both OpenAI and LangChain extensions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fpfp100 added a commit that referenced this pull request Apr 13, 2026
…231)

* Add OTEL gen-ai message format support for auto-instrumented input/output message tracing

- OpenAI extension: Auto-record structured InputMessages/OutputMessages on response, generation,
  and function spans via OpenAIAgentsTraceProcessor with isContentRecordingEnabled option
- LangChain extension: Auto-record structured InputMessages/OutputMessages on chat, invoke_agent,
  and execute_tool spans via LangChainTracer with isContentRecordingEnabled option
- LangChain v1 support: Fix setToolAttributes to handle plain string tool results (v1 format),
  fix tool_call_id extraction from inputs, fix setSystemInstructionsAttribute to use getMessageType()
  for all message formats, fix setTokenAttributes to check last message for usage_metadata,
  fix getModel to check v1 direct response_metadata path
- Add message-schema-validator test helper for validating OTEL gen-ai message contract
- Add LangChainMessageContract and OpenAIMessageContract test suites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address code review findings (CRM-001 through CRM-013)

- CRM-001: Move GEN_AI_TOOL_TYPE_KEY setAttribute outside forEach loop
- CRM-002: Wrap string output/input fallbacks in versioned OTEL message envelope
- CRM-003: Support tokenUsage shape (promptTokens/completionTokens) in setTokenAttributes
- CRM-009: Remove unused getAttributesFromInput export
- CRM-010: Replace dead extractMessageContent with extractStringContent delegating to extractRawContent
- CRM-011: Fix self-referential comment
- CRM-006: Add direct v1 constructor format tests for input/output messages
- CRM-007: Add response span content-gating suppression test
- CRM-008: Add empty array and null entry edge case tests
- CRM-013: Add function_call, input_file, malformed JSON, and unknown block type tests
- Fix getMessageType to skip v1 'constructor' type and check id array for message class

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove isContentRecordingEnabled gating, remove truncateValue from extensions, align tool serialization

- Remove isContentRecordingEnabled toggle: content recording is now ON by default
  (aligned with Python/.NET SDKs). suppressInvokeAgentInput remains.
- Remove truncateValue from both extensions: truncation now happens at the
  span/exporter level in core, not pre-truncated in extensions.
- Use safeSerializeToJson for tool arguments/results in both extensions,
  matching the core ExecuteToolScope pattern from PR #228.
- Export safeSerializeToJson from core index.ts.
- Add tool argument validation tests for both OpenAI and LangChain extensions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address PR review: fix output fallback, input_image part type, stale JSDoc

- processResponseSpanData: add else fallback for non-array output via
  wrapRawContentAsOutputMessages (handles object output)
- mapInputContentBlock: map input_image to type 'blob' (matches BlobPart
  contract) instead of non-standard 'image'
- Remove stale @param options JSDoc from LangChainTraceInstrumentor.instrument

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Use MAX_SPAN_SIZE_BYTES constant for truncation, export from observability, add missing expect import

- Replace hardcoded 1024 with MAX_SPAN_SIZE_BYTES in OpenAI extensions Utils
- Export MAX_SPAN_SIZE_BYTES from observability package
- Add missing `import { expect } from '@jest/globals'` to test helper

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Peng Fan <pefan@microsoft.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants