@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 +102 -20
- package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/package.json +1 -1
- package/dist/node_modules/@struct-ai/sdk/dist/node_modules/@struct-ai/sdk/package.json +1 -1
- package/dist/node_modules/@struct-ai/sdk/package.json +1 -1
- package/package.json +1 -1
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
|
package/package.json
CHANGED