@flutchai/flutch-sdk 0.2.4 → 0.2.6
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 +140 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +137 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4422,6 +4422,48 @@ function generateTextSummary(data, toolCallId) {
|
|
|
4422
4422
|
|
|
4423
4423
|
// src/graph/attachment-tool-node.ts
|
|
4424
4424
|
var DEFAULT_ATTACHMENT_THRESHOLD = Number(process.env.ATTACHMENT_THRESHOLD) || 4e3;
|
|
4425
|
+
var attachmentDataStore = /* @__PURE__ */ new Map();
|
|
4426
|
+
var cleanupTimers = /* @__PURE__ */ new Map();
|
|
4427
|
+
var AUTO_CLEANUP_MS = 10 * 60 * 1e3;
|
|
4428
|
+
function storeAttachmentData(key, data, threadId) {
|
|
4429
|
+
const scope = threadId || "__global__";
|
|
4430
|
+
let threadStore = attachmentDataStore.get(scope);
|
|
4431
|
+
if (!threadStore) {
|
|
4432
|
+
threadStore = /* @__PURE__ */ new Map();
|
|
4433
|
+
attachmentDataStore.set(scope, threadStore);
|
|
4434
|
+
}
|
|
4435
|
+
threadStore.set(key, data);
|
|
4436
|
+
const existingTimer = cleanupTimers.get(scope);
|
|
4437
|
+
if (existingTimer) {
|
|
4438
|
+
clearTimeout(existingTimer);
|
|
4439
|
+
}
|
|
4440
|
+
const timer = setTimeout(() => {
|
|
4441
|
+
attachmentDataStore.delete(scope);
|
|
4442
|
+
cleanupTimers.delete(scope);
|
|
4443
|
+
}, AUTO_CLEANUP_MS);
|
|
4444
|
+
if (timer.unref) timer.unref();
|
|
4445
|
+
cleanupTimers.set(scope, timer);
|
|
4446
|
+
}
|
|
4447
|
+
function getAttachmentData(key, threadId) {
|
|
4448
|
+
const scope = threadId || "__global__";
|
|
4449
|
+
return attachmentDataStore.get(scope)?.get(key);
|
|
4450
|
+
}
|
|
4451
|
+
function clearAttachmentDataStore(threadId) {
|
|
4452
|
+
if (threadId) {
|
|
4453
|
+
attachmentDataStore.delete(threadId);
|
|
4454
|
+
const timer = cleanupTimers.get(threadId);
|
|
4455
|
+
if (timer) {
|
|
4456
|
+
clearTimeout(timer);
|
|
4457
|
+
cleanupTimers.delete(threadId);
|
|
4458
|
+
}
|
|
4459
|
+
} else {
|
|
4460
|
+
attachmentDataStore.clear();
|
|
4461
|
+
for (const timer of cleanupTimers.values()) {
|
|
4462
|
+
clearTimeout(timer);
|
|
4463
|
+
}
|
|
4464
|
+
cleanupTimers.clear();
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4425
4467
|
async function executeToolWithAttachments(params) {
|
|
4426
4468
|
const {
|
|
4427
4469
|
toolCall,
|
|
@@ -4433,17 +4475,23 @@ async function executeToolWithAttachments(params) {
|
|
|
4433
4475
|
logger: logger2,
|
|
4434
4476
|
threshold = DEFAULT_ATTACHMENT_THRESHOLD,
|
|
4435
4477
|
injectIntoArg = "data",
|
|
4436
|
-
sourceAttachmentId
|
|
4478
|
+
sourceAttachmentId,
|
|
4479
|
+
threadId
|
|
4437
4480
|
} = params;
|
|
4438
4481
|
const argsWithInjection = { ...enrichedArgs };
|
|
4439
4482
|
try {
|
|
4440
4483
|
if (shouldInjectData(argsWithInjection, attachments, injectIntoArg)) {
|
|
4441
4484
|
const attachment = sourceAttachmentId ? attachments[sourceAttachmentId] : getLatestAttachment(attachments);
|
|
4442
4485
|
if (attachment) {
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
)
|
|
4486
|
+
const attachmentKey = sourceAttachmentId || attachment.toolCallId;
|
|
4487
|
+
const storedData = getAttachmentData(attachmentKey, threadId);
|
|
4488
|
+
const data = storedData !== void 0 ? storedData : attachment.data;
|
|
4489
|
+
if (data != null) {
|
|
4490
|
+
argsWithInjection[injectIntoArg] = typeof data === "string" ? data : JSON.stringify(data);
|
|
4491
|
+
logger2?.debug(
|
|
4492
|
+
`[Attachment] Auto-injected data from attachment "${attachment.toolCallId}" into ${toolCall.name}.${injectIntoArg} (source: ${storedData !== void 0 ? "memory" : "state"})`
|
|
4493
|
+
);
|
|
4494
|
+
}
|
|
4447
4495
|
}
|
|
4448
4496
|
}
|
|
4449
4497
|
} catch (e) {
|
|
@@ -4463,8 +4511,14 @@ async function executeToolWithAttachments(params) {
|
|
|
4463
4511
|
toolCall.name,
|
|
4464
4512
|
toolCall.id
|
|
4465
4513
|
);
|
|
4514
|
+
storeAttachmentData(toolCall.id, attachment.data, threadId);
|
|
4515
|
+
const stateAttachment = {
|
|
4516
|
+
...attachment,
|
|
4517
|
+
data: null
|
|
4518
|
+
// Data stored in memory, not in graph state
|
|
4519
|
+
};
|
|
4466
4520
|
logger2?.debug(
|
|
4467
|
-
`[Attachment] Stored large result (${content.length} chars) as attachment "${toolCall.id}"`
|
|
4521
|
+
`[Attachment] Stored large result (${content.length} chars) as attachment "${toolCall.id}" (data in memory, metadata in state)`
|
|
4468
4522
|
);
|
|
4469
4523
|
const toolMessage2 = new messages.ToolMessage({
|
|
4470
4524
|
content: attachment.summary,
|
|
@@ -4473,7 +4527,7 @@ async function executeToolWithAttachments(params) {
|
|
|
4473
4527
|
});
|
|
4474
4528
|
return {
|
|
4475
4529
|
toolMessage: toolMessage2,
|
|
4476
|
-
attachment: { key: toolCall.id, value:
|
|
4530
|
+
attachment: { key: toolCall.id, value: stateAttachment }
|
|
4477
4531
|
};
|
|
4478
4532
|
}
|
|
4479
4533
|
} catch (e) {
|
|
@@ -4505,7 +4559,8 @@ function getLatestAttachment(attachments) {
|
|
|
4505
4559
|
}
|
|
4506
4560
|
var logger = new common.Logger("ApiCallTracer");
|
|
4507
4561
|
var DEFAULT_TRACER_OPTIONS = {
|
|
4508
|
-
maxStringLength:
|
|
4562
|
+
maxStringLength: 1e5,
|
|
4563
|
+
// 100KB - enough for most tool outputs, prevents overflow
|
|
4509
4564
|
maxDepth: 15
|
|
4510
4565
|
};
|
|
4511
4566
|
var cachedDispatch;
|
|
@@ -4571,6 +4626,9 @@ function sanitizeTraceData(value, depth = 0, seen = /* @__PURE__ */ new WeakSet(
|
|
|
4571
4626
|
return null;
|
|
4572
4627
|
}
|
|
4573
4628
|
if (typeof value === "string") {
|
|
4629
|
+
if (value.length > opts.maxStringLength) {
|
|
4630
|
+
return `${value.slice(0, opts.maxStringLength)}\u2026 [truncated: ${value.length - opts.maxStringLength} chars]`;
|
|
4631
|
+
}
|
|
4574
4632
|
return value;
|
|
4575
4633
|
}
|
|
4576
4634
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
@@ -4735,6 +4793,19 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4735
4793
|
}
|
|
4736
4794
|
return [];
|
|
4737
4795
|
}
|
|
4796
|
+
/**
|
|
4797
|
+
* Extract attachments from various input formats
|
|
4798
|
+
* Handles both array format (IAttachment[]) and object format (Record<string, IGraphAttachment>)
|
|
4799
|
+
*/
|
|
4800
|
+
extractAttachments(attachments) {
|
|
4801
|
+
if (!attachments) {
|
|
4802
|
+
return [];
|
|
4803
|
+
}
|
|
4804
|
+
const items = Array.isArray(attachments) ? attachments : typeof attachments === "object" ? Object.values(attachments) : [];
|
|
4805
|
+
return items.filter(
|
|
4806
|
+
(item) => item != null && "type" in item && "value" in item
|
|
4807
|
+
);
|
|
4808
|
+
}
|
|
4738
4809
|
/**
|
|
4739
4810
|
* Send delta to UI (unified format)
|
|
4740
4811
|
*/
|
|
@@ -4872,6 +4943,14 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4872
4943
|
const blocks = this.normalizeContentBlocks(event.data.content);
|
|
4873
4944
|
this.processContentStream(acc, channel, blocks, onPartial);
|
|
4874
4945
|
}
|
|
4946
|
+
if (event.name === "send_attachments" && event.data.attachments) {
|
|
4947
|
+
const attachments = event.data.attachments || [];
|
|
4948
|
+
acc.attachments = [...acc.attachments, ...attachments];
|
|
4949
|
+
this.logger.debug("[ATTACHMENTS] Extracted from send_attachments event", {
|
|
4950
|
+
extractedCount: attachments.length,
|
|
4951
|
+
totalAccCount: acc.attachments.length
|
|
4952
|
+
});
|
|
4953
|
+
}
|
|
4875
4954
|
return;
|
|
4876
4955
|
}
|
|
4877
4956
|
if (event.event === "on_chat_model_stream" && event.data?.chunk?.content) {
|
|
@@ -4911,7 +4990,21 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4911
4990
|
}
|
|
4912
4991
|
if (toolBlock && toolBlock.type === "tool_use") {
|
|
4913
4992
|
const output = event.data?.output;
|
|
4914
|
-
|
|
4993
|
+
let outputString;
|
|
4994
|
+
try {
|
|
4995
|
+
outputString = typeof output === "string" ? output : JSON.stringify(output, null, 2);
|
|
4996
|
+
} catch {
|
|
4997
|
+
outputString = typeof output?.content === "string" ? output.content : "[Output too large to display]";
|
|
4998
|
+
}
|
|
4999
|
+
const MAX_TOOL_OUTPUT_LENGTH = 5e4;
|
|
5000
|
+
if (outputString.length > MAX_TOOL_OUTPUT_LENGTH) {
|
|
5001
|
+
let cutAt = outputString.lastIndexOf("\n", MAX_TOOL_OUTPUT_LENGTH);
|
|
5002
|
+
if (cutAt < MAX_TOOL_OUTPUT_LENGTH * 0.8) {
|
|
5003
|
+
cutAt = MAX_TOOL_OUTPUT_LENGTH;
|
|
5004
|
+
}
|
|
5005
|
+
outputString = outputString.slice(0, cutAt) + `
|
|
5006
|
+
... [truncated: ${outputString.length - cutAt} chars]`;
|
|
5007
|
+
}
|
|
4915
5008
|
toolBlock.output = outputString;
|
|
4916
5009
|
this.sendDelta(
|
|
4917
5010
|
channel,
|
|
@@ -4955,32 +5048,6 @@ exports.EventProcessor = class EventProcessor {
|
|
|
4955
5048
|
});
|
|
4956
5049
|
return;
|
|
4957
5050
|
}
|
|
4958
|
-
if (event.event === "on_chain_end") {
|
|
4959
|
-
const channel = event.metadata?.stream_channel ?? "text" /* TEXT */;
|
|
4960
|
-
if (channel === "text" /* TEXT */) {
|
|
4961
|
-
const output = event.data.output;
|
|
4962
|
-
if (output?.answer) {
|
|
4963
|
-
acc.attachments = [
|
|
4964
|
-
...acc.attachments,
|
|
4965
|
-
...output.answer.attachments || []
|
|
4966
|
-
];
|
|
4967
|
-
acc.metadata = { ...acc.metadata, ...output.answer.metadata || {} };
|
|
4968
|
-
} else if (output?.generation) {
|
|
4969
|
-
acc.attachments = [
|
|
4970
|
-
...acc.attachments,
|
|
4971
|
-
...output.generation.attachments || []
|
|
4972
|
-
];
|
|
4973
|
-
acc.metadata = {
|
|
4974
|
-
...acc.metadata,
|
|
4975
|
-
...output.generation.metadata || {}
|
|
4976
|
-
};
|
|
4977
|
-
} else if (output?.attachments || output?.metadata) {
|
|
4978
|
-
acc.attachments = [...acc.attachments, ...output.attachments || []];
|
|
4979
|
-
acc.metadata = { ...acc.metadata, ...output.metadata || {} };
|
|
4980
|
-
}
|
|
4981
|
-
}
|
|
4982
|
-
return;
|
|
4983
|
-
}
|
|
4984
5051
|
}
|
|
4985
5052
|
/**
|
|
4986
5053
|
* Build final result from accumulator
|
|
@@ -5024,7 +5091,9 @@ exports.EventProcessor = class EventProcessor {
|
|
|
5024
5091
|
textChains: allChains.filter((c) => c.channel === "text").length,
|
|
5025
5092
|
processingChains: allChains.filter((c) => c.channel === "processing").length,
|
|
5026
5093
|
totalSteps: allChains.reduce((sum, c) => sum + c.steps.length, 0),
|
|
5027
|
-
textLength: text.length
|
|
5094
|
+
textLength: text.length,
|
|
5095
|
+
attachmentsCount: acc.attachments?.length || 0,
|
|
5096
|
+
attachments: acc.attachments
|
|
5028
5097
|
});
|
|
5029
5098
|
return {
|
|
5030
5099
|
content: {
|
|
@@ -5165,11 +5234,21 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
5165
5234
|
this.logger.debug("[ENGINE] Signal assigned to preparedPayload.signal");
|
|
5166
5235
|
}
|
|
5167
5236
|
const input = await this.deserializeInput(preparedPayload.input || {});
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5237
|
+
try {
|
|
5238
|
+
const result = await graph.invoke(input, {
|
|
5239
|
+
...preparedPayload.config,
|
|
5240
|
+
signal: preparedPayload.signal
|
|
5241
|
+
});
|
|
5242
|
+
return this.processGraphResult(result);
|
|
5243
|
+
} finally {
|
|
5244
|
+
const threadId = this.extractThreadId(preparedPayload);
|
|
5245
|
+
if (threadId) {
|
|
5246
|
+
clearAttachmentDataStore(threadId);
|
|
5247
|
+
this.logger.debug(
|
|
5248
|
+
`[ENGINE] Cleared attachment data store for thread: ${threadId}`
|
|
5249
|
+
);
|
|
5250
|
+
}
|
|
5251
|
+
}
|
|
5173
5252
|
}
|
|
5174
5253
|
async streamGraph(graph, preparedPayload, onPartial, signal) {
|
|
5175
5254
|
const acc = this.eventProcessor.createAccumulator();
|
|
@@ -5210,6 +5289,13 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
5210
5289
|
this.logger.error(`[STREAM-ERROR] Stack trace: ${streamError.stack}`);
|
|
5211
5290
|
} finally {
|
|
5212
5291
|
await this.sendTraceFromAccumulator(acc, preparedPayload, streamError);
|
|
5292
|
+
const threadId = this.extractThreadId(preparedPayload);
|
|
5293
|
+
if (threadId) {
|
|
5294
|
+
clearAttachmentDataStore(threadId);
|
|
5295
|
+
this.logger.debug(
|
|
5296
|
+
`[ENGINE] Cleared attachment data store for thread: ${threadId}`
|
|
5297
|
+
);
|
|
5298
|
+
}
|
|
5213
5299
|
}
|
|
5214
5300
|
const { content, trace } = this.eventProcessor.getResult(acc);
|
|
5215
5301
|
this.logger.debug("[STREAM-RESULT] Got result from EventProcessor", {
|
|
@@ -5388,6 +5474,12 @@ exports.LangGraphEngine = class LangGraphEngine {
|
|
|
5388
5474
|
});
|
|
5389
5475
|
}
|
|
5390
5476
|
}
|
|
5477
|
+
/**
|
|
5478
|
+
* Extract threadId from payload (used for attachment store cleanup)
|
|
5479
|
+
*/
|
|
5480
|
+
extractThreadId(preparedPayload) {
|
|
5481
|
+
return preparedPayload.configurable?.thread_id || preparedPayload.configurable?.context?.threadId || preparedPayload.config?.configurable?.thread_id || preparedPayload.config?.configurable?.context?.threadId || void 0;
|
|
5482
|
+
}
|
|
5391
5483
|
/**
|
|
5392
5484
|
* Process graph execution result
|
|
5393
5485
|
*/
|
|
@@ -5413,6 +5505,9 @@ async function createStaticMessage(content, config) {
|
|
|
5413
5505
|
await dispatch.dispatchCustomEvent("send_static_message", { content }, config);
|
|
5414
5506
|
return message;
|
|
5415
5507
|
}
|
|
5508
|
+
async function dispatchAttachments(attachments, config) {
|
|
5509
|
+
await dispatch.dispatchCustomEvent("send_attachments", { attachments }, config);
|
|
5510
|
+
}
|
|
5416
5511
|
|
|
5417
5512
|
// src/core/universal-graph.module.ts
|
|
5418
5513
|
init_builder_registry_service();
|
|
@@ -7550,14 +7645,17 @@ exports.WithEndpoints = WithEndpoints;
|
|
|
7550
7645
|
exports.WithUIEndpoints = WithUIEndpoints;
|
|
7551
7646
|
exports._internals = _internals;
|
|
7552
7647
|
exports.bootstrap = bootstrap;
|
|
7648
|
+
exports.clearAttachmentDataStore = clearAttachmentDataStore;
|
|
7553
7649
|
exports.createEndpointDescriptors = createEndpointDescriptors;
|
|
7554
7650
|
exports.createGraphAttachment = createGraphAttachment;
|
|
7555
7651
|
exports.createMongoClientAdapter = createMongoClientAdapter;
|
|
7556
7652
|
exports.createStaticMessage = createStaticMessage;
|
|
7653
|
+
exports.dispatchAttachments = dispatchAttachments;
|
|
7557
7654
|
exports.executeToolWithAttachments = executeToolWithAttachments;
|
|
7558
7655
|
exports.findCallbackMethod = findCallbackMethod;
|
|
7559
7656
|
exports.findEndpointMethod = findEndpointMethod;
|
|
7560
7657
|
exports.generateAttachmentSummary = generateAttachmentSummary;
|
|
7658
|
+
exports.getAttachmentData = getAttachmentData;
|
|
7561
7659
|
exports.getCallbackMetadata = getCallbackMetadata;
|
|
7562
7660
|
exports.getEndpointMetadata = getEndpointMetadata;
|
|
7563
7661
|
exports.getUIEndpointClassMetadata = getUIEndpointClassMetadata;
|
|
@@ -7567,6 +7665,7 @@ exports.hasUIEndpoints = hasUIEndpoints;
|
|
|
7567
7665
|
exports.registerFinanceExampleCallback = registerFinanceExampleCallback;
|
|
7568
7666
|
exports.registerUIEndpointsFromClass = registerUIEndpointsFromClass;
|
|
7569
7667
|
exports.sanitizeTraceData = sanitizeTraceData;
|
|
7668
|
+
exports.storeAttachmentData = storeAttachmentData;
|
|
7570
7669
|
exports.traceApiCall = traceApiCall;
|
|
7571
7670
|
//# sourceMappingURL=index.cjs.map
|
|
7572
7671
|
//# sourceMappingURL=index.cjs.map
|