@morsehq-dev/sdk 0.4.0-rc.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.
Files changed (161) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +294 -0
  3. package/dist/anthropic/index.cjs +39 -0
  4. package/dist/anthropic/index.cjs.map +1 -0
  5. package/dist/anthropic/index.d.cts +213 -0
  6. package/dist/anthropic/index.d.ts +213 -0
  7. package/dist/anthropic/index.js +6 -0
  8. package/dist/anthropic/index.js.map +1 -0
  9. package/dist/anthropic-agent-sdk/index.cjs +744 -0
  10. package/dist/anthropic-agent-sdk/index.cjs.map +1 -0
  11. package/dist/anthropic-agent-sdk/index.d.cts +371 -0
  12. package/dist/anthropic-agent-sdk/index.d.ts +371 -0
  13. package/dist/anthropic-agent-sdk/index.js +735 -0
  14. package/dist/anthropic-agent-sdk/index.js.map +1 -0
  15. package/dist/browser/anthropic/index.cjs +39 -0
  16. package/dist/browser/anthropic/index.cjs.map +1 -0
  17. package/dist/browser/anthropic/index.js +6 -0
  18. package/dist/browser/anthropic/index.js.map +1 -0
  19. package/dist/browser/anthropic-agent-sdk/index.cjs +744 -0
  20. package/dist/browser/anthropic-agent-sdk/index.cjs.map +1 -0
  21. package/dist/browser/anthropic-agent-sdk/index.js +735 -0
  22. package/dist/browser/anthropic-agent-sdk/index.js.map +1 -0
  23. package/dist/browser/chunk-3643DC7K.cjs +365 -0
  24. package/dist/browser/chunk-3643DC7K.cjs.map +1 -0
  25. package/dist/browser/chunk-4FALQMOZ.js +232 -0
  26. package/dist/browser/chunk-4FALQMOZ.js.map +1 -0
  27. package/dist/browser/chunk-5J2QBK75.js +884 -0
  28. package/dist/browser/chunk-5J2QBK75.js.map +1 -0
  29. package/dist/browser/chunk-7MSXWGAH.js +53 -0
  30. package/dist/browser/chunk-7MSXWGAH.js.map +1 -0
  31. package/dist/browser/chunk-A24L5N5N.js +596 -0
  32. package/dist/browser/chunk-A24L5N5N.js.map +1 -0
  33. package/dist/browser/chunk-B7DEUDP6.cjs +177 -0
  34. package/dist/browser/chunk-B7DEUDP6.cjs.map +1 -0
  35. package/dist/browser/chunk-F6CJACNH.cjs +604 -0
  36. package/dist/browser/chunk-F6CJACNH.cjs.map +1 -0
  37. package/dist/browser/chunk-JBOYFQSB.js +412 -0
  38. package/dist/browser/chunk-JBOYFQSB.js.map +1 -0
  39. package/dist/browser/chunk-KRBADE6R.cjs +183 -0
  40. package/dist/browser/chunk-KRBADE6R.cjs.map +1 -0
  41. package/dist/browser/chunk-MCJYZH6W.cjs +415 -0
  42. package/dist/browser/chunk-MCJYZH6W.cjs.map +1 -0
  43. package/dist/browser/chunk-NQG2IAQS.js +178 -0
  44. package/dist/browser/chunk-NQG2IAQS.js.map +1 -0
  45. package/dist/browser/chunk-O4HG3OSK.cjs +929 -0
  46. package/dist/browser/chunk-O4HG3OSK.cjs.map +1 -0
  47. package/dist/browser/chunk-QWRQJO57.js +363 -0
  48. package/dist/browser/chunk-QWRQJO57.js.map +1 -0
  49. package/dist/browser/chunk-SWQOPFE4.cjs +234 -0
  50. package/dist/browser/chunk-SWQOPFE4.cjs.map +1 -0
  51. package/dist/browser/chunk-TYDG747E.js +171 -0
  52. package/dist/browser/chunk-TYDG747E.js.map +1 -0
  53. package/dist/browser/chunk-TZRSDDFP.cjs +56 -0
  54. package/dist/browser/chunk-TZRSDDFP.cjs.map +1 -0
  55. package/dist/browser/index.cjs +587 -0
  56. package/dist/browser/index.cjs.map +1 -0
  57. package/dist/browser/index.js +522 -0
  58. package/dist/browser/index.js.map +1 -0
  59. package/dist/browser/integrations/pino.cjs +89 -0
  60. package/dist/browser/integrations/pino.cjs.map +1 -0
  61. package/dist/browser/integrations/pino.js +86 -0
  62. package/dist/browser/integrations/pino.js.map +1 -0
  63. package/dist/browser/langchain/index.cjs +535 -0
  64. package/dist/browser/langchain/index.cjs.map +1 -0
  65. package/dist/browser/langchain/index.js +528 -0
  66. package/dist/browser/langchain/index.js.map +1 -0
  67. package/dist/browser/langgraph/index.cjs +377 -0
  68. package/dist/browser/langgraph/index.cjs.map +1 -0
  69. package/dist/browser/langgraph/index.js +371 -0
  70. package/dist/browser/langgraph/index.js.map +1 -0
  71. package/dist/browser/openai/index.cjs +125 -0
  72. package/dist/browser/openai/index.cjs.map +1 -0
  73. package/dist/browser/openai/index.js +122 -0
  74. package/dist/browser/openai/index.js.map +1 -0
  75. package/dist/browser/openai-agents/index.cjs +689 -0
  76. package/dist/browser/openai-agents/index.cjs.map +1 -0
  77. package/dist/browser/openai-agents/index.js +678 -0
  78. package/dist/browser/openai-agents/index.js.map +1 -0
  79. package/dist/browser/vercel-ai/index.cjs +233 -0
  80. package/dist/browser/vercel-ai/index.cjs.map +1 -0
  81. package/dist/browser/vercel-ai/index.js +231 -0
  82. package/dist/browser/vercel-ai/index.js.map +1 -0
  83. package/dist/chunk-4R4SHGOK.js +363 -0
  84. package/dist/chunk-4R4SHGOK.js.map +1 -0
  85. package/dist/chunk-7EO7MQBA.cjs +183 -0
  86. package/dist/chunk-7EO7MQBA.cjs.map +1 -0
  87. package/dist/chunk-7YCENA54.cjs +604 -0
  88. package/dist/chunk-7YCENA54.cjs.map +1 -0
  89. package/dist/chunk-CKFOGDUF.js +596 -0
  90. package/dist/chunk-CKFOGDUF.js.map +1 -0
  91. package/dist/chunk-FJUNILZT.cjs +1324 -0
  92. package/dist/chunk-FJUNILZT.cjs.map +1 -0
  93. package/dist/chunk-HDAFUKQ3.js +171 -0
  94. package/dist/chunk-HDAFUKQ3.js.map +1 -0
  95. package/dist/chunk-KBWPNIH4.cjs +234 -0
  96. package/dist/chunk-KBWPNIH4.cjs.map +1 -0
  97. package/dist/chunk-KJEO52QS.cjs +365 -0
  98. package/dist/chunk-KJEO52QS.cjs.map +1 -0
  99. package/dist/chunk-KZBCOZIQ.cjs +177 -0
  100. package/dist/chunk-KZBCOZIQ.cjs.map +1 -0
  101. package/dist/chunk-ME5JALGT.js +53 -0
  102. package/dist/chunk-ME5JALGT.js.map +1 -0
  103. package/dist/chunk-PVHDEPRE.cjs +56 -0
  104. package/dist/chunk-PVHDEPRE.cjs.map +1 -0
  105. package/dist/chunk-RTL23YOQ.js +178 -0
  106. package/dist/chunk-RTL23YOQ.js.map +1 -0
  107. package/dist/chunk-TQWI4UYO.js +1277 -0
  108. package/dist/chunk-TQWI4UYO.js.map +1 -0
  109. package/dist/chunk-VXDBDPDR.cjs +415 -0
  110. package/dist/chunk-VXDBDPDR.cjs.map +1 -0
  111. package/dist/chunk-XTKMUJWI.js +232 -0
  112. package/dist/chunk-XTKMUJWI.js.map +1 -0
  113. package/dist/chunk-ZKUGOWER.js +412 -0
  114. package/dist/chunk-ZKUGOWER.js.map +1 -0
  115. package/dist/index.cjs +843 -0
  116. package/dist/index.cjs.map +1 -0
  117. package/dist/index.d.cts +464 -0
  118. package/dist/index.d.ts +464 -0
  119. package/dist/index.js +778 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/integrations/pino.cjs +89 -0
  122. package/dist/integrations/pino.cjs.map +1 -0
  123. package/dist/integrations/pino.d.cts +65 -0
  124. package/dist/integrations/pino.d.ts +65 -0
  125. package/dist/integrations/pino.js +86 -0
  126. package/dist/integrations/pino.js.map +1 -0
  127. package/dist/langchain/index.cjs +535 -0
  128. package/dist/langchain/index.cjs.map +1 -0
  129. package/dist/langchain/index.d.cts +265 -0
  130. package/dist/langchain/index.d.ts +265 -0
  131. package/dist/langchain/index.js +528 -0
  132. package/dist/langchain/index.js.map +1 -0
  133. package/dist/langgraph/index.cjs +377 -0
  134. package/dist/langgraph/index.cjs.map +1 -0
  135. package/dist/langgraph/index.d.cts +324 -0
  136. package/dist/langgraph/index.d.ts +324 -0
  137. package/dist/langgraph/index.js +371 -0
  138. package/dist/langgraph/index.js.map +1 -0
  139. package/dist/openai/index.cjs +125 -0
  140. package/dist/openai/index.cjs.map +1 -0
  141. package/dist/openai/index.d.cts +136 -0
  142. package/dist/openai/index.d.ts +136 -0
  143. package/dist/openai/index.js +122 -0
  144. package/dist/openai/index.js.map +1 -0
  145. package/dist/openai-agents/index.cjs +689 -0
  146. package/dist/openai-agents/index.cjs.map +1 -0
  147. package/dist/openai-agents/index.d.cts +502 -0
  148. package/dist/openai-agents/index.d.ts +502 -0
  149. package/dist/openai-agents/index.js +678 -0
  150. package/dist/openai-agents/index.js.map +1 -0
  151. package/dist/spans-DZtMuBvc.d.cts +73 -0
  152. package/dist/spans-DZtMuBvc.d.ts +73 -0
  153. package/dist/tracing-BYAqjT5Q.d.cts +114 -0
  154. package/dist/tracing-rz9cWQ8d.d.ts +114 -0
  155. package/dist/vercel-ai/index.cjs +233 -0
  156. package/dist/vercel-ai/index.cjs.map +1 -0
  157. package/dist/vercel-ai/index.d.cts +93 -0
  158. package/dist/vercel-ai/index.d.ts +93 -0
  159. package/dist/vercel-ai/index.js +231 -0
  160. package/dist/vercel-ai/index.js.map +1 -0
  161. package/package.json +182 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Morse
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,294 @@
1
+ # Morse TypeScript SDK
2
+
3
+ Unified observability for AI agents and infrastructure — Node backend, one SDK.
4
+
5
+ > **Built for Node; safe to bundle for the browser.** The full feature set
6
+ > targets Node.js backends (Node 18.19+ or 20.6+). Bundlers that build for
7
+ > the browser automatically resolve the `"browser"` export condition to a
8
+ > browser-safe build — no aliasing, no `resolve.fallback`, no config of any
9
+ > kind on your side. This matters in practice for full-stack frameworks
10
+ > (Next.js, Remix, SvelteKit) where the same import is compiled for both
11
+ > the server and the client.
12
+ >
13
+ > In that browser build, `run()` / `span()` / `track()` / `record()` and W3C
14
+ > `traceparent` propagation behave exactly as documented, with traces sent
15
+ > over Morse's JSON transport. Three things are Node-only and quietly
16
+ > inactive in a browser, because they have no browser equivalent:
17
+ > OpenTelemetry OTLP span export, database capture (pg / mysql2
18
+ > instrumentation), and zero-config adapter auto-detect — which hooks
19
+ > `require()`, and a browser has none. The SDK says so once on `init()`
20
+ > rather than leaving you to wonder.
21
+ >
22
+ > This is bundle compatibility for full-stack apps, not a client-side
23
+ > analytics product: there is no session replay, no RUM, and no
24
+ > browser-specific instrumentation.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ npm install @morsehq-dev/sdk
30
+ ```
31
+
32
+ Adapters are peer dependencies — install only the SDKs you actually
33
+ use (`@anthropic-ai/sdk`, `@anthropic-ai/claude-agent-sdk`,
34
+ `@openai/agents`, `@langchain/core`, `@langchain/langgraph`, `ai`).
35
+ Nothing else is pulled in for adapters you don't use.
36
+
37
+ ## Quick Start
38
+
39
+ ```ts
40
+ import * as morse from "@morsehq-dev/sdk";
41
+
42
+ morse.init({ apiKey: process.env.MORSE_API_KEY });
43
+
44
+ morse.record({
45
+ agent: "lead-qualifier",
46
+ success: true,
47
+ outcome: "qualified",
48
+ cost: 0.043,
49
+ });
50
+ ```
51
+
52
+ Or trace a multi-step run:
53
+
54
+ ```ts
55
+ await morse.run({ agentName: "lead-qualifier" }, async (handle) => {
56
+ await morse.spanAsync({ name: "fetch-lead", type: "tool" }, async () => {
57
+ /* ... */
58
+ });
59
+ handle.setOutcome(true, "qualified");
60
+ });
61
+ ```
62
+
63
+ `record()`/`run()`/`span()` all send real OpenTelemetry spans over OTLP
64
+ by default — see [Transport](#transport) below.
65
+
66
+ ## Zero-config instrumentation
67
+
68
+ Once `morse.init()` runs (or `MORSE_API_KEY` is set in the environment),
69
+ the SDK scans for already-loaded — and lazily requires — supported
70
+ libraries and wraps them automatically. Today that covers
71
+ `@anthropic-ai/sdk` and the Vercel AI SDK (`ai`); every call already
72
+ loaded or `require()`d after init gets traced with no further code
73
+ changes. Opt out with `MORSE_DISABLE_AUTO_DETECT=1`.
74
+
75
+ The other adapters below (`anthropic-agent-sdk`, `openai-agents`,
76
+ `langgraph`, `langchain`) don't have a zero-config path yet — call
77
+ their wrap function explicitly, once, at startup. The SDK logs a
78
+ one-time hint naming the exact call when it detects one of these
79
+ installed without being wrapped.
80
+
81
+ ## Adapters
82
+
83
+ Each adapter is a separate subpath export so you only pull in what you
84
+ use.
85
+
86
+ ### `@morsehq-dev/sdk/anthropic` — Anthropic Messages API
87
+
88
+ ```ts
89
+ import Anthropic from "@anthropic-ai/sdk";
90
+ import { wrapAnthropic } from "@morsehq-dev/sdk/anthropic";
91
+
92
+ const client = wrapAnthropic(new Anthropic());
93
+ // every messages.create call now emits an `llm` span automatically
94
+ ```
95
+
96
+ Auto-installed by zero-config detection too — `wrapAnthropic()` is a
97
+ no-op on a client if a global auto-detect install is already active
98
+ (no double-recording). Pass `{ summarize: true }` to also emit a
99
+ sibling `memory` span per call.
100
+
101
+ ### `@morsehq-dev/sdk/anthropic-agent-sdk` — Claude Agent SDK
102
+
103
+ Wraps `ClaudeSDKClient` from `@anthropic-ai/claude-agent-sdk`. Emits an
104
+ outer **agent** span, per-call **llm** spans (with `context_segments`),
105
+ **tool** spans, **subagent.spawn** spans for Task-tool fan-out, and
106
+ **hook** spans for `pre_tool` / `post_tool` / `on_error` hooks.
107
+
108
+ ```ts
109
+ import { ClaudeSDKClient } from "@anthropic-ai/claude-agent-sdk";
110
+ import { wrapClaudeAgentSDKWithFullInstrumentation } from "@morsehq-dev/sdk/anthropic-agent-sdk";
111
+
112
+ const raw = new ClaudeSDKClient({
113
+ /* ... */
114
+ });
115
+ const { client, dispose } = wrapClaudeAgentSDKWithFullInstrumentation(raw);
116
+
117
+ for await (const event of client.query("research the 2026 RLHF landscape")) {
118
+ // your code unchanged — spans flow to Morse as a side-effect
119
+ }
120
+ dispose();
121
+ ```
122
+
123
+ ### `@morsehq-dev/sdk/openai-agents` — OpenAI Agents SDK
124
+
125
+ Wraps `Runner` from `@openai/agents`. Emits an outer **agent** span,
126
+ **llm** + **tool** spans, **subagent.spawn**-shaped spans for
127
+ `handoff` events, and **guardrail** spans with pass/fail status.
128
+
129
+ ```ts
130
+ import { Runner, Agent } from "@openai/agents";
131
+ import { wrapRunnerWithFullInstrumentation } from "@morsehq-dev/sdk/openai-agents";
132
+
133
+ const raw = new Runner();
134
+ const { runner, dispose } = wrapRunnerWithFullInstrumentation(raw);
135
+ const agent = new Agent({ name: "triage", model: "gpt-4o" /* ... */ });
136
+ await runner.run(agent, userInput);
137
+ dispose();
138
+ ```
139
+
140
+ ### `@morsehq-dev/sdk/langgraph` — LangGraph JS
141
+
142
+ `MorseCallbackHandler`, a `BaseCallbackHandler` you pass via
143
+ `callbacks`. Emits **agent** spans per chain (nested chains nest
144
+ properly), **llm** + **tool** spans, and aggregates streaming tokens
145
+ onto the parent llm span rather than emitting per-token spans.
146
+
147
+ ```ts
148
+ import { MorseCallbackHandler } from "@morsehq-dev/sdk/langgraph";
149
+
150
+ const handler = new MorseCallbackHandler();
151
+ const result = await graph.invoke(input, { callbacks: [handler] });
152
+ ```
153
+
154
+ ### `@morsehq-dev/sdk/langchain` — plain LangChain (chains, LLMs, tools, retrievers)
155
+
156
+ `MorseCallbackHandler` for `@langchain/core` outside a LangGraph graph
157
+ — a structural sibling of the `langgraph` adapter, not a subclass.
158
+ Doesn't auto-create a trace when none is active; wrap the invocation in
159
+ `morse.run()`/`runAsync()`.
160
+
161
+ ```ts
162
+ import { MorseCallbackHandler } from "@morsehq-dev/sdk/langchain";
163
+ import { runAsync } from "@morsehq-dev/sdk";
164
+
165
+ const handler = new MorseCallbackHandler({ agentName: "my-agent" });
166
+ await runAsync({ agentName: "my-agent" }, async () => {
167
+ await chain.invoke(input, { callbacks: [handler] });
168
+ });
169
+ ```
170
+
171
+ ### `@morsehq-dev/sdk/vercel-ai` — Vercel AI SDK
172
+
173
+ One `agent` span per top-level `streamText` / `generateText` /
174
+ `generateObject` invocation. **Not** zero-config auto-detected — `ai`'s
175
+ named exports are non-configurable getters on its module namespace (it
176
+ ships pure ESM), so there is nothing a monkey-patch can reassign, unlike
177
+ `@anthropic-ai/sdk`'s `Messages.prototype.create`. Resolve traced
178
+ replacement functions once and call those instead of `ai`'s own:
179
+
180
+ ```ts
181
+ import { createTracedVercelAI } from "@morsehq-dev/sdk/vercel-ai";
182
+
183
+ const { streamText, generateText, generateObject } = await createTracedVercelAI();
184
+ // use streamText(...) / generateText(...) / generateObject(...) exactly
185
+ // like ai's own — same call signature, same return shape.
186
+ ```
187
+
188
+ ### `@morsehq-dev/sdk/integrations/pino` — pino log forwarding
189
+
190
+ Ship pino log lines to Morse, auto-correlated with the active trace.
191
+
192
+ ```ts
193
+ import pino from "pino";
194
+ import { morsePinoDestination } from "@morsehq-dev/sdk/integrations/pino";
195
+
196
+ const logger = pino(
197
+ { level: "info" },
198
+ pino.multistream([{ stream: process.stdout }, { stream: morsePinoDestination() }]),
199
+ );
200
+ ```
201
+
202
+ ### Shared metadata schema
203
+
204
+ The agent-SDK adapters (`anthropic-agent-sdk`, `openai-agents`,
205
+ `langgraph`, `langchain`) tag every span with
206
+ `metadata.adapter ∈ {"anthropic-agent-sdk", "openai-agents", "langgraph-js", "langchain-js"}`.
207
+ Span types use the same vocabulary regardless of source adapter —
208
+ dashboards never branch on adapter origin. `subagent.spawn` and `hook`
209
+ are modeled as `type=agent` + `metadata.spawn_kind="subagent"` and
210
+ `type=tool` + `metadata.tool_kind="hook"` respectively until the
211
+ backend `SpanType` enum gains native variants.
212
+
213
+ ## Cost
214
+
215
+ `cost_usd` is computed automatically from the model + token counts on
216
+ every `llm` span the adapters above emit, using a bundled pricing
217
+ table — no separate call needed, and an explicit value the adapter
218
+ already knows (e.g. from a provider response) always wins over the
219
+ computed one. `record()` doesn't auto-compute — pass `cost` yourself
220
+ if you have it.
221
+
222
+ ## Infra auto-capture (opt-in)
223
+
224
+ Zero-config `db` spans for Postgres (`pg`), MySQL (`mysql2`), and
225
+ SQLite (`better-sqlite3`) — correlated with the active `morse.span()`/
226
+ `morse.run()` via real OpenTelemetry context propagation. Off by
227
+ default; enable with `MORSE_CAPTURE_DB=1` (or `MORSE_CAPTURE_INFRA=1`).
228
+ No code changes needed beyond the env var — the SDK registers the
229
+ matching community OTel instrumentation package for whichever driver
230
+ is actually installed.
231
+
232
+ ## Transport
233
+
234
+ `run()`/`span()`/`record()` emit real `@opentelemetry/sdk-trace-node`
235
+ spans over OTLP (protobuf+gzip) — the same transport architecture as
236
+ the Python SDK. `MORSE_LEGACY_TRANSPORT=1` reverts to a plain
237
+ JSON-over-fetch batcher as an escape hatch during a migration window;
238
+ you shouldn't need it. `track()`/`batchTrack()` are a lower-level,
239
+ non-trace-shaped escape hatch of their own — prefer `record()`.
240
+
241
+ ## PII Redaction
242
+
243
+ Client-side redaction, **default-on**. Sensitive strings (API keys,
244
+ JWTs, credit-card numbers, SSNs, emails, phone numbers) are rewritten
245
+ to `[REDACTED:<kind>]` markers inside your process before any data
246
+ leaves for the Morse ingest endpoint. The same pattern catalogue ships
247
+ in the Python SDK and the server-side ingest layer.
248
+
249
+ ```ts
250
+ import { init } from "@morsehq-dev/sdk";
251
+
252
+ init({
253
+ apiKey: process.env.MORSE_API_KEY,
254
+ redaction: {
255
+ enabled: true, // default
256
+ disabledPatterns: ["email"], // turn off email-only
257
+ extraPatterns: ["INTERNAL-[\\w-]+"],
258
+ },
259
+ });
260
+ ```
261
+
262
+ - **Mandatory patterns cannot be disabled at the SDK.** Trying to
263
+ disable `api_key_prefixed`, `jwt`, `credit_card`, or `ssn_us` makes
264
+ `init()` throw at construction time.
265
+ - **Invalid extra regexes throw at `init()`.** Each entry must compile
266
+ via `new RegExp(...)`; the array must be ≤ 10 entries, each pattern
267
+ ≤ 256 characters.
268
+ - **Disabling redaction at the SDK does NOT bypass the server.** The
269
+ ingest layer always re-runs the mandatory pattern set before writing
270
+ anything to durable storage.
271
+
272
+ | Key | Match | Replacement |
273
+ | ------------------ | ---------------------------------------------------------------------------- | ------------------------ |
274
+ | `api_key_prefixed` | `sk-…`, `sk_(live\|test)_…`, `mhq_…`, `ghp_…`, `xox[bopsa]-…`, `AKIA…`, etc. | `[REDACTED:api_key]` |
275
+ | `jwt` | `eyJ…<dot>eyJ…<dot>…` (≥16 chars per segment) | `[REDACTED:jwt]` |
276
+ | `credit_card` | 13–19 digit groups passing Luhn | `[REDACTED:credit_card]` |
277
+ | `email` | RFC-5322-ish `local@domain.tld` | `[REDACTED:email]` |
278
+ | `phone_us` | US phone formats | `[REDACTED:phone]` |
279
+ | `phone_e164` | International E.164 | `[REDACTED:phone]` |
280
+ | `ssn_us` | `999-99-9999` (with standard exclusions) | `[REDACTED:ssn]` |
281
+ | `ip_address` | IPv4 + IPv6 — **default OFF** (often legitimate metadata) | `[REDACTED:ip]` |
282
+
283
+ ## Docs
284
+
285
+ Full reference — every adapter, all `init()` options, configuration,
286
+ troubleshooting — lives at **[docs.morsehq.dev](https://docs.morsehq.dev)**.
287
+ This README stays a quickstart.
288
+
289
+ ## Naming
290
+
291
+ The npm package is `@morsehq-dev/sdk` (the npm org that exists is
292
+ `morsehq-dev` — npm ties a package scope 1:1 to its owning org login).
293
+ `@morsehq/sdk` is only the internal pnpm workspace identifier used
294
+ inside this monorepo; it is never the published registry name.
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ var chunk7YCENA54_cjs = require('../chunk-7YCENA54.cjs');
4
+ require('../chunk-7EO7MQBA.cjs');
5
+ require('../chunk-KBWPNIH4.cjs');
6
+ require('../chunk-FJUNILZT.cjs');
7
+
8
+
9
+
10
+ Object.defineProperty(exports, "MAX_SEGMENT_CONTENT_BYTES", {
11
+ enumerable: true,
12
+ get: function () { return chunk7YCENA54_cjs.MAX_SEGMENT_CONTENT_BYTES; }
13
+ });
14
+ Object.defineProperty(exports, "_resetAnthropicInstallStateForTesting", {
15
+ enumerable: true,
16
+ get: function () { return chunk7YCENA54_cjs._resetAnthropicInstallStateForTesting; }
17
+ });
18
+ Object.defineProperty(exports, "extractAnthropicSegments", {
19
+ enumerable: true,
20
+ get: function () { return chunk7YCENA54_cjs.extractAnthropicSegments; }
21
+ });
22
+ Object.defineProperty(exports, "instrumentAnthropic", {
23
+ enumerable: true,
24
+ get: function () { return chunk7YCENA54_cjs.instrumentAnthropic; }
25
+ });
26
+ Object.defineProperty(exports, "isAnthropicWrapped", {
27
+ enumerable: true,
28
+ get: function () { return chunk7YCENA54_cjs.isAnthropicWrapped; }
29
+ });
30
+ Object.defineProperty(exports, "uninstallAnthropic", {
31
+ enumerable: true,
32
+ get: function () { return chunk7YCENA54_cjs.uninstallAnthropic; }
33
+ });
34
+ Object.defineProperty(exports, "wrapAnthropic", {
35
+ enumerable: true,
36
+ get: function () { return chunk7YCENA54_cjs.wrapAnthropic; }
37
+ });
38
+ //# sourceMappingURL=index.cjs.map
39
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
@@ -0,0 +1,213 @@
1
+ import { C as ContextSegment } from '../spans-DZtMuBvc.cjs';
2
+
3
+ /**
4
+ * `@morsehq-dev/sdk/anthropic` — Anthropic SDK instrumentation.
5
+ *
6
+ * Wraps `@anthropic-ai/sdk` `client.messages.create` so every Claude call
7
+ * emits an `llm` span carrying pre-segmented `context_segments`. The
8
+ * server-side classifier then skips its own messages-array partitioning
9
+ * and persists the SDK-supplied segments verbatim.
10
+ *
11
+ * Two entry points:
12
+ *
13
+ * - `wrapAnthropic(client)` — returns a Proxy-like wrapper that
14
+ * intercepts `messages.create`. Always succeeds. The customer keeps
15
+ * using the wrapper as if it were the real client.
16
+ *
17
+ * - `instrumentAnthropic(client?)` — top-level helper. If a client is
18
+ * passed, returns the wrapped form. If no client is passed AND the
19
+ * `@anthropic-ai/sdk` package can be loaded, attempts to patch
20
+ * `Messages.prototype.create` so every fresh `new Anthropic()` is
21
+ * instrumented automatically. The prototype path is best-effort —
22
+ * it is documented as fragile across Anthropic SDK versions, and
23
+ * `wrapAnthropic` is the recommended public entry.
24
+ *
25
+ * Idempotent. `uninstallAnthropic()` restores the prototype and clears
26
+ * the install sentinel.
27
+ *
28
+ * Wrapped under `absorbErrors*` so a tracing failure can never break the
29
+ * customer's Anthropic call — at worst, calls go untraced.
30
+ *
31
+ * Mirrors `apps/sdk/typescript/src/vercel-ai/index.ts` in shape and
32
+ * `openspec/changes/.../specs/observability/spec.md` (CTX-08) in
33
+ * segmentation contract.
34
+ */
35
+
36
+ /**
37
+ * Subset of `@anthropic-ai/sdk`'s `MessageCreateParams` we read from. We
38
+ * deliberately decline to import the real types so the SDK works even when
39
+ * `@anthropic-ai/sdk` isn't installed (it's an optional peer dep).
40
+ */
41
+ interface AnthropicMessageCreateParams {
42
+ model: string;
43
+ max_tokens?: number;
44
+ system?: string | AnthropicTextBlockParam[];
45
+ messages: AnthropicMessageParam[];
46
+ tools?: AnthropicToolParam[];
47
+ tool_choice?: unknown;
48
+ [key: string]: unknown;
49
+ }
50
+ interface AnthropicTextBlockParam {
51
+ type: "text";
52
+ text: string;
53
+ cache_control?: {
54
+ type: "ephemeral";
55
+ } | null;
56
+ }
57
+ interface AnthropicToolUseBlockParam {
58
+ type: "tool_use";
59
+ id: string;
60
+ name: string;
61
+ input: unknown;
62
+ }
63
+ interface AnthropicToolResultBlockParam {
64
+ type: "tool_result";
65
+ tool_use_id: string;
66
+ content: string | Array<{
67
+ type: string;
68
+ text?: string;
69
+ [k: string]: unknown;
70
+ }>;
71
+ is_error?: boolean;
72
+ }
73
+ type AnthropicContentBlockParam = AnthropicTextBlockParam | AnthropicToolUseBlockParam | AnthropicToolResultBlockParam | {
74
+ type: string;
75
+ [k: string]: unknown;
76
+ };
77
+ interface AnthropicMessageParam {
78
+ role: "user" | "assistant" | string;
79
+ content: string | AnthropicContentBlockParam[];
80
+ }
81
+ interface AnthropicToolParam {
82
+ name: string;
83
+ description?: string;
84
+ input_schema?: unknown;
85
+ [key: string]: unknown;
86
+ }
87
+ interface AnthropicUsage {
88
+ input_tokens?: number;
89
+ output_tokens?: number;
90
+ cache_creation_input_tokens?: number;
91
+ cache_read_input_tokens?: number;
92
+ [key: string]: unknown;
93
+ }
94
+ interface AnthropicMessageResponse {
95
+ id?: string;
96
+ model?: string;
97
+ usage?: AnthropicUsage;
98
+ content?: Array<{
99
+ type: string;
100
+ text?: string;
101
+ [k: string]: unknown;
102
+ }>;
103
+ [key: string]: unknown;
104
+ }
105
+ /**
106
+ * Structural shape of the Anthropic client we wrap. We only require that
107
+ * `client.messages.create` is a function returning a Promise.
108
+ */
109
+ interface AnthropicClientLike {
110
+ messages: {
111
+ create(params: AnthropicMessageCreateParams, options?: unknown): Promise<AnthropicMessageResponse>;
112
+ [key: string]: unknown;
113
+ };
114
+ [key: string]: unknown;
115
+ }
116
+ interface InstrumentAnthropicOptions {
117
+ /**
118
+ * When provided, used as the parent agent span's name. Defaults to
119
+ * `"anthropic.messages.create"`.
120
+ */
121
+ defaultAgentName?: string;
122
+ /**
123
+ * If a fresh Anthropic *module* import is passed (e.g.,
124
+ * `await import("@anthropic-ai/sdk")`), the adapter will best-effort
125
+ * patch `Messages.prototype.create`. Most users should prefer
126
+ * `wrapAnthropic(client)` instead.
127
+ */
128
+ anthropicModule?: unknown;
129
+ /**
130
+ * When `true` (MEM-11), every wrapped `messages.create` call also
131
+ * emits a sibling `memory`-type span with
132
+ * `metadata.memory_op_type="consolidate"`, `parent_span_id` linking
133
+ * back to the LLM span (server treats this as `producer_span_id`),
134
+ * `metadata.summary_token_count` from the response's output_tokens,
135
+ * and `metadata.summary_content_hash` (SHA-256 of the response's
136
+ * first text block).
137
+ *
138
+ * Use this flag when the customer is calling Claude to summarize
139
+ * their own conversation context (the customer-side compaction
140
+ * pattern). Default `false` — existing callers see zero behavior change.
141
+ *
142
+ * Opt-in only. The adapter never auto-detects summarization from
143
+ * system-prompt content (too many false positives).
144
+ */
145
+ summarize?: boolean;
146
+ }
147
+ /**
148
+ * Wrap an Anthropic client so every `messages.create` call records an
149
+ * `llm` span with `context_segments`. The wrapper preserves the rest of
150
+ * the client's surface (other resources, helpers, etc.) via a Proxy.
151
+ *
152
+ * Idempotent — a previously wrapped client is returned as-is.
153
+ */
154
+ declare function wrapAnthropic<C extends AnthropicClientLike>(client: C, options?: InstrumentAnthropicOptions): C;
155
+ /**
156
+ * Top-level installer. Two modes:
157
+ *
158
+ * - `instrumentAnthropic(client)` — equivalent to `wrapAnthropic(client)`.
159
+ * - `instrumentAnthropic({ anthropicModule: mod })` — best-effort
160
+ * prototype patch. Prefer the wrap form when possible.
161
+ *
162
+ * Always returns the wrapped client, or `undefined` if patching failed.
163
+ * Errors are absorbed; this function never throws back at the caller.
164
+ */
165
+ declare const instrumentAnthropic: <C extends AnthropicClientLike>(clientOrOptions?: InstrumentAnthropicOptions | C | undefined, maybeOptions?: InstrumentAnthropicOptions | undefined) => Promise<boolean | C | undefined>;
166
+ /**
167
+ * Restore the prototype patch and clear the install sentinel.
168
+ *
169
+ * Pass the same module reference that was given to `instrumentAnthropic`
170
+ * (or omit and the function will try to dynamic-import it). Calling
171
+ * `uninstallAnthropic()` on a wrapped client (vs. a module) is a no-op —
172
+ * just discard the wrapped client.
173
+ */
174
+ declare const uninstallAnthropic: (anthropicModule?: unknown) => void | undefined;
175
+ /**
176
+ * Reset module-level install state for tests. Not part of the public API.
177
+ * @internal
178
+ */
179
+ declare function _resetAnthropicInstallStateForTesting(): void;
180
+ /** True when a wrapped Anthropic client is passed in. */
181
+ declare function isAnthropicWrapped(client: unknown): boolean;
182
+ /**
183
+ * Maximum bytes of `content` we ship per segment. Long blobs are truncated
184
+ * with `content_truncated: true`. The server further enforces its own
185
+ * cap; we keep the SDK floor lower to stay friendly to mobile networks.
186
+ */
187
+ declare const MAX_SEGMENT_CONTENT_BYTES = 4096;
188
+ /**
189
+ * Extract `ContextSegment[]` from an Anthropic `messages.create` request
190
+ * + response. The ordering is:
191
+ *
192
+ * 1. `tools` → one `tool_descriptions` segment, position 0.
193
+ * 2. `system` → `system_prompt` segment.
194
+ * 3. Each prior `user` / `assistant` message → `chat_history` segment.
195
+ * `tool_result` blocks (always inside `user.content`) become their
196
+ * own `tool_observation` segments.
197
+ * `tool_use` blocks (assistant-emitted) roll into the parent
198
+ * assistant `chat_history` segment as part of the JSON content.
199
+ * 4. The final `user` message → `current_input`.
200
+ *
201
+ * Cache state heuristic:
202
+ * - `system` blocks with `cache_control.type === "ephemeral"` →
203
+ * `cache_write`.
204
+ * - If the response reports `cache_read_input_tokens > 0`, mark the
205
+ * `system_prompt` and `tool_descriptions` segments as `cache_hit`
206
+ * (overrides `cache_write` — the cache HIT is more informative
207
+ * than the cache write attempt).
208
+ *
209
+ * `tokens` is intentionally left undefined — the server tokenizes.
210
+ */
211
+ declare function extractAnthropicSegments(params: AnthropicMessageCreateParams, response?: AnthropicMessageResponse): ContextSegment[];
212
+
213
+ export { type AnthropicClientLike, type AnthropicContentBlockParam, type AnthropicMessageCreateParams, type AnthropicMessageParam, type AnthropicMessageResponse, type AnthropicTextBlockParam, type AnthropicToolParam, type AnthropicToolResultBlockParam, type AnthropicToolUseBlockParam, type AnthropicUsage, type InstrumentAnthropicOptions, MAX_SEGMENT_CONTENT_BYTES, _resetAnthropicInstallStateForTesting, extractAnthropicSegments, instrumentAnthropic, isAnthropicWrapped, uninstallAnthropic, wrapAnthropic };