@cuylabs/agent-a365-observability 4.6.0 → 4.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -5
- package/dist/index.d.ts +38 -1
- package/dist/index.js +96 -0
- package/docs/README.md +3 -2
- package/docs/agent-core-otel.md +9 -1
- package/docs/architecture.md +17 -3
- package/docs/microsoft-a365-observability.md +1 -2
- package/docs/microsoft-node-package-comparison.md +3 -3
- package/docs/sdk-and-auth-flow.md +3 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ Dependency roles:
|
|
|
40
40
|
```typescript
|
|
41
41
|
import { createAgent } from "@cuylabs/agent-core";
|
|
42
42
|
import {
|
|
43
|
+
createA365ObservedTurnSource,
|
|
43
44
|
createA365S2STokenResolverFromEnv,
|
|
44
45
|
createA365TracingConfig,
|
|
45
46
|
initA365S2SObservability,
|
|
@@ -90,6 +91,25 @@ await agent.close();
|
|
|
90
91
|
await observability.shutdown();
|
|
91
92
|
```
|
|
92
93
|
|
|
94
|
+
When you are adapting a custom channel around `AgentTurnSource`, use
|
|
95
|
+
`createA365ObservedTurnSource(...)` instead of hand-rolling async-generator
|
|
96
|
+
wrapping. The helper keeps the full event stream inside the Agent 365 baggage
|
|
97
|
+
scope while letting the channel own its own metadata mapping:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const observedSource = createA365ObservedTurnSource({
|
|
101
|
+
source: agent,
|
|
102
|
+
context: ({ sessionId }) => ({
|
|
103
|
+
tenantId: "tenant-123",
|
|
104
|
+
agentId: "agent-456",
|
|
105
|
+
conversationId: sessionId,
|
|
106
|
+
sessionId,
|
|
107
|
+
channelName: "slack",
|
|
108
|
+
userId: "slack-user-id",
|
|
109
|
+
}),
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
93
113
|
## M365 / Teams bot turns
|
|
94
114
|
|
|
95
115
|
When your bot uses `@microsoft/agents-hosting` `TurnContext`, use the
|
|
@@ -148,7 +168,10 @@ The integration has four separate pieces:
|
|
|
148
168
|
contract.
|
|
149
169
|
3. `runWithA365Context(...)` or `runWithA365TurnContext(...)` binds
|
|
150
170
|
per-request Agent 365 baggage before `agent.chat()` runs.
|
|
151
|
-
4. `
|
|
171
|
+
4. `createA365ObservedTurnSource(...)` wraps a channel-neutral
|
|
172
|
+
`AgentTurnSource` when a host needs streaming-safe A365 baggage around every
|
|
173
|
+
emitted event.
|
|
174
|
+
5. `createA365S2STokenResolver(...)` provides a reusable service-to-service
|
|
152
175
|
token resolver for Agent 365 Observability API export.
|
|
153
176
|
|
|
154
177
|
The source follows those same boundaries: `auth/` owns Agent 365 S2S token
|
|
@@ -156,11 +179,11 @@ resolution, `context/` owns baggage and TurnContext mapping, `runtime/` owns
|
|
|
156
179
|
Microsoft SDK startup and lazy loading, and `tracing/` owns the agent-core
|
|
157
180
|
tracing config adapter.
|
|
158
181
|
|
|
159
|
-
Use agent-core for portable OpenTelemetry spans:
|
|
182
|
+
Use agent-core and AI SDK v7 for portable OpenTelemetry spans:
|
|
160
183
|
|
|
161
184
|
- `invoke_agent` agent spans
|
|
162
|
-
- `
|
|
163
|
-
- AI SDK
|
|
185
|
+
- AI SDK `chat` model spans nested under the agent turn
|
|
186
|
+
- AI SDK `execute_tool` tool spans when tools run
|
|
164
187
|
|
|
165
188
|
Use this package for Agent 365-specific context on those spans:
|
|
166
189
|
|
|
@@ -189,7 +212,7 @@ See [docs/agent-core-otel.md](./docs/agent-core-otel.md) for details.
|
|
|
189
212
|
|
|
190
213
|
Phoenix is a normal OTLP destination. You pass a span processor/exporter into `agent-core` tracing, and `agent-core` owns the tracer provider lifecycle for that example.
|
|
191
214
|
|
|
192
|
-
Agent 365 is different. The Microsoft SDK owns the exporter and adds an Agent 365 span processor that copies baggage into span attributes. `agent-core` still emits the agent
|
|
215
|
+
Agent 365 is different. The Microsoft SDK owns the exporter and adds an Agent 365 span processor that copies baggage into span attributes. `agent-core` still emits the agent and AI SDK spans, while this package starts the Microsoft exporter and wraps each request with the tenant, agent, conversation, channel, and caller baggage that Agent 365 expects.
|
|
193
216
|
|
|
194
217
|
## AI SDK Telemetry
|
|
195
218
|
|
|
@@ -197,6 +220,8 @@ Agent 365 is different. The Microsoft SDK owns the exporter and adds an Agent 36
|
|
|
197
220
|
|
|
198
221
|
This package does not replace that model telemetry. It adds the Microsoft Agent 365 layer: exporter startup, token resolution, and baggage that flows `microsoft.tenant.id`, `gen_ai.agent.id`, conversation, channel, and caller identity onto the spans.
|
|
199
222
|
|
|
223
|
+
`createA365TracingConfig()` defaults `emitToolSpans` to `false`. AI SDK v7 already emits `execute_tool` spans with the Agent 365 GenAI tool keys, including `gen_ai.tool.name`, `gen_ai.tool.call.id`, `gen_ai.tool.call.arguments`, and `gen_ai.tool.call.result` when content recording is enabled. Disabling agent-core's extra tool-span layer avoids duplicate `execute_tool` spans for one tool call while preserving model and tool observability from the AI SDK integration.
|
|
224
|
+
|
|
200
225
|
If you need to plug in another AI SDK telemetry integration, pass it through `createA365TracingConfig()`:
|
|
201
226
|
|
|
202
227
|
```typescript
|
|
@@ -212,6 +237,8 @@ const agent = createAgent({
|
|
|
212
237
|
|
|
213
238
|
Set `useGenAIOpenTelemetry: false` only when you intentionally want to use global AI SDK telemetry integrations or another model-span integration.
|
|
214
239
|
|
|
240
|
+
Set `emitToolSpans: true` only when your agent execution path does not use AI SDK v7 tool telemetry and you need agent-core to emit tool spans itself.
|
|
241
|
+
|
|
215
242
|
## TurnContext Mapping
|
|
216
243
|
|
|
217
244
|
`runWithA365TurnContext(...)` follows Microsoft's
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TelemetryOptions } from 'ai';
|
|
2
|
+
import { AgentTurnSourceChatOptions, AgentTurnSource } from '@cuylabs/agent-core';
|
|
2
3
|
|
|
3
4
|
type A365TokenResolver = (agentId: string, tenantId: string) => string | null | Promise<string | null>;
|
|
4
5
|
type A365Logger = {
|
|
@@ -125,6 +126,26 @@ type A365TracingConfigOptions = {
|
|
|
125
126
|
agentId?: string;
|
|
126
127
|
agentDescription?: string;
|
|
127
128
|
agentVersion?: string;
|
|
129
|
+
/**
|
|
130
|
+
* Whether to record prompts/tool arguments in GenAI spans.
|
|
131
|
+
*
|
|
132
|
+
* Defaults to agent-core's tracing default.
|
|
133
|
+
*/
|
|
134
|
+
recordInputs?: boolean;
|
|
135
|
+
/**
|
|
136
|
+
* Whether to record responses/tool results in GenAI spans.
|
|
137
|
+
*
|
|
138
|
+
* Defaults to agent-core's tracing default.
|
|
139
|
+
*/
|
|
140
|
+
recordOutputs?: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Whether agent-core should emit its own `execute_tool` spans.
|
|
143
|
+
*
|
|
144
|
+
* Agent 365 defaults this to `false` because AI SDK v7's
|
|
145
|
+
* `GenAIOpenTelemetry` already emits A365-compatible tool spans. Keeping both
|
|
146
|
+
* enabled can produce duplicate `execute_tool` spans for one tool call.
|
|
147
|
+
*/
|
|
148
|
+
emitToolSpans?: boolean;
|
|
128
149
|
/**
|
|
129
150
|
* Include tenant as a static span attribute. Prefer `runWithA365Context`
|
|
130
151
|
* when tenant varies per request.
|
|
@@ -139,6 +160,9 @@ type A365TracingConfig = {
|
|
|
139
160
|
agentId?: string;
|
|
140
161
|
agentDescription?: string;
|
|
141
162
|
agentVersion?: string;
|
|
163
|
+
recordInputs?: boolean;
|
|
164
|
+
recordOutputs?: boolean;
|
|
165
|
+
emitToolSpans?: boolean;
|
|
142
166
|
useGenAIOpenTelemetry?: boolean;
|
|
143
167
|
telemetryIntegrations?: TelemetryOptions["integrations"];
|
|
144
168
|
useGlobalTelemetryIntegrations?: boolean;
|
|
@@ -301,6 +325,19 @@ declare function createA365ContextFromTurnContext(turnContext: A365TurnContextLi
|
|
|
301
325
|
declare function runWithA365TurnContext<T>(turnContext: A365TurnContextLike, fn: () => T, runtimeOptions?: A365ObservabilityRuntimeOptions): Promise<Awaited<T>>;
|
|
302
326
|
declare function runWithA365TurnContext<T>(turnContext: A365TurnContextLike, options: A365TurnContextOptions, fn: () => T, runtimeOptions?: A365ObservabilityRuntimeOptions): Promise<Awaited<T>>;
|
|
303
327
|
|
|
328
|
+
type A365ObservedTurnSourceContextInput = {
|
|
329
|
+
sessionId: string;
|
|
330
|
+
message: string;
|
|
331
|
+
options?: AgentTurnSourceChatOptions;
|
|
332
|
+
};
|
|
333
|
+
type A365ObservedTurnSourceContextFactory = (input: A365ObservedTurnSourceContextInput) => A365RequestContext | Promise<A365RequestContext>;
|
|
334
|
+
type A365ObservedTurnSourceOptions = {
|
|
335
|
+
source: AgentTurnSource;
|
|
336
|
+
context: A365RequestContext | A365ObservedTurnSourceContextFactory;
|
|
337
|
+
runtimeOptions?: A365ObservabilityRuntimeOptions;
|
|
338
|
+
};
|
|
339
|
+
declare function createA365ObservedTurnSource({ context, runtimeOptions, source, }: A365ObservedTurnSourceOptions): AgentTurnSource;
|
|
340
|
+
|
|
304
341
|
declare function initA365Observability(options: InitA365ObservabilityOptions): Promise<A365ObservabilityHandle>;
|
|
305
342
|
declare function runWithA365Context<T>(requestContext: A365RequestContext, fn: () => T, options?: A365ObservabilityRuntimeOptions): Promise<Awaited<T>>;
|
|
306
343
|
declare function updateA365ExportToken(token: string, options?: A365ObservabilityRuntimeOptions): Promise<boolean>;
|
|
@@ -346,4 +383,4 @@ type A365OutputScopeContext = A365RequestContext & {
|
|
|
346
383
|
};
|
|
347
384
|
declare function runWithA365OutputMessages<T>(output: A365OutputScopeContext, fn: () => T, options?: A365ObservabilityRuntimeOptions): Promise<Awaited<T>>;
|
|
348
385
|
|
|
349
|
-
export { type A365ActivityAccountLike, type A365ActivityLike, type A365AuthorizationLike, type A365Environment, type A365ExporterEventName, type A365HeadersCarrier, type A365Logger, type A365ManagedIdentityAssertionProvider, type A365MutableHeadersCarrier, type A365OboTokenCacheOptions, type A365ObservabilityConfiguration, type A365ObservabilityHandle, A365ObservabilityHostingModuleLoadError, A365ObservabilityModuleLoadError, type A365ObservabilityModuleLoader, type A365ObservabilityRuntimeOptions, type A365OutputMessagesParam, type A365OutputScopeContext, type A365ParentSpanRef, type A365PerRequestExportConfiguration, type A365RefreshOboObservabilityTokenOptions, type A365RequestContext, type A365ResolvedObservabilityEnvironment, type A365S2STokenResolverFromEnvOptions, type A365S2STokenResolverLogger, type A365S2STokenResolverOptions, type A365TokenResolver, type A365TraceContextOptions, type A365TracingConfig, type A365TracingConfigOptions, type A365TurnContextLike, type A365TurnContextOptions, A365_BAGGAGE_KEYS, A365_EXPORTER_EVENT_NAMES, type InitA365ObservabilityOptions, type InitA365S2SObservabilityOptions, type SpanAttributeValue, applyA365PerRequestEnvironment, buildA365BaggagePairs, createA365ContextFromTurnContext, createA365ContextWithParentSpanRef, createA365OboTokenResolver, createA365S2STokenResolver, createA365S2STokenResolverFromEnv, createA365TracingConfig, extractA365TraceContextFromHeaders, initA365Observability, initA365S2SObservability, injectA365TraceContextToHeaders, invalidateA365OboObservabilityToken, invalidateAllA365OboObservabilityTokens, refreshA365OboObservabilityToken, resolveA365ObservabilityEnvironment, runWithA365Context, runWithA365ExtractedTraceContext, runWithA365OutputMessages, runWithA365ParentSpanRef, runWithA365TurnContext, updateA365ExportToken };
|
|
386
|
+
export { type A365ActivityAccountLike, type A365ActivityLike, type A365AuthorizationLike, type A365Environment, type A365ExporterEventName, type A365HeadersCarrier, type A365Logger, type A365ManagedIdentityAssertionProvider, type A365MutableHeadersCarrier, type A365OboTokenCacheOptions, type A365ObservabilityConfiguration, type A365ObservabilityHandle, A365ObservabilityHostingModuleLoadError, A365ObservabilityModuleLoadError, type A365ObservabilityModuleLoader, type A365ObservabilityRuntimeOptions, type A365ObservedTurnSourceContextFactory, type A365ObservedTurnSourceContextInput, type A365ObservedTurnSourceOptions, type A365OutputMessagesParam, type A365OutputScopeContext, type A365ParentSpanRef, type A365PerRequestExportConfiguration, type A365RefreshOboObservabilityTokenOptions, type A365RequestContext, type A365ResolvedObservabilityEnvironment, type A365S2STokenResolverFromEnvOptions, type A365S2STokenResolverLogger, type A365S2STokenResolverOptions, type A365TokenResolver, type A365TraceContextOptions, type A365TracingConfig, type A365TracingConfigOptions, type A365TurnContextLike, type A365TurnContextOptions, A365_BAGGAGE_KEYS, A365_EXPORTER_EVENT_NAMES, type InitA365ObservabilityOptions, type InitA365S2SObservabilityOptions, type SpanAttributeValue, applyA365PerRequestEnvironment, buildA365BaggagePairs, createA365ContextFromTurnContext, createA365ContextWithParentSpanRef, createA365OboTokenResolver, createA365ObservedTurnSource, createA365S2STokenResolver, createA365S2STokenResolverFromEnv, createA365TracingConfig, extractA365TraceContextFromHeaders, initA365Observability, initA365S2SObservability, injectA365TraceContextToHeaders, invalidateA365OboObservabilityToken, invalidateAllA365OboObservabilityTokens, refreshA365OboObservabilityToken, resolveA365ObservabilityEnvironment, runWithA365Context, runWithA365ExtractedTraceContext, runWithA365OutputMessages, runWithA365ParentSpanRef, runWithA365TurnContext, updateA365ExportToken };
|
package/dist/index.js
CHANGED
|
@@ -876,6 +876,98 @@ async function runWithA365TurnContext(turnContext, optionsOrFn, maybeFnOrRuntime
|
|
|
876
876
|
);
|
|
877
877
|
}
|
|
878
878
|
|
|
879
|
+
// src/internal/async-queue.ts
|
|
880
|
+
var AsyncQueue = class {
|
|
881
|
+
values = [];
|
|
882
|
+
waiters = [];
|
|
883
|
+
closed = false;
|
|
884
|
+
push(value) {
|
|
885
|
+
if (this.closed) {
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
const waiter = this.waiters.shift();
|
|
889
|
+
if (waiter) {
|
|
890
|
+
waiter({ value, done: false });
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
this.values.push(value);
|
|
894
|
+
}
|
|
895
|
+
close() {
|
|
896
|
+
if (this.closed) {
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
this.closed = true;
|
|
900
|
+
for (const waiter of this.waiters.splice(0)) {
|
|
901
|
+
waiter({ value: void 0, done: true });
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
[Symbol.asyncIterator]() {
|
|
905
|
+
return {
|
|
906
|
+
next: () => this.next()
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
next() {
|
|
910
|
+
if (this.values.length > 0) {
|
|
911
|
+
const value = this.values.shift();
|
|
912
|
+
return Promise.resolve({ value, done: false });
|
|
913
|
+
}
|
|
914
|
+
if (this.closed) {
|
|
915
|
+
return Promise.resolve({ value: void 0, done: true });
|
|
916
|
+
}
|
|
917
|
+
return new Promise((resolve) => {
|
|
918
|
+
this.waiters.push(resolve);
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
// src/context/turn-source.ts
|
|
924
|
+
function createA365ObservedTurnSource({
|
|
925
|
+
context,
|
|
926
|
+
runtimeOptions,
|
|
927
|
+
source
|
|
928
|
+
}) {
|
|
929
|
+
const resolveContext = typeof context === "function" ? context : () => context;
|
|
930
|
+
return {
|
|
931
|
+
async *chat(sessionId, message, options) {
|
|
932
|
+
const requestContext = await resolveContext({
|
|
933
|
+
sessionId,
|
|
934
|
+
message,
|
|
935
|
+
options
|
|
936
|
+
});
|
|
937
|
+
const queue = new AsyncQueue();
|
|
938
|
+
let failure;
|
|
939
|
+
void runWithA365Context(
|
|
940
|
+
requestContext,
|
|
941
|
+
async () => {
|
|
942
|
+
try {
|
|
943
|
+
for await (const event of source.chat(
|
|
944
|
+
sessionId,
|
|
945
|
+
message,
|
|
946
|
+
options
|
|
947
|
+
)) {
|
|
948
|
+
queue.push(event);
|
|
949
|
+
}
|
|
950
|
+
} catch (error) {
|
|
951
|
+
failure = error;
|
|
952
|
+
} finally {
|
|
953
|
+
queue.close();
|
|
954
|
+
}
|
|
955
|
+
},
|
|
956
|
+
runtimeOptions
|
|
957
|
+
).catch((error) => {
|
|
958
|
+
failure = error;
|
|
959
|
+
queue.close();
|
|
960
|
+
});
|
|
961
|
+
for await (const event of queue) {
|
|
962
|
+
yield event;
|
|
963
|
+
}
|
|
964
|
+
if (failure) {
|
|
965
|
+
throw failure;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
|
|
879
971
|
// src/runtime/s2s.ts
|
|
880
972
|
async function initA365S2SObservability(options) {
|
|
881
973
|
const env = resolveA365ObservabilityEnvironment(options.s2s?.env);
|
|
@@ -911,6 +1003,9 @@ function createA365TracingConfig(options = {}) {
|
|
|
911
1003
|
...isNonEmpty(options.agentId) ? { agentId: options.agentId.trim() } : {},
|
|
912
1004
|
...isNonEmpty(options.agentDescription) ? { agentDescription: options.agentDescription.trim() } : {},
|
|
913
1005
|
...isNonEmpty(options.agentVersion) ? { agentVersion: options.agentVersion.trim() } : {},
|
|
1006
|
+
...options.recordInputs !== void 0 ? { recordInputs: options.recordInputs } : {},
|
|
1007
|
+
...options.recordOutputs !== void 0 ? { recordOutputs: options.recordOutputs } : {},
|
|
1008
|
+
emitToolSpans: options.emitToolSpans ?? false,
|
|
914
1009
|
...options.useGenAIOpenTelemetry !== void 0 ? { useGenAIOpenTelemetry: options.useGenAIOpenTelemetry } : {},
|
|
915
1010
|
...options.telemetryIntegrations ? { telemetryIntegrations: options.telemetryIntegrations } : {},
|
|
916
1011
|
...options.useGlobalTelemetryIntegrations !== void 0 ? {
|
|
@@ -1041,6 +1136,7 @@ export {
|
|
|
1041
1136
|
createA365ContextFromTurnContext,
|
|
1042
1137
|
createA365ContextWithParentSpanRef,
|
|
1043
1138
|
createA365OboTokenResolver,
|
|
1139
|
+
createA365ObservedTurnSource,
|
|
1044
1140
|
createA365S2STokenResolver,
|
|
1045
1141
|
createA365S2STokenResolverFromEnv,
|
|
1046
1142
|
createA365TracingConfig,
|
package/docs/README.md
CHANGED
|
@@ -29,5 +29,6 @@ The short version:
|
|
|
29
29
|
- `agent-channel-m365` owns Activity ingress and turn wrapping for M365 hosts.
|
|
30
30
|
- Microsoft's Agent 365 observability SDK owns exporter registration and
|
|
31
31
|
baggage-to-span enrichment.
|
|
32
|
-
- this package starts Microsoft observability and wraps
|
|
33
|
-
the Agent 365 baggage
|
|
32
|
+
- this package starts Microsoft observability and wraps callbacks,
|
|
33
|
+
TurnContexts, or generic `AgentTurnSource` streams with the Agent 365 baggage
|
|
34
|
+
that Microsoft expects.
|
package/docs/agent-core-otel.md
CHANGED
|
@@ -8,7 +8,7 @@ replace agent-core telemetry and it does not create agent-core spans itself.
|
|
|
8
8
|
agent-core's OpenTelemetry middleware emits:
|
|
9
9
|
|
|
10
10
|
- `invoke_agent` spans for agent turns;
|
|
11
|
-
- `execute_tool` spans for tool calls;
|
|
11
|
+
- optional `execute_tool` spans for tool calls when `emitToolSpans` is enabled;
|
|
12
12
|
- AI SDK GenAI spans for model calls when AI SDK telemetry is enabled.
|
|
13
13
|
|
|
14
14
|
The root agent span includes common GenAI attributes such as:
|
|
@@ -27,6 +27,14 @@ The root agent span includes common GenAI attributes such as:
|
|
|
27
27
|
stable agent metadata. Per-request metadata belongs in baggage via
|
|
28
28
|
`runWithA365Context(...)`.
|
|
29
29
|
|
|
30
|
+
The A365 tracing adapter intentionally defaults `emitToolSpans` to `false`.
|
|
31
|
+
AI SDK v7's `GenAIOpenTelemetry` integration already emits `execute_tool`
|
|
32
|
+
spans for tool executions, and Microsoft's Agent 365 exporter recognizes those
|
|
33
|
+
spans. Keeping both the AI SDK tool span and the agent-core tool span enabled
|
|
34
|
+
can create duplicate `execute_tool` records for one tool call. Override
|
|
35
|
+
`emitToolSpans: true` only for execution paths that do not use AI SDK v7 tool
|
|
36
|
+
telemetry.
|
|
37
|
+
|
|
30
38
|
## What This Package Adds
|
|
31
39
|
|
|
32
40
|
This package wraps the turn in Agent 365 baggage before agent-core starts its
|
package/docs/architecture.md
CHANGED
|
@@ -31,12 +31,14 @@ Per agent:
|
|
|
31
31
|
|
|
32
32
|
1. the host calls `createAgent({ tracing: createA365TracingConfig(...) })`;
|
|
33
33
|
2. agent-core installs its normal OpenTelemetry middleware;
|
|
34
|
-
3. agent-core emits `invoke_agent
|
|
34
|
+
3. agent-core emits `invoke_agent` spans and AI SDK v7 emits model and
|
|
35
|
+
`execute_tool` spans.
|
|
35
36
|
|
|
36
37
|
Per turn:
|
|
37
38
|
|
|
38
|
-
1. the host or M365 channel calls `runWithA365Context(...)
|
|
39
|
-
`runWithA365TurnContext(...)
|
|
39
|
+
1. the host or M365 channel calls `runWithA365Context(...)`,
|
|
40
|
+
`runWithA365TurnContext(...)`, or wraps an `AgentTurnSource` with
|
|
41
|
+
`createA365ObservedTurnSource(...)`;
|
|
40
42
|
2. this package builds Agent 365 baggage from tenant, agent, conversation,
|
|
41
43
|
channel, and caller identity;
|
|
42
44
|
3. agent-core runs the turn inside that baggage scope;
|
|
@@ -67,3 +69,15 @@ Agent 365 observability has Microsoft-specific concepts:
|
|
|
67
69
|
|
|
68
70
|
Putting those in agent-core would make core platform-specific. This adapter
|
|
69
71
|
keeps the runtime portable while still supporting Agent 365 deployment.
|
|
72
|
+
|
|
73
|
+
## Channel Bridges
|
|
74
|
+
|
|
75
|
+
Channel-specific packages should not depend on this package just to describe
|
|
76
|
+
their native metadata. For example, a Slack adapter can parse Slack user,
|
|
77
|
+
channel, and thread fields without knowing Agent 365 semantic keys.
|
|
78
|
+
|
|
79
|
+
The bridge that combines a channel with Agent 365 should map those fields into
|
|
80
|
+
`A365RequestContext`, then pass that mapping to `createA365ObservedTurnSource`.
|
|
81
|
+
That keeps the async stream and baggage lifecycle reusable while preserving the
|
|
82
|
+
right ownership boundary: channels own channel facts, and the Agent 365 adapter
|
|
83
|
+
owns Microsoft baggage/export behavior.
|
|
@@ -47,8 +47,7 @@ are documented in [sdk-and-auth-flow.md](./sdk-and-auth-flow.md).
|
|
|
47
47
|
## Scope Classes
|
|
48
48
|
|
|
49
49
|
Microsoft exposes explicit scope classes for several span shapes. agent-core
|
|
50
|
-
already emits
|
|
51
|
-
spans.
|
|
50
|
+
already emits the agent span, and AI SDK telemetry covers model and tool spans.
|
|
52
51
|
|
|
53
52
|
The main shape difference is `OutputScope`, which creates a separate
|
|
54
53
|
`output_messages` span. agent-core currently records output messages on the
|
|
@@ -18,8 +18,8 @@ Microsoft's Node observability packages have three practical layers:
|
|
|
18
18
|
The cuylabs adapter sits beside those framework extensions. OpenAI Agents and
|
|
19
19
|
LangChain need extension packages because their framework callbacks must be
|
|
20
20
|
converted into Agent 365-shaped OpenTelemetry spans. agent-core already emits
|
|
21
|
-
agent
|
|
22
|
-
resolution, and Agent 365 baggage.
|
|
21
|
+
agent spans and AI SDK v7 already emits model/tool spans, so this adapter
|
|
22
|
+
focuses on startup, token resolution, and Agent 365 baggage.
|
|
23
23
|
|
|
24
24
|
## What We Use
|
|
25
25
|
|
|
@@ -45,7 +45,7 @@ resolution, and Agent 365 baggage.
|
|
|
45
45
|
| Microsoft capability | Status | Reason |
|
|
46
46
|
| ----------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
47
47
|
| `InvokeAgentScope` | Not used by default. | agent-core already emits the agent turn span. Creating another scope would duplicate `invoke_agent` telemetry. |
|
|
48
|
-
| `ExecuteToolScope` | Not used by default. |
|
|
48
|
+
| `ExecuteToolScope` | Not used by default. | AI SDK v7 already emits Agent 365-shaped tool spans for agent-core tool calls. |
|
|
49
49
|
| `InferenceScope` | Not used by default. | AI SDK telemetry already emits model spans under the agent turn. |
|
|
50
50
|
| OpenAI Agents extension | Not used by default. | It patches `@openai/agents`; agent-core is the harness we adapt. |
|
|
51
51
|
| LangChain extension | Not used by default. | It patches LangChain callbacks; agent-core already owns the turn and tool lifecycle. |
|
|
@@ -33,7 +33,9 @@ processor and an export processor. The baggage processor copies current Agent
|
|
|
33
33
|
|
|
34
34
|
Per agent, the host passes `createA365TracingConfig(...)` into
|
|
35
35
|
`createAgent({ tracing })`. agent-core still owns the real agent telemetry. It
|
|
36
|
-
emits agent turn spans
|
|
36
|
+
emits agent turn spans and AI SDK v7 emits model/tool spans. The A365 adapter
|
|
37
|
+
defaults agent-core's extra `execute_tool` span layer off so one tool execution
|
|
38
|
+
does not produce duplicate Agent 365 tool records.
|
|
37
39
|
|
|
38
40
|
Per turn, the host or channel adapter calls `runWithA365Context(...)` or
|
|
39
41
|
`runWithA365TurnContext(...)` before running `agent.chat(...)`. The adapter
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cuylabs/agent-a365-observability",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.1",
|
|
4
4
|
"description": "Microsoft Agent 365 observability adapter for @cuylabs/agent-core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"typescript": "^5.7.0",
|
|
27
27
|
"vitest": "^4.0.18",
|
|
28
28
|
"zod": "^3.25.76 || ^4.1.8",
|
|
29
|
-
"@cuylabs/agent-core": "^4.
|
|
29
|
+
"@cuylabs/agent-core": "^4.7.1"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"@cuylabs/agent-core": "^4.0.0",
|