feat(i18n): Enhance internationalization support for tool specifications and notifications
- Added TitleKey and DescriptionKey fields to ToolSpec for dynamic localization. - Updated tool specifications to use i18nx for titles, descriptions, and appendices. - Refactored notification messages to utilize i18nx for localization in conversation and ticket assignment events. - Improved localization in the debug dialog component for skill definitions. - Added new translation keys in English and Chinese for ticket and conversation assignment notifications. - Ensured that fallback messages are properly localized based on user locale.
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/dto"
|
||||
"agent-desk/internal/pkg/dto/request"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
"agent-desk/internal/services"
|
||||
|
||||
componenttool "github.com/cloudwego/eino/components/tool"
|
||||
@@ -89,7 +90,7 @@ func (g *CreateTicketGraph) Run(ctx context.Context, argumentsInJSON string) (st
|
||||
Handled: true,
|
||||
Terminal: true,
|
||||
Action: "ticket_created",
|
||||
ReplyText: fmt.Sprintf("Ticket created. Ticket no: %s. Title: %s.", strings.TrimSpace(item.TicketNo), strings.TrimSpace(item.Title)),
|
||||
ReplyText: i18nx.Getf(i18nx.DefaultLocale, "graph.ticketCreated", strings.TrimSpace(item.TicketNo), strings.TrimSpace(item.Title)),
|
||||
ShouldRetry: false,
|
||||
}), nil
|
||||
case ConfirmationDecisionCancel:
|
||||
@@ -134,7 +135,7 @@ func (g *CreateTicketGraph) buildCreateRequest(argumentsInJSON string) (request.
|
||||
}
|
||||
|
||||
func (g *CreateTicketGraph) buildConfirmationPrompt(req request.CreateTicketFromConversationRequest) string {
|
||||
return fmt.Sprintf("I am ready to create a ticket for you.\nTitle: %s\nDescription: %s\nPlease reply with \"Confirm\" or \"Cancel\".",
|
||||
return i18nx.Getf(i18nx.DefaultLocale, "graph.createTicketConfirmPrompt",
|
||||
strings.TrimSpace(req.Title), strings.TrimSpace(req.Description))
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"agent-desk/internal/ai/runtime/tooling"
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
"agent-desk/internal/pkg/tracex"
|
||||
"agent-desk/internal/services"
|
||||
|
||||
@@ -122,7 +123,7 @@ func (g *HandoffGraph) Run(ctx context.Context, argumentsInJSON string) (string,
|
||||
}
|
||||
|
||||
func (g *HandoffGraph) buildReason(argumentsInJSON string) (string, error) {
|
||||
reason := "The user needs human support."
|
||||
reason := i18nx.Get("graph.defaultHandoffReason")
|
||||
var args handoffGraphArgs
|
||||
if strings.TrimSpace(argumentsInJSON) != "" {
|
||||
if err := json.Unmarshal([]byte(argumentsInJSON), &args); err != nil {
|
||||
@@ -136,7 +137,7 @@ func (g *HandoffGraph) buildReason(argumentsInJSON string) (string, error) {
|
||||
}
|
||||
|
||||
func (g *HandoffGraph) buildConfirmationPrompt(reason string) string {
|
||||
return fmt.Sprintf("I am ready to connect you to a human support agent.\nReason: %s\nPlease reply with \"Confirm\" or \"Cancel\".", strings.TrimSpace(reason))
|
||||
return i18nx.Getf(i18nx.DefaultLocale, "graph.handoffConfirmPrompt", strings.TrimSpace(reason))
|
||||
}
|
||||
|
||||
func parseHandoffDecision(value string) ConfirmationDecision {
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package graphs
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
)
|
||||
|
||||
const (
|
||||
InterruptTypeTicketCreationConfirmation = "ticket_creation_confirmation"
|
||||
InterruptTypeHandoffConfirmation = "handoff_confirmation"
|
||||
ConfirmOrCancelPrompt = `Please reply with "Confirm" or "Cancel".`
|
||||
NeedExplicitConfirmationPrompt = `I need your explicit confirmation. Please reply with "Confirm" or "Cancel".`
|
||||
ConfirmationExpiredReply = "This confirmation has expired. Please start again."
|
||||
CancelCreateTicketReply = "Ticket creation has been cancelled."
|
||||
CancelHandoffReply = "Human handoff has been cancelled."
|
||||
)
|
||||
|
||||
var (
|
||||
ConfirmOrCancelPrompt = i18nx.Get("graph.confirmOrCancel")
|
||||
NeedExplicitConfirmationPrompt = i18nx.Get("graph.needExplicitConfirmation")
|
||||
ConfirmationExpiredReply = i18nx.Get("graph.confirmationExpired")
|
||||
CancelCreateTicketReply = i18nx.Get("graph.cancelCreateTicket")
|
||||
CancelHandoffReply = i18nx.Get("graph.cancelHandoff")
|
||||
)
|
||||
|
||||
type ConfirmationDecision string
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
applicationruntime "agent-desk/internal/ai/application/runtime"
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
svc "agent-desk/internal/services"
|
||||
)
|
||||
|
||||
@@ -39,7 +40,7 @@ func buildConversationInterrupt(conversation models.Conversation, message models
|
||||
|
||||
func resolveInterruptPrompt(summary *applicationruntime.Summary) string {
|
||||
if summary == nil || len(summary.Interrupts) == 0 {
|
||||
return "Please provide more information and try again."
|
||||
return i18nx.Get("conversation.interrupt.defaultPrompt")
|
||||
}
|
||||
if prompt := extractInterruptMessage(summary.Interrupts[0].InfoPreview); prompt != "" {
|
||||
return prompt
|
||||
@@ -47,7 +48,7 @@ func resolveInterruptPrompt(summary *applicationruntime.Summary) string {
|
||||
if prompt := strings.TrimSpace(summary.Interrupts[0].InfoPreview); prompt != "" {
|
||||
return prompt
|
||||
}
|
||||
return "Please provide more information and try again."
|
||||
return i18nx.Get("conversation.interrupt.defaultPrompt")
|
||||
}
|
||||
|
||||
func extractInterruptMessage(infoPreview string) string {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"agent-desk/internal/ai/runtime/graphs"
|
||||
"agent-desk/internal/ai/runtime/registry"
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
"agent-desk/internal/pkg/toolx"
|
||||
|
||||
einotool "github.com/cloudwego/eino/components/tool"
|
||||
@@ -48,7 +49,7 @@ func (t *AnalyzeConversationTool) Build(ctx registry.Context) (einotool.BaseTool
|
||||
func (t *AnalyzeConversationTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
return &schema.ToolInfo{
|
||||
Name: toolx.GraphAnalyzeConversation.Name,
|
||||
Desc: "Graph Tool. Summarizes the current conversation, identifies complaint/payment/sentiment risk signals, and recommends whether to continue answering, create a ticket, or hand off to a human.",
|
||||
Desc: i18nx.Get("tool.graph.analyzeConversation.info"),
|
||||
ParamsOneOf: schema.NewParamsOneOfByJSONSchema(&einojsonschema.Schema{
|
||||
Version: einojsonschema.Version,
|
||||
Type: "object",
|
||||
@@ -57,42 +58,42 @@ func (t *AnalyzeConversationTool) Info(ctx context.Context) (*schema.ToolInfo, e
|
||||
Key: "goal",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Analysis goal, such as whether to hand off to a human, create a ticket, or perform risk review.",
|
||||
Description: i18nx.Get("tool.graph.analyzeConversation.param.goal"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "observedIssue",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Main issue or request observed in the conversation.",
|
||||
Description: i18nx.Get("tool.graph.analyzeConversation.param.observedIssue"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "needTicket",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "boolean",
|
||||
Description: "Whether to focus on evaluating ticket creation.",
|
||||
Description: i18nx.Get("tool.graph.triageServiceRequest.param.needTicket"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "needHumanHandoff",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "boolean",
|
||||
Description: "Whether to focus on evaluating human handoff.",
|
||||
Description: i18nx.Get("tool.graph.triageServiceRequest.param.needHumanHandoff"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "needQualityCheck",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "boolean",
|
||||
Description: "Whether to focus on risk or quality review.",
|
||||
Description: i18nx.Get("tool.graph.analyzeConversation.param.needQualityCheck"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "additionalContext",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Additional context, such as disputes, complaint points, or business constraints already identified.",
|
||||
Description: i18nx.Get("tool.graph.analyzeConversation.param.additionalContext"),
|
||||
},
|
||||
},
|
||||
)),
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"agent-desk/internal/ai/runtime/graphs"
|
||||
"agent-desk/internal/ai/runtime/registry"
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
"agent-desk/internal/pkg/toolx"
|
||||
|
||||
einotool "github.com/cloudwego/eino/components/tool"
|
||||
@@ -52,7 +53,7 @@ func (t *CreateTicketGraphTool) Build(ctx registry.Context) (einotool.BaseTool,
|
||||
func (t *CreateTicketGraphTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
return &schema.ToolInfo{
|
||||
Name: toolx.GraphCreateTicketConfirm.Name,
|
||||
Desc: "Graph Tool. Handles ticket parameter preparation, user confirmation, actual ticket creation, and result return. Use only when the user explicitly asks to create a ticket and the title and description are clear.",
|
||||
Desc: i18nx.Get("tool.graph.createTicketConfirm.info"),
|
||||
ParamsOneOf: schema.NewParamsOneOfByJSONSchema(&einojsonschema.Schema{
|
||||
Version: einojsonschema.Version,
|
||||
Type: "object",
|
||||
@@ -65,14 +66,14 @@ func (t *CreateTicketGraphTool) Info(ctx context.Context) (*schema.ToolInfo, err
|
||||
Key: "title",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Ticket title. Concisely summarizes the issue.",
|
||||
Description: i18nx.Get("tool.graph.createTicketConfirm.param.title"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "description",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Ticket description. Clearly captures the user's issue, symptoms, and request.",
|
||||
Description: i18nx.Get("tool.graph.createTicketConfirm.param.description"),
|
||||
},
|
||||
},
|
||||
)),
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"agent-desk/internal/ai/runtime/graphs"
|
||||
"agent-desk/internal/ai/runtime/registry"
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
"agent-desk/internal/pkg/toolx"
|
||||
|
||||
einotool "github.com/cloudwego/eino/components/tool"
|
||||
@@ -52,7 +53,7 @@ func (t *HandoffGraphTool) Build(ctx registry.Context) (einotool.BaseTool, error
|
||||
func (t *HandoffGraphTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
return &schema.ToolInfo{
|
||||
Name: toolx.GraphHandoffConversation.Name,
|
||||
Desc: "Graph Tool. Handles handoff reason preparation, user confirmation, actual human handoff, and result return. Use only when the user explicitly asks for a human agent or you have confirmed that human handling is required. Do not repeat the call when the result has terminal=true and shouldRetry=false.",
|
||||
Desc: i18nx.Get("tool.graph.handoffConversation.info"),
|
||||
ParamsOneOf: schema.NewParamsOneOfByJSONSchema(&einojsonschema.Schema{
|
||||
Version: einojsonschema.Version,
|
||||
Type: "object",
|
||||
@@ -61,7 +62,7 @@ func (t *HandoffGraphTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
Key: "reason",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Handoff reason. Briefly explain why a human is needed, such as explicit user request, manual verification, or after-sales handling.",
|
||||
Description: i18nx.Get("tool.graph.handoffConversation.param.reason"),
|
||||
},
|
||||
},
|
||||
)),
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"agent-desk/internal/ai/runtime/graphs"
|
||||
"agent-desk/internal/ai/runtime/registry"
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
"agent-desk/internal/pkg/toolx"
|
||||
|
||||
einotool "github.com/cloudwego/eino/components/tool"
|
||||
@@ -48,7 +49,7 @@ func (t *PrepareTicketDraftTool) Build(ctx registry.Context) (einotool.BaseTool,
|
||||
func (t *PrepareTicketDraftTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
return &schema.ToolInfo{
|
||||
Name: toolx.GraphPrepareTicketDraft.Name,
|
||||
Desc: "Graph Tool. Prepares a ticket draft from the current conversation and collected information. Use it before create_ticket_with_confirmation when the ticket content needs to be organized.",
|
||||
Desc: i18nx.Get("tool.graph.prepareTicketDraft.info"),
|
||||
ParamsOneOf: schema.NewParamsOneOfByJSONSchema(&einojsonschema.Schema{
|
||||
Version: einojsonschema.Version,
|
||||
Type: "object",
|
||||
@@ -57,42 +58,42 @@ func (t *PrepareTicketDraftTool) Info(ctx context.Context) (*schema.ToolInfo, er
|
||||
Key: "title",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Prepared ticket title. Optional.",
|
||||
Description: i18nx.Get("tool.graph.prepareTicketDraft.param.title"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "description",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Prepared ticket description. Optional.",
|
||||
Description: i18nx.Get("tool.graph.prepareTicketDraft.param.description"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "issue",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "The issue or error message the user is experiencing.",
|
||||
Description: i18nx.Get("tool.graph.prepareTicketDraft.param.issue"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "impact",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Impact scope, such as unable to sign in, unable to place an order, or business interruption.",
|
||||
Description: i18nx.Get("tool.graph.prepareTicketDraft.param.impact"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "expectedOutcome",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "The user's expected outcome or request.",
|
||||
Description: i18nx.Get("tool.graph.prepareTicketDraft.param.expectedOutcome"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "currentAttempt",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "当前已尝试过的处理步骤,可选。",
|
||||
Description: i18nx.Get("tool.graph.prepareTicketDraft.param.currentAttempt"),
|
||||
},
|
||||
},
|
||||
)),
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"agent-desk/internal/ai/runtime/graphs"
|
||||
"agent-desk/internal/ai/runtime/registry"
|
||||
"agent-desk/internal/models"
|
||||
"agent-desk/internal/pkg/i18nx"
|
||||
"agent-desk/internal/pkg/toolx"
|
||||
|
||||
einotool "github.com/cloudwego/eino/components/tool"
|
||||
@@ -48,7 +49,7 @@ func (t *TriageServiceRequestTool) Build(ctx registry.Context) (einotool.BaseToo
|
||||
func (t *TriageServiceRequestTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
|
||||
return &schema.ToolInfo{
|
||||
Name: toolx.GraphTriageServiceRequest.Name,
|
||||
Desc: "Graph Tool. Analyzes the current conversation to decide whether to continue answering, prepare a ticket draft, or hand off to a human. When ticket creation is recommended, it returns a structured ticket draft suggestion.",
|
||||
Desc: i18nx.Get("tool.graph.triageServiceRequest.info"),
|
||||
ParamsOneOf: schema.NewParamsOneOfByJSONSchema(&einojsonschema.Schema{
|
||||
Version: einojsonschema.Version,
|
||||
Type: "object",
|
||||
@@ -57,35 +58,35 @@ func (t *TriageServiceRequestTool) Info(ctx context.Context) (*schema.ToolInfo,
|
||||
Key: "goal",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Analysis goal, such as whether to escalate, create a ticket, or hand off to a human.",
|
||||
Description: i18nx.Get("tool.graph.triageServiceRequest.param.goal"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "observedIssue",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Main issue or dispute observed in the conversation.",
|
||||
Description: i18nx.Get("tool.graph.triageServiceRequest.param.observedIssue"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "needTicket",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "boolean",
|
||||
Description: "Whether to focus on evaluating ticket creation.",
|
||||
Description: i18nx.Get("tool.graph.triageServiceRequest.param.needTicket"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "needHumanHandoff",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "boolean",
|
||||
Description: "Whether to focus on evaluating human handoff.",
|
||||
Description: i18nx.Get("tool.graph.triageServiceRequest.param.needHumanHandoff"),
|
||||
},
|
||||
},
|
||||
orderedmap.Pair[string, *einojsonschema.Schema]{
|
||||
Key: "additionalContext",
|
||||
Value: &einojsonschema.Schema{
|
||||
Type: "string",
|
||||
Description: "Additional context, such as risk signals or constraints already identified.",
|
||||
Description: i18nx.Get("tool.graph.triageServiceRequest.param.additionalContext"),
|
||||
},
|
||||
},
|
||||
)),
|
||||
|
||||
Reference in New Issue
Block a user