@flutchai/flutch-sdk 0.7.10 → 0.7.12
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 +106 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +106 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2133,11 +2133,28 @@ exports.GraphController = class _GraphController {
|
|
|
2133
2133
|
}
|
|
2134
2134
|
async generateAnswer(payload, res) {
|
|
2135
2135
|
this.cancelOnDisconnect(res, payload.requestId);
|
|
2136
|
+
let beating = false;
|
|
2137
|
+
const stop = this.heartbeat(() => {
|
|
2138
|
+
if (!beating) {
|
|
2139
|
+
res.status(common.HttpStatus.CREATED).setHeader("Content-Type", "application/json");
|
|
2140
|
+
beating = true;
|
|
2141
|
+
}
|
|
2142
|
+
res.write(" ");
|
|
2143
|
+
});
|
|
2136
2144
|
try {
|
|
2137
|
-
|
|
2145
|
+
const result = await this.graphService.generateAnswer(payload);
|
|
2146
|
+
stop();
|
|
2147
|
+
if (beating) res.end(JSON.stringify(result));
|
|
2148
|
+
else res.status(common.HttpStatus.CREATED).json(result);
|
|
2138
2149
|
} catch (error) {
|
|
2150
|
+
stop();
|
|
2139
2151
|
this.logger.error(`Generation failed: ${error.message}`);
|
|
2140
|
-
|
|
2152
|
+
const failure = {
|
|
2153
|
+
statusCode: common.HttpStatus.INTERNAL_SERVER_ERROR,
|
|
2154
|
+
message: `Generation failed: ${error.message}`
|
|
2155
|
+
};
|
|
2156
|
+
if (beating) res.end(JSON.stringify(failure));
|
|
2157
|
+
else res.status(common.HttpStatus.INTERNAL_SERVER_ERROR).json(failure);
|
|
2141
2158
|
}
|
|
2142
2159
|
}
|
|
2143
2160
|
async streamAnswer(payload, res) {
|
|
@@ -2146,6 +2163,7 @@ exports.GraphController = class _GraphController {
|
|
|
2146
2163
|
res.setHeader("Cache-Control", "no-cache");
|
|
2147
2164
|
res.setHeader("Connection", "keep-alive");
|
|
2148
2165
|
this.cancelOnDisconnect(res, payload.requestId);
|
|
2166
|
+
const stop = this.heartbeat(() => res.write(": ping\n\n"));
|
|
2149
2167
|
try {
|
|
2150
2168
|
this.logger.debug(`[CONTROLLER] Starting streamAnswer for requestId: ${payload.requestId}`);
|
|
2151
2169
|
const result = await this.graphService.streamAnswer(payload, (chunk) => {
|
|
@@ -2163,6 +2181,7 @@ exports.GraphController = class _GraphController {
|
|
|
2163
2181
|
reasoningChainsCount: result.reasoningChains?.length || 0,
|
|
2164
2182
|
resultKeys: Object.keys(result || {})
|
|
2165
2183
|
});
|
|
2184
|
+
stop();
|
|
2166
2185
|
res.write(`event: final
|
|
2167
2186
|
`);
|
|
2168
2187
|
res.write(`data: ${JSON.stringify(result)}
|
|
@@ -2171,6 +2190,7 @@ exports.GraphController = class _GraphController {
|
|
|
2171
2190
|
res.end();
|
|
2172
2191
|
this.logger.debug(`[CONTROLLER] Stream completed successfully`);
|
|
2173
2192
|
} catch (error) {
|
|
2193
|
+
stop();
|
|
2174
2194
|
this.logger.error(`[CONTROLLER] Streaming failed: ${error.message}`);
|
|
2175
2195
|
this.logger.error(`[CONTROLLER] Error stack: ${error.stack}`);
|
|
2176
2196
|
res.write(`event: error
|
|
@@ -2184,6 +2204,20 @@ exports.GraphController = class _GraphController {
|
|
|
2184
2204
|
}
|
|
2185
2205
|
}
|
|
2186
2206
|
/**
|
|
2207
|
+
* Calls `beat` every GRAPH_HEARTBEAT_MS (20 s by default, 0 turns it off)
|
|
2208
|
+
* while a run goes on; returns the function that stops it. A caller drops a
|
|
2209
|
+
* connection that stays silent past its idle limit — the backend's is
|
|
2210
|
+
* GRAPH_SERVICE_TIMEOUT_MS — and a graph waiting on other agents is silent
|
|
2211
|
+
* for minutes: a report pipeline was cut at 15 minutes, 21 seconds before
|
|
2212
|
+
* its report was done (29.10.2026).
|
|
2213
|
+
*/
|
|
2214
|
+
heartbeat(beat) {
|
|
2215
|
+
const ms = Number(process.env.GRAPH_HEARTBEAT_MS ?? 2e4);
|
|
2216
|
+
if (!(ms > 0)) return () => void 0;
|
|
2217
|
+
const timer = setInterval(beat, ms);
|
|
2218
|
+
return () => clearInterval(timer);
|
|
2219
|
+
}
|
|
2220
|
+
/**
|
|
2187
2221
|
* A caller that hangs up before the answer is done — its own timeout, a
|
|
2188
2222
|
* restart, a cancelled parent run — no longer waits for it, so the run is
|
|
2189
2223
|
* cancelled: left going, it keeps calling models and tools nobody reads.
|
|
@@ -2269,9 +2303,7 @@ _ts_decorate8([
|
|
|
2269
2303
|
description: "Answer generated"
|
|
2270
2304
|
}),
|
|
2271
2305
|
_ts_param4(0, common.Body()),
|
|
2272
|
-
_ts_param4(1, common.Res(
|
|
2273
|
-
passthrough: true
|
|
2274
|
-
})),
|
|
2306
|
+
_ts_param4(1, common.Res()),
|
|
2275
2307
|
_ts_metadata6("design:type", Function),
|
|
2276
2308
|
_ts_metadata6("design:paramtypes", [
|
|
2277
2309
|
typeof IGraphRequestPayload === "undefined" ? Object : IGraphRequestPayload,
|
|
@@ -4806,6 +4838,20 @@ var StreamChannel = /* @__PURE__ */ (function(StreamChannel2) {
|
|
|
4806
4838
|
return StreamChannel2;
|
|
4807
4839
|
})({});
|
|
4808
4840
|
|
|
4841
|
+
// src/messages/thinking.ts
|
|
4842
|
+
var textOf = /* @__PURE__ */ __name((part) => typeof part === "string" ? part : part && typeof part.text === "string" ? String(part.text) : "", "textOf");
|
|
4843
|
+
var summaryTexts = /* @__PURE__ */ __name((summary) => Array.isArray(summary) ? summary.map(textOf) : [], "summaryTexts");
|
|
4844
|
+
function extractThinking(message) {
|
|
4845
|
+
const blocks = Array.isArray(message.content) ? message.content : [];
|
|
4846
|
+
const reasoning = message.additional_kwargs?.reasoning;
|
|
4847
|
+
return [
|
|
4848
|
+
...blocks.filter((b) => b?.type === "thinking" && typeof b.thinking === "string").map((b) => String(b.thinking)),
|
|
4849
|
+
...blocks.filter((b) => b?.type === "reasoning").flatMap((b) => summaryTexts(b.summary)),
|
|
4850
|
+
...summaryTexts(reasoning?.summary)
|
|
4851
|
+
].map((t) => t.trim()).filter(Boolean).filter((t, i, all) => all.indexOf(t) === i).join("\n\n");
|
|
4852
|
+
}
|
|
4853
|
+
__name(extractThinking, "extractThinking");
|
|
4854
|
+
|
|
4809
4855
|
// src/tools/attachment-summary.ts
|
|
4810
4856
|
var MAX_SAMPLE_ROWS = 5;
|
|
4811
4857
|
var MAX_TEXT_PREVIEW_LENGTH = 500;
|
|
@@ -5156,6 +5202,45 @@ function sanitizeTraceError(error, options) {
|
|
|
5156
5202
|
};
|
|
5157
5203
|
}
|
|
5158
5204
|
__name(sanitizeTraceError, "sanitizeTraceError");
|
|
5205
|
+
|
|
5206
|
+
// src/engines/langgraph/stream-thinking.ts
|
|
5207
|
+
function splitThinking(blocks) {
|
|
5208
|
+
const thoughts = [];
|
|
5209
|
+
const rest = [];
|
|
5210
|
+
for (const block of blocks) {
|
|
5211
|
+
const part = block;
|
|
5212
|
+
if (part?.type === "thinking" || part?.type === "reasoning") {
|
|
5213
|
+
const text = part.type === "thinking" ? part.thinking : part.reasoning;
|
|
5214
|
+
if (typeof text === "string" && text) thoughts.push({
|
|
5215
|
+
text,
|
|
5216
|
+
index: part.index
|
|
5217
|
+
});
|
|
5218
|
+
continue;
|
|
5219
|
+
}
|
|
5220
|
+
rest.push(block);
|
|
5221
|
+
}
|
|
5222
|
+
return {
|
|
5223
|
+
thoughts,
|
|
5224
|
+
rest
|
|
5225
|
+
};
|
|
5226
|
+
}
|
|
5227
|
+
__name(splitThinking, "splitThinking");
|
|
5228
|
+
function thinkingTexts(state, runId, deltas) {
|
|
5229
|
+
const out = [];
|
|
5230
|
+
for (const delta of deltas) {
|
|
5231
|
+
const another = runId !== state.runId || state.index !== void 0 && delta.index !== state.index;
|
|
5232
|
+
out.push(state.shown && another ? `
|
|
5233
|
+
|
|
5234
|
+
${delta.text}` : delta.text);
|
|
5235
|
+
state.runId = runId;
|
|
5236
|
+
state.index = delta.index;
|
|
5237
|
+
state.shown = true;
|
|
5238
|
+
}
|
|
5239
|
+
return out;
|
|
5240
|
+
}
|
|
5241
|
+
__name(thinkingTexts, "thinkingTexts");
|
|
5242
|
+
|
|
5243
|
+
// src/engines/langgraph/event-processor.utils.ts
|
|
5159
5244
|
function _ts_decorate21(decorators, target, key, desc) {
|
|
5160
5245
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5161
5246
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -5463,7 +5548,21 @@ exports.EventProcessor = class _EventProcessor {
|
|
|
5463
5548
|
const chunk = event.data.chunk;
|
|
5464
5549
|
const blocks = [];
|
|
5465
5550
|
if (chunk.content) {
|
|
5466
|
-
|
|
5551
|
+
const { thoughts, rest } = splitThinking(this.normalizeContentBlocks(chunk.content));
|
|
5552
|
+
blocks.push(...rest);
|
|
5553
|
+
if (thoughts.length && event.metadata?.stream_thinking === true) {
|
|
5554
|
+
acc.thinking ??= {
|
|
5555
|
+
runId: null,
|
|
5556
|
+
index: void 0,
|
|
5557
|
+
shown: false
|
|
5558
|
+
};
|
|
5559
|
+
for (const text of thinkingTexts(acc.thinking, event.run_id ?? null, thoughts)) this.processContentStream(acc, StreamChannel.PROCESSING, [
|
|
5560
|
+
{
|
|
5561
|
+
type: "text",
|
|
5562
|
+
text
|
|
5563
|
+
}
|
|
5564
|
+
], onPartial);
|
|
5565
|
+
}
|
|
5467
5566
|
}
|
|
5468
5567
|
const contentHasToolBlocks = blocks.some((block) => block?.type === "tool_use" || block?.type === "tool_call" || block?.type === "input_json_delta");
|
|
5469
5568
|
if (!contentHasToolBlocks && Array.isArray(chunk.tool_call_chunks) && chunk.tool_call_chunks.length > 0) {
|
|
@@ -9275,6 +9374,7 @@ exports.decryptTokens = decryptTokens;
|
|
|
9275
9374
|
exports.dispatchAttachments = dispatchAttachments;
|
|
9276
9375
|
exports.encryptTokens = encryptTokens;
|
|
9277
9376
|
exports.executeToolWithAttachments = executeToolWithAttachments;
|
|
9377
|
+
exports.extractThinking = extractThinking;
|
|
9278
9378
|
exports.findCallbackMethod = findCallbackMethod;
|
|
9279
9379
|
exports.findEndpointMethod = findEndpointMethod;
|
|
9280
9380
|
exports.flutchFetch = flutchFetch;
|