@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/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { i as ports } from './index-Cvr23YCl.cjs';
2
- export { i as runtimeKernel } from './index-Cm-JbzTH.cjs';
2
+ export { i as runtimeKernel } from './index-BanRABEt.cjs';
3
3
  export { i as contracts } from './index-Dl5PLgAv.cjs';
4
4
  export { D as DefineAgentInput, a as DefinedAgent, L as LinnkitQuickstartConfig, R as RunAgentOptions, b as RunAgentResult, d as defineAgent, c as defineConfig, r as resolveConfiguredLlm, e as runAgent } from './runAgent-HYKlXbVr.cjs';
5
5
  export { L as LlmCallTelemetry, w as withLLMTelemetryContext } from './defaultGraphExecutor-BIjJj7WF.cjs';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { i as ports } from './index-DDzuSb0n.js';
2
- export { i as runtimeKernel } from './index-DRBWi1fy.js';
2
+ export { i as runtimeKernel } from './index-Z8NXKNwI.js';
3
3
  export { i as contracts } from './index-CHqwkvGp.js';
4
4
  export { D as DefineAgentInput, a as DefinedAgent, L as LinnkitQuickstartConfig, R as RunAgentOptions, b as RunAgentResult, d as defineAgent, c as defineConfig, r as resolveConfiguredLlm, e as runAgent } from './runAgent-CPj_9e58.js';
5
5
  export { L as LlmCallTelemetry, w as withLLMTelemetryContext } from './defaultGraphExecutor-BBswR8wn.js';
package/dist/index.js CHANGED
@@ -46,11 +46,14 @@ __export(runtime_kernel_exports, {
46
46
  UserNode: () => UserNode,
47
47
  WaitUserNode: () => WaitUserNode,
48
48
  agentHasToolTrigger: () => agentHasToolTrigger,
49
+ appendStreamingProviderReasoningDetails: () => appendStreamingProviderReasoningDetails,
49
50
  applySystemReminders: () => applySystemReminders,
50
51
  audit: () => audit_exports,
51
52
  budgetWarningTrigger: () => budgetWarningTrigger,
52
53
  childRunTrace: () => child_run_trace_exports,
53
54
  childRuns: () => child_runs_exports,
55
+ compactProviderReasoningDetails: () => compactProviderReasoningDetails,
56
+ compactReasoningDetailsInValue: () => compactReasoningDetailsInValue,
54
57
  computeToolIdempotencyKey: () => computeToolIdempotencyKey,
55
58
  consoleAudit: () => consoleAudit,
56
59
  contextBudgetWarningTemplate: () => contextBudgetWarningTemplate,
@@ -135,7 +138,6 @@ var Logger = class {
135
138
  constructor(moduleName) {
136
139
  this.moduleName = moduleName;
137
140
  }
138
- moduleName;
139
141
  debug(message, data) {
140
142
  this.log(0 /* DEBUG */, "debug", message, data);
141
143
  }
@@ -1547,7 +1549,6 @@ var GraphExecutor = class {
1547
1549
  };
1548
1550
  this.telemetryPort = config.telemetryPort ?? noopTelemetry;
1549
1551
  }
1550
- checkpointer;
1551
1552
  nodes = /* @__PURE__ */ new Map();
1552
1553
  ephemeralLocals = /* @__PURE__ */ new Map();
1553
1554
  config;
@@ -4968,6 +4969,22 @@ var ToolNode = class {
4968
4969
  });
4969
4970
  }
4970
4971
  async run(state) {
4972
+ const events = [];
4973
+ while (true) {
4974
+ const result = await this.runNextPendingToolCall(state);
4975
+ if (Array.isArray(result.events) && result.events.length > 0) {
4976
+ events.push(...result.events);
4977
+ }
4978
+ if (result.kind === "route" && result.nextNodeId === "tool") {
4979
+ continue;
4980
+ }
4981
+ return {
4982
+ ...result,
4983
+ events
4984
+ };
4985
+ }
4986
+ }
4987
+ async runNextPendingToolCall(state) {
4971
4988
  const calls = state.local?.pendingToolCalls ?? [];
4972
4989
  const signalRaw = state.local?.signal;
4973
4990
  if (isAbortSignal(signalRaw) && signalRaw.aborted) {
@@ -5175,18 +5192,25 @@ var ToolNode = class {
5175
5192
  rawArguments: context.call.function?.arguments,
5176
5193
  parsedArguments: context.toolArgs
5177
5194
  });
5195
+ const remainingCalls = context.calls.slice(1);
5178
5196
  context.state.local = buildErrorLocalState({
5179
5197
  local: context.local,
5180
- remainingCalls: context.calls.slice(1),
5198
+ remainingCalls,
5181
5199
  conversationId: context.conversationId,
5182
5200
  turnId: context.turnId,
5183
5201
  runtimeEvents: context.bridge.getRuntimeEvents(),
5184
5202
  nextProtocolErrorCount: fuse.nextCount
5185
5203
  });
5186
- if (fuse.shouldFuse) {
5204
+ if (fuse.shouldFuse && remainingCalls.length === 0) {
5187
5205
  throw createToolProtocolFuseError(fuse.nextCount, context.exec.error);
5188
5206
  }
5189
- return { kind: "route", nextNodeId: "llm", events: context.bridge.getRuntimeEvents() };
5207
+ return {
5208
+ kind: "route",
5209
+ // 同一个 assistant.tool_calls batch 必须为每个 call 产出 tool_output。
5210
+ // 出错时也继续消费剩余 call,ToolNode.run 会在本节点内 drain 完 batch 再回 LLM。
5211
+ nextNodeId: remainingCalls.length > 0 ? "tool" : "llm",
5212
+ events: context.bridge.getRuntimeEvents()
5213
+ };
5190
5214
  }
5191
5215
  };
5192
5216
 
@@ -5923,18 +5947,18 @@ function createClassification(category, reason, suggestedDelay, extras) {
5923
5947
  }
5924
5948
  var ErrorClassifier = class {
5925
5949
  static classify(error, context) {
5926
- const isRecord24 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
5950
+ const isRecord25 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
5927
5951
  const baseMsg = (error.message || "").toLowerCase();
5928
5952
  const causeMsg = (() => {
5929
5953
  const cause = error.cause;
5930
5954
  if (typeof cause === "string") return cause.toLowerCase();
5931
5955
  if (cause instanceof Error) return (cause.message || "").toLowerCase();
5932
- if (isRecord24(cause) && typeof cause["message"] === "string") return String(cause["message"]).toLowerCase();
5956
+ if (isRecord25(cause) && typeof cause["message"] === "string") return String(cause["message"]).toLowerCase();
5933
5957
  return "";
5934
5958
  })();
5935
5959
  const causeCode = (() => {
5936
5960
  const cause = error.cause;
5937
- if (isRecord24(cause) && typeof cause["code"] === "string") return String(cause["code"]);
5961
+ if (isRecord25(cause) && typeof cause["code"] === "string") return String(cause["code"]);
5938
5962
  return "";
5939
5963
  })();
5940
5964
  const errorMessage = `${baseMsg} ${causeMsg}`.trim();
@@ -6426,6 +6450,9 @@ __export(llm_exports, {
6426
6450
  LLMPolicyEngine: () => LLMPolicyEngine,
6427
6451
  LlmCaller: () => LlmCaller,
6428
6452
  ModelResolver: () => ModelResolver,
6453
+ appendStreamingProviderReasoningDetails: () => appendStreamingProviderReasoningDetails,
6454
+ compactProviderReasoningDetails: () => compactProviderReasoningDetails,
6455
+ compactReasoningDetailsInValue: () => compactReasoningDetailsInValue,
6429
6456
  createDefaultTokenizerPort: () => createDefaultTokenizerPort,
6430
6457
  defaultPolicyEngine: () => defaultPolicyEngine
6431
6458
  });
@@ -6815,6 +6842,90 @@ function assertToolCallsHaveValidJsonArguments(toolCalls) {
6815
6842
  }
6816
6843
  }
6817
6844
 
6845
+ // src/runtime-kernel/llm/reasoning-details.ts
6846
+ var mergeableTextFields = ["reasoning_content"];
6847
+ function isRecord20(value) {
6848
+ return !!value && typeof value === "object" && !Array.isArray(value);
6849
+ }
6850
+ function findMergeableTextField(detail) {
6851
+ if (!isRecord20(detail)) return void 0;
6852
+ if (typeof detail.provider !== "string") return void 0;
6853
+ if (typeof detail.type !== "string") return void 0;
6854
+ for (const field of mergeableTextFields) {
6855
+ if (typeof detail[field] === "string") {
6856
+ return field;
6857
+ }
6858
+ }
6859
+ return void 0;
6860
+ }
6861
+ function hasOnlyStableTextDetailFields(detail, textField) {
6862
+ const allowedKeys = /* @__PURE__ */ new Set(["provider", "type", textField]);
6863
+ return Object.keys(detail).every((key) => allowedKeys.has(key));
6864
+ }
6865
+ function canMergeTextDetails(previous, incoming) {
6866
+ if (!isRecord20(previous) || !isRecord20(incoming)) return false;
6867
+ const previousField = findMergeableTextField(previous);
6868
+ const incomingField = findMergeableTextField(incoming);
6869
+ if (!previousField || previousField !== incomingField) return false;
6870
+ return previous.provider === incoming.provider && previous.type === incoming.type && hasOnlyStableTextDetailFields(previous, previousField) && hasOnlyStableTextDetailFields(incoming, incomingField);
6871
+ }
6872
+ function mergeStreamingText(previous, incoming) {
6873
+ if (!previous) return incoming;
6874
+ if (!incoming) return previous;
6875
+ if (incoming.startsWith(previous)) {
6876
+ return incoming;
6877
+ }
6878
+ if (previous.endsWith(incoming)) {
6879
+ return previous;
6880
+ }
6881
+ return `${previous}${incoming}`;
6882
+ }
6883
+ function appendStreamingProviderReasoningDetails(existing, incoming) {
6884
+ const next = [...existing];
6885
+ for (const detail of incoming) {
6886
+ const previous = next[next.length - 1];
6887
+ if (canMergeTextDetails(previous, detail)) {
6888
+ const textField = findMergeableTextField(previous);
6889
+ if (textField && isRecord20(detail)) {
6890
+ const mergedText = mergeStreamingText(String(previous[textField]), String(detail[textField]));
6891
+ if (mergedText === previous[textField]) {
6892
+ continue;
6893
+ }
6894
+ next[next.length - 1] = {
6895
+ ...previous,
6896
+ [textField]: mergedText
6897
+ };
6898
+ continue;
6899
+ }
6900
+ }
6901
+ next.push(detail);
6902
+ }
6903
+ return next;
6904
+ }
6905
+ function compactProviderReasoningDetails(reasoningDetails) {
6906
+ return appendStreamingProviderReasoningDetails([], reasoningDetails);
6907
+ }
6908
+ function compactReasoningDetailsInValue(value) {
6909
+ return compactValue(value);
6910
+ }
6911
+ function compactValue(value) {
6912
+ if (Array.isArray(value)) {
6913
+ return value.map((item) => compactValue(item));
6914
+ }
6915
+ if (!isRecord20(value)) {
6916
+ return value;
6917
+ }
6918
+ const compacted = {};
6919
+ for (const [key, childValue] of Object.entries(value)) {
6920
+ if (key === "reasoning_details" && Array.isArray(childValue)) {
6921
+ compacted[key] = compactProviderReasoningDetails(childValue);
6922
+ continue;
6923
+ }
6924
+ compacted[key] = compactValue(childValue);
6925
+ }
6926
+ return compacted;
6927
+ }
6928
+
6818
6929
  // src/runtime-kernel/llm/streaming-adapter.ts
6819
6930
  async function callLlmStream(params) {
6820
6931
  const {
@@ -6827,7 +6938,7 @@ async function callLlmStream(params) {
6827
6938
  } = params;
6828
6939
  let fullResponse = "";
6829
6940
  let streamError = null;
6830
- const reasoningDetails = [];
6941
+ let reasoningDetails = [];
6831
6942
  const streamAnswerId = generateMessageId();
6832
6943
  let streamChunkSeq = 0;
6833
6944
  let capturedUsage = void 0;
@@ -6897,13 +7008,21 @@ async function callLlmStream(params) {
6897
7008
  const reasoning = isRecord19(chunk) ? chunk["reasoning_details"] : void 0;
6898
7009
  if (reasoning !== void 0) {
6899
7010
  const newReasoningDetails = Array.isArray(reasoning) ? reasoning : [reasoning];
6900
- reasoningDetails.push(...newReasoningDetails);
6901
- eventHandler({
6902
- type: "provider_sidecar",
6903
- id: generateMessageId(),
6904
- timestamp: Date.now(),
6905
- reasoning_details: newReasoningDetails
6906
- });
7011
+ const previousReasoningDetails = reasoningDetails;
7012
+ const previousLength = previousReasoningDetails.length;
7013
+ const compactedReasoningDetails = appendStreamingProviderReasoningDetails(reasoningDetails, newReasoningDetails);
7014
+ reasoningDetails = compactedReasoningDetails;
7015
+ const previousLastChanged = previousLength > 0 && compactedReasoningDetails[previousLength - 1] !== previousReasoningDetails[previousLength - 1];
7016
+ const emitFromIndex = previousLastChanged ? previousLength - 1 : previousLength;
7017
+ const emittedReasoningDetails = compactedReasoningDetails.slice(Math.max(0, emitFromIndex));
7018
+ if (emittedReasoningDetails.length > 0) {
7019
+ eventHandler({
7020
+ type: "provider_sidecar",
7021
+ id: generateMessageId(),
7022
+ timestamp: Date.now(),
7023
+ reasoning_details: emittedReasoningDetails
7024
+ });
7025
+ }
6907
7026
  }
6908
7027
  if (chunk.tool_calls) {
6909
7028
  emitThoughtComplete(thoughtSegmenter.onBoundary());
@@ -7329,7 +7448,6 @@ var DefaultTokenizerPort = class {
7329
7448
  constructor(config = {}) {
7330
7449
  this.config = config;
7331
7450
  }
7332
- config;
7333
7451
  estimateText(text, _modelId) {
7334
7452
  return TokenCalculator.estimateTokens(text, {
7335
7453
  encoding: this.config.encoding,
@@ -7471,8 +7589,6 @@ var FinalAnswerCollector = class {
7471
7589
  this.conversationId = conversationId;
7472
7590
  this.turnId = turnId;
7473
7591
  }
7474
- conversationId;
7475
- turnId;
7476
7592
  answerId;
7477
7593
  chunks = [];
7478
7594
  chunkCount = 0;
@@ -7520,7 +7636,7 @@ var FinalAnswerCollector = class {
7520
7636
  };
7521
7637
 
7522
7638
  // src/runtime-kernel/child-runs/childRunTraceSink.ts
7523
- function isRecord20(v) {
7639
+ function isRecord21(v) {
7524
7640
  return !!v && typeof v === "object" && !Array.isArray(v);
7525
7641
  }
7526
7642
  function getString2(obj, key) {
@@ -7553,7 +7669,7 @@ function createChildRunTraceSink(params) {
7553
7669
  const { publisher, conversationId, turnId } = params;
7554
7670
  const finalAnswerCollector = new FinalAnswerCollector(conversationId, turnId);
7555
7671
  const sink = (evt) => {
7556
- if (!isRecord20(evt)) {
7672
+ if (!isRecord21(evt)) {
7557
7673
  return [];
7558
7674
  }
7559
7675
  const type = getString2(evt, "type");
@@ -8222,7 +8338,7 @@ function runRecordToMeta(record) {
8222
8338
  errorIfAny: record.errorIfAny ? { ...record.errorIfAny } : void 0
8223
8339
  };
8224
8340
  }
8225
- function isRecord21(value) {
8341
+ function isRecord22(value) {
8226
8342
  return typeof value === "object" && value !== null && !Array.isArray(value);
8227
8343
  }
8228
8344
  function readStringField(record, key) {
@@ -8243,7 +8359,7 @@ function getRunIdFromMetadata(event) {
8243
8359
  return snakeCaseRunId;
8244
8360
  }
8245
8361
  const runContext = metadata["run_context"];
8246
- if (isRecord21(runContext)) {
8362
+ if (isRecord22(runContext)) {
8247
8363
  return readStringField(runContext, "runId") ?? readStringField(runContext, "run_id");
8248
8364
  }
8249
8365
  return void 0;
@@ -8461,7 +8577,7 @@ function runMetaFromRecord(record) {
8461
8577
  }
8462
8578
 
8463
8579
  // src/runtime-kernel/run-supervisor/runSupervisor.ts
8464
- function isRecord22(value) {
8580
+ function isRecord23(value) {
8465
8581
  return typeof value === "object" && value !== null && !Array.isArray(value);
8466
8582
  }
8467
8583
  function readStringField2(record, key) {
@@ -8478,7 +8594,7 @@ function readRunIdFromRuntimeEvent(event) {
8478
8594
  return directRunId;
8479
8595
  }
8480
8596
  const runContext = metadata["run_context"];
8481
- if (!isRecord22(runContext)) {
8597
+ if (!isRecord23(runContext)) {
8482
8598
  return void 0;
8483
8599
  }
8484
8600
  return readStringField2(runContext, "runId") ?? readStringField2(runContext, "run_id");
@@ -8490,7 +8606,7 @@ function readAwaitingUserReason(event) {
8490
8606
  if (typeof event.prompt === "string" && event.prompt.trim().length > 0) {
8491
8607
  return event.prompt;
8492
8608
  }
8493
- if (isRecord22(event.form)) {
8609
+ if (isRecord23(event.form)) {
8494
8610
  const prompt = readStringField2(event.form, "prompt");
8495
8611
  if (prompt && prompt.trim().length > 0) {
8496
8612
  return prompt;
@@ -9372,7 +9488,7 @@ function createQuickstartTelemetryPort(collector) {
9372
9488
  }
9373
9489
 
9374
9490
  // src/quickstart/runAgent.ts
9375
- function isRecord23(value) {
9491
+ function isRecord24(value) {
9376
9492
  return typeof value === "object" && value !== null && !Array.isArray(value);
9377
9493
  }
9378
9494
  function readString4(value) {
@@ -9386,7 +9502,7 @@ function resolveModelId(agent, options) {
9386
9502
  return modelId;
9387
9503
  }
9388
9504
  function isQuickstartStreamChunkEvent(value) {
9389
- return isRecord23(value) && value.type === "stream_chunk" && typeof value.content === "string";
9505
+ return isRecord24(value) && value.type === "stream_chunk" && typeof value.content === "string";
9390
9506
  }
9391
9507
  function createNoopObservationPreview() {
9392
9508
  return {
@@ -9426,7 +9542,7 @@ function readFinalAnswer(events, checkpointLocal) {
9426
9542
  if (chunks.length > 0) {
9427
9543
  return chunks.join("");
9428
9544
  }
9429
- if (isRecord23(checkpointLocal)) {
9545
+ if (isRecord24(checkpointLocal)) {
9430
9546
  const finalAnswer = checkpointLocal["finalAnswer"];
9431
9547
  if (typeof finalAnswer === "string") {
9432
9548
  return finalAnswer;
@@ -9435,7 +9551,7 @@ function readFinalAnswer(events, checkpointLocal) {
9435
9551
  return "";
9436
9552
  }
9437
9553
  function readContextTrace(checkpointLocal) {
9438
- if (!isRecord23(checkpointLocal)) return void 0;
9554
+ if (!isRecord24(checkpointLocal)) return void 0;
9439
9555
  return checkpointLocal["contextTrace"];
9440
9556
  }
9441
9557
  async function emitRunEvent(event, sink) {