Add first turn option

This commit is contained in:
Xin Wang
2026-02-12 15:23:32 +08:00
parent 56ca95c200
commit edcbc2cec7
9 changed files with 97 additions and 24 deletions

View File

@@ -112,6 +112,7 @@ class Assistant(Base):
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), index=True)
name: Mapped[str] = mapped_column(String(255), nullable=False)
call_count: Mapped[int] = mapped_column(Integer, default=0)
first_turn_mode: Mapped[str] = mapped_column(String(32), default="bot_first")
opener: Mapped[str] = mapped_column(Text, default="")
generated_opener_enabled: Mapped[bool] = mapped_column(default=False)
prompt: Mapped[str] = mapped_column(Text, default="")

View File

@@ -20,6 +20,7 @@ def _is_siliconflow_vendor(vendor: Optional[str]) -> bool:
def _resolve_runtime_metadata(db: Session, assistant: Assistant) -> dict:
metadata = {
"systemPrompt": assistant.prompt or "",
"firstTurnMode": assistant.first_turn_mode or "bot_first",
"greeting": assistant.opener or "",
"generatedOpenerEnabled": bool(assistant.generated_opener_enabled),
"output": {"mode": "audio" if assistant.voice_output_enabled else "text"},
@@ -104,6 +105,7 @@ def assistant_to_dict(assistant: Assistant) -> dict:
"id": assistant.id,
"name": assistant.name,
"callCount": assistant.call_count,
"firstTurnMode": assistant.first_turn_mode or "bot_first",
"opener": assistant.opener or "",
"generatedOpenerEnabled": bool(assistant.generated_opener_enabled),
"prompt": assistant.prompt or "",
@@ -131,6 +133,7 @@ def assistant_to_dict(assistant: Assistant) -> dict:
def _apply_assistant_update(assistant: Assistant, update_data: dict) -> None:
field_map = {
"knowledgeBaseId": "knowledge_base_id",
"firstTurnMode": "first_turn_mode",
"interruptionSensitivity": "interruption_sensitivity",
"botCannotBeInterrupted": "bot_cannot_be_interrupted",
"configMode": "config_mode",
@@ -192,6 +195,7 @@ def create_assistant(data: AssistantCreate, db: Session = Depends(get_db)):
id=str(uuid.uuid4())[:8],
user_id=1, # 默认用户,后续添加认证
name=data.name,
first_turn_mode=data.firstTurnMode,
opener=data.opener,
generated_opener_enabled=data.generatedOpenerEnabled,
prompt=data.prompt,

View File

@@ -272,6 +272,7 @@ class ToolResourceOut(ToolResourceBase):
# ============ Assistant ============
class AssistantBase(BaseModel):
name: str
firstTurnMode: str = "bot_first"
opener: str = ""
generatedOpenerEnabled: bool = False
prompt: str = ""
@@ -300,6 +301,7 @@ class AssistantCreate(AssistantBase):
class AssistantUpdate(BaseModel):
name: Optional[str] = None
firstTurnMode: Optional[str] = None
opener: Optional[str] = None
generatedOpenerEnabled: Optional[bool] = None
prompt: Optional[str] = None

View File

@@ -38,6 +38,10 @@ def migrate_db_schema():
alter_statements.append(
"ALTER TABLE assistants ADD COLUMN generated_opener_enabled BOOLEAN DEFAULT 0"
)
if "first_turn_mode" not in columns:
alter_statements.append(
"ALTER TABLE assistants ADD COLUMN first_turn_mode VARCHAR(32) DEFAULT 'bot_first'"
)
if "bot_cannot_be_interrupted" not in columns:
alter_statements.append(
"ALTER TABLE assistants ADD COLUMN bot_cannot_be_interrupted BOOLEAN DEFAULT 0"

View File

@@ -24,6 +24,7 @@ class TestAssistantAPI:
assert data["prompt"] == sample_assistant_data["prompt"]
assert data["language"] == sample_assistant_data["language"]
assert data["voiceOutputEnabled"] is True
assert data["firstTurnMode"] == "bot_first"
assert data["generatedOpenerEnabled"] is False
assert data["botCannotBeInterrupted"] is False
assert "id" in data
@@ -230,6 +231,7 @@ class TestAssistantAPI:
def test_assistant_interrupt_and_generated_opener_flags(self, client, sample_assistant_data):
sample_assistant_data.update({
"firstTurnMode": "user_first",
"generatedOpenerEnabled": True,
"botCannotBeInterrupted": True,
"interruptionSensitivity": 900,
@@ -241,6 +243,7 @@ class TestAssistantAPI:
get_resp = client.get(f"/api/assistants/{assistant_id}")
assert get_resp.status_code == 200
payload = get_resp.json()
assert payload["firstTurnMode"] == "user_first"
assert payload["generatedOpenerEnabled"] is True
assert payload["botCannotBeInterrupted"] is True
assert payload["interruptionSensitivity"] == 900
@@ -248,6 +251,7 @@ class TestAssistantAPI:
runtime_resp = client.get(f"/api/assistants/{assistant_id}/runtime-config")
assert runtime_resp.status_code == 200
metadata = runtime_resp.json()["sessionStartMetadata"]
assert metadata["firstTurnMode"] == "user_first"
assert metadata["generatedOpenerEnabled"] is True
assert metadata["bargeIn"]["enabled"] is False
assert metadata["bargeIn"]["minDurationMs"] == 900