weflayr 0.29.0 → 0.29.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weflayr",
3
- "version": "0.29.0",
3
+ "version": "0.29.1",
4
4
  "description": "Weflayr JS/TS SDK — instrument any LLM client",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -31,8 +31,8 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@opentelemetry/api": "^1.9.1",
34
- "@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
35
- "@opentelemetry/instrumentation": "^0.222.0",
34
+ "@opentelemetry/exporter-trace-otlp-http": "^0.223.0",
35
+ "@opentelemetry/instrumentation": "^0.223.0",
36
36
  "@opentelemetry/resources": "^2.8.0",
37
37
  "@opentelemetry/sdk-trace-base": "^2.8.0",
38
38
  "@opentelemetry/sdk-trace-node": "^2.8.0",
@@ -13,7 +13,9 @@
13
13
  * paths) to stamp every breakpoint found in the request as
14
14
  * `weflayr.cache.breakpoints`: a JSON list of `{location, ttl}` where location
15
15
  * is `system`, `messages[i]`, `tools[i]` or `auto_last_block` (the top-level
16
- * parameter) and `ttl` is the raw cache_control string, omitted when the
16
+ * parameter), followed by `.content[j]` for a breakpoint on a block that is not
17
+ * the last of its system prompt or message (`formatCacheBreakpointLocation`),
18
+ * and `ttl` is the raw cache_control string, omitted when the
17
19
  * breakpoint sets none; the normalizer owns the TTL vocabulary.
18
20
  */
19
21
  export interface CacheBreakpoint {
@@ -14,12 +14,15 @@
14
14
  * paths) to stamp every breakpoint found in the request as
15
15
  * `weflayr.cache.breakpoints`: a JSON list of `{location, ttl}` where location
16
16
  * is `system`, `messages[i]`, `tools[i]` or `auto_last_block` (the top-level
17
- * parameter) and `ttl` is the raw cache_control string, omitted when the
17
+ * parameter), followed by `.content[j]` for a breakpoint on a block that is not
18
+ * the last of its system prompt or message (`formatCacheBreakpointLocation`),
19
+ * and `ttl` is the raw cache_control string, omitted when the
18
20
  * breakpoint sets none; the normalizer owns the TTL vocabulary.
19
21
  */
20
22
  Object.defineProperty(exports, "__esModule", { value: true });
21
23
  exports.AnthropicCacheConfigInstrumentor = void 0;
22
24
  exports.extractCacheBreakpoints = extractCacheBreakpoints;
25
+ const format_cache_breakpoint_location_1 = require("../shared/format_cache_breakpoint_location");
23
26
  const BREAKPOINTS_ATTR = 'weflayr.cache.breakpoints';
24
27
  // A breakpoint as location + the raw cache_control `ttl` string, omitted when
25
28
  // the request sets none.
@@ -27,22 +30,26 @@ function _breakpointEntry(location, cacheControl) {
27
30
  const ttl = cacheControl && cacheControl.ttl;
28
31
  return ttl ? { location, ttl: String(ttl) } : { location };
29
32
  }
30
- function _cacheControlsInBlocks(blocks) {
33
+ // A breakpoint per block of `blocks` carrying a `cache_control`.
34
+ function _breakpointsInBlocks(blocks, messageLocation) {
31
35
  if (!Array.isArray(blocks))
32
36
  return [];
33
- return blocks.map((block) => block && block.cache_control).filter(Boolean);
37
+ const breakpoints = [];
38
+ blocks.forEach((block, blockIndex) => {
39
+ const cacheControl = block && block.cache_control;
40
+ if (!cacheControl)
41
+ return;
42
+ const location = (0, format_cache_breakpoint_location_1.formatCacheBreakpointLocation)(messageLocation, blockIndex, blocks.length);
43
+ breakpoints.push(_breakpointEntry(location, cacheControl));
44
+ });
45
+ return breakpoints;
34
46
  }
35
47
  // Every `cache_control` breakpoint in the request, as location + the raw
36
48
  // `ttl` string (omitted when the breakpoint sets none).
37
49
  function extractCacheBreakpoints(params) {
38
- const breakpoints = [];
39
- for (const cacheControl of _cacheControlsInBlocks(params.system)) {
40
- breakpoints.push(_breakpointEntry('system', cacheControl));
41
- }
50
+ const breakpoints = _breakpointsInBlocks(params.system, 'system');
42
51
  (params.messages || []).forEach((message, index) => {
43
- for (const cacheControl of _cacheControlsInBlocks(message && message.content)) {
44
- breakpoints.push(_breakpointEntry(`messages[${index}]`, cacheControl));
45
- }
52
+ breakpoints.push(..._breakpointsInBlocks(message && message.content, `messages[${index}]`));
46
53
  });
47
54
  (params.tools || []).forEach((tool, index) => {
48
55
  if (tool && tool.cache_control) {
@@ -29,6 +29,7 @@ exports.BedrockCacheConfigInstrumentor = void 0;
29
29
  exports.recordCommandRegion = recordCommandRegion;
30
30
  exports.extractBedrockCacheBreakpoints = extractBedrockCacheBreakpoints;
31
31
  const get_cache_config_telemetry_1 = require("../anthropic/get_cache_config_telemetry");
32
+ const format_cache_breakpoint_location_1 = require("../shared/format_cache_breakpoint_location");
32
33
  const BREAKPOINTS_ATTR = 'weflayr.cache.breakpoints';
33
34
  const PROVIDER_REGION_ATTR = 'weflayr.provider_region';
34
35
  // The region of the client each pending command was sent with. Keyed by the
@@ -46,13 +47,46 @@ function _cachePointEntry(location, cachePoint) {
46
47
  const ttl = cachePoint && cachePoint.ttl;
47
48
  return ttl ? { location, ttl: String(ttl) } : { location };
48
49
  }
49
- // The first `cachePoint` among a list of blocks (attached to a content block,
50
- // or standing alone as its own block), or undefined.
51
- function _cachePointOfBlocks(blocks) {
50
+ function _isStandaloneCachePoint(block) {
51
+ return (block != null &&
52
+ typeof block === 'object' &&
53
+ Object.keys(block).length === 1 &&
54
+ block.cachePoint !== undefined);
55
+ }
56
+ // A breakpoint per `cachePoint` among a list of blocks. One attached to a
57
+ // content block marks that block, and one standing alone as its own block
58
+ // marks the content block before it, the standalone ones being no content
59
+ // block of their own. A standalone one opening the list caches the prompt up
60
+ // to `previousLocation`, the end of what comes before the list, and is left
61
+ // out when nothing does, since it then caches nothing.
62
+ // Example: [text, cachePoint, text] in messages[0] ->
63
+ // [{ location: "messages[0].content[0]" }].
64
+ function _cachePointBreakpoints(blocks, messageLocation, previousLocation) {
52
65
  if (!Array.isArray(blocks))
53
- return undefined;
54
- const block = blocks.find((entry) => entry && entry.cachePoint != null);
55
- return block && block.cachePoint;
66
+ return [];
67
+ const numContentBlocks = blocks.filter((block) => !_isStandaloneCachePoint(block)).length;
68
+ const breakpoints = [];
69
+ let numContentBlocksSoFar = 0;
70
+ for (const block of blocks) {
71
+ if (!_isStandaloneCachePoint(block))
72
+ numContentBlocksSoFar += 1;
73
+ const cachePoint = block && block.cachePoint;
74
+ if (cachePoint == null)
75
+ continue;
76
+ const markedBlockIndex = numContentBlocksSoFar - 1;
77
+ let location;
78
+ if (markedBlockIndex >= 0) {
79
+ location = (0, format_cache_breakpoint_location_1.formatCacheBreakpointLocation)(messageLocation, markedBlockIndex, numContentBlocks);
80
+ }
81
+ else if (previousLocation !== undefined) {
82
+ location = previousLocation;
83
+ }
84
+ else {
85
+ continue;
86
+ }
87
+ breakpoints.push(_cachePointEntry(location, cachePoint));
88
+ }
89
+ return breakpoints;
56
90
  }
57
91
  // Every cache breakpoint in an InvokeModel request body, as location + the
58
92
  // raw `ttl` string (omitted when the breakpoint sets none): the
@@ -60,17 +94,15 @@ function _cachePointOfBlocks(blocks) {
60
94
  // (which never overlap in one body).
61
95
  function extractBedrockCacheBreakpoints(body) {
62
96
  const breakpoints = (0, get_cache_config_telemetry_1.extractCacheBreakpoints)(body);
63
- const systemCachePoint = _cachePointOfBlocks(body.system);
64
- if (systemCachePoint != null) {
65
- breakpoints.push(_cachePointEntry('system', systemCachePoint));
66
- }
97
+ const tools = (body.toolConfig && body.toolConfig.tools) || [];
98
+ // The prompt is cached in the order tools, system, messages.
99
+ const toolsLocation = tools.length ? `tools[${tools.length - 1}]` : undefined;
100
+ breakpoints.push(..._cachePointBreakpoints(body.system, 'system', toolsLocation));
101
+ const locationBeforeMessages = body.system && body.system.length ? 'system' : toolsLocation;
67
102
  (body.messages || []).forEach((message, index) => {
68
- const cachePoint = _cachePointOfBlocks(message && message.content);
69
- if (cachePoint != null) {
70
- breakpoints.push(_cachePointEntry(`messages[${index}]`, cachePoint));
71
- }
103
+ const previousLocation = index ? `messages[${index - 1}]` : locationBeforeMessages;
104
+ breakpoints.push(..._cachePointBreakpoints(message && message.content, `messages[${index}]`, previousLocation));
72
105
  });
73
- const tools = (body.toolConfig && body.toolConfig.tools) || [];
74
106
  tools.forEach((tool, index) => {
75
107
  if (tool && tool.cachePoint != null) {
76
108
  breakpoints.push(_cachePointEntry(`tools[${index}]`, tool.cachePoint));
@@ -13,9 +13,11 @@
13
13
  *
14
14
  * It covers the chat and the Responses endpoints alike: both take the same
15
15
  * params, and a marker sits on a content block of either `messages` (chat) or
16
- * `input` (Responses), recorded as `messages[i]` / `input[i]`. A Responses
17
- * request's `instructions` count as its item 0 when it sends them, as the
18
- * worker numbers every provider's system prompt.
16
+ * `input` (Responses), recorded as `messages[i]` / `input[i]`, followed by
17
+ * `.content[j]` for a marker on a block that is not the last of its message
18
+ * (`formatCacheBreakpointLocation`). A Responses request's `instructions` count
19
+ * as its item 0 when it sends them, as the worker numbers every provider's
20
+ * system prompt.
19
21
  *
20
22
  * Wrap `startSpan({ type, params })` (covering the streamed and non-streamed
21
23
  * paths) to stamp the values as `weflayr.cache.key` / `weflayr.cache.retention`
@@ -14,9 +14,11 @@
14
14
  *
15
15
  * It covers the chat and the Responses endpoints alike: both take the same
16
16
  * params, and a marker sits on a content block of either `messages` (chat) or
17
- * `input` (Responses), recorded as `messages[i]` / `input[i]`. A Responses
18
- * request's `instructions` count as its item 0 when it sends them, as the
19
- * worker numbers every provider's system prompt.
17
+ * `input` (Responses), recorded as `messages[i]` / `input[i]`, followed by
18
+ * `.content[j]` for a marker on a block that is not the last of its message
19
+ * (`formatCacheBreakpointLocation`). A Responses request's `instructions` count
20
+ * as its item 0 when it sends them, as the worker numbers every provider's
21
+ * system prompt.
20
22
  *
21
23
  * Wrap `startSpan({ type, params })` (covering the streamed and non-streamed
22
24
  * paths) to stamp the values as `weflayr.cache.key` / `weflayr.cache.retention`
@@ -41,6 +43,7 @@
41
43
  */
42
44
  Object.defineProperty(exports, "__esModule", { value: true });
43
45
  exports.OpenAICacheConfigInstrumentor = void 0;
46
+ const format_cache_breakpoint_location_1 = require("../shared/format_cache_breakpoint_location");
44
47
  const CACHE_KEY_ATTR = 'weflayr.cache.key';
45
48
  const CACHE_RETENTION_ATTR = 'weflayr.cache.retention';
46
49
  const CACHE_MODE_ATTR = 'weflayr.cache.mode';
@@ -55,20 +58,21 @@ function breakpointsInItems(items, listName, firstIndex) {
55
58
  const content = item && item.content;
56
59
  if (!Array.isArray(content))
57
60
  return;
58
- for (const block of content) {
61
+ content.forEach((block, blockIndex) => {
59
62
  if (!block || typeof block !== 'object')
60
- continue;
63
+ return;
64
+ const location = (0, format_cache_breakpoint_location_1.formatCacheBreakpointLocation)(`${listName}[${index}]`, blockIndex, content.length);
61
65
  if ('prompt_cache_breakpoint' in block) {
62
- breakpoints.push({ location: `${listName}[${index}]` });
66
+ breakpoints.push({ location });
63
67
  }
64
68
  const cacheControl = block.cache_control;
65
69
  if (cacheControl && typeof cacheControl === 'object') {
66
- const entry = { location: `${listName}[${index}]` };
70
+ const entry = { location };
67
71
  if (cacheControl.ttl)
68
72
  entry.ttl = String(cacheControl.ttl);
69
73
  breakpoints.push(entry);
70
74
  }
71
- }
75
+ });
72
76
  });
73
77
  return breakpoints;
74
78
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The location of a cache breakpoint marked on one block of a message, shared
3
+ * by every provider complement stamping `weflayr.cache.breakpoints`.
4
+ *
5
+ * A breakpoint caches the prompt up to the end of the block it marks. On a
6
+ * message's last block, that is the end of the message, written as the message
7
+ * alone (`messages[1]`). On an earlier block, the prefix ends inside the
8
+ * message, so the location also names the block (`messages[1].content[0]`).
9
+ */
10
+ export declare function formatCacheBreakpointLocation(messageLocation: string, blockIndex: number, numBlocks: number): string;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * The location of a cache breakpoint marked on one block of a message, shared
4
+ * by every provider complement stamping `weflayr.cache.breakpoints`.
5
+ *
6
+ * A breakpoint caches the prompt up to the end of the block it marks. On a
7
+ * message's last block, that is the end of the message, written as the message
8
+ * alone (`messages[1]`). On an earlier block, the prefix ends inside the
9
+ * message, so the location also names the block (`messages[1].content[0]`).
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.formatCacheBreakpointLocation = formatCacheBreakpointLocation;
13
+ // Where a breakpoint on block `blockIndex` of a message of `numBlocks` blocks
14
+ // ends the cached prefix.
15
+ // Example: ("messages[1]", 0, 2) -> "messages[1].content[0]",
16
+ // ("messages[1]", 1, 2) -> "messages[1]".
17
+ function formatCacheBreakpointLocation(messageLocation, blockIndex, numBlocks) {
18
+ if (blockIndex === numBlocks - 1)
19
+ return messageLocation;
20
+ return `${messageLocation}.content[${blockIndex}]`;
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weflayr",
3
- "version": "0.29.0",
3
+ "version": "0.29.1",
4
4
  "description": "Weflayr JS/TS SDK — instrument any LLM client",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -31,8 +31,8 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@opentelemetry/api": "^1.9.1",
34
- "@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
35
- "@opentelemetry/instrumentation": "^0.222.0",
34
+ "@opentelemetry/exporter-trace-otlp-http": "^0.223.0",
35
+ "@opentelemetry/instrumentation": "^0.223.0",
36
36
  "@opentelemetry/resources": "^2.8.0",
37
37
  "@opentelemetry/sdk-trace-base": "^2.8.0",
38
38
  "@opentelemetry/sdk-trace-node": "^2.8.0",