@librechat/agents 3.3.4 → 3.3.6
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/cjs/common/constants.cjs +21 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/events.cjs +10 -1
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +456 -7
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/hooks/HookRegistry.cjs +25 -0
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
- package/dist/cjs/hooks/index.cjs +12 -0
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +1 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +8 -0
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +1 -3
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +268 -3
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +51 -6
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/preempt.cjs +132 -0
- package/dist/cjs/llm/preempt.cjs.map +1 -0
- package/dist/cjs/main.cjs +31 -3
- package/dist/cjs/messages/alternation.cjs +92 -0
- package/dist/cjs/messages/alternation.cjs.map +1 -0
- package/dist/cjs/messages/format.cjs +72 -0
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/handoffCue.cjs +63 -0
- package/dist/cjs/messages/handoffCue.cjs.map +1 -0
- package/dist/cjs/messages/index.cjs +3 -0
- package/dist/cjs/messages/injected.cjs +60 -0
- package/dist/cjs/messages/injected.cjs.map +1 -0
- package/dist/cjs/run.cjs +80 -7
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
- package/dist/cjs/session/handlers.cjs +18 -9
- package/dist/cjs/session/handlers.cjs.map +1 -1
- package/dist/cjs/stream.cjs +34 -8
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +3 -1
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -0
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +19 -16
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +2 -0
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ReadFile.cjs +8 -4
- package/dist/cjs/tools/ReadFile.cjs.map +1 -1
- package/dist/cjs/tools/SkillTool.cjs +2 -0
- package/dist/cjs/tools/SkillTool.cjs.map +1 -1
- package/dist/cjs/tools/SubagentTool.cjs +3 -0
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +91 -50
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +5 -1
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/intentArg.cjs +230 -0
- package/dist/cjs/tools/intentArg.cjs.map +1 -0
- package/dist/cjs/tools/local/CompileCheckTool.cjs +3 -2
- package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +13 -12
- package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +2 -2
- package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-scraper.cjs +90 -0
- package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -0
- package/dist/cjs/tools/search/schema.cjs +2 -0
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +40 -2
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/toolOutputReferences.cjs +41 -7
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/esm/common/constants.mjs +19 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/events.mjs +10 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +455 -6
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/hooks/HookRegistry.mjs +25 -0
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
- package/dist/esm/hooks/index.mjs +12 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +1 -0
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +9 -1
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +1 -3
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +270 -6
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +51 -6
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/preempt.mjs +131 -0
- package/dist/esm/llm/preempt.mjs.map +1 -0
- package/dist/esm/main.mjs +11 -7
- package/dist/esm/messages/alternation.mjs +91 -0
- package/dist/esm/messages/alternation.mjs.map +1 -0
- package/dist/esm/messages/format.mjs +72 -0
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/handoffCue.mjs +61 -0
- package/dist/esm/messages/handoffCue.mjs.map +1 -0
- package/dist/esm/messages/index.mjs +3 -0
- package/dist/esm/messages/injected.mjs +60 -0
- package/dist/esm/messages/injected.mjs.map +1 -0
- package/dist/esm/run.mjs +80 -7
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +1 -1
- package/dist/esm/session/handlers.mjs +19 -10
- package/dist/esm/session/handlers.mjs.map +1 -1
- package/dist/esm/stream.mjs +33 -9
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +3 -1
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -0
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +19 -16
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +2 -0
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ReadFile.mjs +8 -4
- package/dist/esm/tools/ReadFile.mjs.map +1 -1
- package/dist/esm/tools/SkillTool.mjs +2 -0
- package/dist/esm/tools/SkillTool.mjs.map +1 -1
- package/dist/esm/tools/SubagentTool.mjs +3 -0
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +91 -51
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +5 -1
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/intentArg.mjs +220 -0
- package/dist/esm/tools/intentArg.mjs.map +1 -0
- package/dist/esm/tools/local/CompileCheckTool.mjs +3 -2
- package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +13 -12
- package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +2 -2
- package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-scraper.mjs +88 -0
- package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -0
- package/dist/esm/tools/search/schema.mjs +2 -0
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +40 -3
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/toolOutputReferences.mjs +41 -7
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/types/common/constants.d.ts +18 -0
- package/dist/types/graphs/Graph.d.ts +138 -1
- package/dist/types/hooks/HookRegistry.d.ts +15 -0
- package/dist/types/hooks/index.d.ts +12 -1
- package/dist/types/hooks/types.d.ts +45 -6
- package/dist/types/index.d.ts +2 -1
- package/dist/types/llm/invoke.d.ts +7 -0
- package/dist/types/llm/openai/index.d.ts +0 -11
- package/dist/types/llm/preempt.d.ts +40 -0
- package/dist/types/messages/alternation.d.ts +23 -0
- package/dist/types/messages/handoffCue.d.ts +40 -0
- package/dist/types/messages/index.d.ts +3 -0
- package/dist/types/messages/injected.d.ts +3 -0
- package/dist/types/run.d.ts +7 -0
- package/dist/types/stream.d.ts +14 -0
- package/dist/types/tools/BashExecutor.d.ts +18 -0
- package/dist/types/tools/CodeExecutor.d.ts +18 -0
- package/dist/types/tools/ReadFile.d.ts +18 -0
- package/dist/types/tools/SkillTool.d.ts +18 -0
- package/dist/types/tools/SubagentTool.d.ts +9 -0
- package/dist/types/tools/ToolNode.d.ts +37 -12
- package/dist/types/tools/ToolSearch.d.ts +18 -0
- package/dist/types/tools/intentArg.d.ts +119 -0
- package/dist/types/tools/ptcTimeout.d.ts +2 -0
- package/dist/types/tools/search/keenable-scraper.d.ts +15 -0
- package/dist/types/tools/search/schema.d.ts +18 -0
- package/dist/types/tools/search/tool.d.ts +18 -0
- package/dist/types/tools/search/types.d.ts +31 -2
- package/dist/types/tools/toolOutputReferences.d.ts +12 -2
- package/dist/types/types/graph.d.ts +8 -1
- package/dist/types/types/run.d.ts +65 -0
- package/dist/types/types/stream.d.ts +12 -25
- package/dist/types/types/tools.d.ts +27 -2
- package/package.json +1 -1
- package/src/{splitStream.test.ts → aggregator.test.ts} +59 -666
- package/src/common/constants.ts +21 -0
- package/src/events.ts +15 -1
- package/src/graphs/Graph.ts +568 -3
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +18 -7
- package/src/graphs/__tests__/Graph.preemptSignal.test.ts +126 -0
- package/src/hooks/HookRegistry.ts +40 -0
- package/src/hooks/__tests__/preemptBoundary.test.ts +152 -0
- package/src/hooks/index.ts +16 -2
- package/src/hooks/types.ts +47 -3
- package/src/index.ts +2 -1
- package/src/langfuse.ts +26 -1
- package/src/llm/bedrock/utils/message_inputs.test.ts +82 -0
- package/src/llm/bedrock/utils/message_inputs.ts +14 -11
- package/src/llm/bedrock/utils/toolResultCachePoint.test.ts +15 -0
- package/src/llm/invoke.alternation.test.ts +87 -0
- package/src/llm/invoke.handoffCue.test.ts +112 -0
- package/src/llm/invoke.ts +417 -8
- package/src/llm/openai/index.ts +74 -10
- package/src/llm/openai/llm.spec.ts +105 -0
- package/src/llm/preempt.test.ts +323 -0
- package/src/llm/preempt.ts +178 -0
- package/src/messages/alternation.test.ts +212 -0
- package/src/messages/alternation.ts +112 -0
- package/src/messages/format.ts +91 -0
- package/src/messages/formatAgentMessages.steer.test.ts +267 -0
- package/src/messages/handoffCue.test.ts +96 -0
- package/src/messages/handoffCue.ts +78 -0
- package/src/messages/index.ts +3 -0
- package/src/messages/injected.test.ts +90 -0
- package/src/messages/injected.ts +74 -0
- package/src/run.ts +91 -6
- package/src/scripts/preempt-probe.ts +330 -0
- package/src/scripts/preempt-scenarios.ts +388 -0
- package/src/session/handlers.ts +32 -12
- package/src/specs/handoffCue.test.ts +165 -0
- package/src/specs/langfuse-callbacks.test.ts +352 -2
- package/src/specs/preemptSeal.test.ts +309 -0
- package/src/stream.dispatch.test.ts +63 -0
- package/src/stream.ts +48 -9
- package/src/tools/BashExecutor.ts +6 -0
- package/src/tools/BashProgrammaticToolCalling.ts +2 -0
- package/src/tools/CodeExecutor.ts +6 -0
- package/src/tools/ProgrammaticToolCalling.ts +2 -0
- package/src/tools/ReadFile.ts +2 -0
- package/src/tools/SkillTool.ts +2 -0
- package/src/tools/SubagentTool.ts +3 -0
- package/src/tools/ToolNode.ts +193 -74
- package/src/tools/ToolSearch.ts +3 -0
- package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +174 -0
- package/src/tools/__tests__/intentArg.test.ts +281 -0
- package/src/tools/__tests__/intentCoverage.test.ts +139 -0
- package/src/tools/__tests__/toolOutputReferences.test.ts +83 -0
- package/src/tools/intentArg.ts +323 -0
- package/src/tools/local/CompileCheckTool.ts +4 -3
- package/src/tools/local/LocalCodingTools.ts +14 -13
- package/src/tools/ptcTimeout.ts +2 -0
- package/src/tools/search/keenable-scraper.test.ts +153 -0
- package/src/tools/search/keenable-scraper.ts +137 -0
- package/src/tools/search/outcome.test.ts +90 -0
- package/src/tools/search/schema.ts +3 -0
- package/src/tools/search/tool.ts +60 -3
- package/src/tools/search/types.ts +50 -3
- package/src/tools/subagent/SubagentExecutor.ts +2 -1
- package/src/tools/toolOutputReferences.ts +77 -9
- package/src/types/graph.ts +12 -1
- package/src/types/run.ts +67 -0
- package/src/types/stream.ts +12 -41
- package/src/types/tools.ts +24 -2
- package/dist/cjs/splitStream.cjs +0 -151
- package/dist/cjs/splitStream.cjs.map +0 -1
- package/dist/esm/splitStream.mjs +0 -150
- package/dist/esm/splitStream.mjs.map +0 -1
- package/dist/types/mockStream.d.ts +0 -32
- package/dist/types/splitStream.d.ts +0 -37
- package/src/mockStream.ts +0 -99
- package/src/splitStream.ts +0 -234
package/src/tools/ToolNode.ts
CHANGED
|
@@ -31,6 +31,7 @@ import type {
|
|
|
31
31
|
PreResolvedArgsMap,
|
|
32
32
|
ResolvedArgsByCallId,
|
|
33
33
|
ResolveResult,
|
|
34
|
+
ResolveOptions,
|
|
34
35
|
} from '@/tools/toolOutputReferences';
|
|
35
36
|
import type {
|
|
36
37
|
HookRegistry,
|
|
@@ -47,6 +48,13 @@ import {
|
|
|
47
48
|
serializeStructuredValueBounded,
|
|
48
49
|
serializeToolContentBounded,
|
|
49
50
|
} from '@/utils/toolContent';
|
|
51
|
+
import {
|
|
52
|
+
INTENT_ARG,
|
|
53
|
+
readOutcomeFields,
|
|
54
|
+
resolveToolOutcome,
|
|
55
|
+
isIntentLabelProperty,
|
|
56
|
+
outcomeFieldsFromResult,
|
|
57
|
+
} from '@/tools/intentArg';
|
|
50
58
|
import {
|
|
51
59
|
buildToolExecutionRequestPlan,
|
|
52
60
|
resolveRuntimeSessionHint,
|
|
@@ -70,7 +78,7 @@ import {
|
|
|
70
78
|
} from '@/tools/local';
|
|
71
79
|
import { stripCodeSessionFileSummary } from '@/tools/CodeSessionFileSummary';
|
|
72
80
|
import { Constants, GraphEvents, CODE_EXECUTION_TOOLS } from '@/common';
|
|
73
|
-
import {
|
|
81
|
+
import { convertInjectedMessages } from '@/messages/injected';
|
|
74
82
|
import { safeDispatchCustomEvent } from '@/utils/events';
|
|
75
83
|
import { RunnableCallable } from '@/utils';
|
|
76
84
|
import { executeHooks } from '@/hooks';
|
|
@@ -126,8 +134,37 @@ type RunToolBatchContext<T = unknown> = {
|
|
|
126
134
|
* which relies on `node:async_hooks` and is browser-incompatible).
|
|
127
135
|
*/
|
|
128
136
|
runInput?: T;
|
|
137
|
+
/** Batch-local error-completion ownership (see {@link ToolErrorOwnership}). */
|
|
138
|
+
errorOwnership?: ToolErrorOwnership;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Batch-local record of who owns each failed call's completion event.
|
|
143
|
+
*
|
|
144
|
+
* Kept per invocation rather than on the instance: tool-call ids are
|
|
145
|
+
* provider-scoped (and synthetic ids can repeat), so concurrent `run()`s on
|
|
146
|
+
* one ToolNode would otherwise share and cross-consume these markers — one
|
|
147
|
+
* invocation's thrown-error marker suppressing another's only completion,
|
|
148
|
+
* or leaving a stale marker behind when an interrupt aborts a batch before
|
|
149
|
+
* the output loop reads it.
|
|
150
|
+
*
|
|
151
|
+
* - `handlerOwned`: the errorHandler ran and dispatched (or threw — a throw
|
|
152
|
+
* is not proof it didn't dispatch). The output loop must skip these.
|
|
153
|
+
* - `undispatched`: the handler explicitly reported it could NOT dispatch,
|
|
154
|
+
* so the output loop owns the completion instead.
|
|
155
|
+
*
|
|
156
|
+
* A call in NEITHER set returned an error `ToolMessage` without ever
|
|
157
|
+
* entering the catch path, so the output loop owns it too.
|
|
158
|
+
*/
|
|
159
|
+
export type ToolErrorOwnership = {
|
|
160
|
+
handlerOwned: Set<string>;
|
|
161
|
+
undispatched: Set<string>;
|
|
129
162
|
};
|
|
130
163
|
|
|
164
|
+
export function createToolErrorOwnership(): ToolErrorOwnership {
|
|
165
|
+
return { handlerOwned: new Set(), undispatched: new Set() };
|
|
166
|
+
}
|
|
167
|
+
|
|
131
168
|
type BoundedToolOutput = {
|
|
132
169
|
content: string;
|
|
133
170
|
registryContent: string;
|
|
@@ -499,12 +536,13 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
499
536
|
toolCallStepIds?: Map<string, string>;
|
|
500
537
|
errorHandler?: t.ToolNodeConstructorParams['errorHandler'];
|
|
501
538
|
/**
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
539
|
+
* Fallback error-completion ownership for calls that reach `runTool`
|
|
540
|
+
* outside a batch context (direct `runTool` use in tests / embedders).
|
|
541
|
+
* Batch-scoped ownership is threaded via `RunToolBatchContext` instead —
|
|
542
|
+
* see {@link ToolErrorOwnership} for why per-invocation scoping matters.
|
|
506
543
|
*/
|
|
507
|
-
private
|
|
544
|
+
private looseErrorOwnership: ToolErrorOwnership =
|
|
545
|
+
createToolErrorOwnership();
|
|
508
546
|
private toolUsageCount: Map<string, number>;
|
|
509
547
|
/** Maps toolCallId → turn captured in runTool, used by handleRunToolCompletions */
|
|
510
548
|
private toolCallTurns: Map<string, number> = new Map();
|
|
@@ -952,14 +990,17 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
952
990
|
args: T
|
|
953
991
|
) => ResolveResult<T>;
|
|
954
992
|
let resolveFn: ResolveFn | undefined;
|
|
993
|
+
const resolveOptions = {
|
|
994
|
+
substituteIntentKey: this.toolDeclaresBusinessIntent(call.name),
|
|
995
|
+
};
|
|
955
996
|
if (preBatchSnapshot != null) {
|
|
956
997
|
resolveFn = <T>(_runId: string | undefined, args: T): ResolveResult<T> =>
|
|
957
|
-
preBatchSnapshot.resolve(args);
|
|
998
|
+
preBatchSnapshot.resolve(args, resolveOptions);
|
|
958
999
|
} else if (registry != null) {
|
|
959
1000
|
resolveFn = <T>(
|
|
960
1001
|
runIdArg: string | undefined,
|
|
961
1002
|
args: T
|
|
962
|
-
): ResolveResult<T> => registry.resolve(runIdArg, args);
|
|
1003
|
+
): ResolveResult<T> => registry.resolve(runIdArg, args, resolveOptions);
|
|
963
1004
|
}
|
|
964
1005
|
/**
|
|
965
1006
|
* Precompute the reference key once per call — captured locally
|
|
@@ -1266,15 +1307,21 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1266
1307
|
},
|
|
1267
1308
|
config.metadata
|
|
1268
1309
|
);
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1310
|
+
const ownership =
|
|
1311
|
+
batchContext.errorOwnership ?? this.looseErrorOwnership;
|
|
1312
|
+
if (call.id != null && call.id !== '') {
|
|
1313
|
+
if (dispatched === false) {
|
|
1314
|
+
/**
|
|
1315
|
+
* The handler could not dispatch the error completion (typically
|
|
1316
|
+
* a resume pass, where a fast-failing tool errors before the
|
|
1317
|
+
* step replay registers its run step). Remember the call so the
|
|
1318
|
+
* output loop dispatches the completion itself instead of
|
|
1319
|
+
* assuming the handler covered it.
|
|
1320
|
+
*/
|
|
1321
|
+
ownership.undispatched.add(call.id);
|
|
1322
|
+
} else {
|
|
1323
|
+
ownership.handlerOwned.add(call.id);
|
|
1324
|
+
}
|
|
1278
1325
|
}
|
|
1279
1326
|
} catch (handlerError) {
|
|
1280
1327
|
// A THROWN handler is not proof the completion wasn't dispatched: the
|
|
@@ -1284,6 +1331,11 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1284
1331
|
// fallback loop re-emit a duplicate completion — only an explicit
|
|
1285
1332
|
// `false` return (handled above) means "nothing dispatched"; a throw
|
|
1286
1333
|
// is just logged.
|
|
1334
|
+
if (call.id != null && call.id !== '') {
|
|
1335
|
+
(
|
|
1336
|
+
batchContext.errorOwnership ?? this.looseErrorOwnership
|
|
1337
|
+
).handlerOwned.add(call.id);
|
|
1338
|
+
}
|
|
1287
1339
|
// eslint-disable-next-line no-console
|
|
1288
1340
|
console.error('Error in errorHandler:', {
|
|
1289
1341
|
toolName: call.name,
|
|
@@ -1448,13 +1500,20 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1448
1500
|
// (later-awaited) `runTool` will actually run with — both are
|
|
1449
1501
|
// anchored to the pre-batch registry state.
|
|
1450
1502
|
let resolvedArgs = call.args as Record<string, unknown>;
|
|
1503
|
+
const hookResolveOptions = {
|
|
1504
|
+
substituteIntentKey: this.toolDeclaresBusinessIntent(call.name),
|
|
1505
|
+
};
|
|
1451
1506
|
if (batchContext.preBatchSnapshot != null) {
|
|
1452
|
-
const { resolved } = batchContext.preBatchSnapshot.resolve(
|
|
1507
|
+
const { resolved } = batchContext.preBatchSnapshot.resolve(
|
|
1508
|
+
call.args,
|
|
1509
|
+
hookResolveOptions
|
|
1510
|
+
);
|
|
1453
1511
|
resolvedArgs = resolved as Record<string, unknown>;
|
|
1454
1512
|
} else if (this.toolOutputRegistry != null) {
|
|
1455
1513
|
const { resolved } = this.toolOutputRegistry.resolve(
|
|
1456
1514
|
registryRunId,
|
|
1457
|
-
call.args
|
|
1515
|
+
call.args,
|
|
1516
|
+
hookResolveOptions
|
|
1458
1517
|
);
|
|
1459
1518
|
resolvedArgs = resolved as Record<string, unknown>;
|
|
1460
1519
|
}
|
|
@@ -1655,6 +1714,27 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1655
1714
|
}
|
|
1656
1715
|
}
|
|
1657
1716
|
|
|
1717
|
+
/**
|
|
1718
|
+
* A hook (`PreToolUse.updatedInput`) or HITL `edit` decision rewrote the
|
|
1719
|
+
* args: expose the EFFECTIVE args to downstream completion handling
|
|
1720
|
+
* (`handleRunToolCompletions` reads this sink), so the emitted
|
|
1721
|
+
* `tool_call.args` — and any intent/outcome label resolved from them —
|
|
1722
|
+
* reflect what the tool actually ran with. `runTool`'s own placeholder
|
|
1723
|
+
* substitution may overwrite this entry with the post-substitution args,
|
|
1724
|
+
* which is strictly more accurate.
|
|
1725
|
+
*/
|
|
1726
|
+
if (
|
|
1727
|
+
effectiveCall !== call &&
|
|
1728
|
+
batchContext.resolvedArgsByCallId != null &&
|
|
1729
|
+
call.id != null &&
|
|
1730
|
+
call.id !== ''
|
|
1731
|
+
) {
|
|
1732
|
+
batchContext.resolvedArgsByCallId.set(
|
|
1733
|
+
call.id,
|
|
1734
|
+
effectiveCall.args as Record<string, unknown>
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1658
1738
|
const output = await this.runTool(effectiveCall, config, {
|
|
1659
1739
|
...batchContext,
|
|
1660
1740
|
usageCount,
|
|
@@ -2008,8 +2088,10 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2008
2088
|
calls: ToolCall[],
|
|
2009
2089
|
outputs: (BaseMessage | Command)[],
|
|
2010
2090
|
config: RunnableConfig,
|
|
2011
|
-
resolvedArgsByCallId?: ResolvedArgsByCallId
|
|
2091
|
+
resolvedArgsByCallId?: ResolvedArgsByCallId,
|
|
2092
|
+
errorOwnership?: ToolErrorOwnership
|
|
2012
2093
|
): Promise<void> {
|
|
2094
|
+
const ownership = errorOwnership ?? this.looseErrorOwnership;
|
|
2013
2095
|
for (let i = 0; i < calls.length; i++) {
|
|
2014
2096
|
const call = calls[i];
|
|
2015
2097
|
const output = outputs[i];
|
|
@@ -2022,23 +2104,24 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2022
2104
|
const toolMessage = output as ToolMessage;
|
|
2023
2105
|
const toolCallId = call.id ?? '';
|
|
2024
2106
|
|
|
2025
|
-
// Skip error ToolMessages when errorHandler
|
|
2026
|
-
//
|
|
2027
|
-
//
|
|
2028
|
-
//
|
|
2029
|
-
//
|
|
2030
|
-
//
|
|
2107
|
+
// Skip error ToolMessages only when the errorHandler OWNS the completion —
|
|
2108
|
+
// it ran and dispatched (or threw) via handleToolCallErrorStatic, so
|
|
2109
|
+
// dispatching again here would double-dispatch. Two cases fall through:
|
|
2110
|
+
// - the handler reported it could NOT dispatch (no run step registered yet
|
|
2111
|
+
// at error time, e.g. a fast-failing tool on a resume pass); by now the
|
|
2112
|
+
// step replay has usually registered the id, so this loop's dispatch is
|
|
2113
|
+
// the only terminal event the client's tool-call part will ever get.
|
|
2114
|
+
// - the tool RETURNED an error ToolMessage rather than throwing, so the
|
|
2115
|
+
// catch path (and the handler with it) never ran at all.
|
|
2116
|
+
// Markers are CONSUMED: leaving one set would let a later re-entry (same
|
|
2117
|
+
// ToolNode re-executing the batch) take the wrong branch, and the sets
|
|
2118
|
+
// would grow unbounded across a long-lived graph's failing calls.
|
|
2031
2119
|
if (toolMessage.status === 'error' && this.errorHandler != null) {
|
|
2032
|
-
if (
|
|
2033
|
-
|
|
2034
|
-
// Leaving it set would let a later re-entry (same ToolNode instance
|
|
2035
|
-
// re-executing the batch, where the handler CAN dispatch) fall
|
|
2036
|
-
// through here too and double-dispatch — and the set would grow
|
|
2037
|
-
// unbounded across a long-lived graph's fast-failing calls.
|
|
2038
|
-
this.undispatchedToolErrors.delete(toolCallId);
|
|
2039
|
-
} else {
|
|
2120
|
+
if (ownership.handlerOwned.has(toolCallId)) {
|
|
2121
|
+
ownership.handlerOwned.delete(toolCallId);
|
|
2040
2122
|
continue;
|
|
2041
2123
|
}
|
|
2124
|
+
ownership.undispatched.delete(toolCallId);
|
|
2042
2125
|
}
|
|
2043
2126
|
|
|
2044
2127
|
if (this.sessions && this.participatesInCodeSession(call.name)) {
|
|
@@ -2079,6 +2162,13 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2079
2162
|
* the tool actually received rather than leaking the template.
|
|
2080
2163
|
*/
|
|
2081
2164
|
const effectiveArgs = resolvedArgsByCallId?.get(toolCallId) ?? call.args;
|
|
2165
|
+
/** Authored outcomes apply to failed calls too (“Search failed for…”);
|
|
2166
|
+
* without one, an error call simply stays unlabeled. */
|
|
2167
|
+
const outcome = resolveToolOutcome(
|
|
2168
|
+
effectiveArgs,
|
|
2169
|
+
readOutcomeFields(toolMessage.artifact),
|
|
2170
|
+
{ isError: toolMessage.status === 'error' }
|
|
2171
|
+
);
|
|
2082
2172
|
const tool_call: t.ProcessedToolCall = {
|
|
2083
2173
|
args: serializeToolContentBounded(
|
|
2084
2174
|
(effectiveArgs as unknown) ?? {},
|
|
@@ -2088,6 +2178,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2088
2178
|
id: toolCallId,
|
|
2089
2179
|
output: contentString,
|
|
2090
2180
|
progress: 1,
|
|
2181
|
+
...(outcome != null && { outcome }),
|
|
2091
2182
|
};
|
|
2092
2183
|
|
|
2093
2184
|
await safeDispatchCustomEvent(
|
|
@@ -2165,7 +2256,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2165
2256
|
} else if (registry != null) {
|
|
2166
2257
|
const { resolved, unresolved } = registry.resolve(
|
|
2167
2258
|
registryRunId,
|
|
2168
|
-
originalArgs
|
|
2259
|
+
originalArgs,
|
|
2260
|
+
{ substituteIntentKey: this.toolDeclaresBusinessIntent(call.name) }
|
|
2169
2261
|
);
|
|
2170
2262
|
resolvedArgs = resolved as Record<string, unknown>;
|
|
2171
2263
|
if (unresolved.length > 0 && call.id != null) {
|
|
@@ -2386,9 +2478,14 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2386
2478
|
): void => {
|
|
2387
2479
|
if (registry != null) {
|
|
2388
2480
|
const view: ToolOutputResolveView = preBatchSnapshot ?? {
|
|
2389
|
-
resolve: <T>(args: T) =>
|
|
2481
|
+
resolve: <T>(args: T, options?: ResolveOptions) =>
|
|
2482
|
+
registry.resolve(registryRunId, args, options),
|
|
2390
2483
|
};
|
|
2391
|
-
const { resolved, unresolved } = view.resolve(nextArgs
|
|
2484
|
+
const { resolved, unresolved } = view.resolve(nextArgs, {
|
|
2485
|
+
substituteIntentKey: this.toolDeclaresBusinessIntent(
|
|
2486
|
+
entry.call.name
|
|
2487
|
+
),
|
|
2488
|
+
});
|
|
2392
2489
|
entry.args = resolved as Record<string, unknown>;
|
|
2393
2490
|
if (entry.call.id != null) {
|
|
2394
2491
|
if (unresolved.length > 0) {
|
|
@@ -2934,7 +3031,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2934
3031
|
if (result.injectedMessages && result.injectedMessages.length > 0) {
|
|
2935
3032
|
try {
|
|
2936
3033
|
injected.push(
|
|
2937
|
-
...
|
|
3034
|
+
...convertInjectedMessages(result.injectedMessages)
|
|
2938
3035
|
);
|
|
2939
3036
|
} catch (e) {
|
|
2940
3037
|
// eslint-disable-next-line no-console
|
|
@@ -3120,7 +3217,10 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3120
3217
|
request?.args ?? {},
|
|
3121
3218
|
contentString,
|
|
3122
3219
|
config,
|
|
3123
|
-
request?.turn
|
|
3220
|
+
request?.turn,
|
|
3221
|
+
resolveToolOutcome(request?.args, outcomeFieldsFromResult(result), {
|
|
3222
|
+
isError: result.status === 'error',
|
|
3223
|
+
})
|
|
3124
3224
|
);
|
|
3125
3225
|
}
|
|
3126
3226
|
|
|
@@ -3344,7 +3444,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3344
3444
|
*/
|
|
3345
3445
|
if (hookInjectedMessages.length > 0) {
|
|
3346
3446
|
try {
|
|
3347
|
-
injected.push(...
|
|
3447
|
+
injected.push(...convertInjectedMessages(hookInjectedMessages));
|
|
3348
3448
|
} catch (e) {
|
|
3349
3449
|
// eslint-disable-next-line no-console
|
|
3350
3450
|
console.warn(
|
|
@@ -3355,13 +3455,43 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3355
3455
|
}
|
|
3356
3456
|
}
|
|
3357
3457
|
|
|
3458
|
+
/**
|
|
3459
|
+
* Whether `name`'s own schema declares a BUSINESS parameter called
|
|
3460
|
+
* `intent` (declared, and not the injected label contract — see
|
|
3461
|
+
* `isIntentLabelProperty`). Such a parameter must keep participating in
|
|
3462
|
+
* `{{tool…}}` placeholder substitution; only the display label is exempt.
|
|
3463
|
+
*/
|
|
3464
|
+
private toolDeclaresBusinessIntent(name: string): boolean {
|
|
3465
|
+
const instance = this.toolMap.get(name) as
|
|
3466
|
+
| {
|
|
3467
|
+
schema?: {
|
|
3468
|
+
shape?: Record<string, unknown>;
|
|
3469
|
+
properties?: Record<string, unknown>;
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
| undefined;
|
|
3473
|
+
const instanceProp =
|
|
3474
|
+
instance?.schema?.properties?.[INTENT_ARG] ??
|
|
3475
|
+
instance?.schema?.shape?.[INTENT_ARG];
|
|
3476
|
+
if (instanceProp != null) {
|
|
3477
|
+
return !isIntentLabelProperty(instanceProp);
|
|
3478
|
+
}
|
|
3479
|
+
const defProp =
|
|
3480
|
+
this.toolRegistry?.get(name)?.parameters?.properties?.[INTENT_ARG];
|
|
3481
|
+
if (defProp != null) {
|
|
3482
|
+
return !isIntentLabelProperty(defProp);
|
|
3483
|
+
}
|
|
3484
|
+
return false;
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3358
3487
|
private async dispatchStepCompleted(
|
|
3359
3488
|
toolCallId: string,
|
|
3360
3489
|
toolName: string,
|
|
3361
3490
|
args: Record<string, unknown>,
|
|
3362
3491
|
output: string,
|
|
3363
3492
|
config: RunnableConfig,
|
|
3364
|
-
turn?: number
|
|
3493
|
+
turn?: number,
|
|
3494
|
+
outcome?: string
|
|
3365
3495
|
): Promise<boolean> {
|
|
3366
3496
|
const stepId = this.toolCallStepIds?.get(toolCallId) ?? '';
|
|
3367
3497
|
if (!stepId) {
|
|
@@ -3386,6 +3516,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3386
3516
|
id: toolCallId,
|
|
3387
3517
|
output,
|
|
3388
3518
|
progress: 1,
|
|
3519
|
+
...(outcome != null && { outcome }),
|
|
3389
3520
|
} as t.ProcessedToolCall,
|
|
3390
3521
|
},
|
|
3391
3522
|
},
|
|
@@ -3422,38 +3553,13 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3422
3553
|
request.args,
|
|
3423
3554
|
output,
|
|
3424
3555
|
config,
|
|
3425
|
-
request.turn
|
|
3556
|
+
request.turn,
|
|
3557
|
+
resolveToolOutcome(request.args, outcomeFieldsFromResult(result), {
|
|
3558
|
+
isError: result.status === 'error',
|
|
3559
|
+
})
|
|
3426
3560
|
);
|
|
3427
3561
|
}
|
|
3428
3562
|
|
|
3429
|
-
/**
|
|
3430
|
-
* Converts InjectedMessage instances to LangChain HumanMessage objects.
|
|
3431
|
-
* Both 'user' and 'system' roles become HumanMessage to avoid provider
|
|
3432
|
-
* rejections (Anthropic/Google reject non-leading SystemMessages).
|
|
3433
|
-
* The original role is preserved in additional_kwargs for downstream consumers.
|
|
3434
|
-
*/
|
|
3435
|
-
private convertInjectedMessages(
|
|
3436
|
-
messages: t.InjectedMessage[]
|
|
3437
|
-
): BaseMessage[] {
|
|
3438
|
-
const converted: BaseMessage[] = [];
|
|
3439
|
-
for (const msg of messages) {
|
|
3440
|
-
const additional_kwargs: Record<string, unknown> = {
|
|
3441
|
-
role: msg.role,
|
|
3442
|
-
};
|
|
3443
|
-
if (msg.isMeta != null) additional_kwargs.isMeta = msg.isMeta;
|
|
3444
|
-
if (msg.source != null) additional_kwargs.source = msg.source;
|
|
3445
|
-
if (msg.skillName != null) additional_kwargs.skillName = msg.skillName;
|
|
3446
|
-
|
|
3447
|
-
converted.push(
|
|
3448
|
-
new HumanMessage({
|
|
3449
|
-
content: toLangChainContent(msg.content),
|
|
3450
|
-
additional_kwargs,
|
|
3451
|
-
})
|
|
3452
|
-
);
|
|
3453
|
-
}
|
|
3454
|
-
return converted;
|
|
3455
|
-
}
|
|
3456
|
-
|
|
3457
3563
|
/**
|
|
3458
3564
|
* Execute a group of direct (in-process) tool calls with interrupt-safe
|
|
3459
3565
|
* ordering, returning outputs aligned 1:1 with `directCalls`.
|
|
@@ -3578,6 +3684,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3578
3684
|
* ToolNode cannot read or wipe each other's entries.
|
|
3579
3685
|
*/
|
|
3580
3686
|
const resolvedArgsByCallId = new Map<string, Record<string, unknown>>();
|
|
3687
|
+
/** Per-invocation error-completion ownership — see `ToolErrorOwnership`. */
|
|
3688
|
+
const errorOwnership = createToolErrorOwnership();
|
|
3581
3689
|
/**
|
|
3582
3690
|
* Claim this batch's turn synchronously from the registry (or
|
|
3583
3691
|
* fall back to 0 when the feature is disabled). The registry is
|
|
@@ -3623,6 +3731,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3623
3731
|
turn,
|
|
3624
3732
|
batchScopeId,
|
|
3625
3733
|
resolvedArgsByCallId,
|
|
3734
|
+
errorOwnership,
|
|
3626
3735
|
additionalContextsSink: directAdditionalContexts,
|
|
3627
3736
|
runInput: sendState as T,
|
|
3628
3737
|
}
|
|
@@ -3646,7 +3755,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3646
3755
|
// HumanMessage isn't a tool result.
|
|
3647
3756
|
[sendOutput],
|
|
3648
3757
|
config,
|
|
3649
|
-
resolvedArgsByCallId
|
|
3758
|
+
resolvedArgsByCallId,
|
|
3759
|
+
errorOwnership
|
|
3650
3760
|
);
|
|
3651
3761
|
} else {
|
|
3652
3762
|
let messages: BaseMessage[];
|
|
@@ -3771,7 +3881,12 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3771
3881
|
for (const entry of eventEntries) {
|
|
3772
3882
|
if (entry.call.id != null) {
|
|
3773
3883
|
const { resolved, unresolved } = preBatchSnapshot.resolve(
|
|
3774
|
-
entry.call.args as Record<string, unknown
|
|
3884
|
+
entry.call.args as Record<string, unknown>,
|
|
3885
|
+
{
|
|
3886
|
+
substituteIntentKey: this.toolDeclaresBusinessIntent(
|
|
3887
|
+
entry.call.name
|
|
3888
|
+
),
|
|
3889
|
+
}
|
|
3775
3890
|
);
|
|
3776
3891
|
preResolvedEventArgs.set(entry.call.id, {
|
|
3777
3892
|
resolved: resolved as Record<string, unknown>,
|
|
@@ -3796,6 +3911,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3796
3911
|
turn,
|
|
3797
3912
|
batchScopeId,
|
|
3798
3913
|
resolvedArgsByCallId,
|
|
3914
|
+
errorOwnership,
|
|
3799
3915
|
preBatchSnapshot,
|
|
3800
3916
|
additionalContextsSink: directAdditionalContexts,
|
|
3801
3917
|
runInput: input as T,
|
|
@@ -3808,7 +3924,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3808
3924
|
directCalls,
|
|
3809
3925
|
directOutputs,
|
|
3810
3926
|
config,
|
|
3811
|
-
resolvedArgsByCallId
|
|
3927
|
+
resolvedArgsByCallId,
|
|
3928
|
+
errorOwnership
|
|
3812
3929
|
);
|
|
3813
3930
|
}
|
|
3814
3931
|
|
|
@@ -3861,6 +3978,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3861
3978
|
turn,
|
|
3862
3979
|
batchScopeId,
|
|
3863
3980
|
resolvedArgsByCallId,
|
|
3981
|
+
errorOwnership,
|
|
3864
3982
|
preBatchSnapshot,
|
|
3865
3983
|
additionalContextsSink: directAdditionalContexts,
|
|
3866
3984
|
runInput: input as T,
|
|
@@ -3870,7 +3988,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3870
3988
|
filteredCalls,
|
|
3871
3989
|
toolOutputs,
|
|
3872
3990
|
config,
|
|
3873
|
-
resolvedArgsByCallId
|
|
3991
|
+
resolvedArgsByCallId,
|
|
3992
|
+
errorOwnership
|
|
3874
3993
|
);
|
|
3875
3994
|
// Append accumulated additionalContexts as a single
|
|
3876
3995
|
// HumanMessage so the next model turn sees them. Codex P2 #39.
|
package/src/tools/ToolSearch.ts
CHANGED
|
@@ -24,6 +24,7 @@ import fetch, { RequestInit } from 'node-fetch';
|
|
|
24
24
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
25
25
|
import { tool, DynamicStructuredTool } from '@langchain/core/tools';
|
|
26
26
|
import type * as t from '@/types';
|
|
27
|
+
import { INTENT_PROPERTY } from '@/tools/intentArg';
|
|
27
28
|
import { getCodeBaseURL } from './CodeExecutor';
|
|
28
29
|
import { Constants } from '@/common';
|
|
29
30
|
|
|
@@ -51,6 +52,7 @@ const MCP_SERVER_DESCRIPTION =
|
|
|
51
52
|
export const ToolSearchToolSchema = {
|
|
52
53
|
type: 'object',
|
|
53
54
|
properties: {
|
|
55
|
+
intent: { ...INTENT_PROPERTY },
|
|
54
56
|
query: {
|
|
55
57
|
type: 'string',
|
|
56
58
|
maxLength: MAX_PATTERN_LENGTH,
|
|
@@ -117,6 +119,7 @@ function createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {
|
|
|
117
119
|
return {
|
|
118
120
|
type: 'object',
|
|
119
121
|
properties: {
|
|
122
|
+
intent: { ...INTENT_PROPERTY },
|
|
120
123
|
query: {
|
|
121
124
|
type: 'string',
|
|
122
125
|
maxLength: MAX_PATTERN_LENGTH,
|