feat(agent): add opt-in show thinking toggle for Agent v2 chat (#45427)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-11-03 09:49:33 +00:00
1 parent 891340169a
commit 28dabd92ac
67 files changed
+407 -27

No files matched your search

+1
View File
@@ -475,6 +475,7 @@ class Parameters(BaseModel):
speech_to_text: FeatureToggleObject
text_to_speech: TextToSpeechObject
retriever_resource: FeatureToggleObject
show_thoughts: FeatureToggleObject = Field(default_factory=lambda: {"enabled": False})
annotation_reply: FeatureToggleObject
more_like_this: FeatureToggleObject
user_input_form: UserInputFormList
@@ -24,6 +24,7 @@ class AppParametersDict(TypedDict):
speech_to_text: FeatureToggleDict
text_to_speech: FeatureToggleDict
retriever_resource: FeatureToggleDict
show_thoughts: FeatureToggleDict
annotation_reply: FeatureToggleDict
more_like_this: FeatureToggleDict
user_input_form: list[dict[str, Any]]
@@ -36,7 +37,9 @@ def get_parameters_from_feature_dict(
*, features_dict: Mapping[str, Any], user_input_form: list[dict[str, Any]]
) -> AppParametersDict:
"""
Mapping from feature dict to webapp parameters
Map a feature mapping and input form to webapp parameters without mutating either.
Missing or null show_thoughts is exposed as disabled for legacy configurations.
"""
return {
"opening_statement": features_dict.get("opening_statement"),
@@ -45,6 +48,7 @@ def get_parameters_from_feature_dict(
"speech_to_text": features_dict.get("speech_to_text", {"enabled": False}),
"text_to_speech": features_dict.get("text_to_speech", {"enabled": False}),
"retriever_resource": features_dict.get("retriever_resource", {"enabled": False}),
"show_thoughts": features_dict.get("show_thoughts") or {"enabled": False},
"annotation_reply": features_dict.get("annotation_reply", {"enabled": False}),
"more_like_this": features_dict.get("more_like_this", {"enabled": False}),
"user_input_form": user_input_form,
+2
View File
@@ -606,6 +606,8 @@ class AgentSoulAppFeaturesConfig(AgentFlexibleConfig):
speech_to_text: AgentFeatureToggleConfig | None = None
text_to_speech: AgentTextToSpeechFeatureConfig | None = None
retriever_resource: AgentFeatureToggleConfig | None = None
# Missing or null preserves the default of hiding model thoughts in chat.
show_thoughts: AgentFeatureToggleConfig | None = None
sensitive_word_avoidance: AgentSensitiveWordAvoidanceFeatureConfig | None = None
file_upload: AgentFileUploadFeatureConfig = Field(default_factory=AgentFileUploadFeatureConfig)
+2
View File
@@ -20753,6 +20753,7 @@ Visibility and lifecycle scope of an Agent record.
| opening_statement | string | | No |
| retriever_resource | [AgentFeatureToggleConfig](#agentfeaturetoggleconfig) | | No |
| sensitive_word_avoidance | [AgentSensitiveWordAvoidanceFeatureConfig](#agentsensitivewordavoidancefeatureconfig) | | No |
| show_thoughts | [AgentFeatureToggleConfig](#agentfeaturetoggleconfig) | | No |
| speech_to_text | [AgentFeatureToggleConfig](#agentfeaturetoggleconfig) | | No |
| suggested_questions | [ string ] | | No |
| suggested_questions_after_answer | [AgentSuggestedQuestionsAfterAnswerFeatureConfig](#agentsuggestedquestionsafteranswerfeatureconfig) | | No |
@@ -32215,6 +32216,7 @@ Enum class for parameter type.
| opening_statement | | | No |
| retriever_resource | { **"enabled"**: boolean } | | Yes |
| sensitive_word_avoidance | { **"enabled"**: boolean } | | Yes |
| show_thoughts | { **"enabled"**: boolean } | | No |
| speech_to_text | { **"enabled"**: boolean } | | Yes |
| suggested_questions | [ string ] | | Yes |
| suggested_questions_after_answer | { **"enabled"**: boolean } | | Yes |
+1
View File
@@ -7380,6 +7380,7 @@ Form input definition.
| opening_statement | | | No |
| retriever_resource | { **"enabled"**: boolean } | | Yes |
| sensitive_word_avoidance | { **"enabled"**: boolean } | | Yes |
| show_thoughts | { **"enabled"**: boolean } | | No |
| speech_to_text | { **"enabled"**: boolean } | | Yes |
| suggested_questions | [ string ] | | Yes |
| suggested_questions_after_answer | { **"enabled"**: boolean } | | Yes |
+1
View File
@@ -2071,6 +2071,7 @@ Form input definition.
| opening_statement | | | No |
| retriever_resource | { **"enabled"**: boolean } | | Yes |
| sensitive_word_avoidance | { **"enabled"**: boolean } | | Yes |
| show_thoughts | { **"enabled"**: boolean } | | No |
| speech_to_text | { **"enabled"**: boolean } | | Yes |
| suggested_questions | [ string ] | | Yes |
| suggested_questions_after_answer | { **"enabled"**: boolean } | | Yes |
@@ -1,5 +1,7 @@
from unittest.mock import patch
import pytest
from controllers.common.fields import Parameters, Site
from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict
from models.model import IconType
@@ -13,6 +15,22 @@ def test_parameters_model_round_trip() -> None:
assert model.model_dump(mode="json") == parameters
@pytest.mark.parametrize("enabled", [False, True])
def test_parameters_serializes_show_thoughts(enabled: bool) -> None:
parameters = get_parameters_from_feature_dict(
features_dict={"show_thoughts": {"enabled": enabled}}, user_input_form=[]
)
assert Parameters.model_validate(parameters).model_dump(mode="json")["show_thoughts"] == {"enabled": enabled}
def test_parameters_defaults_show_thoughts_for_legacy_payload() -> None:
parameters = dict(get_parameters_from_feature_dict(features_dict={}, user_input_form=[]))
parameters.pop("show_thoughts")
assert Parameters.model_validate(parameters).model_dump(mode="json")["show_thoughts"] == {"enabled": False}
def test_site_icon_url_uses_signed_url_for_image_icon() -> None:
site = Site(
title="Example",
@@ -490,6 +490,7 @@ def test_migrated_saved_message_and_parameter_handlers_dispatch_through_full_adm
"retriever_resource",
"annotation_reply",
"more_like_this",
"show_thoughts",
"sensitive_word_avoidance",
"file_upload",
)
@@ -2490,6 +2490,7 @@ class TestTrialPreviewCases:
"retriever_resource": {"enabled": False},
"annotation_reply": {"enabled": False},
"more_like_this": {"enabled": False},
"show_thoughts": {"enabled": False},
"user_input_form": _INPUT_FORM,
"sensitive_word_avoidance": {"enabled": False, "type": "", "configs": []},
"file_upload": {"enabled": False, "number_limits": 0},
@@ -21,6 +21,15 @@ type _DefaultedFeatureKey = Literal[
class TestGetParametersFromFeatureDict:
"""Test suite for get_parameters_from_feature_dict"""
@pytest.mark.parametrize(
("features", "enabled"),
[({}, False), ({"show_thoughts": None}, False), ({"show_thoughts": {"enabled": True}}, True)],
)
def test_show_thoughts_parameters(self, features: dict[str, object], enabled: bool) -> None:
result = parameters_mapping.get_parameters_from_feature_dict(features_dict=features, user_input_form=[])
assert result["show_thoughts"] == {"enabled": enabled}
@pytest.fixture
def mock_config(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Override file limits on the shared typed config."""
@@ -4,6 +4,7 @@ from pydantic import ValidationError
from core.workflow.file_reference import build_file_reference
from models.agent_config_entities import (
AgentKnowledgeSpaceConfig,
AgentSoulAppFeaturesConfig,
AgentSoulConfig,
AgentSoulKnowledgeConfig,
AgentSoulModelSettings,
@@ -16,6 +17,23 @@ from models.agent_config_entities import (
)
@pytest.mark.parametrize("payload", [{}, {"show_thoughts": None}, {"show_thoughts": {}}])
def test_show_thoughts_defaults_to_disabled(payload: dict[str, object]) -> None:
features = AgentSoulAppFeaturesConfig.model_validate(payload)
assert features.show_thoughts is None or features.show_thoughts.enabled is False
@pytest.mark.parametrize("enabled", [False, True])
def test_show_thoughts_round_trips_in_agent_soul(enabled: bool) -> None:
soul = AgentSoulConfig.model_validate({"app_features": {"show_thoughts": {"enabled": enabled}}})
restored = AgentSoulConfig.model_validate_json(soul.model_dump_json())
assert restored.app_features.show_thoughts is not None
assert restored.app_features.show_thoughts.enabled is enabled
def test_agent_soul_model_settings_preserves_plugin_declared_parameters() -> None:
settings = AgentSoulModelSettings.model_validate(
{
-10
View File
@@ -1032,16 +1032,6 @@
"count": 91
}
},
"web/app/components/base/chat/chat/answer/agent-roster-response-content.tsx": {
"better-tailwindcss/enforce-logical-properties": {
"count": 2
}
},
"web/app/components/base/chat/chat/answer/index.tsx": {
"better-tailwindcss/enforce-logical-properties": {
"count": 7
}
},
"web/app/components/base/chat/chat/answer/more.tsx": {
"better-tailwindcss/enforce-logical-properties": {
"count": 3
@@ -1581,6 +1581,7 @@ export type AgentSoulAppFeaturesConfig = {
opening_statement?: string | null
retriever_resource?: AgentFeatureToggleConfig | null
sensitive_word_avoidance?: AgentSensitiveWordAvoidanceFeatureConfig | null
show_thoughts?: AgentFeatureToggleConfig | null
speech_to_text?: AgentFeatureToggleConfig | null
suggested_questions?: Array<string> | null
suggested_questions_after_answer?: AgentSuggestedQuestionsAfterAnswerFeatureConfig | null
@@ -3133,6 +3133,7 @@ export const zAgentSoulAppFeaturesConfig = z.object({
opening_statement: z.string().nullish(),
retriever_resource: zAgentFeatureToggleConfig.nullish(),
sensitive_word_avoidance: zAgentSensitiveWordAvoidanceFeatureConfig.nullish(),
show_thoughts: zAgentFeatureToggleConfig.nullish(),
speech_to_text: zAgentFeatureToggleConfig.nullish(),
suggested_questions: z.array(z.string()).nullish(),
suggested_questions_after_answer: zAgentSuggestedQuestionsAfterAnswerFeatureConfig.nullish(),
@@ -3525,6 +3525,7 @@ export type AgentSoulAppFeaturesConfig = {
opening_statement?: string | null
retriever_resource?: AgentFeatureToggleConfig | null
sensitive_word_avoidance?: AgentSensitiveWordAvoidanceFeatureConfig | null
show_thoughts?: AgentFeatureToggleConfig | null
speech_to_text?: AgentFeatureToggleConfig | null
suggested_questions?: Array<string> | null
suggested_questions_after_answer?: AgentSuggestedQuestionsAfterAnswerFeatureConfig | null
@@ -6090,6 +6090,7 @@ export const zAgentSoulAppFeaturesConfig = z.object({
opening_statement: z.string().nullish(),
retriever_resource: zAgentFeatureToggleConfig.nullish(),
sensitive_word_avoidance: zAgentSensitiveWordAvoidanceFeatureConfig.nullish(),
show_thoughts: zAgentFeatureToggleConfig.nullish(),
speech_to_text: zAgentFeatureToggleConfig.nullish(),
suggested_questions: z.array(z.string()).nullish(),
suggested_questions_after_answer: zAgentSuggestedQuestionsAfterAnswerFeatureConfig.nullish(),
@@ -299,6 +299,9 @@ export type Parameters = {
sensitive_word_avoidance: {
enabled?: boolean
}
show_thoughts?: {
enabled?: boolean
}
speech_to_text: {
enabled?: boolean
}
@@ -609,6 +609,11 @@ export const zParameters = z.object({
sensitive_word_avoidance: z.object({
enabled: z.boolean().optional(),
}),
show_thoughts: z
.object({
enabled: z.boolean().optional(),
})
.optional(),
speech_to_text: z.object({
enabled: z.boolean().optional(),
}),
@@ -628,6 +628,7 @@ export type AgentSoulAppFeaturesConfig = {
opening_statement?: string | null
retriever_resource?: AgentFeatureToggleConfig | null
sensitive_word_avoidance?: AgentSensitiveWordAvoidanceFeatureConfig | null
show_thoughts?: AgentFeatureToggleConfig | null
speech_to_text?: AgentFeatureToggleConfig | null
suggested_questions?: Array<string> | null
suggested_questions_after_answer?: AgentSuggestedQuestionsAfterAnswerFeatureConfig | null
@@ -1546,6 +1546,7 @@ export const zAgentSoulAppFeaturesConfig = z.object({
opening_statement: z.string().nullish(),
retriever_resource: zAgentFeatureToggleConfig.nullish(),
sensitive_word_avoidance: zAgentSensitiveWordAvoidanceFeatureConfig.nullish(),
show_thoughts: zAgentFeatureToggleConfig.nullish(),
speech_to_text: zAgentFeatureToggleConfig.nullish(),
suggested_questions: z.array(z.string()).nullish(),
suggested_questions_after_answer: zAgentSuggestedQuestionsAfterAnswerFeatureConfig.nullish(),
@@ -339,6 +339,9 @@ export type Parameters = {
sensitive_word_avoidance: {
enabled?: boolean
}
show_thoughts?: {
enabled?: boolean
}
speech_to_text: {
enabled?: boolean
}
@@ -1007,6 +1010,7 @@ export type AgentSoulAppFeaturesConfig = {
opening_statement?: string | null
retriever_resource?: AgentFeatureToggleConfig | null
sensitive_word_avoidance?: AgentSensitiveWordAvoidanceFeatureConfig | null
show_thoughts?: AgentFeatureToggleConfig | null
speech_to_text?: AgentFeatureToggleConfig | null
suggested_questions?: Array<string> | null
suggested_questions_after_answer?: AgentSuggestedQuestionsAfterAnswerFeatureConfig | null
@@ -896,6 +896,11 @@ export const zParameters = z.object({
sensitive_word_avoidance: z.object({
enabled: z.boolean().optional(),
}),
show_thoughts: z
.object({
enabled: z.boolean().optional(),
})
.optional(),
speech_to_text: z.object({
enabled: z.boolean().optional(),
}),
@@ -1936,6 +1941,7 @@ export const zAgentSoulAppFeaturesConfig = z.object({
opening_statement: z.string().nullish(),
retriever_resource: zAgentFeatureToggleConfig.nullish(),
sensitive_word_avoidance: zAgentSensitiveWordAvoidanceFeatureConfig.nullish(),
show_thoughts: zAgentFeatureToggleConfig.nullish(),
speech_to_text: zAgentFeatureToggleConfig.nullish(),
suggested_questions: z.array(z.string()).nullish(),
suggested_questions_after_answer: zAgentSuggestedQuestionsAfterAnswerFeatureConfig.nullish(),
+3
View File
@@ -3484,6 +3484,9 @@ export type Parameters = {
sensitive_word_avoidance: {
enabled?: boolean
}
show_thoughts?: {
enabled?: boolean
}
speech_to_text: {
enabled?: boolean
}
+5
View File
@@ -4966,6 +4966,11 @@ export const zParameters = z.object({
sensitive_word_avoidance: z.object({
enabled: z.boolean().optional(),
}),
show_thoughts: z
.object({
enabled: z.boolean().optional(),
})
.optional(),
speech_to_text: z.object({
enabled: z.boolean().optional(),
}),
+3
View File
@@ -705,6 +705,9 @@ export type Parameters = {
sensitive_word_avoidance: {
enabled?: boolean
}
show_thoughts?: {
enabled?: boolean
}
speech_to_text: {
enabled?: boolean
}
+5
View File
@@ -1458,6 +1458,11 @@ export const zParameters = z.object({
sensitive_word_avoidance: z.object({
enabled: z.boolean().optional(),
}),
show_thoughts: z
.object({
enabled: z.boolean().optional(),
})
.optional(),
speech_to_text: z.object({
enabled: z.boolean().optional(),
}),
@@ -42,6 +42,53 @@ const thinkingOnlyItem = {
} satisfies ChatItem
describe('AgentRosterResponseContent', () => {
it('shows trimmed plain-text thoughts in collapsed history activity only when enabled', async () => {
const user = userEvent.setup()
const thought = {
...thinkingOnlyItem.agent_response_parts[0]!.thought,
thought: ' \n<think>First</think>\n**Second** &amp;\n ',
}
const item: ChatItem = {
...thinkingOnlyItem,
agent_response_parts: undefined,
agent_thoughts: [thought],
}
const { rerender } = render(<AgentRosterResponseContent item={item} />)
expect(screen.queryByRole('button', { name: 'Thinking' })).not.toBeInTheDocument()
rerender(<AgentRosterResponseContent item={item} showThoughts />)
const toggle = screen.getByRole('button', { name: 'Thinking' })
expect(toggle).toHaveAttribute('aria-expanded', 'false')
await user.click(toggle)
const text = screen.getByText('<think>First</think> **Second** &amp;')
expect(text.textContent).toBe('<think>First</think>\n**Second** &amp;')
expect(text.children).toHaveLength(0)
})
it('collapses enabled live thoughts once they become history', async () => {
const user = userEvent.setup()
const { rerender } = render(
<AgentRosterResponseContent item={thinkingOnlyItem} responding showThoughts />,
)
expect(screen.getByText('internal thought should not render')).toBeVisible()
rerender(
<AgentRosterResponseContent
item={{
...thinkingOnlyItem,
agent_response_parts: undefined,
agent_thoughts: [thinkingOnlyItem.agent_response_parts[0]!.thought],
}}
showThoughts
/>,
)
expect(screen.getByRole('button', { name: 'Thinking' })).toHaveAttribute(
'aria-expanded',
'false',
)
await user.click(screen.getByRole('button', { name: 'Thinking' }))
expect(await screen.findByText('internal thought should not render')).toBeVisible()
})
it('renders a verified receipt as a working in-answer link, but not a forged receipt', async () => {
const user = userEvent.setup()
const receiptId = `kfs_${'a'.repeat(32)}`
@@ -80,6 +80,27 @@ describe('Answer Component', () => {
expect(screen.getByText('streamed answer')).toHaveTextContent('streamed answer')
})
it.each([true, false])(
'should pass the configured show thoughts setting (%s) to custom agent content',
(enabled) => {
render(
<Answer
{...defaultProps}
item={{
id: 'msg-with-parts',
content: '',
isAnswer: true,
agent_response_parts: [{ type: 'message', content: 'streamed answer' }],
}}
config={{ show_thoughts: { enabled } } as ComponentProps<typeof Answer>['config']}
renderAgentContent={({ showThoughts }) => <p>{`thoughts ${showThoughts}`}</p>}
/>,
)
expect(screen.getByText(`thoughts ${enabled}`)).toBeInTheDocument()
},
)
it('should render annotation edit title', async () => {
render(
<Answer
@@ -14,6 +14,7 @@ type AgentRosterResponseContentProps = {
item: ChatItem
responding?: boolean
content?: string
showThoughts?: boolean
}
const SHELL_TOOL_NAMES = new Set(['shell_run', 'shell_wait', 'shell_input', 'shell_interrupt'])
@@ -108,11 +109,13 @@ function hashString(value: string) {
return (hash >>> 0).toString(36)
}
function hasVisibleActivity(thought: ThoughtItem) {
return !!thought.tool || !!thought.message_files?.length
function hasVisibleActivity(thought: ThoughtItem, showThoughts: boolean) {
return (
(showThoughts && !!thought.thought?.trim()) || !!thought.tool || !!thought.message_files?.length
)
}
function getAgentActivityEntries(item: ChatItem): AgentActivityEntry[] {
function getAgentActivityEntries(item: ChatItem, showThoughts: boolean): AgentActivityEntry[] {
if (item.agent_response_parts?.length) {
const keyOccurrences = new Map<string, number>()
@@ -128,7 +131,7 @@ function getAgentActivityEntries(item: ChatItem): AgentActivityEntry[] {
if (part.type === 'message')
return part.content ? [{ type: 'message', content: part.content, key }] : []
return hasVisibleActivity(part.thought)
return hasVisibleActivity(part.thought, showThoughts)
? [{ type: 'thought', thought: part.thought, key }]
: []
})
@@ -142,7 +145,7 @@ function getAgentActivityEntries(item: ChatItem): AgentActivityEntry[] {
const answer = thought.answer
if (answer?.trim()) parts.push({ type: 'message', content: answer, key: `message-${key}` })
if (hasVisibleActivity(thought))
if (hasVisibleActivity(thought, showThoughts))
parts.push({ type: 'thought', thought, key: `thought-${key}` })
return parts
@@ -218,7 +221,7 @@ function ToolActivityItem({ tool }: { tool: ToolActivity }) {
<div className="flex w-full max-w-full min-w-0 flex-col items-start">
{hasDetails ? (
<Collapsible className="w-full max-w-full items-start">
<CollapsibleTrigger className="group/tool flex h-6 min-h-0 max-w-full touch-manipulation items-center justify-start gap-0 rounded-md p-1 text-left system-xs-medium text-text-tertiary select-none hover:bg-state-base-hover hover:text-text-primary focus-visible:bg-state-base-hover data-panel-open:text-text-primary">
<CollapsibleTrigger className="group/tool flex h-6 min-h-0 max-w-full touch-manipulation items-center justify-start gap-0 rounded-md p-1 text-start system-xs-medium text-text-tertiary select-none hover:bg-state-base-hover hover:text-text-primary focus-visible:bg-state-base-hover data-panel-open:text-text-primary">
{content}
</CollapsibleTrigger>
<CollapsiblePanel className="w-full max-w-full">
@@ -258,15 +261,22 @@ function ToolActivityItem({ tool }: { tool: ToolActivity }) {
function AgentActivityItem({
thought,
responding,
showThoughts,
}: {
thought: ThoughtItem
responding?: boolean
showThoughts: boolean
}) {
const locale = useLocale()
const tools = getToolActivities(thought, locale, responding)
return (
<div className="flex w-full max-w-full min-w-0 flex-col py-0.5">
{showThoughts && !!thought.thought?.trim() && (
<div className="px-1 body-md-regular wrap-break-word whitespace-pre-wrap text-text-secondary">
{thought.thought.trim()}
</div>
)}
{tools.map((tool) => (
<ToolActivityItem key={`${getThoughtKey(thought)}-${tool.key}`} tool={tool} />
))}
@@ -288,11 +298,13 @@ function AgentActivityDisclosure({
entries,
responding,
defaultOpen,
showThoughts,
}: {
item: ChatItem
entries: AgentActivityEntry[]
responding?: boolean
defaultOpen?: boolean
showThoughts: boolean
}) {
const { t } = useTranslation(['agentV2'])
const workingDuration = useWorkingDuration(responding)
@@ -309,7 +321,7 @@ function AgentActivityDisclosure({
<Collapsible className="w-full max-w-full items-start gap-1" defaultOpen={defaultOpen}>
<CollapsibleTrigger
aria-label={title}
className="group/thinking flex h-6 min-h-0 max-w-full touch-manipulation items-center justify-start gap-1 rounded-md p-1 text-left system-xs-medium text-text-tertiary select-none hover:bg-state-base-hover hover:text-text-primary focus-visible:bg-state-base-hover data-panel-open:text-text-primary"
className="group/thinking flex h-6 min-h-0 max-w-full touch-manipulation items-center justify-start gap-1 rounded-md p-1 text-start system-xs-medium text-text-tertiary select-none hover:bg-state-base-hover hover:text-text-primary focus-visible:bg-state-base-hover data-panel-open:text-text-primary"
>
<span>{thinking}</span>
{duration && (
@@ -332,7 +344,12 @@ function AgentActivityDisclosure({
content={resolveKnowledgeCitationLinks(entry.content, item.citation)}
/>
) : (
<AgentActivityItem key={entry.key} thought={entry.thought} responding={responding} />
<AgentActivityItem
key={entry.key}
thought={entry.thought}
responding={responding}
showThoughts={showThoughts}
/>
),
)}
</div>
@@ -345,6 +362,7 @@ export function AgentRosterResponseContent({
item,
responding,
content,
showThoughts = false,
}: AgentRosterResponseContentProps) {
if (item.annotation?.logAnnotation) {
return (
@@ -355,7 +373,7 @@ export function AgentRosterResponseContent({
)
}
const entries = getAgentActivityEntries(item)
const entries = getAgentActivityEntries(item, showThoughts)
const hasLiveResponseParts = !!item.agent_response_parts?.length
const hasThinkingStatus =
entries.length === 0 && !!item.agent_response_parts?.some((part) => part.type === 'thought')
@@ -381,6 +399,7 @@ export function AgentRosterResponseContent({
item={item}
entries={entries}
responding={responding}
showThoughts={showThoughts}
defaultOpen={hasLiveResponseParts && (!!responding || entries.length > 0)}
/>
)}
@@ -42,6 +42,7 @@ type AnswerProps = {
item: ChatItem
responding?: boolean
content?: string
showThoughts?: boolean
}) => ReactNode
onHumanInputFormSubmit?: (formToken: string, formData: HumanInputFormSubmitData) => Promise<void>
}
@@ -143,7 +144,12 @@ const Answer: FC<AnswerProps> = ({
const contentIsEmpty = typeof content === 'string' && content.trim() === ''
const agentContentNode = renderAgentContent ? (
renderAgentContent({ item, responding, content })
renderAgentContent({
item,
responding,
content,
showThoughts: !!config?.show_thoughts?.enabled,
})
) : (
<AgentContent item={item} responding={responding} content={content} />
)
@@ -163,21 +169,21 @@ const Answer: FC<AnswerProps> = ({
<div className="relative size-10 shrink-0">
{answerIcon || <AnswerIcon />}
{responding && (
<div className="absolute -top-0.75 -left-0.75 flex h-4 w-4 items-center rounded-full border-[0.5px] border-divider-subtle bg-background-section-burn pl-1.5 shadow-xs">
<div className="absolute -inset-s-0.75 -top-0.75 flex h-4 w-4 items-center rounded-full border-[0.5px] border-divider-subtle bg-background-section-burn ps-1.5 shadow-xs">
<LoadingAnim type="avatar" />
</div>
)}
</div>
)}
<div
className="chat-answer-container group ml-4 w-0 grow pb-4"
className="chat-answer-container group ms-4 w-0 grow pb-4"
ref={containerRef}
data-testid="chat-answer-container"
>
{/* Block 1: Workflow Process + Human Input Forms */}
{hasHumanInputs && (
<div
className={cn('group relative pr-10', chatAnswerContainerInner)}
className={cn('group relative pe-10', chatAnswerContainerInner)}
data-testid="chat-answer-container-humaninput"
>
<div
@@ -240,8 +246,8 @@ const Answer: FC<AnswerProps> = ({
{/* Block 2: Response Content (when human inputs exist) */}
{hasHumanInputs && (responding || !contentIsEmpty || hasAgentContent || hasReasoning) && (
<div className={cn('group relative mt-2 pr-10', chatAnswerContainerInner)}>
<div className="absolute -top-2 left-6 h-3 w-0.5 bg-chat-answer-human-input-form-divider-bg" />
<div className={cn('group relative mt-2 pe-10', chatAnswerContainerInner)}>
<div className="absolute inset-s-6 -top-2 h-3 w-0.5 bg-chat-answer-human-input-form-divider-bg" />
<div
ref={contentRef}
className="relative inline-block w-full max-w-full rounded-2xl bg-chat-bubble-bg px-4 py-3 body-lg-regular text-text-primary"
@@ -312,7 +318,7 @@ const Answer: FC<AnswerProps> = ({
{/* Original single block layout (when no human inputs) */}
{!hasHumanInputs && (
<div
className={cn('group relative pr-10', chatAnswerContainerInner)}
className={cn('group relative pe-10', chatAnswerContainerInner)}
data-testid="chat-answer-container-inner"
>
<div
@@ -84,6 +84,7 @@ export type ChatProps = {
item: ChatItem
responding?: boolean
content?: string
showThoughts?: boolean
}) => ReactNode
onHumanInputFormSubmit?: (formToken: string, formData: HumanInputFormSubmitData) => Promise<void>
getHumanInputNodeData?: (nodeID: string) => Node<HumanInputNodeType> | undefined
@@ -124,6 +124,13 @@ describe('NewFeaturePanel', () => {
}
})
it('does not offer thinking display in the shared application feature panel', () => {
renderPanel({ isChatMode: true, inWorkflow: false })
expect(
screen.queryByRole('switch', { name: 'appDebug.feature.showThoughts.title' }),
).not.toBeInTheDocument()
})
describe('Chat Mode Features', () => {
it('should render speech-to-text in chat mode when model is available', () => {
renderPanel({ isChatMode: true })
@@ -15,6 +15,7 @@ import { FollowUp } from '@/app/components/base/features/new-feature-panel/follo
import ImageUpload from '@/app/components/base/features/new-feature-panel/image-upload'
import Moderation from '@/app/components/base/features/new-feature-panel/moderation'
import MoreLikeThis from '@/app/components/base/features/new-feature-panel/more-like-this'
import ShowThoughts from '@/app/components/base/features/new-feature-panel/show-thoughts'
import SpeechToText from '@/app/components/base/features/new-feature-panel/speech-to-text'
import TextToSpeech from '@/app/components/base/features/new-feature-panel/text-to-speech'
import {
@@ -33,6 +34,7 @@ type Props = Readonly<{
onClose: () => void
inWorkflow?: boolean
showFileUpload?: boolean
showThoughtsToggle?: boolean
showModeration?: boolean
showAnnotationReply?: boolean
promptVariables?: PromptVariable[]
@@ -51,6 +53,7 @@ const NewFeaturePanel = ({
onClose,
inWorkflow = true,
showFileUpload = true,
showThoughtsToggle = false,
showModeration = true,
showAnnotationReply = true,
promptVariables,
@@ -114,6 +117,9 @@ const NewFeaturePanel = ({
{showFileUpload && isChatMode && <FileUpload disabled={disabled} onChange={onChange} />}
{showFileUpload && !isChatMode && <ImageUpload disabled={disabled} onChange={onChange} />}
{isChatMode && <Citation disabled={disabled} onChange={onChange} />}
{isChatMode && showThoughtsToggle && (
<ShowThoughts disabled={disabled} onChange={onChange} />
)}
{showModeration && (isChatMode || !inWorkflow) && (
<Moderation disabled={disabled} onChange={onChange} />
)}
@@ -0,0 +1,55 @@
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { produce } from 'immer'
import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
import { FeatureEnum } from '@/app/components/base/features/types'
type Props = Readonly<{
disabled?: boolean
onChange?: OnFeaturesChange
}>
const ShowThoughts = ({ disabled, onChange }: Props) => {
const { t } = useTranslation(['appDebug'])
const features = useFeatures((s) => s.features)
const featuresStore = useFeaturesStore()
const handleChange = useCallback(
(type: FeatureEnum, enabled: boolean) => {
const { features, setFeatures } = featuresStore!.getState()
const newFeatures = produce(features, (draft) => {
draft[type] = {
...draft[type],
enabled,
}
})
setFeatures(newFeatures)
if (onChange) onChange(newFeatures)
},
[featuresStore, onChange],
)
return (
<FeatureCard
icon={
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs">
<span
aria-hidden
className="i-ri-lightbulb-flash-line size-4 text-text-primary-on-surface"
/>
</div>
}
title={t(($) => $['feature.showThoughts.title'], { ns: 'appDebug' })}
value={!!features.showThoughts?.enabled}
description={t(($) => $['feature.showThoughts.description'], { ns: 'appDebug' })!}
onChange={(state) => handleChange(FeatureEnum.showThoughts, state)}
disabled={disabled}
/>
)
}
export default ShowThoughts
@@ -40,6 +40,9 @@ export const createFeaturesStore = (initProps?: Partial<FeaturesState>) => {
citation: {
enabled: false,
},
showThoughts: {
enabled: false,
},
moderation: {
enabled: false,
},
@@ -84,6 +84,7 @@ export const FeatureEnum = {
text2speech: 'text2speech',
speech2text: 'speech2text',
citation: 'citation',
showThoughts: 'showThoughts',
moderation: 'moderation',
file: 'file',
annotationReply: 'annotationReply',
@@ -98,6 +99,7 @@ export type Features = {
[FeatureEnum.text2speech]?: TextToSpeech
[FeatureEnum.speech2text]?: EnabledOrDisabled
[FeatureEnum.citation]?: EnabledOrDisabled
[FeatureEnum.showThoughts]?: EnabledOrDisabled
[FeatureEnum.moderation]?: SensitiveWordAvoidance
[FeatureEnum.file]?: FileUpload
[FeatureEnum.annotationReply]?: AnnotationReplyConfig
@@ -58,6 +58,36 @@ function renderPanel(snapshot: AgentSoulAppFeaturesConfig, draft = snapshot, dis
}
describe('AgentChatFeaturesPanel', () => {
it('defaults thinking display off and saves toggles without changing citations', async () => {
const user = userEvent.setup()
const { store } = renderPanel({ retriever_resource: { enabled: true } })
const toggle = screen.getByRole('switch', { name: 'appDebug.feature.showThoughts.title' })
expect(toggle).not.toBeChecked()
await user.click(toggle)
expect(toggle).toBeChecked()
expect(store.get(agentComposerAppFeaturesAtom)?.show_thoughts).toEqual({ enabled: true })
expect(store.get(agentComposerAppFeaturesAtom)?.retriever_resource).toEqual({ enabled: true })
await user.click(toggle)
expect(toggle).not.toBeChecked()
expect(store.get(agentComposerAppFeaturesAtom)?.show_thoughts).toEqual({ enabled: false })
})
it('shows the published thinking setting read-only without changing the draft', async () => {
const user = userEvent.setup()
const { store } = renderPanel(
{ show_thoughts: { enabled: true } },
{ show_thoughts: { enabled: false } },
true,
)
const toggle = screen.getByRole('switch', { name: 'appDebug.feature.showThoughts.title' })
expect(toggle).toBeChecked()
expect(toggle).toHaveAttribute('aria-disabled', 'true')
await user.click(toggle)
expect(store.get(agentComposerAppFeaturesAtom)?.show_thoughts).toEqual({ enabled: false })
})
it('keeps a newly saved opener enabled before the server snapshot catches up', async () => {
const user = userEvent.setup({ skipHover: true })
const { updateSnapshot, store } = renderPanel({ opening_statement: '' })
@@ -271,6 +271,41 @@ describe('Agent conversation history', () => {
},
)
it.each([false, true])(
'uses the configured show thoughts setting (%s) in preview',
async (enabled) => {
messages.set('conversation-1', [
createMessage({
agent_thoughts: [
{
id: 'thought-setting',
tool_labels: {},
files: [],
message_id: 'message-0',
thought: 'Model reasoning from history',
answer: 'Public progress',
tool: '',
tool_input: '',
observation: '',
position: 1,
},
],
}),
])
renderChat({
conversationId: 'conversation-1',
agentSoulConfig: { schema_version: 1, app_features: { show_thoughts: { enabled } } },
})
const toggle = await screen.findByRole('button', {
name: new RegExp(`${prefix}.answer.thinking`),
})
expect(toggle).toHaveAttribute('aria-expanded', 'false')
await userEvent.setup().click(toggle)
if (enabled) expect(await screen.findByText('Model reasoning from history')).toBeVisible()
else expect(screen.queryByText('Model reasoning from history')).not.toBeInTheDocument()
},
)
it('shows historical thought answers and localized tool activity', async () => {
const user = userEvent.setup()
messages.set('conversation-1', [
@@ -222,6 +222,7 @@ export const buildChatConfig = ({
more_like_this: { enabled: false },
text_to_speech: toEnabledConfig(appFeatures.text_to_speech) as ChatConfig['text_to_speech'],
speech_to_text: toEnabledConfig(appFeatures.speech_to_text),
show_thoughts: toEnabledConfig(appFeatures.show_thoughts),
retriever_resource: toEnabledConfig(appFeatures.retriever_resource),
sensitive_word_avoidance: toEnabledConfig(appFeatures.sensitive_word_avoidance),
annotation_reply: {
@@ -31,6 +31,7 @@ const defaultFeatureState: Features = {
text2speech: { enabled: false },
speech2text: { enabled: false },
citation: { enabled: false },
showThoughts: { enabled: false },
moderation: { enabled: false },
file: {
enabled: false,
@@ -101,6 +102,7 @@ function toPanelFeatures(appFeatures?: AgentSoulAppFeaturesConfig): Features {
defaultFeatureState.text2speech,
speech2text: appFeatures?.speech_to_text ?? defaultFeatureState.speech2text,
citation: appFeatures?.retriever_resource ?? defaultFeatureState.citation,
showThoughts: appFeatures?.show_thoughts ?? defaultFeatureState.showThoughts,
moderation:
(appFeatures?.sensitive_word_avoidance as Features['moderation'] | undefined) ??
defaultFeatureState.moderation,
@@ -126,6 +128,7 @@ function toAppFeatures(
text_to_speech: features.text2speech as AgentSoulAppFeaturesConfig['text_to_speech'],
speech_to_text: features.speech2text,
retriever_resource: features.citation,
show_thoughts: features.showThoughts,
file_upload: toAgentFileUploadFeatureConfig(features.file),
}
}
@@ -156,6 +159,7 @@ function AgentChatFeaturesPanelContent({
isChatMode
disabled={!!disabled}
inWorkflow={false}
showThoughtsToggle
showModeration={false}
showAnnotationReply={false}
drawerClassName="bg-components-panel-bg! data-[swipe-direction=right]:top-1! data-[swipe-direction=right]:right-0! data-[swipe-direction=right]:bottom-1! data-[swipe-direction=right]:rounded-r-none!"
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "توليد نصوص متعددة في وقت واحد، ثم تحريرها ومتابعة التوليد",
"feature.moreLikeThis.tip": "سيؤدي استخدام هذه الميزة إلى تكبد نفقات إضافية للرموز",
"feature.moreLikeThis.title": "المزيد مثل هذا",
"feature.showThoughts.description": "اعرض محتوى تفكير النموذج في المحادثات.",
"feature.showThoughts.title": "إظهار عملية التفكير",
"feature.speechToText.description": "يمكن استخدام الإدخال الصوتي في الدردشة.",
"feature.speechToText.title": "تحويل الكلام إلى نص",
"feature.suggestedQuestionsAfterAnswer.description": "يمكن أن يعطي إعداد اقتراح الأسئلة التالية للمستخدمين دردشة أفضل.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Eyni anda bir neçə mətn yaradın, sonra redaktə edin və yaratmağa davam edin",
"feature.moreLikeThis.tip": "Bu funksiyadan istifadə əlavə token sərfiyyatına səbəb olacaq",
"feature.moreLikeThis.title": "Buna bənzər daha çox mətn",
"feature.showThoughts.description": "Söhbətlərdə modelin düşüncə məzmununu göstərin.",
"feature.showThoughts.title": "Düşüncə prosesini göstər",
"feature.speechToText.description": "Söhbətdə səsli daxiletmədən istifadə etmək olar.",
"feature.speechToText.title": "Səsin mətnə çevrilməsi",
"feature.suggestedQuestionsAfterAnswer.description": "Növbəti sual təkliflərinin qurulması istifadəçilərin söhbət təcrübəsini yaxşılaşdıra bilər.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Mehrere Texte gleichzeitig generieren und dann bearbeiten und weiter generieren",
"feature.moreLikeThis.tip": "Die Verwendung dieser Funktion verursacht zusätzliche Token-Kosten",
"feature.moreLikeThis.title": "Mehr davon",
"feature.showThoughts.description": "Zeigt den Gedankengang des Modells in Gesprächen an.",
"feature.showThoughts.title": "Gedankengang anzeigen",
"feature.speechToText.description": "Einmal aktiviert, können Sie Spracheingabe verwenden.",
"feature.speechToText.title": "Sprache zu Text",
"feature.suggestedQuestionsAfterAnswer.description": "Das Einrichten von Vorschlägen für nächste Fragen kann den Chat für Benutzer verbessern.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Generate multiple texts at once, and then edit and continue to generate",
"feature.moreLikeThis.tip": "Using this feature will incur additional tokens overhead",
"feature.moreLikeThis.title": "More like this",
"feature.showThoughts.description": "Display the model’s thinking in conversations.",
"feature.showThoughts.title": "Show thinking",
"feature.speechToText.description": "Voice input can be used in chat.",
"feature.speechToText.title": "Speech to Text",
"feature.suggestedQuestionsAfterAnswer.description": "Setting up next questions suggestion can give users a better chat.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Genera múltiples textos a la vez, luego edítalos y continúa generando",
"feature.moreLikeThis.tip": "Usar esta función incurrirá en un costo adicional de tokens",
"feature.moreLikeThis.title": "Más como esto",
"feature.showThoughts.description": "Muestra el razonamiento del modelo en las conversaciones.",
"feature.showThoughts.title": "Mostrar razonamiento",
"feature.speechToText.description": "Una vez habilitado, puedes usar la entrada de voz.",
"feature.speechToText.title": "Voz a Texto",
"feature.suggestedQuestionsAfterAnswer.description": "Configurar sugerencias de próximas preguntas puede proporcionar una mejor conversación.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "تولید چندین متن به طور همزمان، و سپس ویرایش و ادامه تولید",
"feature.moreLikeThis.tip": "استفاده از این ویژگی هزینه‌های اضافی توکن‌ها را به همراه دارد",
"feature.moreLikeThis.title": "بیشتر از این",
"feature.showThoughts.description": "محتوای تفکر مدل را در گفتگوها نمایش دهید.",
"feature.showThoughts.title": "نمایش روند تفکر",
"feature.speechToText.description": "پس از فعال شدن، می‌توانید از ورودی صوتی استفاده کنید.",
"feature.speechToText.title": "تبدیل گفتار به متن",
"feature.suggestedQuestionsAfterAnswer.description": "تنظیم پیشنهاد سوالات بعدی می‌تواند به کاربران یک چت بهتر ارائه دهد.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Générez plusieurs textes à la fois, puis modifiez et continuez à générer",
"feature.moreLikeThis.tip": "L'utilisation de cette fonctionnalité entraînera un surcoût de tokens supplémentaires",
"feature.moreLikeThis.title": "Plus comme ça",
"feature.showThoughts.description": "Affichez le raisonnement du modèle dans les conversations.",
"feature.showThoughts.title": "Afficher le raisonnement",
"feature.speechToText.description": "Une fois activé, vous pouvez utiliser l'entrée vocale.",
"feature.speechToText.title": "Discours en Texte",
"feature.suggestedQuestionsAfterAnswer.description": "La configuration de la suggestion des prochaines questions peut offrir aux utilisateurs une meilleure discussion.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "एक बार में कई पाठ उत्पन्न करें, और फिर संपादित करें और जारी रखें",
"feature.moreLikeThis.tip": "इस सुविधा का उपयोग करने से अतिरिक्त टोकन खर्च होगा",
"feature.moreLikeThis.title": "ऐसा और",
"feature.showThoughts.description": "बातचीत में मॉडल की सोचने की प्रक्रिया दिखाएँ।",
"feature.showThoughts.title": "सोचने की प्रक्रिया दिखाएँ",
"feature.speechToText.description": "सक्रिय होने पर, आप वॉयस इनपुट का उपयोग कर सकते हैं।",
"feature.speechToText.title": "वाक् से पाठ",
"feature.suggestedQuestionsAfterAnswer.description": "अगले प्रश्न सुझाव सेट करना उपयोगकर्ताओं को बेहतर चैट दे सकता है।",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Buat beberapa teks sekaligus, lalu edit dan lanjutkan membuat",
"feature.moreLikeThis.tip": "Menggunakan fitur ini akan dikenakan overhead token tambahan",
"feature.moreLikeThis.title": "Lebih seperti ini",
"feature.showThoughts.description": "Tampilkan isi pemikiran model dalam percakapan.",
"feature.showThoughts.title": "Tampilkan proses berpikir",
"feature.speechToText.description": "Input suara dapat digunakan dalam obrolan.",
"feature.speechToText.title": "Ucapan ke Teks",
"feature.suggestedQuestionsAfterAnswer.description": "Menyiapkan saran pertanyaan berikutnya dapat memberi pengguna obrolan yang lebih baik.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Genera più testi contemporaneamente, poi modifica e continua a generare",
"feature.moreLikeThis.tip": "L'utilizzo di questa funzione comporterà un costo aggiuntivo di token",
"feature.moreLikeThis.title": "Altri simili",
"feature.showThoughts.description": "Mostra il ragionamento del modello nelle conversazioni.",
"feature.showThoughts.title": "Mostra ragionamento",
"feature.speechToText.description": "Una volta abilitato, puoi usare l'input vocale.",
"feature.speechToText.title": "Da voce a testo",
"feature.suggestedQuestionsAfterAnswer.description": "Impostare suggerimenti per le prossime domande può offrire agli utenti una chat migliore.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "一度に複数のテキストを生成し、編集して生成を続ける",
"feature.moreLikeThis.tip": "この機能を使用すると、追加のトークンオーバーヘッドが発生します",
"feature.moreLikeThis.title": "これに似たもの",
"feature.showThoughts.description": "会話中にモデルの思考内容を表示します。",
"feature.showThoughts.title": "思考過程を表示",
"feature.speechToText.description": "有効にすると、音声入力を使用できます。",
"feature.speechToText.title": "音声からテキストへ",
"feature.suggestedQuestionsAfterAnswer.description": "次の質問の提案を設定すると、ユーザーにより良いチャットが提供されます。",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "여러 텍스트를 한 번에 생성하고 편집하여 계속해서 생성합니다.",
"feature.moreLikeThis.tip": "이 기능을 사용하면 추가적인 토큰 오버헤드가 발생합니다",
"feature.moreLikeThis.title": "유사한 항목",
"feature.showThoughts.description": "대화에서 모델의 사고 내용을 표시합니다.",
"feature.showThoughts.title": "사고 과정 표시",
"feature.speechToText.description": "활성화하면 음성 입력을 사용할 수 있습니다.",
"feature.speechToText.title": "음성에서 텍스트로",
"feature.suggestedQuestionsAfterAnswer.description": "다음 질문 제안을 설정하면 사용자에게 더 나은 채팅이 제공됩니다.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "ສ້າງຫຼາຍຂໍ້ຄວາມພ້ອມກັນ, ຈາກນັ້ນແກ້ໄຂ ແລະ ສ້າງຕໍ່",
"feature.moreLikeThis.tip": "ການໃຊ້ຄຸນສົມບັດນີ້ຈະມີຄ່າໃຊ້ຈ່າຍ tokens ເພີ່ມເຕີມ",
"feature.moreLikeThis.title": "ຂໍ້ຄວາມທີ່ຄ້າຍຄືກັນນີ້",
"feature.showThoughts.description": "ສະແດງເນື້ອຫາການຄິດຂອງໂມເດລໃນການສົນທະນາ.",
"feature.showThoughts.title": "ສະແດງຂະບວນການຄິດ",
"feature.speechToText.description": "ສາມາດໃຊ້ການປ້ອນຂໍ້ມູນດ້ວຍສຽງໃນການສົນທະນາໄດ້.",
"feature.speechToText.title": "ປ່ຽນສຽງເປັນຂໍ້ຄວາມ",
"feature.suggestedQuestionsAfterAnswer.description": "ການຕັ້ງຄ່າຄຳຖາມແນະນຳຖັດໄປຈະຊ່ວຍໃຫ້ຜູ້ໃຊ້ມີການສົນທະນາທີ່ດີຂຶ້ນ.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Generate multiple texts at once, and then edit and continue to generate",
"feature.moreLikeThis.tip": "Using this feature will incur additional tokens overhead",
"feature.moreLikeThis.title": "More like this",
"feature.showThoughts.description": "Toon het denkproces van het model in gesprekken.",
"feature.showThoughts.title": "Denkproces tonen",
"feature.speechToText.description": "Voice input can be used in chat.",
"feature.speechToText.title": "Speech to Text",
"feature.suggestedQuestionsAfterAnswer.description": "Setting up next questions suggestion can give users a better chat.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Generuj wiele tekstów na raz, a następnie edytuj i kontynuuj generowanie",
"feature.moreLikeThis.tip": "Korzystanie z tej funkcji spowoduje dodatkowe zużycie tokenów",
"feature.moreLikeThis.title": "Więcej takich jak ten",
"feature.showThoughts.description": "Wyświetlaj tok rozumowania modelu w rozmowach.",
"feature.showThoughts.title": "Pokaż tok rozumowania",
"feature.speechToText.description": "Po włączeniu można używać wprowadzania głosowego.",
"feature.speechToText.title": "Mowa na tekst",
"feature.suggestedQuestionsAfterAnswer.description": "Ustawienie kolejnych pytań może poprawić czat.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Gere vários textos de uma vez e, em seguida, edite e continue a gerar",
"feature.moreLikeThis.tip": "Usar esse recurso incorrerá em sobrecarga adicional de tokens",
"feature.moreLikeThis.title": "Mais como isso",
"feature.showThoughts.description": "Exiba o raciocínio do modelo nas conversas.",
"feature.showThoughts.title": "Mostrar raciocínio",
"feature.speechToText.description": "Uma vez ativado, você pode usar entrada de voz.",
"feature.speechToText.title": "Fala para Texto",
"feature.suggestedQuestionsAfterAnswer.description": "Configurar sugestões de próximas perguntas pode proporcionar um melhor chat aos usuários.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Generați mai multe texte o dată, apoi editați și continuați să generați",
"feature.moreLikeThis.tip": "Utilizarea acestei funcții va genera un consum suplimentar de jetoane",
"feature.moreLikeThis.title": "Mai multe ca aceasta",
"feature.showThoughts.description": "Afișează raționamentul modelului în conversații.",
"feature.showThoughts.title": "Afișează raționamentul",
"feature.speechToText.description": "După activare, puteți utiliza intrarea vocală.",
"feature.speechToText.title": "Voce la text",
"feature.suggestedQuestionsAfterAnswer.description": "Setarea sugestiilor pentru întrebările următoare poate oferi utilizatorilor o conversație mai bună.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Сгенерируйте несколько текстов одновременно, а затем отредактируйте и продолжайте генерировать",
"feature.moreLikeThis.tip": "Использование этой функции приведет к дополнительным расходам токенов",
"feature.moreLikeThis.title": "Больше похожего",
"feature.showThoughts.description": "Показывать рассуждения модели в диалогах.",
"feature.showThoughts.title": "Показывать рассуждения",
"feature.speechToText.description": "После включения вы можете использовать голосовой ввод.",
"feature.speechToText.title": "Преобразование речи в текст",
"feature.suggestedQuestionsAfterAnswer.description": "Настройка предложения следующих вопросов может улучшить чат для пользователей.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Ustvari več besedil naenkrat, nato pa jih urejaj in nadaljuj z ustvarjanjem.",
"feature.moreLikeThis.tip": "Uporaba te funkcije povzroča dodatno porabo žetonov.",
"feature.moreLikeThis.title": "Več takšnih",
"feature.showThoughts.description": "Prikaži razmišljanje modela v pogovorih.",
"feature.showThoughts.title": "Prikaži razmišljanje",
"feature.speechToText.description": "Ko je omogočeno, lahko uporabljaš glasovni vnos.",
"feature.speechToText.title": "Govor v besedilo",
"feature.suggestedQuestionsAfterAnswer.description": "Nastavitev predlogov za naslednja vprašanja lahko uporabnikom izboljša klepet.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "สร้างข้อความหลายข้อความพร้อมกัน จากนั้นแก้ไขและสร้างต่อไป",
"feature.moreLikeThis.tip": "การใช้คุณสมบัตินี้จะมีค่าใช้จ่ายโทเค็นเพิ่มเติม",
"feature.moreLikeThis.title": "เพิ่มเติมเช่นนี้",
"feature.showThoughts.description": "แสดงเนื้อหาการคิดของโมเดลในการสนทนา",
"feature.showThoughts.title": "แสดงกระบวนการคิด",
"feature.speechToText.description": "สามารถใช้การป้อนข้อมูลด้วยเสียงในการแชทได้",
"feature.speechToText.title": "คําพูดเป็นข้อความ",
"feature.suggestedQuestionsAfterAnswer.description": "การตั้งค่าคําแนะนําคําถามถัดไปจะช่วยให้ผู้ใช้แชทได้ดีขึ้น",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Birden fazla metni bir kerede üretin, ardından düzenleyin ve üretmeye devam edin",
"feature.moreLikeThis.tip": "Bu özelliği kullanmak ek token maliyetine yol açacaktır",
"feature.moreLikeThis.title": "Bunun gibi daha fazlası",
"feature.showThoughts.description": "Sohbetlerde modelin düşünme içeriğini gösterir.",
"feature.showThoughts.title": "Düşünme sürecini göster",
"feature.speechToText.description": "Etkinleştirildiğinde, sesli giriş kullanabilirsiniz.",
"feature.speechToText.title": "Sesten Metne",
"feature.suggestedQuestionsAfterAnswer.description": "Sonraki soru önerilerini ayarlamak, kullanıcılara daha iyi bir sohbet deneyimi sunabilir.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Згенерувати кілька текстів одночасно, а потім редагувати та продовжити генерацію",
"feature.moreLikeThis.tip": "Використання цієї функції призведе до додаткових витрат токенів",
"feature.moreLikeThis.title": "Більше такого",
"feature.showThoughts.description": "Показувати міркування моделі в розмовах.",
"feature.showThoughts.title": "Показувати міркування",
"feature.speechToText.description": "Після увімкнення ви можете використовувати голосовий ввід.",
"feature.speechToText.title": "Мовлення в текст",
"feature.suggestedQuestionsAfterAnswer.description": "Налаштування пропозицій наступних запитань може надати користувачам кращий чат.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "Tạo nhiều văn bản cùng một lúc, sau đó chỉnh sửa và tiếp tục tạo ra.",
"feature.moreLikeThis.tip": "Sử dụng tính năng này sẽ tiêu tốn thêm token.",
"feature.moreLikeThis.title": "Thêm tương tự",
"feature.showThoughts.description": "Hiển thị nội dung suy nghĩ của mô hình trong cuộc trò chuyện.",
"feature.showThoughts.title": "Hiển thị quá trình suy nghĩ",
"feature.speechToText.description": "Khi được bật, bạn có thể sử dụng đầu vào bằng giọng nói.",
"feature.speechToText.title": "Chuyển đổi giọng nói thành văn bản",
"feature.suggestedQuestionsAfterAnswer.description": "Thiết lập đề xuất câu hỏi tiếp theo có thể tạo ra cuộc trò chuyện tốt hơn cho người dùng.",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "一次生成多条文本,可在此基础上编辑并继续生成",
"feature.moreLikeThis.tip": "使用此功能将会额外消耗 tokens",
"feature.moreLikeThis.title": "更多类似的",
"feature.showThoughts.description": "在对话中展示模型的思考内容。",
"feature.showThoughts.title": "显示思考过程",
"feature.speechToText.description": "您可以使用语音输入。",
"feature.speechToText.title": "语音转文字",
"feature.suggestedQuestionsAfterAnswer.description": "设置下一步问题建议可以让用户更好的对话。",
+2
View File
@@ -95,6 +95,8 @@
"feature.moreLikeThis.description": "一次生成多條文字,可在此基礎上編輯並繼續生成",
"feature.moreLikeThis.tip": "使用此功能將會額外消耗 tokens",
"feature.moreLikeThis.title": "更多類似的",
"feature.showThoughts.description": "在對話中展示模型的思考內容。",
"feature.showThoughts.title": "顯示思考過程",
"feature.speechToText.description": "啟用後,您可以使用語音輸入。",
"feature.speechToText.title": "語音轉文字",
"feature.suggestedQuestionsAfterAnswer.description": "設定下一步問題建議可以讓使用者更好的對話。",
+2
View File
@@ -1091,6 +1091,8 @@ export default interface Resources {
'feature.moreLikeThis.description': 'Generate multiple texts at once, and then edit and continue to generate'
'feature.moreLikeThis.tip': 'Using this feature will incur additional tokens overhead'
'feature.moreLikeThis.title': 'More like this'
'feature.showThoughts.description': 'Display the model’s thinking in conversations.'
'feature.showThoughts.title': 'Show thinking'
'feature.speechToText.description': 'Voice input can be used in chat.'
'feature.speechToText.title': 'Speech to Text'
'feature.suggestedQuestionsAfterAnswer.description': 'Setting up next questions suggestion can give users a better chat.'
+3
View File
@@ -261,6 +261,9 @@ export type ModelConfig = {
language?: string
autoPlay?: TtsAutoPlay
}
show_thoughts?: {
enabled: boolean
}
retriever_resource: {
enabled: boolean
}