diff --git a/src/Observability/Runtime/docs/schemas/EXAMPLES.md b/src/Observability/Runtime/docs/schemas/EXAMPLES.md new file mode 100644 index 00000000..78cad54d --- /dev/null +++ b/src/Observability/Runtime/docs/schemas/EXAMPLES.md @@ -0,0 +1,306 @@ +# A365 Input/Output Message Schema Examples + +> **A365 Schema Version:** 1.0.0 | **Based on OTel Semconv:** v1.40.0 + +--- + +## Input Message Examples (`gen_ai.input.messages`) + +### Simple — Text Chat + +```json +[ + { + "role": "system", + "parts": [ + { "type": "text", "content": "You are a helpful assistant." } + ] + }, + { + "role": "user", + "parts": [ + { "type": "text", "content": "What meetings do I have today?" } + ] + } +] +``` + +### Complex — All Input Part Types + +A multi-turn conversation demonstrating every input part type: text, tool_call (from prior assistant turn), tool_call_response, server_tool_call, server_tool_call_response, blob, file, uri, reasoning, and a custom generic part. + +```json +[ + { + "role": "system", + "parts": [ + { "type": "text", "content": "You are a project assistant with access to tools, files, and images." } + ], + "name": "OrchestratorAgent" + }, + { + "role": "user", + "parts": [ + { "type": "text", "content": "Summarize the attached document, check the weather in Seattle, and describe the whiteboard photo." }, + { + "type": "file", + "modality": "image", + "mime_type": "application/pdf", + "file_id": "file-report-q1-2026" + }, + { + "type": "uri", + "modality": "image", + "mime_type": "image/png", + "uri": "https://sharepoint.com/sites/team/whiteboard-photo.png" + }, + { + "type": "blob", + "modality": "audio", + "mime_type": "audio/wav", + "content": "/9j/4AAQSkZJRg..." + } + ], + "name": "UserJohnDoe" + }, + { + "role": "assistant", + "parts": [ + { "type": "text", "content": "Let me look up the weather and analyze your files." }, + { + "type": "tool_call", + "id": "call_weather_001", + "name": "get_weather", + "arguments": { "city": "Seattle", "units": "fahrenheit" } + }, + { + "type": "reasoning", + "content": "User attached a PDF, an image URI, and an audio blob. I should process the weather tool call first, then analyze the attachments." + } + ] + }, + { + "role": "tool", + "parts": [ + { + "type": "tool_call_response", + "id": "call_weather_001", + "response": { "temperature": 57, "condition": "rainy", "humidity": 82 } + } + ] + }, + { + "role": "assistant", + "parts": [ + { + "type": "server_tool_call", + "id": "stc_code_001", + "name": "code_interpreter", + "server_tool_call": { + "type": "code_interpreter", + "code": "import pandas as pd\ndf = pd.read_csv('sales.csv')\nprint(df.describe())" + } + }, + { + "type": "server_tool_call_response", + "id": "stc_code_001", + "server_tool_call_response": { + "type": "code_interpreter", + "output": "count: 1200, mean: 45000, max: 120000" + } + } + ] + }, + { + "role": "user", + "parts": [ + { + "type": "microsoft.a365.adaptive_card", + "card_id": "ac-approval-001", + "action": "approved" + } + ], + "name": "UserJohnDoe" + } +] +``` + +**Part types demonstrated:** + +| Part Type | Where Used | Description | +|---|---|---| +| `text` | system, user, assistant | Plain text messages | +| `tool_call` | assistant (prior turn) | Model requested a client-side tool | +| `tool_call_response` | tool | Client-side tool result sent back | +| `server_tool_call` | assistant (prior turn) | Server-side tool invocation | +| `server_tool_call_response` | assistant (prior turn) | Server-side tool result | +| `blob` | user | Inline binary data (base64) | +| `file` | user | Pre-uploaded file reference | +| `uri` | user | External file by URL | +| `reasoning` | assistant (prior turn) | Chain-of-thought from model | +| `microsoft.a365.adaptive_card` | user | Custom A365 GenericPart | + +--- + +## Output Message Examples (`gen_ai.output.messages`) + +### Simple — Text Response + +```json +[ + { + "role": "assistant", + "finish_reason": "stop", + "parts": [ + { "type": "text", "content": "You have 3 meetings today: standup at 9 AM, design review at 11 AM, and a 1:1 at 3 PM." } + ] + } +] +``` + +### Complex — All Output Part Types + +A response demonstrating every output part type: reasoning, text, tool_call, server_tool_call with response, and a custom generic part. Also shows multiple finish reasons. + +```json +[ + { + "role": "assistant", + "finish_reason": "stop", + "parts": [ + { + "type": "reasoning", + "content": "The user asked for a document summary, weather, and whiteboard analysis. I have the weather data from the tool call. The code_interpreter analyzed the sales data. I should compile all results into a structured response." + }, + { + "type": "text", + "content": "Here's your summary:\n\n**Weather:** Seattle is currently rainy at 57°F with 82% humidity.\n\n**Q1 Report:** Revenue averaged $45K per deal across 1,200 transactions, with a max deal of $120K.\n\n**Whiteboard:** The whiteboard shows a system architecture diagram with three microservices connected via an API gateway." + }, + { + "type": "server_tool_call", + "id": "stc_search_001", + "name": "web_search", + "server_tool_call": { + "type": "web_search", + "query": "Seattle weather forecast March 2026" + } + }, + { + "type": "server_tool_call_response", + "id": "stc_search_001", + "server_tool_call_response": { + "type": "web_search", + "results": [ + { "title": "Seattle Weather - March 2026", "url": "https://weather.com/seattle", "snippet": "Expect rain through the week..." } + ] + } + }, + { + "type": "blob", + "modality": "image", + "mime_type": "image/png", + "content": "iVBORw0KGgoAAAANSUhEUg..." + }, + { + "type": "uri", + "modality": "image", + "mime_type": "image/png", + "uri": "https://ai-generated.example.com/chart-q1-revenue.png" + } + ], + "name": "ProjectAssistant" + } +] +``` + +**Additional output examples by finish reason:** + +#### Tool Call Request + +```json +[ + { + "role": "assistant", + "finish_reason": "tool_call", + "parts": [ + { "type": "text", "content": "Let me check that for you." }, + { + "type": "tool_call", + "id": "call_sales_q1", + "name": "query_sales_data", + "arguments": { "quarter": "Q1", "year": 2026 } + }, + { + "type": "tool_call", + "id": "call_calendar", + "name": "get_calendar", + "arguments": { "date": "2026-03-25" } + } + ] + } +] +``` + +#### Content Filter + +```json +[ + { + "role": "assistant", + "finish_reason": "content_filter", + "parts": [ + { "type": "text", "content": "I'm unable to provide that information due to content policy restrictions." } + ] + } +] +``` + +#### Token Limit + +```json +[ + { + "role": "assistant", + "finish_reason": "length", + "parts": [ + { "type": "text", "content": "Here is the beginning of the report: Q1 revenue increased by 15% year-over-year driven by strong adoption of..." } + ] + } +] +``` + +#### Error + +```json +[ + { + "role": "assistant", + "finish_reason": "error", + "parts": [ + { "type": "text", "content": "An error occurred while processing your request. Please try again." } + ] + } +] +``` + +**Part types demonstrated in output:** + +| Part Type | Description | +|---|---| +| `text` | Direct text response from model | +| `reasoning` | Chain-of-thought / thinking content | +| `tool_call` | Model requesting client-side tool execution | +| `server_tool_call` | Server-side tool invocation details | +| `server_tool_call_response` | Server-side tool result | +| `blob` | Generated binary content (e.g., chart image) | +| `uri` | Reference to generated content | + +**Finish reasons demonstrated:** + +| Finish Reason | Meaning | +|---|---| +| `stop` | Model completed naturally | +| `tool_call` | Model is requesting tool execution | +| `content_filter` | Blocked by content policy | +| `length` | Token limit exceeded | +| `error` | Generation encountered an error | diff --git a/src/Observability/Runtime/docs/schemas/SCHEMA-VERSION.md b/src/Observability/Runtime/docs/schemas/SCHEMA-VERSION.md new file mode 100644 index 00000000..445bdef8 --- /dev/null +++ b/src/Observability/Runtime/docs/schemas/SCHEMA-VERSION.md @@ -0,0 +1,51 @@ +# A365 Observability Input/Output Message Schema Versions + +## Current Version + +| Field | Value | +|---|---| +| **A365 Schema Version** | 1.0.0 | +| **OTel Semconv Baseline** | [v1.40.0](https://github.com/open-telemetry/semantic-conventions/tree/v1.40.0) | +| **OTel Semconv Commit** | [`30003a993`](https://github.com/open-telemetry/semantic-conventions/commit/30003a9937eb7bcde6984877149055278405e03c) | + +## Schema Files + +| File | Span Attribute | Description | +|---|---|---| +| [a365-input-messages.json](a365-input-messages.json) | `gen_ai.input.messages` | Chat history sent to the model | +| [a365-output-messages.json](a365-output-messages.json) | `gen_ai.output.messages` | Model response (choices/candidates) | + +## OTel Semconv Compatibility Matrix + +| A365 Schema Version | Based on OTel Semconv | Part Types | Notes | +|---|---|---|---| +| 1.0.0 | v1.40.0 | 10 (all OTel types) | Initial release. Includes ServerToolCall parts added in v1.40.0 | + +### OTel Input/Output Schema Change History (for reference) + +| OTel Semconv | File SHA (input) | Changes from Previous | +|---|---|---| +| v1.36.0 | — | Schema files did not exist | +| v1.37.0 | `22910f30` | **Schema introduced.** 4 part types: Text, ToolCallRequest, ToolCallResponse, Generic. No `name` field. | +| v1.38.0 | `5fbd431f` | **Major expansion.** Added Blob, File, Uri, Reasoning parts. Added Modality enum. Added `name` field to ChatMessage. | +| v1.39.0 | `5fbd431f` | No changes (identical to v1.38.0) | +| v1.40.0 | `5585531c` | Added ServerToolCallPart, ServerToolCallResponsePart. Minor wording fix. | + +## Applicable Scopes + +| A365 Scope | Uses This Schema? | Notes | +|---|---|---| +| `InvokeAgentScope` | ✅ | Full conversation context | +| `InferenceScope` | ✅ | Chat history + model response | +| `OutputScope` | ✅ | Outgoing messages to user | +| `ExecuteToolScope` | ❌ | Uses `gen_ai.tool.*` attributes instead | + +## Changelog + +### 1.0.0 + +- Initial A365 input/output message schema +- Profiles OTel GenAI semconv v1.40.0 input/output messages format +- Supports all OTel part types: TextPart, ToolCallRequestPart, ToolCallResponsePart, ServerToolCallPart, ServerToolCallResponsePart, BlobPart, FilePart, UriPart, ReasoningPart, GenericPart +- All objects allow `additionalProperties` for future A365-specific extensions +- Custom A365 part types can be added via `GenericPart` using `microsoft.a365.*` type prefix diff --git a/src/Observability/Runtime/docs/schemas/a365-input-messages.json b/src/Observability/Runtime/docs/schemas/a365-input-messages.json new file mode 100644 index 00000000..21f6b7b1 --- /dev/null +++ b/src/Observability/Runtime/docs/schemas/a365-input-messages.json @@ -0,0 +1,185 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://microsoft.com/agents/a365/observability/schemas/input-messages", + "title": "A365 Input Messages", + "description": "A365 Observability input message schema for the gen_ai.input.messages span attribute. Profiles the OTel GenAI semantic conventions input messages format.", + "a365_schema_version": "1.0.0", + "otel_semconv_baseline": "v1.40.0", + "otel_semconv_commit": "30003a9937eb7bcde6984877149055278405e03c", + + "type": "array", + "items": { + "$ref": "#/$defs/ChatMessage" + }, + + "$defs": { + "Role": { + "description": "Role of the entity that created the message.", + "enum": ["system", "user", "assistant", "tool"], + "type": "string" + }, + + "Modality": { + "description": "The general modality of media content.", + "enum": ["image", "video", "audio"], + "type": "string" + }, + + "ChatMessage": { + "description": "Represents a single message in the chat history sent to the model.", + "type": "object", + "additionalProperties": true, + "required": ["role", "parts"], + "properties": { + "role": { + "anyOf": [{ "$ref": "#/$defs/Role" }, { "type": "string" }], + "description": "Role of the entity that created the message." + }, + "parts": { + "description": "List of message parts that make up the message content.", + "type": "array", + "items": { + "anyOf": [ + { "$ref": "#/$defs/TextPart" }, + { "$ref": "#/$defs/ToolCallRequestPart" }, + { "$ref": "#/$defs/ToolCallResponsePart" }, + { "$ref": "#/$defs/ServerToolCallPart" }, + { "$ref": "#/$defs/ServerToolCallResponsePart" }, + { "$ref": "#/$defs/BlobPart" }, + { "$ref": "#/$defs/FilePart" }, + { "$ref": "#/$defs/UriPart" }, + { "$ref": "#/$defs/ReasoningPart" }, + { "$ref": "#/$defs/GenericPart" } + ] + } + }, + "name": { + "anyOf": [{ "type": "string" }, { "type": "null" }], + "default": null, + "description": "The name of the participant." + } + } + }, + + "TextPart": { + "description": "Represents text content sent to the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "content"], + "properties": { + "type": { "const": "text" }, + "content": { "type": "string", "description": "Text content sent to the model." } + } + }, + + "ToolCallRequestPart": { + "description": "Represents a tool call requested by the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "name"], + "properties": { + "type": { "const": "tool_call" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "Unique identifier for the tool call." }, + "name": { "type": "string", "description": "Name of the tool." }, + "arguments": { "default": null, "description": "Arguments for the tool call." } + } + }, + + "ToolCallResponsePart": { + "description": "Represents a tool call result sent to the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "response"], + "properties": { + "type": { "const": "tool_call_response" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "Unique tool call identifier." }, + "response": { "description": "Tool call response." } + } + }, + + "ServerToolCallPart": { + "description": "Represents a server-side tool call invocation (e.g., code_interpreter, web_search).", + "type": "object", + "additionalProperties": true, + "required": ["type", "name", "server_tool_call"], + "properties": { + "type": { "const": "server_tool_call" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "name": { "type": "string", "description": "Name of the server tool." }, + "server_tool_call": { "description": "Server tool call details.", "type": "object", "additionalProperties": true, "required": ["type"], "properties": { "type": { "type": "string" } } } + } + }, + + "ServerToolCallResponsePart": { + "description": "Represents a server-side tool call response.", + "type": "object", + "additionalProperties": true, + "required": ["type", "server_tool_call_response"], + "properties": { + "type": { "const": "server_tool_call_response" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "server_tool_call_response": { "description": "Server tool call response details.", "type": "object", "additionalProperties": true, "required": ["type"], "properties": { "type": { "type": "string" } } } + } + }, + + "BlobPart": { + "description": "Represents blob binary data sent inline to the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "modality", "content"], + "properties": { + "type": { "const": "blob" }, + "mime_type": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "IANA MIME type." }, + "modality": { "anyOf": [{ "$ref": "#/$defs/Modality" }, { "type": "string" }], "description": "General modality of the data." }, + "content": { "type": "string", "format": "binary", "description": "Base64-encoded binary data." } + } + }, + + "FilePart": { + "description": "Represents an external file sent to the model by file ID.", + "type": "object", + "additionalProperties": true, + "required": ["type", "modality", "file_id"], + "properties": { + "type": { "const": "file" }, + "mime_type": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "modality": { "anyOf": [{ "$ref": "#/$defs/Modality" }, { "type": "string" }] }, + "file_id": { "type": "string", "description": "Identifier referencing a pre-uploaded file." } + } + }, + + "UriPart": { + "description": "Represents an external file sent to the model by URI.", + "type": "object", + "additionalProperties": true, + "required": ["type", "modality", "uri"], + "properties": { + "type": { "const": "uri" }, + "mime_type": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "modality": { "anyOf": [{ "$ref": "#/$defs/Modality" }, { "type": "string" }] }, + "uri": { "type": "string", "description": "URI referencing attached data." } + } + }, + + "ReasoningPart": { + "description": "Represents reasoning/thinking content from the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "content"], + "properties": { + "type": { "const": "reasoning" }, + "content": { "type": "string", "description": "Reasoning/thinking content." } + } + }, + + "GenericPart": { + "description": "Represents an arbitrary message part for extensibility with custom types.", + "type": "object", + "additionalProperties": true, + "required": ["type"], + "properties": { + "type": { "type": "string", "description": "Custom part type identifier." } + } + } + } +} diff --git a/src/Observability/Runtime/docs/schemas/a365-output-messages.json b/src/Observability/Runtime/docs/schemas/a365-output-messages.json new file mode 100644 index 00000000..92820e21 --- /dev/null +++ b/src/Observability/Runtime/docs/schemas/a365-output-messages.json @@ -0,0 +1,195 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://microsoft.com/agents/a365/observability/schemas/output-messages", + "title": "A365 Output Messages", + "description": "A365 Observability output message schema for the gen_ai.output.messages span attribute. Profiles the OTel GenAI semantic conventions output messages format.", + "a365_schema_version": "1.0.0", + "otel_semconv_baseline": "v1.40.0", + "otel_semconv_commit": "30003a9937eb7bcde6984877149055278405e03c", + + "type": "array", + "items": { + "$ref": "#/$defs/OutputMessage" + }, + + "$defs": { + "Role": { + "description": "Role of the entity that created the message.", + "enum": ["system", "user", "assistant", "tool"], + "type": "string" + }, + + "FinishReason": { + "description": "Reason for finishing the generation.", + "enum": ["stop", "length", "content_filter", "tool_call", "error"], + "type": "string" + }, + + "Modality": { + "description": "The general modality of media content.", + "enum": ["image", "video", "audio"], + "type": "string" + }, + + "OutputMessage": { + "description": "Represents an output message generated by the model or agent. Each message corresponds to exactly one generation (choice/candidate).", + "type": "object", + "additionalProperties": true, + "required": ["role", "parts", "finish_reason"], + "properties": { + "role": { + "anyOf": [{ "$ref": "#/$defs/Role" }, { "type": "string" }], + "description": "Role of the entity that created the message." + }, + "parts": { + "description": "List of message parts that make up the message content.", + "type": "array", + "items": { + "anyOf": [ + { "$ref": "#/$defs/TextPart" }, + { "$ref": "#/$defs/ToolCallRequestPart" }, + { "$ref": "#/$defs/ToolCallResponsePart" }, + { "$ref": "#/$defs/ServerToolCallPart" }, + { "$ref": "#/$defs/ServerToolCallResponsePart" }, + { "$ref": "#/$defs/BlobPart" }, + { "$ref": "#/$defs/FilePart" }, + { "$ref": "#/$defs/UriPart" }, + { "$ref": "#/$defs/ReasoningPart" }, + { "$ref": "#/$defs/GenericPart" } + ] + } + }, + "name": { + "anyOf": [{ "type": "string" }, { "type": "null" }], + "default": null, + "description": "The name of the participant." + }, + "finish_reason": { + "anyOf": [{ "$ref": "#/$defs/FinishReason" }, { "type": "string" }], + "description": "Reason for finishing the generation." + } + } + }, + + "TextPart": { + "description": "Represents text content received from the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "content"], + "properties": { + "type": { "const": "text" }, + "content": { "type": "string", "description": "Text content from the model." } + } + }, + + "ToolCallRequestPart": { + "description": "Represents a tool call requested by the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "name"], + "properties": { + "type": { "const": "tool_call" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "Unique identifier for the tool call." }, + "name": { "type": "string", "description": "Name of the tool." }, + "arguments": { "default": null, "description": "Arguments for the tool call." } + } + }, + + "ToolCallResponsePart": { + "description": "Represents a tool call result.", + "type": "object", + "additionalProperties": true, + "required": ["type", "response"], + "properties": { + "type": { "const": "tool_call_response" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "Unique tool call identifier." }, + "response": { "description": "Tool call response." } + } + }, + + "ServerToolCallPart": { + "description": "Represents a server-side tool call invocation (e.g., code_interpreter, web_search).", + "type": "object", + "additionalProperties": true, + "required": ["type", "name", "server_tool_call"], + "properties": { + "type": { "const": "server_tool_call" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "name": { "type": "string", "description": "Name of the server tool." }, + "server_tool_call": { "description": "Server tool call details.", "type": "object", "additionalProperties": true, "required": ["type"], "properties": { "type": { "type": "string" } } } + } + }, + + "ServerToolCallResponsePart": { + "description": "Represents a server-side tool call response.", + "type": "object", + "additionalProperties": true, + "required": ["type", "server_tool_call_response"], + "properties": { + "type": { "const": "server_tool_call_response" }, + "id": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "server_tool_call_response": { "description": "Server tool call response details.", "type": "object", "additionalProperties": true, "required": ["type"], "properties": { "type": { "type": "string" } } } + } + }, + + "BlobPart": { + "description": "Represents blob binary data sent inline.", + "type": "object", + "additionalProperties": true, + "required": ["type", "modality", "content"], + "properties": { + "type": { "const": "blob" }, + "mime_type": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null, "description": "IANA MIME type." }, + "modality": { "anyOf": [{ "$ref": "#/$defs/Modality" }, { "type": "string" }], "description": "General modality of the data." }, + "content": { "type": "string", "format": "binary", "description": "Base64-encoded binary data." } + } + }, + + "FilePart": { + "description": "Represents an external file by file ID.", + "type": "object", + "additionalProperties": true, + "required": ["type", "modality", "file_id"], + "properties": { + "type": { "const": "file" }, + "mime_type": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "modality": { "anyOf": [{ "$ref": "#/$defs/Modality" }, { "type": "string" }] }, + "file_id": { "type": "string", "description": "Identifier referencing a pre-uploaded file." } + } + }, + + "UriPart": { + "description": "Represents an external file by URI.", + "type": "object", + "additionalProperties": true, + "required": ["type", "modality", "uri"], + "properties": { + "type": { "const": "uri" }, + "mime_type": { "anyOf": [{ "type": "string" }, { "type": "null" }], "default": null }, + "modality": { "anyOf": [{ "$ref": "#/$defs/Modality" }, { "type": "string" }] }, + "uri": { "type": "string", "description": "URI referencing attached data." } + } + }, + + "ReasoningPart": { + "description": "Represents reasoning/thinking content from the model.", + "type": "object", + "additionalProperties": true, + "required": ["type", "content"], + "properties": { + "type": { "const": "reasoning" }, + "content": { "type": "string", "description": "Reasoning/thinking content." } + } + }, + + "GenericPart": { + "description": "Represents an arbitrary message part for extensibility with custom types.", + "type": "object", + "additionalProperties": true, + "required": ["type"], + "properties": { + "type": { "type": "string", "description": "Custom part type identifier." } + } + } + } +}