@silmaril-security/sdk 0.7.10 → 0.8.1

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.
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/adapters/langchain.ts
31
31
  var langchain_exports = {};
32
32
  __export(langchain_exports, {
33
- createLangChainHandler: () => createLangChainHandler
33
+ createLangChainHandler: () => createLangChainHandler,
34
+ protectLangChainRunnable: () => protectLangChainRunnable
34
35
  });
35
36
  module.exports = __toCommonJS(langchain_exports);
36
37
 
@@ -184,7 +185,81 @@ function extractTextFromDocuments(documents) {
184
185
  return parts.join("\n");
185
186
  }
186
187
 
188
+ // src/adapters/thread-identity.ts
189
+ function record(value) {
190
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
191
+ }
192
+ function validThreadId(value) {
193
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
194
+ }
195
+ function nativeThreadId(runtime, metadata, inherited, currentConfig) {
196
+ const explicit = record(record(runtime)?.configurable);
197
+ const current = record(record(currentConfig)?.configurable);
198
+ for (const candidate of [explicit, current, record(metadata)]) {
199
+ if (candidate && Object.prototype.hasOwnProperty.call(candidate, "thread_id")) {
200
+ return validThreadId(candidate.thread_id);
201
+ }
202
+ }
203
+ return inherited;
204
+ }
205
+ function rejectConversationOptions(options) {
206
+ if ("conversationId" in options || "conversation_id" in options) {
207
+ throw new TypeError("conversationId/conversation_id was removed. Pass the native configurable.thread_id when invoking the agent or runnable instead.");
208
+ }
209
+ }
210
+ var RunThreadIdentity = class {
211
+ constructor(boundIdentity, currentConfig = () => void 0) {
212
+ this.boundIdentity = boundIdentity;
213
+ this.currentConfig = currentConfig;
214
+ }
215
+ boundIdentity;
216
+ currentConfig;
217
+ runs = /* @__PURE__ */ new Map();
218
+ children = /* @__PURE__ */ new Map();
219
+ start(runId, parentRunId, metadata) {
220
+ const discarded = this.finish(runId);
221
+ if (this.runs.size >= 4096) {
222
+ const oldestRoot = [...this.runs].find(([, run]) => run.parentRunId === void 0 || !this.runs.has(run.parentRunId))?.[0] ?? this.runs.keys().next().value;
223
+ if (oldestRoot !== void 0) discarded.push(...this.finish(oldestRoot));
224
+ }
225
+ const inherited = parentRunId === void 0 ? void 0 : this.runs.get(parentRunId)?.threadId;
226
+ const exposed = record(metadata);
227
+ const threadId = this.boundIdentity && (parentRunId === void 0 || !this.runs.has(parentRunId)) ? this.boundIdentity.threadId : exposed && Object.prototype.hasOwnProperty.call(exposed, "thread_id") ? typeof exposed.langgraph_node === "string" ? nativeThreadId(void 0, exposed, inherited, this.currentConfig()) : validThreadId(exposed.thread_id) : inherited;
228
+ this.runs.set(runId, { threadId, parentRunId });
229
+ if (parentRunId !== void 0 && parentRunId !== runId) {
230
+ const children = this.children.get(parentRunId) ?? /* @__PURE__ */ new Set();
231
+ children.add(runId);
232
+ this.children.set(parentRunId, children);
233
+ }
234
+ return discarded;
235
+ }
236
+ get(runId) {
237
+ const run = this.runs.get(runId);
238
+ return run ? run.threadId : this.boundIdentity?.threadId;
239
+ }
240
+ finish(runId) {
241
+ const pending = [runId];
242
+ const seen = /* @__PURE__ */ new Set();
243
+ while (pending.length) {
244
+ const id = pending.pop();
245
+ if (seen.has(id)) continue;
246
+ seen.add(id);
247
+ pending.push(...this.children.get(id) ?? []);
248
+ this.children.delete(id);
249
+ const parent = this.runs.get(id)?.parentRunId;
250
+ this.runs.delete(id);
251
+ if (parent !== void 0) {
252
+ const siblings = this.children.get(parent);
253
+ siblings?.delete(id);
254
+ if (siblings?.size === 0) this.children.delete(parent);
255
+ }
256
+ }
257
+ return [...seen];
258
+ }
259
+ };
260
+
187
261
  // src/adapters/langchain.ts
262
+ var handlerCleanups = /* @__PURE__ */ new WeakMap();
188
263
  var USER_ROLES = /* @__PURE__ */ new Set(["human", "user"]);
189
264
  function getMessageRole(message) {
190
265
  if (typeof message.role === "string") {
@@ -193,7 +268,8 @@ function getMessageRole(message) {
193
268
  if (typeof message.type === "string") {
194
269
  return message.type.toLowerCase();
195
270
  }
196
- return "";
271
+ const legacyType = message.getType?.() ?? message._getType?.();
272
+ return typeof legacyType === "string" ? legacyType.toLowerCase() : "";
197
273
  }
198
274
  function extractMessageText(content) {
199
275
  if (content === void 0) {
@@ -222,7 +298,16 @@ function findLastUserMessage(messages) {
222
298
  return void 0;
223
299
  }
224
300
  async function createLangChainHandler(firewall, options = {}) {
225
- const { BaseCallbackHandler } = await import("@langchain/core/callbacks/base");
301
+ return buildLangChainHandler(firewall, options);
302
+ }
303
+ async function buildLangChainHandler(firewall, options, boundIdentity) {
304
+ rejectConversationOptions(options);
305
+ const { ensureConfig } = await import("@langchain/core/runnables");
306
+ const threads = new RunThreadIdentity(boundIdentity, () => ensureConfig());
307
+ const { BaseTracer } = await import("@langchain/core/tracers/base");
308
+ let finishRun = (runId) => {
309
+ threads.finish(runId);
310
+ };
226
311
  const enabledHooks = resolveHooks(options.hooks);
227
312
  const includeTool = options.includeTool ?? true;
228
313
  const failOpen = options.failOpen ?? true;
@@ -241,14 +326,14 @@ async function createLangChainHandler(firewall, options = {}) {
241
326
  logger("onClassify callback threw", err);
242
327
  }
243
328
  };
244
- const classify = async (text, hookLabel, runId, toolName) => {
329
+ const classifyEvent = async (text, hookLabel, runId, toolName) => {
245
330
  let result;
246
331
  try {
247
332
  result = await firewall.classify(text, {
248
333
  hook: hookLabel,
249
334
  metadata: {
250
335
  langgraph: { run_id: runId },
251
- ...options.conversationId === void 0 ? {} : { conversationId: options.conversationId }
336
+ ...threads.get(runId) === void 0 ? {} : { conversationId: threads.get(runId) }
252
337
  },
253
338
  ...requestedMode !== void 0 ? { mode: requestedMode } : {},
254
339
  ...toolName !== void 0 ? { toolName } : {}
@@ -292,98 +377,354 @@ async function createLangChainHandler(firewall, options = {}) {
292
377
  result
293
378
  });
294
379
  };
295
- class SilmarilFirewallHandler extends BaseCallbackHandler {
380
+ const classify = async (text, hook, runId, toolName) => {
381
+ try {
382
+ await classifyEvent(text, hook, runId, toolName);
383
+ } catch (error) {
384
+ finishRun(runId);
385
+ throw error;
386
+ }
387
+ };
388
+ function serialized(value, name) {
389
+ if (value && typeof value === "object" && "id" in value && Array.isArray(value.id)) return value;
390
+ return { lc: 1, type: "not_implemented", id: [name] };
391
+ }
392
+ class SilmarilFirewallHandler extends BaseTracer {
296
393
  name = "silmaril_firewall_handler";
297
394
  raiseError = true;
298
395
  awaitHandlers = true;
299
- async handleChatModelStart(_llm, messages, runId) {
300
- if (!enabledHooks.has(FirewallHook.CHAT_MODEL_START)) {
301
- return;
396
+ // LangChain clears runnable context inside ordinary callbacks. Its synchronous
397
+ // tracer pre-start hooks capture native config before that boundary. Runs are
398
+ // memory-only and every terminal path discards both native tracer maps.
399
+ async persistRun() {
400
+ }
401
+ getRunById(runId) {
402
+ return runId === void 0 ? void 0 : this.runMap.get(runId);
403
+ }
404
+ // Only lifecycle identity is needed. Do not retain prompts, outputs, token
405
+ // events, or completed children when upstream omits a cancellation callback.
406
+ _addRunToRunMap(run) {
407
+ return super._addRunToRunMap({
408
+ ...run,
409
+ inputs: {},
410
+ extra: {},
411
+ serialized: {},
412
+ tags: [],
413
+ child_runs: [],
414
+ events: []
415
+ });
416
+ }
417
+ _addChildRun() {
418
+ }
419
+ async _endTrace(run) {
420
+ try {
421
+ await super._endTrace(run);
422
+ } finally {
423
+ run.inputs = {};
424
+ delete run.outputs;
425
+ delete run.error;
426
+ run.extra = {};
427
+ run.events = [];
428
+ run.child_runs = [];
302
429
  }
303
- const batches = messages;
304
- const flat = [];
305
- for (const batch of batches) {
306
- for (const m of batch) {
307
- flat.push(m);
308
- }
430
+ }
431
+ async handleText() {
432
+ }
433
+ async handleAgentAction() {
434
+ }
435
+ async handleAgentEnd() {
436
+ }
437
+ async handleLLMNewToken(_token, _idx, runId) {
438
+ return this.getRunById(runId) ?? this._createRunForLLMStart(serialized(void 0, "llm"), [], runId);
439
+ }
440
+ capture(runId, parentRunId, metadata) {
441
+ for (const id of threads.start(runId, parentRunId, metadata)) {
442
+ this.runMap.delete(id);
443
+ this.runTreeMap?.delete(id);
309
444
  }
310
- const lastUser = findLastUserMessage(flat);
311
- if (!lastUser) {
312
- return;
445
+ }
446
+ finishAll() {
447
+ for (const id of [...this.runMap.keys()]) this.finishRun(id);
448
+ this.runTreeMap?.clear();
449
+ }
450
+ finishRun(runId) {
451
+ for (const id of threads.finish(runId)) {
452
+ this.runMap.delete(id);
453
+ this.runTreeMap?.delete(id);
313
454
  }
314
- const text = extractMessageText(lastUser.content).trim();
315
- if (!text) {
316
- return;
455
+ }
456
+ _createRunForLLMStart(...args) {
457
+ this.capture(args[2], args[3], args[6]);
458
+ return super._createRunForLLMStart(...args);
459
+ }
460
+ _createRunForChatModelStart(...args) {
461
+ this.capture(args[2], args[3], args[6]);
462
+ return super._createRunForChatModelStart(...args);
463
+ }
464
+ _createRunForChainStart(...args) {
465
+ this.capture(args[2], args[3], args[5]);
466
+ return super._createRunForChainStart(...args);
467
+ }
468
+ _createRunForToolStart(...args) {
469
+ this.capture(args[2], args[3], args[5]);
470
+ return super._createRunForToolStart(...args);
471
+ }
472
+ _createRunForRetrieverStart(...args) {
473
+ this.capture(args[2], args[3], args[5]);
474
+ return super._createRunForRetrieverStart(...args);
475
+ }
476
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata) {
477
+ const batches = messages;
478
+ const run = this.getRunById(runId) ?? this._createRunForChatModelStart(
479
+ serialized(llm, "chat_model"),
480
+ messages,
481
+ runId,
482
+ parentRunId,
483
+ extraParams,
484
+ tags,
485
+ metadata
486
+ );
487
+ if (enabledHooks.has(FirewallHook.CHAT_MODEL_START)) {
488
+ const lastUser = findLastUserMessage(batches.flat());
489
+ const text = lastUser ? extractMessageText(lastUser.content).trim() : "";
490
+ if (text) await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.CHAT_MODEL_START], runId);
317
491
  }
318
- await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.CHAT_MODEL_START], runId);
492
+ return run;
319
493
  }
320
- async handleLLMStart(_llm, prompts, runId) {
321
- if (!enabledHooks.has(FirewallHook.LLM_START)) {
322
- return;
494
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata) {
495
+ const run = this.getRunById(runId) ?? this._createRunForLLMStart(
496
+ serialized(llm, "llm"),
497
+ prompts,
498
+ runId,
499
+ parentRunId,
500
+ extraParams,
501
+ tags,
502
+ metadata
503
+ );
504
+ if (enabledHooks.has(FirewallHook.LLM_START)) {
505
+ const text = extractTextFromPrompts(prompts);
506
+ if (text) await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_START], runId);
323
507
  }
324
- const text = extractTextFromPrompts(prompts);
325
- if (!text) {
326
- return;
508
+ return run;
509
+ }
510
+ async handleToolStart(tool, inputStr, runId, parentRunId, tags, metadata) {
511
+ const run = this.getRunById(runId) ?? this._createRunForToolStart(
512
+ serialized(tool, tool?.name ?? "tool"),
513
+ inputStr,
514
+ runId,
515
+ parentRunId,
516
+ tags,
517
+ metadata
518
+ );
519
+ if (includeTool && enabledHooks.has(FirewallHook.TOOL_START)) {
520
+ const text = extractTextFromToolInput(inputStr);
521
+ if (text) await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_START], runId, tool?.name);
327
522
  }
328
- await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_START], runId);
523
+ return run;
329
524
  }
330
- async handleToolStart(tool, inputStr, runId) {
331
- if (!includeTool || !enabledHooks.has(FirewallHook.TOOL_START)) {
332
- return;
525
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata) {
526
+ const run = this.getRunById(runId) ?? this._createRunForRetrieverStart(
527
+ serialized(retriever, "retriever"),
528
+ query,
529
+ runId,
530
+ parentRunId,
531
+ tags,
532
+ metadata
533
+ );
534
+ if (enabledHooks.has(FirewallHook.RETRIEVER_START) && query.trim()) {
535
+ await classify(query.trim(), FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_START], runId);
333
536
  }
334
- const text = extractTextFromToolInput(inputStr);
335
- if (!text) {
336
- return;
537
+ return run;
538
+ }
539
+ async handleLLMEnd(output, runId) {
540
+ try {
541
+ if (!this.getRunById(runId)) this._createRunForLLMStart(serialized(void 0, "llm"), [], runId);
542
+ if (enabledHooks.has(FirewallHook.LLM_END)) {
543
+ const text = extractTextFromLLMResult(output);
544
+ if (text) await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_END], runId);
545
+ }
546
+ return await super.handleLLMEnd(output, runId);
547
+ } finally {
548
+ finishRun(runId);
337
549
  }
338
- const toolName = tool?.name;
339
- await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_START], runId, toolName);
340
550
  }
341
- async handleRetrieverStart(_retriever, query, runId) {
342
- if (!enabledHooks.has(FirewallHook.RETRIEVER_START)) {
343
- return;
551
+ async handleToolEnd(output, runId, _parentRunId, _tags, kwargs) {
552
+ try {
553
+ if (!this.getRunById(runId)) this._createRunForToolStart(serialized(void 0, "tool"), "", runId);
554
+ if (includeTool && enabledHooks.has(FirewallHook.TOOL_END)) {
555
+ const text = String(output).trim();
556
+ if (text) await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_END], runId, kwargs?.name);
557
+ }
558
+ return await super.handleToolEnd(output, runId);
559
+ } finally {
560
+ finishRun(runId);
344
561
  }
345
- const text = query.trim();
346
- if (!text) {
347
- return;
562
+ }
563
+ async handleRetrieverEnd(documents, runId) {
564
+ try {
565
+ if (!this.getRunById(runId)) this._createRunForRetrieverStart(serialized(void 0, "retriever"), "", runId);
566
+ if (enabledHooks.has(FirewallHook.RETRIEVER_END)) {
567
+ const text = extractTextFromDocuments(documents);
568
+ if (text) await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_END], runId);
569
+ }
570
+ return await super.handleRetrieverEnd(documents, runId);
571
+ } finally {
572
+ finishRun(runId);
348
573
  }
349
- await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_START], runId);
350
574
  }
351
- async handleLLMEnd(output, runId) {
352
- if (!enabledHooks.has(FirewallHook.LLM_END)) {
353
- return;
575
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, name) {
576
+ return super.handleChainStart(serialized(chain, "chain"), inputs, runId, parentRunId, tags, metadata, runType, name);
577
+ }
578
+ async handleChainEnd(...args) {
579
+ if (!this.getRunById(args[1])) this._createRunForChainStart(serialized(void 0, "chain"), {}, args[1]);
580
+ try {
581
+ return await super.handleChainEnd(...args);
582
+ } finally {
583
+ finishRun(args[1]);
354
584
  }
355
- const text = extractTextFromLLMResult(output);
356
- if (!text) {
357
- return;
585
+ }
586
+ async handleChainError(...args) {
587
+ if (!this.getRunById(args[1])) this._createRunForChainStart(serialized(void 0, "chain"), {}, args[1]);
588
+ try {
589
+ return await super.handleChainError(...args);
590
+ } finally {
591
+ finishRun(args[1]);
358
592
  }
359
- await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.LLM_END], runId);
360
593
  }
361
- async handleToolEnd(output, runId, _parentRunId, _tags, _kwargs) {
362
- if (!includeTool || !enabledHooks.has(FirewallHook.TOOL_END)) {
363
- return;
594
+ async handleLLMError(...args) {
595
+ if (!this.getRunById(args[1])) this._createRunForLLMStart(serialized(void 0, "llm"), [], args[1]);
596
+ try {
597
+ return await super.handleLLMError(...args);
598
+ } finally {
599
+ finishRun(args[1]);
364
600
  }
365
- const text = String(output).trim();
366
- if (!text) {
367
- return;
601
+ }
602
+ async handleToolError(...args) {
603
+ if (!this.getRunById(args[1])) this._createRunForToolStart(serialized(void 0, "tool"), "", args[1]);
604
+ try {
605
+ return await super.handleToolError(...args);
606
+ } finally {
607
+ finishRun(args[1]);
368
608
  }
369
- const toolName = _kwargs?.name;
370
- await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.TOOL_END], runId, toolName);
371
609
  }
372
- async handleRetrieverEnd(documents, runId) {
373
- if (!enabledHooks.has(FirewallHook.RETRIEVER_END)) {
374
- return;
610
+ async handleRetrieverError(...args) {
611
+ if (!this.getRunById(args[1])) this._createRunForRetrieverStart(serialized(void 0, "retriever"), "", args[1]);
612
+ try {
613
+ return await super.handleRetrieverError(...args);
614
+ } finally {
615
+ finishRun(args[1]);
375
616
  }
376
- const text = extractTextFromDocuments(documents);
377
- if (!text) {
378
- return;
617
+ }
618
+ }
619
+ const handler = new SilmarilFirewallHandler();
620
+ finishRun = (runId) => {
621
+ handler.finishRun(runId);
622
+ };
623
+ handlerCleanups.set(handler, () => handler.finishAll());
624
+ return handler;
625
+ }
626
+ async function protectLangChainRunnable(firewall, runnable, options = {}) {
627
+ rejectConversationOptions(options);
628
+ const { RunnableBinding, RunnableRetry, ensureConfig, mergeConfigs } = await import("@langchain/core/runnables");
629
+ const { IterableReadableStream } = await import("@langchain/core/utils/stream");
630
+ const configFactories = [async (config) => {
631
+ const effective = ensureConfig(config);
632
+ const handler = await buildLangChainHandler(firewall, options, {
633
+ threadId: validThreadId(effective.configurable?.thread_id)
634
+ });
635
+ return { callbacks: [handler] };
636
+ }];
637
+ class ProtectedBinding extends RunnableBinding {
638
+ async scopedConfig(...configs) {
639
+ const created = [];
640
+ const scopedFactories = configFactories.map((factory) => async (config2) => {
641
+ const update = await factory(config2);
642
+ if (Array.isArray(update.callbacks)) created.push(...update.callbacks);
643
+ return update;
644
+ });
645
+ const scoped = new RunnableBinding({ bound: this.bound, config: this.config, configFactories: scopedFactories });
646
+ const config = await scoped._mergeConfig(...configs);
647
+ return { config, dispose: () => {
648
+ for (const handler of created) handlerCleanups.get(handler)?.();
649
+ } };
650
+ }
651
+ async invoke(input, options2) {
652
+ const scoped = await this.scopedConfig(options2, this.kwargs);
653
+ try {
654
+ return await this.bound.invoke(input, scoped.config);
655
+ } finally {
656
+ scoped.dispose();
657
+ }
658
+ }
659
+ async stream(input, options2) {
660
+ const scoped = await this.scopedConfig(ensureConfig(options2), this.kwargs);
661
+ let upstream;
662
+ try {
663
+ upstream = await this.bound.stream(input, scoped.config);
664
+ } catch (error) {
665
+ scoped.dispose();
666
+ throw error;
379
667
  }
380
- await classify(text, FIREWALL_HOOK_TO_LABEL[FirewallHook.RETRIEVER_END], runId);
668
+ const managed = async function* () {
669
+ try {
670
+ yield* upstream;
671
+ } finally {
672
+ scoped.dispose();
673
+ }
674
+ };
675
+ return IterableReadableStream.fromAsyncGenerator(managed());
676
+ }
677
+ async *_streamIterator(input, options2) {
678
+ const stream = await this.stream(input, options2);
679
+ yield* stream;
680
+ }
681
+ withConfig(config) {
682
+ return new ProtectedBinding({ bound: this.bound, config: mergeConfigs(this.config, config), configFactories });
683
+ }
684
+ withListeners(fields) {
685
+ return new RunnableBinding({ bound: this, config: {} }).withListeners(fields);
686
+ }
687
+ withRetry(fields) {
688
+ return new RunnableRetry({
689
+ bound: this,
690
+ config: {},
691
+ ...fields?.stopAfterAttempt === void 0 ? {} : { maxAttemptNumber: fields.stopAfterAttempt },
692
+ ...fields?.onFailedAttempt === void 0 ? {} : { onFailedAttempt: fields.onFailedAttempt }
693
+ });
694
+ }
695
+ }
696
+ const bindings = /* @__PURE__ */ new Set();
697
+ const installBoundary = (candidate) => {
698
+ if (!RunnableBinding.isRunnableBinding(candidate)) {
699
+ return new ProtectedBinding({ bound: candidate, config: {}, configFactories });
700
+ }
701
+ if (bindings.has(candidate)) throw new TypeError("Cannot protect cyclic runnable bindings");
702
+ bindings.add(candidate);
703
+ const binding = candidate;
704
+ const Binding = binding.constructor;
705
+ return new Binding({ ...binding, bound: installBoundary(binding.bound) });
706
+ };
707
+ class ComposableBinding extends RunnableBinding {
708
+ withConfig(config) {
709
+ return new ComposableBinding({ bound: this.bound, config: mergeConfigs(this.config, config) });
710
+ }
711
+ withListeners(fields) {
712
+ return new RunnableBinding({ bound: this, config: {} }).withListeners(fields);
713
+ }
714
+ withRetry(fields) {
715
+ return new RunnableRetry({
716
+ bound: this,
717
+ config: {},
718
+ ...fields?.stopAfterAttempt === void 0 ? {} : { maxAttemptNumber: fields.stopAfterAttempt },
719
+ ...fields?.onFailedAttempt === void 0 ? {} : { onFailedAttempt: fields.onFailedAttempt }
720
+ });
381
721
  }
382
722
  }
383
- return new SilmarilFirewallHandler();
723
+ return new ComposableBinding({ bound: installBoundary(runnable), config: {} });
384
724
  }
385
725
  // Annotate the CommonJS export names for ESM import in node:
386
726
  0 && (module.exports = {
387
- createLangChainHandler
727
+ createLangChainHandler,
728
+ protectLangChainRunnable
388
729
  });
389
730
  //# sourceMappingURL=langchain.cjs.map