@flutchai/flutch-sdk 0.2.20 → 0.3.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/dist/index.cjs +234 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +234 -42
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -15,6 +15,7 @@ var crypto = require('crypto');
|
|
|
15
15
|
var promClient = require('prom-client');
|
|
16
16
|
var messages = require('@langchain/core/messages');
|
|
17
17
|
var LangGraph = require('@langchain/langgraph');
|
|
18
|
+
var async_hooks = require('async_hooks');
|
|
18
19
|
var dispatch = require('@langchain/core/callbacks/dispatch');
|
|
19
20
|
var tools = require('@langchain/core/tools');
|
|
20
21
|
var zod = require('zod');
|
|
@@ -23,6 +24,7 @@ var zodToJsonSchema = require('zod-to-json-schema');
|
|
|
23
24
|
var manager = require('@langchain/core/callbacks/manager');
|
|
24
25
|
var openai = require('@langchain/openai');
|
|
25
26
|
var aws = require('@langchain/aws');
|
|
27
|
+
var core$1 = require('cohere-ai/core');
|
|
26
28
|
var anthropic = require('@langchain/anthropic');
|
|
27
29
|
var cohere = require('@langchain/cohere');
|
|
28
30
|
var cohereAi = require('cohere-ai');
|
|
@@ -4817,6 +4819,36 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4817
4819
|
}
|
|
4818
4820
|
return [];
|
|
4819
4821
|
}
|
|
4822
|
+
/**
|
|
4823
|
+
* Convert LangChain unified `tool_call_chunks` (Bedrock / OpenAI streaming
|
|
4824
|
+
* format) into Anthropic-style blocks so the rest of the pipeline can stay
|
|
4825
|
+
* uniform. The first chunk for a tool carries `name` (and usually `id`);
|
|
4826
|
+
* subsequent chunks carry partial `args` strings that need to accumulate.
|
|
4827
|
+
*
|
|
4828
|
+
* NOTE: assumes tool calls arrive sequentially. Parallel tool calls with
|
|
4829
|
+
* interleaved `args` chunks across different `index`es will misroute args
|
|
4830
|
+
* to the most recently opened tool_use block.
|
|
4831
|
+
*/
|
|
4832
|
+
toolCallChunksToBlocks(toolCallChunks) {
|
|
4833
|
+
const blocks = [];
|
|
4834
|
+
for (const tcc of toolCallChunks) {
|
|
4835
|
+
if (tcc.name) {
|
|
4836
|
+
blocks.push({
|
|
4837
|
+
type: "tool_use",
|
|
4838
|
+
id: tcc.id,
|
|
4839
|
+
name: tcc.name,
|
|
4840
|
+
input: ""
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
if (typeof tcc.args === "string" && tcc.args.length > 0) {
|
|
4844
|
+
blocks.push({
|
|
4845
|
+
type: "input_json_delta",
|
|
4846
|
+
input: tcc.args
|
|
4847
|
+
});
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
return blocks;
|
|
4851
|
+
}
|
|
4820
4852
|
/**
|
|
4821
4853
|
* Extract attachments from various input formats
|
|
4822
4854
|
* Handles both array format (IAttachment[]) and object format (Record<string, IGraphAttachment>)
|
|
@@ -4980,10 +5012,19 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4980
5012
|
}
|
|
4981
5013
|
return;
|
|
4982
5014
|
}
|
|
4983
|
-
if (event.event === "on_chat_model_stream" && event.data?.chunk
|
|
5015
|
+
if (event.event === "on_chat_model_stream" && event.data?.chunk) {
|
|
4984
5016
|
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4985
|
-
const
|
|
4986
|
-
|
|
5017
|
+
const chunk = event.data.chunk;
|
|
5018
|
+
const blocks = [];
|
|
5019
|
+
if (chunk.content) {
|
|
5020
|
+
blocks.push(...this.normalizeContentBlocks(chunk.content));
|
|
5021
|
+
}
|
|
5022
|
+
if (Array.isArray(chunk.tool_call_chunks) && chunk.tool_call_chunks.length > 0) {
|
|
5023
|
+
blocks.push(...this.toolCallChunksToBlocks(chunk.tool_call_chunks));
|
|
5024
|
+
}
|
|
5025
|
+
if (blocks.length > 0) {
|
|
5026
|
+
this.processContentStream(acc, channel, blocks, onPartial);
|
|
5027
|
+
}
|
|
4987
5028
|
return;
|
|
4988
5029
|
}
|
|
4989
5030
|
if (event.event === "on_tool_start") {
|
|
@@ -4996,6 +5037,44 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4996
5037
|
if (idx !== -1) {
|
|
4997
5038
|
const block = state.pendingToolBlocks.splice(idx, 1)[0];
|
|
4998
5039
|
state.toolBlocksByRunId.set(event.run_id, block);
|
|
5040
|
+
} else {
|
|
5041
|
+
const toolInput = event.data?.input;
|
|
5042
|
+
let inputString;
|
|
5043
|
+
try {
|
|
5044
|
+
inputString = typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput ?? {});
|
|
5045
|
+
} catch {
|
|
5046
|
+
inputString = "";
|
|
5047
|
+
}
|
|
5048
|
+
const synthesizedBlock = {
|
|
5049
|
+
index: state.contentChain.length + (state.currentBlock ? 1 : 0),
|
|
5050
|
+
type: "tool_use",
|
|
5051
|
+
name: event.name,
|
|
5052
|
+
id: event.run_id,
|
|
5053
|
+
input: inputString,
|
|
5054
|
+
output: ""
|
|
5055
|
+
};
|
|
5056
|
+
if (state.currentBlock) {
|
|
5057
|
+
state.contentChain.push(state.currentBlock);
|
|
5058
|
+
state.currentBlock = null;
|
|
5059
|
+
}
|
|
5060
|
+
state.contentChain.push(synthesizedBlock);
|
|
5061
|
+
state.toolBlocksByRunId.set(event.run_id, synthesizedBlock);
|
|
5062
|
+
this.sendDelta(
|
|
5063
|
+
channel,
|
|
5064
|
+
{ type: "step_started", step: synthesizedBlock },
|
|
5065
|
+
onPartial
|
|
5066
|
+
);
|
|
5067
|
+
if (inputString.length > 0) {
|
|
5068
|
+
this.sendDelta(
|
|
5069
|
+
channel,
|
|
5070
|
+
{
|
|
5071
|
+
type: "tool_input_chunk",
|
|
5072
|
+
stepId: synthesizedBlock.id,
|
|
5073
|
+
chunk: inputString
|
|
5074
|
+
},
|
|
5075
|
+
onPartial
|
|
5076
|
+
);
|
|
5077
|
+
}
|
|
4999
5078
|
}
|
|
5000
5079
|
}
|
|
5001
5080
|
this.logger.log("\u{1F527} Tool execution started", {
|
|
@@ -5225,6 +5304,71 @@ exports.EventProcessor = class EventProcessor {
|
|
|
5225
5304
|
exports.EventProcessor = __decorateClass([
|
|
5226
5305
|
common.Injectable()
|
|
5227
5306
|
], exports.EventProcessor);
|
|
5307
|
+
var als = new async_hooks.AsyncLocalStorage();
|
|
5308
|
+
function withFlutchContext(ctx, fn) {
|
|
5309
|
+
return als.run(ctx, fn);
|
|
5310
|
+
}
|
|
5311
|
+
function getFlutchContext() {
|
|
5312
|
+
return als.getStore();
|
|
5313
|
+
}
|
|
5314
|
+
var HEADER_MAP = {
|
|
5315
|
+
messageId: "x-flutch-message-id",
|
|
5316
|
+
threadId: "x-flutch-thread-id",
|
|
5317
|
+
agentId: "x-flutch-agent-id",
|
|
5318
|
+
userId: "x-flutch-user-id",
|
|
5319
|
+
nodeName: "x-flutch-node"
|
|
5320
|
+
};
|
|
5321
|
+
var flutchFetch = (input, init) => {
|
|
5322
|
+
const ctx = als.getStore();
|
|
5323
|
+
if (!ctx) {
|
|
5324
|
+
return fetch(input, init);
|
|
5325
|
+
}
|
|
5326
|
+
const headers = new Headers(init?.headers);
|
|
5327
|
+
for (const key of Object.keys(HEADER_MAP)) {
|
|
5328
|
+
const value = ctx[key];
|
|
5329
|
+
if (value) {
|
|
5330
|
+
headers.set(HEADER_MAP[key], String(value));
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
return fetch(input, { ...init, headers });
|
|
5334
|
+
};
|
|
5335
|
+
function flutchHeaders() {
|
|
5336
|
+
const ctx = als.getStore();
|
|
5337
|
+
if (!ctx) return {};
|
|
5338
|
+
const out = {};
|
|
5339
|
+
for (const key of Object.keys(HEADER_MAP)) {
|
|
5340
|
+
const value = ctx[key];
|
|
5341
|
+
if (value) {
|
|
5342
|
+
out[HEADER_MAP[key]] = String(value);
|
|
5343
|
+
}
|
|
5344
|
+
}
|
|
5345
|
+
return out;
|
|
5346
|
+
}
|
|
5347
|
+
function flutchMistralHook(req) {
|
|
5348
|
+
const extras = flutchHeaders();
|
|
5349
|
+
if (Object.keys(extras).length === 0) {
|
|
5350
|
+
return req;
|
|
5351
|
+
}
|
|
5352
|
+
const headers = new Headers(req.headers);
|
|
5353
|
+
for (const [k, v] of Object.entries(extras)) {
|
|
5354
|
+
headers.set(k, v);
|
|
5355
|
+
}
|
|
5356
|
+
return new Request(req, { headers });
|
|
5357
|
+
}
|
|
5358
|
+
function wrapCohereFetcher(inner) {
|
|
5359
|
+
return ((args) => {
|
|
5360
|
+
const extras = flutchHeaders();
|
|
5361
|
+
if (Object.keys(extras).length === 0) {
|
|
5362
|
+
return inner(args);
|
|
5363
|
+
}
|
|
5364
|
+
return inner({
|
|
5365
|
+
...args,
|
|
5366
|
+
headers: { ...args.headers ?? {}, ...extras }
|
|
5367
|
+
});
|
|
5368
|
+
});
|
|
5369
|
+
}
|
|
5370
|
+
|
|
5371
|
+
// src/engines/langgraph/langgraph-engine.ts
|
|
5228
5372
|
process.setMaxListeners(0);
|
|
5229
5373
|
exports.LangGraphEngine = class LangGraphEngine {
|
|
5230
5374
|
constructor(eventProcessor, configService) {
|
|
@@ -5276,29 +5420,42 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
5276
5420
|
* Method to invoke LangGraph
|
|
5277
5421
|
*/
|
|
5278
5422
|
async invokeGraph(graph, preparedPayload, signal) {
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5423
|
+
return withFlutchContext(
|
|
5424
|
+
this.extractFlutchContext(preparedPayload),
|
|
5425
|
+
async () => {
|
|
5426
|
+
this.logger.debug("invokeGraph preparedPayload", preparedPayload);
|
|
5427
|
+
if (signal) {
|
|
5428
|
+
preparedPayload.signal = signal;
|
|
5429
|
+
this.logger.debug(
|
|
5430
|
+
"[ENGINE] Signal assigned to preparedPayload.signal"
|
|
5431
|
+
);
|
|
5432
|
+
}
|
|
5433
|
+
const input = await this.deserializeInput(preparedPayload.input || {});
|
|
5434
|
+
try {
|
|
5435
|
+
const result = await graph.invoke(input, {
|
|
5436
|
+
...preparedPayload.config,
|
|
5437
|
+
signal: preparedPayload.signal
|
|
5438
|
+
});
|
|
5439
|
+
return this.processGraphResult(result);
|
|
5440
|
+
} finally {
|
|
5441
|
+
const threadId = this.extractThreadId(preparedPayload);
|
|
5442
|
+
if (threadId) {
|
|
5443
|
+
clearAttachmentDataStore(threadId);
|
|
5444
|
+
this.logger.debug(
|
|
5445
|
+
`[ENGINE] Cleared attachment data store for thread: ${threadId}`
|
|
5446
|
+
);
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5298
5449
|
}
|
|
5299
|
-
|
|
5450
|
+
);
|
|
5300
5451
|
}
|
|
5301
5452
|
async streamGraph(graph, preparedPayload, onPartial, signal) {
|
|
5453
|
+
return withFlutchContext(
|
|
5454
|
+
this.extractFlutchContext(preparedPayload),
|
|
5455
|
+
() => this.streamGraphInner(graph, preparedPayload, onPartial, signal)
|
|
5456
|
+
);
|
|
5457
|
+
}
|
|
5458
|
+
async streamGraphInner(graph, preparedPayload, onPartial, signal) {
|
|
5302
5459
|
const acc = this.eventProcessor.createAccumulator();
|
|
5303
5460
|
let streamError = null;
|
|
5304
5461
|
this.logger.debug({
|
|
@@ -5528,6 +5685,22 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
5528
5685
|
extractThreadId(preparedPayload) {
|
|
5529
5686
|
return preparedPayload.configurable?.thread_id || preparedPayload.configurable?.context?.threadId || preparedPayload.config?.configurable?.thread_id || preparedPayload.config?.configurable?.context?.threadId || void 0;
|
|
5530
5687
|
}
|
|
5688
|
+
/**
|
|
5689
|
+
* Extract Flutch billing/attribution context from the prepared payload.
|
|
5690
|
+
*
|
|
5691
|
+
* Read by `flutchFetch` (in node-sdk/src/models/flutch-context.ts) to
|
|
5692
|
+
* attach X-Flutch-* headers to every router-bound LLM call made during
|
|
5693
|
+
* this graph run.
|
|
5694
|
+
*/
|
|
5695
|
+
extractFlutchContext(preparedPayload) {
|
|
5696
|
+
const ctx = preparedPayload?.config?.configurable?.context || preparedPayload?.configurable?.context || {};
|
|
5697
|
+
return {
|
|
5698
|
+
messageId: ctx.messageId,
|
|
5699
|
+
threadId: ctx.threadId || preparedPayload?.config?.configurable?.thread_id,
|
|
5700
|
+
agentId: ctx.agentId,
|
|
5701
|
+
userId: ctx.userId
|
|
5702
|
+
};
|
|
5703
|
+
}
|
|
5531
5704
|
/**
|
|
5532
5705
|
* Process graph execution result
|
|
5533
5706
|
*/
|
|
@@ -6683,7 +6856,10 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6683
6856
|
);
|
|
6684
6857
|
const routerURL = resolveRouterURL(baseURL);
|
|
6685
6858
|
if (routerURL) {
|
|
6686
|
-
config.configuration = {
|
|
6859
|
+
config.configuration = {
|
|
6860
|
+
baseURL: `${routerURL}/v1`,
|
|
6861
|
+
fetch: flutchFetch
|
|
6862
|
+
};
|
|
6687
6863
|
}
|
|
6688
6864
|
return new openai.ChatOpenAI(config);
|
|
6689
6865
|
},
|
|
@@ -6693,15 +6869,19 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6693
6869
|
defaultMaxTokens,
|
|
6694
6870
|
apiToken,
|
|
6695
6871
|
baseURL
|
|
6696
|
-
}) =>
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6872
|
+
}) => {
|
|
6873
|
+
const routerURL = resolveRouterURL(baseURL);
|
|
6874
|
+
return new anthropic.ChatAnthropic({
|
|
6875
|
+
modelName,
|
|
6876
|
+
temperature: defaultTemperature,
|
|
6877
|
+
maxTokens: defaultMaxTokens,
|
|
6878
|
+
anthropicApiKey: apiToken || this.resolveApiKey("anthropic" /* ANTHROPIC */),
|
|
6879
|
+
...routerURL && {
|
|
6880
|
+
anthropicApiUrl: routerURL,
|
|
6881
|
+
clientOptions: { fetch: flutchFetch }
|
|
6882
|
+
}
|
|
6883
|
+
});
|
|
6884
|
+
},
|
|
6705
6885
|
["cohere" /* COHERE */]: ({
|
|
6706
6886
|
modelName,
|
|
6707
6887
|
defaultTemperature,
|
|
@@ -6714,7 +6894,13 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6714
6894
|
return routerURL ? new cohere.ChatCohere({
|
|
6715
6895
|
model: modelName,
|
|
6716
6896
|
temperature: defaultTemperature,
|
|
6717
|
-
client: new cohereAi.CohereClient({
|
|
6897
|
+
client: new cohereAi.CohereClient({
|
|
6898
|
+
token,
|
|
6899
|
+
baseUrl: routerURL,
|
|
6900
|
+
// Inject X-Flutch-* headers from the ALS context on every
|
|
6901
|
+
// outbound request via the wrapped default fetcher.
|
|
6902
|
+
fetcher: wrapCohereFetcher(core$1.fetcher)
|
|
6903
|
+
})
|
|
6718
6904
|
}) : new cohere.ChatCohere({
|
|
6719
6905
|
model: modelName,
|
|
6720
6906
|
temperature: defaultTemperature,
|
|
@@ -6734,7 +6920,13 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6734
6920
|
temperature: defaultTemperature,
|
|
6735
6921
|
maxTokens: defaultMaxTokens,
|
|
6736
6922
|
apiKey: apiToken || this.resolveApiKey("mistral" /* MISTRAL */),
|
|
6737
|
-
...routerURL && {
|
|
6923
|
+
...routerURL && {
|
|
6924
|
+
serverURL: `${routerURL}/v1`,
|
|
6925
|
+
// Mistral SDK doesn't accept a custom fetch directly — its
|
|
6926
|
+
// beforeRequestHooks let us mutate the outgoing Request to add
|
|
6927
|
+
// X-Flutch-* headers from the ALS context.
|
|
6928
|
+
beforeRequestHooks: [flutchMistralHook]
|
|
6929
|
+
}
|
|
6738
6930
|
});
|
|
6739
6931
|
},
|
|
6740
6932
|
["voyageai" /* VOYAGEAI */]: () => {
|
|
@@ -6789,7 +6981,7 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6789
6981
|
model: modelName,
|
|
6790
6982
|
apiKey: apiToken || this.resolveApiKey("openai" /* OPENAI */),
|
|
6791
6983
|
...routerURL && {
|
|
6792
|
-
configuration: { baseURL: `${routerURL}/v1
|
|
6984
|
+
configuration: { baseURL: `${routerURL}/v1`, fetch: flutchFetch }
|
|
6793
6985
|
}
|
|
6794
6986
|
});
|
|
6795
6987
|
},
|
|
@@ -7783,11 +7975,15 @@ exports.encryptTokens = encryptTokens;
|
|
|
7783
7975
|
exports.executeToolWithAttachments = executeToolWithAttachments;
|
|
7784
7976
|
exports.findCallbackMethod = findCallbackMethod;
|
|
7785
7977
|
exports.findEndpointMethod = findEndpointMethod;
|
|
7978
|
+
exports.flutchFetch = flutchFetch;
|
|
7979
|
+
exports.flutchHeaders = flutchHeaders;
|
|
7980
|
+
exports.flutchMistralHook = flutchMistralHook;
|
|
7786
7981
|
exports.generateAttachmentSummary = generateAttachmentSummary;
|
|
7787
7982
|
exports.generateModelCacheKey = generateModelCacheKey;
|
|
7788
7983
|
exports.getAttachmentData = getAttachmentData;
|
|
7789
7984
|
exports.getCallbackMetadata = getCallbackMetadata;
|
|
7790
7985
|
exports.getEndpointMetadata = getEndpointMetadata;
|
|
7986
|
+
exports.getFlutchContext = getFlutchContext;
|
|
7791
7987
|
exports.getOAuthProvider = getOAuthProvider;
|
|
7792
7988
|
exports.getOAuthProviderNames = getOAuthProviderNames;
|
|
7793
7989
|
exports.getUIEndpointClassMetadata = getUIEndpointClassMetadata;
|
|
@@ -7805,5 +8001,7 @@ exports.resolveRouterURL = resolveRouterURL;
|
|
|
7805
8001
|
exports.sanitizeTraceData = sanitizeTraceData;
|
|
7806
8002
|
exports.storeAttachmentData = storeAttachmentData;
|
|
7807
8003
|
exports.traceApiCall = traceApiCall;
|
|
8004
|
+
exports.withFlutchContext = withFlutchContext;
|
|
8005
|
+
exports.wrapCohereFetcher = wrapCohereFetcher;
|
|
7808
8006
|
//# sourceMappingURL=index.cjs.map
|
|
7809
8007
|
//# sourceMappingURL=index.cjs.map
|