@linnlabs/linnkit 0.8.0 → 0.9.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/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/cli.cjs +118 -28
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +118 -28
- package/dist/cli.js.map +1 -1
- package/dist/context-manager.cjs +0 -4
- package/dist/context-manager.cjs.map +1 -1
- package/dist/context-manager.js +0 -4
- package/dist/context-manager.js.map +1 -1
- package/dist/{index-Cm-JbzTH.d.cts → index-BanRABEt.d.cts} +14 -3
- package/dist/{index-DRBWi1fy.d.ts → index-Z8NXKNwI.d.ts} +14 -3
- package/dist/index.cjs +146 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +146 -30
- package/dist/index.js.map +1 -1
- package/dist/quickstart.cjs +115 -25
- package/dist/quickstart.cjs.map +1 -1
- package/dist/quickstart.js +115 -25
- package/dist/quickstart.js.map +1 -1
- package/dist/runtime-kernel.cjs +142 -26
- package/dist/runtime-kernel.cjs.map +1 -1
- package/dist/runtime-kernel.d.cts +1 -1
- package/dist/runtime-kernel.d.ts +1 -1
- package/dist/runtime-kernel.js +140 -27
- package/dist/runtime-kernel.js.map +1 -1
- package/dist/testkit.cjs +155 -39
- package/dist/testkit.cjs.map +1 -1
- package/dist/testkit.js +155 -39
- package/dist/testkit.js.map +1 -1
- package/package.json +3 -3
package/dist/quickstart.js
CHANGED
|
@@ -1198,7 +1198,6 @@ var Logger = class {
|
|
|
1198
1198
|
constructor(moduleName) {
|
|
1199
1199
|
this.moduleName = moduleName;
|
|
1200
1200
|
}
|
|
1201
|
-
moduleName;
|
|
1202
1201
|
debug(message, data) {
|
|
1203
1202
|
this.log(0 /* DEBUG */, "debug", message, data);
|
|
1204
1203
|
}
|
|
@@ -1280,7 +1279,6 @@ var GraphExecutor = class {
|
|
|
1280
1279
|
};
|
|
1281
1280
|
this.telemetryPort = config.telemetryPort ?? noopTelemetry;
|
|
1282
1281
|
}
|
|
1283
|
-
checkpointer;
|
|
1284
1282
|
nodes = /* @__PURE__ */ new Map();
|
|
1285
1283
|
ephemeralLocals = /* @__PURE__ */ new Map();
|
|
1286
1284
|
config;
|
|
@@ -4562,6 +4560,22 @@ var ToolNode = class {
|
|
|
4562
4560
|
});
|
|
4563
4561
|
}
|
|
4564
4562
|
async run(state) {
|
|
4563
|
+
const events = [];
|
|
4564
|
+
while (true) {
|
|
4565
|
+
const result = await this.runNextPendingToolCall(state);
|
|
4566
|
+
if (Array.isArray(result.events) && result.events.length > 0) {
|
|
4567
|
+
events.push(...result.events);
|
|
4568
|
+
}
|
|
4569
|
+
if (result.kind === "route" && result.nextNodeId === "tool") {
|
|
4570
|
+
continue;
|
|
4571
|
+
}
|
|
4572
|
+
return {
|
|
4573
|
+
...result,
|
|
4574
|
+
events
|
|
4575
|
+
};
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
async runNextPendingToolCall(state) {
|
|
4565
4579
|
const calls = state.local?.pendingToolCalls ?? [];
|
|
4566
4580
|
const signalRaw = state.local?.signal;
|
|
4567
4581
|
if (isAbortSignal(signalRaw) && signalRaw.aborted) {
|
|
@@ -4769,18 +4783,25 @@ var ToolNode = class {
|
|
|
4769
4783
|
rawArguments: context.call.function?.arguments,
|
|
4770
4784
|
parsedArguments: context.toolArgs
|
|
4771
4785
|
});
|
|
4786
|
+
const remainingCalls = context.calls.slice(1);
|
|
4772
4787
|
context.state.local = buildErrorLocalState({
|
|
4773
4788
|
local: context.local,
|
|
4774
|
-
remainingCalls
|
|
4789
|
+
remainingCalls,
|
|
4775
4790
|
conversationId: context.conversationId,
|
|
4776
4791
|
turnId: context.turnId,
|
|
4777
4792
|
runtimeEvents: context.bridge.getRuntimeEvents(),
|
|
4778
4793
|
nextProtocolErrorCount: fuse.nextCount
|
|
4779
4794
|
});
|
|
4780
|
-
if (fuse.shouldFuse) {
|
|
4795
|
+
if (fuse.shouldFuse && remainingCalls.length === 0) {
|
|
4781
4796
|
throw createToolProtocolFuseError(fuse.nextCount, context.exec.error);
|
|
4782
4797
|
}
|
|
4783
|
-
return {
|
|
4798
|
+
return {
|
|
4799
|
+
kind: "route",
|
|
4800
|
+
// 同一个 assistant.tool_calls batch 必须为每个 call 产出 tool_output。
|
|
4801
|
+
// 出错时也继续消费剩余 call,ToolNode.run 会在本节点内 drain 完 batch 再回 LLM。
|
|
4802
|
+
nextNodeId: remainingCalls.length > 0 ? "tool" : "llm",
|
|
4803
|
+
events: context.bridge.getRuntimeEvents()
|
|
4804
|
+
};
|
|
4784
4805
|
}
|
|
4785
4806
|
};
|
|
4786
4807
|
|
|
@@ -5276,18 +5297,18 @@ function createClassification(category, reason, suggestedDelay, extras) {
|
|
|
5276
5297
|
}
|
|
5277
5298
|
var ErrorClassifier = class {
|
|
5278
5299
|
static classify(error, context) {
|
|
5279
|
-
const
|
|
5300
|
+
const isRecord22 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
5280
5301
|
const baseMsg = (error.message || "").toLowerCase();
|
|
5281
5302
|
const causeMsg = (() => {
|
|
5282
5303
|
const cause = error.cause;
|
|
5283
5304
|
if (typeof cause === "string") return cause.toLowerCase();
|
|
5284
5305
|
if (cause instanceof Error) return (cause.message || "").toLowerCase();
|
|
5285
|
-
if (
|
|
5306
|
+
if (isRecord22(cause) && typeof cause["message"] === "string") return String(cause["message"]).toLowerCase();
|
|
5286
5307
|
return "";
|
|
5287
5308
|
})();
|
|
5288
5309
|
const causeCode = (() => {
|
|
5289
5310
|
const cause = error.cause;
|
|
5290
|
-
if (
|
|
5311
|
+
if (isRecord22(cause) && typeof cause["code"] === "string") return String(cause["code"]);
|
|
5291
5312
|
return "";
|
|
5292
5313
|
})();
|
|
5293
5314
|
const errorMessage = `${baseMsg} ${causeMsg}`.trim();
|
|
@@ -5963,6 +5984,67 @@ function assertToolCallsHaveValidJsonArguments(toolCalls) {
|
|
|
5963
5984
|
}
|
|
5964
5985
|
}
|
|
5965
5986
|
|
|
5987
|
+
// src/runtime-kernel/llm/reasoning-details.ts
|
|
5988
|
+
var mergeableTextFields = ["reasoning_content"];
|
|
5989
|
+
function isRecord18(value) {
|
|
5990
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5991
|
+
}
|
|
5992
|
+
function findMergeableTextField(detail) {
|
|
5993
|
+
if (!isRecord18(detail)) return void 0;
|
|
5994
|
+
if (typeof detail.provider !== "string") return void 0;
|
|
5995
|
+
if (typeof detail.type !== "string") return void 0;
|
|
5996
|
+
for (const field of mergeableTextFields) {
|
|
5997
|
+
if (typeof detail[field] === "string") {
|
|
5998
|
+
return field;
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
return void 0;
|
|
6002
|
+
}
|
|
6003
|
+
function hasOnlyStableTextDetailFields(detail, textField) {
|
|
6004
|
+
const allowedKeys = /* @__PURE__ */ new Set(["provider", "type", textField]);
|
|
6005
|
+
return Object.keys(detail).every((key) => allowedKeys.has(key));
|
|
6006
|
+
}
|
|
6007
|
+
function canMergeTextDetails(previous, incoming) {
|
|
6008
|
+
if (!isRecord18(previous) || !isRecord18(incoming)) return false;
|
|
6009
|
+
const previousField = findMergeableTextField(previous);
|
|
6010
|
+
const incomingField = findMergeableTextField(incoming);
|
|
6011
|
+
if (!previousField || previousField !== incomingField) return false;
|
|
6012
|
+
return previous.provider === incoming.provider && previous.type === incoming.type && hasOnlyStableTextDetailFields(previous, previousField) && hasOnlyStableTextDetailFields(incoming, incomingField);
|
|
6013
|
+
}
|
|
6014
|
+
function mergeStreamingText(previous, incoming) {
|
|
6015
|
+
if (!previous) return incoming;
|
|
6016
|
+
if (!incoming) return previous;
|
|
6017
|
+
if (incoming.startsWith(previous)) {
|
|
6018
|
+
return incoming;
|
|
6019
|
+
}
|
|
6020
|
+
if (previous.endsWith(incoming)) {
|
|
6021
|
+
return previous;
|
|
6022
|
+
}
|
|
6023
|
+
return `${previous}${incoming}`;
|
|
6024
|
+
}
|
|
6025
|
+
function appendStreamingProviderReasoningDetails(existing, incoming) {
|
|
6026
|
+
const next = [...existing];
|
|
6027
|
+
for (const detail of incoming) {
|
|
6028
|
+
const previous = next[next.length - 1];
|
|
6029
|
+
if (canMergeTextDetails(previous, detail)) {
|
|
6030
|
+
const textField = findMergeableTextField(previous);
|
|
6031
|
+
if (textField && isRecord18(detail)) {
|
|
6032
|
+
const mergedText = mergeStreamingText(String(previous[textField]), String(detail[textField]));
|
|
6033
|
+
if (mergedText === previous[textField]) {
|
|
6034
|
+
continue;
|
|
6035
|
+
}
|
|
6036
|
+
next[next.length - 1] = {
|
|
6037
|
+
...previous,
|
|
6038
|
+
[textField]: mergedText
|
|
6039
|
+
};
|
|
6040
|
+
continue;
|
|
6041
|
+
}
|
|
6042
|
+
}
|
|
6043
|
+
next.push(detail);
|
|
6044
|
+
}
|
|
6045
|
+
return next;
|
|
6046
|
+
}
|
|
6047
|
+
|
|
5966
6048
|
// src/runtime-kernel/llm/streaming-adapter.ts
|
|
5967
6049
|
async function callLlmStream(params) {
|
|
5968
6050
|
const {
|
|
@@ -5975,7 +6057,7 @@ async function callLlmStream(params) {
|
|
|
5975
6057
|
} = params;
|
|
5976
6058
|
let fullResponse = "";
|
|
5977
6059
|
let streamError = null;
|
|
5978
|
-
|
|
6060
|
+
let reasoningDetails = [];
|
|
5979
6061
|
const streamAnswerId = generateMessageId();
|
|
5980
6062
|
let streamChunkSeq = 0;
|
|
5981
6063
|
let capturedUsage = void 0;
|
|
@@ -6045,13 +6127,21 @@ async function callLlmStream(params) {
|
|
|
6045
6127
|
const reasoning = isRecord17(chunk) ? chunk["reasoning_details"] : void 0;
|
|
6046
6128
|
if (reasoning !== void 0) {
|
|
6047
6129
|
const newReasoningDetails = Array.isArray(reasoning) ? reasoning : [reasoning];
|
|
6048
|
-
reasoningDetails
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6130
|
+
const previousReasoningDetails = reasoningDetails;
|
|
6131
|
+
const previousLength = previousReasoningDetails.length;
|
|
6132
|
+
const compactedReasoningDetails = appendStreamingProviderReasoningDetails(reasoningDetails, newReasoningDetails);
|
|
6133
|
+
reasoningDetails = compactedReasoningDetails;
|
|
6134
|
+
const previousLastChanged = previousLength > 0 && compactedReasoningDetails[previousLength - 1] !== previousReasoningDetails[previousLength - 1];
|
|
6135
|
+
const emitFromIndex = previousLastChanged ? previousLength - 1 : previousLength;
|
|
6136
|
+
const emittedReasoningDetails = compactedReasoningDetails.slice(Math.max(0, emitFromIndex));
|
|
6137
|
+
if (emittedReasoningDetails.length > 0) {
|
|
6138
|
+
eventHandler({
|
|
6139
|
+
type: "provider_sidecar",
|
|
6140
|
+
id: generateMessageId(),
|
|
6141
|
+
timestamp: Date.now(),
|
|
6142
|
+
reasoning_details: emittedReasoningDetails
|
|
6143
|
+
});
|
|
6144
|
+
}
|
|
6055
6145
|
}
|
|
6056
6146
|
if (chunk.tool_calls) {
|
|
6057
6147
|
emitThoughtComplete(thoughtSegmenter.onBoundary());
|
|
@@ -6622,7 +6712,7 @@ function runRecordToMeta(record) {
|
|
|
6622
6712
|
errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0
|
|
6623
6713
|
};
|
|
6624
6714
|
}
|
|
6625
|
-
function
|
|
6715
|
+
function isRecord19(value) {
|
|
6626
6716
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6627
6717
|
}
|
|
6628
6718
|
function readStringField(record, key) {
|
|
@@ -6643,7 +6733,7 @@ function getRunIdFromMetadata(event) {
|
|
|
6643
6733
|
return snakeCaseRunId;
|
|
6644
6734
|
}
|
|
6645
6735
|
const runContext = metadata["run_context"];
|
|
6646
|
-
if (
|
|
6736
|
+
if (isRecord19(runContext)) {
|
|
6647
6737
|
return readStringField(runContext, "runId") ?? readStringField(runContext, "run_id");
|
|
6648
6738
|
}
|
|
6649
6739
|
return void 0;
|
|
@@ -6861,7 +6951,7 @@ function runMetaFromRecord(record) {
|
|
|
6861
6951
|
}
|
|
6862
6952
|
|
|
6863
6953
|
// src/runtime-kernel/run-supervisor/runSupervisor.ts
|
|
6864
|
-
function
|
|
6954
|
+
function isRecord20(value) {
|
|
6865
6955
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6866
6956
|
}
|
|
6867
6957
|
function readStringField2(record, key) {
|
|
@@ -6878,7 +6968,7 @@ function readRunIdFromRuntimeEvent(event) {
|
|
|
6878
6968
|
return directRunId;
|
|
6879
6969
|
}
|
|
6880
6970
|
const runContext = metadata["run_context"];
|
|
6881
|
-
if (!
|
|
6971
|
+
if (!isRecord20(runContext)) {
|
|
6882
6972
|
return void 0;
|
|
6883
6973
|
}
|
|
6884
6974
|
return readStringField2(runContext, "runId") ?? readStringField2(runContext, "run_id");
|
|
@@ -6890,7 +6980,7 @@ function readAwaitingUserReason(event) {
|
|
|
6890
6980
|
if (typeof event.prompt === "string" && event.prompt.trim().length > 0) {
|
|
6891
6981
|
return event.prompt;
|
|
6892
6982
|
}
|
|
6893
|
-
if (
|
|
6983
|
+
if (isRecord20(event.form)) {
|
|
6894
6984
|
const prompt = readStringField2(event.form, "prompt");
|
|
6895
6985
|
if (prompt && prompt.trim().length > 0) {
|
|
6896
6986
|
return prompt;
|
|
@@ -7500,7 +7590,7 @@ function createQuickstartTelemetryPort(collector) {
|
|
|
7500
7590
|
}
|
|
7501
7591
|
|
|
7502
7592
|
// src/quickstart/runAgent.ts
|
|
7503
|
-
function
|
|
7593
|
+
function isRecord21(value) {
|
|
7504
7594
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7505
7595
|
}
|
|
7506
7596
|
function readString4(value) {
|
|
@@ -7514,7 +7604,7 @@ function resolveModelId(agent, options) {
|
|
|
7514
7604
|
return modelId;
|
|
7515
7605
|
}
|
|
7516
7606
|
function isQuickstartStreamChunkEvent(value) {
|
|
7517
|
-
return
|
|
7607
|
+
return isRecord21(value) && value.type === "stream_chunk" && typeof value.content === "string";
|
|
7518
7608
|
}
|
|
7519
7609
|
function createNoopObservationPreview() {
|
|
7520
7610
|
return {
|
|
@@ -7554,7 +7644,7 @@ function readFinalAnswer(events, checkpointLocal) {
|
|
|
7554
7644
|
if (chunks.length > 0) {
|
|
7555
7645
|
return chunks.join("");
|
|
7556
7646
|
}
|
|
7557
|
-
if (
|
|
7647
|
+
if (isRecord21(checkpointLocal)) {
|
|
7558
7648
|
const finalAnswer = checkpointLocal["finalAnswer"];
|
|
7559
7649
|
if (typeof finalAnswer === "string") {
|
|
7560
7650
|
return finalAnswer;
|
|
@@ -7563,7 +7653,7 @@ function readFinalAnswer(events, checkpointLocal) {
|
|
|
7563
7653
|
return "";
|
|
7564
7654
|
}
|
|
7565
7655
|
function readContextTrace(checkpointLocal) {
|
|
7566
|
-
if (!
|
|
7656
|
+
if (!isRecord21(checkpointLocal)) return void 0;
|
|
7567
7657
|
return checkpointLocal["contextTrace"];
|
|
7568
7658
|
}
|
|
7569
7659
|
async function emitRunEvent(event, sink) {
|