mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-11 22:51:26 +00:00
feat: gate unified user message tag behind experimental setting
- Add UNIFIED_USER_MESSAGE_TAG experiment (disabled by default) - Create userContentTags utility for conditional tag formatting - Update Task.ts to conditionally wrap task/resume content - Update tool files (AskFollowupQuestion, AttemptCompletion, ExecuteCommand) to conditionally wrap feedback/answers - Update formatResponse functions to accept useUnifiedTag parameter - Update presentAssistantMessage.ts to pass experiment flag - Update ReadFileTool.ts to pass experiment flag - Update processUserContentMentions.ts to detect tags based on experiment When experiment is disabled (default): - Uses legacy tags: <task>, <feedback>, <answer> - Maintains backward compatibility When experiment is enabled: - Uses unified <user_message> tag for all contexts - Simplifies tag detection and handling Relates to COM-450
This commit is contained in:
parent
4b17f985b4
commit
f8f631dc82
11 changed files with 156 additions and 36 deletions
|
|
@ -14,6 +14,7 @@ export const experimentIds = [
|
|||
"runSlashCommand",
|
||||
"multipleNativeToolCalls",
|
||||
"customTools",
|
||||
"unifiedUserMessageTag",
|
||||
] as const
|
||||
|
||||
export const experimentIdsSchema = z.enum(experimentIds)
|
||||
|
|
@ -32,6 +33,7 @@ export const experimentsSchema = z.object({
|
|||
runSlashCommand: z.boolean().optional(),
|
||||
multipleNativeToolCalls: z.boolean().optional(),
|
||||
customTools: z.boolean().optional(),
|
||||
unifiedUserMessageTag: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export type Experiments = z.infer<typeof experimentsSchema>
|
||||
|
|
|
|||
|
|
@ -73,6 +73,10 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
cline.presentAssistantMessageLocked = true
|
||||
cline.presentAssistantMessageHasPendingUpdates = false
|
||||
|
||||
// Get experiment setting for unified tags once for this presentation
|
||||
const state = await cline.providerRef.deref()?.getState()
|
||||
const useUnifiedTag = experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.UNIFIED_USER_MESSAGE_TAG)
|
||||
|
||||
if (cline.currentStreamingContentIndex >= cline.assistantMessageContent.length) {
|
||||
// This may happen if the last content block was completed before
|
||||
// streaming could finish. If streaming is finished, and we're out of
|
||||
|
|
@ -174,7 +178,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
|
||||
// Merge approval feedback into tool result (GitHub #10465)
|
||||
if (approvalFeedback) {
|
||||
const feedbackText = formatResponse.toolApprovedWithFeedback(approvalFeedback.text, toolProtocol)
|
||||
const feedbackText = formatResponse.toolApprovedWithFeedback(approvalFeedback.text, toolProtocol, useUnifiedTag)
|
||||
resultContent = `${feedbackText}\n\n${resultContent}`
|
||||
|
||||
// Add feedback images to the image blocks
|
||||
|
|
@ -221,7 +225,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
await cline.say("user_feedback", text, images)
|
||||
pushToolResult(
|
||||
formatResponse.toolResult(
|
||||
formatResponse.toolDeniedWithFeedback(text, toolProtocol),
|
||||
formatResponse.toolDeniedWithFeedback(text, toolProtocol, useUnifiedTag),
|
||||
images,
|
||||
),
|
||||
)
|
||||
|
|
@ -372,8 +376,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
break
|
||||
}
|
||||
case "tool_use": {
|
||||
// Fetch state early so it's available for toolDescription and validation
|
||||
const state = await cline.providerRef.deref()?.getState()
|
||||
// Use already-fetched state for toolDescription and validation
|
||||
const { mode, customModes, experiments: stateExperiments } = state ?? {}
|
||||
|
||||
const toolDescription = (): string => {
|
||||
|
|
@ -556,6 +559,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
const feedbackText = formatResponse.toolApprovedWithFeedback(
|
||||
approvalFeedback.text,
|
||||
toolProtocol,
|
||||
useUnifiedTag,
|
||||
)
|
||||
resultContent = `${feedbackText}\n\n${resultContent}`
|
||||
|
||||
|
|
@ -597,6 +601,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
const feedbackText = formatResponse.toolApprovedWithFeedback(
|
||||
approvalFeedback.text,
|
||||
toolProtocol,
|
||||
useUnifiedTag,
|
||||
)
|
||||
resultContent = `${feedbackText}\n\n${resultContent}`
|
||||
}
|
||||
|
|
@ -658,7 +663,7 @@ export async function presentAssistantMessage(cline: Task) {
|
|||
await cline.say("user_feedback", text, images)
|
||||
pushToolResult(
|
||||
formatResponse.toolResult(
|
||||
formatResponse.toolDeniedWithFeedback(text, toolProtocol),
|
||||
formatResponse.toolDeniedWithFeedback(text, toolProtocol, useUnifiedTag),
|
||||
images,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
|
|||
import { parseMentions, ParseMentionsResult } from "./index"
|
||||
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
|
||||
import { FileContextTracker } from "../context-tracking/FileContextTracker"
|
||||
import { hasUserContentTags } from "../../utils/userContentTags"
|
||||
|
||||
export interface ProcessUserContentMentionsResult {
|
||||
content: Anthropic.Messages.ContentBlockParam[]
|
||||
|
|
@ -9,7 +10,7 @@ export interface ProcessUserContentMentionsResult {
|
|||
}
|
||||
|
||||
/**
|
||||
* Process mentions in user content, specifically within task and feedback tags
|
||||
* Process mentions in user content, specifically within user message tags
|
||||
*/
|
||||
export async function processUserContentMentions({
|
||||
userContent,
|
||||
|
|
@ -21,6 +22,7 @@ export async function processUserContentMentions({
|
|||
includeDiagnosticMessages = true,
|
||||
maxDiagnosticMessages = 50,
|
||||
maxReadFileLine,
|
||||
useUnifiedTag = false,
|
||||
}: {
|
||||
userContent: Anthropic.Messages.ContentBlockParam[]
|
||||
cwd: string
|
||||
|
|
@ -31,6 +33,7 @@ export async function processUserContentMentions({
|
|||
includeDiagnosticMessages?: boolean
|
||||
maxDiagnosticMessages?: number
|
||||
maxReadFileLine?: number
|
||||
useUnifiedTag?: boolean
|
||||
}): Promise<ProcessUserContentMentionsResult> {
|
||||
// Track the first mode found from slash commands
|
||||
let commandMode: string | undefined
|
||||
|
|
@ -38,20 +41,13 @@ export async function processUserContentMentions({
|
|||
// Process userContent array, which contains various block types:
|
||||
// TextBlockParam, ImageBlockParam, ToolUseBlockParam, and ToolResultBlockParam.
|
||||
// We need to apply parseMentions() to:
|
||||
// 1. All TextBlockParam's text (first user message with task)
|
||||
// 2. ToolResultBlockParam's content/context text arrays if it contains
|
||||
// "<feedback>" (see formatToolDeniedFeedback, attemptCompletion,
|
||||
// executeCommand, and consecutiveMistakeCount >= 3) or "<answer>"
|
||||
// (see askFollowupQuestion), we place all user generated content in
|
||||
// these tags so they can effectively be used as markers for when we
|
||||
// should parse mentions).
|
||||
// 1. All TextBlockParam's text (first user message)
|
||||
// 2. ToolResultBlockParam's content/context text arrays if it contains user content tags
|
||||
// We place all user generated content in these tags so they can effectively be used as
|
||||
// markers for when we should parse mentions.
|
||||
const content = await Promise.all(
|
||||
userContent.map(async (block) => {
|
||||
const shouldProcessMentions = (text: string) =>
|
||||
text.includes("<task>") ||
|
||||
text.includes("<feedback>") ||
|
||||
text.includes("<answer>") ||
|
||||
text.includes("<user_message>")
|
||||
const shouldProcessMentions = (text: string) => hasUserContentTags(text, useUnifiedTag)
|
||||
|
||||
if (block.type === "text") {
|
||||
if (shouldProcessMentions(block.text)) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import * as diff from "diff"
|
|||
import { RooIgnoreController, LOCK_TEXT_SYMBOL } from "../ignore/RooIgnoreController"
|
||||
import { RooProtectedController } from "../protect/RooProtectedController"
|
||||
import { ToolProtocol, isNativeProtocol, TOOL_PROTOCOL } from "@roo-code/types"
|
||||
import { wrapUserContent } from "../../utils/userContentTags"
|
||||
|
||||
export const formatResponse = {
|
||||
toolDenied: (protocol?: ToolProtocol) => {
|
||||
|
|
@ -16,26 +17,26 @@ export const formatResponse = {
|
|||
return `The user denied this operation.`
|
||||
},
|
||||
|
||||
toolDeniedWithFeedback: (feedback?: string, protocol?: ToolProtocol) => {
|
||||
toolDeniedWithFeedback: (feedback?: string, protocol?: ToolProtocol, useUnifiedTag?: boolean) => {
|
||||
if (isNativeProtocol(protocol ?? TOOL_PROTOCOL.XML)) {
|
||||
return JSON.stringify({
|
||||
status: "denied",
|
||||
message: "The user denied this operation and provided the following feedback",
|
||||
feedback: feedback,
|
||||
})
|
||||
}
|
||||
return `The user denied this operation and provided the following feedback:\n<feedback>\n${feedback}\n</feedback>`
|
||||
const wrappedFeedback = wrapUserContent(feedback ?? "", "feedback", useUnifiedTag ?? false)
|
||||
return `The user denied this operation and responded with the message:\n${wrappedFeedback}`
|
||||
},
|
||||
|
||||
toolApprovedWithFeedback: (feedback?: string, protocol?: ToolProtocol) => {
|
||||
toolApprovedWithFeedback: (feedback?: string, protocol?: ToolProtocol, useUnifiedTag?: boolean) => {
|
||||
if (isNativeProtocol(protocol ?? TOOL_PROTOCOL.XML)) {
|
||||
return JSON.stringify({
|
||||
status: "approved",
|
||||
message: "The user approved this operation and provided the following context",
|
||||
feedback: feedback,
|
||||
})
|
||||
}
|
||||
return `The user approved this operation and provided the following context:\n<feedback>\n${feedback}\n</feedback>`
|
||||
const wrappedFeedback = wrapUserContent(feedback ?? "", "feedback", useUnifiedTag ?? false)
|
||||
return `The user approved this operation and responded with the message:\n${wrappedFeedback}`
|
||||
},
|
||||
|
||||
toolError: (error?: string, protocol?: ToolProtocol) => {
|
||||
|
|
@ -77,15 +78,15 @@ Otherwise, if you have not completed the task and do not need additional informa
|
|||
(This is an automated message, so do not respond to it conversationally.)`
|
||||
},
|
||||
|
||||
tooManyMistakes: (feedback?: string, protocol?: ToolProtocol) => {
|
||||
tooManyMistakes: (feedback?: string, protocol?: ToolProtocol, useUnifiedTag?: boolean) => {
|
||||
if (isNativeProtocol(protocol ?? TOOL_PROTOCOL.XML)) {
|
||||
return JSON.stringify({
|
||||
status: "guidance",
|
||||
message: "You seem to be having trouble proceeding",
|
||||
feedback: feedback,
|
||||
})
|
||||
}
|
||||
return `You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n<feedback>\n${feedback}\n</feedback>`
|
||||
const wrappedFeedback = wrapUserContent(feedback ?? "", "feedback", useUnifiedTag ?? false)
|
||||
return `You seem to be having trouble proceeding. The user has provided the following feedback to help guide you:\n${wrappedFeedback}`
|
||||
},
|
||||
|
||||
missingToolParameterError: (paramName: string, protocol?: ToolProtocol) => {
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ import { defaultModeSlug, getModeBySlug, getGroupName } from "../../shared/modes
|
|||
import { DiffStrategy, type ToolUse, type ToolParamName, toolParamNames } from "../../shared/tools"
|
||||
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
|
||||
import { getModelMaxOutputTokens } from "../../shared/api"
|
||||
import { wrapUserContent } from "../../utils/userContentTags"
|
||||
|
||||
// services
|
||||
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
|
||||
|
|
@ -2508,9 +2509,13 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
)
|
||||
|
||||
if (response === "messageResponse") {
|
||||
// Get experiment setting for unified tags
|
||||
const mistakeState = await this.providerRef.deref()?.getState()
|
||||
const useUnifiedTagForMistakes = experiments.isEnabled(mistakeState?.experiments ?? {}, EXPERIMENT_IDS.UNIFIED_USER_MESSAGE_TAG)
|
||||
|
||||
currentUserContent.push(
|
||||
...[
|
||||
{ type: "text" as const, text: formatResponse.tooManyMistakes(text) },
|
||||
{ type: "text" as const, text: formatResponse.tooManyMistakes(text, this._taskToolProtocol, useUnifiedTagForMistakes) },
|
||||
...formatResponse.imageBlocks(images),
|
||||
],
|
||||
)
|
||||
|
|
@ -2553,8 +2558,11 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
includeDiagnosticMessages = true,
|
||||
maxDiagnosticMessages = 50,
|
||||
maxReadFileLine = -1,
|
||||
experiments: experimentsConfig,
|
||||
} = (await this.providerRef.deref()?.getState()) ?? {}
|
||||
|
||||
const useUnifiedTag = experiments.isEnabled(experimentsConfig ?? {}, EXPERIMENT_IDS.UNIFIED_USER_MESSAGE_TAG)
|
||||
|
||||
const { content: parsedUserContent, mode: slashCommandMode } = await processUserContentMentions({
|
||||
userContent: currentUserContent,
|
||||
cwd: this.cwd,
|
||||
|
|
@ -2565,6 +2573,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
includeDiagnosticMessages,
|
||||
maxDiagnosticMessages,
|
||||
maxReadFileLine,
|
||||
useUnifiedTag,
|
||||
})
|
||||
|
||||
// Switch mode if specified in a slash command's frontmatter
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { Task } from "../task/Task"
|
|||
import { formatResponse } from "../prompts/responses"
|
||||
import { parseXml } from "../../utils/xml"
|
||||
import type { ToolUse } from "../../shared/tools"
|
||||
import { wrapUserContent } from "../../utils/userContentTags"
|
||||
import { experiments, EXPERIMENT_IDS } from "../../shared/experiments"
|
||||
|
||||
import { BaseTool, ToolCallbacks } from "./BaseTool"
|
||||
|
||||
|
|
@ -86,7 +88,13 @@ export class AskFollowupQuestionTool extends BaseTool<"ask_followup_question"> {
|
|||
task.consecutiveMistakeCount = 0
|
||||
const { text, images } = await task.ask("followup", JSON.stringify(follow_up_json), false)
|
||||
await task.say("user_feedback", text ?? "", images)
|
||||
pushToolResult(formatResponse.toolResult(`<answer>\n${text}\n</answer>`, images))
|
||||
|
||||
// Get experiment setting for unified tags
|
||||
const state = await task.providerRef.deref()?.getState()
|
||||
const useUnifiedTag = experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.UNIFIED_USER_MESSAGE_TAG)
|
||||
const wrappedAnswer = wrapUserContent(text ?? "", "answer", useUnifiedTag)
|
||||
|
||||
pushToolResult(formatResponse.toolResult(wrappedAnswer, images))
|
||||
} catch (error) {
|
||||
await handleError("asking question", error as Error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import { formatResponse } from "../prompts/responses"
|
|||
import { Package } from "../../shared/package"
|
||||
import type { ToolUse } from "../../shared/tools"
|
||||
import { t } from "../../i18n"
|
||||
import { wrapUserContent } from "../../utils/userContentTags"
|
||||
import { experiments, EXPERIMENT_IDS } from "../../shared/experiments"
|
||||
|
||||
import { BaseTool, ToolCallbacks } from "./BaseTool"
|
||||
|
||||
|
|
@ -150,8 +152,12 @@ export class AttemptCompletionTool extends BaseTool<"attempt_completion"> {
|
|||
// User provided feedback - push tool result to continue the conversation
|
||||
await task.say("user_feedback", text ?? "", images)
|
||||
|
||||
const feedbackText = `The user has provided feedback on the results. Consider their input to continue the task, and then attempt completion again.\n<feedback>\n${text}\n</feedback>`
|
||||
pushToolResult(formatResponse.toolResult(feedbackText, images))
|
||||
// Get experiment setting for unified tags
|
||||
const state = await task.providerRef.deref()?.getState()
|
||||
const useUnifiedTag = experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.UNIFIED_USER_MESSAGE_TAG)
|
||||
const wrappedFeedback = wrapUserContent(text ?? "", "feedback", useUnifiedTag)
|
||||
|
||||
pushToolResult(formatResponse.toolResult(wrappedFeedback, images))
|
||||
} catch (error) {
|
||||
await handleError("inspecting site", error as Error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import { Terminal } from "../../integrations/terminal/Terminal"
|
|||
import { Package } from "../../shared/package"
|
||||
import { t } from "../../i18n"
|
||||
import { BaseTool, ToolCallbacks } from "./BaseTool"
|
||||
import { wrapUserContent } from "../../utils/userContentTags"
|
||||
import { experiments, EXPERIMENT_IDS } from "../../shared/experiments"
|
||||
|
||||
class ShellIntegrationError extends Error {}
|
||||
|
||||
|
|
@ -334,14 +336,18 @@ export async function executeCommandInTerminal(
|
|||
const { text, images } = message
|
||||
await task.say("user_feedback", text, images)
|
||||
|
||||
// Get experiment setting for unified tags
|
||||
const state = await task.providerRef.deref()?.getState()
|
||||
const useUnifiedTag = experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.UNIFIED_USER_MESSAGE_TAG)
|
||||
const wrappedFeedback = wrapUserContent(text ?? "", "feedback", useUnifiedTag)
|
||||
|
||||
return [
|
||||
true,
|
||||
formatResponse.toolResult(
|
||||
[
|
||||
`Command is still running in terminal from '${terminal.getCurrentWorkingDirectory().toPosix()}'.`,
|
||||
result.length > 0 ? `Here's the output so far:\n${result}\n` : "\n",
|
||||
`The user provided the following feedback:`,
|
||||
`<feedback>\n${text}\n</feedback>`,
|
||||
wrappedFeedback,
|
||||
].join("\n"),
|
||||
images,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
|
|||
import { parseXml } from "../../utils/xml"
|
||||
import { resolveToolProtocol } from "../../utils/resolveToolProtocol"
|
||||
import type { ToolUse } from "../../shared/tools"
|
||||
import { experiments, EXPERIMENT_IDS } from "../../shared/experiments"
|
||||
|
||||
import {
|
||||
DEFAULT_MAX_IMAGE_FILE_SIZE_MB,
|
||||
|
|
@ -343,7 +344,9 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
maxReadFileLine = -1,
|
||||
maxImageFileSize = DEFAULT_MAX_IMAGE_FILE_SIZE_MB,
|
||||
maxTotalImageSize = DEFAULT_MAX_TOTAL_IMAGE_SIZE_MB,
|
||||
experiments: stateExperiments,
|
||||
} = state ?? {}
|
||||
const useUnifiedTag = experiments.isEnabled(stateExperiments ?? {}, EXPERIMENT_IDS.UNIFIED_USER_MESSAGE_TAG)
|
||||
|
||||
for (const fileResult of fileResults) {
|
||||
if (fileResult.status !== "approved") continue
|
||||
|
|
@ -649,17 +652,17 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
const deniedWithFeedback = fileResults.find((result) => result.status === "denied" && result.feedbackText)
|
||||
|
||||
if (deniedWithFeedback && deniedWithFeedback.feedbackText) {
|
||||
statusMessage = formatResponse.toolDeniedWithFeedback(deniedWithFeedback.feedbackText)
|
||||
statusMessage = formatResponse.toolDeniedWithFeedback(deniedWithFeedback.feedbackText, toolProtocol, useUnifiedTag)
|
||||
feedbackImages = deniedWithFeedback.feedbackImages || []
|
||||
} else if (task.didRejectTool) {
|
||||
statusMessage = formatResponse.toolDenied()
|
||||
statusMessage = formatResponse.toolDenied(toolProtocol)
|
||||
} else {
|
||||
const approvedWithFeedback = fileResults.find(
|
||||
(result) => result.status === "approved" && result.feedbackText,
|
||||
)
|
||||
|
||||
if (approvedWithFeedback && approvedWithFeedback.feedbackText) {
|
||||
statusMessage = formatResponse.toolApprovedWithFeedback(approvedWithFeedback.feedbackText)
|
||||
statusMessage = formatResponse.toolApprovedWithFeedback(approvedWithFeedback.feedbackText, toolProtocol, useUnifiedTag)
|
||||
feedbackImages = approvedWithFeedback.feedbackImages || []
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export const EXPERIMENT_IDS = {
|
|||
RUN_SLASH_COMMAND: "runSlashCommand",
|
||||
MULTIPLE_NATIVE_TOOL_CALLS: "multipleNativeToolCalls",
|
||||
CUSTOM_TOOLS: "customTools",
|
||||
UNIFIED_USER_MESSAGE_TAG: "unifiedUserMessageTag",
|
||||
} as const satisfies Record<string, ExperimentId>
|
||||
|
||||
type _AssertExperimentIds = AssertEqual<Equals<ExperimentId, Values<typeof EXPERIMENT_IDS>>>
|
||||
|
|
@ -26,6 +27,7 @@ export const experimentConfigsMap: Record<ExperimentKey, ExperimentConfig> = {
|
|||
RUN_SLASH_COMMAND: { enabled: false },
|
||||
MULTIPLE_NATIVE_TOOL_CALLS: { enabled: false },
|
||||
CUSTOM_TOOLS: { enabled: false },
|
||||
UNIFIED_USER_MESSAGE_TAG: { enabled: false },
|
||||
}
|
||||
|
||||
export const experimentDefault = Object.fromEntries(
|
||||
|
|
|
|||
82
src/utils/userContentTags.ts
Normal file
82
src/utils/userContentTags.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Utilities for handling user content wrapper tags.
|
||||
*
|
||||
* When the UNIFIED_USER_MESSAGE_TAG experiment is enabled, all user content
|
||||
* (task start, feedback, answers, resume messages) uses a single <user_message> tag.
|
||||
*
|
||||
* When disabled (legacy mode), uses context-specific tags:
|
||||
* - <task> for initial task
|
||||
* - <feedback> for user feedback
|
||||
* - <answer> for follow-up question responses
|
||||
*/
|
||||
|
||||
export type UserContentContext = "task" | "feedback" | "answer" | "resume"
|
||||
|
||||
/**
|
||||
* Get the opening tag for user content based on context and experiment setting
|
||||
*/
|
||||
export function getUserContentOpenTag(context: UserContentContext, useUnifiedTag: boolean): string {
|
||||
if (useUnifiedTag) {
|
||||
return "<user_message>"
|
||||
}
|
||||
|
||||
switch (context) {
|
||||
case "task":
|
||||
return "<task>"
|
||||
case "feedback":
|
||||
return "<feedback>"
|
||||
case "answer":
|
||||
return "<answer>"
|
||||
case "resume":
|
||||
return "<user_message>"
|
||||
default:
|
||||
return "<user_message>"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the closing tag for user content based on context and experiment setting
|
||||
*/
|
||||
export function getUserContentCloseTag(context: UserContentContext, useUnifiedTag: boolean): string {
|
||||
if (useUnifiedTag) {
|
||||
return "</user_message>"
|
||||
}
|
||||
|
||||
switch (context) {
|
||||
case "task":
|
||||
return "</task>"
|
||||
case "feedback":
|
||||
return "</feedback>"
|
||||
case "answer":
|
||||
return "</answer>"
|
||||
case "resume":
|
||||
return "</user_message>"
|
||||
default:
|
||||
return "</user_message>"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap user content with appropriate tags
|
||||
*/
|
||||
export function wrapUserContent(content: string, context: UserContentContext, useUnifiedTag: boolean): string {
|
||||
const openTag = getUserContentOpenTag(context, useUnifiedTag)
|
||||
const closeTag = getUserContentCloseTag(context, useUnifiedTag)
|
||||
return `${openTag}\n${content}\n${closeTag}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if text contains any user content tags (for mention processing)
|
||||
*/
|
||||
export function hasUserContentTags(text: string, useUnifiedTag: boolean): boolean {
|
||||
if (useUnifiedTag) {
|
||||
return text.includes("<user_message>")
|
||||
}
|
||||
|
||||
return (
|
||||
text.includes("<task>") ||
|
||||
text.includes("<feedback>") ||
|
||||
text.includes("<answer>") ||
|
||||
text.includes("<user_message>")
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue