@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.
- package/LICENSE +21 -0
- package/README.md +294 -0
- package/dist/anthropic/index.cjs +39 -0
- package/dist/anthropic/index.cjs.map +1 -0
- package/dist/anthropic/index.d.cts +213 -0
- package/dist/anthropic/index.d.ts +213 -0
- package/dist/anthropic/index.js +6 -0
- package/dist/anthropic/index.js.map +1 -0
- package/dist/anthropic-agent-sdk/index.cjs +744 -0
- package/dist/anthropic-agent-sdk/index.cjs.map +1 -0
- package/dist/anthropic-agent-sdk/index.d.cts +371 -0
- package/dist/anthropic-agent-sdk/index.d.ts +371 -0
- package/dist/anthropic-agent-sdk/index.js +735 -0
- package/dist/anthropic-agent-sdk/index.js.map +1 -0
- package/dist/browser/anthropic/index.cjs +39 -0
- package/dist/browser/anthropic/index.cjs.map +1 -0
- package/dist/browser/anthropic/index.js +6 -0
- package/dist/browser/anthropic/index.js.map +1 -0
- package/dist/browser/anthropic-agent-sdk/index.cjs +744 -0
- package/dist/browser/anthropic-agent-sdk/index.cjs.map +1 -0
- package/dist/browser/anthropic-agent-sdk/index.js +735 -0
- package/dist/browser/anthropic-agent-sdk/index.js.map +1 -0
- package/dist/browser/chunk-3643DC7K.cjs +365 -0
- package/dist/browser/chunk-3643DC7K.cjs.map +1 -0
- package/dist/browser/chunk-4FALQMOZ.js +232 -0
- package/dist/browser/chunk-4FALQMOZ.js.map +1 -0
- package/dist/browser/chunk-5J2QBK75.js +884 -0
- package/dist/browser/chunk-5J2QBK75.js.map +1 -0
- package/dist/browser/chunk-7MSXWGAH.js +53 -0
- package/dist/browser/chunk-7MSXWGAH.js.map +1 -0
- package/dist/browser/chunk-A24L5N5N.js +596 -0
- package/dist/browser/chunk-A24L5N5N.js.map +1 -0
- package/dist/browser/chunk-B7DEUDP6.cjs +177 -0
- package/dist/browser/chunk-B7DEUDP6.cjs.map +1 -0
- package/dist/browser/chunk-F6CJACNH.cjs +604 -0
- package/dist/browser/chunk-F6CJACNH.cjs.map +1 -0
- package/dist/browser/chunk-JBOYFQSB.js +412 -0
- package/dist/browser/chunk-JBOYFQSB.js.map +1 -0
- package/dist/browser/chunk-KRBADE6R.cjs +183 -0
- package/dist/browser/chunk-KRBADE6R.cjs.map +1 -0
- package/dist/browser/chunk-MCJYZH6W.cjs +415 -0
- package/dist/browser/chunk-MCJYZH6W.cjs.map +1 -0
- package/dist/browser/chunk-NQG2IAQS.js +178 -0
- package/dist/browser/chunk-NQG2IAQS.js.map +1 -0
- package/dist/browser/chunk-O4HG3OSK.cjs +929 -0
- package/dist/browser/chunk-O4HG3OSK.cjs.map +1 -0
- package/dist/browser/chunk-QWRQJO57.js +363 -0
- package/dist/browser/chunk-QWRQJO57.js.map +1 -0
- package/dist/browser/chunk-SWQOPFE4.cjs +234 -0
- package/dist/browser/chunk-SWQOPFE4.cjs.map +1 -0
- package/dist/browser/chunk-TYDG747E.js +171 -0
- package/dist/browser/chunk-TYDG747E.js.map +1 -0
- package/dist/browser/chunk-TZRSDDFP.cjs +56 -0
- package/dist/browser/chunk-TZRSDDFP.cjs.map +1 -0
- package/dist/browser/index.cjs +587 -0
- package/dist/browser/index.cjs.map +1 -0
- package/dist/browser/index.js +522 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/integrations/pino.cjs +89 -0
- package/dist/browser/integrations/pino.cjs.map +1 -0
- package/dist/browser/integrations/pino.js +86 -0
- package/dist/browser/integrations/pino.js.map +1 -0
- package/dist/browser/langchain/index.cjs +535 -0
- package/dist/browser/langchain/index.cjs.map +1 -0
- package/dist/browser/langchain/index.js +528 -0
- package/dist/browser/langchain/index.js.map +1 -0
- package/dist/browser/langgraph/index.cjs +377 -0
- package/dist/browser/langgraph/index.cjs.map +1 -0
- package/dist/browser/langgraph/index.js +371 -0
- package/dist/browser/langgraph/index.js.map +1 -0
- package/dist/browser/openai/index.cjs +125 -0
- package/dist/browser/openai/index.cjs.map +1 -0
- package/dist/browser/openai/index.js +122 -0
- package/dist/browser/openai/index.js.map +1 -0
- package/dist/browser/openai-agents/index.cjs +689 -0
- package/dist/browser/openai-agents/index.cjs.map +1 -0
- package/dist/browser/openai-agents/index.js +678 -0
- package/dist/browser/openai-agents/index.js.map +1 -0
- package/dist/browser/vercel-ai/index.cjs +233 -0
- package/dist/browser/vercel-ai/index.cjs.map +1 -0
- package/dist/browser/vercel-ai/index.js +231 -0
- package/dist/browser/vercel-ai/index.js.map +1 -0
- package/dist/chunk-4R4SHGOK.js +363 -0
- package/dist/chunk-4R4SHGOK.js.map +1 -0
- package/dist/chunk-7EO7MQBA.cjs +183 -0
- package/dist/chunk-7EO7MQBA.cjs.map +1 -0
- package/dist/chunk-7YCENA54.cjs +604 -0
- package/dist/chunk-7YCENA54.cjs.map +1 -0
- package/dist/chunk-CKFOGDUF.js +596 -0
- package/dist/chunk-CKFOGDUF.js.map +1 -0
- package/dist/chunk-FJUNILZT.cjs +1324 -0
- package/dist/chunk-FJUNILZT.cjs.map +1 -0
- package/dist/chunk-HDAFUKQ3.js +171 -0
- package/dist/chunk-HDAFUKQ3.js.map +1 -0
- package/dist/chunk-KBWPNIH4.cjs +234 -0
- package/dist/chunk-KBWPNIH4.cjs.map +1 -0
- package/dist/chunk-KJEO52QS.cjs +365 -0
- package/dist/chunk-KJEO52QS.cjs.map +1 -0
- package/dist/chunk-KZBCOZIQ.cjs +177 -0
- package/dist/chunk-KZBCOZIQ.cjs.map +1 -0
- package/dist/chunk-ME5JALGT.js +53 -0
- package/dist/chunk-ME5JALGT.js.map +1 -0
- package/dist/chunk-PVHDEPRE.cjs +56 -0
- package/dist/chunk-PVHDEPRE.cjs.map +1 -0
- package/dist/chunk-RTL23YOQ.js +178 -0
- package/dist/chunk-RTL23YOQ.js.map +1 -0
- package/dist/chunk-TQWI4UYO.js +1277 -0
- package/dist/chunk-TQWI4UYO.js.map +1 -0
- package/dist/chunk-VXDBDPDR.cjs +415 -0
- package/dist/chunk-VXDBDPDR.cjs.map +1 -0
- package/dist/chunk-XTKMUJWI.js +232 -0
- package/dist/chunk-XTKMUJWI.js.map +1 -0
- package/dist/chunk-ZKUGOWER.js +412 -0
- package/dist/chunk-ZKUGOWER.js.map +1 -0
- package/dist/index.cjs +843 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +464 -0
- package/dist/index.d.ts +464 -0
- package/dist/index.js +778 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/pino.cjs +89 -0
- package/dist/integrations/pino.cjs.map +1 -0
- package/dist/integrations/pino.d.cts +65 -0
- package/dist/integrations/pino.d.ts +65 -0
- package/dist/integrations/pino.js +86 -0
- package/dist/integrations/pino.js.map +1 -0
- package/dist/langchain/index.cjs +535 -0
- package/dist/langchain/index.cjs.map +1 -0
- package/dist/langchain/index.d.cts +265 -0
- package/dist/langchain/index.d.ts +265 -0
- package/dist/langchain/index.js +528 -0
- package/dist/langchain/index.js.map +1 -0
- package/dist/langgraph/index.cjs +377 -0
- package/dist/langgraph/index.cjs.map +1 -0
- package/dist/langgraph/index.d.cts +324 -0
- package/dist/langgraph/index.d.ts +324 -0
- package/dist/langgraph/index.js +371 -0
- package/dist/langgraph/index.js.map +1 -0
- package/dist/openai/index.cjs +125 -0
- package/dist/openai/index.cjs.map +1 -0
- package/dist/openai/index.d.cts +136 -0
- package/dist/openai/index.d.ts +136 -0
- package/dist/openai/index.js +122 -0
- package/dist/openai/index.js.map +1 -0
- package/dist/openai-agents/index.cjs +689 -0
- package/dist/openai-agents/index.cjs.map +1 -0
- package/dist/openai-agents/index.d.cts +502 -0
- package/dist/openai-agents/index.d.ts +502 -0
- package/dist/openai-agents/index.js +678 -0
- package/dist/openai-agents/index.js.map +1 -0
- package/dist/spans-DZtMuBvc.d.cts +73 -0
- package/dist/spans-DZtMuBvc.d.ts +73 -0
- package/dist/tracing-BYAqjT5Q.d.cts +114 -0
- package/dist/tracing-rz9cWQ8d.d.ts +114 -0
- package/dist/vercel-ai/index.cjs +233 -0
- package/dist/vercel-ai/index.cjs.map +1 -0
- package/dist/vercel-ai/index.d.cts +93 -0
- package/dist/vercel-ai/index.d.ts +93 -0
- package/dist/vercel-ai/index.js +231 -0
- package/dist/vercel-ai/index.js.map +1 -0
- 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 };
|