@contractspec/lib.ai-agent 2.0.0 → 2.1.0
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/dist/agent/agent-factory.js +255 -35
- package/dist/agent/contract-spec-agent.d.ts +3 -1
- package/dist/agent/contract-spec-agent.js +255 -35
- package/dist/agent/index.js +255 -35
- package/dist/agent/json-runner.js +255 -35
- package/dist/agent/unified-agent.js +255 -35
- package/dist/node/agent/agent-factory.js +255 -35
- package/dist/node/agent/contract-spec-agent.js +255 -35
- package/dist/node/agent/index.js +255 -35
- package/dist/node/agent/json-runner.js +255 -35
- package/dist/node/agent/unified-agent.js +255 -35
- package/dist/node/telemetry/adapter.js +84 -4
- package/dist/node/telemetry/index.js +165 -15
- package/dist/node/telemetry/posthog.js +81 -11
- package/dist/telemetry/adapter.d.ts +10 -1
- package/dist/telemetry/adapter.js +84 -4
- package/dist/telemetry/adapter.test.d.ts +1 -0
- package/dist/telemetry/index.js +165 -15
- package/dist/telemetry/posthog-types.d.ts +12 -0
- package/dist/telemetry/posthog.js +81 -11
- package/package.json +6 -6
|
@@ -2536,24 +2536,78 @@ function generateSessionId() {
|
|
|
2536
2536
|
|
|
2537
2537
|
// src/telemetry/adapter.ts
|
|
2538
2538
|
function parseAgentId(agentId) {
|
|
2539
|
-
const match = agentId.match(/^(.+)\.v(\
|
|
2539
|
+
const match = agentId.match(/^(.+)\.v(\d+)$/);
|
|
2540
2540
|
if (match) {
|
|
2541
2541
|
return { name: match[1], version: match[2] };
|
|
2542
2542
|
}
|
|
2543
2543
|
return { name: agentId, version: "1.0.0" };
|
|
2544
2544
|
}
|
|
2545
|
-
|
|
2545
|
+
function getRecord(value) {
|
|
2546
|
+
return value && typeof value === "object" ? value : undefined;
|
|
2547
|
+
}
|
|
2548
|
+
function getStepResponse(step) {
|
|
2549
|
+
const response = getRecord(step.response);
|
|
2550
|
+
if (!response)
|
|
2551
|
+
return;
|
|
2552
|
+
return {
|
|
2553
|
+
id: response["id"],
|
|
2554
|
+
modelId: response["modelId"],
|
|
2555
|
+
timestamp: response["timestamp"],
|
|
2556
|
+
headers: response["headers"],
|
|
2557
|
+
body: response["body"],
|
|
2558
|
+
messages: response["messages"]
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
function getRequestBodyValue(request, key) {
|
|
2562
|
+
const body = request?.["body"];
|
|
2563
|
+
if (!body)
|
|
2564
|
+
return;
|
|
2565
|
+
if (typeof body === "string") {
|
|
2566
|
+
try {
|
|
2567
|
+
const parsed = JSON.parse(body);
|
|
2568
|
+
return typeof parsed[key] === "string" ? parsed[key] : undefined;
|
|
2569
|
+
} catch {
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
const record = getRecord(body);
|
|
2574
|
+
return typeof record?.[key] === "string" ? record[key] : undefined;
|
|
2575
|
+
}
|
|
2576
|
+
async function trackAgentStep(collector, agentId, step, durationMs, context) {
|
|
2546
2577
|
const { name, version } = parseAgentId(agentId);
|
|
2578
|
+
const response = getStepResponse(step);
|
|
2579
|
+
const providerMetadata = step.providerMetadata;
|
|
2580
|
+
const warnings = step.warnings;
|
|
2581
|
+
const rawFinishReason = step.rawFinishReason;
|
|
2582
|
+
const request = getRecord(step.request);
|
|
2583
|
+
const traceId = context?.traceId ?? getRequestBodyValue(request, "$ai_trace_id");
|
|
2584
|
+
const sessionId = context?.sessionId ?? getRequestBodyValue(request, "$ai_session_id");
|
|
2585
|
+
const parentSpanId = response?.id;
|
|
2547
2586
|
for (const toolCall of step.toolCalls ?? []) {
|
|
2587
|
+
const toolResult = step.toolResults?.find((r) => r.toolCallId === toolCall.toolCallId);
|
|
2588
|
+
const toolError = getRecord(toolResult?.output)?.["error"];
|
|
2548
2589
|
const toolSample = {
|
|
2549
2590
|
operation: { name: `${name}.${toolCall.toolName}`, version },
|
|
2550
2591
|
durationMs: durationMs ?? 0,
|
|
2551
2592
|
success: step.toolResults?.some((r) => r.toolCallId === toolCall.toolCallId && r.output !== undefined) ?? false,
|
|
2552
2593
|
timestamp: new Date,
|
|
2553
2594
|
metadata: {
|
|
2595
|
+
telemetryEvent: "span",
|
|
2596
|
+
traceId,
|
|
2597
|
+
sessionId,
|
|
2598
|
+
spanId: toolCall.toolCallId,
|
|
2599
|
+
parentSpanId,
|
|
2600
|
+
spanName: `tool.${toolCall.toolName}`,
|
|
2554
2601
|
agentId,
|
|
2602
|
+
actorId: context?.actorId,
|
|
2603
|
+
tenantId: context?.tenantId,
|
|
2604
|
+
stepIndex: context?.stepIndex,
|
|
2555
2605
|
toolName: toolCall.toolName,
|
|
2556
|
-
|
|
2606
|
+
toolCallArgs: toolCall.input,
|
|
2607
|
+
toolResultOutput: toolResult?.output,
|
|
2608
|
+
errorMessage: typeof toolError === "string" ? toolError : typeof toolResult?.output === "string" ? toolResult.output : undefined,
|
|
2609
|
+
finishReason: step.finishReason,
|
|
2610
|
+
rawFinishReason
|
|
2557
2611
|
}
|
|
2558
2612
|
};
|
|
2559
2613
|
await collector.collect(toolSample);
|
|
@@ -2564,10 +2618,36 @@ async function trackAgentStep(collector, agentId, step, durationMs) {
|
|
|
2564
2618
|
success: step.finishReason !== "error",
|
|
2565
2619
|
timestamp: new Date,
|
|
2566
2620
|
metadata: {
|
|
2621
|
+
telemetryEvent: "generation",
|
|
2622
|
+
traceId,
|
|
2623
|
+
sessionId,
|
|
2624
|
+
spanId: response?.id,
|
|
2625
|
+
spanName: `agent.${name}.step`,
|
|
2567
2626
|
agentId,
|
|
2627
|
+
actorId: context?.actorId,
|
|
2628
|
+
tenantId: context?.tenantId,
|
|
2629
|
+
stepIndex: context?.stepIndex,
|
|
2630
|
+
stepStartedAt: context?.stepStartedAt,
|
|
2568
2631
|
finishReason: step.finishReason,
|
|
2632
|
+
rawFinishReason,
|
|
2569
2633
|
tokenUsage: step.usage,
|
|
2570
|
-
|
|
2634
|
+
totalUsage: step.totalUsage,
|
|
2635
|
+
providerMetadata,
|
|
2636
|
+
warnings,
|
|
2637
|
+
stepText: step.text,
|
|
2638
|
+
stepReasoningText: step.reasoningText,
|
|
2639
|
+
responseId: response?.id,
|
|
2640
|
+
responseModelId: response?.modelId,
|
|
2641
|
+
responseTimestamp: response?.timestamp,
|
|
2642
|
+
responseHeaders: response?.headers,
|
|
2643
|
+
responseBody: response?.body,
|
|
2644
|
+
responseMessages: response?.messages,
|
|
2645
|
+
requestBody: request?.["body"],
|
|
2646
|
+
requestHeaders: request?.["headers"],
|
|
2647
|
+
toolCallCount: step.toolCalls?.length ?? 0,
|
|
2648
|
+
toolCalls: step.toolCalls,
|
|
2649
|
+
toolResults: step.toolResults,
|
|
2650
|
+
errorMessage: step.finishReason === "error" ? step.text : undefined
|
|
2571
2651
|
}
|
|
2572
2652
|
};
|
|
2573
2653
|
await collector.collect(stepSample);
|
|
@@ -2627,23 +2707,60 @@ class PostHogTelemetryCollector {
|
|
|
2627
2707
|
}
|
|
2628
2708
|
async collect(sample) {
|
|
2629
2709
|
const client = await this.getClient();
|
|
2630
|
-
const
|
|
2710
|
+
const metadata = asRecord(sample.metadata);
|
|
2711
|
+
const distinctId = this.config.defaults?.posthogDistinctId ?? asString(metadata["actorId"]) ?? "system";
|
|
2712
|
+
const traceId = asString(metadata["traceId"]) ?? this.config.defaults?.posthogTraceId;
|
|
2713
|
+
const sessionId = asString(metadata["sessionId"]);
|
|
2714
|
+
const telemetryEvent = asString(metadata["telemetryEvent"]);
|
|
2715
|
+
const event = telemetryEvent === "span" ? "$ai_span" : "$ai_generation";
|
|
2716
|
+
const tokenUsage = metadata["tokenUsage"];
|
|
2717
|
+
const totalUsage = metadata["totalUsage"];
|
|
2718
|
+
const errorMessage = asString(metadata["errorMessage"]);
|
|
2631
2719
|
client.capture({
|
|
2632
2720
|
distinctId,
|
|
2633
|
-
event
|
|
2721
|
+
event,
|
|
2634
2722
|
properties: {
|
|
2635
|
-
$ai_model: sample.operation.name,
|
|
2636
|
-
$ai_provider: "contractspec",
|
|
2723
|
+
$ai_model: asString(metadata["responseModelId"]) ?? sample.operation.name,
|
|
2724
|
+
$ai_provider: asString(metadata["provider"]) ?? "contractspec",
|
|
2637
2725
|
$ai_latency: sample.durationMs / 1000,
|
|
2638
2726
|
$ai_is_error: !sample.success,
|
|
2639
|
-
$
|
|
2640
|
-
|
|
2727
|
+
$ai_error: !sample.success ? errorMessage : undefined,
|
|
2728
|
+
$ai_trace_id: traceId,
|
|
2729
|
+
$ai_session_id: sessionId,
|
|
2730
|
+
$ai_span_id: asString(metadata["spanId"]),
|
|
2731
|
+
$ai_parent_id: asString(metadata["parentSpanId"]),
|
|
2732
|
+
$ai_span_name: asString(metadata["spanName"]) ?? sample.operation.name,
|
|
2733
|
+
...tokenUsage ? mapTokenUsage(tokenUsage) : {},
|
|
2734
|
+
...totalUsage ? mapTotalUsage(totalUsage) : {},
|
|
2735
|
+
$ai_http_status: asNumber(metadata["httpStatus"]),
|
|
2736
|
+
$ai_request_url: asString(metadata["requestUrl"]),
|
|
2737
|
+
$ai_base_url: asString(metadata["baseUrl"]),
|
|
2641
2738
|
...this.config.defaults?.posthogProperties,
|
|
2642
2739
|
contractspec_operation: sample.operation.name,
|
|
2643
2740
|
contractspec_version: sample.operation.version,
|
|
2644
|
-
contractspec_agent_id:
|
|
2645
|
-
|
|
2646
|
-
|
|
2741
|
+
contractspec_agent_id: asString(metadata["agentId"]),
|
|
2742
|
+
contractspec_tenant_id: asString(metadata["tenantId"]),
|
|
2743
|
+
contractspec_actor_id: asString(metadata["actorId"]),
|
|
2744
|
+
contractspec_step_index: asNumber(metadata["stepIndex"]),
|
|
2745
|
+
contractspec_step_started_at: asDateIso(metadata["stepStartedAt"]),
|
|
2746
|
+
contractspec_finish_reason: asString(metadata["finishReason"]),
|
|
2747
|
+
contractspec_finish_reason_raw: asString(metadata["rawFinishReason"]),
|
|
2748
|
+
contractspec_tool_count: asNumber(metadata["toolCallCount"]),
|
|
2749
|
+
contractspec_tool_name: asString(metadata["toolName"]),
|
|
2750
|
+
contractspec_tool_call_args: metadata["toolCallArgs"],
|
|
2751
|
+
contractspec_tool_result_output: metadata["toolResultOutput"],
|
|
2752
|
+
contractspec_provider_metadata: metadata["providerMetadata"],
|
|
2753
|
+
contractspec_step_warnings: metadata["warnings"],
|
|
2754
|
+
contractspec_response_id: asString(metadata["responseId"]),
|
|
2755
|
+
contractspec_response_model_id: asString(metadata["responseModelId"]),
|
|
2756
|
+
contractspec_response_timestamp: asDateIso(metadata["responseTimestamp"]),
|
|
2757
|
+
contractspec_response_headers: metadata["responseHeaders"],
|
|
2758
|
+
contractspec_response_body: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["responseBody"],
|
|
2759
|
+
contractspec_response_messages: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["responseMessages"],
|
|
2760
|
+
contractspec_request_headers: metadata["requestHeaders"],
|
|
2761
|
+
contractspec_request_body: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["requestBody"],
|
|
2762
|
+
contractspec_step_text: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["stepText"],
|
|
2763
|
+
contractspec_step_reasoning_text: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["stepReasoningText"]
|
|
2647
2764
|
},
|
|
2648
2765
|
groups: this.config.defaults?.posthogGroups
|
|
2649
2766
|
});
|
|
@@ -2704,11 +2821,44 @@ async function resolvePostHogClient(config) {
|
|
|
2704
2821
|
}
|
|
2705
2822
|
}
|
|
2706
2823
|
function mapTokenUsage(usage) {
|
|
2824
|
+
const usageRecord = asRecord(usage);
|
|
2825
|
+
const inputTokenDetails = asRecord(usageRecord["inputTokenDetails"]);
|
|
2826
|
+
const outputTokenDetails = asRecord(usageRecord["outputTokenDetails"]);
|
|
2707
2827
|
return {
|
|
2708
|
-
$ai_input_tokens:
|
|
2709
|
-
$ai_output_tokens:
|
|
2828
|
+
$ai_input_tokens: asNumber(usageRecord["inputTokens"]) ?? asNumber(usageRecord["promptTokens"]),
|
|
2829
|
+
$ai_output_tokens: asNumber(usageRecord["outputTokens"]) ?? asNumber(usageRecord["completionTokens"]),
|
|
2830
|
+
$ai_reasoning_tokens: asNumber(outputTokenDetails["reasoningTokens"]) ?? asNumber(usageRecord["reasoningTokens"]),
|
|
2831
|
+
$ai_cache_read_input_tokens: asNumber(inputTokenDetails["cacheReadTokens"]) ?? asNumber(usageRecord["cachedInputTokens"]),
|
|
2832
|
+
$ai_cache_creation_input_tokens: asNumber(inputTokenDetails["cacheWriteTokens"]),
|
|
2833
|
+
$ai_usage: maybeRecord(usageRecord["raw"]) ?? usageRecord
|
|
2710
2834
|
};
|
|
2711
2835
|
}
|
|
2836
|
+
function mapTotalUsage(usage) {
|
|
2837
|
+
const usageRecord = asRecord(usage);
|
|
2838
|
+
return {
|
|
2839
|
+
contractspec_total_input_tokens: asNumber(usageRecord["inputTokens"]),
|
|
2840
|
+
contractspec_total_output_tokens: asNumber(usageRecord["outputTokens"]),
|
|
2841
|
+
contractspec_total_tokens: asNumber(usageRecord["totalTokens"]),
|
|
2842
|
+
contractspec_total_usage_raw: maybeRecord(usageRecord["raw"]) ?? usageRecord
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
function asRecord(value) {
|
|
2846
|
+
return value && typeof value === "object" ? value : {};
|
|
2847
|
+
}
|
|
2848
|
+
function maybeRecord(value) {
|
|
2849
|
+
return value && typeof value === "object" ? value : undefined;
|
|
2850
|
+
}
|
|
2851
|
+
function asString(value) {
|
|
2852
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
2853
|
+
}
|
|
2854
|
+
function asNumber(value) {
|
|
2855
|
+
return typeof value === "number" ? value : undefined;
|
|
2856
|
+
}
|
|
2857
|
+
function asDateIso(value) {
|
|
2858
|
+
if (value instanceof Date)
|
|
2859
|
+
return value.toISOString();
|
|
2860
|
+
return;
|
|
2861
|
+
}
|
|
2712
2862
|
|
|
2713
2863
|
// src/agent/contract-spec-agent.ts
|
|
2714
2864
|
var exports_contract_spec_agent = {};
|
|
@@ -2719,6 +2869,7 @@ import {
|
|
|
2719
2869
|
Experimental_Agent as ToolLoopAgent,
|
|
2720
2870
|
stepCountIs
|
|
2721
2871
|
} from "ai";
|
|
2872
|
+
import { randomUUID } from "node:crypto";
|
|
2722
2873
|
import * as z3 from "zod";
|
|
2723
2874
|
|
|
2724
2875
|
class ContractSpecAgent {
|
|
@@ -2726,33 +2877,18 @@ class ContractSpecAgent {
|
|
|
2726
2877
|
id;
|
|
2727
2878
|
spec;
|
|
2728
2879
|
tools;
|
|
2729
|
-
inner;
|
|
2730
2880
|
config;
|
|
2731
2881
|
instructions;
|
|
2882
|
+
activeStepContexts = new Map;
|
|
2732
2883
|
constructor(config, instructions, tools) {
|
|
2733
2884
|
this.config = config;
|
|
2734
2885
|
this.spec = config.spec;
|
|
2735
2886
|
this.id = agentKey(config.spec.meta);
|
|
2736
2887
|
this.tools = tools;
|
|
2737
2888
|
this.instructions = instructions;
|
|
2738
|
-
this.inner = new ToolLoopAgent({
|
|
2739
|
-
model: config.model,
|
|
2740
|
-
instructions,
|
|
2741
|
-
tools,
|
|
2742
|
-
stopWhen: stepCountIs(config.spec.maxSteps ?? 10),
|
|
2743
|
-
callOptionsSchema: ContractSpecCallOptionsSchema,
|
|
2744
|
-
onStepFinish: async (step) => {
|
|
2745
|
-
await this.handleStepFinish(step);
|
|
2746
|
-
}
|
|
2747
|
-
});
|
|
2748
2889
|
}
|
|
2749
2890
|
static async create(config) {
|
|
2750
|
-
|
|
2751
|
-
if (config.posthogConfig) {
|
|
2752
|
-
const { createPostHogTracedModel: createPostHogTracedModel2 } = await Promise.resolve().then(() => exports_posthog);
|
|
2753
|
-
const tracedModel = await createPostHogTracedModel2(config.model, config.posthogConfig, config.posthogConfig.tracingOptions);
|
|
2754
|
-
effectiveConfig = { ...config, model: tracedModel };
|
|
2755
|
-
}
|
|
2891
|
+
const effectiveConfig = config;
|
|
2756
2892
|
const instructions = await injectStaticKnowledge(effectiveConfig.spec.instructions, effectiveConfig.spec.knowledge ?? [], effectiveConfig.knowledgeRetriever);
|
|
2757
2893
|
const specTools = specToolsToAISDKTools(effectiveConfig.spec.tools, effectiveConfig.toolHandlers, { agentId: agentKey(effectiveConfig.spec.meta) });
|
|
2758
2894
|
const knowledgeTool = effectiveConfig.knowledgeRetriever ? createKnowledgeQueryTool(effectiveConfig.knowledgeRetriever, effectiveConfig.spec.knowledge ?? []) : null;
|
|
@@ -2765,6 +2901,14 @@ class ContractSpecAgent {
|
|
|
2765
2901
|
}
|
|
2766
2902
|
async generate(params) {
|
|
2767
2903
|
const sessionId = params.options?.sessionId ?? generateSessionId();
|
|
2904
|
+
const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID();
|
|
2905
|
+
this.activeStepContexts.set(sessionId, {
|
|
2906
|
+
traceId,
|
|
2907
|
+
tenantId: params.options?.tenantId,
|
|
2908
|
+
actorId: params.options?.actorId,
|
|
2909
|
+
stepIndex: 0,
|
|
2910
|
+
stepStartedAt: new Date
|
|
2911
|
+
});
|
|
2768
2912
|
if (this.config.sessionStore) {
|
|
2769
2913
|
const existing = await this.config.sessionStore.get(sessionId);
|
|
2770
2914
|
if (!existing) {
|
|
@@ -2785,7 +2929,13 @@ class ContractSpecAgent {
|
|
|
2785
2929
|
${params.systemOverride}
|
|
2786
2930
|
|
|
2787
2931
|
${params.prompt}` : params.prompt;
|
|
2788
|
-
const
|
|
2932
|
+
const model = await this.resolveModelForCall({
|
|
2933
|
+
sessionId,
|
|
2934
|
+
traceId,
|
|
2935
|
+
options: params.options
|
|
2936
|
+
});
|
|
2937
|
+
const inner = this.createInnerAgent(model);
|
|
2938
|
+
const result = await inner.generate({
|
|
2789
2939
|
prompt,
|
|
2790
2940
|
abortSignal: params.signal,
|
|
2791
2941
|
options: {
|
|
@@ -2794,6 +2944,8 @@ ${params.prompt}` : params.prompt;
|
|
|
2794
2944
|
sessionId,
|
|
2795
2945
|
metadata: params.options?.metadata
|
|
2796
2946
|
}
|
|
2947
|
+
}).finally(() => {
|
|
2948
|
+
this.activeStepContexts.delete(sessionId);
|
|
2797
2949
|
});
|
|
2798
2950
|
if (this.config.sessionStore) {
|
|
2799
2951
|
await this.config.sessionStore.update(sessionId, {
|
|
@@ -2821,12 +2973,26 @@ ${params.prompt}` : params.prompt;
|
|
|
2821
2973
|
}
|
|
2822
2974
|
async stream(params) {
|
|
2823
2975
|
const sessionId = params.options?.sessionId ?? generateSessionId();
|
|
2976
|
+
const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID();
|
|
2977
|
+
this.activeStepContexts.set(sessionId, {
|
|
2978
|
+
traceId,
|
|
2979
|
+
tenantId: params.options?.tenantId,
|
|
2980
|
+
actorId: params.options?.actorId,
|
|
2981
|
+
stepIndex: 0,
|
|
2982
|
+
stepStartedAt: new Date
|
|
2983
|
+
});
|
|
2824
2984
|
const prompt = params.systemOverride ? `${this.instructions}
|
|
2825
2985
|
|
|
2826
2986
|
${params.systemOverride}
|
|
2827
2987
|
|
|
2828
2988
|
${params.prompt}` : params.prompt;
|
|
2829
|
-
|
|
2989
|
+
const model = await this.resolveModelForCall({
|
|
2990
|
+
sessionId,
|
|
2991
|
+
traceId,
|
|
2992
|
+
options: params.options
|
|
2993
|
+
});
|
|
2994
|
+
const inner = this.createInnerAgent(model);
|
|
2995
|
+
return inner.stream({
|
|
2830
2996
|
prompt,
|
|
2831
2997
|
abortSignal: params.signal,
|
|
2832
2998
|
options: {
|
|
@@ -2843,9 +3009,63 @@ ${params.prompt}` : params.prompt;
|
|
|
2843
3009
|
await this.config.sessionStore.appendStep(sessionId, step);
|
|
2844
3010
|
}
|
|
2845
3011
|
if (this.config.telemetryCollector) {
|
|
2846
|
-
|
|
3012
|
+
const now = new Date;
|
|
3013
|
+
const context = sessionId ? this.activeStepContexts.get(sessionId) : undefined;
|
|
3014
|
+
const stepStartedAt = context?.stepStartedAt ?? now;
|
|
3015
|
+
const durationMs = Math.max(now.getTime() - stepStartedAt.getTime(), 0);
|
|
3016
|
+
if (context) {
|
|
3017
|
+
context.stepIndex += 1;
|
|
3018
|
+
context.stepStartedAt = now;
|
|
3019
|
+
}
|
|
3020
|
+
await trackAgentStep(this.config.telemetryCollector, this.id, step, durationMs, {
|
|
3021
|
+
sessionId,
|
|
3022
|
+
tenantId: context?.tenantId,
|
|
3023
|
+
actorId: context?.actorId,
|
|
3024
|
+
traceId: context?.traceId,
|
|
3025
|
+
stepIndex: context?.stepIndex,
|
|
3026
|
+
stepStartedAt
|
|
3027
|
+
});
|
|
3028
|
+
if (sessionId && step.finishReason !== "tool-calls") {
|
|
3029
|
+
this.activeStepContexts.delete(sessionId);
|
|
3030
|
+
}
|
|
2847
3031
|
}
|
|
2848
3032
|
}
|
|
3033
|
+
createInnerAgent(model) {
|
|
3034
|
+
return new ToolLoopAgent({
|
|
3035
|
+
model,
|
|
3036
|
+
instructions: this.instructions,
|
|
3037
|
+
tools: this.tools,
|
|
3038
|
+
stopWhen: stepCountIs(this.spec.maxSteps ?? 10),
|
|
3039
|
+
callOptionsSchema: ContractSpecCallOptionsSchema,
|
|
3040
|
+
onStepFinish: async (step) => {
|
|
3041
|
+
await this.handleStepFinish(step);
|
|
3042
|
+
}
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
async resolveModelForCall(params) {
|
|
3046
|
+
const posthogConfig = this.config.posthogConfig;
|
|
3047
|
+
if (!posthogConfig) {
|
|
3048
|
+
return this.config.model;
|
|
3049
|
+
}
|
|
3050
|
+
const mergedProperties = {
|
|
3051
|
+
...posthogConfig.defaults?.posthogProperties,
|
|
3052
|
+
...posthogConfig.tracingOptions?.posthogProperties,
|
|
3053
|
+
$ai_session_id: params.sessionId,
|
|
3054
|
+
contractspec_session_id: params.sessionId,
|
|
3055
|
+
contractspec_trace_id: params.traceId,
|
|
3056
|
+
contractspec_agent_id: this.id,
|
|
3057
|
+
contractspec_tenant_id: params.options?.tenantId,
|
|
3058
|
+
contractspec_actor_id: params.options?.actorId
|
|
3059
|
+
};
|
|
3060
|
+
const tracingOptions = {
|
|
3061
|
+
...posthogConfig.tracingOptions,
|
|
3062
|
+
posthogDistinctId: posthogConfig.tracingOptions?.posthogDistinctId ?? params.options?.actorId,
|
|
3063
|
+
posthogTraceId: params.traceId,
|
|
3064
|
+
posthogProperties: mergedProperties
|
|
3065
|
+
};
|
|
3066
|
+
const { createPostHogTracedModel: createPostHogTracedModel2 } = await Promise.resolve().then(() => exports_posthog);
|
|
3067
|
+
return createPostHogTracedModel2(this.config.model, posthogConfig, tracingOptions);
|
|
3068
|
+
}
|
|
2849
3069
|
}
|
|
2850
3070
|
var ContractSpecCallOptionsSchema;
|
|
2851
3071
|
var init_contract_spec_agent = __esm(() => {
|
|
@@ -14,24 +14,78 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
14
14
|
|
|
15
15
|
// src/telemetry/adapter.ts
|
|
16
16
|
function parseAgentId(agentId) {
|
|
17
|
-
const match = agentId.match(/^(.+)\.v(\
|
|
17
|
+
const match = agentId.match(/^(.+)\.v(\d+)$/);
|
|
18
18
|
if (match) {
|
|
19
19
|
return { name: match[1], version: match[2] };
|
|
20
20
|
}
|
|
21
21
|
return { name: agentId, version: "1.0.0" };
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
function getRecord(value) {
|
|
24
|
+
return value && typeof value === "object" ? value : undefined;
|
|
25
|
+
}
|
|
26
|
+
function getStepResponse(step) {
|
|
27
|
+
const response = getRecord(step.response);
|
|
28
|
+
if (!response)
|
|
29
|
+
return;
|
|
30
|
+
return {
|
|
31
|
+
id: response["id"],
|
|
32
|
+
modelId: response["modelId"],
|
|
33
|
+
timestamp: response["timestamp"],
|
|
34
|
+
headers: response["headers"],
|
|
35
|
+
body: response["body"],
|
|
36
|
+
messages: response["messages"]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function getRequestBodyValue(request, key) {
|
|
40
|
+
const body = request?.["body"];
|
|
41
|
+
if (!body)
|
|
42
|
+
return;
|
|
43
|
+
if (typeof body === "string") {
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(body);
|
|
46
|
+
return typeof parsed[key] === "string" ? parsed[key] : undefined;
|
|
47
|
+
} catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const record = getRecord(body);
|
|
52
|
+
return typeof record?.[key] === "string" ? record[key] : undefined;
|
|
53
|
+
}
|
|
54
|
+
async function trackAgentStep(collector, agentId, step, durationMs, context) {
|
|
24
55
|
const { name, version } = parseAgentId(agentId);
|
|
56
|
+
const response = getStepResponse(step);
|
|
57
|
+
const providerMetadata = step.providerMetadata;
|
|
58
|
+
const warnings = step.warnings;
|
|
59
|
+
const rawFinishReason = step.rawFinishReason;
|
|
60
|
+
const request = getRecord(step.request);
|
|
61
|
+
const traceId = context?.traceId ?? getRequestBodyValue(request, "$ai_trace_id");
|
|
62
|
+
const sessionId = context?.sessionId ?? getRequestBodyValue(request, "$ai_session_id");
|
|
63
|
+
const parentSpanId = response?.id;
|
|
25
64
|
for (const toolCall of step.toolCalls ?? []) {
|
|
65
|
+
const toolResult = step.toolResults?.find((r) => r.toolCallId === toolCall.toolCallId);
|
|
66
|
+
const toolError = getRecord(toolResult?.output)?.["error"];
|
|
26
67
|
const toolSample = {
|
|
27
68
|
operation: { name: `${name}.${toolCall.toolName}`, version },
|
|
28
69
|
durationMs: durationMs ?? 0,
|
|
29
70
|
success: step.toolResults?.some((r) => r.toolCallId === toolCall.toolCallId && r.output !== undefined) ?? false,
|
|
30
71
|
timestamp: new Date,
|
|
31
72
|
metadata: {
|
|
73
|
+
telemetryEvent: "span",
|
|
74
|
+
traceId,
|
|
75
|
+
sessionId,
|
|
76
|
+
spanId: toolCall.toolCallId,
|
|
77
|
+
parentSpanId,
|
|
78
|
+
spanName: `tool.${toolCall.toolName}`,
|
|
32
79
|
agentId,
|
|
80
|
+
actorId: context?.actorId,
|
|
81
|
+
tenantId: context?.tenantId,
|
|
82
|
+
stepIndex: context?.stepIndex,
|
|
33
83
|
toolName: toolCall.toolName,
|
|
34
|
-
|
|
84
|
+
toolCallArgs: toolCall.input,
|
|
85
|
+
toolResultOutput: toolResult?.output,
|
|
86
|
+
errorMessage: typeof toolError === "string" ? toolError : typeof toolResult?.output === "string" ? toolResult.output : undefined,
|
|
87
|
+
finishReason: step.finishReason,
|
|
88
|
+
rawFinishReason
|
|
35
89
|
}
|
|
36
90
|
};
|
|
37
91
|
await collector.collect(toolSample);
|
|
@@ -42,10 +96,36 @@ async function trackAgentStep(collector, agentId, step, durationMs) {
|
|
|
42
96
|
success: step.finishReason !== "error",
|
|
43
97
|
timestamp: new Date,
|
|
44
98
|
metadata: {
|
|
99
|
+
telemetryEvent: "generation",
|
|
100
|
+
traceId,
|
|
101
|
+
sessionId,
|
|
102
|
+
spanId: response?.id,
|
|
103
|
+
spanName: `agent.${name}.step`,
|
|
45
104
|
agentId,
|
|
105
|
+
actorId: context?.actorId,
|
|
106
|
+
tenantId: context?.tenantId,
|
|
107
|
+
stepIndex: context?.stepIndex,
|
|
108
|
+
stepStartedAt: context?.stepStartedAt,
|
|
46
109
|
finishReason: step.finishReason,
|
|
110
|
+
rawFinishReason,
|
|
47
111
|
tokenUsage: step.usage,
|
|
48
|
-
|
|
112
|
+
totalUsage: step.totalUsage,
|
|
113
|
+
providerMetadata,
|
|
114
|
+
warnings,
|
|
115
|
+
stepText: step.text,
|
|
116
|
+
stepReasoningText: step.reasoningText,
|
|
117
|
+
responseId: response?.id,
|
|
118
|
+
responseModelId: response?.modelId,
|
|
119
|
+
responseTimestamp: response?.timestamp,
|
|
120
|
+
responseHeaders: response?.headers,
|
|
121
|
+
responseBody: response?.body,
|
|
122
|
+
responseMessages: response?.messages,
|
|
123
|
+
requestBody: request?.["body"],
|
|
124
|
+
requestHeaders: request?.["headers"],
|
|
125
|
+
toolCallCount: step.toolCalls?.length ?? 0,
|
|
126
|
+
toolCalls: step.toolCalls,
|
|
127
|
+
toolResults: step.toolResults,
|
|
128
|
+
errorMessage: step.finishReason === "error" ? step.text : undefined
|
|
49
129
|
}
|
|
50
130
|
};
|
|
51
131
|
await collector.collect(stepSample);
|