@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.cjs
CHANGED
|
@@ -1200,7 +1200,6 @@ var Logger = class {
|
|
|
1200
1200
|
constructor(moduleName) {
|
|
1201
1201
|
this.moduleName = moduleName;
|
|
1202
1202
|
}
|
|
1203
|
-
moduleName;
|
|
1204
1203
|
debug(message, data) {
|
|
1205
1204
|
this.log(0 /* DEBUG */, "debug", message, data);
|
|
1206
1205
|
}
|
|
@@ -1282,7 +1281,6 @@ var GraphExecutor = class {
|
|
|
1282
1281
|
};
|
|
1283
1282
|
this.telemetryPort = config.telemetryPort ?? noopTelemetry;
|
|
1284
1283
|
}
|
|
1285
|
-
checkpointer;
|
|
1286
1284
|
nodes = /* @__PURE__ */ new Map();
|
|
1287
1285
|
ephemeralLocals = /* @__PURE__ */ new Map();
|
|
1288
1286
|
config;
|
|
@@ -4564,6 +4562,22 @@ var ToolNode = class {
|
|
|
4564
4562
|
});
|
|
4565
4563
|
}
|
|
4566
4564
|
async run(state) {
|
|
4565
|
+
const events = [];
|
|
4566
|
+
while (true) {
|
|
4567
|
+
const result = await this.runNextPendingToolCall(state);
|
|
4568
|
+
if (Array.isArray(result.events) && result.events.length > 0) {
|
|
4569
|
+
events.push(...result.events);
|
|
4570
|
+
}
|
|
4571
|
+
if (result.kind === "route" && result.nextNodeId === "tool") {
|
|
4572
|
+
continue;
|
|
4573
|
+
}
|
|
4574
|
+
return {
|
|
4575
|
+
...result,
|
|
4576
|
+
events
|
|
4577
|
+
};
|
|
4578
|
+
}
|
|
4579
|
+
}
|
|
4580
|
+
async runNextPendingToolCall(state) {
|
|
4567
4581
|
const calls = state.local?.pendingToolCalls ?? [];
|
|
4568
4582
|
const signalRaw = state.local?.signal;
|
|
4569
4583
|
if (isAbortSignal(signalRaw) && signalRaw.aborted) {
|
|
@@ -4771,18 +4785,25 @@ var ToolNode = class {
|
|
|
4771
4785
|
rawArguments: context.call.function?.arguments,
|
|
4772
4786
|
parsedArguments: context.toolArgs
|
|
4773
4787
|
});
|
|
4788
|
+
const remainingCalls = context.calls.slice(1);
|
|
4774
4789
|
context.state.local = buildErrorLocalState({
|
|
4775
4790
|
local: context.local,
|
|
4776
|
-
remainingCalls
|
|
4791
|
+
remainingCalls,
|
|
4777
4792
|
conversationId: context.conversationId,
|
|
4778
4793
|
turnId: context.turnId,
|
|
4779
4794
|
runtimeEvents: context.bridge.getRuntimeEvents(),
|
|
4780
4795
|
nextProtocolErrorCount: fuse.nextCount
|
|
4781
4796
|
});
|
|
4782
|
-
if (fuse.shouldFuse) {
|
|
4797
|
+
if (fuse.shouldFuse && remainingCalls.length === 0) {
|
|
4783
4798
|
throw createToolProtocolFuseError(fuse.nextCount, context.exec.error);
|
|
4784
4799
|
}
|
|
4785
|
-
return {
|
|
4800
|
+
return {
|
|
4801
|
+
kind: "route",
|
|
4802
|
+
// 同一个 assistant.tool_calls batch 必须为每个 call 产出 tool_output。
|
|
4803
|
+
// 出错时也继续消费剩余 call,ToolNode.run 会在本节点内 drain 完 batch 再回 LLM。
|
|
4804
|
+
nextNodeId: remainingCalls.length > 0 ? "tool" : "llm",
|
|
4805
|
+
events: context.bridge.getRuntimeEvents()
|
|
4806
|
+
};
|
|
4786
4807
|
}
|
|
4787
4808
|
};
|
|
4788
4809
|
|
|
@@ -5278,18 +5299,18 @@ function createClassification(category, reason, suggestedDelay, extras) {
|
|
|
5278
5299
|
}
|
|
5279
5300
|
var ErrorClassifier = class {
|
|
5280
5301
|
static classify(error, context) {
|
|
5281
|
-
const
|
|
5302
|
+
const isRecord22 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
5282
5303
|
const baseMsg = (error.message || "").toLowerCase();
|
|
5283
5304
|
const causeMsg = (() => {
|
|
5284
5305
|
const cause = error.cause;
|
|
5285
5306
|
if (typeof cause === "string") return cause.toLowerCase();
|
|
5286
5307
|
if (cause instanceof Error) return (cause.message || "").toLowerCase();
|
|
5287
|
-
if (
|
|
5308
|
+
if (isRecord22(cause) && typeof cause["message"] === "string") return String(cause["message"]).toLowerCase();
|
|
5288
5309
|
return "";
|
|
5289
5310
|
})();
|
|
5290
5311
|
const causeCode = (() => {
|
|
5291
5312
|
const cause = error.cause;
|
|
5292
|
-
if (
|
|
5313
|
+
if (isRecord22(cause) && typeof cause["code"] === "string") return String(cause["code"]);
|
|
5293
5314
|
return "";
|
|
5294
5315
|
})();
|
|
5295
5316
|
const errorMessage = `${baseMsg} ${causeMsg}`.trim();
|
|
@@ -5965,6 +5986,67 @@ function assertToolCallsHaveValidJsonArguments(toolCalls) {
|
|
|
5965
5986
|
}
|
|
5966
5987
|
}
|
|
5967
5988
|
|
|
5989
|
+
// src/runtime-kernel/llm/reasoning-details.ts
|
|
5990
|
+
var mergeableTextFields = ["reasoning_content"];
|
|
5991
|
+
function isRecord18(value) {
|
|
5992
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5993
|
+
}
|
|
5994
|
+
function findMergeableTextField(detail) {
|
|
5995
|
+
if (!isRecord18(detail)) return void 0;
|
|
5996
|
+
if (typeof detail.provider !== "string") return void 0;
|
|
5997
|
+
if (typeof detail.type !== "string") return void 0;
|
|
5998
|
+
for (const field of mergeableTextFields) {
|
|
5999
|
+
if (typeof detail[field] === "string") {
|
|
6000
|
+
return field;
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
return void 0;
|
|
6004
|
+
}
|
|
6005
|
+
function hasOnlyStableTextDetailFields(detail, textField) {
|
|
6006
|
+
const allowedKeys = /* @__PURE__ */ new Set(["provider", "type", textField]);
|
|
6007
|
+
return Object.keys(detail).every((key) => allowedKeys.has(key));
|
|
6008
|
+
}
|
|
6009
|
+
function canMergeTextDetails(previous, incoming) {
|
|
6010
|
+
if (!isRecord18(previous) || !isRecord18(incoming)) return false;
|
|
6011
|
+
const previousField = findMergeableTextField(previous);
|
|
6012
|
+
const incomingField = findMergeableTextField(incoming);
|
|
6013
|
+
if (!previousField || previousField !== incomingField) return false;
|
|
6014
|
+
return previous.provider === incoming.provider && previous.type === incoming.type && hasOnlyStableTextDetailFields(previous, previousField) && hasOnlyStableTextDetailFields(incoming, incomingField);
|
|
6015
|
+
}
|
|
6016
|
+
function mergeStreamingText(previous, incoming) {
|
|
6017
|
+
if (!previous) return incoming;
|
|
6018
|
+
if (!incoming) return previous;
|
|
6019
|
+
if (incoming.startsWith(previous)) {
|
|
6020
|
+
return incoming;
|
|
6021
|
+
}
|
|
6022
|
+
if (previous.endsWith(incoming)) {
|
|
6023
|
+
return previous;
|
|
6024
|
+
}
|
|
6025
|
+
return `${previous}${incoming}`;
|
|
6026
|
+
}
|
|
6027
|
+
function appendStreamingProviderReasoningDetails(existing, incoming) {
|
|
6028
|
+
const next = [...existing];
|
|
6029
|
+
for (const detail of incoming) {
|
|
6030
|
+
const previous = next[next.length - 1];
|
|
6031
|
+
if (canMergeTextDetails(previous, detail)) {
|
|
6032
|
+
const textField = findMergeableTextField(previous);
|
|
6033
|
+
if (textField && isRecord18(detail)) {
|
|
6034
|
+
const mergedText = mergeStreamingText(String(previous[textField]), String(detail[textField]));
|
|
6035
|
+
if (mergedText === previous[textField]) {
|
|
6036
|
+
continue;
|
|
6037
|
+
}
|
|
6038
|
+
next[next.length - 1] = {
|
|
6039
|
+
...previous,
|
|
6040
|
+
[textField]: mergedText
|
|
6041
|
+
};
|
|
6042
|
+
continue;
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
6045
|
+
next.push(detail);
|
|
6046
|
+
}
|
|
6047
|
+
return next;
|
|
6048
|
+
}
|
|
6049
|
+
|
|
5968
6050
|
// src/runtime-kernel/llm/streaming-adapter.ts
|
|
5969
6051
|
async function callLlmStream(params) {
|
|
5970
6052
|
const {
|
|
@@ -5977,7 +6059,7 @@ async function callLlmStream(params) {
|
|
|
5977
6059
|
} = params;
|
|
5978
6060
|
let fullResponse = "";
|
|
5979
6061
|
let streamError = null;
|
|
5980
|
-
|
|
6062
|
+
let reasoningDetails = [];
|
|
5981
6063
|
const streamAnswerId = generateMessageId();
|
|
5982
6064
|
let streamChunkSeq = 0;
|
|
5983
6065
|
let capturedUsage = void 0;
|
|
@@ -6047,13 +6129,21 @@ async function callLlmStream(params) {
|
|
|
6047
6129
|
const reasoning = isRecord17(chunk) ? chunk["reasoning_details"] : void 0;
|
|
6048
6130
|
if (reasoning !== void 0) {
|
|
6049
6131
|
const newReasoningDetails = Array.isArray(reasoning) ? reasoning : [reasoning];
|
|
6050
|
-
reasoningDetails
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6132
|
+
const previousReasoningDetails = reasoningDetails;
|
|
6133
|
+
const previousLength = previousReasoningDetails.length;
|
|
6134
|
+
const compactedReasoningDetails = appendStreamingProviderReasoningDetails(reasoningDetails, newReasoningDetails);
|
|
6135
|
+
reasoningDetails = compactedReasoningDetails;
|
|
6136
|
+
const previousLastChanged = previousLength > 0 && compactedReasoningDetails[previousLength - 1] !== previousReasoningDetails[previousLength - 1];
|
|
6137
|
+
const emitFromIndex = previousLastChanged ? previousLength - 1 : previousLength;
|
|
6138
|
+
const emittedReasoningDetails = compactedReasoningDetails.slice(Math.max(0, emitFromIndex));
|
|
6139
|
+
if (emittedReasoningDetails.length > 0) {
|
|
6140
|
+
eventHandler({
|
|
6141
|
+
type: "provider_sidecar",
|
|
6142
|
+
id: generateMessageId(),
|
|
6143
|
+
timestamp: Date.now(),
|
|
6144
|
+
reasoning_details: emittedReasoningDetails
|
|
6145
|
+
});
|
|
6146
|
+
}
|
|
6057
6147
|
}
|
|
6058
6148
|
if (chunk.tool_calls) {
|
|
6059
6149
|
emitThoughtComplete(thoughtSegmenter.onBoundary());
|
|
@@ -6624,7 +6714,7 @@ function runRecordToMeta(record) {
|
|
|
6624
6714
|
errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0
|
|
6625
6715
|
};
|
|
6626
6716
|
}
|
|
6627
|
-
function
|
|
6717
|
+
function isRecord19(value) {
|
|
6628
6718
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6629
6719
|
}
|
|
6630
6720
|
function readStringField(record, key) {
|
|
@@ -6645,7 +6735,7 @@ function getRunIdFromMetadata(event) {
|
|
|
6645
6735
|
return snakeCaseRunId;
|
|
6646
6736
|
}
|
|
6647
6737
|
const runContext = metadata["run_context"];
|
|
6648
|
-
if (
|
|
6738
|
+
if (isRecord19(runContext)) {
|
|
6649
6739
|
return readStringField(runContext, "runId") ?? readStringField(runContext, "run_id");
|
|
6650
6740
|
}
|
|
6651
6741
|
return void 0;
|
|
@@ -6863,7 +6953,7 @@ function runMetaFromRecord(record) {
|
|
|
6863
6953
|
}
|
|
6864
6954
|
|
|
6865
6955
|
// src/runtime-kernel/run-supervisor/runSupervisor.ts
|
|
6866
|
-
function
|
|
6956
|
+
function isRecord20(value) {
|
|
6867
6957
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6868
6958
|
}
|
|
6869
6959
|
function readStringField2(record, key) {
|
|
@@ -6880,7 +6970,7 @@ function readRunIdFromRuntimeEvent(event) {
|
|
|
6880
6970
|
return directRunId;
|
|
6881
6971
|
}
|
|
6882
6972
|
const runContext = metadata["run_context"];
|
|
6883
|
-
if (!
|
|
6973
|
+
if (!isRecord20(runContext)) {
|
|
6884
6974
|
return void 0;
|
|
6885
6975
|
}
|
|
6886
6976
|
return readStringField2(runContext, "runId") ?? readStringField2(runContext, "run_id");
|
|
@@ -6892,7 +6982,7 @@ function readAwaitingUserReason(event) {
|
|
|
6892
6982
|
if (typeof event.prompt === "string" && event.prompt.trim().length > 0) {
|
|
6893
6983
|
return event.prompt;
|
|
6894
6984
|
}
|
|
6895
|
-
if (
|
|
6985
|
+
if (isRecord20(event.form)) {
|
|
6896
6986
|
const prompt = readStringField2(event.form, "prompt");
|
|
6897
6987
|
if (prompt && prompt.trim().length > 0) {
|
|
6898
6988
|
return prompt;
|
|
@@ -7502,7 +7592,7 @@ function createQuickstartTelemetryPort(collector) {
|
|
|
7502
7592
|
}
|
|
7503
7593
|
|
|
7504
7594
|
// src/quickstart/runAgent.ts
|
|
7505
|
-
function
|
|
7595
|
+
function isRecord21(value) {
|
|
7506
7596
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7507
7597
|
}
|
|
7508
7598
|
function readString4(value) {
|
|
@@ -7516,7 +7606,7 @@ function resolveModelId(agent, options) {
|
|
|
7516
7606
|
return modelId;
|
|
7517
7607
|
}
|
|
7518
7608
|
function isQuickstartStreamChunkEvent(value) {
|
|
7519
|
-
return
|
|
7609
|
+
return isRecord21(value) && value.type === "stream_chunk" && typeof value.content === "string";
|
|
7520
7610
|
}
|
|
7521
7611
|
function createNoopObservationPreview() {
|
|
7522
7612
|
return {
|
|
@@ -7556,7 +7646,7 @@ function readFinalAnswer(events, checkpointLocal) {
|
|
|
7556
7646
|
if (chunks.length > 0) {
|
|
7557
7647
|
return chunks.join("");
|
|
7558
7648
|
}
|
|
7559
|
-
if (
|
|
7649
|
+
if (isRecord21(checkpointLocal)) {
|
|
7560
7650
|
const finalAnswer = checkpointLocal["finalAnswer"];
|
|
7561
7651
|
if (typeof finalAnswer === "string") {
|
|
7562
7652
|
return finalAnswer;
|
|
@@ -7565,7 +7655,7 @@ function readFinalAnswer(events, checkpointLocal) {
|
|
|
7565
7655
|
return "";
|
|
7566
7656
|
}
|
|
7567
7657
|
function readContextTrace(checkpointLocal) {
|
|
7568
|
-
if (!
|
|
7658
|
+
if (!isRecord21(checkpointLocal)) return void 0;
|
|
7569
7659
|
return checkpointLocal["contextTrace"];
|
|
7570
7660
|
}
|
|
7571
7661
|
async function emitRunEvent(event, sink) {
|