@temporalio/langsmith 1.20.0
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 +216 -0
- package/lib/activity-interceptor.d.ts +21 -0
- package/lib/activity-interceptor.js +121 -0
- package/lib/activity-interceptor.js.map +1 -0
- package/lib/client-interceptor.d.ts +11 -0
- package/lib/client-interceptor.js +82 -0
- package/lib/client-interceptor.js.map +1 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +11 -0
- package/lib/index.js.map +1 -0
- package/lib/plugin.d.ts +88 -0
- package/lib/plugin.js +235 -0
- package/lib/plugin.js.map +1 -0
- package/lib/propagation.d.ts +57 -0
- package/lib/propagation.js +134 -0
- package/lib/propagation.js.map +1 -0
- package/lib/run-tree.d.ts +94 -0
- package/lib/run-tree.js +319 -0
- package/lib/run-tree.js.map +1 -0
- package/lib/sinks.d.ts +54 -0
- package/lib/sinks.js +72 -0
- package/lib/sinks.js.map +1 -0
- package/lib/workflow-interceptors.d.ts +14 -0
- package/lib/workflow-interceptors.js +350 -0
- package/lib/workflow-interceptors.js.map +1 -0
- package/package.json +88 -0
- package/src/activity-interceptor.ts +139 -0
- package/src/client-interceptor.ts +109 -0
- package/src/index.ts +8 -0
- package/src/plugin.ts +300 -0
- package/src/propagation.ts +153 -0
- package/src/run-tree.ts +330 -0
- package/src/sinks.ts +119 -0
- package/src/workflow-interceptors.ts +532 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-2025 Temporal Technologies Inc. All rights reserved.
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# @temporalio/langsmith — LangSmith tracing for Temporal
|
|
2
|
+
|
|
3
|
+
This plugin makes [LangSmith](https://docs.smith.langchain.com/) observability
|
|
4
|
+
work inside Temporal Workflows and Activities **without changing your existing
|
|
5
|
+
instrumentation**. Code you already trace with LangSmith's native `traceable`
|
|
6
|
+
keeps working when you move it into a Workflow or Activity body — you only add
|
|
7
|
+
the plugin to your `Client` and `Worker`.
|
|
8
|
+
|
|
9
|
+
This plugin is built on Temporal's Plugin API, which is experimental; its APIs
|
|
10
|
+
may change in a future release.
|
|
11
|
+
|
|
12
|
+
It handles the parts that are otherwise hard:
|
|
13
|
+
|
|
14
|
+
- **Replay safety.** Workflows replay history; a naive tracer re-emits every run
|
|
15
|
+
on every replay and floods your project with duplicates. This plugin emits
|
|
16
|
+
runs with deterministic IDs out-of-isolate via a Temporal Sink that does not
|
|
17
|
+
fire during replay.
|
|
18
|
+
- **Run parenting across boundaries.** A trace started on the client threads
|
|
19
|
+
through `workflow → activity → child-workflow → Nexus` so the runs nest the
|
|
20
|
+
way you expect, instead of fragmenting into disconnected roots.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @temporalio/langsmith langsmith
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`langsmith` is a peer dependency — install the version your project already uses.
|
|
29
|
+
|
|
30
|
+
## Enable tracing
|
|
31
|
+
|
|
32
|
+
Tracing is **off by default**, matching the `langsmith` library: the plugin
|
|
33
|
+
emits nothing unless LangSmith tracing is enabled in the worker/client process
|
|
34
|
+
environment. Enable it with LangSmith's standard environment variables:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
export LANGSMITH_TRACING=true
|
|
38
|
+
export LANGSMITH_API_KEY="<your key>"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The plugin reads the same flags LangSmith itself uses (`LANGSMITH_TRACING` /
|
|
42
|
+
`LANGSMITH_TRACING_V2` and their `LANGCHAIN_` aliases); with none set to `true`,
|
|
43
|
+
tracing stays off and the plugin is a no-op.
|
|
44
|
+
|
|
45
|
+
## Hello world
|
|
46
|
+
|
|
47
|
+
Your existing LangSmith instrumentation does not change. Here a `traceable`
|
|
48
|
+
runs inside an Activity:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// activities.ts
|
|
52
|
+
import { traceable } from 'langsmith/traceable';
|
|
53
|
+
|
|
54
|
+
const callModel = traceable(
|
|
55
|
+
async (prompt: string) => {
|
|
56
|
+
// ... your real model call ...
|
|
57
|
+
return `answer to: ${prompt}`;
|
|
58
|
+
},
|
|
59
|
+
{ name: 'inner_llm_call' }
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
export async function answer(prompt: string): Promise<string> {
|
|
63
|
+
return callModel(prompt);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// workflows.ts
|
|
69
|
+
import { proxyActivities } from '@temporalio/workflow';
|
|
70
|
+
import type * as activities from './activities';
|
|
71
|
+
|
|
72
|
+
const { answer } = proxyActivities<typeof activities>({
|
|
73
|
+
startToCloseTimeout: '1 minute',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export async function GreetingWorkflow(prompt: string): Promise<string> {
|
|
77
|
+
return answer(prompt);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The only new code is the plugin registration on the `Client` and the `Worker`:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// worker.ts
|
|
85
|
+
import { Worker } from '@temporalio/worker';
|
|
86
|
+
import { Client } from '@temporalio/client';
|
|
87
|
+
import { Client as LangSmithClient } from 'langsmith';
|
|
88
|
+
import { LangSmithPlugin } from '@temporalio/langsmith';
|
|
89
|
+
import * as activities from './activities';
|
|
90
|
+
|
|
91
|
+
const langsmith = new LangSmithClient(); // reads LANGSMITH_API_KEY from the env
|
|
92
|
+
|
|
93
|
+
// In TypeScript the Client and Worker are configured independently, so add the
|
|
94
|
+
// plugin to each. (Construct one plugin instance and share it.)
|
|
95
|
+
const plugin = new LangSmithPlugin({ client: langsmith, addTemporalRuns: true });
|
|
96
|
+
|
|
97
|
+
const client = new Client({ plugins: [plugin] });
|
|
98
|
+
|
|
99
|
+
const worker = await Worker.create({
|
|
100
|
+
taskQueue: 'greeting',
|
|
101
|
+
workflowsPath: require.resolve('./workflows'),
|
|
102
|
+
activities,
|
|
103
|
+
plugins: [plugin],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
await worker.run();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// starter.ts — start the workflow from inside your own trace
|
|
111
|
+
import { traceable } from 'langsmith/traceable';
|
|
112
|
+
|
|
113
|
+
const pipeline = traceable(
|
|
114
|
+
async () => {
|
|
115
|
+
return client.workflow.execute(GreetingWorkflow, {
|
|
116
|
+
taskQueue: 'greeting',
|
|
117
|
+
workflowId: 'greeting-1',
|
|
118
|
+
args: ['hello'],
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
{ name: 'user_pipeline' }
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
await pipeline();
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
With `addTemporalRuns: true`, the resulting trace nests like this:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
user_pipeline
|
|
131
|
+
StartWorkflow:GreetingWorkflow
|
|
132
|
+
RunWorkflow:GreetingWorkflow
|
|
133
|
+
StartActivity:answer
|
|
134
|
+
RunActivity:answer
|
|
135
|
+
inner_llm_call
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Set `addTemporalRuns: false` (the default) to emit only your own `traceable`
|
|
139
|
+
runs — the trace context still propagates across boundaries, so they nest
|
|
140
|
+
correctly, but no `StartWorkflow:` / `RunActivity:` scaffolding is added:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
user_pipeline
|
|
144
|
+
inner_llm_call
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Options
|
|
148
|
+
|
|
149
|
+
| Option | Default | Meaning |
|
|
150
|
+
| ----------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
151
|
+
| `client` | `new Client()` | The LangSmith client runs are emitted to. Lives only in the worker/client process — it is never serialized or sent across a Temporal boundary. |
|
|
152
|
+
| `addTemporalRuns` | `false` | Emit first-class runs for Temporal operations (`StartWorkflow:`, `RunActivity:`, `HandleSignal:`, …) in addition to your `traceable` runs. |
|
|
153
|
+
| `projectName` | LangSmith default | Target LangSmith project for emitted runs. |
|
|
154
|
+
| `tags` | — | Tags attached to every run the plugin emits. |
|
|
155
|
+
| `metadata` | — | Metadata merged into every run the plugin emits. Credential-looking keys are scrubbed before emission. |
|
|
156
|
+
|
|
157
|
+
The LangSmith API key is never accepted as a plugin option and never crosses a
|
|
158
|
+
Temporal boundary. Supply a pre-constructed `Client` (which reads
|
|
159
|
+
`LANGSMITH_API_KEY` from the process environment) or let the plugin build a
|
|
160
|
+
default client from the environment.
|
|
161
|
+
|
|
162
|
+
## Where `traceable` works
|
|
163
|
+
|
|
164
|
+
`traceable` from `langsmith/traceable` works **unchanged** in every position
|
|
165
|
+
below. Each row is exercised by the plugin's test suite.
|
|
166
|
+
|
|
167
|
+
| Position | Works? | Notes |
|
|
168
|
+
| ------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
169
|
+
| Client side, before `client.workflow.start(...)` | ✅ | The trace propagates into the workflow; `RunWorkflow:` nests under your run. |
|
|
170
|
+
| Inside an **Activity** body | ✅ | Runs in the real worker process. Nests under `RunActivity:` (or under the propagated parent when `addTemporalRuns: false`). |
|
|
171
|
+
| Inside a **Workflow** body | ✅ | Replay-safe: deterministic IDs, emitted out-of-isolate, suppressed on replay. Works whether or not a parent trace is propagated in. |
|
|
172
|
+
| Inside **signal / query / update** handlers | ✅ | Handler-body `traceable` runs nest under the handler's run (workflow-body semantics). Temporal-internal queries (`__temporal*`, `__stack_trace`) are never traced. |
|
|
173
|
+
|
|
174
|
+
**Concurrency caveat (workflow body only).** Inside a Workflow, parent
|
|
175
|
+
resolution uses a synchronous context stack rather than `node:async_hooks`
|
|
176
|
+
(which is unavailable in the workflow isolate). Sequential `await inner(...)`
|
|
177
|
+
nesting is exact. Under `Promise.all(...)` fan-out, or for `traceable` calls
|
|
178
|
+
made _after_ an `await` in the same scope, parenting falls back to the workflow
|
|
179
|
+
run. This affects only the visual shape of the trace, never workflow history or
|
|
180
|
+
control flow. Activity-body and client-side `traceable` use LangSmith's real
|
|
181
|
+
async context and are unaffected.
|
|
182
|
+
|
|
183
|
+
## Process-wide effects to be aware of
|
|
184
|
+
|
|
185
|
+
- **Workflow context provider.** Loading the plugin's workflow interceptor
|
|
186
|
+
module installs a global LangSmith async-context provider inside the workflow
|
|
187
|
+
isolate (via `AsyncLocalStorageProviderSingleton.initializeGlobalInstance`).
|
|
188
|
+
This is what lets unchanged `traceable` calls find their parent inside a
|
|
189
|
+
Workflow. It is scoped to the workflow bundle and does not affect your
|
|
190
|
+
client/worker process context.
|
|
191
|
+
|
|
192
|
+
## Composing with other plugins
|
|
193
|
+
|
|
194
|
+
Register observability **first** (outermost) so it observes everything beneath
|
|
195
|
+
it, then governance, then agent-framework plugins:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
const worker = await Worker.create({
|
|
199
|
+
taskQueue: 'tq',
|
|
200
|
+
workflowsPath: require.resolve('./workflows'),
|
|
201
|
+
activities,
|
|
202
|
+
plugins: [
|
|
203
|
+
new LangSmithPlugin({ client: langsmith }), // observability — first
|
|
204
|
+
// new GovernancePlugin(...),
|
|
205
|
+
// new AgentFrameworkPlugin(...),
|
|
206
|
+
],
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The plugin is safe to register on both the `Client` and the `Worker`; it
|
|
211
|
+
de-duplicates its own interceptors and sinks, so a worker built from a
|
|
212
|
+
plugin-configured client will not double-instrument.
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity-side and Nexus-handler-side LangSmith interceptors. Both run in the
|
|
3
|
+
* real Node worker process and install the reconstructed run via `withRunTree`
|
|
4
|
+
* so a user's unchanged body `traceable` calls nest under it.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { ActivityInboundCallsInterceptorFactory, NexusInboundCallsInterceptor } from '@temporalio/worker';
|
|
9
|
+
import type { EmitterConfig } from './sinks';
|
|
10
|
+
/**
|
|
11
|
+
* Build the activity-inbound interceptor factory. The worker calls the factory
|
|
12
|
+
* once per activity with that activity's {@link ActivityContext}, from which we
|
|
13
|
+
* read the activity type for the run name.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createActivityInboundInterceptor(config: EmitterConfig): ActivityInboundCallsInterceptorFactory;
|
|
16
|
+
/**
|
|
17
|
+
* Build the Nexus-handler interceptor. `startOperation` opens a
|
|
18
|
+
* `RunStartNexusOperationHandler:` run (so workflows the handler starts nest
|
|
19
|
+
* under it); `cancelOperation` opens `RunCancelNexusOperationHandler:`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createNexusInboundInterceptor(config: EmitterConfig): NexusInboundCallsInterceptor;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Activity-side and Nexus-handler-side LangSmith interceptors. Both run in the
|
|
4
|
+
* real Node worker process and install the reconstructed run via `withRunTree`
|
|
5
|
+
* so a user's unchanged body `traceable` calls nest under it.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createActivityInboundInterceptor = createActivityInboundInterceptor;
|
|
11
|
+
exports.createNexusInboundInterceptor = createNexusInboundInterceptor;
|
|
12
|
+
const langsmith_1 = require("langsmith");
|
|
13
|
+
const run_trees_1 = require("langsmith/run_trees");
|
|
14
|
+
const traceable_1 = require("langsmith/traceable");
|
|
15
|
+
const propagation_1 = require("./propagation");
|
|
16
|
+
const run_tree_1 = require("./run-tree");
|
|
17
|
+
/**
|
|
18
|
+
* Reconstruct the propagated parent run from a LangSmith trace context, wired to
|
|
19
|
+
* the plugin-configured client so descendant runs emit to the right place. The
|
|
20
|
+
* returned run is the *parent* — never posted itself — used only to parent
|
|
21
|
+
* the operation run (or directly as ambient when `addTemporalRuns` is off).
|
|
22
|
+
*/
|
|
23
|
+
function reconstructParentRun(config, ctx) {
|
|
24
|
+
const parsed = (0, run_tree_1.runTreeFromContext)(ctx);
|
|
25
|
+
if (!parsed) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return new run_trees_1.RunTree({
|
|
29
|
+
name: parsed.name || 'parent',
|
|
30
|
+
run_type: parsed.run_type || run_tree_1.RUN_TYPE.CHAIN,
|
|
31
|
+
id: parsed.id,
|
|
32
|
+
trace_id: parsed.trace_id,
|
|
33
|
+
dotted_order: parsed.dotted_order,
|
|
34
|
+
parent_run_id: parsed.parent_run_id,
|
|
35
|
+
project_name: config.projectName ?? parsed.project_name,
|
|
36
|
+
client: config.client,
|
|
37
|
+
// Force-enable so nested body `traceable` runs emit; tracing gate is `isTracingEnabled()`.
|
|
38
|
+
tracingEnabled: true,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Run `fn` with `op` installed as the active LangSmith run, emitting the run
|
|
43
|
+
* around the call. Shared by activity and Nexus handlers.
|
|
44
|
+
*/
|
|
45
|
+
async function traceOperation(op, fn) {
|
|
46
|
+
await op.postRun();
|
|
47
|
+
try {
|
|
48
|
+
const result = await (0, traceable_1.withRunTree)(op, fn);
|
|
49
|
+
await op.end((0, run_tree_1.asOutputs)(result));
|
|
50
|
+
await op.patchRun();
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
await op.end(undefined, (0, run_tree_1.describeError)(err));
|
|
55
|
+
await op.patchRun();
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build the activity-inbound interceptor factory. The worker calls the factory
|
|
61
|
+
* once per activity with that activity's {@link ActivityContext}, from which we
|
|
62
|
+
* read the activity type for the run name.
|
|
63
|
+
*/
|
|
64
|
+
function createActivityInboundInterceptor(config) {
|
|
65
|
+
return (ctx) => ({
|
|
66
|
+
async execute(input, next) {
|
|
67
|
+
if (!(0, langsmith_1.isTracingEnabled)()) {
|
|
68
|
+
return next(input);
|
|
69
|
+
}
|
|
70
|
+
const parent = reconstructParentRun(config, (0, propagation_1.readContextHeader)(input.headers));
|
|
71
|
+
if (!config.addTemporalRuns) {
|
|
72
|
+
// Propagation only: nest the user's body `traceable` runs under the
|
|
73
|
+
// reconstructed parent without emitting a Temporal-operation run.
|
|
74
|
+
// No propagated parent: run the body with no ambient run by design (nothing to attach to).
|
|
75
|
+
return parent ? (0, traceable_1.withRunTree)(parent, () => next(input)) : next(input);
|
|
76
|
+
}
|
|
77
|
+
const activityType = ctx.info.activityType;
|
|
78
|
+
const run = (0, run_tree_1.buildRunTree)(config, {
|
|
79
|
+
name: (0, run_tree_1.runActivityRunName)(activityType),
|
|
80
|
+
runType: run_tree_1.RUN_TYPE.TOOL,
|
|
81
|
+
parent,
|
|
82
|
+
inputs: { args: input.args },
|
|
83
|
+
});
|
|
84
|
+
return traceOperation(run, () => next(input));
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function nexusContext(headers) {
|
|
89
|
+
return (0, propagation_1.decodeContextString)(headers[propagation_1.HEADER_KEY]);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build the Nexus-handler interceptor. `startOperation` opens a
|
|
93
|
+
* `RunStartNexusOperationHandler:` run (so workflows the handler starts nest
|
|
94
|
+
* under it); `cancelOperation` opens `RunCancelNexusOperationHandler:`.
|
|
95
|
+
*/
|
|
96
|
+
function createNexusInboundInterceptor(config) {
|
|
97
|
+
const handle = async (input, next, nameOf) => {
|
|
98
|
+
if (!(0, langsmith_1.isTracingEnabled)()) {
|
|
99
|
+
return next(input);
|
|
100
|
+
}
|
|
101
|
+
const parent = reconstructParentRun(config, nexusContext(input.ctx.headers));
|
|
102
|
+
if (!config.addTemporalRuns) {
|
|
103
|
+
return parent ? (0, traceable_1.withRunTree)(parent, () => next(input)) : next(input);
|
|
104
|
+
}
|
|
105
|
+
const run = (0, run_tree_1.buildRunTree)(config, {
|
|
106
|
+
name: nameOf(input.ctx.service, input.ctx.operation),
|
|
107
|
+
runType: run_tree_1.RUN_TYPE.CHAIN,
|
|
108
|
+
parent,
|
|
109
|
+
});
|
|
110
|
+
return traceOperation(run, () => next(input));
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
startOperation(input, next) {
|
|
114
|
+
return handle(input, next, run_tree_1.runStartNexusHandlerRunName);
|
|
115
|
+
},
|
|
116
|
+
cancelOperation(input, next) {
|
|
117
|
+
return handle(input, next, run_tree_1.runCancelNexusHandlerRunName);
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=activity-interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-interceptor.js","sourceRoot":"","sources":["../src/activity-interceptor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side LangSmith interceptor. Execution ops (`start`) emit a peer marker
|
|
3
|
+
* and propagate the **ambient** context (the remote run is a sibling); messaging
|
|
4
|
+
* ops (`signal`, `query`, `update`, …) emit the marker and propagate the
|
|
5
|
+
* **marker** context (the remote handler nests under it).
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { WorkflowClientInterceptor } from '@temporalio/client';
|
|
10
|
+
import type { EmitterConfig } from './sinks';
|
|
11
|
+
export declare function createClientInterceptor(config: EmitterConfig): WorkflowClientInterceptor;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Client-side LangSmith interceptor. Execution ops (`start`) emit a peer marker
|
|
4
|
+
* and propagate the **ambient** context (the remote run is a sibling); messaging
|
|
5
|
+
* ops (`signal`, `query`, `update`, …) emit the marker and propagate the
|
|
6
|
+
* **marker** context (the remote handler nests under it).
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.createClientInterceptor = createClientInterceptor;
|
|
12
|
+
const langsmith_1 = require("langsmith");
|
|
13
|
+
const traceable_1 = require("langsmith/traceable");
|
|
14
|
+
const propagation_1 = require("./propagation");
|
|
15
|
+
const run_tree_1 = require("./run-tree");
|
|
16
|
+
function createClientInterceptor(config) {
|
|
17
|
+
const peerStart = async (input, next, name, args) => {
|
|
18
|
+
if (!(0, langsmith_1.isTracingEnabled)()) {
|
|
19
|
+
return next(input);
|
|
20
|
+
}
|
|
21
|
+
const ambient = (0, traceable_1.getCurrentRunTree)(true);
|
|
22
|
+
if (config.addTemporalRuns) {
|
|
23
|
+
await (0, run_tree_1.emitMarkerRun)((0, run_tree_1.buildRunTree)(config, { name, runType: run_tree_1.RUN_TYPE.CHAIN, parent: ambient, inputs: { args } }));
|
|
24
|
+
}
|
|
25
|
+
const headers = (0, propagation_1.withContextHeader)(input.headers, (0, run_tree_1.runHeaders)(ambient));
|
|
26
|
+
return next({ ...input, headers });
|
|
27
|
+
};
|
|
28
|
+
const parentMarker = async (input, next, name, args) => {
|
|
29
|
+
if (!(0, langsmith_1.isTracingEnabled)()) {
|
|
30
|
+
return next(input);
|
|
31
|
+
}
|
|
32
|
+
const ambient = (0, traceable_1.getCurrentRunTree)(true);
|
|
33
|
+
let propagate = ambient;
|
|
34
|
+
if (config.addTemporalRuns) {
|
|
35
|
+
const marker = (0, run_tree_1.buildRunTree)(config, { name, runType: run_tree_1.RUN_TYPE.CHAIN, parent: ambient, inputs: { args } });
|
|
36
|
+
await (0, run_tree_1.emitMarkerRun)(marker);
|
|
37
|
+
propagate = marker;
|
|
38
|
+
}
|
|
39
|
+
const headers = (0, propagation_1.withContextHeader)(input.headers, (0, run_tree_1.runHeaders)(propagate));
|
|
40
|
+
return next({ ...input, headers });
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
start(input, next) {
|
|
44
|
+
return peerStart(input, next, (0, run_tree_1.startWorkflowRunName)(input.workflowType), input.options.args);
|
|
45
|
+
},
|
|
46
|
+
startWithDetails(input, next) {
|
|
47
|
+
return peerStart(input, next, (0, run_tree_1.startWorkflowRunName)(input.workflowType), input.options.args);
|
|
48
|
+
},
|
|
49
|
+
signal(input, next) {
|
|
50
|
+
return parentMarker(input, next, (0, run_tree_1.signalWorkflowRunName)(input.signalName), input.args);
|
|
51
|
+
},
|
|
52
|
+
signalWithStart(input, next) {
|
|
53
|
+
return parentMarker(input, next, (0, run_tree_1.signalWithStartRunName)(input.workflowType), input.signalArgs);
|
|
54
|
+
},
|
|
55
|
+
query(input, next) {
|
|
56
|
+
return parentMarker(input, next, (0, run_tree_1.queryWorkflowRunName)(input.queryType), input.args);
|
|
57
|
+
},
|
|
58
|
+
startUpdate(input, next) {
|
|
59
|
+
return parentMarker(input, next, (0, run_tree_1.startWorkflowUpdateRunName)(input.updateName), input.args);
|
|
60
|
+
},
|
|
61
|
+
async startUpdateWithStart(input, next) {
|
|
62
|
+
if (!(0, langsmith_1.isTracingEnabled)()) {
|
|
63
|
+
return next(input);
|
|
64
|
+
}
|
|
65
|
+
const ambient = (0, traceable_1.getCurrentRunTree)(true);
|
|
66
|
+
let propagate = ambient;
|
|
67
|
+
if (config.addTemporalRuns) {
|
|
68
|
+
const marker = (0, run_tree_1.buildRunTree)(config, {
|
|
69
|
+
name: (0, run_tree_1.startUpdateWithStartRunName)(input.updateName),
|
|
70
|
+
runType: run_tree_1.RUN_TYPE.CHAIN,
|
|
71
|
+
parent: ambient,
|
|
72
|
+
inputs: { args: input.updateArgs },
|
|
73
|
+
});
|
|
74
|
+
await (0, run_tree_1.emitMarkerRun)(marker);
|
|
75
|
+
propagate = marker;
|
|
76
|
+
}
|
|
77
|
+
const workflowStartHeaders = (0, propagation_1.withContextHeader)(input.workflowStartHeaders, (0, run_tree_1.runHeaders)(propagate));
|
|
78
|
+
return next({ ...input, workflowStartHeaders });
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=client-interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-interceptor.js","sourceRoot":"","sources":["../src/client-interceptor.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `@temporalio/langsmith` — LangSmith observability for Temporal.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.LangSmithPlugin = void 0;
|
|
9
|
+
var plugin_1 = require("./plugin");
|
|
10
|
+
Object.defineProperty(exports, "LangSmithPlugin", { enumerable: true, get: function () { return plugin_1.LangSmithPlugin; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,mCAA2C;AAAlC,yGAAA,eAAe,OAAA"}
|
package/lib/plugin.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {@link LangSmithPlugin} — the single object a user adds to their Temporal
|
|
3
|
+
* `Client` and `Worker` to get LangSmith tracing across workflow / activity /
|
|
4
|
+
* child-workflow / Nexus boundaries with no changes to their existing
|
|
5
|
+
* `traceable` instrumentation.
|
|
6
|
+
*
|
|
7
|
+
* The plugin wires four things:
|
|
8
|
+
* 1. a **client interceptor** that propagates trace context out of any
|
|
9
|
+
* `start` / `signal` / `query` / `update` call;
|
|
10
|
+
* 2. **activity + Nexus inbound interceptors** that reconstruct the trace and
|
|
11
|
+
* install it as the active run (so body `traceable` calls nest correctly);
|
|
12
|
+
* 3. the **workflow interceptor module** (loaded into the workflow bundle) plus
|
|
13
|
+
* a bundle-time global carrying the plugin config; and
|
|
14
|
+
* 4. the **LangSmith sink** that performs the actual out-of-isolate emission.
|
|
15
|
+
*
|
|
16
|
+
* On worker shutdown it flushes the LangSmith client so in-flight traces are
|
|
17
|
+
* not lost.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import { Client } from 'langsmith';
|
|
22
|
+
import { SimplePlugin } from '@temporalio/plugin';
|
|
23
|
+
import type { ClientOptions } from '@temporalio/client';
|
|
24
|
+
import type { BundleOptions, ReplayWorkerOptions, Worker, WorkerOptions } from '@temporalio/worker';
|
|
25
|
+
/**
|
|
26
|
+
* Options for {@link LangSmithPlugin}.
|
|
27
|
+
*
|
|
28
|
+
* Secrets (the LangSmith API key) are never accepted here as plaintext and
|
|
29
|
+
* never cross a Temporal boundary — supply a pre-constructed {@link Client}
|
|
30
|
+
* (which reads `LANGSMITH_API_KEY` from the worker/client process env) or let
|
|
31
|
+
* the plugin construct a default client from the environment.
|
|
32
|
+
*
|
|
33
|
+
* @experimental Plugins is an experimental feature; APIs may change without notice.
|
|
34
|
+
*/
|
|
35
|
+
export interface LangSmithPluginOptions {
|
|
36
|
+
/**
|
|
37
|
+
* The LangSmith client runs are emitted to. Defaults to `new Client()`, which
|
|
38
|
+
* reads `LANGSMITH_API_KEY` / `LANGSMITH_ENDPOINT` from the process
|
|
39
|
+
* environment. Lives only in the worker/client process — never serialized.
|
|
40
|
+
*/
|
|
41
|
+
client?: Client;
|
|
42
|
+
/** Target LangSmith project for every emitted run. */
|
|
43
|
+
projectName?: string;
|
|
44
|
+
/**
|
|
45
|
+
* When `true`, emit first-class runs for Temporal operations themselves
|
|
46
|
+
* (`StartWorkflow:`, `RunActivity:`, `HandleSignal:`, …) in addition to the
|
|
47
|
+
* user's `traceable` runs. When `false` (default), only the user's
|
|
48
|
+
* `traceable` runs are emitted — trace context still propagates across
|
|
49
|
+
* boundaries so they nest correctly.
|
|
50
|
+
*/
|
|
51
|
+
addTemporalRuns?: boolean;
|
|
52
|
+
/** Tags attached to every run the plugin emits. */
|
|
53
|
+
tags?: string[];
|
|
54
|
+
/** Metadata merged into every run the plugin emits (credential keys scrubbed). */
|
|
55
|
+
metadata?: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Temporal plugin that adds LangSmith observability to a Client + Worker.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { traceable } from 'langsmith/traceable';
|
|
63
|
+
* import { LangSmithPlugin } from '@temporalio/langsmith';
|
|
64
|
+
*
|
|
65
|
+
* const plugin = new LangSmithPlugin({ addTemporalRuns: true });
|
|
66
|
+
* const worker = await Worker.create({ workflowsPath, taskQueue: 'tq', plugins: [plugin] });
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @experimental Plugins is an experimental feature; APIs may change without notice.
|
|
70
|
+
*/
|
|
71
|
+
export declare class LangSmithPlugin extends SimplePlugin {
|
|
72
|
+
private readonly client;
|
|
73
|
+
private readonly emitter;
|
|
74
|
+
private readonly workflowConfig;
|
|
75
|
+
constructor(options?: LangSmithPluginOptions);
|
|
76
|
+
configureClient(options: ClientOptions): ClientOptions;
|
|
77
|
+
configureWorker(options: WorkerOptions): WorkerOptions;
|
|
78
|
+
configureReplayWorker(options: ReplayWorkerOptions): ReplayWorkerOptions;
|
|
79
|
+
private withLangSmithWorker;
|
|
80
|
+
configureBundler(options: BundleOptions): BundleOptions;
|
|
81
|
+
/**
|
|
82
|
+
* Flush the LangSmith client on worker shutdown so traces that were emitted
|
|
83
|
+
* just before exit are delivered. Wraps the worker run loop and flushes in a
|
|
84
|
+
* `finally`, swallowing flush errors (shutdown must not fail on telemetry).
|
|
85
|
+
*/
|
|
86
|
+
runWorker(worker: Worker, next: (worker: Worker) => Promise<void>): Promise<void>;
|
|
87
|
+
private flush;
|
|
88
|
+
}
|