@struct-ai/sdk 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -20,11 +20,15 @@ Requires Node 18+.
20
20
 
21
21
  ## Quickstart
22
22
 
23
+ Get an ingest key from
24
+ [app.struct.ai/settings?tab=ingest-keys](https://app.struct.ai/settings?tab=ingest-keys),
25
+ then:
26
+
23
27
  ```ts
24
28
  import { struct } from "@struct-ai/sdk";
25
29
  // Initialize once, as early as possible in your process
26
30
  struct.init({
27
- ingestKey: process.env.STRUCT_INGEST_KEY!,
31
+ ingestKey: process.env.STRUCT_INGEST_KEY!, // or pass the string directly
28
32
  serviceName: "my-agent",
29
33
  environment: "production",
30
34
  });
@@ -58,6 +62,103 @@ await struct.agent({ name: "checkout" }, async () => {
58
62
  | `@langchain/core` `BaseRetriever` | `.invoke` | `retrieval {name}` | |
59
63
  | `@langchain/langgraph` `Pregel` | `.invoke`, `.stream` | `invoke_agent {name}` | Covers `createReactAgent`, custom graphs. `thread_id` → `gen_ai.conversation.id` |
60
64
 
65
+ ## Framework integration
66
+
67
+ `struct.init()` takes the same options regardless of which framework
68
+ you're instrumenting. Required: `ingestKey` (get one at
69
+ [app.struct.ai/settings?tab=ingest-keys](https://app.struct.ai/settings?tab=ingest-keys)).
70
+ Recommended: `serviceName`, `environment`.
71
+
72
+ What you need to do beyond `init()` depends on whether you're using an
73
+ **agent framework** (which has built-in concepts of agents and tools) or
74
+ an **LLM SDK directly** (which only knows about chat completions). The
75
+ SDK auto-instruments both, but only agent frameworks get full agent +
76
+ tool spans for free — when you call an LLM SDK directly, you have to
77
+ tell the SDK where the agent and tool boundaries are.
78
+
79
+ Call `init()` once, as early as possible, *before* the instrumented
80
+ libraries are imported, so their prototypes are patched before any
81
+ instance is constructed.
82
+
83
+ ### Agent frameworks — fully auto-instrumented
84
+
85
+ For these, calling `struct.init()` is the only setup. Agent, tool, chat,
86
+ and retrieval spans all emit automatically.
87
+
88
+ #### LangChain / LangGraph (with an agent or graph)
89
+
90
+ ```ts
91
+ import { struct } from "@struct-ai/sdk";
92
+ struct.init({ ingestKey: "pk-...", serviceName: "my-graph" });
93
+
94
+ import { createReactAgent } from "@langchain/langgraph/prebuilt";
95
+ // Pregel invocations get invoke_agent spans. BaseChatModel calls get
96
+ // chat spans. StructuredTool.invoke gets execute_tool spans.
97
+ // BaseRetriever.invoke gets retrieval spans.
98
+ ```
99
+
100
+ ### LLM SDKs used directly — manual agent + tool scopes required
101
+
102
+ When you call an LLM SDK directly (no agent framework wrapping it), only
103
+ `chat` spans emit automatically. You need to wrap your agent loop in
104
+ `struct.agent()` and each tool execution in `struct.tool()` so the SDK
105
+ knows where to put the agent and tool boundaries — otherwise you'll see
106
+ free-floating chat spans with no agent or tool context around them.
107
+
108
+ #### Anthropic SDK (raw)
109
+
110
+ ```ts
111
+ import { struct } from "@struct-ai/sdk";
112
+ struct.init({ ingestKey: "pk-...", serviceName: "checkout-agent" });
113
+
114
+ import Anthropic from "@anthropic-ai/sdk";
115
+ const client = new Anthropic();
116
+
117
+ // Required: wrap the agent loop yourself.
118
+ await struct.agent({ name: "checkout" }, async () => {
119
+ const msg = await client.messages.create({
120
+ model: "claude-3-5-sonnet-20241022",
121
+ max_tokens: 1024,
122
+ messages: [...],
123
+ });
124
+
125
+ // Required: wrap each tool execution.
126
+ // tool_call_id is auto-filled from the preceding Anthropic response.
127
+ await struct.tool({ name: "search" }, async () => {
128
+ return await search(...);
129
+ });
130
+ });
131
+ ```
132
+
133
+ `@anthropic-ai/sdk`, `@anthropic-ai/bedrock-sdk`, and `@anthropic-ai/vertex-sdk`
134
+ are all auto-instrumented for chat spans.
135
+
136
+ #### LangChain `BaseChatModel` (no agent/graph)
137
+
138
+ If you call `ChatAnthropic.invoke(...)` (or any other `BaseChatModel`)
139
+ without wrapping it in `AgentExecutor` or a LangGraph graph, only the chat
140
+ span emits automatically. Same rule as raw Anthropic — wrap your agent
141
+ loop in `struct.agent()` and tool execution in `struct.tool()`.
142
+
143
+ ```ts
144
+ import { struct } from "@struct-ai/sdk";
145
+ struct.init({ ingestKey: "pk-...", serviceName: "my-agent" });
146
+
147
+ import { ChatAnthropic } from "@langchain/anthropic";
148
+ const llm = new ChatAnthropic({ model: "claude-3-5-sonnet-20241022" });
149
+
150
+ await struct.agent({ name: "my-agent" }, async () => {
151
+ const response = await llm.invoke([["user", "..."]]);
152
+ await struct.tool({ name: "search" }, async () => {
153
+ // ...
154
+ });
155
+ });
156
+ ```
157
+
158
+ When you do use `ChatAnthropic` *and* have `@anthropic-ai/sdk` installed,
159
+ the chat span comes from the Anthropic patch (single span); the LangChain
160
+ layer suppresses its duplicate.
161
+
61
162
  ## Content capture
62
163
 
63
164
  The SDK supports four capture modes controlling how prompt/response content is emitted.
@@ -144,25 +245,6 @@ response excludes). Matches the Python SDK.
144
245
  attribute is still set, so "Spawned by" on the child side still renders —
145
246
  but the parent's forward link to the subagent won't appear.
146
247
 
147
- ## Parity with the Python SDK
148
-
149
- Span names, attribute keys, and log event shapes match `struct-sdk-python`
150
- byte-for-byte. Running the same agent logic in both SDKs against the same
151
- tenant produces structurally identical traces in the Struct UI.
152
-
153
- One deliberate divergence: the TS SDK finalizes streaming chat spans via the
154
- `finalMessage` event, closing a known gap in the Python SDK where
155
- `messages.stream()` didn't populate the pending-tool-call queue.
156
-
157
- ## Development
158
-
159
- ```bash
160
- pnpm install
161
- pnpm -F @struct-ai/sdk typecheck
162
- pnpm -F @struct-ai/sdk test
163
- pnpm -F @struct-ai/sdk build
164
- ```
165
-
166
248
  ## License
167
249
 
168
250
  Apache-2.0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struct-ai/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Struct agent observability SDK — auto-instruments AI agent frameworks with OpenTelemetry",
5
5
  "type": "module",
6
6
  "main": "./dist/commonjs/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struct-ai/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Struct agent observability SDK — auto-instruments AI agent frameworks with OpenTelemetry",
5
5
  "type": "module",
6
6
  "main": "./dist/commonjs/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struct-ai/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Struct agent observability SDK — auto-instruments AI agent frameworks with OpenTelemetry",
5
5
  "type": "module",
6
6
  "main": "./dist/commonjs/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struct-ai/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Struct agent observability SDK — auto-instruments AI agent frameworks with OpenTelemetry",
5
5
  "type": "module",
6
6
  "main": "./dist/commonjs/index.js",