autotel-genai 0.3.0 → 0.3.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/dist/agent/index.js +1 -2
- package/dist/{agent-yHB-GF6g.js → agent-DthMDQbW.js} +3 -96
- package/dist/agent-DthMDQbW.js.map +1 -0
- package/dist/context-B2wjX3O1.js +73 -0
- package/dist/context-B2wjX3O1.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/observer/index.js +1 -1
- package/dist/{observer-50RGrqzo.js → observer-2SKgcQI_.js} +68 -2
- package/dist/observer-2SKgcQI_.js.map +1 -0
- package/package.json +3 -3
- package/dist/agent-security-ChL0rIh-.js +0 -181
- package/dist/agent-security-ChL0rIh-.js.map +0 -1
- package/dist/agent-yHB-GF6g.js.map +0 -1
- package/dist/observer-50RGrqzo.js.map +0 -1
package/dist/agent/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { C as canonicalizeForHash, S as createAgentAuditMetadata, T as AGENT_AUDIT_SCHEMA_VERSION, _ as recordPolicyDecision, a as withScopedTool, b as flattenAgentAttributes, c as resolvePrivacyProfile, d as withAgentSession, f as delegateToAgent, g as recordDecisionBasis, h as defineAgentToolCall, i as runAgentPlanClassifier, l as sanitizeAuditPayload, m as defineAgentAction, n as heuristicPlanRiskClassifier, o as createSignedEventEnvelope, p as recordAgentHandoff, r as recordPlanRiskAssessment, s as verifyEventEnvelopeHash, t as AGENT_PLAN_RISK_ATTR, u as createAgentIdentityRegistry, v as withAgentAction, w as hashPayload, x as setAgentAttributes, y as withAgentToolCall } from "../agent-yHB-GF6g.js";
|
|
1
|
+
import { A as withAgentAction, C as withAgentSession, D as defineAgentToolCall, E as defineAgentAction, F as canonicalizeForHash, I as hashPayload, L as AGENT_AUDIT_SCHEMA_VERSION, M as flattenAgentAttributes, N as setAgentAttributes, O as recordDecisionBasis, P as createAgentAuditMetadata, S as createAgentIdentityRegistry, T as recordAgentHandoff, _ as withScopedTool, a as heuristicPlanRiskClassifier, b as resolvePrivacyProfile, c as recordControllerId, d as recordMemoryAccess, f as recordPlanRiskAssessment, g as tryRecordHumanApproval, h as runAgentPlanClassifier, i as deriveActionRiskClass, j as withAgentToolCall, k as recordPolicyDecision, l as recordHumanApproval, m as recordRenderOutput, n as AGENT_SECURITY_ATTR, o as recordActionRiskClass, p as recordPlanStep, r as agentContextFromSpan, s as recordActiveScopes, t as AGENT_PLAN_RISK_ATTR, u as recordInputProvenance, v as createSignedEventEnvelope, w as delegateToAgent, x as sanitizeAuditPayload, y as verifyEventEnvelopeHash } from "../agent-DthMDQbW.js";
|
|
3
2
|
|
|
4
3
|
export { AGENT_AUDIT_SCHEMA_VERSION, AGENT_PLAN_RISK_ATTR, AGENT_SECURITY_ATTR, agentContextFromSpan, canonicalizeForHash, createAgentAuditMetadata, createAgentIdentityRegistry, createSignedEventEnvelope, defineAgentAction, defineAgentToolCall, delegateToAgent, deriveActionRiskClass, flattenAgentAttributes, hashPayload, heuristicPlanRiskClassifier, recordActionRiskClass, recordActiveScopes, recordAgentHandoff, recordControllerId, recordDecisionBasis, recordHumanApproval, recordInputProvenance, recordMemoryAccess, recordPlanRiskAssessment, recordPlanStep, recordPolicyDecision, recordRenderOutput, resolvePrivacyProfile, runAgentPlanClassifier, sanitizeAuditPayload, setAgentAttributes, tryRecordHumanApproval, verifyEventEnvelopeHash, withAgentAction, withAgentSession, withAgentToolCall, withScopedTool };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { estimateLLMCost } from "./cost.js";
|
|
2
2
|
import { i as genAiResponseAttributes, r as genAiRequestAttributes, s as genAiUsageAttributes } from "./attributes-DU-PmLqZ.js";
|
|
3
|
-
import {
|
|
3
|
+
import { a as toAttributeValue, i as resolveContextSafe, o as warnMissingContextOnce, r as resolveContext, t as MISSING_CONTEXT_MESSAGE } from "./context-B2wjX3O1.js";
|
|
4
4
|
import { createNoopRequestLogger, createStructuredError, getRequestLoggerSafe } from "autotel";
|
|
5
5
|
import { forceKeepAuditEvent, securityEvent, withAudit } from "autotel-audit";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
@@ -903,98 +903,5 @@ async function withScopedTool(definition, input, fn, options = {}) {
|
|
|
903
903
|
}
|
|
904
904
|
|
|
905
905
|
//#endregion
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
const AGENT_PLAN_RISK_ATTR = {
|
|
909
|
-
verdict: "agent.plan.risk.verdict",
|
|
910
|
-
score: "agent.plan.risk.score",
|
|
911
|
-
categories: "agent.plan.risk.categories",
|
|
912
|
-
toolSequence: "agent.plan.risk.tool_sequence"
|
|
913
|
-
};
|
|
914
|
-
function setPlanRiskAttrs(ctx, attrs) {
|
|
915
|
-
const traceCtx = resolveContext(ctx);
|
|
916
|
-
const mapped = {};
|
|
917
|
-
for (const [key, value] of Object.entries(attrs)) {
|
|
918
|
-
const attr = toAttributeValue(value);
|
|
919
|
-
if (attr !== void 0) mapped[key] = attr;
|
|
920
|
-
}
|
|
921
|
-
if (Object.keys(mapped).length > 0) traceCtx.setAttributes(mapped);
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Stamp plan-risk assessment attrs on the active span.
|
|
925
|
-
*/
|
|
926
|
-
function recordPlanRiskAssessment(options) {
|
|
927
|
-
const { assessment, toolSequence } = options;
|
|
928
|
-
setPlanRiskAttrs(options.ctx, {
|
|
929
|
-
[AGENT_PLAN_RISK_ATTR.verdict]: assessment.verdict,
|
|
930
|
-
...assessment.score !== void 0 && { [AGENT_PLAN_RISK_ATTR.score]: assessment.score },
|
|
931
|
-
...assessment.categories?.length && { [AGENT_PLAN_RISK_ATTR.categories]: assessment.categories },
|
|
932
|
-
...toolSequence?.length && { [AGENT_PLAN_RISK_ATTR.toolSequence]: toolSequence },
|
|
933
|
-
...assessment.reason !== void 0 && { "decision.summary": assessment.reason }
|
|
934
|
-
});
|
|
935
|
-
if (options.emitSecurityEvent && assessment.verdict !== "low") securityEvent({
|
|
936
|
-
name: "llm.plan.risk.elevated",
|
|
937
|
-
category: "llm",
|
|
938
|
-
outcome: assessment.verdict === "critical" ? "blocked" : "denied",
|
|
939
|
-
severity: assessment.verdict === "critical" ? "critical" : assessment.verdict === "high" ? "error" : "warning",
|
|
940
|
-
reason: assessment.reason ?? assessment.verdict,
|
|
941
|
-
...assessment.score !== void 0 && { score: assessment.score },
|
|
942
|
-
...assessment.categories?.length && { categories: assessment.categories.join(",") }
|
|
943
|
-
}, { ctx: options.ctx });
|
|
944
|
-
}
|
|
945
|
-
/**
|
|
946
|
-
* Run a pluggable plan-risk classifier and record its verdict on the span.
|
|
947
|
-
* Classifier failures degrade quietly (no assessment recorded).
|
|
948
|
-
*/
|
|
949
|
-
async function runAgentPlanClassifier(classifier, input, options = {}) {
|
|
950
|
-
let assessment;
|
|
951
|
-
try {
|
|
952
|
-
assessment = await classifier(input);
|
|
953
|
-
} catch {
|
|
954
|
-
return;
|
|
955
|
-
}
|
|
956
|
-
if (!assessment) return void 0;
|
|
957
|
-
recordPlanRiskAssessment({
|
|
958
|
-
...options,
|
|
959
|
-
assessment,
|
|
960
|
-
toolSequence: input.toolSequence
|
|
961
|
-
});
|
|
962
|
-
return assessment;
|
|
963
|
-
}
|
|
964
|
-
const DESTRUCTIVE_TOOL = /\b(delete|remove|send|post|transfer|pay|upload|execute)\b/i;
|
|
965
|
-
const UNTRUSTED_READ = /\b(read|fetch|get|search|load|parse|inbox|email|web|scrape)\b/i;
|
|
966
|
-
/**
|
|
967
|
-
* Dependency-free first-pass plan-risk heuristic. Opt-in — pass as
|
|
968
|
-
* `AgentPlanClassifier` or wrap your own Model Armor / Llama Guard adapter.
|
|
969
|
-
*/
|
|
970
|
-
function heuristicPlanRiskClassifier() {
|
|
971
|
-
return ({ toolSequence }) => {
|
|
972
|
-
if (toolSequence.length === 0) return {
|
|
973
|
-
verdict: "low",
|
|
974
|
-
score: 0
|
|
975
|
-
};
|
|
976
|
-
const normalized = toolSequence.map((name) => name.replaceAll("_", " "));
|
|
977
|
-
const hasDestructive = normalized.some((name) => DESTRUCTIVE_TOOL.test(name));
|
|
978
|
-
const hasUntrustedRead = normalized.some((name) => UNTRUSTED_READ.test(name));
|
|
979
|
-
if (hasDestructive && hasUntrustedRead) return {
|
|
980
|
-
verdict: "high",
|
|
981
|
-
score: .85,
|
|
982
|
-
categories: ["untrusted_to_destructive_chain"],
|
|
983
|
-
reason: "mixed_untrusted_and_destructive_tools"
|
|
984
|
-
};
|
|
985
|
-
if (toolSequence.length >= 8) return {
|
|
986
|
-
verdict: "medium",
|
|
987
|
-
score: .55,
|
|
988
|
-
categories: ["long_tool_chain"],
|
|
989
|
-
reason: "long_tool_sequence"
|
|
990
|
-
};
|
|
991
|
-
return {
|
|
992
|
-
verdict: "low",
|
|
993
|
-
score: .1
|
|
994
|
-
};
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
//#endregion
|
|
999
|
-
export { canonicalizeForHash as C, createAgentAuditMetadata as S, AGENT_AUDIT_SCHEMA_VERSION as T, recordPolicyDecision as _, withScopedTool as a, flattenAgentAttributes as b, resolvePrivacyProfile as c, withAgentSession as d, delegateToAgent as f, recordDecisionBasis as g, defineAgentToolCall as h, runAgentPlanClassifier as i, sanitizeAuditPayload as l, defineAgentAction as m, heuristicPlanRiskClassifier as n, createSignedEventEnvelope as o, recordAgentHandoff as p, recordPlanRiskAssessment as r, verifyEventEnvelopeHash as s, AGENT_PLAN_RISK_ATTR as t, createAgentIdentityRegistry as u, withAgentAction as v, hashPayload as w, setAgentAttributes as x, withAgentToolCall as y };
|
|
1000
|
-
//# sourceMappingURL=agent-yHB-GF6g.js.map
|
|
906
|
+
export { withAgentAction as A, withAgentSession as C, defineAgentToolCall as D, defineAgentAction as E, canonicalizeForHash as F, hashPayload as I, AGENT_AUDIT_SCHEMA_VERSION as L, flattenAgentAttributes as M, setAgentAttributes as N, recordDecisionBasis as O, createAgentAuditMetadata as P, createAgentIdentityRegistry as S, recordAgentHandoff as T, withScopedTool as _, heuristicPlanRiskClassifier as a, resolvePrivacyProfile as b, recordControllerId as c, recordMemoryAccess as d, recordPlanRiskAssessment as f, tryRecordHumanApproval as g, runAgentPlanClassifier as h, deriveActionRiskClass as i, withAgentToolCall as j, recordPolicyDecision as k, recordHumanApproval as l, recordRenderOutput as m, AGENT_SECURITY_ATTR as n, recordActionRiskClass as o, recordPlanStep as p, agentContextFromSpan as r, recordActiveScopes as s, AGENT_PLAN_RISK_ATTR as t, recordInputProvenance as u, createSignedEventEnvelope as v, delegateToAgent as w, sanitizeAuditPayload as x, verifyEventEnvelopeHash as y };
|
|
907
|
+
//# sourceMappingURL=agent-DthMDQbW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-DthMDQbW.js","names":["toIsoString","toIsoString","normalizeScopes"],"sources":["../src/agent/constants.ts","../src/agent/hash.ts","../src/agent/metadata.ts","../src/agent/attributes.ts","../src/agent/runtime.ts","../src/agent/delegation.ts","../src/agent/session.ts","../src/agent/identity-registry.ts","../src/agent/privacy.ts","../src/agent/non-repudiation.ts","../src/agent/scoped-tool.ts"],"sourcesContent":["export const AGENT_AUDIT_SCHEMA_VERSION = '1.1.0';\n","import { createHash } from 'node:crypto';\n\nexport interface HashPayloadOptions {\n algorithm?: 'sha256';\n}\n\nfunction canonicalize(value: unknown): unknown {\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'bigint') {\n return value.toString(10);\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => canonicalize(entry));\n }\n\n if (value && typeof value === 'object') {\n // `toSorted()` would need ES2023 lib types; keep runtime output ES2022-friendly.\n const entries = Object.entries(value as Record<string, unknown>);\n entries.sort(([left], [right]) => left.localeCompare(right));\n return Object.fromEntries(\n entries.map(([key, entryValue]) => [key, canonicalize(entryValue)]),\n );\n }\n\n return value;\n}\n\nexport function canonicalizeForHash(value: unknown): string {\n return JSON.stringify(canonicalize(value));\n}\n\nexport function hashPayload(\n value: unknown,\n options: HashPayloadOptions = {},\n): string {\n const algorithm = options.algorithm ?? 'sha256';\n const canonical = canonicalizeForHash(value);\n const digest = createHash(algorithm).update(canonical).digest('hex');\n return `${algorithm}:${digest}`;\n}\n","import { AGENT_AUDIT_SCHEMA_VERSION } from './constants.js';\nimport { hashPayload } from './hash.js';\nimport type {\n AgentActionMetadata,\n AgentDecisionMetadata,\n AgentEventKind,\n GovernanceMetadata,\n ToolCallMetadata,\n} from './types.js';\n\ninterface AuditMetadataLike {\n action: string;\n resource?: string;\n actorId?: string;\n category?: string;\n outcome?: string;\n [key: string]: unknown;\n}\n\nexport function defaultEventKind(\n metadata: AgentActionMetadata,\n): AgentEventKind {\n if (metadata.eventKind) return metadata.eventKind;\n if (metadata.tool) return 'tool_call';\n if (metadata.policy) return 'policy_decision';\n return 'action';\n}\n\nexport function normalizeTool(\n tool?: ToolCallMetadata,\n): ToolCallMetadata | undefined {\n if (!tool) return undefined;\n\n return {\n name: tool.name,\n ...(tool.callId !== undefined && { callId: tool.callId }),\n inputHash:\n tool.input === undefined\n ? tool.inputHash\n : (tool.inputHash ?? hashPayload(tool.input)),\n outputHash:\n tool.output === undefined\n ? tool.outputHash\n : (tool.outputHash ?? hashPayload(tool.output)),\n ...(tool.status !== undefined && { status: tool.status }),\n ...(tool.executionMs !== undefined && { executionMs: tool.executionMs }),\n };\n}\n\nexport function sanitizeTool(\n tool?: ToolCallMetadata,\n): ToolCallMetadata | undefined {\n if (!tool) return undefined;\n\n return {\n name: tool.name,\n ...(tool.callId !== undefined && { callId: tool.callId }),\n ...(tool.inputHash !== undefined && { inputHash: tool.inputHash }),\n ...(tool.outputHash !== undefined && { outputHash: tool.outputHash }),\n ...(tool.status !== undefined && { status: tool.status }),\n ...(tool.executionMs !== undefined && { executionMs: tool.executionMs }),\n };\n}\n\nexport function sanitizeGovernance(\n governance?: GovernanceMetadata,\n): GovernanceMetadata | undefined {\n if (!governance) return undefined;\n return {\n ...(governance.reviewRequired !== undefined && {\n reviewRequired: governance.reviewRequired,\n }),\n ...(governance.reviewerId !== undefined && {\n reviewerId: governance.reviewerId,\n }),\n ...(governance.controlId !== undefined && {\n controlId: governance.controlId,\n }),\n ...(governance.documentationUrl !== undefined && {\n documentationUrl: governance.documentationUrl,\n }),\n ...(governance.lifecycleStage !== undefined && {\n lifecycleStage: governance.lifecycleStage,\n }),\n ...(governance.framework !== undefined && {\n framework: governance.framework,\n }),\n };\n}\n\nfunction normalizeDecision(\n decision?: AgentDecisionMetadata,\n reasoningSummary?: string,\n): AgentDecisionMetadata | undefined {\n if (decision) {\n return {\n ...decision,\n summary: decision.summary ?? reasoningSummary ?? '',\n };\n }\n\n if (reasoningSummary === undefined) return undefined;\n\n return {\n summary: reasoningSummary,\n };\n}\n\nexport function createAgentAuditMetadata(\n metadata: AgentActionMetadata,\n): AgentActionMetadata {\n const eventKind = defaultEventKind(metadata);\n\n if (eventKind === 'tool_call' && !metadata.tool) {\n throw new Error(\n '[autotel-genai] eventKind \"tool_call\" requires metadata.tool.',\n );\n }\n\n if (eventKind === 'policy_decision' && !metadata.policy) {\n throw new Error(\n '[autotel-genai] eventKind \"policy_decision\" requires metadata.policy.',\n );\n }\n\n if (eventKind === 'handoff' && !metadata.delegation) {\n throw new Error(\n '[autotel-genai] eventKind \"handoff\" requires metadata.delegation.',\n );\n }\n\n const delegation =\n metadata.delegation &&\n (\n metadata.delegation.authorityLineageHash === undefined ||\n metadata.delegation.depth === undefined\n )\n ? {\n ...metadata.delegation,\n ...(metadata.delegation.authorityLineage && {\n authorityLineageHash:\n metadata.delegation.authorityLineageHash ??\n hashPayload(metadata.delegation.authorityLineage),\n depth:\n metadata.delegation.depth ??\n Math.max(metadata.delegation.authorityLineage.length - 1, 0),\n }),\n }\n : metadata.delegation;\n\n return {\n ...metadata,\n schemaVersion: metadata.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n eventKind,\n decision: normalizeDecision(metadata.decision, metadata.reasoningSummary),\n ...(delegation !== undefined && { delegation }),\n };\n}\n\nexport function normalizeMetadata(\n metadata: AgentActionMetadata,\n): AgentActionMetadata {\n const normalized = createAgentAuditMetadata(metadata);\n return {\n ...normalized,\n tool: normalizeTool(normalized.tool),\n };\n}\n\nexport function buildAuditMetadata(\n metadata: AgentActionMetadata,\n): AuditMetadataLike {\n return {\n action: metadata.action,\n ...(metadata.resource !== undefined && { resource: metadata.resource }),\n actorId:\n metadata.actorId ??\n metadata.delegation?.parentIdentity ??\n metadata.agent.id,\n category: metadata.category ?? 'agent',\n ...(metadata.outcome !== undefined && { outcome: metadata.outcome }),\n agentId: metadata.agent.id,\n agentEventKind: metadata.eventKind,\n agentAuditVersion: metadata.schemaVersion,\n ...(metadata.agent.version !== undefined && {\n agentVersion: metadata.agent.version,\n }),\n ...(metadata.tool?.name !== undefined && { toolName: metadata.tool.name }),\n ...(metadata.policy?.decision !== undefined && {\n policyDecision: metadata.policy.decision,\n }),\n ...(metadata.session?.status !== undefined && {\n sessionStatus: metadata.session.status,\n }),\n };\n}\n\nexport function buildLoggerContext(\n metadata: AgentActionMetadata,\n): Record<string, unknown> {\n const tool = sanitizeTool(metadata.tool);\n const governance = sanitizeGovernance(metadata.governance);\n\n const context: Record<string, unknown> = {\n agent: {\n ...metadata.agent,\n ...(metadata.resource !== undefined && { resource: metadata.resource }),\n ...(metadata.outcome !== undefined && { outcome: metadata.outcome }),\n ...(metadata.reasoningSummary !== undefined && {\n reasoningSummary: metadata.reasoningSummary,\n }),\n schemaVersion: metadata.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n eventKind: metadata.eventKind ?? defaultEventKind(metadata),\n },\n ...(metadata.delegation !== undefined && {\n delegation: metadata.delegation,\n }),\n ...(tool !== undefined && { tool }),\n ...(metadata.policy !== undefined && { policy: metadata.policy }),\n ...(governance !== undefined && { governance }),\n ...(metadata.session !== undefined && { session: metadata.session }),\n ...(metadata.decision !== undefined && { decision: metadata.decision }),\n };\n\n // Hand the request logger an independent copy. `logger.set()` deep-merges and\n // intentionally *concatenates* array fields across calls (autotel wide-event\n // semantics). Agent lifecycles call `.set()` more than once per action with\n // the same `delegation`/`decision` objects, so sharing references would let\n // the merge mutate arrays (e.g. `authority_lineage`) in place — which would\n // then leak onto the span via `setAgentAttributes`. Cloning keeps the\n // span-bound metadata pristine.\n return structuredClone(context);\n}\n\n/**\n * Context for the *completion* `logger.set()` of a specialized lifecycle\n * wrapper. Carries only the domain state that finished mutating — tool or\n * session status. Outcome is owned by `withAgentAction`, which wraps every\n * variant and stamps it on both span and log. This deliberately omits the\n * request-level `delegation`/`decision` blocks: those were set once at the\n * start, and re-sending them would concatenate their array fields into the\n * wide event (see `buildLoggerContext`).\n */\nexport function buildLifecycleUpdateContext(\n metadata: AgentActionMetadata,\n): Record<string, unknown> {\n const tool = sanitizeTool(metadata.tool);\n return {\n ...(tool !== undefined && { tool }),\n ...(metadata.session !== undefined && {\n session: structuredClone(metadata.session),\n }),\n };\n}\n","import { AGENT_AUDIT_SCHEMA_VERSION } from './constants.js';\nimport { resolveContext, toAttributeValue, type AgentContext } from './context.js';\nimport { defaultEventKind, normalizeMetadata } from './metadata.js';\nimport type {\n AgentActionMetadata,\n AgentDecisionMetadata,\n AgentIdentity,\n AgentSessionMetadata,\n DelegationContext,\n GovernanceMetadata,\n PolicyMetadata,\n ToolCallMetadata,\n} from './types.js';\n\ntype AttributeValue =\n | string\n | number\n | boolean\n | string[]\n | number[]\n | boolean[];\n\ntype AttributeMap = Record<string, AttributeValue>;\n\nfunction setIfPresent(target: AttributeMap, key: string, value: unknown): void {\n const attr = toAttributeValue(value);\n if (attr !== undefined) {\n target[key] = attr;\n }\n}\n\nfunction appendIdentityAttributes(attrs: AttributeMap, agent: AgentIdentity): void {\n setIfPresent(attrs, 'agent.id', agent.id);\n setIfPresent(attrs, 'agent.version', agent.version);\n setIfPresent(attrs, 'agent.framework', agent.framework);\n setIfPresent(attrs, 'agent.model', agent.model);\n setIfPresent(attrs, 'agent.role', agent.role);\n setIfPresent(attrs, 'agent.session.id', agent.sessionId);\n setIfPresent(attrs, 'agent.conversation.id', agent.conversationId);\n}\n\nfunction appendDelegationAttributes(\n attrs: AttributeMap,\n delegation?: DelegationContext,\n): void {\n if (!delegation) return;\n setIfPresent(attrs, 'delegation.parent_identity', delegation.parentIdentity);\n setIfPresent(attrs, 'delegation.scope', delegation.scope);\n setIfPresent(attrs, 'delegation.token_id', delegation.tokenId);\n setIfPresent(attrs, 'delegation.id', delegation.delegationId);\n setIfPresent(attrs, 'delegation.authority_lineage', delegation.authorityLineage);\n setIfPresent(\n attrs,\n 'delegation.authority_lineage_hash',\n delegation.authorityLineageHash,\n );\n setIfPresent(attrs, 'delegation.depth', delegation.depth);\n setIfPresent(attrs, 'delegation.issued_at', delegation.issuedAt);\n setIfPresent(attrs, 'delegation.expires_at', delegation.expiresAt);\n}\n\nfunction appendToolAttributes(attrs: AttributeMap, tool?: ToolCallMetadata): void {\n if (!tool) return;\n setIfPresent(attrs, 'tool.name', tool.name);\n setIfPresent(attrs, 'tool.call.id', tool.callId);\n setIfPresent(attrs, 'tool.input_hash', tool.inputHash);\n setIfPresent(attrs, 'tool.output_hash', tool.outputHash);\n setIfPresent(attrs, 'tool.status', tool.status);\n setIfPresent(attrs, 'tool.execution_ms', tool.executionMs);\n}\n\nfunction appendPolicyAttributes(attrs: AttributeMap, policy?: PolicyMetadata): void {\n if (!policy) return;\n setIfPresent(attrs, 'policy.decision', policy.decision);\n setIfPresent(attrs, 'policy.id', policy.policyId);\n setIfPresent(attrs, 'policy.risk_score', policy.riskScore);\n setIfPresent(attrs, 'policy.reason', policy.reason);\n}\n\nfunction appendGovernanceAttributes(\n attrs: AttributeMap,\n governance?: GovernanceMetadata,\n): void {\n if (!governance) return;\n setIfPresent(attrs, 'governance.review_required', governance.reviewRequired);\n setIfPresent(attrs, 'governance.reviewer_id', governance.reviewerId);\n setIfPresent(attrs, 'governance.control_id', governance.controlId);\n setIfPresent(attrs, 'governance.documentation_url', governance.documentationUrl);\n setIfPresent(attrs, 'governance.lifecycle_stage', governance.lifecycleStage);\n setIfPresent(attrs, 'governance.framework', governance.framework);\n}\n\nfunction appendSessionAttributes(\n attrs: AttributeMap,\n session?: AgentSessionMetadata,\n): void {\n if (!session) return;\n setIfPresent(attrs, 'agent.session.status', session.status);\n setIfPresent(attrs, 'agent.session.started_at', session.startedAt);\n setIfPresent(attrs, 'agent.session.ended_at', session.endedAt);\n setIfPresent(attrs, 'agent.session.delegated_by', session.delegatedBy);\n}\n\nfunction appendDecisionAttributes(\n attrs: AttributeMap,\n decision?: AgentDecisionMetadata,\n): void {\n if (!decision) return;\n setIfPresent(attrs, 'decision.summary', decision.summary);\n setIfPresent(attrs, 'decision.input_hash', decision.inputHash);\n setIfPresent(attrs, 'decision.policy_ids', decision.policyIds);\n setIfPresent(attrs, 'decision.justification_codes', decision.justificationCodes);\n setIfPresent(attrs, 'decision.evidence_ids', decision.evidenceIds);\n setIfPresent(attrs, 'decision.review_required', decision.reviewRequired);\n setIfPresent(attrs, 'decision.confidence', decision.confidence);\n}\n\nexport function flattenAgentAttributes(\n metadata: AgentActionMetadata,\n): AttributeMap {\n const normalized = normalizeMetadata(metadata);\n const attrs: AttributeMap = {\n 'autotel.agent': true,\n 'agent.action': normalized.action,\n 'agent.audit.version':\n normalized.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n 'agent.event.kind': normalized.eventKind ?? defaultEventKind(normalized),\n };\n\n setIfPresent(attrs, 'agent.resource', normalized.resource);\n setIfPresent(attrs, 'agent.outcome', normalized.outcome);\n setIfPresent(attrs, 'reasoning.summary', normalized.reasoningSummary);\n appendIdentityAttributes(attrs, normalized.agent);\n appendDelegationAttributes(attrs, normalized.delegation);\n appendToolAttributes(attrs, normalized.tool);\n appendPolicyAttributes(attrs, normalized.policy);\n appendGovernanceAttributes(attrs, normalized.governance);\n appendSessionAttributes(attrs, normalized.session);\n appendDecisionAttributes(attrs, normalized.decision);\n\n return attrs;\n}\n\nexport function setAgentAttributes(\n metadata: AgentActionMetadata,\n ctx?: AgentContext,\n): void {\n const traceCtx = resolveContext(ctx);\n traceCtx.setAttributes(flattenAgentAttributes(metadata));\n}\n\n/**\n * Stamp only the terminal outcome on the active span. Used by lifecycle\n * wrappers on completion so they don't re-flatten (and clobber) richer state a\n * nested step already wrote — e.g. a tool call's `tool.status=complete`.\n */\nexport function setAgentOutcome(\n outcome: AgentActionMetadata['outcome'] & string,\n ctx?: AgentContext,\n): void {\n resolveContext(ctx).setAttribute('agent.outcome', outcome);\n}\n","import {\n createNoopRequestLogger,\n getRequestLoggerSafe,\n type RequestLogger,\n} from 'autotel';\nimport { forceKeepAuditEvent, withAudit } from 'autotel-audit';\nimport { estimateLLMCost, type TokenUsage } from '../cost.js';\nimport {\n genAiRequestAttributes,\n genAiResponseAttributes,\n genAiUsageAttributes,\n type GenAiAttributeMap,\n} from '../attributes.js';\nimport { setAgentAttributes, setAgentOutcome } from './attributes.js';\nimport {\n buildLoggerContext,\n buildLifecycleUpdateContext,\n buildAuditMetadata,\n normalizeMetadata,\n} from './metadata.js';\nimport {\n MISSING_CONTEXT_MESSAGE,\n resolveContextSafe,\n warnMissingContextOnce,\n type AgentContext,\n} from './context.js';\nimport { hashPayload } from './hash.js';\nimport type {\n AgentActionFactory,\n AgentActionMetadata,\n AgentAiMetadata,\n AgentActionOptions,\n AgentHandler,\n AgentMetadataInput,\n AgentToolCallActionMetadata,\n AgentToolCallOptions,\n ToolCallMetadata,\n} from './types.js';\n\n/**\n * Record canonical OpenTelemetry GenAI semantic attributes for an LLM-backed\n * agent action, reusing the local cost model. Best-effort: anything unknown is\n * simply omitted. `gen_ai.request.model` is always recorded; token counts and\n * the estimated `gen_ai.usage.cost.usd` are recorded when `usage` is available\n * (up front via metadata, or post-call via `options.extractUsage`).\n *\n * Emits canonical v1.42.0 keys only — no `gen_ai.usage.total_tokens` (not a\n * registry attribute) and no legacy `gen.ai.*` names.\n */\nfunction recordAiTelemetry(\n ctx: AgentContext,\n ai: AgentAiMetadata,\n usage?: TokenUsage,\n): void {\n const attrs: GenAiAttributeMap = {\n ...genAiRequestAttributes({\n operation: ai.operation,\n provider: ai.provider,\n model: ai.model,\n }),\n ...genAiResponseAttributes({\n model: ai.responseModel,\n id: ai.responseId,\n finishReasons: ai.finishReasons,\n }),\n };\n if (usage) {\n const cost = estimateLLMCost(\n ai.model,\n usage,\n ai.pricing ? { pricing: ai.pricing } : undefined,\n );\n Object.assign(attrs, genAiUsageAttributes({ ...usage, costUsd: cost }));\n }\n ctx.setAttributes(attrs);\n}\n\nexport async function withAgentAction<T>(\n metadata: AgentActionMetadata,\n fn: AgentHandler<T>,\n options: AgentActionOptions = {},\n): Promise<T> {\n const normalized = normalizeMetadata(metadata);\n\n return withAudit(\n buildAuditMetadata(normalized),\n async (ctx: AgentContext, logger: RequestLogger) => {\n setAgentAttributes(normalized, ctx);\n logger.set(buildLoggerContext(normalized));\n\n try {\n const result = await fn(ctx as AgentContext, logger);\n const outcome = normalized.outcome ?? 'success';\n setAgentOutcome(outcome, ctx);\n logger.set({ agent: { outcome } });\n if (normalized.ai) {\n recordAiTelemetry(\n ctx,\n normalized.ai,\n options.extractUsage?.(result) ?? normalized.ai.usage,\n );\n }\n return result;\n } catch (error) {\n setAgentOutcome('failure', ctx);\n logger.set({ agent: { outcome: 'failure' } });\n if (normalized.ai) recordAiTelemetry(ctx, normalized.ai);\n throw error;\n }\n },\n options,\n );\n}\n\nexport function recordPolicyDecision(\n metadata: AgentActionMetadata,\n options: AgentActionOptions = {},\n): void {\n const normalized = normalizeMetadata(metadata);\n const traceCtx = resolveContextSafe(options.ctx);\n\n // No trace context: degrade per onMissingContext instead of throwing into\n // business logic. A policy decision we couldn't record is not worth a crash.\n if (!traceCtx) {\n const mode = options.onMissingContext ?? 'warn';\n if (mode === 'throw') {\n throw new Error(MISSING_CONTEXT_MESSAGE);\n }\n if (mode === 'warn') {\n warnMissingContextOnce(normalized.action);\n }\n return;\n }\n\n const logger =\n options.logger ?? getRequestLoggerSafe() ?? createNoopRequestLogger();\n\n if (options.forceKeep !== false) {\n forceKeepAuditEvent(traceCtx);\n }\n\n setAgentAttributes(normalized, traceCtx);\n logger.set(buildLoggerContext(normalized));\n\n if (options.emitNow) {\n logger.emitNow();\n }\n}\n\nexport function recordDecisionBasis(\n metadata: AgentActionMetadata,\n options: AgentActionOptions = {},\n): void {\n if (!metadata.decision && !metadata.reasoningSummary) {\n throw new Error(\n '[autotel-genai] recordDecisionBasis requires metadata.decision or metadata.reasoningSummary.',\n );\n }\n\n recordPolicyDecision(metadata, options);\n}\n\n/**\n * Define a reusable, instrumented agent action — the `trace()`-style factory\n * companion to `withAgentAction`. Declare it once at module scope and call the\n * returned function many times; each call opens its own audit scope.\n *\n * `metadata` may be a static object or a function of the call arguments, so\n * call-specific fields can be derived per invocation.\n *\n * @example\n * ```ts\n * const planTrip = defineAgentAction(\n * (req: TripRequest) => ({\n * action: 'agent.trip.plan',\n * agent: { id: 'planner' },\n * delegation: { parentIdentity: req.userId, scope: ['trip:plan'] },\n * }),\n * (ctx) => async (req: TripRequest) => planItinerary(req),\n * );\n *\n * await planTrip({ userId: 'usr_1', destination: 'Lisbon' });\n * ```\n */\nexport function defineAgentAction<TArgs extends unknown[], TResult>(\n metadata: AgentMetadataInput<TArgs, AgentActionMetadata>,\n factory: AgentActionFactory<TArgs, TResult>,\n options: AgentActionOptions = {},\n): (...args: TArgs) => Promise<TResult> {\n return (...args: TArgs): Promise<TResult> => {\n const resolved =\n typeof metadata === 'function' ? metadata(...args) : metadata;\n return withAgentAction(\n resolved,\n (ctx, logger) => factory(ctx, logger)(...args),\n options,\n );\n };\n}\n\n/**\n * Define a reusable, instrumented agent tool call — the `trace()`-style factory\n * companion to `withAgentToolCall`. Declare it once and call it per invocation;\n * tool inputs/results are hashed (never attached raw) on every call.\n *\n * Pass `metadata` as a function of the arguments when `tool.input` (or any other\n * field) depends on the call, so each invocation hashes its own input.\n *\n * @example\n * ```ts\n * const handleRefund = defineAgentToolCall(\n * (req: RefundRequest) => ({\n * action: 'agent.refund.tool_call',\n * resource: 'stripe_refund_v3',\n * agent: { id: 'refunds-specialist' },\n * tool: { name: 'stripe_refund_v3', input: { refundId: req.refundId } },\n * }),\n * (ctx) => async (req: RefundRequest) => stripe.refunds.create(req),\n * );\n *\n * await handleRefund({ refundId: 're_123' });\n * ```\n */\nexport function defineAgentToolCall<TArgs extends unknown[], TResult>(\n metadata: AgentMetadataInput<TArgs, AgentToolCallActionMetadata>,\n factory: AgentActionFactory<TArgs, TResult>,\n options: AgentToolCallOptions = {},\n): (...args: TArgs) => Promise<TResult> {\n return (...args: TArgs): Promise<TResult> => {\n const resolved =\n typeof metadata === 'function' ? metadata(...args) : metadata;\n return withAgentToolCall(\n resolved,\n (ctx, logger) => factory(ctx, logger)(...args),\n options,\n );\n };\n}\n\nexport async function withAgentToolCall<T>(\n metadata: AgentActionMetadata & { tool: ToolCallMetadata },\n fn: AgentHandler<T>,\n options: AgentToolCallOptions = {},\n): Promise<T> {\n const start = Date.now();\n const normalized = normalizeMetadata({\n ...metadata,\n tool: {\n ...metadata.tool,\n status: metadata.tool?.status ?? 'planned',\n } as ToolCallMetadata,\n });\n\n return withAgentAction(\n normalized,\n async (ctx, logger) => {\n try {\n const result = await fn(ctx, logger);\n const executionMs = Date.now() - start;\n const completed: AgentActionMetadata = {\n ...normalized,\n outcome: normalized.outcome ?? 'success',\n tool: {\n ...metadata.tool,\n inputHash: normalized.tool?.inputHash,\n outputHash:\n normalized.tool?.outputHash ??\n (options.hashResult === false ? undefined : hashPayload(result)),\n status: 'complete',\n executionMs,\n },\n };\n setAgentAttributes(completed, ctx);\n logger.set(buildLifecycleUpdateContext(normalizeMetadata(completed)));\n return result;\n } catch (error) {\n const failed: AgentActionMetadata = {\n ...normalized,\n outcome: 'failure',\n tool: {\n ...metadata.tool,\n inputHash: normalized.tool?.inputHash,\n status: 'error',\n executionMs: Date.now() - start,\n },\n };\n setAgentAttributes(failed, ctx);\n logger.set(buildLifecycleUpdateContext(normalizeMetadata(failed)));\n throw error;\n }\n },\n options,\n );\n}\n","import { hashPayload } from './hash.js';\nimport { recordPolicyDecision } from './runtime.js';\nimport type {\n AgentActionOptions,\n AgentIdentity,\n DelegationContext,\n GovernanceMetadata,\n} from './types.js';\n\nfunction buildAuthorityLineage(\n parentIdentity: string,\n agentId: string,\n existingLineage?: string[],\n): string[] {\n const lineage = existingLineage ? [...existingLineage] : [parentIdentity];\n if (lineage.at(-1) !== agentId) {\n lineage.push(agentId);\n }\n return lineage;\n}\n\nexport interface DelegateToAgentInput {\n parentIdentity: string;\n targetAgentId: string;\n scope?: string | string[];\n tokenId?: string;\n delegationId?: string;\n authorityLineage?: string[];\n issuedAt?: string | Date;\n expiresAt?: string | Date;\n}\n\nexport interface RecordAgentHandoffMetadata {\n action: string;\n fromAgent: AgentIdentity;\n toAgent: AgentIdentity;\n parentIdentity: string;\n resource?: string;\n scope?: string | string[];\n tokenId?: string;\n delegationId?: string;\n authorityLineage?: string[];\n governance?: GovernanceMetadata;\n}\n\nexport function delegateToAgent(input: DelegateToAgentInput): DelegationContext {\n const authorityLineage = buildAuthorityLineage(\n input.parentIdentity,\n input.targetAgentId,\n input.authorityLineage,\n );\n\n return {\n parentIdentity: input.parentIdentity,\n ...(input.scope !== undefined && { scope: input.scope }),\n ...(input.tokenId !== undefined && { tokenId: input.tokenId }),\n ...(input.delegationId !== undefined && { delegationId: input.delegationId }),\n authorityLineage,\n authorityLineageHash: hashPayload(authorityLineage),\n depth: Math.max(authorityLineage.length - 1, 0),\n issuedAt: input.issuedAt ?? new Date().toISOString(),\n ...(input.expiresAt !== undefined && { expiresAt: input.expiresAt }),\n };\n}\n\nexport function recordAgentHandoff(\n metadata: RecordAgentHandoffMetadata,\n options: AgentActionOptions = {},\n): void {\n // Seed the lineage with the source agent when the caller didn't supply one,\n // so the \"from\" side of the handoff is recorded in the canonical, queryable\n // `delegation.authority_lineage` (and its hash) rather than surviving only in\n // the free-text reasoningSummary.\n const authorityLineage =\n metadata.authorityLineage ?? [metadata.parentIdentity, metadata.fromAgent.id];\n\n const delegation = delegateToAgent({\n parentIdentity: metadata.parentIdentity,\n targetAgentId: metadata.toAgent.id,\n scope: metadata.scope,\n tokenId: metadata.tokenId,\n delegationId: metadata.delegationId,\n authorityLineage,\n });\n\n recordPolicyDecision(\n {\n action: metadata.action,\n resource: metadata.resource,\n eventKind: 'handoff',\n agent: metadata.toAgent,\n delegation,\n governance: metadata.governance,\n reasoningSummary: `Control passed from ${metadata.fromAgent.id} to ${metadata.toAgent.id}.`,\n },\n options,\n );\n}\n","import { buildLifecycleUpdateContext } from './metadata.js';\nimport { setAgentAttributes } from './attributes.js';\nimport { withAgentAction } from './runtime.js';\nimport type {\n AgentActionOptions,\n AgentHandler,\n AgentSessionActionMetadata,\n} from './types.js';\n\nfunction toIsoString(value?: string | Date): string {\n if (!value) return new Date().toISOString();\n return value instanceof Date ? value.toISOString() : value;\n}\n\nexport async function withAgentSession<T>(\n metadata: AgentSessionActionMetadata,\n fn: AgentHandler<T>,\n options: AgentActionOptions = {},\n): Promise<T> {\n const startedAt = toIsoString(metadata.session?.startedAt);\n\n return withAgentAction(\n {\n ...metadata,\n category: metadata.category ?? 'agent_session',\n session: {\n ...metadata.session,\n status: metadata.session?.status ?? 'active',\n startedAt,\n },\n },\n async (ctx, logger) => {\n try {\n const result = await fn(ctx, logger);\n const completed = {\n ...metadata,\n outcome: metadata.outcome ?? 'success',\n session: {\n ...metadata.session,\n status: 'completed' as const,\n startedAt,\n endedAt: new Date().toISOString(),\n },\n };\n setAgentAttributes(completed, ctx);\n logger.set(buildLifecycleUpdateContext(completed));\n return result;\n } catch (error) {\n const failed = {\n ...metadata,\n outcome: 'failure' as const,\n session: {\n ...metadata.session,\n status: 'failed' as const,\n startedAt,\n endedAt: new Date().toISOString(),\n },\n };\n setAgentAttributes(failed, ctx);\n logger.set(buildLifecycleUpdateContext(failed));\n throw error;\n }\n },\n options,\n );\n}\n","import { hashPayload } from './hash.js';\nimport { delegateToAgent } from './delegation.js';\nimport type {\n AgentIdentity,\n AgentIdentityRegistry,\n AgentIdentityRecord,\n AgentIdentityStatus,\n DelegationContext,\n} from './types.js';\n\nfunction toIsoString(value?: string | Date): string | undefined {\n if (!value) return undefined;\n return value instanceof Date ? value.toISOString() : value;\n}\n\nfunction normalizeScopes(scope?: string | string[]): string[] {\n if (!scope) return [];\n return Array.isArray(scope) ? [...scope] : [scope];\n}\n\nfunction isExpired(record: AgentIdentityRecord, at: string): boolean {\n return record.expiresAt !== undefined && record.expiresAt < at;\n}\n\nexport interface ProvisionAgentIdentityInput {\n agent: AgentIdentity;\n scopes?: string[];\n tokenId?: string;\n delegatedBy?: string;\n provisionedAt?: string | Date;\n expiresAt?: string | Date;\n metadata?: Record<string, unknown>;\n}\n\nexport interface RotateAgentIdentityInput {\n scopes?: string[];\n tokenId?: string;\n delegatedBy?: string;\n rotatedAt?: string | Date;\n expiresAt?: string | Date;\n metadata?: Record<string, unknown>;\n}\n\nexport interface RevokeAgentIdentityInput {\n reason: string;\n revokedAt?: string | Date;\n}\n\nexport function createAgentIdentityRegistry(\n initial: ProvisionAgentIdentityInput[] = [],\n): AgentIdentityRegistry {\n const records = new Map<string, AgentIdentityRecord>();\n\n const provisionIdentity = (\n input: ProvisionAgentIdentityInput,\n ): AgentIdentityRecord => {\n const now = toIsoString(input.provisionedAt) ?? new Date().toISOString();\n const record: AgentIdentityRecord = {\n agent: input.agent,\n scopes: input.scopes ?? [],\n status: 'active',\n tokenId: input.tokenId,\n tokenHash:\n input.tokenId === undefined ? undefined : hashPayload(input.tokenId),\n delegatedBy: input.delegatedBy,\n provisionedAt: now,\n expiresAt: toIsoString(input.expiresAt),\n metadata: input.metadata,\n };\n records.set(input.agent.id, record);\n return record;\n };\n\n for (const item of initial) {\n provisionIdentity(item);\n }\n\n return {\n provisionIdentity,\n rotateIdentity(agentId: string, input: RotateAgentIdentityInput = {}) {\n const existing = records.get(agentId);\n if (!existing) {\n throw new Error(\n `[autotel-genai] Cannot rotate unknown agent identity \"${agentId}\".`,\n );\n }\n\n const rotatedAt = toIsoString(input.rotatedAt) ?? new Date().toISOString();\n const record: AgentIdentityRecord = {\n ...existing,\n scopes: input.scopes ?? existing.scopes,\n status: 'rotated',\n tokenId: input.tokenId ?? existing.tokenId,\n tokenHash:\n input.tokenId === undefined\n ? existing.tokenHash\n : hashPayload(input.tokenId),\n delegatedBy: input.delegatedBy ?? existing.delegatedBy,\n rotatedAt,\n expiresAt: toIsoString(input.expiresAt) ?? existing.expiresAt,\n metadata: input.metadata ?? existing.metadata,\n };\n records.set(agentId, record);\n return record;\n },\n revokeIdentity(agentId: string, input: RevokeAgentIdentityInput) {\n const existing = records.get(agentId);\n if (!existing) {\n throw new Error(\n `[autotel-genai] Cannot revoke unknown agent identity \"${agentId}\".`,\n );\n }\n\n const revokedAt = toIsoString(input.revokedAt) ?? new Date().toISOString();\n const record: AgentIdentityRecord = {\n ...existing,\n status: 'revoked',\n revokedAt,\n revocationReason: input.reason,\n };\n records.set(agentId, record);\n return record;\n },\n getIdentity(agentId: string) {\n return records.get(agentId);\n },\n getIdentityStatus(agentId: string, at = new Date().toISOString()) {\n const record = records.get(agentId);\n if (!record) return;\n return isExpired(record, at) ? 'expired' : record.status;\n },\n assertUsable(agentId: string, at = new Date().toISOString()) {\n const record = records.get(agentId);\n if (!record) {\n throw new Error(\n `[autotel-genai] Unknown agent identity \"${agentId}\". Provision it before use.`,\n );\n }\n\n const status: AgentIdentityStatus = isExpired(record, at)\n ? 'expired'\n : record.status;\n\n if (status !== 'active' && status !== 'rotated') {\n throw new Error(\n `[autotel-genai] Agent identity \"${agentId}\" is ${status} and cannot execute delegated work.`,\n );\n }\n\n return record;\n },\n assertScopes(agentId: string, requiredScopes: string[]) {\n const record = this.assertUsable(agentId);\n const missing = requiredScopes.filter(\n (scope) => !record.scopes.includes(scope),\n );\n\n if (missing.length > 0) {\n throw new Error(\n `[autotel-genai] Agent identity \"${agentId}\" is missing delegated scopes: ${missing.join(', ')}.`,\n );\n }\n\n return record;\n },\n issueDelegation(agentId: string, input) {\n const record = this.assertUsable(agentId);\n const scope = normalizeScopes(input.scope);\n if (scope.length > 0) {\n this.assertScopes(agentId, scope);\n }\n\n return delegateToAgent({\n parentIdentity: input.parentIdentity,\n targetAgentId: record.agent.id,\n scope: input.scope ?? record.scopes,\n tokenId: input.tokenId ?? record.tokenId,\n delegationId: input.delegationId,\n authorityLineage: input.authorityLineage,\n issuedAt: input.issuedAt,\n expiresAt: input.expiresAt ?? record.expiresAt,\n }) satisfies DelegationContext;\n },\n list() {\n return [...records.values()];\n },\n };\n}\n","import { hashPayload } from './hash.js';\nimport type { PrivacyProfile, PrivacyProfileName } from './types.js';\n\nexport type PrivacyProfileInput = PrivacyProfileName | PrivacyProfile;\n\nconst PRIVACY_PROFILES: Record<PrivacyProfileName, PrivacyProfile> = {\n strict: {\n name: 'strict',\n hashKeys: [\n /email/i,\n /phone/i,\n /user_?id/i,\n /account/i,\n /customer/i,\n /card/i,\n /iban/i,\n /tax/i,\n ],\n dropKeys: [\n /secret/i,\n /token/i,\n /api[_-]?key/i,\n /authorization/i,\n /cookie/i,\n /password/i,\n /bearer/i,\n ],\n maskKeys: [/name/i, /address/i, /prompt/i, /message/i, /content/i],\n maxStringLength: 256,\n },\n pci: {\n name: 'pci',\n hashKeys: [/card/i, /pan/i, /account/i, /customer/i, /email/i],\n dropKeys: [/cvv/i, /cvc/i, /secret/i, /token/i, /api[_-]?key/i],\n maskKeys: [/name/i, /address/i],\n maxStringLength: 128,\n },\n healthcare: {\n name: 'healthcare',\n hashKeys: [/patient/i, /mrn/i, /member/i, /email/i, /phone/i],\n dropKeys: [/diagnosis/i, /notes/i, /secret/i, /token/i, /password/i],\n maskKeys: [/name/i, /address/i, /symptom/i],\n maxStringLength: 128,\n },\n};\n\nfunction maskValue(value: unknown): unknown {\n if (typeof value !== 'string') {\n return '<masked>';\n }\n\n if (value.length <= 6) return '***';\n return `${value.slice(0, 3)}***${value.slice(-3)}`;\n}\n\nfunction matches(patterns: RegExp[] | undefined, key: string): boolean {\n return patterns?.some((pattern) => pattern.test(key)) ?? false;\n}\n\nfunction truncateString(value: string, maxLength?: number): string {\n if (maxLength === undefined || value.length <= maxLength) {\n return value;\n }\n\n return `${value.slice(0, maxLength)}…`;\n}\n\nfunction sanitizeNode(\n value: unknown,\n profile: PrivacyProfile,\n keyPath: string,\n): unknown {\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n const lowered = keyPath.toLowerCase();\n\n if (matches(profile.dropKeys, lowered)) {\n return '<redacted>';\n }\n\n if (matches(profile.hashKeys, lowered)) {\n return hashPayload(value);\n }\n\n if (matches(profile.maskKeys, lowered)) {\n return maskValue(value);\n }\n\n if (typeof value === 'string') {\n return truncateString(value, profile.maxStringLength);\n }\n\n if (Array.isArray(value)) {\n return value.map((entry, index) =>\n sanitizeNode(entry, profile, `${keyPath}[${index}]`),\n );\n }\n\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, entry]) => [\n key,\n sanitizeNode(entry, profile, keyPath ? `${keyPath}.${key}` : key),\n ]),\n );\n }\n\n if (typeof value === 'bigint') {\n return value.toString(10);\n }\n\n return value;\n}\n\nexport function resolvePrivacyProfile(\n profile: PrivacyProfileInput = 'strict',\n): PrivacyProfile {\n return typeof profile === 'string' ? PRIVACY_PROFILES[profile] : profile;\n}\n\nexport function sanitizeAuditPayload(\n value: unknown,\n profile: PrivacyProfileInput = 'strict',\n): unknown {\n return sanitizeNode(value, resolvePrivacyProfile(profile), '');\n}\n","import { AGENT_AUDIT_SCHEMA_VERSION } from './constants.js';\nimport { canonicalizeForHash, hashPayload } from './hash.js';\nimport { normalizeMetadata } from './metadata.js';\nimport { sanitizeAuditPayload, type PrivacyProfileInput } from './privacy.js';\nimport type {\n AgentActionMetadata,\n AgentAuditEventEnvelope,\n} from './types.js';\n\nfunction toIsoString(value?: string | Date): string {\n if (!value) return new Date().toISOString();\n return value instanceof Date ? value.toISOString() : value;\n}\n\nexport interface CreateSignedEventEnvelopeOptions {\n emittedAt?: string | Date;\n previousEventHash?: string;\n evidence?: unknown;\n privacyProfile?: PrivacyProfileInput;\n signer?: (serialized: string) => string | Promise<string>;\n}\n\nexport async function createSignedEventEnvelope(\n metadata: AgentActionMetadata,\n options: CreateSignedEventEnvelopeOptions = {},\n): Promise<AgentAuditEventEnvelope> {\n const normalized = normalizeMetadata(metadata);\n const envelopeBase = {\n schemaVersion: normalized.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n emittedAt: toIsoString(options.emittedAt),\n ...(options.previousEventHash !== undefined && {\n previousEventHash: options.previousEventHash,\n }),\n metadata: normalized,\n ...(options.evidence !== undefined && {\n evidence: sanitizeAuditPayload(\n options.evidence,\n options.privacyProfile ?? 'strict',\n ),\n }),\n };\n\n const eventHash = hashPayload(envelopeBase);\n const signature = options.signer\n ? await options.signer(canonicalizeForHash(envelopeBase))\n : undefined;\n\n return {\n ...envelopeBase,\n eventHash,\n ...(signature !== undefined && { signature }),\n };\n}\n\nexport function verifyEventEnvelopeHash(\n envelope: AgentAuditEventEnvelope,\n): boolean {\n const expected = hashPayload({\n schemaVersion: envelope.schemaVersion,\n emittedAt: envelope.emittedAt,\n ...(envelope.previousEventHash !== undefined && {\n previousEventHash: envelope.previousEventHash,\n }),\n metadata: envelope.metadata,\n ...(envelope.evidence !== undefined && {\n evidence: envelope.evidence,\n }),\n });\n return envelope.eventHash === expected;\n}\n","import { createStructuredError } from 'autotel';\nimport { securityEvent } from 'autotel-audit';\nimport { sanitizeAuditPayload, type PrivacyProfileInput } from './privacy.js';\nimport { recordDecisionBasis, recordPolicyDecision, withAgentToolCall } from './runtime.js';\nimport { hashPayload } from './hash.js';\nimport type {\n AgentActionOptions,\n AgentDecisionMetadata,\n AgentHandler,\n AgentToolCallOptions,\n DelegationContext,\n GovernanceMetadata,\n PolicyMetadata,\n ScopedToolDefinition,\n} from './types.js';\n\nfunction normalizeScopes(scope?: string | string[]): string[] {\n if (!scope) return [];\n return Array.isArray(scope) ? scope : [scope];\n}\n\nfunction missingScopes(\n delegated: string[],\n required: string[],\n): string[] {\n return required.filter((scope) => !delegated.includes(scope));\n}\n\ninterface ScopeDenial {\n scopes: string[];\n reason: string;\n why: string;\n}\n\n/**\n * Decide whether a scoped tool call must be denied.\n *\n * When the identity is registry-backed, the registry is authoritative: a\n * delegation may only *narrow* the stored grant, never widen it. Scopes a\n * caller claims that the registry never granted are a forged escalation and are\n * denied before any missing-scope check — otherwise passing an explicit\n * `delegation.scope` could grant access the registry record does not allow.\n */\nfunction resolveScopeDenial(\n claimedScopes: string[],\n requiredScopes: string[],\n registryScopes: string[] | undefined,\n): ScopeDenial | undefined {\n const unauthorized = registryScopes\n ? claimedScopes.filter((scope) => !registryScopes.includes(scope))\n : [];\n if (unauthorized.length > 0) {\n return {\n scopes: unauthorized,\n reason: `unauthorized_scope:${unauthorized.join(',')}`,\n why: `Delegation claims scopes the identity was never granted: ${unauthorized.join(', ')}`,\n };\n }\n\n const missing = missingScopes(claimedScopes, requiredScopes);\n if (missing.length > 0) {\n return {\n scopes: missing,\n reason: `missing_scope:${missing.join(',')}`,\n why: `Missing delegated scopes: ${missing.join(', ')}`,\n };\n }\n\n return undefined;\n}\n\nfunction resolveDelegation(\n definition: Pick<ScopedToolDefinition<unknown>, 'agent' | 'delegation' | 'identityRegistry'>,\n): DelegationContext | undefined {\n const registry = definition.identityRegistry;\n if (registry) {\n registry.assertUsable(definition.agent.id);\n }\n\n return definition.delegation;\n}\n\nfunction buildGovernance(\n governance: GovernanceMetadata | undefined,\n reviewRequired: boolean | undefined,\n): GovernanceMetadata | undefined {\n if (!governance && reviewRequired === undefined) return governance;\n return {\n ...governance,\n ...(reviewRequired !== undefined && { reviewRequired }),\n };\n}\n\nfunction buildDecision(\n input: unknown,\n decision: AgentDecisionMetadata | undefined,\n privacyProfile: PrivacyProfileInput | undefined,\n): AgentDecisionMetadata | undefined {\n if (!decision) return undefined;\n\n const sanitizedInput = sanitizeAuditPayload(input, privacyProfile ?? 'strict');\n return {\n ...decision,\n inputHash: decision.inputHash ?? hashPayload(sanitizedInput),\n };\n}\n\nexport async function withScopedTool<TInput, TOutput>(\n definition: ScopedToolDefinition<TInput>,\n input: TInput,\n fn: AgentHandler<TOutput>,\n options: AgentToolCallOptions & AgentActionOptions = {},\n): Promise<TOutput> {\n const requiredScopes = definition.requiredScopes ?? [];\n const delegation = resolveDelegation(definition);\n const registryScopes = definition.identityRegistry?.getIdentity(\n definition.agent.id,\n )?.scopes;\n const claimedScopes = normalizeScopes(delegation?.scope ?? registryScopes);\n const denial = resolveScopeDenial(\n claimedScopes,\n requiredScopes,\n registryScopes,\n );\n const policy: PolicyMetadata | undefined =\n definition.policyId || definition.riskScore !== undefined || denial\n ? {\n decision: denial ? 'deny' : 'permit',\n ...(definition.policyId !== undefined && {\n policyId: definition.policyId,\n }),\n ...(definition.riskScore !== undefined && {\n riskScore: definition.riskScore,\n }),\n ...(denial && { reason: denial.reason }),\n }\n : undefined;\n\n const governance = buildGovernance(\n definition.governance,\n definition.reviewRequired,\n );\n\n if (policy && policy.decision === 'deny' && denial) {\n recordPolicyDecision(\n {\n action: definition.action,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n policy,\n governance,\n decision: buildDecision(\n input,\n definition.decision,\n definition.privacyProfile,\n ),\n },\n options,\n );\n\n securityEvent(\n {\n name: 'llm.tool_call.denied',\n category: 'llm',\n outcome: 'denied',\n severity: 'warning',\n reason: denial.reason,\n targetType: 'tool',\n targetId: definition.tool.name,\n policyId: definition.policyId,\n },\n { ctx: options.ctx, onMissingContext: options.onMissingContext ?? 'warn' },\n );\n\n throw createStructuredError({\n status: 403,\n code: 'AGENT_SCOPE_DENIED',\n message: `Agent \"${definition.agent.id}\" cannot invoke ${definition.tool.name}.`,\n why: denial.why,\n fix: 'Grant the missing scopes or route the task to an agent with the required delegation.',\n });\n }\n\n if (policy) {\n recordPolicyDecision(\n {\n action: `${definition.action}.policy`,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n policy,\n governance,\n },\n options,\n );\n }\n\n if (definition.decision) {\n recordDecisionBasis(\n {\n action: `${definition.action}.decision`,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n governance,\n decision: buildDecision(\n input,\n definition.decision,\n definition.privacyProfile,\n ),\n },\n options,\n );\n }\n\n return withAgentToolCall(\n {\n action: definition.action,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n governance,\n tool: {\n ...definition.tool,\n input,\n },\n },\n fn,\n options,\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { getTraceContext, otelTrace } from "autotel";
|
|
2
|
+
|
|
3
|
+
//#region src/agent/context.ts
|
|
4
|
+
const MISSING_CONTEXT_MESSAGE = "[autotel-genai] No active trace context. Wrap the call in trace()/instrument(), pass options.ctx, or set options.onMissingContext to \"warn\"/\"skip\" to degrade gracefully instead of throwing.";
|
|
5
|
+
/**
|
|
6
|
+
* Resolve an agent context without throwing. Returns `null` when no trace context
|
|
7
|
+
* is available, so callers can degrade gracefully (best-effort instrumentation).
|
|
8
|
+
*/
|
|
9
|
+
const INVALID_TRACE_ID = "00000000000000000000000000000000";
|
|
10
|
+
function resolveContextSafe(ctx) {
|
|
11
|
+
if (ctx) return ctx;
|
|
12
|
+
const span = otelTrace.getActiveSpan();
|
|
13
|
+
if (!span) return null;
|
|
14
|
+
const ids = getTraceContext();
|
|
15
|
+
const sc = span.spanContext();
|
|
16
|
+
const traceId = ids?.traceId ?? sc.traceId;
|
|
17
|
+
if (!traceId || traceId === INVALID_TRACE_ID) return null;
|
|
18
|
+
return {
|
|
19
|
+
traceId,
|
|
20
|
+
spanId: ids?.spanId ?? sc.spanId,
|
|
21
|
+
correlationId: ids?.correlationId ?? traceId.slice(0, 16),
|
|
22
|
+
setAttribute: (key, value) => span.setAttribute(key, value),
|
|
23
|
+
setAttributes: (attrs) => span.setAttributes(attrs)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function resolveContext(ctx) {
|
|
27
|
+
const resolved = resolveContextSafe(ctx);
|
|
28
|
+
if (resolved) return resolved;
|
|
29
|
+
throw new Error(MISSING_CONTEXT_MESSAGE);
|
|
30
|
+
}
|
|
31
|
+
const warnedMissingContext = /* @__PURE__ */ new Set();
|
|
32
|
+
/** Warn (once per action) that an agent action is running without a trace context. */
|
|
33
|
+
function warnMissingContextOnce(action) {
|
|
34
|
+
if (warnedMissingContext.has(action)) return;
|
|
35
|
+
warnedMissingContext.add(action);
|
|
36
|
+
console.warn(`[autotel-genai] No active trace context for "${action}" — running un-audited. Wrap the call in trace()/instrument() or pass options.ctx to capture agent audit telemetry. (set options.onMissingContext: "throw" to fail fast, or "skip" to silence this warning)`);
|
|
37
|
+
}
|
|
38
|
+
/** Adapt an OpenTelemetry span (or span-like object) to {@link AgentContext}. */
|
|
39
|
+
function agentContextFromSpan(span) {
|
|
40
|
+
const sc = span.spanContext();
|
|
41
|
+
return {
|
|
42
|
+
traceId: sc.traceId,
|
|
43
|
+
spanId: sc.spanId,
|
|
44
|
+
correlationId: sc.traceId.slice(0, 16),
|
|
45
|
+
setAttribute: (key, value) => span.setAttribute(key, value),
|
|
46
|
+
setAttributes: (attrs) => span.setAttributes(attrs)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function toAttributeValue(value) {
|
|
50
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
if (value.every((entry) => typeof entry === "string")) return value;
|
|
53
|
+
if (value.every((entry) => typeof entry === "number")) return value;
|
|
54
|
+
if (value.every((entry) => typeof entry === "boolean")) return value;
|
|
55
|
+
try {
|
|
56
|
+
return JSON.stringify(value);
|
|
57
|
+
} catch {
|
|
58
|
+
return "<serialization-failed>";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (value instanceof Date) return value.toISOString();
|
|
62
|
+
if (typeof value === "bigint") return value.toString(10);
|
|
63
|
+
if (value === null || value === void 0) return;
|
|
64
|
+
try {
|
|
65
|
+
return JSON.stringify(value);
|
|
66
|
+
} catch {
|
|
67
|
+
return "<serialization-failed>";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { toAttributeValue as a, resolveContextSafe as i, agentContextFromSpan as n, warnMissingContextOnce as o, resolveContext as r, MISSING_CONTEXT_MESSAGE as t };
|
|
73
|
+
//# sourceMappingURL=context-B2wjX3O1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-B2wjX3O1.js","names":[],"sources":["../src/agent/context.ts"],"sourcesContent":["import { getTraceContext, otelTrace } from 'autotel';\n\nexport interface AgentContext {\n traceId: string;\n spanId: string;\n correlationId: string;\n setAttribute(key: string, value: string | number | boolean): void;\n setAttributes(\n attrs: Record<string, string | number | boolean | string[] | number[] | boolean[]>,\n ): void;\n}\n\nexport const MISSING_CONTEXT_MESSAGE =\n '[autotel-genai] No active trace context. Wrap the call in trace()/instrument(), pass options.ctx, ' +\n 'or set options.onMissingContext to \"warn\"/\"skip\" to degrade gracefully instead of throwing.';\n\n/**\n * Resolve an agent context without throwing. Returns `null` when no trace context\n * is available, so callers can degrade gracefully (best-effort instrumentation).\n */\nconst INVALID_TRACE_ID = '00000000000000000000000000000000';\n\nexport function resolveContextSafe(ctx?: AgentContext): AgentContext | null {\n if (ctx) return ctx;\n\n const span = otelTrace.getActiveSpan();\n if (!span) return null;\n\n // Resolve trace ids from autotel's context when available, otherwise from the\n // active OTel span itself. This makes agent audit work in *any* OTel setup —\n // @effect/opentelemetry, a vanilla NodeSDK, autotel-cloudflare's instrumented\n // fetch handler — not just inside autotel's own `trace()`.\n const ids = getTraceContext();\n const sc = span.spanContext();\n const traceId = ids?.traceId ?? sc.traceId;\n if (!traceId || traceId === INVALID_TRACE_ID) return null;\n\n return {\n traceId,\n spanId: ids?.spanId ?? sc.spanId,\n correlationId: ids?.correlationId ?? traceId.slice(0, 16),\n setAttribute: (key, value) => span.setAttribute(key, value),\n setAttributes: (attrs) => span.setAttributes(attrs),\n };\n}\n\nexport function resolveContext(ctx?: AgentContext): AgentContext {\n const resolved = resolveContextSafe(ctx);\n if (resolved) return resolved;\n throw new Error(MISSING_CONTEXT_MESSAGE);\n}\n\nconst warnedMissingContext = new Set<string>();\n\n/** Warn (once per action) that an agent action is running without a trace context. */\nexport function warnMissingContextOnce(action: string): void {\n if (warnedMissingContext.has(action)) return;\n warnedMissingContext.add(action);\n console.warn(\n `[autotel-genai] No active trace context for \"${action}\" — running un-audited. ` +\n 'Wrap the call in trace()/instrument() or pass options.ctx to capture agent audit telemetry. ' +\n '(set options.onMissingContext: \"throw\" to fail fast, or \"skip\" to silence this warning)',\n );\n}\n\n/** A no-op {@link AgentContext} whose attribute setters do nothing. */\nexport function noopAgentContext(): AgentContext {\n return {\n traceId: '',\n spanId: '',\n correlationId: '',\n setAttribute() {},\n setAttributes() {},\n };\n}\n\n/** Adapt an OpenTelemetry span (or span-like object) to {@link AgentContext}. */\nexport function agentContextFromSpan(span: {\n spanContext(): { traceId: string; spanId: string };\n setAttribute(key: string, value: string | number | boolean): void;\n setAttributes(\n attrs: Record<string, string | number | boolean | string[] | number[] | boolean[]>,\n ): void;\n}): AgentContext {\n const sc = span.spanContext();\n return {\n traceId: sc.traceId,\n spanId: sc.spanId,\n correlationId: sc.traceId.slice(0, 16),\n setAttribute: (key, value) => span.setAttribute(key, value),\n setAttributes: (attrs) => span.setAttributes(attrs),\n };\n}\n\nexport function toAttributeValue(\n value: unknown,\n): string | number | boolean | string[] | number[] | boolean[] | undefined {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n\n if (Array.isArray(value)) {\n if (value.every((entry) => typeof entry === 'string')) {\n return value;\n }\n\n if (value.every((entry) => typeof entry === 'number')) {\n return value;\n }\n\n if (value.every((entry) => typeof entry === 'boolean')) {\n return value;\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return '<serialization-failed>';\n }\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'bigint') {\n return value.toString(10);\n }\n\n if (value === null || value === undefined) {\n return undefined;\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return '<serialization-failed>';\n }\n}\n"],"mappings":";;;AAYA,MAAa,0BACX;;;;;AAOF,MAAM,mBAAmB;AAEzB,SAAgB,mBAAmB,KAAyC;CAC1E,IAAI,KAAK,OAAO;CAEhB,MAAM,OAAO,UAAU,cAAc;CACrC,IAAI,CAAC,MAAM,OAAO;CAMlB,MAAM,MAAM,gBAAgB;CAC5B,MAAM,KAAK,KAAK,YAAY;CAC5B,MAAM,UAAU,KAAK,WAAW,GAAG;CACnC,IAAI,CAAC,WAAW,YAAY,kBAAkB,OAAO;CAErD,OAAO;EACL;EACA,QAAQ,KAAK,UAAU,GAAG;EAC1B,eAAe,KAAK,iBAAiB,QAAQ,MAAM,GAAG,EAAE;EACxD,eAAe,KAAK,UAAU,KAAK,aAAa,KAAK,KAAK;EAC1D,gBAAgB,UAAU,KAAK,cAAc,KAAK;CACpD;AACF;AAEA,SAAgB,eAAe,KAAkC;CAC/D,MAAM,WAAW,mBAAmB,GAAG;CACvC,IAAI,UAAU,OAAO;CACrB,MAAM,IAAI,MAAM,uBAAuB;AACzC;AAEA,MAAM,uCAAuB,IAAI,IAAY;;AAG7C,SAAgB,uBAAuB,QAAsB;CAC3D,IAAI,qBAAqB,IAAI,MAAM,GAAG;CACtC,qBAAqB,IAAI,MAAM;CAC/B,QAAQ,KACN,gDAAgD,OAAO,4MAGzD;AACF;;AAcA,SAAgB,qBAAqB,MAMpB;CACf,MAAM,KAAK,KAAK,YAAY;CAC5B,OAAO;EACL,SAAS,GAAG;EACZ,QAAQ,GAAG;EACX,eAAe,GAAG,QAAQ,MAAM,GAAG,EAAE;EACrC,eAAe,KAAK,UAAU,KAAK,aAAa,KAAK,KAAK;EAC1D,gBAAgB,UAAU,KAAK,cAAc,KAAK;CACpD;AACF;AAEA,SAAgB,iBACd,OACyE;CACzE,IACE,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,WAEjB,OAAO;CAGT,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,IAAI,MAAM,OAAO,UAAU,OAAO,UAAU,QAAQ,GAClD,OAAO;EAGT,IAAI,MAAM,OAAO,UAAU,OAAO,UAAU,QAAQ,GAClD,OAAO;EAGT,IAAI,MAAM,OAAO,UAAU,OAAO,UAAU,SAAS,GACnD,OAAO;EAGT,IAAI;GACF,OAAO,KAAK,UAAU,KAAK;EAC7B,QAAQ;GACN,OAAO;EACT;CACF;CAEA,IAAI,iBAAiB,MACnB,OAAO,MAAM,YAAY;CAG3B,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,SAAS,EAAE;CAG1B,IAAI,UAAU,QAAQ,UAAU,QAC9B;CAGF,IAAI;EACF,OAAO,KAAK,UAAU,KAAK;CAC7B,QAAQ;EACN,OAAO;CACT;AACF"}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { chunkIntervalStats, computeStreamTiming, createStreamTimer, recordStrea
|
|
|
7
7
|
import { recordGenAiResponse, recordGenAiUsage, traceGenAI, traceLLM } from "./trace.js";
|
|
8
8
|
import { CONTEXT_LIMITS, contextBudget, costCeiling, createGenAiBudget, createGenAiGuard, errorLoop, maxDuration, maxSteps, maxToolCalls, parseGuardRules, spinLoop, tokenCeiling } from "./guard.js";
|
|
9
9
|
import { AI_SDK_ATTR, estimateAiSdkCost, extractAiSdkModel, extractAiSdkUsage, mapAiSdkAttributes, normalizeAiSdkProvider, recordAiSdkCost } from "./ai-sdk-bridge.js";
|
|
10
|
-
import { i as SpanRegistry, n as observeAiSdkResult, r as createGenAiObserver, t as createLangChainObserver } from "./observer-
|
|
11
|
-
import {
|
|
10
|
+
import { i as SpanRegistry, n as observeAiSdkResult, r as createGenAiObserver, t as createLangChainObserver } from "./observer-2SKgcQI_.js";
|
|
11
|
+
import { A as withAgentAction, C as withAgentSession, D as defineAgentToolCall, E as defineAgentAction, F as canonicalizeForHash, I as hashPayload, L as AGENT_AUDIT_SCHEMA_VERSION, M as flattenAgentAttributes, N as setAgentAttributes, O as recordDecisionBasis, P as createAgentAuditMetadata, S as createAgentIdentityRegistry, T as recordAgentHandoff, _ as withScopedTool, b as resolvePrivacyProfile, j as withAgentToolCall, k as recordPolicyDecision, v as createSignedEventEnvelope, w as delegateToAgent, x as sanitizeAuditPayload, y as verifyEventEnvelopeHash } from "./agent-DthMDQbW.js";
|
|
12
12
|
|
|
13
13
|
export { AGENT_AUDIT_SCHEMA_VERSION, AI_SDK_ATTR, CONTEXT_LIMITS, GEN_AI, GEN_AI_COST_ATTRIBUTE, GEN_AI_COST_USD_BUCKETS, GEN_AI_DURATION_BUCKETS_SECONDS, GEN_AI_EVENT, GEN_AI_EXT_EVENT, GEN_AI_GUARD_EVENT, GEN_AI_METRIC, GEN_AI_OPERATION, GEN_AI_OUTPUT_TYPE, GEN_AI_PROVIDER, GEN_AI_TOKEN_TYPE, GEN_AI_TOKEN_USAGE_BUCKETS, GEN_AI_TOOL_TYPE, MODEL_PRICING, SpanRegistry, canonicalizeForHash, chunkIntervalStats, computeStreamTiming, contextBudget, costCeiling, createAgentAuditMetadata, createAgentIdentityRegistry, createGenAiBudget, createGenAiGuard, createGenAiObserver, createLangChainObserver, createSignedEventEnvelope, createStreamTimer, defineAgentAction, defineAgentToolCall, delegateToAgent, errorLoop, estimateAiSdkCost, estimateLLMCost, extractAiSdkModel, extractAiSdkUsage, flattenAgentAttributes, genAiAgentAttributes, genAiMemoryAttributes, genAiMetricViews, genAiRequestAttributes, genAiResponseAttributes, genAiRetrievalAttributes, genAiSpanName, genAiToolAttributes, genAiUsageAttributes, genAiWorkflowAttributes, hashPayload, llmHistogramAdvice, mapAiSdkAttributes, maxDuration, maxSteps, maxToolCalls, normalizeAiSdkProvider, observeAiSdkResult, parseGuardRules, recordAgentHandoff, recordAiSdkCost, recordDecisionBasis, recordEvaluationResult, recordGenAiResponse, recordGenAiUsage, recordInferenceDetails, recordLLMCost, recordModelWarnings, recordOperationException, recordPolicyDecision, recordStreamTiming, resolvePrivacyProfile, sanitizeAuditPayload, setAgentAttributes, setGenAiContent, spinLoop, tokenCeiling, traceGenAI, traceLLM, verifyEventEnvelopeHash, withAgentAction, withAgentSession, withAgentToolCall, withScopedTool };
|
package/dist/observer/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as SpanRegistry, n as observeAiSdkResult, r as createGenAiObserver, t as createLangChainObserver } from "../observer-
|
|
1
|
+
import { i as SpanRegistry, n as observeAiSdkResult, r as createGenAiObserver, t as createLangChainObserver } from "../observer-2SKgcQI_.js";
|
|
2
2
|
|
|
3
3
|
export { SpanRegistry, createGenAiObserver, createLangChainObserver, observeAiSdkResult };
|
|
@@ -3,9 +3,75 @@ import { estimateLLMCost } from "./cost.js";
|
|
|
3
3
|
import { c as genAiWorkflowAttributes, i as genAiResponseAttributes, o as genAiToolAttributes, r as genAiRequestAttributes, s as genAiUsageAttributes, t as genAiAgentAttributes } from "./attributes-DU-PmLqZ.js";
|
|
4
4
|
import { setGenAiContent } from "./events.js";
|
|
5
5
|
import { normalizeAiSdkProvider } from "./ai-sdk-bridge.js";
|
|
6
|
-
import {
|
|
6
|
+
import { a as toAttributeValue, n as agentContextFromSpan, r as resolveContext } from "./context-B2wjX3O1.js";
|
|
7
|
+
import "autotel-audit";
|
|
7
8
|
import { SpanKind, SpanStatusCode, context, trace } from "@opentelemetry/api";
|
|
8
9
|
|
|
10
|
+
//#region src/agent/agent-security.ts
|
|
11
|
+
/** Canonical agent security attribute keys (Google SAIF / human-control aligned). */
|
|
12
|
+
const AGENT_SECURITY_ATTR = {
|
|
13
|
+
controllerId: "agent.controller.id",
|
|
14
|
+
inputProvenance: "agent.input.provenance",
|
|
15
|
+
actionRiskClass: "agent.action.risk_class",
|
|
16
|
+
consentRequired: "agent.consent.required",
|
|
17
|
+
consentOutcome: "agent.consent.outcome",
|
|
18
|
+
scopeActive: "agent.scope.active",
|
|
19
|
+
memoryOperation: "agent.memory.operation",
|
|
20
|
+
memoryIsolationKey: "agent.memory.isolation_key",
|
|
21
|
+
memoryContentHash: "agent.memory.content_hash",
|
|
22
|
+
planStepIndex: "agent.plan.step_index",
|
|
23
|
+
planToolIntents: "agent.plan.tool_intents",
|
|
24
|
+
planPolicyIds: "agent.plan.policy_ids",
|
|
25
|
+
outputFormat: "agent.output.format",
|
|
26
|
+
outputContainsUrl: "agent.output.contains_url",
|
|
27
|
+
outputUrlCount: "agent.output.url_count"
|
|
28
|
+
};
|
|
29
|
+
function setSecurityAttr(ctx, key, value) {
|
|
30
|
+
const attr = toAttributeValue(value);
|
|
31
|
+
if (attr === void 0) return;
|
|
32
|
+
const traceCtx = resolveContext(ctx);
|
|
33
|
+
if (Array.isArray(attr)) {
|
|
34
|
+
traceCtx.setAttributes({ [key]: attr });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
traceCtx.setAttribute(key, attr);
|
|
38
|
+
}
|
|
39
|
+
function setSecurityAttrs(ctx, attrs) {
|
|
40
|
+
const traceCtx = resolveContext(ctx);
|
|
41
|
+
const mapped = {};
|
|
42
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
43
|
+
const attr = toAttributeValue(value);
|
|
44
|
+
if (attr !== void 0) mapped[key] = attr;
|
|
45
|
+
}
|
|
46
|
+
if (Object.keys(mapped).length > 0) traceCtx.setAttributes(mapped);
|
|
47
|
+
}
|
|
48
|
+
function recordInputProvenance(input) {
|
|
49
|
+
setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.inputProvenance, input.provenance);
|
|
50
|
+
}
|
|
51
|
+
function recordMemoryAccess(input) {
|
|
52
|
+
setSecurityAttrs(input.ctx, {
|
|
53
|
+
[AGENT_SECURITY_ATTR.memoryOperation]: input.operation,
|
|
54
|
+
[AGENT_SECURITY_ATTR.memoryIsolationKey]: input.isolationKey,
|
|
55
|
+
...input.contentHash !== void 0 && { [AGENT_SECURITY_ATTR.memoryContentHash]: input.contentHash }
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function recordPlanStep(input) {
|
|
59
|
+
setSecurityAttrs(input.ctx, {
|
|
60
|
+
[AGENT_SECURITY_ATTR.planStepIndex]: input.stepIndex,
|
|
61
|
+
...input.toolIntents !== void 0 && { [AGENT_SECURITY_ATTR.planToolIntents]: input.toolIntents },
|
|
62
|
+
...input.policyIds !== void 0 && { [AGENT_SECURITY_ATTR.planPolicyIds]: input.policyIds },
|
|
63
|
+
...input.summary !== void 0 && { "decision.summary": input.summary }
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function recordRenderOutput(input) {
|
|
67
|
+
setSecurityAttrs(input.ctx, {
|
|
68
|
+
...input.format !== void 0 && { [AGENT_SECURITY_ATTR.outputFormat]: input.format },
|
|
69
|
+
...input.containsUrl !== void 0 && { [AGENT_SECURITY_ATTR.outputContainsUrl]: input.containsUrl },
|
|
70
|
+
...input.urlCount !== void 0 && { [AGENT_SECURITY_ATTR.outputUrlCount]: input.urlCount }
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
9
75
|
//#region src/observer/span-registry.ts
|
|
10
76
|
/**
|
|
11
77
|
* Tracks the spans currently open in a {@link createGenAiObserver} stream and
|
|
@@ -544,4 +610,4 @@ function num(value) {
|
|
|
544
610
|
|
|
545
611
|
//#endregion
|
|
546
612
|
export { SpanRegistry as i, observeAiSdkResult as n, createGenAiObserver as r, createLangChainObserver as t };
|
|
547
|
-
//# sourceMappingURL=observer-
|
|
613
|
+
//# sourceMappingURL=observer-2SKgcQI_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-2SKgcQI_.js","names":["otelTrace","otelContext"],"sources":["../src/agent/agent-security.ts","../src/observer/span-registry.ts","../src/observer/observer.ts","../src/observer/ai-sdk.ts","../src/observer/langchain.ts"],"sourcesContent":["import { hashIdentifier } from 'autotel-audit';\nimport { resolveContext, resolveContextSafe, toAttributeValue, type AgentContext } from './context.js';\n\n/** Canonical agent security attribute keys (Google SAIF / human-control aligned). */\nexport const AGENT_SECURITY_ATTR = {\n controllerId: 'agent.controller.id',\n inputProvenance: 'agent.input.provenance',\n actionRiskClass: 'agent.action.risk_class',\n consentRequired: 'agent.consent.required',\n consentOutcome: 'agent.consent.outcome',\n scopeActive: 'agent.scope.active',\n memoryOperation: 'agent.memory.operation',\n memoryIsolationKey: 'agent.memory.isolation_key',\n memoryContentHash: 'agent.memory.content_hash',\n planStepIndex: 'agent.plan.step_index',\n planToolIntents: 'agent.plan.tool_intents',\n planPolicyIds: 'agent.plan.policy_ids',\n outputFormat: 'agent.output.format',\n outputContainsUrl: 'agent.output.contains_url',\n outputUrlCount: 'agent.output.url_count',\n} as const;\n\nexport type AgentInputProvenance =\n | 'user_direct'\n | 'user_voice'\n | 'rag'\n | 'memory'\n | 'tool_result'\n | 'external_untrusted';\n\nexport type AgentActionRiskClass =\n | 'read'\n | 'write'\n | 'destructive'\n | 'financial'\n | 'exfiltration_capable';\n\nexport type AgentConsentOutcome = 'approved' | 'denied' | 'timeout' | 'revoked';\n\nexport type AgentMemoryOperation = 'read' | 'write' | 'delete' | 'search';\n\nexport type AgentOutputFormat = 'text' | 'markdown' | 'html' | 'json' | 'mixed';\n\nexport interface AgentSecurityRecordOptions {\n ctx?: AgentContext;\n}\n\nexport interface RecordControllerInput extends AgentSecurityRecordOptions {\n /** Controlling human user id — hashed before emission unless already a digest. */\n controllerId: string;\n /** Pass a stable per-deployment salt to `hashIdentifier`. */\n hashSalt?: string;\n /** When false, emit the id as given (must not be raw PII). Default true. */\n hash?: boolean;\n}\n\nexport interface RecordInputProvenanceInput extends AgentSecurityRecordOptions {\n provenance: AgentInputProvenance;\n}\n\nexport interface RecordHumanApprovalInput extends AgentSecurityRecordOptions {\n toolCallId: string;\n toolName?: string;\n approved: boolean;\n required?: boolean;\n controllerId?: string;\n hashSalt?: string;\n}\n\nexport interface RecordActiveScopesInput extends AgentSecurityRecordOptions {\n scopes: string[];\n}\n\nexport interface RecordMemoryAccessInput extends AgentSecurityRecordOptions {\n operation: AgentMemoryOperation;\n isolationKey: string;\n contentHash?: string;\n}\n\nexport interface RecordPlanStepInput extends AgentSecurityRecordOptions {\n stepIndex: number;\n toolIntents?: string[];\n policyIds?: string[];\n summary?: string;\n}\n\nexport interface RecordRenderOutputInput extends AgentSecurityRecordOptions {\n format?: AgentOutputFormat;\n containsUrl?: boolean;\n urlCount?: number;\n}\n\nexport interface ActionRiskHints {\n readOnlyHint?: boolean;\n destructiveHint?: boolean;\n openWorldHint?: boolean;\n untrustedContentHint?: boolean;\n financial?: boolean;\n exfiltrationCapable?: boolean;\n}\n\nfunction setSecurityAttr(\n ctx: AgentContext | undefined,\n key: string,\n value: unknown,\n): void {\n const attr = toAttributeValue(value);\n if (attr === undefined) return;\n const traceCtx = resolveContext(ctx);\n if (Array.isArray(attr)) {\n traceCtx.setAttributes({ [key]: attr });\n return;\n }\n traceCtx.setAttribute(key, attr);\n}\n\nfunction setSecurityAttrs(\n ctx: AgentContext | undefined,\n attrs: Record<string, unknown>,\n): void {\n const traceCtx = resolveContext(ctx);\n const mapped: Record<string, string | number | boolean | string[] | number[] | boolean[]> =\n {};\n for (const [key, value] of Object.entries(attrs)) {\n const attr = toAttributeValue(value);\n if (attr !== undefined) {\n mapped[key] = attr;\n }\n }\n if (Object.keys(mapped).length > 0) {\n traceCtx.setAttributes(mapped);\n }\n}\n\n/**\n * Derive a coarse action risk class from MCP tool hints or explicit overrides.\n */\nexport function deriveActionRiskClass(\n hints: ActionRiskHints,\n override?: AgentActionRiskClass,\n): AgentActionRiskClass {\n if (override) return override;\n if (hints.financial) return 'financial';\n if (hints.exfiltrationCapable || hints.openWorldHint) {\n return 'exfiltration_capable';\n }\n if (hints.destructiveHint) return 'destructive';\n if (hints.readOnlyHint) return 'read';\n if (hints.untrustedContentHint) return 'read';\n return 'write';\n}\n\nexport function recordControllerId(input: RecordControllerInput): void {\n const id =\n input.hash === false\n ? input.controllerId\n : hashIdentifier(input.controllerId, { salt: input.hashSalt });\n setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.controllerId, id);\n}\n\nexport function recordInputProvenance(input: RecordInputProvenanceInput): void {\n setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.inputProvenance, input.provenance);\n}\n\nexport function recordHumanApproval(input: RecordHumanApprovalInput): void {\n const attrs: Record<string, unknown> = {\n [AGENT_SECURITY_ATTR.consentRequired]: input.required ?? true,\n [AGENT_SECURITY_ATTR.consentOutcome]: input.approved ? 'approved' : 'denied',\n 'tool.call.id': input.toolCallId,\n };\n if (input.toolName) {\n attrs['tool.name'] = input.toolName;\n }\n if (input.controllerId) {\n attrs[AGENT_SECURITY_ATTR.controllerId] = hashIdentifier(input.controllerId, {\n salt: input.hashSalt,\n });\n }\n setSecurityAttrs(input.ctx, attrs);\n}\n\nexport function recordActiveScopes(input: RecordActiveScopesInput): void {\n setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.scopeActive, input.scopes);\n}\n\nexport function recordActionRiskClass(\n riskClass: AgentActionRiskClass,\n options: AgentSecurityRecordOptions = {},\n): void {\n setSecurityAttr(options.ctx, AGENT_SECURITY_ATTR.actionRiskClass, riskClass);\n}\n\nexport function recordMemoryAccess(input: RecordMemoryAccessInput): void {\n setSecurityAttrs(input.ctx, {\n [AGENT_SECURITY_ATTR.memoryOperation]: input.operation,\n [AGENT_SECURITY_ATTR.memoryIsolationKey]: input.isolationKey,\n ...(input.contentHash !== undefined && {\n [AGENT_SECURITY_ATTR.memoryContentHash]: input.contentHash,\n }),\n });\n}\n\nexport function recordPlanStep(input: RecordPlanStepInput): void {\n setSecurityAttrs(input.ctx, {\n [AGENT_SECURITY_ATTR.planStepIndex]: input.stepIndex,\n ...(input.toolIntents !== undefined && {\n [AGENT_SECURITY_ATTR.planToolIntents]: input.toolIntents,\n }),\n ...(input.policyIds !== undefined && {\n [AGENT_SECURITY_ATTR.planPolicyIds]: input.policyIds,\n }),\n ...(input.summary !== undefined && { 'decision.summary': input.summary }),\n });\n}\n\nexport function recordRenderOutput(input: RecordRenderOutputInput): void {\n setSecurityAttrs(input.ctx, {\n ...(input.format !== undefined && {\n [AGENT_SECURITY_ATTR.outputFormat]: input.format,\n }),\n ...(input.containsUrl !== undefined && {\n [AGENT_SECURITY_ATTR.outputContainsUrl]: input.containsUrl,\n }),\n ...(input.urlCount !== undefined && {\n [AGENT_SECURITY_ATTR.outputUrlCount]: input.urlCount,\n }),\n });\n}\n\n/** Best-effort variant — no throw when trace context is missing. */\nexport function tryRecordHumanApproval(input: RecordHumanApprovalInput): boolean {\n const ctx = resolveContextSafe(input.ctx);\n if (!ctx) return false;\n recordHumanApproval({ ...input, ctx });\n return true;\n}\n","/**\n * Tracks the spans currently open in a {@link createGenAiObserver} stream and\n * the parent each was started under, so the observer can:\n *\n * - look up a parent span when a child starts, and\n * - force-close any descendant whose terminal event never arrived because its\n * parent ended first (an aborted tool call, a cancelled turn, a run that was\n * interrupted). Without this, abandoned spans leak open forever.\n */\n\nimport { SpanStatusCode, type Span, type TimeInput } from '@opentelemetry/api';\n\ninterface Entry {\n span: Span;\n parentId: string | undefined;\n}\n\nexport class SpanRegistry {\n private readonly entries = new Map<string, Entry>();\n\n /** Record an open span and the parent it was started under. */\n add(id: string, span: Span, parentId: string | undefined): void {\n this.entries.set(id, { span, parentId });\n }\n\n /** The open span for `id`, if any (used to parent a starting child). */\n spanFor(id: string): Span | undefined {\n return this.entries.get(id)?.span;\n }\n\n /** Remove and return the open span for `id`. */\n take(id: string): Span | undefined {\n const entry = this.entries.get(id);\n if (!entry) return undefined;\n this.entries.delete(id);\n return entry.span;\n }\n\n /**\n * Close every still-open descendant of `parentId` as ERROR — their terminal\n * event never arrived because the parent ended first. Depth-first, so the\n * deepest leaks close before their own parents.\n */\n reapDescendants(\n parentId: string,\n message: string,\n endTime?: TimeInput,\n ): void {\n // Deleting from a Map during its own for…of is well-defined; recursion only\n // removes deeper descendants (parentId === id), never an unvisited sibling.\n for (const [id, entry] of this.entries) {\n if (entry.parentId !== parentId) continue;\n this.entries.delete(id);\n this.reapDescendants(id, message, endTime);\n entry.span.setStatus({ code: SpanStatusCode.ERROR, message });\n entry.span.end(endTime);\n }\n }\n\n /** Count of spans still open — for tests and leak assertions. */\n get openCount(): number {\n return this.entries.size;\n }\n}\n","/**\n * `createGenAiObserver` — turn a stream of GenAI lifecycle events into a\n * canonical `gen_ai.*` span tree.\n *\n * A complement to {@link traceGenAI}: where the wrapper instruments code you\n * own, the observer instruments a framework that emits its own event stream.\n * Subscribe it once and feed every event through it; it reconstructs the span\n * hierarchy, estimates cost, force-closes abandoned children, and keeps\n * sensitive content off spans unless you opt in.\n *\n * Scope: this adapter records span attributes only. It deliberately does not\n * emit the `gen_ai.*` log events (`inference.operation.details`,\n * `operation.exception`) that `recordInferenceDetails` provides — the source\n * event stream already carries that detail.\n *\n * @example\n * ```ts\n * const observe = createGenAiObserver();\n * observe({ type: 'agent.start', id: 'a1', agent: { name: 'planner' } });\n * observe({ type: 'chat.start', id: 'c1', parentId: 'a1',\n * request: { provider: 'openai', model: 'gpt-4o' } });\n * observe({ type: 'chat.end', id: 'c1',\n * usage: { inputTokens: 412, outputTokens: 87 } });\n * observe({ type: 'agent.end', id: 'a1' });\n * ```\n */\n\nimport {\n context as otelContext,\n SpanKind,\n SpanStatusCode,\n trace as otelTrace,\n type Context,\n type Span,\n type SpanOptions,\n} from '@opentelemetry/api';\nimport {\n genAiAgentAttributes,\n genAiRequestAttributes,\n genAiResponseAttributes,\n genAiToolAttributes,\n genAiUsageAttributes,\n genAiWorkflowAttributes,\n type GenAiAttributeMap,\n} from '../attributes.js';\nimport { estimateLLMCost } from '../cost.js';\nimport { setGenAiContent, type GenAiContentSink } from '../events.js';\nimport { GEN_AI, GEN_AI_OPERATION, genAiSpanName } from '../semconv.js';\nimport {\n recordInputProvenance,\n recordMemoryAccess,\n recordPlanStep,\n recordRenderOutput,\n} from '../agent/agent-security.js';\nimport { agentContextFromSpan } from '../agent/context.js';\nimport { SpanRegistry } from './span-registry.js';\nimport type {\n ChatEndEvent,\n ChatStartEvent,\n GenAiObserver,\n GenAiObserverEvent,\n GenAiObserverOptions,\n SpanEnd,\n InputProvenanceEvent,\n MemoryAccessEvent,\n PlanStepEvent,\n RenderOutputEvent,\n ToolEndEvent,\n ToolStartEvent,\n} from './types.js';\n\nconst ORPHAN_MESSAGE =\n 'Parent ended before this span received its terminal event.';\n\n/** The `*.start` half of the event union — the events that open a span. */\ntype StartEvent = Extract<GenAiObserverEvent, { type: `${string}.start` }>;\n\nexport function createGenAiObserver(\n options: GenAiObserverOptions = {},\n): GenAiObserver {\n const tracer =\n options.tracer ?? otelTrace.getTracer('autotel-genai/observer');\n const registry = new SpanRegistry();\n\n /** Parent context: a tracked parent span, else the resolver, else root. */\n function parentContext(event: StartEvent): Context | undefined {\n const parentSpan = event.parentId\n ? registry.spanFor(event.parentId)\n : undefined;\n if (parentSpan) return otelTrace.setSpan(otelContext.active(), parentSpan);\n return options.resolveParentContext?.(event);\n }\n\n /** Start a span, register it under its parent, and return it. */\n function start(\n event: StartEvent,\n name: string,\n kind: SpanKind,\n attributes: GenAiAttributeMap,\n ): Span {\n const parent = parentContext(event);\n const spanOptions: SpanOptions = {\n kind,\n attributes,\n startTime: event.startTime,\n links: event.links,\n root: parent === undefined,\n };\n const span = tracer.startSpan(name, spanOptions, parent);\n registry.add(event.id, span, event.parentId);\n return span;\n }\n\n /**\n * Close the span for `event.id`: first force-close any descendant whose\n * terminal event never arrived, then decorate, set status, and end.\n */\n function end(event: SpanEnd, decorate?: (span: Span) => void): void {\n const span = registry.take(event.id);\n if (!span) return;\n registry.reapDescendants(event.id, ORPHAN_MESSAGE, event.endTime);\n decorate?.(span);\n if (event.error !== undefined) {\n const message = errorMessage(event.error);\n span.setStatus({ code: SpanStatusCode.ERROR, message });\n // The SDK normalizes a string or Error; hand it the original Error when\n // we have one, otherwise the message we already derived.\n span.recordException(\n event.error instanceof Error ? event.error : (message ?? 'error'),\n );\n }\n span.end(event.endTime);\n }\n\n /** Run the privacy gate; without it, content is always omitted. */\n function approvedContent(\n event: GenAiObserverEvent,\n ): GenAiObserverEvent | undefined {\n if (!options.exportContent) return undefined;\n try {\n return options.exportContent({ ...event });\n } catch (error) {\n console.error('[autotel-genai:observer] exportContent failed:', error);\n return undefined;\n }\n }\n\n function applyChatStart(span: Span, event: ChatStartEvent): void {\n const content = approvedContent(event);\n if (content?.type !== 'chat.start') return;\n setGenAiContent(spanSink(span), {\n inputMessages: content.inputMessages,\n systemInstructions: content.systemInstructions,\n });\n }\n\n function applyChatEnd(span: Span, event: ChatEndEvent): void {\n if (event.response) {\n span.setAttributes(genAiResponseAttributes(event.response));\n }\n if (event.usage) {\n const costModel = event.costModel ?? event.response?.model;\n const costUsd = costModel\n ? estimateLLMCost(costModel, event.usage)\n : undefined;\n span.setAttributes(genAiUsageAttributes({ ...event.usage, costUsd }));\n }\n const content = approvedContent(event);\n if (content?.type === 'chat.end') {\n setGenAiContent(spanSink(span), {\n outputMessages: content.outputMessages,\n });\n }\n }\n\n function applyToolStart(span: Span, event: ToolStartEvent): void {\n const content = approvedContent(event);\n if (content?.type !== 'tool.start') return;\n span.setAttributes(\n genAiToolAttributes({ callArguments: content.callArguments }),\n );\n }\n\n function applyToolEnd(span: Span, event: ToolEndEvent): void {\n const content = approvedContent(event);\n if (content?.type !== 'tool.end') return;\n span.setAttributes(genAiToolAttributes({ callResult: content.callResult }));\n }\n\n function stampOnParent(\n parentId: string,\n apply: (ctx: ReturnType<typeof agentContextFromSpan>) => void,\n ): void {\n const parent = registry.spanFor(parentId);\n if (!parent) return;\n apply(agentContextFromSpan(parent));\n }\n\n return (event: GenAiObserverEvent): void => {\n switch (event.type) {\n case 'workflow.start': {\n start(\n event,\n genAiSpanName(\n GEN_AI_OPERATION.INVOKE_WORKFLOW,\n event.workflow.workflowName,\n ),\n SpanKind.INTERNAL,\n {\n [GEN_AI.OPERATION_NAME]: GEN_AI_OPERATION.INVOKE_WORKFLOW,\n ...genAiWorkflowAttributes(event.workflow),\n },\n );\n return;\n }\n case 'agent.start': {\n const internal = !event.remote;\n start(\n event,\n genAiSpanName(GEN_AI_OPERATION.INVOKE_AGENT, event.agent.name),\n internal ? SpanKind.INTERNAL : SpanKind.CLIENT,\n {\n [GEN_AI.OPERATION_NAME]: GEN_AI_OPERATION.INVOKE_AGENT,\n ...(event.provider\n ? { [GEN_AI.PROVIDER_NAME]: event.provider }\n : {}),\n ...genAiAgentAttributes(event.agent, { internal }),\n },\n );\n return;\n }\n case 'chat.start': {\n const operation = event.request.operation ?? GEN_AI_OPERATION.CHAT;\n const span = start(\n event,\n genAiSpanName(operation, event.request.model),\n SpanKind.CLIENT,\n genAiRequestAttributes({ ...event.request, operation }),\n );\n applyChatStart(span, event);\n return;\n }\n case 'tool.start': {\n const span = start(\n event,\n genAiSpanName(GEN_AI_OPERATION.EXECUTE_TOOL, event.tool.name),\n SpanKind.INTERNAL,\n {\n [GEN_AI.OPERATION_NAME]: GEN_AI_OPERATION.EXECUTE_TOOL,\n ...genAiToolAttributes(event.tool),\n },\n );\n applyToolStart(span, event);\n return;\n }\n case 'workflow.end':\n case 'agent.end': {\n end(event);\n return;\n }\n case 'chat.end': {\n end(event, (span) => applyChatEnd(span, event));\n return;\n }\n case 'tool.end': {\n end(event, (span) => applyToolEnd(span, event));\n return;\n }\n case 'plan.step': {\n stampOnParent(event.parentId, (ctx) =>\n recordPlanStep({\n ctx,\n stepIndex: event.stepIndex,\n toolIntents: event.toolIntents,\n policyIds: event.policyIds,\n summary: event.summary,\n }),\n );\n return;\n }\n case 'input.provenance': {\n stampOnParent(event.parentId, (ctx) =>\n recordInputProvenance({ ctx, provenance: event.provenance }),\n );\n return;\n }\n case 'memory.access': {\n stampOnParent(event.parentId, (ctx) =>\n recordMemoryAccess({\n ctx,\n operation: event.operation,\n isolationKey: event.isolationKey,\n contentHash: event.contentHash,\n }),\n );\n return;\n }\n case 'render.output': {\n stampOnParent(event.parentId, (ctx) =>\n recordRenderOutput({\n ctx,\n format: event.format,\n containsUrl: event.containsUrl,\n urlCount: event.urlCount,\n }),\n );\n return;\n }\n default: {\n const unexpected: never = event;\n void unexpected;\n }\n }\n };\n}\n\n/** A {@link GenAiContentSink} backed by a raw span (only `setAttributes` is used). */\nfunction spanSink(span: Span): GenAiContentSink {\n return {\n setAttributes: (attrs) => {\n span.setAttributes(attrs);\n },\n track: () => {},\n };\n}\n\nfunction errorMessage(error: unknown): string | undefined {\n if (error === undefined) return undefined;\n if (typeof error === 'string') return error || undefined;\n if (error instanceof Error) return error.message;\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n}\n","/**\n * Vercel AI SDK → {@link createGenAiObserver} glue.\n *\n * The AI SDK has no global event stream; its stable surface is the result of a\n * `generateText`/`streamText` call (`steps`, each with `usage`, `toolCalls`,\n * `toolResults`, `response`). {@link observeAiSdkResult} walks that result and\n * emits observer events:\n *\n * - a trivial single-step call with no tools → one `chat` span;\n * - a multi-step or tool-using call → an `invoke_agent` wrapper (mirroring the\n * AI SDK's own `invoke_agent › chat › execute_tool` hierarchy) with a `chat`\n * per step and an `execute_tool` per tool call.\n *\n * Typed structurally against the AI SDK result shape so it pulls in no\n * dependency and tolerates v4/v5 field differences (`promptTokens` vs\n * `inputTokens`). Cost is left to the observer, which prices `chat` usage.\n *\n * @example\n * ```ts\n * const observe = createGenAiObserver();\n * const result = await generateText({ model: openai('gpt-4o'), prompt });\n * observeAiSdkResult(observe, result, { id: 'gen-1', provider: 'openai', model: 'gpt-4o' });\n * ```\n */\n\nimport type { TimeInput } from '@opentelemetry/api';\nimport { normalizeAiSdkProvider } from '../ai-sdk-bridge.js';\nimport type { TokenUsage } from '../cost.js';\nimport type { GenAiProviderName } from '../semconv.js';\nimport type { GenAiObserver } from './types.js';\n\n/** AI SDK usage object — canonical (v5) or legacy (v4) field names. */\nexport interface AiSdkUsage {\n inputTokens?: number;\n outputTokens?: number;\n promptTokens?: number;\n completionTokens?: number;\n reasoningTokens?: number;\n cachedInputTokens?: number;\n}\n\nexport interface AiSdkToolCall {\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n args?: unknown;\n}\n\nexport interface AiSdkToolResult {\n toolCallId?: string;\n toolName?: string;\n output?: unknown;\n result?: unknown;\n}\n\n/** One AI SDK step (also the shape of a single-call result). */\nexport interface AiSdkStep {\n usage?: AiSdkUsage;\n finishReason?: string;\n response?: { id?: string; modelId?: string; timestamp?: Date | number };\n toolCalls?: AiSdkToolCall[];\n toolResults?: AiSdkToolResult[];\n}\n\n/** An AI SDK `generateText`/`streamText` result. */\nexport interface AiSdkResult extends AiSdkStep {\n steps?: AiSdkStep[];\n}\n\nexport interface ObserveAiSdkOptions {\n /** Base span id; per-step and per-tool ids derive from it. */\n id: string;\n parentId?: string;\n /** AI SDK provider id (e.g. `openai`, `amazon-bedrock`); normalized for you. */\n provider?: string;\n /** Request model — used for the span name and as the cost model. */\n model?: string;\n}\n\nconst AI_SDK_AGENT_NAME = 'ai-sdk';\n\nexport function observeAiSdkResult(\n observe: GenAiObserver,\n result: AiSdkResult,\n options: ObserveAiSdkOptions,\n): void {\n const provider: GenAiProviderName | undefined = options.provider\n ? normalizeAiSdkProvider(options.provider)\n : undefined;\n const steps = result.steps ?? [result];\n const toolCount = steps.reduce(\n (total, step) => total + (step.toolCalls?.length ?? 0),\n 0,\n );\n\n if (steps.length <= 1 && toolCount === 0) {\n emitChat(observe, steps[0] ?? result, {\n id: options.id,\n parentId: options.parentId,\n provider,\n model: options.model,\n });\n return;\n }\n\n observe({\n type: 'agent.start',\n id: options.id,\n parentId: options.parentId,\n provider,\n agent: { name: options.model ?? AI_SDK_AGENT_NAME },\n });\n steps.forEach((step, index) => {\n emitChat(observe, step, {\n id: `${options.id}:step:${index}`,\n parentId: options.id,\n provider,\n model: options.model,\n });\n emitTools(observe, step, options.id, index);\n });\n observe({ type: 'agent.end', id: options.id });\n}\n\ninterface ChatContext {\n id: string;\n parentId?: string;\n provider?: GenAiProviderName;\n model?: string;\n}\n\nfunction emitChat(\n observe: GenAiObserver,\n step: AiSdkStep,\n ctx: ChatContext,\n): void {\n observe({\n type: 'chat.start',\n id: ctx.id,\n parentId: ctx.parentId,\n request: { provider: ctx.provider, model: ctx.model },\n });\n const responseModel = step.response?.modelId;\n observe({\n type: 'chat.end',\n id: ctx.id,\n response: {\n model: responseModel,\n id: step.response?.id,\n finishReasons: step.finishReason ? [step.finishReason] : undefined,\n },\n usage: aiSdkUsage(step.usage),\n costModel: ctx.model ?? responseModel,\n endTime: asTimeInput(step.response?.timestamp),\n });\n}\n\nfunction emitTools(\n observe: GenAiObserver,\n step: AiSdkStep,\n parentId: string,\n stepIndex: number,\n): void {\n const results = step.toolResults ?? [];\n (step.toolCalls ?? []).forEach((call, callIndex) => {\n const id = `${parentId}:tool:${call.toolCallId ?? `${stepIndex}.${callIndex}`}`;\n observe({\n type: 'tool.start',\n id,\n parentId,\n tool: { name: call.toolName, callId: call.toolCallId },\n callArguments: call.input ?? call.args,\n });\n const result = call.toolCallId\n ? results.find((r) => r.toolCallId === call.toolCallId)\n : results[callIndex];\n observe({\n type: 'tool.end',\n id,\n callResult: result?.output ?? result?.result,\n });\n });\n}\n\nfunction aiSdkUsage(usage?: AiSdkUsage): TokenUsage | undefined {\n if (!usage) return undefined;\n const tokenUsage: TokenUsage = {\n inputTokens: usage.inputTokens ?? usage.promptTokens,\n outputTokens: usage.outputTokens ?? usage.completionTokens,\n reasoningOutputTokens: usage.reasoningTokens,\n cacheReadInputTokens: usage.cachedInputTokens,\n };\n return Object.values(tokenUsage).some((v) => v !== undefined)\n ? tokenUsage\n : undefined;\n}\n\nfunction asTimeInput(value: Date | number | undefined): TimeInput | undefined {\n return value instanceof Date || typeof value === 'number' ? value : undefined;\n}\n","/**\n * LangChain / LangGraph → {@link createGenAiObserver} glue.\n *\n * LangChain's callback system is a real event stream: register one handler and\n * it receives every run's start/end/error with a `runId` and `parentRunId` —\n * which map directly onto the observer's `id` / `parentId`. {@link\n * createLangChainObserver} returns a handler object you pass to `callbacks`:\n *\n * - chain runs (LangGraph nodes, agents) → `invoke_agent` spans;\n * - LLM / chat-model runs → `chat` spans (with usage and estimated cost);\n * - tool runs → `execute_tool` spans.\n *\n * Typed structurally against the callback payloads so it pulls in no LangChain\n * dependency. Pass it via `{ callbacks: [createLangChainObserver(observe)] }`.\n *\n * @example\n * ```ts\n * const observe = createGenAiObserver();\n * await graph.invoke(input, { callbacks: [createLangChainObserver(observe)] });\n * ```\n */\n\nimport { normalizeAiSdkProvider } from '../ai-sdk-bridge.js';\nimport type { TokenUsage } from '../cost.js';\nimport type { GenAiObserver } from './types.js';\n\n/** LangChain `Serialized` — the identity of a chain/LLM/tool. */\ninterface Serialized {\n id?: string[];\n name?: string;\n kwargs?: Record<string, unknown>;\n}\n\ninterface LLMGeneration {\n generationInfo?: Record<string, unknown>;\n message?: {\n usage_metadata?: Record<string, unknown>;\n response_metadata?: Record<string, unknown>;\n };\n}\n\n/** LangChain `LLMResult` — what an LLM/chat-model run returns. */\ninterface LLMResult {\n generations?: LLMGeneration[][];\n llmOutput?: Record<string, unknown>;\n}\n\n/** The subset of LangChain's `CallbackHandlerMethods` this adapter implements. */\nexport interface LangChainObserverHandler {\n handleChainStart(\n chain: Serialized,\n inputs: unknown,\n runId: string,\n parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n runType?: string,\n runName?: string,\n ): void;\n handleChainEnd(outputs: unknown, runId: string): void;\n handleChainError(error: unknown, runId: string): void;\n handleLLMStart(\n llm: Serialized,\n prompts: string[],\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, unknown>,\n ): void;\n handleChatModelStart(\n llm: Serialized,\n messages: unknown,\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, unknown>,\n ): void;\n handleLLMEnd(output: LLMResult, runId: string): void;\n handleLLMError(error: unknown, runId: string): void;\n handleToolStart(\n tool: Serialized,\n input: string,\n runId: string,\n parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n runName?: string,\n ): void;\n handleToolEnd(output: unknown, runId: string): void;\n handleToolError(error: unknown, runId: string): void;\n}\n\nexport interface LangChainObserverOptions {\n /**\n * Decide whether a chain run becomes an `invoke_agent` span. The default\n * skips LangChain/LangGraph plumbing (Runnable*, ChannelWrite, Branch,\n * prompts, `__start__`/`__end__`) so only the graph and its named nodes show;\n * children of a skipped chain reparent to the nearest kept ancestor.\n */\n skipChain?: (name: string) => boolean;\n}\n\n/** LangChain/LangGraph structural runnables that are noise, not real steps. */\nconst PLUMBING_CHAIN = /^(Runnable|Channel|Branch|Prompt|ChatPrompt|__)/i;\n\nexport function createLangChainObserver(\n observe: GenAiObserver,\n options: LangChainObserverOptions = {},\n): LangChainObserverHandler {\n const skipChain = options.skipChain ?? ((name) => PLUMBING_CHAIN.test(name));\n // Remember each LLM run's request model so `chat.end` can price it — the end\n // payload doesn't reliably carry the model. Cleared on end and error.\n const models = new Map<string, string>();\n // Skipped chains record the kept ancestor their children should parent to.\n const reparented = new Map<string, string | undefined>();\n\n /** The span id a child of `runId` should use as its parent. */\n function keptParent(runId: string | undefined): string | undefined {\n if (runId === undefined) return undefined;\n return reparented.has(runId) ? reparented.get(runId) : runId;\n }\n\n function startChat(\n llm: Serialized,\n runId: string,\n parentRunId: string | undefined,\n extraParams: Record<string, unknown> | undefined,\n ): void {\n const model = langChainModel(llm, extraParams);\n if (model) models.set(runId, model);\n observe({\n type: 'chat.start',\n id: runId,\n parentId: keptParent(parentRunId),\n request: { provider: langChainProvider(llm), model },\n });\n }\n\n return {\n handleChainStart(\n chain,\n _inputs,\n runId,\n parentRunId,\n _tags,\n _metadata,\n _runType,\n runName,\n ) {\n const name = runName ?? lastIdSegment(chain) ?? 'chain';\n const parentId = keptParent(parentRunId);\n if (skipChain(name)) {\n reparented.set(runId, parentId);\n return;\n }\n observe({ type: 'agent.start', id: runId, parentId, agent: { name } });\n },\n handleChainEnd(_outputs, runId) {\n if (reparented.delete(runId)) return;\n observe({ type: 'agent.end', id: runId });\n },\n handleChainError(error, runId) {\n if (reparented.delete(runId)) return;\n observe({ type: 'agent.end', id: runId, error });\n },\n\n handleLLMStart(llm, _prompts, runId, parentRunId, extraParams) {\n startChat(llm, runId, parentRunId, extraParams);\n },\n handleChatModelStart(llm, _messages, runId, parentRunId, extraParams) {\n startChat(llm, runId, parentRunId, extraParams);\n },\n handleLLMEnd(output, runId) {\n const costModel = models.get(runId);\n models.delete(runId);\n observe({\n type: 'chat.end',\n id: runId,\n response: { finishReasons: finishReasons(output) },\n usage: langChainUsage(output),\n costModel,\n });\n },\n handleLLMError(error, runId) {\n models.delete(runId);\n observe({ type: 'chat.end', id: runId, error });\n },\n\n handleToolStart(\n tool,\n input,\n runId,\n parentRunId,\n _tags,\n _metadata,\n runName,\n ) {\n observe({\n type: 'tool.start',\n id: runId,\n parentId: keptParent(parentRunId),\n tool: { name: runName ?? lastIdSegment(tool) },\n callArguments: input,\n });\n },\n handleToolEnd(output, runId) {\n observe({ type: 'tool.end', id: runId, callResult: output });\n },\n handleToolError(error, runId) {\n observe({ type: 'tool.end', id: runId, error });\n },\n };\n}\n\n/**\n * Provider from a `Serialized.id` path. LangChain serializes a chat model as\n * `[...namespace, provider, ClassName]` (e.g. `…, 'openai', 'ChatOpenAI'`), so\n * the provider is the lowercase module segment before the PascalCase class.\n */\nfunction langChainProvider(serialized: Serialized): string | undefined {\n const candidate = serialized.id?.at(-2);\n return candidate && candidate === candidate.toLowerCase()\n ? normalizeAiSdkProvider(candidate)\n : undefined;\n}\n\nfunction langChainModel(\n serialized: Serialized,\n extraParams: Record<string, unknown> | undefined,\n): string | undefined {\n const invocation = asRecord(extraParams?.invocation_params);\n return (\n str(invocation?.model) ??\n str(invocation?.model_name) ??\n str(serialized.kwargs?.model) ??\n str(serialized.kwargs?.model_name)\n );\n}\n\nfunction langChainUsage(output: LLMResult): TokenUsage | undefined {\n // `usage_metadata` is LangChain's canonical cross-provider shape (Ollama,\n // newer integrations); `llmOutput.tokenUsage` is OpenAI; `llmOutput.usage`\n // is Anthropic-style.\n const usageMetadata = asRecord(\n firstGeneration(output)?.message?.usage_metadata,\n );\n const tokenUsage = asRecord(output.llmOutput?.tokenUsage);\n const usage = asRecord(output.llmOutput?.usage);\n const inputTokens =\n num(usageMetadata?.input_tokens) ??\n num(tokenUsage?.promptTokens) ??\n num(usage?.input_tokens);\n const outputTokens =\n num(usageMetadata?.output_tokens) ??\n num(tokenUsage?.completionTokens) ??\n num(usage?.output_tokens);\n if (inputTokens === undefined && outputTokens === undefined) return undefined;\n return { inputTokens, outputTokens };\n}\n\nfunction finishReasons(output: LLMResult): string[] | undefined {\n const generation = firstGeneration(output);\n const reason =\n str(generation?.generationInfo?.finish_reason) ??\n str(asRecord(generation?.message?.response_metadata)?.done_reason);\n return reason ? [reason] : undefined;\n}\n\nfunction firstGeneration(output: LLMResult): LLMGeneration | undefined {\n return output.generations?.[0]?.[0];\n}\n\nfunction lastIdSegment(serialized: Serialized): string | undefined {\n return serialized.name ?? serialized.id?.at(-1);\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction num(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value)\n ? value\n : undefined;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-genai",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Gold-standard OpenTelemetry GenAI semantic-convention instrumentation for LLM calls, tools, and agents — cost, tokens, metrics, events, and agent governance.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -84,8 +84,8 @@
|
|
|
84
84
|
"author": "Jag Reehal <jag@jagreehal.com> (https://jagreehal.com)",
|
|
85
85
|
"license": "MIT",
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"autotel": "4.2.
|
|
88
|
-
"autotel-audit": "0.4.
|
|
87
|
+
"autotel": "4.2.1",
|
|
88
|
+
"autotel-audit": "0.4.1"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
91
|
"@opentelemetry/api": "*",
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { getTraceContext, otelTrace } from "autotel";
|
|
2
|
-
import { hashIdentifier } from "autotel-audit";
|
|
3
|
-
|
|
4
|
-
//#region src/agent/context.ts
|
|
5
|
-
const MISSING_CONTEXT_MESSAGE = "[autotel-genai] No active trace context. Wrap the call in trace()/instrument(), pass options.ctx, or set options.onMissingContext to \"warn\"/\"skip\" to degrade gracefully instead of throwing.";
|
|
6
|
-
/**
|
|
7
|
-
* Resolve an agent context without throwing. Returns `null` when no trace context
|
|
8
|
-
* is available, so callers can degrade gracefully (best-effort instrumentation).
|
|
9
|
-
*/
|
|
10
|
-
const INVALID_TRACE_ID = "00000000000000000000000000000000";
|
|
11
|
-
function resolveContextSafe(ctx) {
|
|
12
|
-
if (ctx) return ctx;
|
|
13
|
-
const span = otelTrace.getActiveSpan();
|
|
14
|
-
if (!span) return null;
|
|
15
|
-
const ids = getTraceContext();
|
|
16
|
-
const sc = span.spanContext();
|
|
17
|
-
const traceId = ids?.traceId ?? sc.traceId;
|
|
18
|
-
if (!traceId || traceId === INVALID_TRACE_ID) return null;
|
|
19
|
-
return {
|
|
20
|
-
traceId,
|
|
21
|
-
spanId: ids?.spanId ?? sc.spanId,
|
|
22
|
-
correlationId: ids?.correlationId ?? traceId.slice(0, 16),
|
|
23
|
-
setAttribute: (key, value) => span.setAttribute(key, value),
|
|
24
|
-
setAttributes: (attrs) => span.setAttributes(attrs)
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function resolveContext(ctx) {
|
|
28
|
-
const resolved = resolveContextSafe(ctx);
|
|
29
|
-
if (resolved) return resolved;
|
|
30
|
-
throw new Error(MISSING_CONTEXT_MESSAGE);
|
|
31
|
-
}
|
|
32
|
-
const warnedMissingContext = /* @__PURE__ */ new Set();
|
|
33
|
-
/** Warn (once per action) that an agent action is running without a trace context. */
|
|
34
|
-
function warnMissingContextOnce(action) {
|
|
35
|
-
if (warnedMissingContext.has(action)) return;
|
|
36
|
-
warnedMissingContext.add(action);
|
|
37
|
-
console.warn(`[autotel-genai] No active trace context for "${action}" — running un-audited. Wrap the call in trace()/instrument() or pass options.ctx to capture agent audit telemetry. (set options.onMissingContext: "throw" to fail fast, or "skip" to silence this warning)`);
|
|
38
|
-
}
|
|
39
|
-
/** Adapt an OpenTelemetry span (or span-like object) to {@link AgentContext}. */
|
|
40
|
-
function agentContextFromSpan(span) {
|
|
41
|
-
const sc = span.spanContext();
|
|
42
|
-
return {
|
|
43
|
-
traceId: sc.traceId,
|
|
44
|
-
spanId: sc.spanId,
|
|
45
|
-
correlationId: sc.traceId.slice(0, 16),
|
|
46
|
-
setAttribute: (key, value) => span.setAttribute(key, value),
|
|
47
|
-
setAttributes: (attrs) => span.setAttributes(attrs)
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function toAttributeValue(value) {
|
|
51
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
52
|
-
if (Array.isArray(value)) {
|
|
53
|
-
if (value.every((entry) => typeof entry === "string")) return value;
|
|
54
|
-
if (value.every((entry) => typeof entry === "number")) return value;
|
|
55
|
-
if (value.every((entry) => typeof entry === "boolean")) return value;
|
|
56
|
-
try {
|
|
57
|
-
return JSON.stringify(value);
|
|
58
|
-
} catch {
|
|
59
|
-
return "<serialization-failed>";
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (value instanceof Date) return value.toISOString();
|
|
63
|
-
if (typeof value === "bigint") return value.toString(10);
|
|
64
|
-
if (value === null || value === void 0) return;
|
|
65
|
-
try {
|
|
66
|
-
return JSON.stringify(value);
|
|
67
|
-
} catch {
|
|
68
|
-
return "<serialization-failed>";
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
//#endregion
|
|
73
|
-
//#region src/agent/agent-security.ts
|
|
74
|
-
/** Canonical agent security attribute keys (Google SAIF / human-control aligned). */
|
|
75
|
-
const AGENT_SECURITY_ATTR = {
|
|
76
|
-
controllerId: "agent.controller.id",
|
|
77
|
-
inputProvenance: "agent.input.provenance",
|
|
78
|
-
actionRiskClass: "agent.action.risk_class",
|
|
79
|
-
consentRequired: "agent.consent.required",
|
|
80
|
-
consentOutcome: "agent.consent.outcome",
|
|
81
|
-
scopeActive: "agent.scope.active",
|
|
82
|
-
memoryOperation: "agent.memory.operation",
|
|
83
|
-
memoryIsolationKey: "agent.memory.isolation_key",
|
|
84
|
-
memoryContentHash: "agent.memory.content_hash",
|
|
85
|
-
planStepIndex: "agent.plan.step_index",
|
|
86
|
-
planToolIntents: "agent.plan.tool_intents",
|
|
87
|
-
planPolicyIds: "agent.plan.policy_ids",
|
|
88
|
-
outputFormat: "agent.output.format",
|
|
89
|
-
outputContainsUrl: "agent.output.contains_url",
|
|
90
|
-
outputUrlCount: "agent.output.url_count"
|
|
91
|
-
};
|
|
92
|
-
function setSecurityAttr(ctx, key, value) {
|
|
93
|
-
const attr = toAttributeValue(value);
|
|
94
|
-
if (attr === void 0) return;
|
|
95
|
-
const traceCtx = resolveContext(ctx);
|
|
96
|
-
if (Array.isArray(attr)) {
|
|
97
|
-
traceCtx.setAttributes({ [key]: attr });
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
traceCtx.setAttribute(key, attr);
|
|
101
|
-
}
|
|
102
|
-
function setSecurityAttrs(ctx, attrs) {
|
|
103
|
-
const traceCtx = resolveContext(ctx);
|
|
104
|
-
const mapped = {};
|
|
105
|
-
for (const [key, value] of Object.entries(attrs)) {
|
|
106
|
-
const attr = toAttributeValue(value);
|
|
107
|
-
if (attr !== void 0) mapped[key] = attr;
|
|
108
|
-
}
|
|
109
|
-
if (Object.keys(mapped).length > 0) traceCtx.setAttributes(mapped);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Derive a coarse action risk class from MCP tool hints or explicit overrides.
|
|
113
|
-
*/
|
|
114
|
-
function deriveActionRiskClass(hints, override) {
|
|
115
|
-
if (override) return override;
|
|
116
|
-
if (hints.financial) return "financial";
|
|
117
|
-
if (hints.exfiltrationCapable || hints.openWorldHint) return "exfiltration_capable";
|
|
118
|
-
if (hints.destructiveHint) return "destructive";
|
|
119
|
-
if (hints.readOnlyHint) return "read";
|
|
120
|
-
if (hints.untrustedContentHint) return "read";
|
|
121
|
-
return "write";
|
|
122
|
-
}
|
|
123
|
-
function recordControllerId(input) {
|
|
124
|
-
const id = input.hash === false ? input.controllerId : hashIdentifier(input.controllerId, { salt: input.hashSalt });
|
|
125
|
-
setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.controllerId, id);
|
|
126
|
-
}
|
|
127
|
-
function recordInputProvenance(input) {
|
|
128
|
-
setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.inputProvenance, input.provenance);
|
|
129
|
-
}
|
|
130
|
-
function recordHumanApproval(input) {
|
|
131
|
-
const attrs = {
|
|
132
|
-
[AGENT_SECURITY_ATTR.consentRequired]: input.required ?? true,
|
|
133
|
-
[AGENT_SECURITY_ATTR.consentOutcome]: input.approved ? "approved" : "denied",
|
|
134
|
-
"tool.call.id": input.toolCallId
|
|
135
|
-
};
|
|
136
|
-
if (input.toolName) attrs["tool.name"] = input.toolName;
|
|
137
|
-
if (input.controllerId) attrs[AGENT_SECURITY_ATTR.controllerId] = hashIdentifier(input.controllerId, { salt: input.hashSalt });
|
|
138
|
-
setSecurityAttrs(input.ctx, attrs);
|
|
139
|
-
}
|
|
140
|
-
function recordActiveScopes(input) {
|
|
141
|
-
setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.scopeActive, input.scopes);
|
|
142
|
-
}
|
|
143
|
-
function recordActionRiskClass(riskClass, options = {}) {
|
|
144
|
-
setSecurityAttr(options.ctx, AGENT_SECURITY_ATTR.actionRiskClass, riskClass);
|
|
145
|
-
}
|
|
146
|
-
function recordMemoryAccess(input) {
|
|
147
|
-
setSecurityAttrs(input.ctx, {
|
|
148
|
-
[AGENT_SECURITY_ATTR.memoryOperation]: input.operation,
|
|
149
|
-
[AGENT_SECURITY_ATTR.memoryIsolationKey]: input.isolationKey,
|
|
150
|
-
...input.contentHash !== void 0 && { [AGENT_SECURITY_ATTR.memoryContentHash]: input.contentHash }
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
function recordPlanStep(input) {
|
|
154
|
-
setSecurityAttrs(input.ctx, {
|
|
155
|
-
[AGENT_SECURITY_ATTR.planStepIndex]: input.stepIndex,
|
|
156
|
-
...input.toolIntents !== void 0 && { [AGENT_SECURITY_ATTR.planToolIntents]: input.toolIntents },
|
|
157
|
-
...input.policyIds !== void 0 && { [AGENT_SECURITY_ATTR.planPolicyIds]: input.policyIds },
|
|
158
|
-
...input.summary !== void 0 && { "decision.summary": input.summary }
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
function recordRenderOutput(input) {
|
|
162
|
-
setSecurityAttrs(input.ctx, {
|
|
163
|
-
...input.format !== void 0 && { [AGENT_SECURITY_ATTR.outputFormat]: input.format },
|
|
164
|
-
...input.containsUrl !== void 0 && { [AGENT_SECURITY_ATTR.outputContainsUrl]: input.containsUrl },
|
|
165
|
-
...input.urlCount !== void 0 && { [AGENT_SECURITY_ATTR.outputUrlCount]: input.urlCount }
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
/** Best-effort variant — no throw when trace context is missing. */
|
|
169
|
-
function tryRecordHumanApproval(input) {
|
|
170
|
-
const ctx = resolveContextSafe(input.ctx);
|
|
171
|
-
if (!ctx) return false;
|
|
172
|
-
recordHumanApproval({
|
|
173
|
-
...input,
|
|
174
|
-
ctx
|
|
175
|
-
});
|
|
176
|
-
return true;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
//#endregion
|
|
180
|
-
export { warnMissingContextOnce as _, recordControllerId as a, recordMemoryAccess as c, tryRecordHumanApproval as d, MISSING_CONTEXT_MESSAGE as f, toAttributeValue as g, resolveContextSafe as h, recordActiveScopes as i, recordPlanStep as l, resolveContext as m, deriveActionRiskClass as n, recordHumanApproval as o, agentContextFromSpan as p, recordActionRiskClass as r, recordInputProvenance as s, AGENT_SECURITY_ATTR as t, recordRenderOutput as u };
|
|
181
|
-
//# sourceMappingURL=agent-security-ChL0rIh-.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent-security-ChL0rIh-.js","names":[],"sources":["../src/agent/context.ts","../src/agent/agent-security.ts"],"sourcesContent":["import { getTraceContext, otelTrace } from 'autotel';\n\nexport interface AgentContext {\n traceId: string;\n spanId: string;\n correlationId: string;\n setAttribute(key: string, value: string | number | boolean): void;\n setAttributes(\n attrs: Record<string, string | number | boolean | string[] | number[] | boolean[]>,\n ): void;\n}\n\nexport const MISSING_CONTEXT_MESSAGE =\n '[autotel-genai] No active trace context. Wrap the call in trace()/instrument(), pass options.ctx, ' +\n 'or set options.onMissingContext to \"warn\"/\"skip\" to degrade gracefully instead of throwing.';\n\n/**\n * Resolve an agent context without throwing. Returns `null` when no trace context\n * is available, so callers can degrade gracefully (best-effort instrumentation).\n */\nconst INVALID_TRACE_ID = '00000000000000000000000000000000';\n\nexport function resolveContextSafe(ctx?: AgentContext): AgentContext | null {\n if (ctx) return ctx;\n\n const span = otelTrace.getActiveSpan();\n if (!span) return null;\n\n // Resolve trace ids from autotel's context when available, otherwise from the\n // active OTel span itself. This makes agent audit work in *any* OTel setup —\n // @effect/opentelemetry, a vanilla NodeSDK, autotel-cloudflare's instrumented\n // fetch handler — not just inside autotel's own `trace()`.\n const ids = getTraceContext();\n const sc = span.spanContext();\n const traceId = ids?.traceId ?? sc.traceId;\n if (!traceId || traceId === INVALID_TRACE_ID) return null;\n\n return {\n traceId,\n spanId: ids?.spanId ?? sc.spanId,\n correlationId: ids?.correlationId ?? traceId.slice(0, 16),\n setAttribute: (key, value) => span.setAttribute(key, value),\n setAttributes: (attrs) => span.setAttributes(attrs),\n };\n}\n\nexport function resolveContext(ctx?: AgentContext): AgentContext {\n const resolved = resolveContextSafe(ctx);\n if (resolved) return resolved;\n throw new Error(MISSING_CONTEXT_MESSAGE);\n}\n\nconst warnedMissingContext = new Set<string>();\n\n/** Warn (once per action) that an agent action is running without a trace context. */\nexport function warnMissingContextOnce(action: string): void {\n if (warnedMissingContext.has(action)) return;\n warnedMissingContext.add(action);\n console.warn(\n `[autotel-genai] No active trace context for \"${action}\" — running un-audited. ` +\n 'Wrap the call in trace()/instrument() or pass options.ctx to capture agent audit telemetry. ' +\n '(set options.onMissingContext: \"throw\" to fail fast, or \"skip\" to silence this warning)',\n );\n}\n\n/** A no-op {@link AgentContext} whose attribute setters do nothing. */\nexport function noopAgentContext(): AgentContext {\n return {\n traceId: '',\n spanId: '',\n correlationId: '',\n setAttribute() {},\n setAttributes() {},\n };\n}\n\n/** Adapt an OpenTelemetry span (or span-like object) to {@link AgentContext}. */\nexport function agentContextFromSpan(span: {\n spanContext(): { traceId: string; spanId: string };\n setAttribute(key: string, value: string | number | boolean): void;\n setAttributes(\n attrs: Record<string, string | number | boolean | string[] | number[] | boolean[]>,\n ): void;\n}): AgentContext {\n const sc = span.spanContext();\n return {\n traceId: sc.traceId,\n spanId: sc.spanId,\n correlationId: sc.traceId.slice(0, 16),\n setAttribute: (key, value) => span.setAttribute(key, value),\n setAttributes: (attrs) => span.setAttributes(attrs),\n };\n}\n\nexport function toAttributeValue(\n value: unknown,\n): string | number | boolean | string[] | number[] | boolean[] | undefined {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n\n if (Array.isArray(value)) {\n if (value.every((entry) => typeof entry === 'string')) {\n return value;\n }\n\n if (value.every((entry) => typeof entry === 'number')) {\n return value;\n }\n\n if (value.every((entry) => typeof entry === 'boolean')) {\n return value;\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return '<serialization-failed>';\n }\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'bigint') {\n return value.toString(10);\n }\n\n if (value === null || value === undefined) {\n return undefined;\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return '<serialization-failed>';\n }\n}\n","import { hashIdentifier } from 'autotel-audit';\nimport { resolveContext, resolveContextSafe, toAttributeValue, type AgentContext } from './context.js';\n\n/** Canonical agent security attribute keys (Google SAIF / human-control aligned). */\nexport const AGENT_SECURITY_ATTR = {\n controllerId: 'agent.controller.id',\n inputProvenance: 'agent.input.provenance',\n actionRiskClass: 'agent.action.risk_class',\n consentRequired: 'agent.consent.required',\n consentOutcome: 'agent.consent.outcome',\n scopeActive: 'agent.scope.active',\n memoryOperation: 'agent.memory.operation',\n memoryIsolationKey: 'agent.memory.isolation_key',\n memoryContentHash: 'agent.memory.content_hash',\n planStepIndex: 'agent.plan.step_index',\n planToolIntents: 'agent.plan.tool_intents',\n planPolicyIds: 'agent.plan.policy_ids',\n outputFormat: 'agent.output.format',\n outputContainsUrl: 'agent.output.contains_url',\n outputUrlCount: 'agent.output.url_count',\n} as const;\n\nexport type AgentInputProvenance =\n | 'user_direct'\n | 'user_voice'\n | 'rag'\n | 'memory'\n | 'tool_result'\n | 'external_untrusted';\n\nexport type AgentActionRiskClass =\n | 'read'\n | 'write'\n | 'destructive'\n | 'financial'\n | 'exfiltration_capable';\n\nexport type AgentConsentOutcome = 'approved' | 'denied' | 'timeout' | 'revoked';\n\nexport type AgentMemoryOperation = 'read' | 'write' | 'delete' | 'search';\n\nexport type AgentOutputFormat = 'text' | 'markdown' | 'html' | 'json' | 'mixed';\n\nexport interface AgentSecurityRecordOptions {\n ctx?: AgentContext;\n}\n\nexport interface RecordControllerInput extends AgentSecurityRecordOptions {\n /** Controlling human user id — hashed before emission unless already a digest. */\n controllerId: string;\n /** Pass a stable per-deployment salt to `hashIdentifier`. */\n hashSalt?: string;\n /** When false, emit the id as given (must not be raw PII). Default true. */\n hash?: boolean;\n}\n\nexport interface RecordInputProvenanceInput extends AgentSecurityRecordOptions {\n provenance: AgentInputProvenance;\n}\n\nexport interface RecordHumanApprovalInput extends AgentSecurityRecordOptions {\n toolCallId: string;\n toolName?: string;\n approved: boolean;\n required?: boolean;\n controllerId?: string;\n hashSalt?: string;\n}\n\nexport interface RecordActiveScopesInput extends AgentSecurityRecordOptions {\n scopes: string[];\n}\n\nexport interface RecordMemoryAccessInput extends AgentSecurityRecordOptions {\n operation: AgentMemoryOperation;\n isolationKey: string;\n contentHash?: string;\n}\n\nexport interface RecordPlanStepInput extends AgentSecurityRecordOptions {\n stepIndex: number;\n toolIntents?: string[];\n policyIds?: string[];\n summary?: string;\n}\n\nexport interface RecordRenderOutputInput extends AgentSecurityRecordOptions {\n format?: AgentOutputFormat;\n containsUrl?: boolean;\n urlCount?: number;\n}\n\nexport interface ActionRiskHints {\n readOnlyHint?: boolean;\n destructiveHint?: boolean;\n openWorldHint?: boolean;\n untrustedContentHint?: boolean;\n financial?: boolean;\n exfiltrationCapable?: boolean;\n}\n\nfunction setSecurityAttr(\n ctx: AgentContext | undefined,\n key: string,\n value: unknown,\n): void {\n const attr = toAttributeValue(value);\n if (attr === undefined) return;\n const traceCtx = resolveContext(ctx);\n if (Array.isArray(attr)) {\n traceCtx.setAttributes({ [key]: attr });\n return;\n }\n traceCtx.setAttribute(key, attr);\n}\n\nfunction setSecurityAttrs(\n ctx: AgentContext | undefined,\n attrs: Record<string, unknown>,\n): void {\n const traceCtx = resolveContext(ctx);\n const mapped: Record<string, string | number | boolean | string[] | number[] | boolean[]> =\n {};\n for (const [key, value] of Object.entries(attrs)) {\n const attr = toAttributeValue(value);\n if (attr !== undefined) {\n mapped[key] = attr;\n }\n }\n if (Object.keys(mapped).length > 0) {\n traceCtx.setAttributes(mapped);\n }\n}\n\n/**\n * Derive a coarse action risk class from MCP tool hints or explicit overrides.\n */\nexport function deriveActionRiskClass(\n hints: ActionRiskHints,\n override?: AgentActionRiskClass,\n): AgentActionRiskClass {\n if (override) return override;\n if (hints.financial) return 'financial';\n if (hints.exfiltrationCapable || hints.openWorldHint) {\n return 'exfiltration_capable';\n }\n if (hints.destructiveHint) return 'destructive';\n if (hints.readOnlyHint) return 'read';\n if (hints.untrustedContentHint) return 'read';\n return 'write';\n}\n\nexport function recordControllerId(input: RecordControllerInput): void {\n const id =\n input.hash === false\n ? input.controllerId\n : hashIdentifier(input.controllerId, { salt: input.hashSalt });\n setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.controllerId, id);\n}\n\nexport function recordInputProvenance(input: RecordInputProvenanceInput): void {\n setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.inputProvenance, input.provenance);\n}\n\nexport function recordHumanApproval(input: RecordHumanApprovalInput): void {\n const attrs: Record<string, unknown> = {\n [AGENT_SECURITY_ATTR.consentRequired]: input.required ?? true,\n [AGENT_SECURITY_ATTR.consentOutcome]: input.approved ? 'approved' : 'denied',\n 'tool.call.id': input.toolCallId,\n };\n if (input.toolName) {\n attrs['tool.name'] = input.toolName;\n }\n if (input.controllerId) {\n attrs[AGENT_SECURITY_ATTR.controllerId] = hashIdentifier(input.controllerId, {\n salt: input.hashSalt,\n });\n }\n setSecurityAttrs(input.ctx, attrs);\n}\n\nexport function recordActiveScopes(input: RecordActiveScopesInput): void {\n setSecurityAttr(input.ctx, AGENT_SECURITY_ATTR.scopeActive, input.scopes);\n}\n\nexport function recordActionRiskClass(\n riskClass: AgentActionRiskClass,\n options: AgentSecurityRecordOptions = {},\n): void {\n setSecurityAttr(options.ctx, AGENT_SECURITY_ATTR.actionRiskClass, riskClass);\n}\n\nexport function recordMemoryAccess(input: RecordMemoryAccessInput): void {\n setSecurityAttrs(input.ctx, {\n [AGENT_SECURITY_ATTR.memoryOperation]: input.operation,\n [AGENT_SECURITY_ATTR.memoryIsolationKey]: input.isolationKey,\n ...(input.contentHash !== undefined && {\n [AGENT_SECURITY_ATTR.memoryContentHash]: input.contentHash,\n }),\n });\n}\n\nexport function recordPlanStep(input: RecordPlanStepInput): void {\n setSecurityAttrs(input.ctx, {\n [AGENT_SECURITY_ATTR.planStepIndex]: input.stepIndex,\n ...(input.toolIntents !== undefined && {\n [AGENT_SECURITY_ATTR.planToolIntents]: input.toolIntents,\n }),\n ...(input.policyIds !== undefined && {\n [AGENT_SECURITY_ATTR.planPolicyIds]: input.policyIds,\n }),\n ...(input.summary !== undefined && { 'decision.summary': input.summary }),\n });\n}\n\nexport function recordRenderOutput(input: RecordRenderOutputInput): void {\n setSecurityAttrs(input.ctx, {\n ...(input.format !== undefined && {\n [AGENT_SECURITY_ATTR.outputFormat]: input.format,\n }),\n ...(input.containsUrl !== undefined && {\n [AGENT_SECURITY_ATTR.outputContainsUrl]: input.containsUrl,\n }),\n ...(input.urlCount !== undefined && {\n [AGENT_SECURITY_ATTR.outputUrlCount]: input.urlCount,\n }),\n });\n}\n\n/** Best-effort variant — no throw when trace context is missing. */\nexport function tryRecordHumanApproval(input: RecordHumanApprovalInput): boolean {\n const ctx = resolveContextSafe(input.ctx);\n if (!ctx) return false;\n recordHumanApproval({ ...input, ctx });\n return true;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent-yHB-GF6g.js","names":["toIsoString","toIsoString","normalizeScopes"],"sources":["../src/agent/constants.ts","../src/agent/hash.ts","../src/agent/metadata.ts","../src/agent/attributes.ts","../src/agent/runtime.ts","../src/agent/delegation.ts","../src/agent/session.ts","../src/agent/identity-registry.ts","../src/agent/privacy.ts","../src/agent/non-repudiation.ts","../src/agent/scoped-tool.ts","../src/agent/agent-plan-classifier.ts"],"sourcesContent":["export const AGENT_AUDIT_SCHEMA_VERSION = '1.1.0';\n","import { createHash } from 'node:crypto';\n\nexport interface HashPayloadOptions {\n algorithm?: 'sha256';\n}\n\nfunction canonicalize(value: unknown): unknown {\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'bigint') {\n return value.toString(10);\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => canonicalize(entry));\n }\n\n if (value && typeof value === 'object') {\n // `toSorted()` would need ES2023 lib types; keep runtime output ES2022-friendly.\n const entries = Object.entries(value as Record<string, unknown>);\n entries.sort(([left], [right]) => left.localeCompare(right));\n return Object.fromEntries(\n entries.map(([key, entryValue]) => [key, canonicalize(entryValue)]),\n );\n }\n\n return value;\n}\n\nexport function canonicalizeForHash(value: unknown): string {\n return JSON.stringify(canonicalize(value));\n}\n\nexport function hashPayload(\n value: unknown,\n options: HashPayloadOptions = {},\n): string {\n const algorithm = options.algorithm ?? 'sha256';\n const canonical = canonicalizeForHash(value);\n const digest = createHash(algorithm).update(canonical).digest('hex');\n return `${algorithm}:${digest}`;\n}\n","import { AGENT_AUDIT_SCHEMA_VERSION } from './constants.js';\nimport { hashPayload } from './hash.js';\nimport type {\n AgentActionMetadata,\n AgentDecisionMetadata,\n AgentEventKind,\n GovernanceMetadata,\n ToolCallMetadata,\n} from './types.js';\n\ninterface AuditMetadataLike {\n action: string;\n resource?: string;\n actorId?: string;\n category?: string;\n outcome?: string;\n [key: string]: unknown;\n}\n\nexport function defaultEventKind(\n metadata: AgentActionMetadata,\n): AgentEventKind {\n if (metadata.eventKind) return metadata.eventKind;\n if (metadata.tool) return 'tool_call';\n if (metadata.policy) return 'policy_decision';\n return 'action';\n}\n\nexport function normalizeTool(\n tool?: ToolCallMetadata,\n): ToolCallMetadata | undefined {\n if (!tool) return undefined;\n\n return {\n name: tool.name,\n ...(tool.callId !== undefined && { callId: tool.callId }),\n inputHash:\n tool.input === undefined\n ? tool.inputHash\n : (tool.inputHash ?? hashPayload(tool.input)),\n outputHash:\n tool.output === undefined\n ? tool.outputHash\n : (tool.outputHash ?? hashPayload(tool.output)),\n ...(tool.status !== undefined && { status: tool.status }),\n ...(tool.executionMs !== undefined && { executionMs: tool.executionMs }),\n };\n}\n\nexport function sanitizeTool(\n tool?: ToolCallMetadata,\n): ToolCallMetadata | undefined {\n if (!tool) return undefined;\n\n return {\n name: tool.name,\n ...(tool.callId !== undefined && { callId: tool.callId }),\n ...(tool.inputHash !== undefined && { inputHash: tool.inputHash }),\n ...(tool.outputHash !== undefined && { outputHash: tool.outputHash }),\n ...(tool.status !== undefined && { status: tool.status }),\n ...(tool.executionMs !== undefined && { executionMs: tool.executionMs }),\n };\n}\n\nexport function sanitizeGovernance(\n governance?: GovernanceMetadata,\n): GovernanceMetadata | undefined {\n if (!governance) return undefined;\n return {\n ...(governance.reviewRequired !== undefined && {\n reviewRequired: governance.reviewRequired,\n }),\n ...(governance.reviewerId !== undefined && {\n reviewerId: governance.reviewerId,\n }),\n ...(governance.controlId !== undefined && {\n controlId: governance.controlId,\n }),\n ...(governance.documentationUrl !== undefined && {\n documentationUrl: governance.documentationUrl,\n }),\n ...(governance.lifecycleStage !== undefined && {\n lifecycleStage: governance.lifecycleStage,\n }),\n ...(governance.framework !== undefined && {\n framework: governance.framework,\n }),\n };\n}\n\nfunction normalizeDecision(\n decision?: AgentDecisionMetadata,\n reasoningSummary?: string,\n): AgentDecisionMetadata | undefined {\n if (decision) {\n return {\n ...decision,\n summary: decision.summary ?? reasoningSummary ?? '',\n };\n }\n\n if (reasoningSummary === undefined) return undefined;\n\n return {\n summary: reasoningSummary,\n };\n}\n\nexport function createAgentAuditMetadata(\n metadata: AgentActionMetadata,\n): AgentActionMetadata {\n const eventKind = defaultEventKind(metadata);\n\n if (eventKind === 'tool_call' && !metadata.tool) {\n throw new Error(\n '[autotel-genai] eventKind \"tool_call\" requires metadata.tool.',\n );\n }\n\n if (eventKind === 'policy_decision' && !metadata.policy) {\n throw new Error(\n '[autotel-genai] eventKind \"policy_decision\" requires metadata.policy.',\n );\n }\n\n if (eventKind === 'handoff' && !metadata.delegation) {\n throw new Error(\n '[autotel-genai] eventKind \"handoff\" requires metadata.delegation.',\n );\n }\n\n const delegation =\n metadata.delegation &&\n (\n metadata.delegation.authorityLineageHash === undefined ||\n metadata.delegation.depth === undefined\n )\n ? {\n ...metadata.delegation,\n ...(metadata.delegation.authorityLineage && {\n authorityLineageHash:\n metadata.delegation.authorityLineageHash ??\n hashPayload(metadata.delegation.authorityLineage),\n depth:\n metadata.delegation.depth ??\n Math.max(metadata.delegation.authorityLineage.length - 1, 0),\n }),\n }\n : metadata.delegation;\n\n return {\n ...metadata,\n schemaVersion: metadata.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n eventKind,\n decision: normalizeDecision(metadata.decision, metadata.reasoningSummary),\n ...(delegation !== undefined && { delegation }),\n };\n}\n\nexport function normalizeMetadata(\n metadata: AgentActionMetadata,\n): AgentActionMetadata {\n const normalized = createAgentAuditMetadata(metadata);\n return {\n ...normalized,\n tool: normalizeTool(normalized.tool),\n };\n}\n\nexport function buildAuditMetadata(\n metadata: AgentActionMetadata,\n): AuditMetadataLike {\n return {\n action: metadata.action,\n ...(metadata.resource !== undefined && { resource: metadata.resource }),\n actorId:\n metadata.actorId ??\n metadata.delegation?.parentIdentity ??\n metadata.agent.id,\n category: metadata.category ?? 'agent',\n ...(metadata.outcome !== undefined && { outcome: metadata.outcome }),\n agentId: metadata.agent.id,\n agentEventKind: metadata.eventKind,\n agentAuditVersion: metadata.schemaVersion,\n ...(metadata.agent.version !== undefined && {\n agentVersion: metadata.agent.version,\n }),\n ...(metadata.tool?.name !== undefined && { toolName: metadata.tool.name }),\n ...(metadata.policy?.decision !== undefined && {\n policyDecision: metadata.policy.decision,\n }),\n ...(metadata.session?.status !== undefined && {\n sessionStatus: metadata.session.status,\n }),\n };\n}\n\nexport function buildLoggerContext(\n metadata: AgentActionMetadata,\n): Record<string, unknown> {\n const tool = sanitizeTool(metadata.tool);\n const governance = sanitizeGovernance(metadata.governance);\n\n const context: Record<string, unknown> = {\n agent: {\n ...metadata.agent,\n ...(metadata.resource !== undefined && { resource: metadata.resource }),\n ...(metadata.outcome !== undefined && { outcome: metadata.outcome }),\n ...(metadata.reasoningSummary !== undefined && {\n reasoningSummary: metadata.reasoningSummary,\n }),\n schemaVersion: metadata.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n eventKind: metadata.eventKind ?? defaultEventKind(metadata),\n },\n ...(metadata.delegation !== undefined && {\n delegation: metadata.delegation,\n }),\n ...(tool !== undefined && { tool }),\n ...(metadata.policy !== undefined && { policy: metadata.policy }),\n ...(governance !== undefined && { governance }),\n ...(metadata.session !== undefined && { session: metadata.session }),\n ...(metadata.decision !== undefined && { decision: metadata.decision }),\n };\n\n // Hand the request logger an independent copy. `logger.set()` deep-merges and\n // intentionally *concatenates* array fields across calls (autotel wide-event\n // semantics). Agent lifecycles call `.set()` more than once per action with\n // the same `delegation`/`decision` objects, so sharing references would let\n // the merge mutate arrays (e.g. `authority_lineage`) in place — which would\n // then leak onto the span via `setAgentAttributes`. Cloning keeps the\n // span-bound metadata pristine.\n return structuredClone(context);\n}\n\n/**\n * Context for the *completion* `logger.set()` of a specialized lifecycle\n * wrapper. Carries only the domain state that finished mutating — tool or\n * session status. Outcome is owned by `withAgentAction`, which wraps every\n * variant and stamps it on both span and log. This deliberately omits the\n * request-level `delegation`/`decision` blocks: those were set once at the\n * start, and re-sending them would concatenate their array fields into the\n * wide event (see `buildLoggerContext`).\n */\nexport function buildLifecycleUpdateContext(\n metadata: AgentActionMetadata,\n): Record<string, unknown> {\n const tool = sanitizeTool(metadata.tool);\n return {\n ...(tool !== undefined && { tool }),\n ...(metadata.session !== undefined && {\n session: structuredClone(metadata.session),\n }),\n };\n}\n","import { AGENT_AUDIT_SCHEMA_VERSION } from './constants.js';\nimport { resolveContext, toAttributeValue, type AgentContext } from './context.js';\nimport { defaultEventKind, normalizeMetadata } from './metadata.js';\nimport type {\n AgentActionMetadata,\n AgentDecisionMetadata,\n AgentIdentity,\n AgentSessionMetadata,\n DelegationContext,\n GovernanceMetadata,\n PolicyMetadata,\n ToolCallMetadata,\n} from './types.js';\n\ntype AttributeValue =\n | string\n | number\n | boolean\n | string[]\n | number[]\n | boolean[];\n\ntype AttributeMap = Record<string, AttributeValue>;\n\nfunction setIfPresent(target: AttributeMap, key: string, value: unknown): void {\n const attr = toAttributeValue(value);\n if (attr !== undefined) {\n target[key] = attr;\n }\n}\n\nfunction appendIdentityAttributes(attrs: AttributeMap, agent: AgentIdentity): void {\n setIfPresent(attrs, 'agent.id', agent.id);\n setIfPresent(attrs, 'agent.version', agent.version);\n setIfPresent(attrs, 'agent.framework', agent.framework);\n setIfPresent(attrs, 'agent.model', agent.model);\n setIfPresent(attrs, 'agent.role', agent.role);\n setIfPresent(attrs, 'agent.session.id', agent.sessionId);\n setIfPresent(attrs, 'agent.conversation.id', agent.conversationId);\n}\n\nfunction appendDelegationAttributes(\n attrs: AttributeMap,\n delegation?: DelegationContext,\n): void {\n if (!delegation) return;\n setIfPresent(attrs, 'delegation.parent_identity', delegation.parentIdentity);\n setIfPresent(attrs, 'delegation.scope', delegation.scope);\n setIfPresent(attrs, 'delegation.token_id', delegation.tokenId);\n setIfPresent(attrs, 'delegation.id', delegation.delegationId);\n setIfPresent(attrs, 'delegation.authority_lineage', delegation.authorityLineage);\n setIfPresent(\n attrs,\n 'delegation.authority_lineage_hash',\n delegation.authorityLineageHash,\n );\n setIfPresent(attrs, 'delegation.depth', delegation.depth);\n setIfPresent(attrs, 'delegation.issued_at', delegation.issuedAt);\n setIfPresent(attrs, 'delegation.expires_at', delegation.expiresAt);\n}\n\nfunction appendToolAttributes(attrs: AttributeMap, tool?: ToolCallMetadata): void {\n if (!tool) return;\n setIfPresent(attrs, 'tool.name', tool.name);\n setIfPresent(attrs, 'tool.call.id', tool.callId);\n setIfPresent(attrs, 'tool.input_hash', tool.inputHash);\n setIfPresent(attrs, 'tool.output_hash', tool.outputHash);\n setIfPresent(attrs, 'tool.status', tool.status);\n setIfPresent(attrs, 'tool.execution_ms', tool.executionMs);\n}\n\nfunction appendPolicyAttributes(attrs: AttributeMap, policy?: PolicyMetadata): void {\n if (!policy) return;\n setIfPresent(attrs, 'policy.decision', policy.decision);\n setIfPresent(attrs, 'policy.id', policy.policyId);\n setIfPresent(attrs, 'policy.risk_score', policy.riskScore);\n setIfPresent(attrs, 'policy.reason', policy.reason);\n}\n\nfunction appendGovernanceAttributes(\n attrs: AttributeMap,\n governance?: GovernanceMetadata,\n): void {\n if (!governance) return;\n setIfPresent(attrs, 'governance.review_required', governance.reviewRequired);\n setIfPresent(attrs, 'governance.reviewer_id', governance.reviewerId);\n setIfPresent(attrs, 'governance.control_id', governance.controlId);\n setIfPresent(attrs, 'governance.documentation_url', governance.documentationUrl);\n setIfPresent(attrs, 'governance.lifecycle_stage', governance.lifecycleStage);\n setIfPresent(attrs, 'governance.framework', governance.framework);\n}\n\nfunction appendSessionAttributes(\n attrs: AttributeMap,\n session?: AgentSessionMetadata,\n): void {\n if (!session) return;\n setIfPresent(attrs, 'agent.session.status', session.status);\n setIfPresent(attrs, 'agent.session.started_at', session.startedAt);\n setIfPresent(attrs, 'agent.session.ended_at', session.endedAt);\n setIfPresent(attrs, 'agent.session.delegated_by', session.delegatedBy);\n}\n\nfunction appendDecisionAttributes(\n attrs: AttributeMap,\n decision?: AgentDecisionMetadata,\n): void {\n if (!decision) return;\n setIfPresent(attrs, 'decision.summary', decision.summary);\n setIfPresent(attrs, 'decision.input_hash', decision.inputHash);\n setIfPresent(attrs, 'decision.policy_ids', decision.policyIds);\n setIfPresent(attrs, 'decision.justification_codes', decision.justificationCodes);\n setIfPresent(attrs, 'decision.evidence_ids', decision.evidenceIds);\n setIfPresent(attrs, 'decision.review_required', decision.reviewRequired);\n setIfPresent(attrs, 'decision.confidence', decision.confidence);\n}\n\nexport function flattenAgentAttributes(\n metadata: AgentActionMetadata,\n): AttributeMap {\n const normalized = normalizeMetadata(metadata);\n const attrs: AttributeMap = {\n 'autotel.agent': true,\n 'agent.action': normalized.action,\n 'agent.audit.version':\n normalized.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n 'agent.event.kind': normalized.eventKind ?? defaultEventKind(normalized),\n };\n\n setIfPresent(attrs, 'agent.resource', normalized.resource);\n setIfPresent(attrs, 'agent.outcome', normalized.outcome);\n setIfPresent(attrs, 'reasoning.summary', normalized.reasoningSummary);\n appendIdentityAttributes(attrs, normalized.agent);\n appendDelegationAttributes(attrs, normalized.delegation);\n appendToolAttributes(attrs, normalized.tool);\n appendPolicyAttributes(attrs, normalized.policy);\n appendGovernanceAttributes(attrs, normalized.governance);\n appendSessionAttributes(attrs, normalized.session);\n appendDecisionAttributes(attrs, normalized.decision);\n\n return attrs;\n}\n\nexport function setAgentAttributes(\n metadata: AgentActionMetadata,\n ctx?: AgentContext,\n): void {\n const traceCtx = resolveContext(ctx);\n traceCtx.setAttributes(flattenAgentAttributes(metadata));\n}\n\n/**\n * Stamp only the terminal outcome on the active span. Used by lifecycle\n * wrappers on completion so they don't re-flatten (and clobber) richer state a\n * nested step already wrote — e.g. a tool call's `tool.status=complete`.\n */\nexport function setAgentOutcome(\n outcome: AgentActionMetadata['outcome'] & string,\n ctx?: AgentContext,\n): void {\n resolveContext(ctx).setAttribute('agent.outcome', outcome);\n}\n","import {\n createNoopRequestLogger,\n getRequestLoggerSafe,\n type RequestLogger,\n} from 'autotel';\nimport { forceKeepAuditEvent, withAudit } from 'autotel-audit';\nimport { estimateLLMCost, type TokenUsage } from '../cost.js';\nimport {\n genAiRequestAttributes,\n genAiResponseAttributes,\n genAiUsageAttributes,\n type GenAiAttributeMap,\n} from '../attributes.js';\nimport { setAgentAttributes, setAgentOutcome } from './attributes.js';\nimport {\n buildLoggerContext,\n buildLifecycleUpdateContext,\n buildAuditMetadata,\n normalizeMetadata,\n} from './metadata.js';\nimport {\n MISSING_CONTEXT_MESSAGE,\n resolveContextSafe,\n warnMissingContextOnce,\n type AgentContext,\n} from './context.js';\nimport { hashPayload } from './hash.js';\nimport type {\n AgentActionFactory,\n AgentActionMetadata,\n AgentAiMetadata,\n AgentActionOptions,\n AgentHandler,\n AgentMetadataInput,\n AgentToolCallActionMetadata,\n AgentToolCallOptions,\n ToolCallMetadata,\n} from './types.js';\n\n/**\n * Record canonical OpenTelemetry GenAI semantic attributes for an LLM-backed\n * agent action, reusing the local cost model. Best-effort: anything unknown is\n * simply omitted. `gen_ai.request.model` is always recorded; token counts and\n * the estimated `gen_ai.usage.cost.usd` are recorded when `usage` is available\n * (up front via metadata, or post-call via `options.extractUsage`).\n *\n * Emits canonical v1.42.0 keys only — no `gen_ai.usage.total_tokens` (not a\n * registry attribute) and no legacy `gen.ai.*` names.\n */\nfunction recordAiTelemetry(\n ctx: AgentContext,\n ai: AgentAiMetadata,\n usage?: TokenUsage,\n): void {\n const attrs: GenAiAttributeMap = {\n ...genAiRequestAttributes({\n operation: ai.operation,\n provider: ai.provider,\n model: ai.model,\n }),\n ...genAiResponseAttributes({\n model: ai.responseModel,\n id: ai.responseId,\n finishReasons: ai.finishReasons,\n }),\n };\n if (usage) {\n const cost = estimateLLMCost(\n ai.model,\n usage,\n ai.pricing ? { pricing: ai.pricing } : undefined,\n );\n Object.assign(attrs, genAiUsageAttributes({ ...usage, costUsd: cost }));\n }\n ctx.setAttributes(attrs);\n}\n\nexport async function withAgentAction<T>(\n metadata: AgentActionMetadata,\n fn: AgentHandler<T>,\n options: AgentActionOptions = {},\n): Promise<T> {\n const normalized = normalizeMetadata(metadata);\n\n return withAudit(\n buildAuditMetadata(normalized),\n async (ctx: AgentContext, logger: RequestLogger) => {\n setAgentAttributes(normalized, ctx);\n logger.set(buildLoggerContext(normalized));\n\n try {\n const result = await fn(ctx as AgentContext, logger);\n const outcome = normalized.outcome ?? 'success';\n setAgentOutcome(outcome, ctx);\n logger.set({ agent: { outcome } });\n if (normalized.ai) {\n recordAiTelemetry(\n ctx,\n normalized.ai,\n options.extractUsage?.(result) ?? normalized.ai.usage,\n );\n }\n return result;\n } catch (error) {\n setAgentOutcome('failure', ctx);\n logger.set({ agent: { outcome: 'failure' } });\n if (normalized.ai) recordAiTelemetry(ctx, normalized.ai);\n throw error;\n }\n },\n options,\n );\n}\n\nexport function recordPolicyDecision(\n metadata: AgentActionMetadata,\n options: AgentActionOptions = {},\n): void {\n const normalized = normalizeMetadata(metadata);\n const traceCtx = resolveContextSafe(options.ctx);\n\n // No trace context: degrade per onMissingContext instead of throwing into\n // business logic. A policy decision we couldn't record is not worth a crash.\n if (!traceCtx) {\n const mode = options.onMissingContext ?? 'warn';\n if (mode === 'throw') {\n throw new Error(MISSING_CONTEXT_MESSAGE);\n }\n if (mode === 'warn') {\n warnMissingContextOnce(normalized.action);\n }\n return;\n }\n\n const logger =\n options.logger ?? getRequestLoggerSafe() ?? createNoopRequestLogger();\n\n if (options.forceKeep !== false) {\n forceKeepAuditEvent(traceCtx);\n }\n\n setAgentAttributes(normalized, traceCtx);\n logger.set(buildLoggerContext(normalized));\n\n if (options.emitNow) {\n logger.emitNow();\n }\n}\n\nexport function recordDecisionBasis(\n metadata: AgentActionMetadata,\n options: AgentActionOptions = {},\n): void {\n if (!metadata.decision && !metadata.reasoningSummary) {\n throw new Error(\n '[autotel-genai] recordDecisionBasis requires metadata.decision or metadata.reasoningSummary.',\n );\n }\n\n recordPolicyDecision(metadata, options);\n}\n\n/**\n * Define a reusable, instrumented agent action — the `trace()`-style factory\n * companion to `withAgentAction`. Declare it once at module scope and call the\n * returned function many times; each call opens its own audit scope.\n *\n * `metadata` may be a static object or a function of the call arguments, so\n * call-specific fields can be derived per invocation.\n *\n * @example\n * ```ts\n * const planTrip = defineAgentAction(\n * (req: TripRequest) => ({\n * action: 'agent.trip.plan',\n * agent: { id: 'planner' },\n * delegation: { parentIdentity: req.userId, scope: ['trip:plan'] },\n * }),\n * (ctx) => async (req: TripRequest) => planItinerary(req),\n * );\n *\n * await planTrip({ userId: 'usr_1', destination: 'Lisbon' });\n * ```\n */\nexport function defineAgentAction<TArgs extends unknown[], TResult>(\n metadata: AgentMetadataInput<TArgs, AgentActionMetadata>,\n factory: AgentActionFactory<TArgs, TResult>,\n options: AgentActionOptions = {},\n): (...args: TArgs) => Promise<TResult> {\n return (...args: TArgs): Promise<TResult> => {\n const resolved =\n typeof metadata === 'function' ? metadata(...args) : metadata;\n return withAgentAction(\n resolved,\n (ctx, logger) => factory(ctx, logger)(...args),\n options,\n );\n };\n}\n\n/**\n * Define a reusable, instrumented agent tool call — the `trace()`-style factory\n * companion to `withAgentToolCall`. Declare it once and call it per invocation;\n * tool inputs/results are hashed (never attached raw) on every call.\n *\n * Pass `metadata` as a function of the arguments when `tool.input` (or any other\n * field) depends on the call, so each invocation hashes its own input.\n *\n * @example\n * ```ts\n * const handleRefund = defineAgentToolCall(\n * (req: RefundRequest) => ({\n * action: 'agent.refund.tool_call',\n * resource: 'stripe_refund_v3',\n * agent: { id: 'refunds-specialist' },\n * tool: { name: 'stripe_refund_v3', input: { refundId: req.refundId } },\n * }),\n * (ctx) => async (req: RefundRequest) => stripe.refunds.create(req),\n * );\n *\n * await handleRefund({ refundId: 're_123' });\n * ```\n */\nexport function defineAgentToolCall<TArgs extends unknown[], TResult>(\n metadata: AgentMetadataInput<TArgs, AgentToolCallActionMetadata>,\n factory: AgentActionFactory<TArgs, TResult>,\n options: AgentToolCallOptions = {},\n): (...args: TArgs) => Promise<TResult> {\n return (...args: TArgs): Promise<TResult> => {\n const resolved =\n typeof metadata === 'function' ? metadata(...args) : metadata;\n return withAgentToolCall(\n resolved,\n (ctx, logger) => factory(ctx, logger)(...args),\n options,\n );\n };\n}\n\nexport async function withAgentToolCall<T>(\n metadata: AgentActionMetadata & { tool: ToolCallMetadata },\n fn: AgentHandler<T>,\n options: AgentToolCallOptions = {},\n): Promise<T> {\n const start = Date.now();\n const normalized = normalizeMetadata({\n ...metadata,\n tool: {\n ...metadata.tool,\n status: metadata.tool?.status ?? 'planned',\n } as ToolCallMetadata,\n });\n\n return withAgentAction(\n normalized,\n async (ctx, logger) => {\n try {\n const result = await fn(ctx, logger);\n const executionMs = Date.now() - start;\n const completed: AgentActionMetadata = {\n ...normalized,\n outcome: normalized.outcome ?? 'success',\n tool: {\n ...metadata.tool,\n inputHash: normalized.tool?.inputHash,\n outputHash:\n normalized.tool?.outputHash ??\n (options.hashResult === false ? undefined : hashPayload(result)),\n status: 'complete',\n executionMs,\n },\n };\n setAgentAttributes(completed, ctx);\n logger.set(buildLifecycleUpdateContext(normalizeMetadata(completed)));\n return result;\n } catch (error) {\n const failed: AgentActionMetadata = {\n ...normalized,\n outcome: 'failure',\n tool: {\n ...metadata.tool,\n inputHash: normalized.tool?.inputHash,\n status: 'error',\n executionMs: Date.now() - start,\n },\n };\n setAgentAttributes(failed, ctx);\n logger.set(buildLifecycleUpdateContext(normalizeMetadata(failed)));\n throw error;\n }\n },\n options,\n );\n}\n","import { hashPayload } from './hash.js';\nimport { recordPolicyDecision } from './runtime.js';\nimport type {\n AgentActionOptions,\n AgentIdentity,\n DelegationContext,\n GovernanceMetadata,\n} from './types.js';\n\nfunction buildAuthorityLineage(\n parentIdentity: string,\n agentId: string,\n existingLineage?: string[],\n): string[] {\n const lineage = existingLineage ? [...existingLineage] : [parentIdentity];\n if (lineage.at(-1) !== agentId) {\n lineage.push(agentId);\n }\n return lineage;\n}\n\nexport interface DelegateToAgentInput {\n parentIdentity: string;\n targetAgentId: string;\n scope?: string | string[];\n tokenId?: string;\n delegationId?: string;\n authorityLineage?: string[];\n issuedAt?: string | Date;\n expiresAt?: string | Date;\n}\n\nexport interface RecordAgentHandoffMetadata {\n action: string;\n fromAgent: AgentIdentity;\n toAgent: AgentIdentity;\n parentIdentity: string;\n resource?: string;\n scope?: string | string[];\n tokenId?: string;\n delegationId?: string;\n authorityLineage?: string[];\n governance?: GovernanceMetadata;\n}\n\nexport function delegateToAgent(input: DelegateToAgentInput): DelegationContext {\n const authorityLineage = buildAuthorityLineage(\n input.parentIdentity,\n input.targetAgentId,\n input.authorityLineage,\n );\n\n return {\n parentIdentity: input.parentIdentity,\n ...(input.scope !== undefined && { scope: input.scope }),\n ...(input.tokenId !== undefined && { tokenId: input.tokenId }),\n ...(input.delegationId !== undefined && { delegationId: input.delegationId }),\n authorityLineage,\n authorityLineageHash: hashPayload(authorityLineage),\n depth: Math.max(authorityLineage.length - 1, 0),\n issuedAt: input.issuedAt ?? new Date().toISOString(),\n ...(input.expiresAt !== undefined && { expiresAt: input.expiresAt }),\n };\n}\n\nexport function recordAgentHandoff(\n metadata: RecordAgentHandoffMetadata,\n options: AgentActionOptions = {},\n): void {\n // Seed the lineage with the source agent when the caller didn't supply one,\n // so the \"from\" side of the handoff is recorded in the canonical, queryable\n // `delegation.authority_lineage` (and its hash) rather than surviving only in\n // the free-text reasoningSummary.\n const authorityLineage =\n metadata.authorityLineage ?? [metadata.parentIdentity, metadata.fromAgent.id];\n\n const delegation = delegateToAgent({\n parentIdentity: metadata.parentIdentity,\n targetAgentId: metadata.toAgent.id,\n scope: metadata.scope,\n tokenId: metadata.tokenId,\n delegationId: metadata.delegationId,\n authorityLineage,\n });\n\n recordPolicyDecision(\n {\n action: metadata.action,\n resource: metadata.resource,\n eventKind: 'handoff',\n agent: metadata.toAgent,\n delegation,\n governance: metadata.governance,\n reasoningSummary: `Control passed from ${metadata.fromAgent.id} to ${metadata.toAgent.id}.`,\n },\n options,\n );\n}\n","import { buildLifecycleUpdateContext } from './metadata.js';\nimport { setAgentAttributes } from './attributes.js';\nimport { withAgentAction } from './runtime.js';\nimport type {\n AgentActionOptions,\n AgentHandler,\n AgentSessionActionMetadata,\n} from './types.js';\n\nfunction toIsoString(value?: string | Date): string {\n if (!value) return new Date().toISOString();\n return value instanceof Date ? value.toISOString() : value;\n}\n\nexport async function withAgentSession<T>(\n metadata: AgentSessionActionMetadata,\n fn: AgentHandler<T>,\n options: AgentActionOptions = {},\n): Promise<T> {\n const startedAt = toIsoString(metadata.session?.startedAt);\n\n return withAgentAction(\n {\n ...metadata,\n category: metadata.category ?? 'agent_session',\n session: {\n ...metadata.session,\n status: metadata.session?.status ?? 'active',\n startedAt,\n },\n },\n async (ctx, logger) => {\n try {\n const result = await fn(ctx, logger);\n const completed = {\n ...metadata,\n outcome: metadata.outcome ?? 'success',\n session: {\n ...metadata.session,\n status: 'completed' as const,\n startedAt,\n endedAt: new Date().toISOString(),\n },\n };\n setAgentAttributes(completed, ctx);\n logger.set(buildLifecycleUpdateContext(completed));\n return result;\n } catch (error) {\n const failed = {\n ...metadata,\n outcome: 'failure' as const,\n session: {\n ...metadata.session,\n status: 'failed' as const,\n startedAt,\n endedAt: new Date().toISOString(),\n },\n };\n setAgentAttributes(failed, ctx);\n logger.set(buildLifecycleUpdateContext(failed));\n throw error;\n }\n },\n options,\n );\n}\n","import { hashPayload } from './hash.js';\nimport { delegateToAgent } from './delegation.js';\nimport type {\n AgentIdentity,\n AgentIdentityRegistry,\n AgentIdentityRecord,\n AgentIdentityStatus,\n DelegationContext,\n} from './types.js';\n\nfunction toIsoString(value?: string | Date): string | undefined {\n if (!value) return undefined;\n return value instanceof Date ? value.toISOString() : value;\n}\n\nfunction normalizeScopes(scope?: string | string[]): string[] {\n if (!scope) return [];\n return Array.isArray(scope) ? [...scope] : [scope];\n}\n\nfunction isExpired(record: AgentIdentityRecord, at: string): boolean {\n return record.expiresAt !== undefined && record.expiresAt < at;\n}\n\nexport interface ProvisionAgentIdentityInput {\n agent: AgentIdentity;\n scopes?: string[];\n tokenId?: string;\n delegatedBy?: string;\n provisionedAt?: string | Date;\n expiresAt?: string | Date;\n metadata?: Record<string, unknown>;\n}\n\nexport interface RotateAgentIdentityInput {\n scopes?: string[];\n tokenId?: string;\n delegatedBy?: string;\n rotatedAt?: string | Date;\n expiresAt?: string | Date;\n metadata?: Record<string, unknown>;\n}\n\nexport interface RevokeAgentIdentityInput {\n reason: string;\n revokedAt?: string | Date;\n}\n\nexport function createAgentIdentityRegistry(\n initial: ProvisionAgentIdentityInput[] = [],\n): AgentIdentityRegistry {\n const records = new Map<string, AgentIdentityRecord>();\n\n const provisionIdentity = (\n input: ProvisionAgentIdentityInput,\n ): AgentIdentityRecord => {\n const now = toIsoString(input.provisionedAt) ?? new Date().toISOString();\n const record: AgentIdentityRecord = {\n agent: input.agent,\n scopes: input.scopes ?? [],\n status: 'active',\n tokenId: input.tokenId,\n tokenHash:\n input.tokenId === undefined ? undefined : hashPayload(input.tokenId),\n delegatedBy: input.delegatedBy,\n provisionedAt: now,\n expiresAt: toIsoString(input.expiresAt),\n metadata: input.metadata,\n };\n records.set(input.agent.id, record);\n return record;\n };\n\n for (const item of initial) {\n provisionIdentity(item);\n }\n\n return {\n provisionIdentity,\n rotateIdentity(agentId: string, input: RotateAgentIdentityInput = {}) {\n const existing = records.get(agentId);\n if (!existing) {\n throw new Error(\n `[autotel-genai] Cannot rotate unknown agent identity \"${agentId}\".`,\n );\n }\n\n const rotatedAt = toIsoString(input.rotatedAt) ?? new Date().toISOString();\n const record: AgentIdentityRecord = {\n ...existing,\n scopes: input.scopes ?? existing.scopes,\n status: 'rotated',\n tokenId: input.tokenId ?? existing.tokenId,\n tokenHash:\n input.tokenId === undefined\n ? existing.tokenHash\n : hashPayload(input.tokenId),\n delegatedBy: input.delegatedBy ?? existing.delegatedBy,\n rotatedAt,\n expiresAt: toIsoString(input.expiresAt) ?? existing.expiresAt,\n metadata: input.metadata ?? existing.metadata,\n };\n records.set(agentId, record);\n return record;\n },\n revokeIdentity(agentId: string, input: RevokeAgentIdentityInput) {\n const existing = records.get(agentId);\n if (!existing) {\n throw new Error(\n `[autotel-genai] Cannot revoke unknown agent identity \"${agentId}\".`,\n );\n }\n\n const revokedAt = toIsoString(input.revokedAt) ?? new Date().toISOString();\n const record: AgentIdentityRecord = {\n ...existing,\n status: 'revoked',\n revokedAt,\n revocationReason: input.reason,\n };\n records.set(agentId, record);\n return record;\n },\n getIdentity(agentId: string) {\n return records.get(agentId);\n },\n getIdentityStatus(agentId: string, at = new Date().toISOString()) {\n const record = records.get(agentId);\n if (!record) return;\n return isExpired(record, at) ? 'expired' : record.status;\n },\n assertUsable(agentId: string, at = new Date().toISOString()) {\n const record = records.get(agentId);\n if (!record) {\n throw new Error(\n `[autotel-genai] Unknown agent identity \"${agentId}\". Provision it before use.`,\n );\n }\n\n const status: AgentIdentityStatus = isExpired(record, at)\n ? 'expired'\n : record.status;\n\n if (status !== 'active' && status !== 'rotated') {\n throw new Error(\n `[autotel-genai] Agent identity \"${agentId}\" is ${status} and cannot execute delegated work.`,\n );\n }\n\n return record;\n },\n assertScopes(agentId: string, requiredScopes: string[]) {\n const record = this.assertUsable(agentId);\n const missing = requiredScopes.filter(\n (scope) => !record.scopes.includes(scope),\n );\n\n if (missing.length > 0) {\n throw new Error(\n `[autotel-genai] Agent identity \"${agentId}\" is missing delegated scopes: ${missing.join(', ')}.`,\n );\n }\n\n return record;\n },\n issueDelegation(agentId: string, input) {\n const record = this.assertUsable(agentId);\n const scope = normalizeScopes(input.scope);\n if (scope.length > 0) {\n this.assertScopes(agentId, scope);\n }\n\n return delegateToAgent({\n parentIdentity: input.parentIdentity,\n targetAgentId: record.agent.id,\n scope: input.scope ?? record.scopes,\n tokenId: input.tokenId ?? record.tokenId,\n delegationId: input.delegationId,\n authorityLineage: input.authorityLineage,\n issuedAt: input.issuedAt,\n expiresAt: input.expiresAt ?? record.expiresAt,\n }) satisfies DelegationContext;\n },\n list() {\n return [...records.values()];\n },\n };\n}\n","import { hashPayload } from './hash.js';\nimport type { PrivacyProfile, PrivacyProfileName } from './types.js';\n\nexport type PrivacyProfileInput = PrivacyProfileName | PrivacyProfile;\n\nconst PRIVACY_PROFILES: Record<PrivacyProfileName, PrivacyProfile> = {\n strict: {\n name: 'strict',\n hashKeys: [\n /email/i,\n /phone/i,\n /user_?id/i,\n /account/i,\n /customer/i,\n /card/i,\n /iban/i,\n /tax/i,\n ],\n dropKeys: [\n /secret/i,\n /token/i,\n /api[_-]?key/i,\n /authorization/i,\n /cookie/i,\n /password/i,\n /bearer/i,\n ],\n maskKeys: [/name/i, /address/i, /prompt/i, /message/i, /content/i],\n maxStringLength: 256,\n },\n pci: {\n name: 'pci',\n hashKeys: [/card/i, /pan/i, /account/i, /customer/i, /email/i],\n dropKeys: [/cvv/i, /cvc/i, /secret/i, /token/i, /api[_-]?key/i],\n maskKeys: [/name/i, /address/i],\n maxStringLength: 128,\n },\n healthcare: {\n name: 'healthcare',\n hashKeys: [/patient/i, /mrn/i, /member/i, /email/i, /phone/i],\n dropKeys: [/diagnosis/i, /notes/i, /secret/i, /token/i, /password/i],\n maskKeys: [/name/i, /address/i, /symptom/i],\n maxStringLength: 128,\n },\n};\n\nfunction maskValue(value: unknown): unknown {\n if (typeof value !== 'string') {\n return '<masked>';\n }\n\n if (value.length <= 6) return '***';\n return `${value.slice(0, 3)}***${value.slice(-3)}`;\n}\n\nfunction matches(patterns: RegExp[] | undefined, key: string): boolean {\n return patterns?.some((pattern) => pattern.test(key)) ?? false;\n}\n\nfunction truncateString(value: string, maxLength?: number): string {\n if (maxLength === undefined || value.length <= maxLength) {\n return value;\n }\n\n return `${value.slice(0, maxLength)}…`;\n}\n\nfunction sanitizeNode(\n value: unknown,\n profile: PrivacyProfile,\n keyPath: string,\n): unknown {\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n const lowered = keyPath.toLowerCase();\n\n if (matches(profile.dropKeys, lowered)) {\n return '<redacted>';\n }\n\n if (matches(profile.hashKeys, lowered)) {\n return hashPayload(value);\n }\n\n if (matches(profile.maskKeys, lowered)) {\n return maskValue(value);\n }\n\n if (typeof value === 'string') {\n return truncateString(value, profile.maxStringLength);\n }\n\n if (Array.isArray(value)) {\n return value.map((entry, index) =>\n sanitizeNode(entry, profile, `${keyPath}[${index}]`),\n );\n }\n\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, entry]) => [\n key,\n sanitizeNode(entry, profile, keyPath ? `${keyPath}.${key}` : key),\n ]),\n );\n }\n\n if (typeof value === 'bigint') {\n return value.toString(10);\n }\n\n return value;\n}\n\nexport function resolvePrivacyProfile(\n profile: PrivacyProfileInput = 'strict',\n): PrivacyProfile {\n return typeof profile === 'string' ? PRIVACY_PROFILES[profile] : profile;\n}\n\nexport function sanitizeAuditPayload(\n value: unknown,\n profile: PrivacyProfileInput = 'strict',\n): unknown {\n return sanitizeNode(value, resolvePrivacyProfile(profile), '');\n}\n","import { AGENT_AUDIT_SCHEMA_VERSION } from './constants.js';\nimport { canonicalizeForHash, hashPayload } from './hash.js';\nimport { normalizeMetadata } from './metadata.js';\nimport { sanitizeAuditPayload, type PrivacyProfileInput } from './privacy.js';\nimport type {\n AgentActionMetadata,\n AgentAuditEventEnvelope,\n} from './types.js';\n\nfunction toIsoString(value?: string | Date): string {\n if (!value) return new Date().toISOString();\n return value instanceof Date ? value.toISOString() : value;\n}\n\nexport interface CreateSignedEventEnvelopeOptions {\n emittedAt?: string | Date;\n previousEventHash?: string;\n evidence?: unknown;\n privacyProfile?: PrivacyProfileInput;\n signer?: (serialized: string) => string | Promise<string>;\n}\n\nexport async function createSignedEventEnvelope(\n metadata: AgentActionMetadata,\n options: CreateSignedEventEnvelopeOptions = {},\n): Promise<AgentAuditEventEnvelope> {\n const normalized = normalizeMetadata(metadata);\n const envelopeBase = {\n schemaVersion: normalized.schemaVersion ?? AGENT_AUDIT_SCHEMA_VERSION,\n emittedAt: toIsoString(options.emittedAt),\n ...(options.previousEventHash !== undefined && {\n previousEventHash: options.previousEventHash,\n }),\n metadata: normalized,\n ...(options.evidence !== undefined && {\n evidence: sanitizeAuditPayload(\n options.evidence,\n options.privacyProfile ?? 'strict',\n ),\n }),\n };\n\n const eventHash = hashPayload(envelopeBase);\n const signature = options.signer\n ? await options.signer(canonicalizeForHash(envelopeBase))\n : undefined;\n\n return {\n ...envelopeBase,\n eventHash,\n ...(signature !== undefined && { signature }),\n };\n}\n\nexport function verifyEventEnvelopeHash(\n envelope: AgentAuditEventEnvelope,\n): boolean {\n const expected = hashPayload({\n schemaVersion: envelope.schemaVersion,\n emittedAt: envelope.emittedAt,\n ...(envelope.previousEventHash !== undefined && {\n previousEventHash: envelope.previousEventHash,\n }),\n metadata: envelope.metadata,\n ...(envelope.evidence !== undefined && {\n evidence: envelope.evidence,\n }),\n });\n return envelope.eventHash === expected;\n}\n","import { createStructuredError } from 'autotel';\nimport { securityEvent } from 'autotel-audit';\nimport { sanitizeAuditPayload, type PrivacyProfileInput } from './privacy.js';\nimport { recordDecisionBasis, recordPolicyDecision, withAgentToolCall } from './runtime.js';\nimport { hashPayload } from './hash.js';\nimport type {\n AgentActionOptions,\n AgentDecisionMetadata,\n AgentHandler,\n AgentToolCallOptions,\n DelegationContext,\n GovernanceMetadata,\n PolicyMetadata,\n ScopedToolDefinition,\n} from './types.js';\n\nfunction normalizeScopes(scope?: string | string[]): string[] {\n if (!scope) return [];\n return Array.isArray(scope) ? scope : [scope];\n}\n\nfunction missingScopes(\n delegated: string[],\n required: string[],\n): string[] {\n return required.filter((scope) => !delegated.includes(scope));\n}\n\ninterface ScopeDenial {\n scopes: string[];\n reason: string;\n why: string;\n}\n\n/**\n * Decide whether a scoped tool call must be denied.\n *\n * When the identity is registry-backed, the registry is authoritative: a\n * delegation may only *narrow* the stored grant, never widen it. Scopes a\n * caller claims that the registry never granted are a forged escalation and are\n * denied before any missing-scope check — otherwise passing an explicit\n * `delegation.scope` could grant access the registry record does not allow.\n */\nfunction resolveScopeDenial(\n claimedScopes: string[],\n requiredScopes: string[],\n registryScopes: string[] | undefined,\n): ScopeDenial | undefined {\n const unauthorized = registryScopes\n ? claimedScopes.filter((scope) => !registryScopes.includes(scope))\n : [];\n if (unauthorized.length > 0) {\n return {\n scopes: unauthorized,\n reason: `unauthorized_scope:${unauthorized.join(',')}`,\n why: `Delegation claims scopes the identity was never granted: ${unauthorized.join(', ')}`,\n };\n }\n\n const missing = missingScopes(claimedScopes, requiredScopes);\n if (missing.length > 0) {\n return {\n scopes: missing,\n reason: `missing_scope:${missing.join(',')}`,\n why: `Missing delegated scopes: ${missing.join(', ')}`,\n };\n }\n\n return undefined;\n}\n\nfunction resolveDelegation(\n definition: Pick<ScopedToolDefinition<unknown>, 'agent' | 'delegation' | 'identityRegistry'>,\n): DelegationContext | undefined {\n const registry = definition.identityRegistry;\n if (registry) {\n registry.assertUsable(definition.agent.id);\n }\n\n return definition.delegation;\n}\n\nfunction buildGovernance(\n governance: GovernanceMetadata | undefined,\n reviewRequired: boolean | undefined,\n): GovernanceMetadata | undefined {\n if (!governance && reviewRequired === undefined) return governance;\n return {\n ...governance,\n ...(reviewRequired !== undefined && { reviewRequired }),\n };\n}\n\nfunction buildDecision(\n input: unknown,\n decision: AgentDecisionMetadata | undefined,\n privacyProfile: PrivacyProfileInput | undefined,\n): AgentDecisionMetadata | undefined {\n if (!decision) return undefined;\n\n const sanitizedInput = sanitizeAuditPayload(input, privacyProfile ?? 'strict');\n return {\n ...decision,\n inputHash: decision.inputHash ?? hashPayload(sanitizedInput),\n };\n}\n\nexport async function withScopedTool<TInput, TOutput>(\n definition: ScopedToolDefinition<TInput>,\n input: TInput,\n fn: AgentHandler<TOutput>,\n options: AgentToolCallOptions & AgentActionOptions = {},\n): Promise<TOutput> {\n const requiredScopes = definition.requiredScopes ?? [];\n const delegation = resolveDelegation(definition);\n const registryScopes = definition.identityRegistry?.getIdentity(\n definition.agent.id,\n )?.scopes;\n const claimedScopes = normalizeScopes(delegation?.scope ?? registryScopes);\n const denial = resolveScopeDenial(\n claimedScopes,\n requiredScopes,\n registryScopes,\n );\n const policy: PolicyMetadata | undefined =\n definition.policyId || definition.riskScore !== undefined || denial\n ? {\n decision: denial ? 'deny' : 'permit',\n ...(definition.policyId !== undefined && {\n policyId: definition.policyId,\n }),\n ...(definition.riskScore !== undefined && {\n riskScore: definition.riskScore,\n }),\n ...(denial && { reason: denial.reason }),\n }\n : undefined;\n\n const governance = buildGovernance(\n definition.governance,\n definition.reviewRequired,\n );\n\n if (policy && policy.decision === 'deny' && denial) {\n recordPolicyDecision(\n {\n action: definition.action,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n policy,\n governance,\n decision: buildDecision(\n input,\n definition.decision,\n definition.privacyProfile,\n ),\n },\n options,\n );\n\n securityEvent(\n {\n name: 'llm.tool_call.denied',\n category: 'llm',\n outcome: 'denied',\n severity: 'warning',\n reason: denial.reason,\n targetType: 'tool',\n targetId: definition.tool.name,\n policyId: definition.policyId,\n },\n { ctx: options.ctx, onMissingContext: options.onMissingContext ?? 'warn' },\n );\n\n throw createStructuredError({\n status: 403,\n code: 'AGENT_SCOPE_DENIED',\n message: `Agent \"${definition.agent.id}\" cannot invoke ${definition.tool.name}.`,\n why: denial.why,\n fix: 'Grant the missing scopes or route the task to an agent with the required delegation.',\n });\n }\n\n if (policy) {\n recordPolicyDecision(\n {\n action: `${definition.action}.policy`,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n policy,\n governance,\n },\n options,\n );\n }\n\n if (definition.decision) {\n recordDecisionBasis(\n {\n action: `${definition.action}.decision`,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n governance,\n decision: buildDecision(\n input,\n definition.decision,\n definition.privacyProfile,\n ),\n },\n options,\n );\n }\n\n return withAgentToolCall(\n {\n action: definition.action,\n resource: definition.resource ?? definition.tool.name,\n category: definition.category,\n agent: definition.agent,\n delegation,\n governance,\n tool: {\n ...definition.tool,\n input,\n },\n },\n fn,\n options,\n );\n}\n","import { securityEvent } from 'autotel-audit';\nimport { resolveContext, toAttributeValue, type AgentContext } from './context.js';\n\n/** Canonical plan-risk attribute keys (Google SAIF plan-risk predictor aligned). */\nexport const AGENT_PLAN_RISK_ATTR = {\n verdict: 'agent.plan.risk.verdict',\n score: 'agent.plan.risk.score',\n categories: 'agent.plan.risk.categories',\n toolSequence: 'agent.plan.risk.tool_sequence',\n} as const;\n\nexport type AgentPlanRiskVerdict = 'low' | 'medium' | 'high' | 'critical';\n\nexport interface AgentPlanClassifierInput {\n /** Proposed tool names in execution order. */\n toolSequence: string[];\n stepIndex?: number;\n summary?: string;\n policyIds?: string[];\n /** Extra context attrs (scopes, intents) — values are coerced for OTel. */\n context?: Record<string, unknown>;\n}\n\nexport interface AgentPlanClassifierResult {\n verdict: AgentPlanRiskVerdict;\n /** 0..1 risk score from the classifier. */\n score?: number;\n categories?: string[];\n reason?: string;\n}\n\nexport type AgentPlanClassifier = (\n input: AgentPlanClassifierInput,\n) =>\n | AgentPlanClassifierResult\n | undefined\n | Promise<AgentPlanClassifierResult | undefined>;\n\nexport interface RecordPlanRiskAssessmentOptions {\n ctx?: AgentContext;\n assessment: AgentPlanClassifierResult;\n toolSequence?: string[];\n /** Emit `llm.plan.risk.elevated` when verdict is not `low`. Default false. */\n emitSecurityEvent?: boolean;\n}\n\nfunction setPlanRiskAttrs(\n ctx: AgentContext | undefined,\n attrs: Record<string, unknown>,\n): void {\n const traceCtx = resolveContext(ctx);\n const mapped: Record<string, string | number | boolean | string[] | number[] | boolean[]> =\n {};\n for (const [key, value] of Object.entries(attrs)) {\n const attr = toAttributeValue(value);\n if (attr !== undefined) {\n mapped[key] = attr;\n }\n }\n if (Object.keys(mapped).length > 0) {\n traceCtx.setAttributes(mapped);\n }\n}\n\n/**\n * Stamp plan-risk assessment attrs on the active span.\n */\nexport function recordPlanRiskAssessment(\n options: RecordPlanRiskAssessmentOptions,\n): void {\n const { assessment, toolSequence } = options;\n setPlanRiskAttrs(options.ctx, {\n [AGENT_PLAN_RISK_ATTR.verdict]: assessment.verdict,\n ...(assessment.score !== undefined && {\n [AGENT_PLAN_RISK_ATTR.score]: assessment.score,\n }),\n ...(assessment.categories?.length && {\n [AGENT_PLAN_RISK_ATTR.categories]: assessment.categories,\n }),\n ...(toolSequence?.length && {\n [AGENT_PLAN_RISK_ATTR.toolSequence]: toolSequence,\n }),\n ...(assessment.reason !== undefined && { 'decision.summary': assessment.reason }),\n });\n\n if (\n options.emitSecurityEvent &&\n assessment.verdict !== 'low'\n ) {\n securityEvent(\n {\n name: 'llm.plan.risk.elevated',\n category: 'llm',\n outcome: assessment.verdict === 'critical' ? 'blocked' : 'denied',\n severity:\n assessment.verdict === 'critical'\n ? 'critical'\n : assessment.verdict === 'high'\n ? 'error'\n : 'warning',\n reason: assessment.reason ?? assessment.verdict,\n ...(assessment.score !== undefined && { score: assessment.score }),\n ...(assessment.categories?.length && {\n categories: assessment.categories.join(','),\n }),\n },\n { ctx: options.ctx },\n );\n }\n}\n\n/**\n * Run a pluggable plan-risk classifier and record its verdict on the span.\n * Classifier failures degrade quietly (no assessment recorded).\n */\nexport async function runAgentPlanClassifier(\n classifier: AgentPlanClassifier,\n input: AgentPlanClassifierInput,\n options: Omit<RecordPlanRiskAssessmentOptions, 'assessment'> = {},\n): Promise<AgentPlanClassifierResult | undefined> {\n let assessment: AgentPlanClassifierResult | undefined;\n try {\n assessment = await classifier(input);\n } catch {\n return undefined;\n }\n if (!assessment) return undefined;\n recordPlanRiskAssessment({\n ...options,\n assessment,\n toolSequence: input.toolSequence,\n });\n return assessment;\n}\n\nconst DESTRUCTIVE_TOOL = /\\b(delete|remove|send|post|transfer|pay|upload|execute)\\b/i;\nconst UNTRUSTED_READ = /\\b(read|fetch|get|search|load|parse|inbox|email|web|scrape)\\b/i;\n\n/**\n * Dependency-free first-pass plan-risk heuristic. Opt-in — pass as\n * `AgentPlanClassifier` or wrap your own Model Armor / Llama Guard adapter.\n */\nexport function heuristicPlanRiskClassifier(): AgentPlanClassifier {\n return ({ toolSequence }) => {\n if (toolSequence.length === 0) {\n return { verdict: 'low', score: 0 };\n }\n\n const normalized = toolSequence.map((name) => name.replaceAll('_', ' '));\n const hasDestructive = normalized.some((name) => DESTRUCTIVE_TOOL.test(name));\n const hasUntrustedRead = normalized.some((name) => UNTRUSTED_READ.test(name));\n\n if (hasDestructive && hasUntrustedRead) {\n return {\n verdict: 'high',\n score: 0.85,\n categories: ['untrusted_to_destructive_chain'],\n reason: 'mixed_untrusted_and_destructive_tools',\n };\n }\n\n if (toolSequence.length >= 8) {\n return {\n verdict: 'medium',\n score: 0.55,\n categories: ['long_tool_chain'],\n reason: 'long_tool_sequence',\n };\n }\n\n return { verdict: 'low', score: 0.1 };\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observer-50RGrqzo.js","names":["otelTrace","otelContext"],"sources":["../src/observer/span-registry.ts","../src/observer/observer.ts","../src/observer/ai-sdk.ts","../src/observer/langchain.ts"],"sourcesContent":["/**\n * Tracks the spans currently open in a {@link createGenAiObserver} stream and\n * the parent each was started under, so the observer can:\n *\n * - look up a parent span when a child starts, and\n * - force-close any descendant whose terminal event never arrived because its\n * parent ended first (an aborted tool call, a cancelled turn, a run that was\n * interrupted). Without this, abandoned spans leak open forever.\n */\n\nimport { SpanStatusCode, type Span, type TimeInput } from '@opentelemetry/api';\n\ninterface Entry {\n span: Span;\n parentId: string | undefined;\n}\n\nexport class SpanRegistry {\n private readonly entries = new Map<string, Entry>();\n\n /** Record an open span and the parent it was started under. */\n add(id: string, span: Span, parentId: string | undefined): void {\n this.entries.set(id, { span, parentId });\n }\n\n /** The open span for `id`, if any (used to parent a starting child). */\n spanFor(id: string): Span | undefined {\n return this.entries.get(id)?.span;\n }\n\n /** Remove and return the open span for `id`. */\n take(id: string): Span | undefined {\n const entry = this.entries.get(id);\n if (!entry) return undefined;\n this.entries.delete(id);\n return entry.span;\n }\n\n /**\n * Close every still-open descendant of `parentId` as ERROR — their terminal\n * event never arrived because the parent ended first. Depth-first, so the\n * deepest leaks close before their own parents.\n */\n reapDescendants(\n parentId: string,\n message: string,\n endTime?: TimeInput,\n ): void {\n // Deleting from a Map during its own for…of is well-defined; recursion only\n // removes deeper descendants (parentId === id), never an unvisited sibling.\n for (const [id, entry] of this.entries) {\n if (entry.parentId !== parentId) continue;\n this.entries.delete(id);\n this.reapDescendants(id, message, endTime);\n entry.span.setStatus({ code: SpanStatusCode.ERROR, message });\n entry.span.end(endTime);\n }\n }\n\n /** Count of spans still open — for tests and leak assertions. */\n get openCount(): number {\n return this.entries.size;\n }\n}\n","/**\n * `createGenAiObserver` — turn a stream of GenAI lifecycle events into a\n * canonical `gen_ai.*` span tree.\n *\n * A complement to {@link traceGenAI}: where the wrapper instruments code you\n * own, the observer instruments a framework that emits its own event stream.\n * Subscribe it once and feed every event through it; it reconstructs the span\n * hierarchy, estimates cost, force-closes abandoned children, and keeps\n * sensitive content off spans unless you opt in.\n *\n * Scope: this adapter records span attributes only. It deliberately does not\n * emit the `gen_ai.*` log events (`inference.operation.details`,\n * `operation.exception`) that `recordInferenceDetails` provides — the source\n * event stream already carries that detail.\n *\n * @example\n * ```ts\n * const observe = createGenAiObserver();\n * observe({ type: 'agent.start', id: 'a1', agent: { name: 'planner' } });\n * observe({ type: 'chat.start', id: 'c1', parentId: 'a1',\n * request: { provider: 'openai', model: 'gpt-4o' } });\n * observe({ type: 'chat.end', id: 'c1',\n * usage: { inputTokens: 412, outputTokens: 87 } });\n * observe({ type: 'agent.end', id: 'a1' });\n * ```\n */\n\nimport {\n context as otelContext,\n SpanKind,\n SpanStatusCode,\n trace as otelTrace,\n type Context,\n type Span,\n type SpanOptions,\n} from '@opentelemetry/api';\nimport {\n genAiAgentAttributes,\n genAiRequestAttributes,\n genAiResponseAttributes,\n genAiToolAttributes,\n genAiUsageAttributes,\n genAiWorkflowAttributes,\n type GenAiAttributeMap,\n} from '../attributes.js';\nimport { estimateLLMCost } from '../cost.js';\nimport { setGenAiContent, type GenAiContentSink } from '../events.js';\nimport { GEN_AI, GEN_AI_OPERATION, genAiSpanName } from '../semconv.js';\nimport {\n recordInputProvenance,\n recordMemoryAccess,\n recordPlanStep,\n recordRenderOutput,\n} from '../agent/agent-security.js';\nimport { agentContextFromSpan } from '../agent/context.js';\nimport { SpanRegistry } from './span-registry.js';\nimport type {\n ChatEndEvent,\n ChatStartEvent,\n GenAiObserver,\n GenAiObserverEvent,\n GenAiObserverOptions,\n SpanEnd,\n InputProvenanceEvent,\n MemoryAccessEvent,\n PlanStepEvent,\n RenderOutputEvent,\n ToolEndEvent,\n ToolStartEvent,\n} from './types.js';\n\nconst ORPHAN_MESSAGE =\n 'Parent ended before this span received its terminal event.';\n\n/** The `*.start` half of the event union — the events that open a span. */\ntype StartEvent = Extract<GenAiObserverEvent, { type: `${string}.start` }>;\n\nexport function createGenAiObserver(\n options: GenAiObserverOptions = {},\n): GenAiObserver {\n const tracer =\n options.tracer ?? otelTrace.getTracer('autotel-genai/observer');\n const registry = new SpanRegistry();\n\n /** Parent context: a tracked parent span, else the resolver, else root. */\n function parentContext(event: StartEvent): Context | undefined {\n const parentSpan = event.parentId\n ? registry.spanFor(event.parentId)\n : undefined;\n if (parentSpan) return otelTrace.setSpan(otelContext.active(), parentSpan);\n return options.resolveParentContext?.(event);\n }\n\n /** Start a span, register it under its parent, and return it. */\n function start(\n event: StartEvent,\n name: string,\n kind: SpanKind,\n attributes: GenAiAttributeMap,\n ): Span {\n const parent = parentContext(event);\n const spanOptions: SpanOptions = {\n kind,\n attributes,\n startTime: event.startTime,\n links: event.links,\n root: parent === undefined,\n };\n const span = tracer.startSpan(name, spanOptions, parent);\n registry.add(event.id, span, event.parentId);\n return span;\n }\n\n /**\n * Close the span for `event.id`: first force-close any descendant whose\n * terminal event never arrived, then decorate, set status, and end.\n */\n function end(event: SpanEnd, decorate?: (span: Span) => void): void {\n const span = registry.take(event.id);\n if (!span) return;\n registry.reapDescendants(event.id, ORPHAN_MESSAGE, event.endTime);\n decorate?.(span);\n if (event.error !== undefined) {\n const message = errorMessage(event.error);\n span.setStatus({ code: SpanStatusCode.ERROR, message });\n // The SDK normalizes a string or Error; hand it the original Error when\n // we have one, otherwise the message we already derived.\n span.recordException(\n event.error instanceof Error ? event.error : (message ?? 'error'),\n );\n }\n span.end(event.endTime);\n }\n\n /** Run the privacy gate; without it, content is always omitted. */\n function approvedContent(\n event: GenAiObserverEvent,\n ): GenAiObserverEvent | undefined {\n if (!options.exportContent) return undefined;\n try {\n return options.exportContent({ ...event });\n } catch (error) {\n console.error('[autotel-genai:observer] exportContent failed:', error);\n return undefined;\n }\n }\n\n function applyChatStart(span: Span, event: ChatStartEvent): void {\n const content = approvedContent(event);\n if (content?.type !== 'chat.start') return;\n setGenAiContent(spanSink(span), {\n inputMessages: content.inputMessages,\n systemInstructions: content.systemInstructions,\n });\n }\n\n function applyChatEnd(span: Span, event: ChatEndEvent): void {\n if (event.response) {\n span.setAttributes(genAiResponseAttributes(event.response));\n }\n if (event.usage) {\n const costModel = event.costModel ?? event.response?.model;\n const costUsd = costModel\n ? estimateLLMCost(costModel, event.usage)\n : undefined;\n span.setAttributes(genAiUsageAttributes({ ...event.usage, costUsd }));\n }\n const content = approvedContent(event);\n if (content?.type === 'chat.end') {\n setGenAiContent(spanSink(span), {\n outputMessages: content.outputMessages,\n });\n }\n }\n\n function applyToolStart(span: Span, event: ToolStartEvent): void {\n const content = approvedContent(event);\n if (content?.type !== 'tool.start') return;\n span.setAttributes(\n genAiToolAttributes({ callArguments: content.callArguments }),\n );\n }\n\n function applyToolEnd(span: Span, event: ToolEndEvent): void {\n const content = approvedContent(event);\n if (content?.type !== 'tool.end') return;\n span.setAttributes(genAiToolAttributes({ callResult: content.callResult }));\n }\n\n function stampOnParent(\n parentId: string,\n apply: (ctx: ReturnType<typeof agentContextFromSpan>) => void,\n ): void {\n const parent = registry.spanFor(parentId);\n if (!parent) return;\n apply(agentContextFromSpan(parent));\n }\n\n return (event: GenAiObserverEvent): void => {\n switch (event.type) {\n case 'workflow.start': {\n start(\n event,\n genAiSpanName(\n GEN_AI_OPERATION.INVOKE_WORKFLOW,\n event.workflow.workflowName,\n ),\n SpanKind.INTERNAL,\n {\n [GEN_AI.OPERATION_NAME]: GEN_AI_OPERATION.INVOKE_WORKFLOW,\n ...genAiWorkflowAttributes(event.workflow),\n },\n );\n return;\n }\n case 'agent.start': {\n const internal = !event.remote;\n start(\n event,\n genAiSpanName(GEN_AI_OPERATION.INVOKE_AGENT, event.agent.name),\n internal ? SpanKind.INTERNAL : SpanKind.CLIENT,\n {\n [GEN_AI.OPERATION_NAME]: GEN_AI_OPERATION.INVOKE_AGENT,\n ...(event.provider\n ? { [GEN_AI.PROVIDER_NAME]: event.provider }\n : {}),\n ...genAiAgentAttributes(event.agent, { internal }),\n },\n );\n return;\n }\n case 'chat.start': {\n const operation = event.request.operation ?? GEN_AI_OPERATION.CHAT;\n const span = start(\n event,\n genAiSpanName(operation, event.request.model),\n SpanKind.CLIENT,\n genAiRequestAttributes({ ...event.request, operation }),\n );\n applyChatStart(span, event);\n return;\n }\n case 'tool.start': {\n const span = start(\n event,\n genAiSpanName(GEN_AI_OPERATION.EXECUTE_TOOL, event.tool.name),\n SpanKind.INTERNAL,\n {\n [GEN_AI.OPERATION_NAME]: GEN_AI_OPERATION.EXECUTE_TOOL,\n ...genAiToolAttributes(event.tool),\n },\n );\n applyToolStart(span, event);\n return;\n }\n case 'workflow.end':\n case 'agent.end': {\n end(event);\n return;\n }\n case 'chat.end': {\n end(event, (span) => applyChatEnd(span, event));\n return;\n }\n case 'tool.end': {\n end(event, (span) => applyToolEnd(span, event));\n return;\n }\n case 'plan.step': {\n stampOnParent(event.parentId, (ctx) =>\n recordPlanStep({\n ctx,\n stepIndex: event.stepIndex,\n toolIntents: event.toolIntents,\n policyIds: event.policyIds,\n summary: event.summary,\n }),\n );\n return;\n }\n case 'input.provenance': {\n stampOnParent(event.parentId, (ctx) =>\n recordInputProvenance({ ctx, provenance: event.provenance }),\n );\n return;\n }\n case 'memory.access': {\n stampOnParent(event.parentId, (ctx) =>\n recordMemoryAccess({\n ctx,\n operation: event.operation,\n isolationKey: event.isolationKey,\n contentHash: event.contentHash,\n }),\n );\n return;\n }\n case 'render.output': {\n stampOnParent(event.parentId, (ctx) =>\n recordRenderOutput({\n ctx,\n format: event.format,\n containsUrl: event.containsUrl,\n urlCount: event.urlCount,\n }),\n );\n return;\n }\n default: {\n const unexpected: never = event;\n void unexpected;\n }\n }\n };\n}\n\n/** A {@link GenAiContentSink} backed by a raw span (only `setAttributes` is used). */\nfunction spanSink(span: Span): GenAiContentSink {\n return {\n setAttributes: (attrs) => {\n span.setAttributes(attrs);\n },\n track: () => {},\n };\n}\n\nfunction errorMessage(error: unknown): string | undefined {\n if (error === undefined) return undefined;\n if (typeof error === 'string') return error || undefined;\n if (error instanceof Error) return error.message;\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n}\n","/**\n * Vercel AI SDK → {@link createGenAiObserver} glue.\n *\n * The AI SDK has no global event stream; its stable surface is the result of a\n * `generateText`/`streamText` call (`steps`, each with `usage`, `toolCalls`,\n * `toolResults`, `response`). {@link observeAiSdkResult} walks that result and\n * emits observer events:\n *\n * - a trivial single-step call with no tools → one `chat` span;\n * - a multi-step or tool-using call → an `invoke_agent` wrapper (mirroring the\n * AI SDK's own `invoke_agent › chat › execute_tool` hierarchy) with a `chat`\n * per step and an `execute_tool` per tool call.\n *\n * Typed structurally against the AI SDK result shape so it pulls in no\n * dependency and tolerates v4/v5 field differences (`promptTokens` vs\n * `inputTokens`). Cost is left to the observer, which prices `chat` usage.\n *\n * @example\n * ```ts\n * const observe = createGenAiObserver();\n * const result = await generateText({ model: openai('gpt-4o'), prompt });\n * observeAiSdkResult(observe, result, { id: 'gen-1', provider: 'openai', model: 'gpt-4o' });\n * ```\n */\n\nimport type { TimeInput } from '@opentelemetry/api';\nimport { normalizeAiSdkProvider } from '../ai-sdk-bridge.js';\nimport type { TokenUsage } from '../cost.js';\nimport type { GenAiProviderName } from '../semconv.js';\nimport type { GenAiObserver } from './types.js';\n\n/** AI SDK usage object — canonical (v5) or legacy (v4) field names. */\nexport interface AiSdkUsage {\n inputTokens?: number;\n outputTokens?: number;\n promptTokens?: number;\n completionTokens?: number;\n reasoningTokens?: number;\n cachedInputTokens?: number;\n}\n\nexport interface AiSdkToolCall {\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n args?: unknown;\n}\n\nexport interface AiSdkToolResult {\n toolCallId?: string;\n toolName?: string;\n output?: unknown;\n result?: unknown;\n}\n\n/** One AI SDK step (also the shape of a single-call result). */\nexport interface AiSdkStep {\n usage?: AiSdkUsage;\n finishReason?: string;\n response?: { id?: string; modelId?: string; timestamp?: Date | number };\n toolCalls?: AiSdkToolCall[];\n toolResults?: AiSdkToolResult[];\n}\n\n/** An AI SDK `generateText`/`streamText` result. */\nexport interface AiSdkResult extends AiSdkStep {\n steps?: AiSdkStep[];\n}\n\nexport interface ObserveAiSdkOptions {\n /** Base span id; per-step and per-tool ids derive from it. */\n id: string;\n parentId?: string;\n /** AI SDK provider id (e.g. `openai`, `amazon-bedrock`); normalized for you. */\n provider?: string;\n /** Request model — used for the span name and as the cost model. */\n model?: string;\n}\n\nconst AI_SDK_AGENT_NAME = 'ai-sdk';\n\nexport function observeAiSdkResult(\n observe: GenAiObserver,\n result: AiSdkResult,\n options: ObserveAiSdkOptions,\n): void {\n const provider: GenAiProviderName | undefined = options.provider\n ? normalizeAiSdkProvider(options.provider)\n : undefined;\n const steps = result.steps ?? [result];\n const toolCount = steps.reduce(\n (total, step) => total + (step.toolCalls?.length ?? 0),\n 0,\n );\n\n if (steps.length <= 1 && toolCount === 0) {\n emitChat(observe, steps[0] ?? result, {\n id: options.id,\n parentId: options.parentId,\n provider,\n model: options.model,\n });\n return;\n }\n\n observe({\n type: 'agent.start',\n id: options.id,\n parentId: options.parentId,\n provider,\n agent: { name: options.model ?? AI_SDK_AGENT_NAME },\n });\n steps.forEach((step, index) => {\n emitChat(observe, step, {\n id: `${options.id}:step:${index}`,\n parentId: options.id,\n provider,\n model: options.model,\n });\n emitTools(observe, step, options.id, index);\n });\n observe({ type: 'agent.end', id: options.id });\n}\n\ninterface ChatContext {\n id: string;\n parentId?: string;\n provider?: GenAiProviderName;\n model?: string;\n}\n\nfunction emitChat(\n observe: GenAiObserver,\n step: AiSdkStep,\n ctx: ChatContext,\n): void {\n observe({\n type: 'chat.start',\n id: ctx.id,\n parentId: ctx.parentId,\n request: { provider: ctx.provider, model: ctx.model },\n });\n const responseModel = step.response?.modelId;\n observe({\n type: 'chat.end',\n id: ctx.id,\n response: {\n model: responseModel,\n id: step.response?.id,\n finishReasons: step.finishReason ? [step.finishReason] : undefined,\n },\n usage: aiSdkUsage(step.usage),\n costModel: ctx.model ?? responseModel,\n endTime: asTimeInput(step.response?.timestamp),\n });\n}\n\nfunction emitTools(\n observe: GenAiObserver,\n step: AiSdkStep,\n parentId: string,\n stepIndex: number,\n): void {\n const results = step.toolResults ?? [];\n (step.toolCalls ?? []).forEach((call, callIndex) => {\n const id = `${parentId}:tool:${call.toolCallId ?? `${stepIndex}.${callIndex}`}`;\n observe({\n type: 'tool.start',\n id,\n parentId,\n tool: { name: call.toolName, callId: call.toolCallId },\n callArguments: call.input ?? call.args,\n });\n const result = call.toolCallId\n ? results.find((r) => r.toolCallId === call.toolCallId)\n : results[callIndex];\n observe({\n type: 'tool.end',\n id,\n callResult: result?.output ?? result?.result,\n });\n });\n}\n\nfunction aiSdkUsage(usage?: AiSdkUsage): TokenUsage | undefined {\n if (!usage) return undefined;\n const tokenUsage: TokenUsage = {\n inputTokens: usage.inputTokens ?? usage.promptTokens,\n outputTokens: usage.outputTokens ?? usage.completionTokens,\n reasoningOutputTokens: usage.reasoningTokens,\n cacheReadInputTokens: usage.cachedInputTokens,\n };\n return Object.values(tokenUsage).some((v) => v !== undefined)\n ? tokenUsage\n : undefined;\n}\n\nfunction asTimeInput(value: Date | number | undefined): TimeInput | undefined {\n return value instanceof Date || typeof value === 'number' ? value : undefined;\n}\n","/**\n * LangChain / LangGraph → {@link createGenAiObserver} glue.\n *\n * LangChain's callback system is a real event stream: register one handler and\n * it receives every run's start/end/error with a `runId` and `parentRunId` —\n * which map directly onto the observer's `id` / `parentId`. {@link\n * createLangChainObserver} returns a handler object you pass to `callbacks`:\n *\n * - chain runs (LangGraph nodes, agents) → `invoke_agent` spans;\n * - LLM / chat-model runs → `chat` spans (with usage and estimated cost);\n * - tool runs → `execute_tool` spans.\n *\n * Typed structurally against the callback payloads so it pulls in no LangChain\n * dependency. Pass it via `{ callbacks: [createLangChainObserver(observe)] }`.\n *\n * @example\n * ```ts\n * const observe = createGenAiObserver();\n * await graph.invoke(input, { callbacks: [createLangChainObserver(observe)] });\n * ```\n */\n\nimport { normalizeAiSdkProvider } from '../ai-sdk-bridge.js';\nimport type { TokenUsage } from '../cost.js';\nimport type { GenAiObserver } from './types.js';\n\n/** LangChain `Serialized` — the identity of a chain/LLM/tool. */\ninterface Serialized {\n id?: string[];\n name?: string;\n kwargs?: Record<string, unknown>;\n}\n\ninterface LLMGeneration {\n generationInfo?: Record<string, unknown>;\n message?: {\n usage_metadata?: Record<string, unknown>;\n response_metadata?: Record<string, unknown>;\n };\n}\n\n/** LangChain `LLMResult` — what an LLM/chat-model run returns. */\ninterface LLMResult {\n generations?: LLMGeneration[][];\n llmOutput?: Record<string, unknown>;\n}\n\n/** The subset of LangChain's `CallbackHandlerMethods` this adapter implements. */\nexport interface LangChainObserverHandler {\n handleChainStart(\n chain: Serialized,\n inputs: unknown,\n runId: string,\n parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n runType?: string,\n runName?: string,\n ): void;\n handleChainEnd(outputs: unknown, runId: string): void;\n handleChainError(error: unknown, runId: string): void;\n handleLLMStart(\n llm: Serialized,\n prompts: string[],\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, unknown>,\n ): void;\n handleChatModelStart(\n llm: Serialized,\n messages: unknown,\n runId: string,\n parentRunId?: string,\n extraParams?: Record<string, unknown>,\n ): void;\n handleLLMEnd(output: LLMResult, runId: string): void;\n handleLLMError(error: unknown, runId: string): void;\n handleToolStart(\n tool: Serialized,\n input: string,\n runId: string,\n parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n runName?: string,\n ): void;\n handleToolEnd(output: unknown, runId: string): void;\n handleToolError(error: unknown, runId: string): void;\n}\n\nexport interface LangChainObserverOptions {\n /**\n * Decide whether a chain run becomes an `invoke_agent` span. The default\n * skips LangChain/LangGraph plumbing (Runnable*, ChannelWrite, Branch,\n * prompts, `__start__`/`__end__`) so only the graph and its named nodes show;\n * children of a skipped chain reparent to the nearest kept ancestor.\n */\n skipChain?: (name: string) => boolean;\n}\n\n/** LangChain/LangGraph structural runnables that are noise, not real steps. */\nconst PLUMBING_CHAIN = /^(Runnable|Channel|Branch|Prompt|ChatPrompt|__)/i;\n\nexport function createLangChainObserver(\n observe: GenAiObserver,\n options: LangChainObserverOptions = {},\n): LangChainObserverHandler {\n const skipChain = options.skipChain ?? ((name) => PLUMBING_CHAIN.test(name));\n // Remember each LLM run's request model so `chat.end` can price it — the end\n // payload doesn't reliably carry the model. Cleared on end and error.\n const models = new Map<string, string>();\n // Skipped chains record the kept ancestor their children should parent to.\n const reparented = new Map<string, string | undefined>();\n\n /** The span id a child of `runId` should use as its parent. */\n function keptParent(runId: string | undefined): string | undefined {\n if (runId === undefined) return undefined;\n return reparented.has(runId) ? reparented.get(runId) : runId;\n }\n\n function startChat(\n llm: Serialized,\n runId: string,\n parentRunId: string | undefined,\n extraParams: Record<string, unknown> | undefined,\n ): void {\n const model = langChainModel(llm, extraParams);\n if (model) models.set(runId, model);\n observe({\n type: 'chat.start',\n id: runId,\n parentId: keptParent(parentRunId),\n request: { provider: langChainProvider(llm), model },\n });\n }\n\n return {\n handleChainStart(\n chain,\n _inputs,\n runId,\n parentRunId,\n _tags,\n _metadata,\n _runType,\n runName,\n ) {\n const name = runName ?? lastIdSegment(chain) ?? 'chain';\n const parentId = keptParent(parentRunId);\n if (skipChain(name)) {\n reparented.set(runId, parentId);\n return;\n }\n observe({ type: 'agent.start', id: runId, parentId, agent: { name } });\n },\n handleChainEnd(_outputs, runId) {\n if (reparented.delete(runId)) return;\n observe({ type: 'agent.end', id: runId });\n },\n handleChainError(error, runId) {\n if (reparented.delete(runId)) return;\n observe({ type: 'agent.end', id: runId, error });\n },\n\n handleLLMStart(llm, _prompts, runId, parentRunId, extraParams) {\n startChat(llm, runId, parentRunId, extraParams);\n },\n handleChatModelStart(llm, _messages, runId, parentRunId, extraParams) {\n startChat(llm, runId, parentRunId, extraParams);\n },\n handleLLMEnd(output, runId) {\n const costModel = models.get(runId);\n models.delete(runId);\n observe({\n type: 'chat.end',\n id: runId,\n response: { finishReasons: finishReasons(output) },\n usage: langChainUsage(output),\n costModel,\n });\n },\n handleLLMError(error, runId) {\n models.delete(runId);\n observe({ type: 'chat.end', id: runId, error });\n },\n\n handleToolStart(\n tool,\n input,\n runId,\n parentRunId,\n _tags,\n _metadata,\n runName,\n ) {\n observe({\n type: 'tool.start',\n id: runId,\n parentId: keptParent(parentRunId),\n tool: { name: runName ?? lastIdSegment(tool) },\n callArguments: input,\n });\n },\n handleToolEnd(output, runId) {\n observe({ type: 'tool.end', id: runId, callResult: output });\n },\n handleToolError(error, runId) {\n observe({ type: 'tool.end', id: runId, error });\n },\n };\n}\n\n/**\n * Provider from a `Serialized.id` path. LangChain serializes a chat model as\n * `[...namespace, provider, ClassName]` (e.g. `…, 'openai', 'ChatOpenAI'`), so\n * the provider is the lowercase module segment before the PascalCase class.\n */\nfunction langChainProvider(serialized: Serialized): string | undefined {\n const candidate = serialized.id?.at(-2);\n return candidate && candidate === candidate.toLowerCase()\n ? normalizeAiSdkProvider(candidate)\n : undefined;\n}\n\nfunction langChainModel(\n serialized: Serialized,\n extraParams: Record<string, unknown> | undefined,\n): string | undefined {\n const invocation = asRecord(extraParams?.invocation_params);\n return (\n str(invocation?.model) ??\n str(invocation?.model_name) ??\n str(serialized.kwargs?.model) ??\n str(serialized.kwargs?.model_name)\n );\n}\n\nfunction langChainUsage(output: LLMResult): TokenUsage | undefined {\n // `usage_metadata` is LangChain's canonical cross-provider shape (Ollama,\n // newer integrations); `llmOutput.tokenUsage` is OpenAI; `llmOutput.usage`\n // is Anthropic-style.\n const usageMetadata = asRecord(\n firstGeneration(output)?.message?.usage_metadata,\n );\n const tokenUsage = asRecord(output.llmOutput?.tokenUsage);\n const usage = asRecord(output.llmOutput?.usage);\n const inputTokens =\n num(usageMetadata?.input_tokens) ??\n num(tokenUsage?.promptTokens) ??\n num(usage?.input_tokens);\n const outputTokens =\n num(usageMetadata?.output_tokens) ??\n num(tokenUsage?.completionTokens) ??\n num(usage?.output_tokens);\n if (inputTokens === undefined && outputTokens === undefined) return undefined;\n return { inputTokens, outputTokens };\n}\n\nfunction finishReasons(output: LLMResult): string[] | undefined {\n const generation = firstGeneration(output);\n const reason =\n str(generation?.generationInfo?.finish_reason) ??\n str(asRecord(generation?.message?.response_metadata)?.done_reason);\n return reason ? [reason] : undefined;\n}\n\nfunction firstGeneration(output: LLMResult): LLMGeneration | undefined {\n return output.generations?.[0]?.[0];\n}\n\nfunction lastIdSegment(serialized: Serialized): string | undefined {\n return serialized.name ?? serialized.id?.at(-1);\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction num(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value)\n ? value\n : undefined;\n}\n"],"mappings":"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"}
|