@posthog/mcp 0.10.7 → 0.10.8

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.
Files changed (41) hide show
  1. package/dist/extensions/analytics-parameters.d.ts +7 -2
  2. package/dist/extensions/analytics-parameters.d.ts.map +1 -1
  3. package/dist/extensions/analytics-parameters.js +4 -2
  4. package/dist/extensions/analytics-parameters.mjs +4 -2
  5. package/dist/extensions/conversation-id.d.ts +37 -8
  6. package/dist/extensions/conversation-id.d.ts.map +1 -1
  7. package/dist/extensions/conversation-id.js +8 -13
  8. package/dist/extensions/conversation-id.mjs +8 -13
  9. package/dist/extensions/instrument-highlevel.d.ts.map +1 -1
  10. package/dist/extensions/instrument-highlevel.js +1 -1
  11. package/dist/extensions/instrument-highlevel.mjs +1 -1
  12. package/dist/extensions/instrumentation.d.ts.map +1 -1
  13. package/dist/extensions/instrumentation.js +35 -16
  14. package/dist/extensions/instrumentation.mjs +35 -16
  15. package/dist/extensions/internal.d.ts +8 -1
  16. package/dist/extensions/internal.d.ts.map +1 -1
  17. package/dist/extensions/internal.js +2 -2
  18. package/dist/extensions/internal.mjs +2 -2
  19. package/dist/extensions/output-instructions.d.ts +70 -0
  20. package/dist/extensions/output-instructions.d.ts.map +1 -0
  21. package/dist/extensions/output-instructions.js +131 -0
  22. package/dist/extensions/output-instructions.mjs +82 -0
  23. package/dist/extensions/session.d.ts +26 -5
  24. package/dist/extensions/session.d.ts.map +1 -1
  25. package/dist/extensions/session.js +32 -14
  26. package/dist/extensions/session.mjs +30 -15
  27. package/dist/types.d.ts +23 -1
  28. package/dist/types.d.ts.map +1 -1
  29. package/dist/version.d.ts +1 -1
  30. package/dist/version.js +1 -1
  31. package/dist/version.mjs +1 -1
  32. package/package.json +4 -4
  33. package/src/extensions/analytics-parameters.ts +15 -2
  34. package/src/extensions/conversation-id.ts +51 -29
  35. package/src/extensions/instrument-highlevel.ts +3 -1
  36. package/src/extensions/instrumentation.ts +77 -29
  37. package/src/extensions/internal.ts +10 -2
  38. package/src/extensions/output-instructions.ts +231 -0
  39. package/src/extensions/session.ts +127 -28
  40. package/src/types.ts +23 -1
  41. package/src/version.ts +1 -1
@@ -12,6 +12,11 @@ export interface AnalyticsInjectableJsonSchema {
12
12
  export declare function hasAnalyticsParameter(schema: AnalyticsInjectableJsonSchema | undefined, parameterName: string): boolean;
13
13
  export declare function canInjectAnalyticsParameter(schema: AnalyticsInjectableJsonSchema | undefined, parameterName: string): boolean;
14
14
  export declare function analyticsOwnsParameter(inputSchema: unknown, parameterName: string): boolean;
15
- export declare function getAnalyticsParameterOwnership(inputSchema: unknown): AnalyticsParameterOwnership;
16
- export declare function stripOwnedAnalyticsArguments(args: unknown, ownership: AnalyticsParameterOwnership): unknown;
15
+ export declare function getAnalyticsParameterOwnership(inputSchema: unknown, outputSchema?: unknown): AnalyticsParameterOwnership;
16
+ /**
17
+ * Removes the arguments we injected, leaving the host's own. Input-side only, so
18
+ * it takes just those two flags rather than the whole ownership record — callers
19
+ * that have no output-schema context should not have to invent a value for it.
20
+ */
21
+ export declare function stripOwnedAnalyticsArguments(args: unknown, ownership: Pick<AnalyticsParameterOwnership, 'context' | 'conversationId'>): unknown;
17
22
  //# sourceMappingURL=analytics-parameters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/analytics-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAA;AAgB3D,MAAM,WAAW,6BAA6B;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAET;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAyB3F;AAED,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,OAAO,GAAG,2BAA2B,CAKhG;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,2BAA2B,GAAG,OAAO,CAW3G"}
1
+ {"version":3,"file":"analytics-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/analytics-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAA;AAiB3D,MAAM,WAAW,6BAA6B;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAET;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAyB3F;AAED,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,OAAO,EACpB,YAAY,CAAC,EAAE,OAAO,GACrB,2BAA2B,CAM7B;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,IAAI,CAAC,2BAA2B,EAAE,SAAS,GAAG,gBAAgB,CAAC,GACzE,OAAO,CAWT"}
@@ -31,6 +31,7 @@ __webpack_require__.d(__webpack_exports__, {
31
31
  stripOwnedAnalyticsArguments: ()=>stripOwnedAnalyticsArguments
32
32
  });
33
33
  const external_mcp_sdk_compat_js_namespaceObject = require("./mcp-sdk-compat.js");
34
+ const external_output_instructions_js_namespaceObject = require("./output-instructions.js");
34
35
  const JSON_SCHEMA_KEYWORDS = [
35
36
  '$defs',
36
37
  '$ref',
@@ -63,10 +64,11 @@ function analyticsOwnsParameter(inputSchema, parameterName) {
63
64
  if ('_def' in schema || '_zod' in schema || '~standard' in schema) return canInjectAnalyticsParameter(void 0, parameterName);
64
65
  return canInjectAnalyticsParameter(schema, parameterName);
65
66
  }
66
- function getAnalyticsParameterOwnership(inputSchema) {
67
+ function getAnalyticsParameterOwnership(inputSchema, outputSchema) {
67
68
  return {
68
69
  context: analyticsOwnsParameter(inputSchema, 'context'),
69
- conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id')
70
+ conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id'),
71
+ outputInstructions: (0, external_output_instructions_js_namespaceObject.canDeclareOutputInstructions)(outputSchema)
70
72
  };
71
73
  }
72
74
  function stripOwnedAnalyticsArguments(args, ownership) {
@@ -1,4 +1,5 @@
1
1
  import { getObjectShape, isZodRawShapeCompat } from "./mcp-sdk-compat.mjs";
2
+ import { canDeclareOutputInstructions } from "./output-instructions.mjs";
2
3
  const JSON_SCHEMA_KEYWORDS = [
3
4
  '$defs',
4
5
  '$ref',
@@ -31,10 +32,11 @@ function analyticsOwnsParameter(inputSchema, parameterName) {
31
32
  if ('_def' in schema || '_zod' in schema || '~standard' in schema) return canInjectAnalyticsParameter(void 0, parameterName);
32
33
  return canInjectAnalyticsParameter(schema, parameterName);
33
34
  }
34
- function getAnalyticsParameterOwnership(inputSchema) {
35
+ function getAnalyticsParameterOwnership(inputSchema, outputSchema) {
35
36
  return {
36
37
  context: analyticsOwnsParameter(inputSchema, 'context'),
37
- conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id')
38
+ conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id'),
39
+ outputInstructions: canDeclareOutputInstructions(outputSchema)
38
40
  };
39
41
  }
40
42
  function stripOwnedAnalyticsArguments(args, ownership) {
@@ -7,7 +7,13 @@ export interface ConversationIdInjectableTool {
7
7
  [key: string]: unknown;
8
8
  }
9
9
  export declare function addConversationIdToTool<TTool extends ConversationIdInjectableTool>(tool: TTool, logger?: LoggerFn): TTool;
10
- export declare function addConversationIdToTools<TTool extends ConversationIdInjectableTool>(tools: TTool[], missingCapabilityToolName?: string, skipMissingCapabilityTool?: boolean, logger?: LoggerFn): TTool[];
10
+ /**
11
+ * Injects `conversation_id` across a tool listing, including the virtual
12
+ * `get_more_tools` tool. Its calls publish `$mcp_missing_capability`, and a
13
+ * capability gap is only meaningful next to the work that hit it — so it belongs
14
+ * in the same session as the surrounding tool calls.
15
+ */
16
+ export declare function addConversationIdToTools<TTool extends ConversationIdInjectableTool>(tools: TTool[], logger?: LoggerFn): TTool[];
11
17
  export type ConversationIdResolution = {
12
18
  minted: false;
13
19
  conversationId: string | undefined;
@@ -17,15 +23,38 @@ export type ConversationIdResolution = {
17
23
  };
18
24
  /**
19
25
  * Decides which conversation_id to use for a tool call:
20
- * - disabled or get_more_tools → none
21
- * - agent supplied a value → use it
22
- * - agent omitted → mint a UUID
26
+ * - disabled → none
27
+ * - agent echoed a handle we could have minted → use it
28
+ * - anything else → mint a fresh one
29
+ *
30
+ * The shape check matters because this value becomes `$session_id`, and the
31
+ * derivation is deterministic so that two pods agree — which also means two
32
+ * *callers* sending the same string land in the same session. The strings agents
33
+ * invent are not random (`conv-1`, `1`, `session`), so trusting them verbatim
34
+ * would silently merge unrelated conversations, potentially across users.
35
+ *
36
+ * A compliant agent echoes the uuidv7 we minted and is unaffected. Anything else
37
+ * is treated exactly as if the handle were absent: mint, and prompt back. Shape
38
+ * rather than a registry of issued ids, because a per-request server has no
39
+ * memory of what it minted.
40
+ *
41
+ * This narrows the problem, it does not prove provenance: a caller supplying a
42
+ * well-formed uuidv7 is trusted, so two that pick the *same* one still merge. That
43
+ * residue is far smaller than the case it replaces — an agent ignoring the
44
+ * parameter description reaches for `conv-1` or `1`, not a conforming uuidv7 — and
45
+ * closing it needs a signed handle, i.e. a secret shared by every pod. Worth doing
46
+ * if this ever anchors something security-bearing; `$session_id` is an analytics
47
+ * grouping key, so it does not today.
23
48
  */
24
- export declare function resolveConversationId(enabled: boolean, args: unknown, toolName: string | undefined, missingCapabilityToolName?: string): ConversationIdResolution;
49
+ export declare function resolveConversationId(enabled: boolean, args: unknown): ConversationIdResolution;
25
50
  /**
26
- * Predicate matching the same eligibility checks injectConversationIdPromptBack uses,
27
- * exposed so callers can pre-decide whether the prompt-back will actually land
28
- * (and clear event.conversationId if not, to avoid orphan ids in analytics).
51
+ * Whether the prompt-back can ride this result's `content`. The only requirement
52
+ * is an array to append to.
53
+ *
54
+ * Errored results included on purpose. A tool that fails on the first call of a
55
+ * conversation is exactly when the agent needs the session handle: without it the
56
+ * retry starts a fresh conversation, so the failure and its fix land in different
57
+ * sessions.
29
58
  */
30
59
  export declare function canInjectConversationIdPromptBack(result: unknown): boolean;
31
60
  export declare function extractConversationId(args: unknown): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-id.d.ts","sourceRoot":"","sources":["../../src/extensions/conversation-id.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,6BAA6B,EACnC,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAG7C,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,4BAA4B,EAChF,IAAI,EAAE,KAAK,EACX,MAAM,GAAE,QAAc,GACrB,KAAK,CA4CP;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,4BAA4B,EACjF,KAAK,EAAE,KAAK,EAAE,EACd,yBAAyB,GAAE,MAA4B,EACvD,yBAAyB,UAAO,EAChC,MAAM,GAAE,QAAc,GACrB,KAAK,EAAE,CAOT;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,yBAAyB,GAAE,MAA4B,GACtD,wBAAwB,CAS1B;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAS1E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAUvE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG;IACrE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAKA;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAS/F"}
1
+ {"version":3,"file":"conversation-id.d.ts","sourceRoot":"","sources":["../../src/extensions/conversation-id.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,6BAA6B,EACnC,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE7C,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,4BAA4B,EAChF,IAAI,EAAE,KAAK,EACX,MAAM,GAAE,QAAc,GACrB,KAAK,CA4CP;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,4BAA4B,EACjF,KAAK,EAAE,KAAK,EAAE,EACd,MAAM,GAAE,QAAc,GACrB,KAAK,EAAE,CAET;AAQD,MAAM,MAAM,wBAAwB,GAChC;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,wBAAwB,CAa/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAK1E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAUvE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG;IACrE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAKA;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAS/F"}
@@ -38,7 +38,6 @@ const core_namespaceObject = require("@posthog/core");
38
38
  const external_analytics_parameters_js_namespaceObject = require("./analytics-parameters.js");
39
39
  const external_constants_js_namespaceObject = require("./constants.js");
40
40
  const external_logger_js_namespaceObject = require("./logger.js");
41
- const external_tools_js_namespaceObject = require("./tools.js");
42
41
  const CONVERSATION_ID_PARAM_NAME = 'conversation_id';
43
42
  function addConversationIdToTool(tool, logger = external_logger_js_namespaceObject.log) {
44
43
  const modifiedTool = {
@@ -65,21 +64,19 @@ function addConversationIdToTool(tool, logger = external_logger_js_namespaceObje
65
64
  };
66
65
  return modifiedTool;
67
66
  }
68
- function addConversationIdToTools(tools, missingCapabilityToolName = external_tools_js_namespaceObject.GET_MORE_TOOLS_NAME, skipMissingCapabilityTool = true, logger = external_logger_js_namespaceObject.log) {
69
- return tools.map((tool)=>{
70
- if (skipMissingCapabilityTool && tool.name === missingCapabilityToolName) return tool;
71
- return addConversationIdToTool(tool, logger);
72
- });
67
+ function addConversationIdToTools(tools, logger = external_logger_js_namespaceObject.log) {
68
+ return tools.map((tool)=>addConversationIdToTool(tool, logger));
73
69
  }
74
- function resolveConversationId(enabled, args, toolName, missingCapabilityToolName = external_tools_js_namespaceObject.GET_MORE_TOOLS_NAME) {
75
- if (!enabled || toolName === missingCapabilityToolName) return {
70
+ const MINTED_CONVERSATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
71
+ function resolveConversationId(enabled, args) {
72
+ if (!enabled) return {
76
73
  minted: false,
77
74
  conversationId: void 0
78
75
  };
79
76
  const supplied = extractConversationId(args);
80
- if (supplied) return {
77
+ if (supplied && MINTED_CONVERSATION_ID.test(supplied)) return {
81
78
  minted: false,
82
- conversationId: supplied
79
+ conversationId: supplied.toLowerCase()
83
80
  };
84
81
  return {
85
82
  minted: true,
@@ -88,9 +85,7 @@ function resolveConversationId(enabled, args, toolName, missingCapabilityToolNam
88
85
  }
89
86
  function canInjectConversationIdPromptBack(result) {
90
87
  if (!(result && 'object' == typeof result)) return false;
91
- const resultObj = result;
92
- if (true === resultObj.isError) return false;
93
- return Array.isArray(resultObj.content);
88
+ return Array.isArray(result.content);
94
89
  }
95
90
  function extractConversationId(args) {
96
91
  if (!(args && 'object' == typeof args)) return;
@@ -2,7 +2,6 @@ import { uuidv7 } from "@posthog/core";
2
2
  import { canInjectAnalyticsParameter, hasAnalyticsParameter } from "./analytics-parameters.mjs";
3
3
  import { DEFAULT_CONVERSATION_ID_DESCRIPTION } from "./constants.mjs";
4
4
  import { log } from "./logger.mjs";
5
- import { GET_MORE_TOOLS_NAME } from "./tools.mjs";
6
5
  const CONVERSATION_ID_PARAM_NAME = 'conversation_id';
7
6
  function addConversationIdToTool(tool, logger = log) {
8
7
  const modifiedTool = {
@@ -29,21 +28,19 @@ function addConversationIdToTool(tool, logger = log) {
29
28
  };
30
29
  return modifiedTool;
31
30
  }
32
- function addConversationIdToTools(tools, missingCapabilityToolName = GET_MORE_TOOLS_NAME, skipMissingCapabilityTool = true, logger = log) {
33
- return tools.map((tool)=>{
34
- if (skipMissingCapabilityTool && tool.name === missingCapabilityToolName) return tool;
35
- return addConversationIdToTool(tool, logger);
36
- });
31
+ function addConversationIdToTools(tools, logger = log) {
32
+ return tools.map((tool)=>addConversationIdToTool(tool, logger));
37
33
  }
38
- function resolveConversationId(enabled, args, toolName, missingCapabilityToolName = GET_MORE_TOOLS_NAME) {
39
- if (!enabled || toolName === missingCapabilityToolName) return {
34
+ const MINTED_CONVERSATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
35
+ function resolveConversationId(enabled, args) {
36
+ if (!enabled) return {
40
37
  minted: false,
41
38
  conversationId: void 0
42
39
  };
43
40
  const supplied = extractConversationId(args);
44
- if (supplied) return {
41
+ if (supplied && MINTED_CONVERSATION_ID.test(supplied)) return {
45
42
  minted: false,
46
- conversationId: supplied
43
+ conversationId: supplied.toLowerCase()
47
44
  };
48
45
  return {
49
46
  minted: true,
@@ -52,9 +49,7 @@ function resolveConversationId(enabled, args, toolName, missingCapabilityToolNam
52
49
  }
53
50
  function canInjectConversationIdPromptBack(result) {
54
51
  if (!(result && 'object' == typeof result)) return false;
55
- const resultObj = result;
56
- if (true === resultObj.isError) return false;
57
- return Array.isArray(resultObj.content);
52
+ return Array.isArray(result.content);
58
53
  }
59
54
  function extractConversationId(args) {
60
55
  if (!(args && 'object' == typeof args)) return;
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,sBAAsB,EAIvB,MAAM,UAAU,CAAA;AASjB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AA8PxC,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA2BhG"}
1
+ {"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,sBAAsB,EAIvB,MAAM,UAAU,CAAA;AASjB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAgQxC,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA2BhG"}
@@ -177,7 +177,7 @@ async function handleToolCallRequest(highLevelServer, server, originalCallToolHa
177
177
  request,
178
178
  extra,
179
179
  execute: (downstreamRequest)=>originalCallToolHandler(downstreamRequest, extra),
180
- parameterOwnership: registeredTool ? (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(registeredTool.inputSchema) : void 0,
180
+ parameterOwnership: registeredTool ? (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(registeredTool.inputSchema, registeredTool.outputSchema) : void 0,
181
181
  takeCapturedError: ()=>{
182
182
  const captured = extra?.__mcp_analytics_error;
183
183
  if (extra) extra.__mcp_analytics_error = void 0;
@@ -149,7 +149,7 @@ async function handleToolCallRequest(highLevelServer, server, originalCallToolHa
149
149
  request,
150
150
  extra,
151
151
  execute: (downstreamRequest)=>originalCallToolHandler(downstreamRequest, extra),
152
- parameterOwnership: registeredTool ? getAnalyticsParameterOwnership(registeredTool.inputSchema) : void 0,
152
+ parameterOwnership: registeredTool ? getAnalyticsParameterOwnership(registeredTool.inputSchema, registeredTool.outputSchema) : void 0,
153
153
  takeCapturedError: ()=>{
154
154
  const captured = extra?.__mcp_analytics_error;
155
155
  if (extra) extra.__mcp_analytics_error = void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,7 @@ const external_analytics_parameters_js_namespaceObject = require("./analytics-pa
37
37
  const external_context_parameters_js_namespaceObject = require("./context-parameters.js");
38
38
  const external_conversation_id_js_namespaceObject = require("./conversation-id.js");
39
39
  const external_client_identity_js_namespaceObject = require("./client-identity.js");
40
+ const external_output_instructions_js_namespaceObject = require("./output-instructions.js");
40
41
  const external_capture_js_namespaceObject = require("./capture.js");
41
42
  const external_event_types_js_namespaceObject = require("./event-types.js");
42
43
  const external_exceptions_js_namespaceObject = require("./exceptions.js");
@@ -52,7 +53,7 @@ async function captureToolCall(params) {
52
53
  const { server, data, request, extra, execute, parameterOwnership, eventType, explicitContextIntent, takeCapturedError } = params;
53
54
  const resolvedEventType = eventType ?? external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpToolsCall;
54
55
  const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership, resolvedEventType === external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability);
55
- const conversation = (0, external_conversation_id_js_namespaceObject.resolveConversationId)(ownership.conversationId, request.params?.arguments, request.params?.name, resolvedEventType === external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability ? (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options) : '');
56
+ const conversation = (0, external_conversation_id_js_namespaceObject.resolveConversationId)(ownership.conversationId, request.params?.arguments);
56
57
  const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership);
57
58
  const startTime = new Date();
58
59
  const preparedEvent = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType);
@@ -64,15 +65,17 @@ async function captureToolCall(params) {
64
65
  publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, data.logger);
65
66
  throw error;
66
67
  }
67
- const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation);
68
+ const finalResult = applyConversationInstructions(preparedEvent?.event ?? null, result, conversation, ownership);
68
69
  publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError);
69
70
  return finalResult;
70
71
  }
71
72
  function getActiveAnalyticsParameterOwnership(data, toolName, override, isMissingCapabilityTool) {
72
- const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0);
73
+ const listed = toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0;
74
+ const ownership = override ?? listed;
73
75
  return {
74
76
  context: !isMissingCapabilityTool && (0, external_context_parameters_js_namespaceObject.isContextEnabled)(data.options.context) && ownership?.context === true,
75
- conversationId: !isMissingCapabilityTool && true === data.options.enableConversationId && ownership?.conversationId === true
77
+ conversationId: true === data.options.enableConversationId && ownership?.conversationId === true,
78
+ outputInstructions: true === data.options.enableConversationId && listed?.outputInstructions === true
76
79
  };
77
80
  }
78
81
  function cloneRequestWithoutOwnedAnalyticsArguments(request, ownership) {
@@ -89,9 +92,9 @@ function cloneRequestWithoutOwnedAnalyticsArguments(request, ownership) {
89
92
  }
90
93
  async function prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, eventType) {
91
94
  try {
92
- const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra);
95
+ const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra, conversation.conversationId);
93
96
  const sessionInfo = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId);
94
- const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, sessionInfo, extra);
97
+ const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, sessionInfo, extra, !!conversation.conversationId);
95
98
  const requestAttribution = (0, external_internal_js_namespaceObject.withIdentity)(sessionInfo, identity);
96
99
  const toolName = request.params?.name;
97
100
  const event = {
@@ -116,11 +119,22 @@ async function prepareToolCallEvent(server, data, request, downstreamRequest, ex
116
119
  return null;
117
120
  }
118
121
  }
119
- function applyConversationPromptBack(event, result, conversation) {
120
- if (!conversation.minted) return result;
121
- if ((0, external_conversation_id_js_namespaceObject.canInjectConversationIdPromptBack)(result)) return (0, external_conversation_id_js_namespaceObject.injectConversationIdPromptBack)(result, conversation.conversationId);
122
- if (event) event.conversationId = void 0;
123
- return result;
122
+ function applyConversationInstructions(event, result, conversation, ownership) {
123
+ const conversationId = conversation.conversationId;
124
+ if (!conversationId) return result;
125
+ let updated = result;
126
+ let delivered = false;
127
+ if (ownership.outputInstructions) {
128
+ const mirrored = (0, external_output_instructions_js_namespaceObject.mirrorInstructionsIntoStructuredContent)(updated, conversationId);
129
+ delivered = mirrored !== updated;
130
+ updated = mirrored;
131
+ }
132
+ if (conversation.minted && (0, external_conversation_id_js_namespaceObject.canInjectConversationIdPromptBack)(updated)) {
133
+ updated = (0, external_conversation_id_js_namespaceObject.injectConversationIdPromptBack)(updated, conversationId);
134
+ delivered = true;
135
+ }
136
+ if (!delivered && conversation.minted && event) event.conversationId = void 0;
137
+ return updated;
124
138
  }
125
139
  function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) {
126
140
  if (!preparedEvent) return;
@@ -240,7 +254,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
240
254
  };
241
255
  }
242
256
  function cacheToolAnalyticsParameterOwnership(cache, tools) {
243
- for (const tool of tools)if (tool?.name) cache.set(tool.name, (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(tool.inputSchema));
257
+ for (const tool of tools)if (tool?.name) cache.set(tool.name, (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(tool.inputSchema, tool.outputSchema));
244
258
  }
245
259
  function collectListedToolNames(tools) {
246
260
  if (!tools || 0 === tools.length) return;
@@ -258,16 +272,21 @@ async function getTracedToolsList(server, originalListToolsHandler, request, ext
258
272
  if (data && (0, external_context_parameters_js_namespaceObject.isContextEnabled)(data.options.context)) tools = (0, external_context_parameters_js_namespaceObject.addContextParameterToTools)(tools, (0, external_context_parameters_js_namespaceObject.getContextDescription)(data.options.context), data.logger);
259
273
  if (data) {
260
274
  const missingToolName = (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options);
261
- let injectedMissingCapabilityTool = false;
262
275
  if (data.options.reportMissing) {
263
276
  const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
264
277
  if (alreadyPresent) data.logger(`Warning: Cannot inject missing-capability tool "${missingToolName}" because a real tool already uses that name. The real tool will not be intercepted.`);
265
278
  else {
266
- tools.push((0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(missingToolName));
267
- injectedMissingCapabilityTool = true;
279
+ const virtualTool = (0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(missingToolName);
280
+ tools.push(virtualTool);
281
+ cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [
282
+ virtualTool
283
+ ]);
268
284
  }
269
285
  }
270
- if (data.options.enableConversationId) tools = (0, external_conversation_id_js_namespaceObject.addConversationIdToTools)(tools, missingToolName, injectedMissingCapabilityTool, data.logger);
286
+ if (data.options.enableConversationId) {
287
+ tools = (0, external_conversation_id_js_namespaceObject.addConversationIdToTools)(tools, data.logger);
288
+ tools = (0, external_output_instructions_js_namespaceObject.addInstructionsToOutputSchemas)(tools, data.logger);
289
+ }
271
290
  }
272
291
  if (data) {
273
292
  cacheToolDescriptions(data.toolDescriptions, tools);
@@ -2,6 +2,7 @@ import { getAnalyticsParameterOwnership, stripOwnedAnalyticsArguments } from "./
2
2
  import { addContextParameterToTools, getContextDescription, isContextEnabled } from "./context-parameters.mjs";
3
3
  import { addConversationIdToTools, canInjectConversationIdPromptBack, injectConversationIdPromptBack, resolveConversationId } from "./conversation-id.mjs";
4
4
  import { stampMetaClientInfo } from "./client-identity.mjs";
5
+ import { addInstructionsToOutputSchemas, mirrorInstructionsIntoStructuredContent } from "./output-instructions.mjs";
5
6
  import { captureEvent } from "./capture.mjs";
6
7
  import { MCPAnalyticsEventType } from "./event-types.mjs";
7
8
  import { captureException } from "./exceptions.mjs";
@@ -17,7 +18,7 @@ async function captureToolCall(params) {
17
18
  const { server, data, request, extra, execute, parameterOwnership, eventType, explicitContextIntent, takeCapturedError } = params;
18
19
  const resolvedEventType = eventType ?? MCPAnalyticsEventType.mcpToolsCall;
19
20
  const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership, resolvedEventType === MCPAnalyticsEventType.mcpMissingCapability);
20
- const conversation = resolveConversationId(ownership.conversationId, request.params?.arguments, request.params?.name, resolvedEventType === MCPAnalyticsEventType.mcpMissingCapability ? resolveMissingCapabilityToolName(data.options) : '');
21
+ const conversation = resolveConversationId(ownership.conversationId, request.params?.arguments);
21
22
  const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership);
22
23
  const startTime = new Date();
23
24
  const preparedEvent = await prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, resolvedEventType);
@@ -29,15 +30,17 @@ async function captureToolCall(params) {
29
30
  publishFailedToolEvent(server, preparedEvent, error, startTime, conversation, data.logger);
30
31
  throw error;
31
32
  }
32
- const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation);
33
+ const finalResult = applyConversationInstructions(preparedEvent?.event ?? null, result, conversation, ownership);
33
34
  publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError);
34
35
  return finalResult;
35
36
  }
36
37
  function getActiveAnalyticsParameterOwnership(data, toolName, override, isMissingCapabilityTool) {
37
- const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0);
38
+ const listed = toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0;
39
+ const ownership = override ?? listed;
38
40
  return {
39
41
  context: !isMissingCapabilityTool && isContextEnabled(data.options.context) && ownership?.context === true,
40
- conversationId: !isMissingCapabilityTool && true === data.options.enableConversationId && ownership?.conversationId === true
42
+ conversationId: true === data.options.enableConversationId && ownership?.conversationId === true,
43
+ outputInstructions: true === data.options.enableConversationId && listed?.outputInstructions === true
41
44
  };
42
45
  }
43
46
  function cloneRequestWithoutOwnedAnalyticsArguments(request, ownership) {
@@ -54,9 +57,9 @@ function cloneRequestWithoutOwnedAnalyticsArguments(request, ownership) {
54
57
  }
55
58
  async function prepareToolCallEvent(server, data, request, downstreamRequest, extra, startTime, conversation, ownership, eventType) {
56
59
  try {
57
- const sessionId = getSessionId(server, extra);
60
+ const sessionId = getSessionId(server, extra, conversation.conversationId);
58
61
  const sessionInfo = getSessionInfo(server, data, sessionId);
59
- const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra);
62
+ const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra, !!conversation.conversationId);
60
63
  const requestAttribution = withIdentity(sessionInfo, identity);
61
64
  const toolName = request.params?.name;
62
65
  const event = {
@@ -81,11 +84,22 @@ async function prepareToolCallEvent(server, data, request, downstreamRequest, ex
81
84
  return null;
82
85
  }
83
86
  }
84
- function applyConversationPromptBack(event, result, conversation) {
85
- if (!conversation.minted) return result;
86
- if (canInjectConversationIdPromptBack(result)) return injectConversationIdPromptBack(result, conversation.conversationId);
87
- if (event) event.conversationId = void 0;
88
- return result;
87
+ function applyConversationInstructions(event, result, conversation, ownership) {
88
+ const conversationId = conversation.conversationId;
89
+ if (!conversationId) return result;
90
+ let updated = result;
91
+ let delivered = false;
92
+ if (ownership.outputInstructions) {
93
+ const mirrored = mirrorInstructionsIntoStructuredContent(updated, conversationId);
94
+ delivered = mirrored !== updated;
95
+ updated = mirrored;
96
+ }
97
+ if (conversation.minted && canInjectConversationIdPromptBack(updated)) {
98
+ updated = injectConversationIdPromptBack(updated, conversationId);
99
+ delivered = true;
100
+ }
101
+ if (!delivered && conversation.minted && event) event.conversationId = void 0;
102
+ return updated;
89
103
  }
90
104
  function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) {
91
105
  if (!preparedEvent) return;
@@ -205,7 +219,7 @@ async function handleListToolsRequest(server, originalListToolsHandler, request,
205
219
  };
206
220
  }
207
221
  function cacheToolAnalyticsParameterOwnership(cache, tools) {
208
- for (const tool of tools)if (tool?.name) cache.set(tool.name, getAnalyticsParameterOwnership(tool.inputSchema));
222
+ for (const tool of tools)if (tool?.name) cache.set(tool.name, getAnalyticsParameterOwnership(tool.inputSchema, tool.outputSchema));
209
223
  }
210
224
  function collectListedToolNames(tools) {
211
225
  if (!tools || 0 === tools.length) return;
@@ -223,16 +237,21 @@ async function getTracedToolsList(server, originalListToolsHandler, request, ext
223
237
  if (data && isContextEnabled(data.options.context)) tools = addContextParameterToTools(tools, getContextDescription(data.options.context), data.logger);
224
238
  if (data) {
225
239
  const missingToolName = resolveMissingCapabilityToolName(data.options);
226
- let injectedMissingCapabilityTool = false;
227
240
  if (data.options.reportMissing) {
228
241
  const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName);
229
242
  if (alreadyPresent) data.logger(`Warning: Cannot inject missing-capability tool "${missingToolName}" because a real tool already uses that name. The real tool will not be intercepted.`);
230
243
  else {
231
- tools.push(getReportMissingToolDescriptor(missingToolName));
232
- injectedMissingCapabilityTool = true;
244
+ const virtualTool = getReportMissingToolDescriptor(missingToolName);
245
+ tools.push(virtualTool);
246
+ cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [
247
+ virtualTool
248
+ ]);
233
249
  }
234
250
  }
235
- if (data.options.enableConversationId) tools = addConversationIdToTools(tools, missingToolName, injectedMissingCapabilityTool, data.logger);
251
+ if (data.options.enableConversationId) {
252
+ tools = addConversationIdToTools(tools, data.logger);
253
+ tools = addInstructionsToOutputSchemas(tools, data.logger);
254
+ }
236
255
  }
237
256
  if (data) {
238
257
  cacheToolDescriptions(data.toolDescriptions, tools);
@@ -24,7 +24,14 @@ export declare function mergeIdentities(previous: UserIdentity | undefined, next
24
24
  * `$identify` event at most once per session: at `initialize`, when a
25
25
  * long-lived server first sees the identity, or when it materially changes.
26
26
  */
27
- export declare function handleIdentify(server: MCPServerLike, data: MCPAnalyticsData, sessionId: string, request: MCPRequestLike, requestAttribution: SessionInfo, extra?: CompatibleRequestHandlerExtra): Promise<UserIdentity | undefined>;
27
+ export declare function handleIdentify(server: MCPServerLike, data: MCPAnalyticsData, sessionId: string, request: MCPRequestLike, requestAttribution: SessionInfo, extra?: CompatibleRequestHandlerExtra,
28
+ /**
29
+ * True when this session id came from an agent-carried `conversation_id`
30
+ * rather than the transport. Such a session is brand new and was never
31
+ * announced at `initialize`, whatever `data.sessionSource` still says about
32
+ * the connection.
33
+ */
34
+ sessionFromConversation?: boolean): Promise<UserIdentity | undefined>;
28
35
  export declare function withIdentity(sessionInfo: SessionInfo, identity: UserIdentity | undefined): SessionInfo;
29
36
  /**
30
37
  * Resolves the `eventProperties` callback. Returns null when no callback is
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,WAAW,EACX,YAAY,EACb,MAAM,UAAU,CAAA;AAKjB;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,OAAO,SAAO;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAWhD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAapD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B,IAAI,IAAI,MAAM;CAGf;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B5E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAapG;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,kBAAkB,EAAE,WAAW,EAC/B,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAsDnC;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,WAAW,CAOtG;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,WAAW,EACX,YAAY,EACb,MAAM,UAAU,CAAA;AAKjB;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,OAAO,SAAO;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAWhD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAapD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B,IAAI,IAAI,MAAM;CAGf;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B5E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAapG;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,kBAAkB,EAAE,WAAW,EAC/B,KAAK,CAAC,EAAE,6BAA6B;AACrC;;;;;GAKG;AACH,uBAAuB,UAAQ,GAC9B,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAuDnC;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,WAAW,CAOtG;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC"}
@@ -95,7 +95,7 @@ function mergeIdentities(previous, next) {
95
95
  groups: next.groups ?? previous.groups
96
96
  };
97
97
  }
98
- async function handleIdentify(server, data, sessionId, request, requestAttribution, extra) {
98
+ async function handleIdentify(server, data, sessionId, request, requestAttribution, extra, sessionFromConversation = false) {
99
99
  const identityBeforeRequest = data.identifiedSessions.get(sessionId);
100
100
  const sessionSourceBeforeIdentify = data.sessionSource;
101
101
  if (!data.options.identify) return identityBeforeRequest;
@@ -117,7 +117,7 @@ async function handleIdentify(server, data, sessionId, request, requestAttributi
117
117
  const mergedIdentity = mergeIdentities(previousIdentity, identityResult);
118
118
  const changed = void 0 !== previousIdentity && !areIdentitiesEqual(previousIdentity, mergedIdentity);
119
119
  const firstSeen = void 0 === previousIdentity;
120
- const announcedAtInitialize = 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method;
120
+ const announcedAtInitialize = !sessionFromConversation && 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method;
121
121
  const shouldPublish = changed || firstSeen && !announcedAtInitialize;
122
122
  data.identifiedSessions.set(sessionId, mergedIdentity);
123
123
  if (shouldPublish) {
@@ -60,7 +60,7 @@ function mergeIdentities(previous, next) {
60
60
  groups: next.groups ?? previous.groups
61
61
  };
62
62
  }
63
- async function handleIdentify(server, data, sessionId, request, requestAttribution, extra) {
63
+ async function handleIdentify(server, data, sessionId, request, requestAttribution, extra, sessionFromConversation = false) {
64
64
  const identityBeforeRequest = data.identifiedSessions.get(sessionId);
65
65
  const sessionSourceBeforeIdentify = data.sessionSource;
66
66
  if (!data.options.identify) return identityBeforeRequest;
@@ -82,7 +82,7 @@ async function handleIdentify(server, data, sessionId, request, requestAttributi
82
82
  const mergedIdentity = mergeIdentities(previousIdentity, identityResult);
83
83
  const changed = void 0 !== previousIdentity && !areIdentitiesEqual(previousIdentity, mergedIdentity);
84
84
  const firstSeen = void 0 === previousIdentity;
85
- const announcedAtInitialize = 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method;
85
+ const announcedAtInitialize = !sessionFromConversation && 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method;
86
86
  const shouldPublish = changed || firstSeen && !announcedAtInitialize;
87
87
  data.identifiedSessions.set(sessionId, mergedIdentity);
88
88
  if (shouldPublish) {