feat(ai): add Jev shadow gates (triage before, review after the LLM diagnosis)
TypeSafe System One(Jev)への最小クライアントと、診断ループに並走する shadow ゲート 2 つを追加した。triage はアラートと事前取得サンプルからラベル・ 回復中か・層を判定し、review は診断の根拠・ランブック・target を検証して best_action を選ぶ。JEV_MODE=shadow のときだけ動き、答えは ai.jev_shadow と 診断結果の jev フィールドに記録するだけで、処理の分岐は一切変えない。
This commit is contained in:
1 parent
af1cb4f6dc
commit
91cdd9ada5
6 files changed
+479
-19
No files matched your search
@@ -0,0 +1,43 @@
|
||||
package jev
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAskRoundTrip(t *testing.T) {
|
||||
var got map[string]any
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/v1/systemone" || r.Header.Get("Authorization") != "Bearer k1" {
|
||||
t.Errorf("bad request: %s %s", r.URL.Path, r.Header.Get("Authorization"))
|
||||
}
|
||||
_ = json.NewDecoder(r.Body).Decode(&got)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"model":"jev-1.13.0","answers":{"recovering":{"type":"noul","noul":0.91},"label":{"type":"choice","choice":"db_primary_down","probabilities":{"db_primary_down":0.8,"unknown":0.2},"confidence":0.6}},"usage":{"input_tokens":120,"output_tokens":4}}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
c := New(srv.URL, "", func() (string, error) { return "k1", nil })
|
||||
resp, err := c.Ask(context.Background(), map[string]any{"a": 1}, map[string]Question{
|
||||
"recovering": {Type: "noul", Instructions: "q1"},
|
||||
"label": {Type: "choice", Instructions: "q2", Criteria: map[string]string{"db_primary_down": "x", "unknown": "y"}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got["model"] != "jev-1.13.0" || got["questions"].(map[string]any)["label"].(map[string]any)["type"] != "choice" {
|
||||
t.Errorf("request body: %v", got)
|
||||
}
|
||||
if *resp.Answers["recovering"].Noul != 0.91 || resp.Answers["label"].Choice != "db_primary_down" || resp.Usage.InputTokens != 120 {
|
||||
t.Errorf("response: %+v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAskNoKey(t *testing.T) {
|
||||
c := New("http://127.0.0.1:1", "", func() (string, error) { return "", nil })
|
||||
if _, err := c.Ask(context.Background(), "s", nil); err != ErrNoKey {
|
||||
t.Errorf("want ErrNoKey, got %v", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user