@librechat/agents 3.4.2 → 3.4.4

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.
Files changed (75) hide show
  1. package/dist/cjs/graphs/Graph.cjs +27 -14
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +1 -1
  4. package/dist/cjs/instrumentation.cjs +3 -3
  5. package/dist/cjs/langfuse.cjs +3 -3
  6. package/dist/cjs/langfuseRuntimeScope.cjs +1 -1
  7. package/dist/cjs/langfuseToolOutputTracing.cjs +2 -2
  8. package/dist/cjs/main.cjs +5 -1
  9. package/dist/cjs/messages/assistantPhase.cjs +59 -0
  10. package/dist/cjs/messages/assistantPhase.cjs.map +1 -0
  11. package/dist/cjs/messages/index.cjs +1 -0
  12. package/dist/cjs/prompts/activityLabel.cjs +76 -0
  13. package/dist/cjs/prompts/activityLabel.cjs.map +1 -1
  14. package/dist/cjs/run.cjs +200 -10
  15. package/dist/cjs/run.cjs.map +1 -1
  16. package/dist/cjs/session/AgentSession.cjs +1 -1
  17. package/dist/cjs/stream.cjs +45 -8
  18. package/dist/cjs/stream.cjs.map +1 -1
  19. package/dist/cjs/tools/ToolNode.cjs +3 -3
  20. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +81 -6
  21. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  22. package/dist/cjs/utils/callbacks.cjs +8 -0
  23. package/dist/cjs/utils/callbacks.cjs.map +1 -1
  24. package/dist/esm/graphs/Graph.mjs +27 -14
  25. package/dist/esm/graphs/Graph.mjs.map +1 -1
  26. package/dist/esm/graphs/MultiAgentGraph.mjs +1 -1
  27. package/dist/esm/instrumentation.mjs +3 -3
  28. package/dist/esm/langfuse.mjs +3 -3
  29. package/dist/esm/langfuseRuntimeScope.mjs +1 -1
  30. package/dist/esm/langfuseToolOutputTracing.mjs +2 -2
  31. package/dist/esm/main.mjs +3 -2
  32. package/dist/esm/messages/assistantPhase.mjs +57 -0
  33. package/dist/esm/messages/assistantPhase.mjs.map +1 -0
  34. package/dist/esm/messages/index.mjs +1 -0
  35. package/dist/esm/prompts/activityLabel.mjs +74 -1
  36. package/dist/esm/prompts/activityLabel.mjs.map +1 -1
  37. package/dist/esm/run.mjs +202 -12
  38. package/dist/esm/run.mjs.map +1 -1
  39. package/dist/esm/session/AgentSession.mjs +1 -1
  40. package/dist/esm/stream.mjs +45 -8
  41. package/dist/esm/stream.mjs.map +1 -1
  42. package/dist/esm/tools/ToolNode.mjs +3 -3
  43. package/dist/esm/tools/subagent/SubagentExecutor.mjs +81 -6
  44. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  45. package/dist/esm/utils/callbacks.mjs +8 -1
  46. package/dist/esm/utils/callbacks.mjs.map +1 -1
  47. package/dist/types/messages/assistantPhase.d.ts +22 -0
  48. package/dist/types/messages/index.d.ts +1 -0
  49. package/dist/types/prompts/activityLabel.d.ts +21 -1
  50. package/dist/types/run.d.ts +15 -2
  51. package/dist/types/types/activityLabel.d.ts +63 -0
  52. package/dist/types/types/assistantPhase.d.ts +6 -0
  53. package/dist/types/types/graph.d.ts +8 -1
  54. package/dist/types/types/index.d.ts +1 -0
  55. package/dist/types/types/stream.d.ts +11 -0
  56. package/dist/types/utils/callbacks.d.ts +1 -0
  57. package/package.json +3 -3
  58. package/src/graphs/Graph.ts +33 -9
  59. package/src/graphs/__tests__/Graph.reasoning.test.ts +57 -0
  60. package/src/messages/assistantPhase.test.ts +75 -0
  61. package/src/messages/assistantPhase.ts +91 -0
  62. package/src/messages/index.ts +1 -0
  63. package/src/prompts/activityLabel.ts +177 -1
  64. package/src/run.ts +403 -21
  65. package/src/specs/activity-label-prompt.test.ts +123 -1
  66. package/src/specs/activity-phase-label.test.ts +306 -0
  67. package/src/stream.ts +69 -12
  68. package/src/tools/__tests__/SubagentExecutor.test.ts +436 -0
  69. package/src/tools/subagent/SubagentExecutor.ts +160 -8
  70. package/src/types/activityLabel.ts +65 -0
  71. package/src/types/assistantPhase.ts +6 -0
  72. package/src/types/graph.ts +8 -0
  73. package/src/types/index.ts +1 -0
  74. package/src/types/stream.ts +9 -0
  75. package/src/utils/callbacks.ts +21 -0
@@ -4,8 +4,8 @@ import { HARD_MAX_TOOL_RESULT_CHARS } from "../utils/truncation.mjs";
4
4
  import { serializeToolContentBounded } from "../utils/toolContent.mjs";
5
5
  import { StandardGraph } from "./Graph.mjs";
6
6
  import { PromptTemplate } from "@langchain/core/prompts";
7
- import { AIMessage, HumanMessage, ToolMessage, getBufferString } from "@langchain/core/messages";
8
7
  import { Annotation, Command, END, START, StateGraph, messagesStateReducer } from "@langchain/langgraph";
8
+ import { AIMessage, HumanMessage, ToolMessage, getBufferString } from "@langchain/core/messages";
9
9
  import { tool } from "@langchain/core/tools";
10
10
  //#region src/graphs/MultiAgentGraph.ts
11
11
  /** Pattern to extract instructions from transfer ToolMessage content */
@@ -1,11 +1,11 @@
1
- import { traceIdFromSeed } from "./langfuseRuntimeContext.mjs";
2
1
  import { isPresent } from "./utils/misc.mjs";
2
+ import { traceIdFromSeed } from "./langfuseRuntimeContext.mjs";
3
3
  import { resolveLangfuseConfigForSpan, resolveTraceIdSeedForSpan } from "./langfuseRuntimeScope.mjs";
4
+ import { createLangfuseSpanProcessor } from "./langfuseToolOutputTracing.mjs";
4
5
  import { getLangfuseDestinationKey, getLangfuseSpanProcessorParams, registerLangfuseManagedSpan } from "./langfuseSpanRegistry.mjs";
5
6
  import { createLibreChatTraceAttributes } from "./langfuse.mjs";
6
- import { createLangfuseSpanProcessor } from "./langfuseToolOutputTracing.mjs";
7
- import { ROOT_CONTEXT, context, createContextKey } from "@opentelemetry/api";
8
7
  import { setLangfuseTracerProvider } from "@langfuse/tracing";
8
+ import { ROOT_CONTEXT, context, createContextKey } from "@opentelemetry/api";
9
9
  import { randomBytes } from "node:crypto";
10
10
  import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
11
11
  import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
@@ -2,12 +2,12 @@ import { isPresent, parseBooleanEnv } from "./utils/misc.mjs";
2
2
  import { hasLangfuseConfigCredentials, hasLangfuseEnvConfig, hasLangfuseEnvCredentials, resolveToolOutputTracingConfig } from "./langfuseConfig.mjs";
3
3
  import { resolveLangfuseConfigForSpan, resolveLangfuseScopeAgentId, resolveLangfuseScopeRunId, resolveTraceIdSeedForSpan, withLangfuseRuntimeScope } from "./langfuseRuntimeScope.mjs";
4
4
  import { getLangfuseManagedSpanDestination, resolveLangfuseDestinationKey } from "./langfuseSpanRegistry.mjs";
5
- import { AIMessage, AIMessageChunk } from "@langchain/core/messages";
6
5
  import { isGraphInterrupt, isParentCommand } from "@langchain/langgraph";
6
+ import { AIMessage, AIMessageChunk } from "@langchain/core/messages";
7
+ import { getLangfuseTracerProvider, propagateAttributes } from "@langfuse/tracing";
8
+ import { context, trace } from "@opentelemetry/api";
7
9
  import { CallbackHandler } from "@langfuse/langchain";
8
10
  import { LangfuseOtelContextKeys } from "@langfuse/core";
9
- import { context, trace } from "@opentelemetry/api";
10
- import { getLangfuseTracerProvider, propagateAttributes } from "@langfuse/tracing";
11
11
  //#region src/langfuse.ts
12
12
  const TRACE_METADATA_MAX_LENGTH = 200;
13
13
  const LANGFUSE_FORCE_FLUSH_ON_DISPOSE = "LANGFUSE_FORCE_FLUSH_ON_DISPOSE";
@@ -1,5 +1,5 @@
1
- import { getLangfuseRuntimeConfig, getLangfuseRuntimeToolOutputTracingConfig, getLangfuseScopeAgentId, getLangfuseScopeRunId, getTraceIdSeed, hasLangfuseRuntimeContextValue, replaceLangfuseRuntimeContext, runWithLangfuseRuntimeContext } from "./langfuseRuntimeContext.mjs";
2
1
  import { hasToolOutputTracingConfig, resolveLangfuseConfig, resolveToolOutputTracingConfig } from "./langfuseConfig.mjs";
2
+ import { getLangfuseRuntimeConfig, getLangfuseRuntimeToolOutputTracingConfig, getLangfuseScopeAgentId, getLangfuseScopeRunId, getTraceIdSeed, hasLangfuseRuntimeContextValue, replaceLangfuseRuntimeContext, runWithLangfuseRuntimeContext } from "./langfuseRuntimeContext.mjs";
3
3
  import { context, createContextKey } from "@opentelemetry/api";
4
4
  //#region src/langfuseRuntimeScope.ts
5
5
  const langfuseToolOutputTracingConfigKey = createContextKey("librechat.langfuse.tool-output-tracing");
@@ -1,8 +1,8 @@
1
1
  import { hasToolOutputTracingConfig, normalizeToolName, resolveLangfuseConfig, resolveToolOutputTracingConfig } from "./langfuseConfig.mjs";
2
- import { resolveToolOutputTracingConfigForSpan } from "./langfuseRuntimeScope.mjs";
3
2
  import { shapeLangfuseSpan, shouldDropLangfuseSpan } from "./langfuseTraceShaping.mjs";
4
- import { LangfuseOtelSpanAttributes } from "@langfuse/tracing";
3
+ import { resolveToolOutputTracingConfigForSpan } from "./langfuseRuntimeScope.mjs";
5
4
  import { LangfuseSpanProcessor } from "@langfuse/otel";
5
+ import { LangfuseOtelSpanAttributes } from "@langfuse/tracing";
6
6
  //#region src/langfuseToolOutputTracing.ts
7
7
  const LANGGRAPH_TOOL_NODE_PREFIX = "tools=";
8
8
  const SERVER_TOOL_RESULT_PREFIX = "{\"serverToolResult\":";
package/dist/esm/main.mjs CHANGED
@@ -20,12 +20,13 @@ import { coalesceAdjacentUserTurns, strictAlternationProviders } from "./message
20
20
  import { PREDECESSOR_HANDOFF_CUE, appendPredecessorHandoffCue, removePredecessorHandoffCue } from "./messages/handoffCue.mjs";
21
21
  import { REMOVE_ALL_MESSAGES, createRemoveAllMessage, messagesStateReducer } from "./messages/reducer.mjs";
22
22
  import { DEFAULT_RETAIN_RECENT_TURNS, splitAtRecencyBoundary } from "./messages/recency.mjs";
23
+ import { getAssistantTextPhase, getMessageCreationContentMetadata, splitAssistantTextContentByPhase } from "./messages/assistantPhase.mjs";
23
24
  import "./messages/index.mjs";
24
25
  import { joinKeys, resetIfNotEmpty } from "./utils/graph.mjs";
25
26
  import { isAnthropicLike, isGoogleLike, isOpenAILike } from "./utils/llm.mjs";
26
27
  import { resolveFetchProxyAgent, shouldBypassProxy } from "./utils/proxy.mjs";
27
- import { handleServerToolResult, handleToolCallChunks, handleToolCalls, toolResultTypes } from "./tools/handlers.mjs";
28
28
  import { DEFAULT_MAX_TOOL_CALL_ARG_BYTES, StreamLimitExceededError, resolveStreamLimits } from "./llm/streamLimits.mjs";
29
+ import { handleServerToolResult, handleToolCallChunks, handleToolCalls, toolResultTypes } from "./tools/handlers.mjs";
29
30
  import { INTENT_ARG, INTENT_DESCRIPTION, INTENT_LABEL_MARKER, INTENT_PROPERTY, applyOutcome, isIntentLabelProperty, outcomeFieldsFromResult, readIntent, readOutcomeFields, resolveToolOutcome, stripIntent, withIntent, withoutIntent } from "./tools/intentArg.mjs";
30
31
  import { ChatModelStreamHandler, SDK_STREAM_DISPATCH, createContentAggregator, dispatchesChatModelStream, getChunkContent } from "./stream.mjs";
31
32
  import { HandlerRegistry, LLMStreamHandler, ModelEndHandler, TestChatStreamHandler, TestLLMStreamHandler, ToolEndHandler, composeEventHandlers, createMetadataAggregator } from "./events.mjs";
@@ -108,4 +109,4 @@ import { Runnable, RunnableLambda, RunnableSequence } from "./langchain/runnable
108
109
  import { DynamicStructuredTool, StructuredTool, Tool, tool } from "./langchain/tools.mjs";
109
110
  import "./langchain/index.mjs";
110
111
  import { BaseCheckpointSaver, Command, INTERRUPT, MemorySaver, interrupt, isInterrupted } from "@langchain/langgraph";
111
- export { AIMessage, AIMessageChunk, ANTHROPIC_TOOL_TOKEN_MULTIPLIER, AgentSession, BASH_SHELL_GUIDANCE, BaseCheckpointSaver, BaseMessage, BaseMessageChunk, BashExecutionToolDefinition, BashExecutionToolDescription, BashExecutionToolName, BashExecutionToolSchema, BashProgrammaticToolCallingDefinition, BashProgrammaticToolCallingDescription, BashProgrammaticToolCallingName, BashProgrammaticToolCallingSchema, BashToolOutputReferencesGuide, CALIBRATION_RATIO_MAX, CALIBRATION_RATIO_MIN, CLOUDFLARE_BASH_CODING_TOOL_NAMES, CLOUDFLARE_CODING_TOOL_NAMES, CODE_API_AUTHORIZATION_ERROR_MESSAGE, CODE_API_EXECUTION_FAILED_ERROR_MESSAGE, CODE_API_INVALID_REQUEST_ERROR_MESSAGE, CODE_API_RATE_LIMITED_ERROR_MESSAGE, CODE_API_UNAVAILABLE_ERROR_MESSAGE, CODE_ARTIFACT_PATH_GUIDANCE, CODE_EXECUTION_TOOLS, Calculator, CalculatorSchema, CalculatorToolDefinition, CalculatorToolDescription, CalculatorToolName, Callback, ChatModelStreamHandler, ChatOpenRouter, CloudflareBashExecutionToolDescription, CloudflareCodeExecutionToolDescription, CodeApiRequestError, CodeExecutionToolDefinition, CodeExecutionToolDescription, CodeExecutionToolName, CodeExecutionToolSchema, Command, CommonEvents, CompileCheckToolName, Constants, ContentTypes, CustomChatMistralAI, CustomOpenAIClient, DATE_RANGE, DEFAULT_CONTEXT_PRUNING_SETTINGS, DEFAULT_COUNTRY_DESCRIPTION, DEFAULT_HOOK_TIMEOUT_MS, DEFAULT_MAX_SEALS, DEFAULT_MAX_TOOL_CALL_ARG_BYTES, DEFAULT_PROMPT_CACHE_TTL, DEFAULT_QUERY_DESCRIPTION, DEFAULT_RECURSION_LIMIT, DEFAULT_RESERVE_RATIO, DEFAULT_RETAIN_RECENT_TURNS, DEFAULT_STREAM_DELAY, DEFAULT_SUBAGENT_DESCRIPTION, DEFAULT_TOOL_TOKEN_MULTIPLIER, DynamicStructuredTool, EnvVar, FAILED_EXECUTION_FILE_REMINDER, FakeChatModel, Graph, GraphEvents, GraphNodeActions, GraphNodeKeys, HARD_MAX_TOOL_RESULT_CHARS, HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE, HOOK_EVENTS, HOOK_INJECTED_MESSAGES_CAPABLE, HOOK_PREEMPT_BOUNDARY_CAPABLE, HandlerRegistry, HookRegistry, HumanMessage, IMAGE_TOKEN_SAFETY_MARGIN, INTENT_ARG, INTENT_DESCRIPTION, INTENT_LABEL_MARKER, INTENT_PROPERTY, INTERRUPT, JsonlSessionStore, LLMStreamHandler, LOCAL_CODING_BUNDLE_NAMES, LOCAL_CODING_TOOL_NAMES, LOCAL_SPAWN_TIMEOUT_MS, LocalBashExecutionToolDescription, LocalCodeExecutionToolDescription, LocalEditFileToolName, LocalEditFileToolSchema, LocalFileCheckpointerImpl, LocalGlobSearchToolName, LocalGlobSearchToolSchema, LocalGrepSearchToolName, LocalGrepSearchToolSchema, LocalListDirectoryToolName, LocalListDirectoryToolSchema, LocalReadFileToolSchema, LocalWriteFileToolName, LocalWriteFileToolSchema, MAX_CACHE_SIZE, MAX_PATTERN_LENGTH, MemorySaver, ModelEndHandler, MultiAgentGraph, OPENAI_RESPONSES_REPLAY_POSITIONS_KEY, ORIGINAL_CONTENT_MAX_CHARS, PREDECESSOR_HANDOFF_CUE, PREEMPT_BOUNDARY_HOOK_TIMEOUT_MS, ProgrammaticToolCallingDefinition, ProgrammaticToolCallingDescription, ProgrammaticToolCallingName, ProgrammaticToolCallingSchema, PromptTemplate, Providers, REMOVE_ALL_MESSAGES, REPLY_PRIMER_TOKENS, ReadFileToolDefinition, ReadFileToolDescription, ReadFileToolName, ReadFileToolSchema, Run, Runnable, RunnableCallable, RunnableLambda, RunnableSequence, SDK_STREAM_DISPATCH, STATEFUL_BASH_NOTE, STATEFUL_ENV_NOTE, SessionManager, SkillToolDefinition, SkillToolDescription, SkillToolName, SkillToolSchema, StandardGraph, StatefulBashExecutionToolDescription, StatefulCodeExecutionToolDescription, StepTypes, StreamLimitExceededError, StructuredTool, SubagentExecutor, SubagentToolDefinition, SubagentToolDescription, SubagentToolName, SubagentToolSchema, SystemMessage, TMP_SCRATCH_OUTPUT_REMINDER, TOOL_APPROVAL_EXECUTION_SCOPE_CONFIG_KEY, TestChatStreamHandler, TestLLMStreamHandler, TitleMethod, TokenEncoderManager, Tool, ToolCallTypes, ToolEndHandler, ToolMessage, ToolNode, ToolSearchToolDefinition, ToolSearchToolDescription, ToolSearchToolName, ToolSearchToolSchema, UnsafeTokenMeasurementError, WebSearchToolDefinition, WebSearchToolDescription, WebSearchToolName, WebSearchToolSchema, _createBashProgramForTests, _resetLocalEngineWarningsForTests, _resetRipgrepCacheForTests, _resetSyntaxCheckProbeCacheForTests, _resetUnrecognizedTriggerWarnings, addBedrockCacheControl, addBedrockTailCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, addTailCacheControl, appendCodeSessionFileSummary, appendFailedExecutionFileReminder, appendPredecessorHandoffCue, appendTmpScratchReminder, applyContextPruning, applyEdit, applyOutcome, applyPreToolUseHooksForBridge, apportionTokenCounts, askUserQuestion, attemptInvoke, bashAstFindingsToErrors, buildAnthropicCacheControl, buildBashExecutionToolDescription, buildBashExecutionToolSchema, buildBedrockCachePoint, buildChildInputs, buildCodeApiExecutionErrorMessage, buildCodeApiHttpErrorMessage, buildCodeExecutionToolDescription, buildCodeExecutionToolSchema, buildSandboxRuntimeConfig, buildSubagentToolParams, calculateMaxToolCallInputChars, calculateMaxToolResultChars, calculateMaxTotalToolOutputSize, calculateTotalTokens, canSealPreempt, checkValidNumber, clampCalibrationRatio, classifyAttachment, clientExecTimeoutMs, clientFsTimeoutMs, cloneMessage, coalesceAdjacentUserTurns, composeAbortSignals, composeEventHandlers, computeAdaptivePieceSize, convertInjectedMessages, convertMessagesToContent, countNestedGroups, countrySchema, createAgentSession, createBashExecutionTool, createBashProgrammaticToolCallingSchema, createBashProgrammaticToolCallingTool, createCloudflareBashExecutionTool, createCloudflareBashProgrammaticToolCallingTool, createCloudflareBridgeRuntime, createCloudflareCodeExecutionTool, createCloudflareCodingToolBundle, createCloudflareCodingTools, createCloudflareExecutionTool, createCloudflareLocalExecutionConfig, createCloudflareProgrammaticToolCallingTool, createCloudflareWorkspaceFS, createCodeExecutionTool, createCompileCheckTool, createCompileCheckToolDefinition, createContentAggregator, createFakeStreamingLLM, createGraph, createHandlers, createLocalBashExecutionTool, createLocalBashProgrammaticToolCallingTool, createLocalCodeExecutionTool, createLocalCodingToolBundle, createLocalCodingToolDefinitions, createLocalCodingToolRegistry, createLocalCodingTools, createLocalEditFileTool, createLocalFileCheckpointer, createLocalGlobSearchTool, createLocalGrepSearchTool, createLocalListDirectoryTool, createLocalProgrammaticToolCallingTool, createLocalReadFileTool, createLocalWriteFileTool, createMetadataAggregator, createProgrammaticToolCallingSchema, createProgrammaticToolCallingTool, createPruneMessages, createRemoveAllMessage, createRunHandlers, createSchemaOnlyTool, createSchemaOnlyTools, createSearchTool, createSubagentToolDefinition, createTokenCounter, createToolErrorOwnership, createToolPolicyHook, createToolSearch, createWorkspacePolicyHook, dateSchema, decodeFile, defaultOmitOptions, deserializeMessage, dispatchesChatModelStream, emptyOutputMessage, encodeFile, encodingForModel, enforceOriginalContentCap, ensureThinkingBlockInMessages, escapeRegexSpecialChars, estimateAnthropicImageTokens, estimateDocumentBlockTokens, estimateImageBlockTokens, estimateOpenAIImageTokens, estimateTimedMediaBlockTokens, execWithClientTimeout, executeCloudflareBash, executeCloudflareCode, executeHooks, executeLocalBash, executeLocalBashWithArgs, executeLocalCode, executeParallelSearches, executeTools, extractErrorMessage, extractImageDimensions, extractMcpServerName, extractTextFromContent, extractToolDiscoveries, extractUsedBashToolNames, extractUsedToolNames, fetchSessionFiles, filterBashToolsByUsage, filterGraphSubagentResult, filterSubagentResult, filterToolsByUsage, findLastIndex, foldToolBlocksForToollessAgent, formatAgentMessages, formatAnthropicArtifactContent, formatAnthropicMessage, formatArtifactPayload, formatCloudflareOutput, formatCompletedResponse, formatContentStrings, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, formatServerListing, formatSkillCatalog, getAvailableMcpServers, getBaseToolName, getBufferString, getChatModelClass, getChunkContent, getCloudflareWorkspaceRoot, getCodeBaseURL, getContextOverflowInfo, getConverseOverrideMessage, getDeferredToolsListing, getLocalCwd, getLocalSessionId, getMaxOutputTokensKey, getMessageId, getMessagesWithinTokenLimit, getReadRoots, getSpawn, getTokenCountForMessage, getWorkspaceFS, getWorkspaceRoots, getWriteRoots, handleServerToolResult, handleToolCallChunks, handleToolCalls, hasNestedQuantifier, hasNestedQuantifiers, hasToolSearchInCurrentTurn, hasUnsafeStructuredSerialization, imageAttachmentContent, imagesSchema, initializeModel, interrupt, isAIMessage, isAnthropicLike, isBaseMessage, isContextOverflowError, isDangerousPattern, isFromAnyMcpServer, isFromMcpServer, isGoogleLike, isGraphSubagentConfig, isIntentLabelProperty, isInterrupted, isLegacyConvertible, isLikelyContextOverflowError, isOpenAILike, isPresent, isSyntheticProviderContextMessage, isThinkingEnabled, isToolMessage, isZodSchema, joinKeys, labelContentByAgent, locateEdit, makeIsDeferred, makeRequest, maskConsumedToolResults, matchesQuery, messagesStateReducer, modifyDeltaProperties, newsSchema, normalizeBashToolResultsForReplay, normalizeCodeApiRequestError, normalizeServerFilter, normalizeSubagentConfigEntries, normalizeSubagentConfigs, normalizeToBashIdentifier, normalizeToPythonIdentifier, outcomeFieldsFromResult, parseBooleanEnv, partitionAndMarkAnthropicToolCache, performLocalSearch, preFlightTruncateToolCallInputs, preFlightTruncateToolResults, projectAgentContextUsage, projectAnthropicArtifactContent, projectArtifactPayload, projectCacheControlledToolOutputsToText, projectComputerCallOutputsToText, projectOpenAIChatToolMessageContent, projectOpenAIResponsesToolMessageContent, projectOpenAIToolMessageContent, projectOpenRouterToolMessageContent, projectSingleTextToolOutputsToText, projectStructuredToolOutputsToText, projectToolCallInputs, projectToolStreamContentForProvider, querySchema, readIntent, readOutcomeFields, removePredecessorHandoffCue, repairOrphanedToolMessages, resetIfNotEmpty, resolveBedrockPromptCacheTtl, resolveCloudflareSandbox, resolveCodeApiAuthHeaders, resolveContextPruningSettings, resolveFetchProxyAgent, resolveLocalExecutionConfig, resolveLocalExecutionTools, resolveLocalToolRegistry, resolveLocalToolsForBinding, resolvePromptCacheTtl, resolveSearchOutcome, resolveStreamDelay, resolveStreamLimits, resolveSubagentConfigEntries, resolveSubagentConfigs, resolveToolOutcome, resolveWorkspacePath, resolveWorkspacePathSafe, runBashAstChecks, runPostEditSyntaxCheck, sanitizeOrphanToolBlocks, sanitizeRegex, serializeMessage, serializeToolCallInput, shellQuote, shiftIndexTokenCountMap, shouldBypassProxy, shouldTriggerSummarization, sleep, smoothStream, spawnLocalProcess, splitAtRecencyBoundary, strictAlternationProviders, stripAnthropicCacheControl, stripBedrockCacheControl, stripCodeSessionFileSummary, stripIntent, summarizeEvent, supportsBedrockToolCache, syncBudgetDerivedFields, toJsonSchema, tool, toolResultTypes, toolsCondition, truncateLocalOutput, truncateToolInput, truncateToolResultContent, tryFallbackProviders, unescapeObject, unwrapToolResponse, validateBashCommand, validateCloudflareBashCommand, videosSchema, withClientTimeout, withIntent, withMessageRole, withoutIntent };
112
+ export { AIMessage, AIMessageChunk, ANTHROPIC_TOOL_TOKEN_MULTIPLIER, AgentSession, BASH_SHELL_GUIDANCE, BaseCheckpointSaver, BaseMessage, BaseMessageChunk, BashExecutionToolDefinition, BashExecutionToolDescription, BashExecutionToolName, BashExecutionToolSchema, BashProgrammaticToolCallingDefinition, BashProgrammaticToolCallingDescription, BashProgrammaticToolCallingName, BashProgrammaticToolCallingSchema, BashToolOutputReferencesGuide, CALIBRATION_RATIO_MAX, CALIBRATION_RATIO_MIN, CLOUDFLARE_BASH_CODING_TOOL_NAMES, CLOUDFLARE_CODING_TOOL_NAMES, CODE_API_AUTHORIZATION_ERROR_MESSAGE, CODE_API_EXECUTION_FAILED_ERROR_MESSAGE, CODE_API_INVALID_REQUEST_ERROR_MESSAGE, CODE_API_RATE_LIMITED_ERROR_MESSAGE, CODE_API_UNAVAILABLE_ERROR_MESSAGE, CODE_ARTIFACT_PATH_GUIDANCE, CODE_EXECUTION_TOOLS, Calculator, CalculatorSchema, CalculatorToolDefinition, CalculatorToolDescription, CalculatorToolName, Callback, ChatModelStreamHandler, ChatOpenRouter, CloudflareBashExecutionToolDescription, CloudflareCodeExecutionToolDescription, CodeApiRequestError, CodeExecutionToolDefinition, CodeExecutionToolDescription, CodeExecutionToolName, CodeExecutionToolSchema, Command, CommonEvents, CompileCheckToolName, Constants, ContentTypes, CustomChatMistralAI, CustomOpenAIClient, DATE_RANGE, DEFAULT_CONTEXT_PRUNING_SETTINGS, DEFAULT_COUNTRY_DESCRIPTION, DEFAULT_HOOK_TIMEOUT_MS, DEFAULT_MAX_SEALS, DEFAULT_MAX_TOOL_CALL_ARG_BYTES, DEFAULT_PROMPT_CACHE_TTL, DEFAULT_QUERY_DESCRIPTION, DEFAULT_RECURSION_LIMIT, DEFAULT_RESERVE_RATIO, DEFAULT_RETAIN_RECENT_TURNS, DEFAULT_STREAM_DELAY, DEFAULT_SUBAGENT_DESCRIPTION, DEFAULT_TOOL_TOKEN_MULTIPLIER, DynamicStructuredTool, EnvVar, FAILED_EXECUTION_FILE_REMINDER, FakeChatModel, Graph, GraphEvents, GraphNodeActions, GraphNodeKeys, HARD_MAX_TOOL_RESULT_CHARS, HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE, HOOK_EVENTS, HOOK_INJECTED_MESSAGES_CAPABLE, HOOK_PREEMPT_BOUNDARY_CAPABLE, HandlerRegistry, HookRegistry, HumanMessage, IMAGE_TOKEN_SAFETY_MARGIN, INTENT_ARG, INTENT_DESCRIPTION, INTENT_LABEL_MARKER, INTENT_PROPERTY, INTERRUPT, JsonlSessionStore, LLMStreamHandler, LOCAL_CODING_BUNDLE_NAMES, LOCAL_CODING_TOOL_NAMES, LOCAL_SPAWN_TIMEOUT_MS, LocalBashExecutionToolDescription, LocalCodeExecutionToolDescription, LocalEditFileToolName, LocalEditFileToolSchema, LocalFileCheckpointerImpl, LocalGlobSearchToolName, LocalGlobSearchToolSchema, LocalGrepSearchToolName, LocalGrepSearchToolSchema, LocalListDirectoryToolName, LocalListDirectoryToolSchema, LocalReadFileToolSchema, LocalWriteFileToolName, LocalWriteFileToolSchema, MAX_CACHE_SIZE, MAX_PATTERN_LENGTH, MemorySaver, ModelEndHandler, MultiAgentGraph, OPENAI_RESPONSES_REPLAY_POSITIONS_KEY, ORIGINAL_CONTENT_MAX_CHARS, PREDECESSOR_HANDOFF_CUE, PREEMPT_BOUNDARY_HOOK_TIMEOUT_MS, ProgrammaticToolCallingDefinition, ProgrammaticToolCallingDescription, ProgrammaticToolCallingName, ProgrammaticToolCallingSchema, PromptTemplate, Providers, REMOVE_ALL_MESSAGES, REPLY_PRIMER_TOKENS, ReadFileToolDefinition, ReadFileToolDescription, ReadFileToolName, ReadFileToolSchema, Run, Runnable, RunnableCallable, RunnableLambda, RunnableSequence, SDK_STREAM_DISPATCH, STATEFUL_BASH_NOTE, STATEFUL_ENV_NOTE, SessionManager, SkillToolDefinition, SkillToolDescription, SkillToolName, SkillToolSchema, StandardGraph, StatefulBashExecutionToolDescription, StatefulCodeExecutionToolDescription, StepTypes, StreamLimitExceededError, StructuredTool, SubagentExecutor, SubagentToolDefinition, SubagentToolDescription, SubagentToolName, SubagentToolSchema, SystemMessage, TMP_SCRATCH_OUTPUT_REMINDER, TOOL_APPROVAL_EXECUTION_SCOPE_CONFIG_KEY, TestChatStreamHandler, TestLLMStreamHandler, TitleMethod, TokenEncoderManager, Tool, ToolCallTypes, ToolEndHandler, ToolMessage, ToolNode, ToolSearchToolDefinition, ToolSearchToolDescription, ToolSearchToolName, ToolSearchToolSchema, UnsafeTokenMeasurementError, WebSearchToolDefinition, WebSearchToolDescription, WebSearchToolName, WebSearchToolSchema, _createBashProgramForTests, _resetLocalEngineWarningsForTests, _resetRipgrepCacheForTests, _resetSyntaxCheckProbeCacheForTests, _resetUnrecognizedTriggerWarnings, addBedrockCacheControl, addBedrockTailCacheControl, addCacheControl, addCacheControlToStablePrefixMessages, addTailCacheControl, appendCodeSessionFileSummary, appendFailedExecutionFileReminder, appendPredecessorHandoffCue, appendTmpScratchReminder, applyContextPruning, applyEdit, applyOutcome, applyPreToolUseHooksForBridge, apportionTokenCounts, askUserQuestion, attemptInvoke, bashAstFindingsToErrors, buildAnthropicCacheControl, buildBashExecutionToolDescription, buildBashExecutionToolSchema, buildBedrockCachePoint, buildChildInputs, buildCodeApiExecutionErrorMessage, buildCodeApiHttpErrorMessage, buildCodeExecutionToolDescription, buildCodeExecutionToolSchema, buildSandboxRuntimeConfig, buildSubagentToolParams, calculateMaxToolCallInputChars, calculateMaxToolResultChars, calculateMaxTotalToolOutputSize, calculateTotalTokens, canSealPreempt, checkValidNumber, clampCalibrationRatio, classifyAttachment, clientExecTimeoutMs, clientFsTimeoutMs, cloneMessage, coalesceAdjacentUserTurns, composeAbortSignals, composeEventHandlers, computeAdaptivePieceSize, convertInjectedMessages, convertMessagesToContent, countNestedGroups, countrySchema, createAgentSession, createBashExecutionTool, createBashProgrammaticToolCallingSchema, createBashProgrammaticToolCallingTool, createCloudflareBashExecutionTool, createCloudflareBashProgrammaticToolCallingTool, createCloudflareBridgeRuntime, createCloudflareCodeExecutionTool, createCloudflareCodingToolBundle, createCloudflareCodingTools, createCloudflareExecutionTool, createCloudflareLocalExecutionConfig, createCloudflareProgrammaticToolCallingTool, createCloudflareWorkspaceFS, createCodeExecutionTool, createCompileCheckTool, createCompileCheckToolDefinition, createContentAggregator, createFakeStreamingLLM, createGraph, createHandlers, createLocalBashExecutionTool, createLocalBashProgrammaticToolCallingTool, createLocalCodeExecutionTool, createLocalCodingToolBundle, createLocalCodingToolDefinitions, createLocalCodingToolRegistry, createLocalCodingTools, createLocalEditFileTool, createLocalFileCheckpointer, createLocalGlobSearchTool, createLocalGrepSearchTool, createLocalListDirectoryTool, createLocalProgrammaticToolCallingTool, createLocalReadFileTool, createLocalWriteFileTool, createMetadataAggregator, createProgrammaticToolCallingSchema, createProgrammaticToolCallingTool, createPruneMessages, createRemoveAllMessage, createRunHandlers, createSchemaOnlyTool, createSchemaOnlyTools, createSearchTool, createSubagentToolDefinition, createTokenCounter, createToolErrorOwnership, createToolPolicyHook, createToolSearch, createWorkspacePolicyHook, dateSchema, decodeFile, defaultOmitOptions, deserializeMessage, dispatchesChatModelStream, emptyOutputMessage, encodeFile, encodingForModel, enforceOriginalContentCap, ensureThinkingBlockInMessages, escapeRegexSpecialChars, estimateAnthropicImageTokens, estimateDocumentBlockTokens, estimateImageBlockTokens, estimateOpenAIImageTokens, estimateTimedMediaBlockTokens, execWithClientTimeout, executeCloudflareBash, executeCloudflareCode, executeHooks, executeLocalBash, executeLocalBashWithArgs, executeLocalCode, executeParallelSearches, executeTools, extractErrorMessage, extractImageDimensions, extractMcpServerName, extractTextFromContent, extractToolDiscoveries, extractUsedBashToolNames, extractUsedToolNames, fetchSessionFiles, filterBashToolsByUsage, filterGraphSubagentResult, filterSubagentResult, filterToolsByUsage, findLastIndex, foldToolBlocksForToollessAgent, formatAgentMessages, formatAnthropicArtifactContent, formatAnthropicMessage, formatArtifactPayload, formatCloudflareOutput, formatCompletedResponse, formatContentStrings, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, formatServerListing, formatSkillCatalog, getAssistantTextPhase, getAvailableMcpServers, getBaseToolName, getBufferString, getChatModelClass, getChunkContent, getCloudflareWorkspaceRoot, getCodeBaseURL, getContextOverflowInfo, getConverseOverrideMessage, getDeferredToolsListing, getLocalCwd, getLocalSessionId, getMaxOutputTokensKey, getMessageCreationContentMetadata, getMessageId, getMessagesWithinTokenLimit, getReadRoots, getSpawn, getTokenCountForMessage, getWorkspaceFS, getWorkspaceRoots, getWriteRoots, handleServerToolResult, handleToolCallChunks, handleToolCalls, hasNestedQuantifier, hasNestedQuantifiers, hasToolSearchInCurrentTurn, hasUnsafeStructuredSerialization, imageAttachmentContent, imagesSchema, initializeModel, interrupt, isAIMessage, isAnthropicLike, isBaseMessage, isContextOverflowError, isDangerousPattern, isFromAnyMcpServer, isFromMcpServer, isGoogleLike, isGraphSubagentConfig, isIntentLabelProperty, isInterrupted, isLegacyConvertible, isLikelyContextOverflowError, isOpenAILike, isPresent, isSyntheticProviderContextMessage, isThinkingEnabled, isToolMessage, isZodSchema, joinKeys, labelContentByAgent, locateEdit, makeIsDeferred, makeRequest, maskConsumedToolResults, matchesQuery, messagesStateReducer, modifyDeltaProperties, newsSchema, normalizeBashToolResultsForReplay, normalizeCodeApiRequestError, normalizeServerFilter, normalizeSubagentConfigEntries, normalizeSubagentConfigs, normalizeToBashIdentifier, normalizeToPythonIdentifier, outcomeFieldsFromResult, parseBooleanEnv, partitionAndMarkAnthropicToolCache, performLocalSearch, preFlightTruncateToolCallInputs, preFlightTruncateToolResults, projectAgentContextUsage, projectAnthropicArtifactContent, projectArtifactPayload, projectCacheControlledToolOutputsToText, projectComputerCallOutputsToText, projectOpenAIChatToolMessageContent, projectOpenAIResponsesToolMessageContent, projectOpenAIToolMessageContent, projectOpenRouterToolMessageContent, projectSingleTextToolOutputsToText, projectStructuredToolOutputsToText, projectToolCallInputs, projectToolStreamContentForProvider, querySchema, readIntent, readOutcomeFields, removePredecessorHandoffCue, repairOrphanedToolMessages, resetIfNotEmpty, resolveBedrockPromptCacheTtl, resolveCloudflareSandbox, resolveCodeApiAuthHeaders, resolveContextPruningSettings, resolveFetchProxyAgent, resolveLocalExecutionConfig, resolveLocalExecutionTools, resolveLocalToolRegistry, resolveLocalToolsForBinding, resolvePromptCacheTtl, resolveSearchOutcome, resolveStreamDelay, resolveStreamLimits, resolveSubagentConfigEntries, resolveSubagentConfigs, resolveToolOutcome, resolveWorkspacePath, resolveWorkspacePathSafe, runBashAstChecks, runPostEditSyntaxCheck, sanitizeOrphanToolBlocks, sanitizeRegex, serializeMessage, serializeToolCallInput, shellQuote, shiftIndexTokenCountMap, shouldBypassProxy, shouldTriggerSummarization, sleep, smoothStream, spawnLocalProcess, splitAssistantTextContentByPhase, splitAtRecencyBoundary, strictAlternationProviders, stripAnthropicCacheControl, stripBedrockCacheControl, stripCodeSessionFileSummary, stripIntent, summarizeEvent, supportsBedrockToolCache, syncBudgetDerivedFields, toJsonSchema, tool, toolResultTypes, toolsCondition, truncateLocalOutput, truncateToolInput, truncateToolResultContent, tryFallbackProviders, unescapeObject, unwrapToolResponse, validateBashCommand, validateCloudflareBashCommand, videosSchema, withClientTimeout, withIntent, withMessageRole, withoutIntent };
@@ -0,0 +1,57 @@
1
+ import "../common/enum.mjs";
2
+ import "../common/index.mjs";
3
+ //#region src/messages/assistantPhase.ts
4
+ function toAssistantTextPhase(value) {
5
+ return value === "commentary" || value === "final_answer" ? value : void 0;
6
+ }
7
+ /** Reads both provider-native and LangChain standard-content phase fields. */
8
+ function getAssistantTextPhase(contentPart) {
9
+ return toAssistantTextPhase(contentPart.phase) ?? toAssistantTextPhase(contentPart.extras?.phase);
10
+ }
11
+ /**
12
+ * Keeps provider-authored text phases in distinct message-creation steps.
13
+ * Open Responses may return commentary and final-answer blocks in one chunk;
14
+ * collapsing the array into one step would assign the first block's phase to
15
+ * every block and hide the boundary that closes an activity phase.
16
+ */
17
+ function splitAssistantTextContentByPhase(content) {
18
+ const groups = [];
19
+ for (const contentPart of content) {
20
+ const phase = getAssistantTextPhase(contentPart);
21
+ const currentGroup = groups.at(-1);
22
+ if (currentGroup == null || getAssistantTextPhase(currentGroup[0]) !== phase) {
23
+ groups.push([contentPart]);
24
+ continue;
25
+ }
26
+ currentGroup.push(contentPart);
27
+ }
28
+ return groups;
29
+ }
30
+ function isTextPart(contentPart) {
31
+ return contentPart.type?.startsWith("text") ?? false;
32
+ }
33
+ function isReasoningPart(contentPart) {
34
+ return contentPart.type === "think" || (contentPart.type?.startsWith("thinking") ?? false) || (contentPart.type?.startsWith("reasoning") ?? false) || (contentPart.type?.startsWith("reasoning_content") ?? false) || contentPart.type === "redacted_thinking";
35
+ }
36
+ /**
37
+ * Derives additive message-creation metadata before a content delta is
38
+ * dispatched. The fallback covers string-only providers whose semantic lane
39
+ * is tracked by the stream handler rather than represented on a block.
40
+ */
41
+ function getMessageCreationContentMetadata(content, fallbackContentType) {
42
+ if (!Array.isArray(content)) return fallbackContentType == null ? {} : { content_type: fallbackContentType };
43
+ const textPart = content.find(isTextPart);
44
+ if (textPart != null) {
45
+ const phase = getAssistantTextPhase(textPart);
46
+ return {
47
+ content_type: "text",
48
+ ...phase == null ? {} : { phase }
49
+ };
50
+ }
51
+ if (content.some(isReasoningPart)) return { content_type: "think" };
52
+ return fallbackContentType == null ? {} : { content_type: fallbackContentType };
53
+ }
54
+ //#endregion
55
+ export { getAssistantTextPhase, getMessageCreationContentMetadata, splitAssistantTextContentByPhase };
56
+
57
+ //# sourceMappingURL=assistantPhase.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistantPhase.mjs","names":[],"sources":["../../../src/messages/assistantPhase.ts"],"sourcesContent":["import type { AssistantTextPhase } from '@/types/assistantPhase';\nimport type { MessageContentComplex } from '@/types/stream';\nimport { ContentTypes } from '@/common';\n\nexport type MessageCreationContentMetadata = {\n content_type?: ContentTypes.TEXT | ContentTypes.THINK;\n phase?: AssistantTextPhase;\n};\n\nfunction toAssistantTextPhase(value: unknown): AssistantTextPhase | undefined {\n return value === 'commentary' || value === 'final_answer' ? value : undefined;\n}\n\n/** Reads both provider-native and LangChain standard-content phase fields. */\nexport function getAssistantTextPhase(\n contentPart: MessageContentComplex\n): AssistantTextPhase | undefined {\n return (\n toAssistantTextPhase(contentPart.phase) ??\n toAssistantTextPhase(contentPart.extras?.phase)\n );\n}\n\n/**\n * Keeps provider-authored text phases in distinct message-creation steps.\n * Open Responses may return commentary and final-answer blocks in one chunk;\n * collapsing the array into one step would assign the first block's phase to\n * every block and hide the boundary that closes an activity phase.\n */\nexport function splitAssistantTextContentByPhase(\n content: MessageContentComplex[]\n): MessageContentComplex[][] {\n const groups: MessageContentComplex[][] = [];\n for (const contentPart of content) {\n const phase = getAssistantTextPhase(contentPart);\n const currentGroup = groups.at(-1);\n if (\n currentGroup == null ||\n getAssistantTextPhase(currentGroup[0]) !== phase\n ) {\n groups.push([contentPart]);\n continue;\n }\n currentGroup.push(contentPart);\n }\n return groups;\n}\n\nfunction isTextPart(contentPart: MessageContentComplex): boolean {\n return contentPart.type?.startsWith(ContentTypes.TEXT) ?? false;\n}\n\nfunction isReasoningPart(contentPart: MessageContentComplex): boolean {\n return (\n contentPart.type === ContentTypes.THINK ||\n (contentPart.type?.startsWith(ContentTypes.THINKING) ?? false) ||\n (contentPart.type?.startsWith(ContentTypes.REASONING) ?? false) ||\n (contentPart.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false) ||\n contentPart.type === 'redacted_thinking'\n );\n}\n\n/**\n * Derives additive message-creation metadata before a content delta is\n * dispatched. The fallback covers string-only providers whose semantic lane\n * is tracked by the stream handler rather than represented on a block.\n */\nexport function getMessageCreationContentMetadata(\n content: string | MessageContentComplex[] | undefined,\n fallbackContentType?: ContentTypes.TEXT | ContentTypes.THINK\n): MessageCreationContentMetadata {\n if (!Array.isArray(content)) {\n return fallbackContentType == null\n ? {}\n : { content_type: fallbackContentType };\n }\n const textPart = content.find(isTextPart);\n if (textPart != null) {\n const phase = getAssistantTextPhase(textPart);\n return {\n content_type: ContentTypes.TEXT,\n ...(phase == null ? {} : { phase }),\n };\n }\n if (content.some(isReasoningPart)) {\n return { content_type: ContentTypes.THINK };\n }\n return fallbackContentType == null\n ? {}\n : { content_type: fallbackContentType };\n}\n"],"mappings":";;;AASA,SAAS,qBAAqB,OAAgD;CAC5E,OAAO,UAAU,gBAAgB,UAAU,iBAAiB,QAAQ,KAAA;AACtE;;AAGA,SAAgB,sBACd,aACgC;CAChC,OACE,qBAAqB,YAAY,KAAK,KACtC,qBAAqB,YAAY,QAAQ,KAAK;AAElD;;;;;;;AAQA,SAAgB,iCACd,SAC2B;CAC3B,MAAM,SAAoC,CAAC;CAC3C,KAAK,MAAM,eAAe,SAAS;EACjC,MAAM,QAAQ,sBAAsB,WAAW;EAC/C,MAAM,eAAe,OAAO,GAAG,EAAE;EACjC,IACE,gBAAgB,QAChB,sBAAsB,aAAa,EAAE,MAAM,OAC3C;GACA,OAAO,KAAK,CAAC,WAAW,CAAC;GACzB;EACF;EACA,aAAa,KAAK,WAAW;CAC/B;CACA,OAAO;AACT;AAEA,SAAS,WAAW,aAA6C;CAC/D,OAAO,YAAY,MAAM,WAAA,MAA4B,KAAK;AAC5D;AAEA,SAAS,gBAAgB,aAA6C;CACpE,OACE,YAAY,SAAA,YACX,YAAY,MAAM,WAAA,UAAgC,KAAK,WACvD,YAAY,MAAM,WAAA,WAAiC,KAAK,WACxD,YAAY,MAAM,WAAA,mBAAyC,KAAK,UACjE,YAAY,SAAS;AAEzB;;;;;;AAOA,SAAgB,kCACd,SACA,qBACgC;CAChC,IAAI,CAAC,MAAM,QAAQ,OAAO,GACxB,OAAO,uBAAuB,OAC1B,CAAC,IACD,EAAE,cAAc,oBAAoB;CAE1C,MAAM,WAAW,QAAQ,KAAK,UAAU;CACxC,IAAI,YAAY,MAAM;EACpB,MAAM,QAAQ,sBAAsB,QAAQ;EAC5C,OAAO;GACL,cAAA;GACA,GAAI,SAAS,OAAO,CAAC,IAAI,EAAE,MAAM;EACnC;CACF;CACA,IAAI,QAAQ,KAAK,eAAe,GAC9B,OAAO,EAAE,cAAA,QAAiC;CAE5C,OAAO,uBAAuB,OAC1B,CAAC,IACD,EAAE,cAAc,oBAAoB;AAC1C"}
@@ -14,4 +14,5 @@ import "./alternation.mjs";
14
14
  import "./handoffCue.mjs";
15
15
  import "./reducer.mjs";
16
16
  import "./recency.mjs";
17
+ import "./assistantPhase.mjs";
17
18
  export {};
@@ -22,6 +22,27 @@ Examples:
22
22
  - Fixed failing auth middleware tests
23
23
  - Read project config and dependency manifests
24
24
  - Attempted database migration, hit permission errors`;
25
+ /** Default system prompt for a run-wide parent activity phase. */
26
+ const ACTIVITY_PHASE_LABEL_PROMPT = `Summarize what this phase of an agent run accomplished. The result appears as the header of one collapsed parent group containing several activities.
27
+
28
+ Rules:
29
+ - One line, 8 to 18 words, past tense
30
+ - Lead with the concrete outcome and name the most distinctive subject
31
+ - Synthesize the phase; do not enumerate, count, or restate individual activities
32
+ - Describe failures plainly when they are the phase's material outcome
33
+ - Never mention tool names, calls, arguments, reasoning, commentary, or activity counts
34
+ - Output only the summary — no quotes, no trailing punctuation, no preamble
35
+
36
+ Examples:
37
+ - Reconciled authentication behavior and fixed the failing session refresh path
38
+ - Compared deployment options and documented the safest production rollout
39
+ - Investigated database latency but could not confirm the suspected index regression
40
+
41
+ Bad examples:
42
+ - Used three tools to inspect files and run tests
43
+ - Searched code, read configuration, and updated middleware`;
44
+ /** Hard ceiling across every activity/context section in one phase request. */
45
+ const ACTIVITY_PHASE_PROMPT_MAX_LENGTH = 12e3;
25
46
  /** Truncates a serialized value for the label prompt. */
26
47
  function truncateForLabel(value, maxLength) {
27
48
  if (value.length <= maxLength) return value;
@@ -81,6 +102,8 @@ const PREVIOUS_LABEL_LIMIT = 200;
81
102
  * produce one, and the cap keeps a 200-call programmatic batch from
82
103
  * building an enormous prompt out of per-field-bounded pieces. */
83
104
  const MAX_PROMPT_ENTRIES = 12;
105
+ const MAX_PHASE_ACTIVITIES = 12;
106
+ const MAX_PHASE_TOOL_ENTRIES = 6;
84
107
  /**
85
108
  * Builds the user prompt for a fast-model activity label. Pure — exported
86
109
  * for direct testing of redaction and truncation behavior.
@@ -134,7 +157,57 @@ function buildActivityLabelPrompt({ entries, charLimit, thinkingExcerpts, lastAs
134
157
  sections.push("Header:");
135
158
  return sections.join("\n\n");
136
159
  }
160
+ /**
161
+ * Builds bounded, redaction-aware evidence for a parent activity phase.
162
+ * Committed child labels are preferred; raw tool/reasoning evidence is only
163
+ * used when no child label exists.
164
+ */
165
+ function buildActivityPhaseLabelPrompt({ activities, totalActivityCount, charLimit, assistantContext, redaction }) {
166
+ const freeFormSuppressed = redaction != null && (redaction.enabled === false || redaction.redactedToolNames.size > 0);
167
+ const sections = [];
168
+ if (!freeFormSuppressed && assistantContext != null && assistantContext.length > 0) {
169
+ const context = assistantContext.slice(-3).map((text) => truncateForLabel(text.replace(/\s+/g, " ").trim(), charLimit)).filter((text) => text.length > 0);
170
+ if (context.length > 0) sections.push("Intermediate assistant context (do not quote or restate):\n" + context.map((text) => `- ${text}`).join("\n"));
171
+ }
172
+ let hasDescribableEvidence = false;
173
+ const activityLines = activities.slice(0, MAX_PHASE_ACTIVITIES).map((activity, index) => {
174
+ let status = "completed";
175
+ if (activity.status === "error") status = "failed";
176
+ else if (activity.status === "partial") status = "partial";
177
+ if (!freeFormSuppressed && activity.label != null && activity.label.trim() !== "") {
178
+ hasDescribableEvidence = true;
179
+ return `${index + 1}. ${status}: ${truncateForLabel(activity.label.replace(/\s+/g, " ").trim(), charLimit)}`;
180
+ }
181
+ const evidence = [];
182
+ if (!freeFormSuppressed && activity.thinkingExcerpts != null && activity.thinkingExcerpts.length > 0) evidence.push(...activity.thinkingExcerpts.slice(0, MAX_THINKING_EXCERPTS).map((excerpt) => truncateForLabel(excerpt.replace(/\s+/g, " ").trim(), charLimit)).filter((excerpt) => excerpt.length > 0).map((excerpt) => `context=${excerpt}`));
183
+ if (activity.entries != null && activity.entries.length > 0) evidence.push(...activity.entries.slice(0, MAX_PHASE_TOOL_ENTRIES).map((entry) => {
184
+ const entryRedacted = redaction != null && shouldRedactTool(entry.toolName, redaction);
185
+ const input = truncateForLabel(serializeForLabel(entry.toolInput, charLimit), charLimit);
186
+ let outcome;
187
+ if (entryRedacted) outcome = redaction.redactionText;
188
+ else if (entry.status === "error") outcome = `ERROR: ${truncateForLabel(entry.error ?? "unknown error", charLimit)}`;
189
+ else outcome = truncateForLabel(serializeForLabel(entry.toolOutput, charLimit), charLimit);
190
+ return `${entry.toolName}(${input}) → ${outcome}`;
191
+ }));
192
+ if (evidence.length > 0) hasDescribableEvidence = true;
193
+ return `${index + 1}. ${status}${evidence.length > 0 ? `: ${evidence.join("; ")}` : ""}`;
194
+ });
195
+ if (!hasDescribableEvidence) return "";
196
+ const activityCount = Math.max(activities.length, totalActivityCount ?? 0);
197
+ if (activityCount > MAX_PHASE_ACTIVITIES) activityLines.push(`13. …and ${activityCount - MAX_PHASE_ACTIVITIES} more activities`);
198
+ sections.push("Activities in this phase (synthesize; do not restate):\n" + activityLines.join("\n"));
199
+ const terminalCue = "\n\nPhase summary:";
200
+ const evidence = sections.join("\n\n");
201
+ const prompt = evidence + terminalCue;
202
+ if (prompt.length <= 12e3) return prompt;
203
+ const evidenceLimit = ACTIVITY_PHASE_PROMPT_MAX_LENGTH - 16 - 1;
204
+ return `${evidence.slice(0, evidenceLimit).trimEnd()}…${terminalCue}`;
205
+ }
206
+ /** Normalizes a model result for safe single-row persistence and display. */
207
+ function normalizeActivityPhaseLabel(label) {
208
+ return truncateForLabel(label.replace(/\s+/g, " ").trim().replace(/^["']|["']$/g, "").replace(/[.!?]+$/g, ""), 160);
209
+ }
137
210
  //#endregion
138
- export { ACTIVITY_LABEL_PROMPT, buildActivityLabelPrompt };
211
+ export { ACTIVITY_LABEL_PROMPT, ACTIVITY_PHASE_LABEL_PROMPT, buildActivityLabelPrompt, buildActivityPhaseLabelPrompt, normalizeActivityPhaseLabel };
139
212
 
140
213
  //# sourceMappingURL=activityLabel.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"activityLabel.mjs","names":[],"sources":["../../../src/prompts/activityLabel.ts"],"sourcesContent":["import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';\nimport type { ActivityLabelToolEntry } from '@/types/activityLabel';\nimport { shouldRedactTool } from '@/langfuseToolOutputTracing';\n\n/**\n * Default system prompt for fast-model activity labeling.\n *\n * Style synthesized from Claude Code's tool-use summary prompt (git-subject\n * register, past tense, distinctive nouns) and claude.ai's observed group\n * headers (5–9 words describing a mixed reasoning + tool block, e.g.\n * \"Synthesized version data and curated comparative framework\").\n */\nexport const ACTIVITY_LABEL_PROMPT = `Write a short label describing what this block of agent activity accomplished. It appears as the header of a collapsed activity group in a chat UI.\n\nRules:\n- 5 to 9 words, past-tense verb first\n- Name the most distinctive subject (file, API, topic); drop articles and filler\n- Describe outcomes, not mechanics; if something failed, say so plainly\n- Output only the label — no quotes, no punctuation at the end, no preamble\n\nExamples:\n- Searched Node.js release notes and changelogs\n- Compared runtime versions across official sources\n- Fixed failing auth middleware tests\n- Read project config and dependency manifests\n- Attempted database migration, hit permission errors`;\n\n/** Truncates a serialized value for the label prompt. */\nexport function truncateForLabel(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return value.slice(0, Math.max(0, maxLength - 1)) + '…';\n}\n\n/**\n * Reduces a committed label to bounded single-line data.\n *\n * Sections in this prompt are delimited by blank lines, so a label carrying\n * embedded newlines could otherwise forge an apparent entries section or\n * `Header:` cue. Unlike every other input here, previous labels re-enter\n * the prompt on EVERY later batch, so one malformed result — plain model\n * noncompliance, or injection surfacing through a tool result — would\n * persistently steer unrelated later labels rather than affecting one. The\n * clip bounds the same way `lastAssistantText` and reasoning excerpts are\n * bounded: oversized headers must not inflate later requests past the fast\n * model's window and starve the run of labels entirely.\n */\nfunction sanitizePreviousLabel(label: string): string {\n return truncateForLabel(\n label.replace(/\\s+/g, ' ').trim(),\n PREVIOUS_LABEL_LIMIT\n );\n}\n\nconst ABORT_SERIALIZATION = Symbol('abort-label-serialization');\n\n/**\n * Serializes a tool value for the prompt WITHOUT materializing huge JSON:\n * the output is clipped to a few hundred characters anyway, so a multi-\n * megabyte tool result must not be stringified in full on the label path.\n * Strings clip immediately; structured values serialize under a character\n * budget and degrade to a shape summary once it is exhausted.\n */\nfunction serializeForLabel(value: unknown, limit: number): string {\n if (value == null) {\n return '';\n }\n if (typeof value === 'string') {\n return value.length > limit ? value.slice(0, limit + 1) : value;\n }\n let budget = limit * 4;\n try {\n return (\n JSON.stringify(value, (_key, nested: unknown) => {\n if (budget <= 0) {\n throw ABORT_SERIALIZATION;\n }\n if (typeof nested === 'string') {\n const clipped =\n nested.length > limit ? nested.slice(0, limit) : nested;\n budget -= clipped.length;\n return clipped;\n }\n budget -= 8;\n return nested;\n }) ?? ''\n );\n } catch (error) {\n if (error === ABORT_SERIALIZATION) {\n return Array.isArray(value) ? `[Array(${value.length})]` : '[Object]';\n }\n return String(value);\n }\n}\n\nconst INPUT_CONTEXT_LIMIT = 200;\nconst MAX_THINKING_EXCERPTS = 4;\nconst MAX_PREVIOUS_LABELS = 3;\n/** Per-label bound. A header is 5-9 words; anything past this is\n * noncompliance or payload, and previous labels are the one input that\n * RE-ENTERS the prompt on every later batch of the run. */\nconst PREVIOUS_LABEL_LIMIT = 200;\n/** A label is 5-9 words; no batch needs more than this many entries to\n * produce one, and the cap keeps a 200-call programmatic batch from\n * building an enormous prompt out of per-field-bounded pieces. */\nconst MAX_PROMPT_ENTRIES = 12;\n\nexport type BuildActivityLabelPromptParams = {\n entries: ActivityLabelToolEntry[];\n charLimit: number;\n thinkingExcerpts?: string[];\n lastAssistantText?: string;\n /**\n * Headers already committed for earlier batches in this run, in run order\n * with the most recent last. Rendered ahead of the block context so the\n * label continues the run's story instead of restating a line the user is\n * already reading. Capped at {@link MAX_PREVIOUS_LABELS}.\n */\n previousLabels?: string[];\n /**\n * Resolved tool-output tracing policy. The label prompt becomes Langfuse\n * generation input, so outputs/errors excluded from tracing (global\n * disable or `redactedToolNames`) must never appear in it — the same\n * redaction the span processor applies to structured tool observations.\n */\n redaction?: ResolvedLangfuseToolOutputTracingConfig;\n};\n\n/**\n * Builds the user prompt for a fast-model activity label. Pure — exported\n * for direct testing of redaction and truncation behavior.\n */\nexport function buildActivityLabelPrompt({\n entries,\n charLimit,\n thinkingExcerpts,\n lastAssistantText,\n previousLabels,\n redaction,\n}: BuildActivityLabelPromptParams): string {\n const clip = truncateForLabel;\n /** Reasoning and intent text can quote tool output verbatim — including\n * output from EARLIER calls to a redacted tool that this batch does not\n * contain — so any active policy (global disable or a configured\n * redacted-name list) drops both wholesale. There is no reliable way to\n * scrub a quoted fragment out of free-form model prose. */\n const excerptsRedacted =\n redaction != null &&\n (redaction.enabled === false || redaction.redactedToolNames.size > 0);\n const sections: string[] = [];\n /** Previous labels are free-form model prose too, and per-agent overlays\n * mean an earlier header may have been generated under ANOTHER agent's\n * weaker policy — so they share the excerpts' wholesale drop rather than\n * letting a handoff leak a looser agent's phrasing into this trace. */\n if (\n !excerptsRedacted &&\n previousLabels != null &&\n previousLabels.length > 0\n ) {\n const recent = previousLabels\n .slice(-MAX_PREVIOUS_LABELS)\n .map(sanitizePreviousLabel)\n /** A label that sanitizes to nothing carries no story to continue;\n * rendering it would leave a bare bullet implying a missing header. */\n .filter((label) => label.length > 0);\n if (recent.length > 0) {\n sections.push(\n 'Previous headers in this run (most recent last):\\n' +\n recent.map((label) => `- ${label}`).join('\\n')\n );\n }\n }\n /** Intent text is free-form assistant prose that can quote a redacted\n * tool result just as reasoning can, so it shares the excerpts' fate. */\n if (\n !excerptsRedacted &&\n lastAssistantText != null &&\n lastAssistantText.length > 0\n ) {\n sections.push(\n `Intent (assistant's last message): ${clip(lastAssistantText, INPUT_CONTEXT_LIMIT)}`\n );\n }\n if (\n !excerptsRedacted &&\n thinkingExcerpts != null &&\n thinkingExcerpts.length > 0\n ) {\n sections.push(\n 'Reasoning excerpts:\\n' +\n thinkingExcerpts\n .slice(0, MAX_THINKING_EXCERPTS)\n .map((excerpt) => `- ${clip(excerpt, charLimit)}`)\n .join('\\n')\n );\n }\n if (entries.length > 0) {\n const shown = entries.slice(0, MAX_PROMPT_ENTRIES);\n const omitted = entries.length - shown.length;\n sections.push(\n /** Frames the list as reference material, not the thing to\n * transcribe. Ported from LibreChat's fallback builder (its\n * runtime.ts documents that without this the model \"hands back a\n * transcription\" of the list) after the eval harness measured it\n * across three independent sweeps: fewer template-redundancy and\n * length violations than a bare `Tool calls:` heading, with no\n * per-case regressions (agents #360). */\n 'What it called, and what came back (do not restate these):\\n' +\n shown\n .map((entry) => {\n const input = clip(\n serializeForLabel(entry.toolInput, charLimit),\n charLimit\n );\n const redacted =\n redaction != null && shouldRedactTool(entry.toolName, redaction);\n let outcome: string;\n if (redacted) {\n outcome = redaction.redactionText;\n } else if (entry.status === 'error') {\n outcome = `ERROR: ${clip(entry.error ?? 'unknown error', charLimit)}`;\n } else {\n outcome = clip(\n serializeForLabel(entry.toolOutput, charLimit),\n charLimit\n );\n }\n return `- ${entry.toolName}(${input}) → ${outcome}`;\n })\n .join('\\n') +\n (omitted > 0\n ? `\\n- …and ${omitted} more tool ${omitted === 1 ? 'call' : 'calls'}`\n : '')\n );\n }\n /** The fallback builder's terminal cue, measured alongside the heading\n * (same sweeps). The default system prompt already describes the\n * output as \"the header of a collapsed activity group\". */\n sections.push('Header:');\n return sections.join('\\n\\n');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"activityLabel.mjs","names":[],"sources":["../../../src/prompts/activityLabel.ts"],"sourcesContent":["import type {\n ActivityLabelToolEntry,\n ActivityPhaseEntry,\n} from '@/types/activityLabel';\nimport type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';\nimport { shouldRedactTool } from '@/langfuseToolOutputTracing';\n\n/**\n * Default system prompt for fast-model activity labeling.\n *\n * Style synthesized from Claude Code's tool-use summary prompt (git-subject\n * register, past tense, distinctive nouns) and claude.ai's observed group\n * headers (5–9 words describing a mixed reasoning + tool block, e.g.\n * \"Synthesized version data and curated comparative framework\").\n */\nexport const ACTIVITY_LABEL_PROMPT = `Write a short label describing what this block of agent activity accomplished. It appears as the header of a collapsed activity group in a chat UI.\n\nRules:\n- 5 to 9 words, past-tense verb first\n- Name the most distinctive subject (file, API, topic); drop articles and filler\n- Describe outcomes, not mechanics; if something failed, say so plainly\n- Output only the label — no quotes, no punctuation at the end, no preamble\n\nExamples:\n- Searched Node.js release notes and changelogs\n- Compared runtime versions across official sources\n- Fixed failing auth middleware tests\n- Read project config and dependency manifests\n- Attempted database migration, hit permission errors`;\n\n/** Default system prompt for a run-wide parent activity phase. */\nexport const ACTIVITY_PHASE_LABEL_PROMPT = `Summarize what this phase of an agent run accomplished. The result appears as the header of one collapsed parent group containing several activities.\n\nRules:\n- One line, 8 to 18 words, past tense\n- Lead with the concrete outcome and name the most distinctive subject\n- Synthesize the phase; do not enumerate, count, or restate individual activities\n- Describe failures plainly when they are the phase's material outcome\n- Never mention tool names, calls, arguments, reasoning, commentary, or activity counts\n- Output only the summary — no quotes, no trailing punctuation, no preamble\n\nExamples:\n- Reconciled authentication behavior and fixed the failing session refresh path\n- Compared deployment options and documented the safest production rollout\n- Investigated database latency but could not confirm the suspected index regression\n\nBad examples:\n- Used three tools to inspect files and run tests\n- Searched code, read configuration, and updated middleware`;\n\n/** Hard ceiling across every activity/context section in one phase request. */\nexport const ACTIVITY_PHASE_PROMPT_MAX_LENGTH = 12_000;\n\n/** Truncates a serialized value for the label prompt. */\nexport function truncateForLabel(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return value.slice(0, Math.max(0, maxLength - 1)) + '…';\n}\n\n/**\n * Reduces a committed label to bounded single-line data.\n *\n * Sections in this prompt are delimited by blank lines, so a label carrying\n * embedded newlines could otherwise forge an apparent entries section or\n * `Header:` cue. Unlike every other input here, previous labels re-enter\n * the prompt on EVERY later batch, so one malformed result — plain model\n * noncompliance, or injection surfacing through a tool result — would\n * persistently steer unrelated later labels rather than affecting one. The\n * clip bounds the same way `lastAssistantText` and reasoning excerpts are\n * bounded: oversized headers must not inflate later requests past the fast\n * model's window and starve the run of labels entirely.\n */\nfunction sanitizePreviousLabel(label: string): string {\n return truncateForLabel(\n label.replace(/\\s+/g, ' ').trim(),\n PREVIOUS_LABEL_LIMIT\n );\n}\n\nconst ABORT_SERIALIZATION = Symbol('abort-label-serialization');\n\n/**\n * Serializes a tool value for the prompt WITHOUT materializing huge JSON:\n * the output is clipped to a few hundred characters anyway, so a multi-\n * megabyte tool result must not be stringified in full on the label path.\n * Strings clip immediately; structured values serialize under a character\n * budget and degrade to a shape summary once it is exhausted.\n */\nfunction serializeForLabel(value: unknown, limit: number): string {\n if (value == null) {\n return '';\n }\n if (typeof value === 'string') {\n return value.length > limit ? value.slice(0, limit + 1) : value;\n }\n let budget = limit * 4;\n try {\n return (\n JSON.stringify(value, (_key, nested: unknown) => {\n if (budget <= 0) {\n throw ABORT_SERIALIZATION;\n }\n if (typeof nested === 'string') {\n const clipped =\n nested.length > limit ? nested.slice(0, limit) : nested;\n budget -= clipped.length;\n return clipped;\n }\n budget -= 8;\n return nested;\n }) ?? ''\n );\n } catch (error) {\n if (error === ABORT_SERIALIZATION) {\n return Array.isArray(value) ? `[Array(${value.length})]` : '[Object]';\n }\n return String(value);\n }\n}\n\nconst INPUT_CONTEXT_LIMIT = 200;\nconst MAX_THINKING_EXCERPTS = 4;\nconst MAX_PREVIOUS_LABELS = 3;\n/** Per-label bound. A header is 5-9 words; anything past this is\n * noncompliance or payload, and previous labels are the one input that\n * RE-ENTERS the prompt on every later batch of the run. */\nconst PREVIOUS_LABEL_LIMIT = 200;\n/** A label is 5-9 words; no batch needs more than this many entries to\n * produce one, and the cap keeps a 200-call programmatic batch from\n * building an enormous prompt out of per-field-bounded pieces. */\nconst MAX_PROMPT_ENTRIES = 12;\nconst MAX_PHASE_ACTIVITIES = 12;\nconst MAX_PHASE_CONTEXT = 3;\nconst MAX_PHASE_TOOL_ENTRIES = 6;\nexport const ACTIVITY_PHASE_LABEL_MAX_LENGTH = 160;\n\nexport type BuildActivityLabelPromptParams = {\n entries: ActivityLabelToolEntry[];\n charLimit: number;\n thinkingExcerpts?: string[];\n lastAssistantText?: string;\n /**\n * Headers already committed for earlier batches in this run, in run order\n * with the most recent last. Rendered ahead of the block context so the\n * label continues the run's story instead of restating a line the user is\n * already reading. Capped at {@link MAX_PREVIOUS_LABELS}.\n */\n previousLabels?: string[];\n /**\n * Resolved tool-output tracing policy. The label prompt becomes Langfuse\n * generation input, so outputs/errors excluded from tracing (global\n * disable or `redactedToolNames`) must never appear in it — the same\n * redaction the span processor applies to structured tool observations.\n */\n redaction?: ResolvedLangfuseToolOutputTracingConfig;\n};\n\n/**\n * Builds the user prompt for a fast-model activity label. Pure — exported\n * for direct testing of redaction and truncation behavior.\n */\nexport function buildActivityLabelPrompt({\n entries,\n charLimit,\n thinkingExcerpts,\n lastAssistantText,\n previousLabels,\n redaction,\n}: BuildActivityLabelPromptParams): string {\n const clip = truncateForLabel;\n /** Reasoning and intent text can quote tool output verbatim — including\n * output from EARLIER calls to a redacted tool that this batch does not\n * contain — so any active policy (global disable or a configured\n * redacted-name list) drops both wholesale. There is no reliable way to\n * scrub a quoted fragment out of free-form model prose. */\n const excerptsRedacted =\n redaction != null &&\n (redaction.enabled === false || redaction.redactedToolNames.size > 0);\n const sections: string[] = [];\n /** Previous labels are free-form model prose too, and per-agent overlays\n * mean an earlier header may have been generated under ANOTHER agent's\n * weaker policy — so they share the excerpts' wholesale drop rather than\n * letting a handoff leak a looser agent's phrasing into this trace. */\n if (\n !excerptsRedacted &&\n previousLabels != null &&\n previousLabels.length > 0\n ) {\n const recent = previousLabels\n .slice(-MAX_PREVIOUS_LABELS)\n .map(sanitizePreviousLabel)\n /** A label that sanitizes to nothing carries no story to continue;\n * rendering it would leave a bare bullet implying a missing header. */\n .filter((label) => label.length > 0);\n if (recent.length > 0) {\n sections.push(\n 'Previous headers in this run (most recent last):\\n' +\n recent.map((label) => `- ${label}`).join('\\n')\n );\n }\n }\n /** Intent text is free-form assistant prose that can quote a redacted\n * tool result just as reasoning can, so it shares the excerpts' fate. */\n if (\n !excerptsRedacted &&\n lastAssistantText != null &&\n lastAssistantText.length > 0\n ) {\n sections.push(\n `Intent (assistant's last message): ${clip(lastAssistantText, INPUT_CONTEXT_LIMIT)}`\n );\n }\n if (\n !excerptsRedacted &&\n thinkingExcerpts != null &&\n thinkingExcerpts.length > 0\n ) {\n sections.push(\n 'Reasoning excerpts:\\n' +\n thinkingExcerpts\n .slice(0, MAX_THINKING_EXCERPTS)\n .map((excerpt) => `- ${clip(excerpt, charLimit)}`)\n .join('\\n')\n );\n }\n if (entries.length > 0) {\n const shown = entries.slice(0, MAX_PROMPT_ENTRIES);\n const omitted = entries.length - shown.length;\n sections.push(\n /** Frames the list as reference material, not the thing to\n * transcribe. Ported from LibreChat's fallback builder (its\n * runtime.ts documents that without this the model \"hands back a\n * transcription\" of the list) after the eval harness measured it\n * across three independent sweeps: fewer template-redundancy and\n * length violations than a bare `Tool calls:` heading, with no\n * per-case regressions (agents #360). */\n 'What it called, and what came back (do not restate these):\\n' +\n shown\n .map((entry) => {\n const input = clip(\n serializeForLabel(entry.toolInput, charLimit),\n charLimit\n );\n const redacted =\n redaction != null && shouldRedactTool(entry.toolName, redaction);\n let outcome: string;\n if (redacted) {\n outcome = redaction.redactionText;\n } else if (entry.status === 'error') {\n outcome = `ERROR: ${clip(entry.error ?? 'unknown error', charLimit)}`;\n } else {\n outcome = clip(\n serializeForLabel(entry.toolOutput, charLimit),\n charLimit\n );\n }\n return `- ${entry.toolName}(${input}) → ${outcome}`;\n })\n .join('\\n') +\n (omitted > 0\n ? `\\n- …and ${omitted} more tool ${omitted === 1 ? 'call' : 'calls'}`\n : '')\n );\n }\n /** The fallback builder's terminal cue, measured alongside the heading\n * (same sweeps). The default system prompt already describes the\n * output as \"the header of a collapsed activity group\". */\n sections.push('Header:');\n return sections.join('\\n\\n');\n}\n\nexport type BuildActivityPhaseLabelPromptParams = {\n activities: ActivityPhaseEntry[];\n totalActivityCount?: number;\n charLimit: number;\n assistantContext?: string[];\n redaction?: ResolvedLangfuseToolOutputTracingConfig;\n};\n\n/**\n * Builds bounded, redaction-aware evidence for a parent activity phase.\n * Committed child labels are preferred; raw tool/reasoning evidence is only\n * used when no child label exists.\n */\nexport function buildActivityPhaseLabelPrompt({\n activities,\n totalActivityCount,\n charLimit,\n assistantContext,\n redaction,\n}: BuildActivityPhaseLabelPromptParams): string {\n const freeFormSuppressed =\n redaction != null &&\n (redaction.enabled === false || redaction.redactedToolNames.size > 0);\n const sections: string[] = [];\n if (\n !freeFormSuppressed &&\n assistantContext != null &&\n assistantContext.length > 0\n ) {\n const context = assistantContext\n .slice(-MAX_PHASE_CONTEXT)\n .map((text) =>\n truncateForLabel(text.replace(/\\s+/g, ' ').trim(), charLimit)\n )\n .filter((text) => text.length > 0);\n if (context.length > 0) {\n sections.push(\n 'Intermediate assistant context (do not quote or restate):\\n' +\n context.map((text) => `- ${text}`).join('\\n')\n );\n }\n }\n\n let hasDescribableEvidence = false;\n const activityLines = activities\n .slice(0, MAX_PHASE_ACTIVITIES)\n .map((activity, index) => {\n let status = 'completed';\n if (activity.status === 'error') {\n status = 'failed';\n } else if (activity.status === 'partial') {\n status = 'partial';\n }\n if (\n !freeFormSuppressed &&\n activity.label != null &&\n activity.label.trim() !== ''\n ) {\n hasDescribableEvidence = true;\n return `${index + 1}. ${status}: ${truncateForLabel(activity.label.replace(/\\s+/g, ' ').trim(), charLimit)}`;\n }\n\n const evidence: string[] = [];\n if (\n !freeFormSuppressed &&\n activity.thinkingExcerpts != null &&\n activity.thinkingExcerpts.length > 0\n ) {\n evidence.push(\n ...activity.thinkingExcerpts\n .slice(0, MAX_THINKING_EXCERPTS)\n .map((excerpt) =>\n truncateForLabel(excerpt.replace(/\\s+/g, ' ').trim(), charLimit)\n )\n .filter((excerpt) => excerpt.length > 0)\n .map((excerpt) => `context=${excerpt}`)\n );\n }\n if (activity.entries != null && activity.entries.length > 0) {\n evidence.push(\n ...activity.entries.slice(0, MAX_PHASE_TOOL_ENTRIES).map((entry) => {\n const entryRedacted =\n redaction != null && shouldRedactTool(entry.toolName, redaction);\n const input = truncateForLabel(\n serializeForLabel(entry.toolInput, charLimit),\n charLimit\n );\n let outcome: string;\n if (entryRedacted) {\n outcome = redaction.redactionText;\n } else if (entry.status === 'error') {\n outcome = `ERROR: ${truncateForLabel(\n entry.error ?? 'unknown error',\n charLimit\n )}`;\n } else {\n outcome = truncateForLabel(\n serializeForLabel(entry.toolOutput, charLimit),\n charLimit\n );\n }\n return `${entry.toolName}(${input}) → ${outcome}`;\n })\n );\n }\n if (evidence.length > 0) {\n hasDescribableEvidence = true;\n }\n return `${index + 1}. ${status}${evidence.length > 0 ? `: ${evidence.join('; ')}` : ''}`;\n });\n\n if (!hasDescribableEvidence) {\n return '';\n }\n\n const activityCount = Math.max(activities.length, totalActivityCount ?? 0);\n if (activityCount > MAX_PHASE_ACTIVITIES) {\n activityLines.push(\n `${MAX_PHASE_ACTIVITIES + 1}. …and ${activityCount - MAX_PHASE_ACTIVITIES} more activities`\n );\n }\n sections.push(\n 'Activities in this phase (synthesize; do not restate):\\n' +\n activityLines.join('\\n')\n );\n const terminalCue = '\\n\\nPhase summary:';\n const evidence = sections.join('\\n\\n');\n const prompt = evidence + terminalCue;\n if (prompt.length <= ACTIVITY_PHASE_PROMPT_MAX_LENGTH) {\n return prompt;\n }\n const evidenceLimit =\n ACTIVITY_PHASE_PROMPT_MAX_LENGTH - terminalCue.length - 1;\n return `${evidence.slice(0, evidenceLimit).trimEnd()}…${terminalCue}`;\n}\n\n/** Normalizes a model result for safe single-row persistence and display. */\nexport function normalizeActivityPhaseLabel(label: string): string {\n const normalized = label\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/^[\"']|[\"']$/g, '')\n .replace(/[.!?]+$/g, '');\n return truncateForLabel(normalized, ACTIVITY_PHASE_LABEL_MAX_LENGTH);\n}\n"],"mappings":"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"}