feat(ai): localize hitl Discord messages via HITL_LANG (en, ja)
Discord に投稿する提案・エスカレーション・期限切れ・ボタンの文言を 言語セット(en / ja)に分離し、HITL_LANG で起動時に選択できるようにした。 識別子(action id、ラベル、run id、JSON)は言語に関係なくそのまま出す。
This commit is contained in:
1 parent
8b403c54df
commit
af1cb4f6dc
3 files changed
+131
-33
No files matched your search
@@ -0,0 +1,96 @@
|
||||
package hitl
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Strings holds every user-facing text of the bot. The language is chosen once at start (HITL_LANG=en|ja).
|
||||
// Identifiers (action ids, labels, run ids, JSON) stay as they are; only the surrounding text changes.
|
||||
type Strings struct {
|
||||
ProposalTitle func(actionID string) string
|
||||
FieldRootCause string
|
||||
FieldTarget string
|
||||
FieldEvidence string
|
||||
FieldRationale string
|
||||
FieldRun string
|
||||
FieldStatus string
|
||||
FieldResult string
|
||||
FieldAlert string
|
||||
RootCauseValue func(label string, conf float64) string
|
||||
ButtonApprove string
|
||||
ButtonReject string
|
||||
StatusWaiting func(unixTS int64) string
|
||||
StatusRejected func(by string) string
|
||||
StatusExecuting func(by string) string
|
||||
StatusExecuted func(by string) string
|
||||
StatusApproveFailed func(err string) string
|
||||
StatusExecFailed func(by, err string) string
|
||||
StatusExpiredBefore string
|
||||
StatusNoDecision string
|
||||
ExpiryMessage func(actionID, target, runID, scenarioID string) string
|
||||
EscalationTitle func(label string) string
|
||||
EscalationStatus string
|
||||
ThreadRunbook string
|
||||
NotAllowed string
|
||||
Footer func(model, prompt, session string) string
|
||||
Empty string
|
||||
}
|
||||
|
||||
var langs = map[string]Strings{
|
||||
"en": {
|
||||
ProposalTitle: func(a string) string { return "Layer-2 proposal: " + a },
|
||||
FieldRootCause: "Root cause", FieldTarget: "Target", FieldEvidence: "Evidence", FieldRationale: "Rationale",
|
||||
FieldRun: "Run / scenario", FieldStatus: "Status", FieldResult: "Result", FieldAlert: "Alert",
|
||||
RootCauseValue: func(l string, c float64) string { return fmt.Sprintf("%s (confidence %.2f)", l, c) },
|
||||
ButtonApprove: "Approve", ButtonReject: "Reject",
|
||||
StatusWaiting: func(t int64) string { return fmt.Sprintf("waiting for approval until <t:%d:T>", t) },
|
||||
StatusRejected: func(by string) string { return "rejected by " + by },
|
||||
StatusExecuting: func(by string) string { return "approved by " + by + ", executing..." },
|
||||
StatusExecuted: func(by string) string { return "approved by " + by + "; executed" },
|
||||
StatusApproveFailed: func(e string) string { return "approval failed: " + e },
|
||||
StatusExecFailed: func(by, e string) string { return "approved by " + by + "; execution failed: " + e },
|
||||
StatusExpiredBefore: "expired before approval",
|
||||
StatusNoDecision: "no decision within the window; moved to layer 3",
|
||||
ExpiryMessage: func(a, t, r, s string) string {
|
||||
return fmt.Sprintf("Proposal `%s` for `%s` (run %s, scenario %s) received no decision within the approval window. Layer 3: follow the runbook or call the harness `/actions/execute` with the operator token.", a, t, r, s)
|
||||
},
|
||||
EscalationTitle: func(l string) string { return "Escalation: " + l },
|
||||
EscalationStatus: "layer 3: human decision required",
|
||||
ThreadRunbook: "Runbook:\n",
|
||||
NotAllowed: "You are not in the approver role.",
|
||||
Footer: func(m, p, s string) string { return fmt.Sprintf("model %s, prompt %s, session %s", m, p, s) },
|
||||
Empty: "-",
|
||||
},
|
||||
"ja": {
|
||||
ProposalTitle: func(a string) string { return "第2層の提案: " + a },
|
||||
FieldRootCause: "推定原因", FieldTarget: "対象", FieldEvidence: "根拠", FieldRationale: "判断理由",
|
||||
FieldRun: "Run / シナリオ", FieldStatus: "状態", FieldResult: "実行結果", FieldAlert: "アラート",
|
||||
RootCauseValue: func(l string, c float64) string { return fmt.Sprintf("%s(確信度 %.2f)", l, c) },
|
||||
ButtonApprove: "承認", ButtonReject: "却下",
|
||||
StatusWaiting: func(t int64) string { return fmt.Sprintf("承認待ち(期限 <t:%d:T>)", t) },
|
||||
StatusRejected: func(by string) string { return by + " が却下" },
|
||||
StatusExecuting: func(by string) string { return by + " が承認、実行中..." },
|
||||
StatusExecuted: func(by string) string { return by + " が承認、実行済み" },
|
||||
StatusApproveFailed: func(e string) string { return "承認の記録に失敗: " + e },
|
||||
StatusExecFailed: func(by, e string) string { return by + " が承認したが実行に失敗: " + e },
|
||||
StatusExpiredBefore: "承認前に期限切れ",
|
||||
StatusNoDecision: "期限内に判断がなかったため第3層へ引き継ぎ",
|
||||
ExpiryMessage: func(a, t, r, s string) string {
|
||||
return fmt.Sprintf("提案 `%s`(対象 `%s`、run %s、シナリオ %s)は承認期限内に判断されませんでした。第3層の対応です。ランブックに従って手動で対処するか、オペレーター用トークンでハーネスの `/actions/execute` を呼び出してください。", a, t, r, s)
|
||||
},
|
||||
EscalationTitle: func(l string) string { return "エスカレーション: " + l },
|
||||
EscalationStatus: "第3層: 人の判断が必要",
|
||||
ThreadRunbook: "ランブック:\n",
|
||||
NotAllowed: "承認ロールが付与されていません。",
|
||||
Footer: func(m, p, s string) string {
|
||||
return fmt.Sprintf("モデル %s、プロンプト %s、セッション %s", m, p, s)
|
||||
},
|
||||
Empty: "-",
|
||||
},
|
||||
}
|
||||
|
||||
// Lang returns the string set for a language code; unknown codes fall back to English.
|
||||
func Lang(code string) Strings {
|
||||
if s, ok := langs[code]; ok {
|
||||
return s
|
||||
}
|
||||
return langs["en"]
|
||||
}
|
||||
Reference in new issue
Block a user