Skip to content

Commit 0fa0cc1

Browse files
committed
feat(langchain): cover embeddings for all OTel provider packages
The OTel path covered 6 chat provider packages; chat is already handled by the single @langchain/core BaseChatModel hook. For embeddings (the per-package surface), wire the packages that ship an Embeddings subclass: openai, google-genai, mistralai, and google-vertexai (whose methods live on the shared @langchain/google-common base). anthropic and groq are chat-only. The embeddings channel list is derived from the provider list so adding a provider is a single edit.
1 parent fcebfb9 commit 0fa0cc1

2 files changed

Lines changed: 33 additions & 14 deletions

File tree

packages/server-utils/src/integrations/tracing-channel/langchain.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
} from '@sentry/core';
1717
import { DEBUG_BUILD } from '../../debug-build';
1818
import { CHANNELS } from '../../orchestrion/channels';
19+
import { langchainEmbeddingsChannels } from '../../orchestrion/config/langchain';
1920
import { bindTracingChannelToSpan } from '../../tracing-channel';
2021

2122
// Same name as the OTel integration by design: when enabled, the OTel 'LangChain' integration is
@@ -89,7 +90,7 @@ const _langChainChannelIntegration = ((options: LangChainOptions = {}) => {
8990
// do the same here. `bindTracingChannelToSpan` needs the async-context binding that
9091
// `initOpenTelemetry()` registers after `setupOnce`, so wait for it before subscribing.
9192
waitForTracingChannelBinding(() => {
92-
for (const channelName of [CHANNELS.LANGCHAIN_EMBED_QUERY, CHANNELS.LANGCHAIN_EMBED_DOCUMENTS]) {
93+
for (const channelName of langchainEmbeddingsChannels) {
9394
DEBUG_BUILD && debug.log(`[orchestrion:langchain] subscribing to channel "${channelName}"`);
9495
bindTracingChannelToSpan(
9596
diagnosticsChannel.tracingChannel<EmbeddingsChannelContext>(channelName),

packages/server-utils/src/orchestrion/config/langchain.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,41 @@ const chatModelConfig = ['dist/language_models/chat_models.cjs', 'dist/language_
2929
);
3030

3131
// Embeddings have no shared concrete method on the base class (each provider implements
32-
// `embedQuery`/`embedDocuments`), so they're hooked per provider. Only `@langchain/openai` is wired
33-
// for now; other providers follow the same shape (a class extending `Embeddings` with async
34-
// `embedQuery`/`embedDocuments`).
35-
const embeddingsConfig = ['dist/embeddings.cjs', 'dist/embeddings.js'].flatMap(filePath => {
36-
const module = { name: '@langchain/openai', versionRange: '>=0.1.0 <2.0.0', filePath };
37-
38-
return [
39-
{ channelName: 'embedQuery', module, functionQuery: { methodName: 'embedQuery', kind: 'Async' as const } },
40-
{ channelName: 'embedDocuments', module, functionQuery: { methodName: 'embedDocuments', kind: 'Async' as const } },
41-
];
42-
});
32+
// `embedQuery`/`embedDocuments`), so they're hooked per package. These are the provider packages the
33+
// vendored OTel instrumentation covered that actually ship an `Embeddings` subclass: `@langchain/openai`,
34+
// `@langchain/google-genai` and `@langchain/mistralai` define the two methods on their own class, while
35+
// `@langchain/google-vertexai` inherits them from the shared `@langchain/google-common` base, so that base
36+
// is the module hooked for it. (anthropic and groq are chat-only — they ship no embeddings class.) The
37+
// `embedQuery`/`embedDocuments` channel names are per-method; orchestrion prefixes them with the module
38+
// name, so the full channel strings stay distinct across packages.
39+
const EMBEDDINGS_PROVIDERS = [
40+
{ name: '@langchain/openai', versionRange: '>=0.1.0 <2.0.0' },
41+
{ name: '@langchain/google-genai', versionRange: '>=0.1.0 <3.0.0' },
42+
{ name: '@langchain/mistralai', versionRange: '>=0.1.0 <2.0.0' },
43+
{ name: '@langchain/google-common', versionRange: '>=0.1.0 <3.0.0' },
44+
];
45+
46+
const EMBEDDINGS_METHODS = ['embedQuery', 'embedDocuments'] as const;
47+
48+
const embeddingsConfig = EMBEDDINGS_PROVIDERS.flatMap(({ name, versionRange }) =>
49+
['dist/embeddings.cjs', 'dist/embeddings.js'].flatMap(filePath =>
50+
EMBEDDINGS_METHODS.map(method => ({
51+
channelName: method,
52+
module: { name, versionRange, filePath },
53+
functionQuery: { methodName: method, kind: 'Async' as const },
54+
})),
55+
),
56+
);
4357

4458
export const langchainConfig = [...chatModelConfig, ...embeddingsConfig] satisfies InstrumentationConfig[];
4559

60+
// The embeddings channel strings the subscriber binds to, derived from the provider list above so that
61+
// adding a provider is a single edit that both instruments it and subscribes the listener to it.
62+
export const langchainEmbeddingsChannels = EMBEDDINGS_PROVIDERS.flatMap(({ name }) =>
63+
EMBEDDINGS_METHODS.map(method => `orchestrion:${name}:${method}`),
64+
);
65+
4666
export const langchainChannels = {
4767
LANGCHAIN_CHAT_MODEL_INVOKE: 'orchestrion:@langchain/core:chatModelInvoke',
4868
LANGCHAIN_CHAT_MODEL_STREAM: 'orchestrion:@langchain/core:chatModelStream',
49-
LANGCHAIN_EMBED_QUERY: 'orchestrion:@langchain/openai:embedQuery',
50-
LANGCHAIN_EMBED_DOCUMENTS: 'orchestrion:@langchain/openai:embedDocuments',
5169
} as const;

0 commit comments

Comments
 (0)