G-ACE commited on
Commit
67b4632
·
verified ·
1 Parent(s): 8cbec40

Deploy GitHub main 5532a4ca5b8bc3ecdd0cc53b12a396ead042dea1

Browse files
.deploy/customer-ai-free-model CHANGED
@@ -1,7 +1,10 @@
1
- customerai-master-v2-completed-kb
2
- customerai-index-v2-effective-all-records
3
  free-local-model=Qwen/Qwen3-0.6B
4
- live-story-suite=100
5
- trigger=2026-07-29T18:23:00+09:00
6
- evidence=deployment-evidence/live-story-latest.json
 
 
 
7
  mode=private-space-internal-signed-routes
 
1
+ customerai-master-v2-hp-public-ai-v2
2
+ customerai-index-v2-hp-public-ai-v2
3
  free-local-model=Qwen/Qwen3-0.6B
4
+ baseline-live-story-suite=100
5
+ hp-public-live-story-suite=100
6
+ total-live-story-cases=200
7
+ hp-public-source-sha256=8c2de4259b00a4c64dc175bb76ed7187387db1c127e2f3de66fc21278490d8f5
8
+ trigger=2026-07-29T21:25:44+09:00
9
+ evidence=deployment-evidence/live-story-latest.json,deployment-evidence/hp-public-story-latest.json
10
  mode=private-space-internal-signed-routes
scripts/run_hp_public_story_suite.py ADDED
@@ -0,0 +1,369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import sys
6
+ from datetime import UTC, datetime
7
+ from pathlib import Path
8
+
9
+ import httpx
10
+
11
+ ROOT = Path(__file__).resolve().parents[1]
12
+ if str(ROOT) not in sys.path:
13
+ sys.path.insert(0, str(ROOT))
14
+
15
+ from scripts import live_story_test as base # noqa: E402
16
+
17
+ REPORT_PATH = ROOT / "test-results" / "hp-public-story-report.json"
18
+
19
+
20
+ def _build_cases() -> list[dict[str, object]]:
21
+ cases: list[dict[str, object]] = []
22
+
23
+ def add(messages: list[str], expected_terms: list[str]) -> None:
24
+ cases.extend(
25
+ {
26
+ "type": "known",
27
+ "message": message,
28
+ "expected_terms": expected_terms,
29
+ }
30
+ for message in messages
31
+ )
32
+
33
+ add(
34
+ [
35
+ "Asteraとは何ですか?",
36
+ "アステラを一言で説明して",
37
+ "外付けAI強化外装ってどういう意味?",
38
+ "Asteraは何を外側から追加するの?",
39
+ "ChatGPTを置き換える製品ですか?",
40
+ "ClaudeやGeminiをやめてAsteraだけ使うの?",
41
+ "主役AIを残したまま使えるの?",
42
+ "Asteraの一般向けの位置付けは?",
43
+ "AI強化外装という表現を詳しく説明して",
44
+ "AsteraはBrowser拡張機能のことですか?",
45
+ ],
46
+ ["外付けAI強化外装", "置き換え"],
47
+ )
48
+ add(
49
+ [
50
+ "Google V8は生成AIの名前ですか?",
51
+ "Astera v8のV8ってLLMですか?",
52
+ "V8が回答を生成するのですか?",
53
+ "Google V8は何を担当しますか?",
54
+ "V8 Runtimeと生成AI Modelの違いは?",
55
+ "Asteraの実行基盤は何ですか?",
56
+ "多重並列思考を動かすのはどの部分?",
57
+ "V8を使う理由は?",
58
+ ],
59
+ ["V8", "生成AI Model"],
60
+ )
61
+ add(
62
+ [
63
+ "多重並列思考とは何ですか?",
64
+ "8項目を全部同時に実行するの?",
65
+ "5本柱は完全同時並列ですか?",
66
+ "並列処理でも依存順序は守りますか?",
67
+ "Asteraの判断のしくみを技術的に説明して",
68
+ "FactとRiskの後に何をするの?",
69
+ "MultiとCompareはいつ動きますか?",
70
+ "多重並列という表現は誇張では?",
71
+ ],
72
+ ["並列", "依存"],
73
+ )
74
+ add(
75
+ [
76
+ "判断素材8項目を全部教えて",
77
+ "Asteraが出す8つの判断材料は?",
78
+ "判断素材の順番は固定ですか?",
79
+ "8項目は内部Moduleの一覧ですか?",
80
+ "主役AIへ渡す材料は何項目ですか?",
81
+ "Asteraの公開出力Contractは?",
82
+ "8項目の名前を順番に説明して",
83
+ "目的から再指示までの流れは?",
84
+ ],
85
+ ["本当の目的", "主役AIへの再指示"],
86
+ )
87
+
88
+ item_groups = [
89
+ (
90
+ [
91
+ "本当の目的では何を見る?",
92
+ "表面的な依頼と真の目的をどう分ける?",
93
+ "成功条件や対象者も主役AIへ渡しますか?",
94
+ ],
95
+ ["成功条件", "優先順位"],
96
+ ),
97
+ (
98
+ [
99
+ "前提不足では何を探す?",
100
+ "予算や期限がない質問はどう扱う?",
101
+ "確認質問ばかり返すの?",
102
+ ],
103
+ ["足りない条件", "確認"],
104
+ ),
105
+ (
106
+ [
107
+ "事実確認では何を分ける?",
108
+ "推測を事実として扱わないためには?",
109
+ "最新情報もAsteraだけで保証できますか?",
110
+ ],
111
+ ["事実", "未確認"],
112
+ ),
113
+ (
114
+ [
115
+ "危機察知では何を確認する?",
116
+ "法務やSecurityの危険も見る?",
117
+ "Risk候補は必ず起きるという意味?",
118
+ ],
119
+ ["Risk", "対策"],
120
+ ),
121
+ (
122
+ [
123
+ "反対視点は何のため?",
124
+ "依頼者の案を否定する機能ですか?",
125
+ "批判に耐える回答にできますか?",
126
+ ],
127
+ ["反対", "補強"],
128
+ ),
129
+ (
130
+ [
131
+ "比較案では何を並べる?",
132
+ "一つの案だけを押し付けますか?",
133
+ "安い案や安全な案も比較できますか?",
134
+ ],
135
+ ["案A", "採用条件"],
136
+ ),
137
+ (
138
+ [
139
+ "推奨判断は最終決定ですか?",
140
+ "どの案を勧めるかの理由も出ますか?",
141
+ "採用しない案の理由も分かりますか?",
142
+ ],
143
+ ["条件付き", "次の一手"],
144
+ ),
145
+ (
146
+ [
147
+ "主役AIへの再指示はどう使う?",
148
+ "もう一回考えてと頼むのと何が違う?",
149
+ "再指示に禁止事項や出力形式も入りますか?",
150
+ ],
151
+ ["再指示", "出力形式"],
152
+ ),
153
+ ]
154
+ for messages, expected_terms in item_groups:
155
+ add(messages, expected_terms)
156
+
157
+ add(
158
+ [
159
+ "判断材料はどうやってChatGPTへ渡す?",
160
+ "APIなしでもAsteraを使えますか?",
161
+ "CopyとFormの違いは?",
162
+ "自社AIへ組み込む方法は?",
163
+ "WebhookでBotへ送れますか?",
164
+ "Copy・Form・API・Webhookを使い分ける基準は?",
165
+ "今すべての連携が本番利用できますか?",
166
+ "手動利用から自動化へ移れますか?",
167
+ ],
168
+ ["Copy", "Webhook"],
169
+ )
170
+ add(
171
+ [
172
+ "Asteraを使うとAI回答が強くなる理由は?",
173
+ "前提抜けはどう減りますか?",
174
+ "事実と推測を分けると何が良い?",
175
+ "反対意見を先に見る価値は?",
176
+ "比較・検証・レビューは回答へどう効く?",
177
+ "Asteraを使えば必ず正解になりますか?",
178
+ "どのAIでも同じだけ改善しますか?",
179
+ "専門家確認は不要になりますか?",
180
+ ],
181
+ ["目的", "比較"],
182
+ )
183
+ add(
184
+ [
185
+ "HPの外付けAI強化外装とRuntime説明は矛盾しない?",
186
+ "8項目と5本柱は同じもの?",
187
+ "38 Genre LensはHPの8項目に置き換わったの?",
188
+ "一般向け説明と技術者向け説明を分けて教えて",
189
+ "HPではなぜ5本柱を前面に出さないの?",
190
+ "公開コピーとRepositoryの技術構造の関係は?",
191
+ "Asteraのブランド説明とArchitecture説明はどちらが正しい?",
192
+ ],
193
+ ["HP", "技術"],
194
+ )
195
+ add(
196
+ [
197
+ "Proプランは今も月額2,000円ですか?",
198
+ "Businessは9,800円ですか?",
199
+ "決済はStripeですか?",
200
+ "古い公開ドキュメントの料金を現在も使えますか?",
201
+ "旧KAGURAの仕様が現在のAstera正本ですか?",
202
+ "古いREADMEと最新HPが違う場合どちらを信じる?",
203
+ ],
204
+ ["最新", "正本"],
205
+ )
206
+ add(
207
+ [
208
+ "AsteraはAIですか?V8はModelですか?8項目もまとめて説明してください。",
209
+ "外付けAI強化外装、多重並列思考、主役AIへの再指示の関係を一度に説明して。",
210
+ "Asteraが主役AIを置き換えない理由と、回答が強くなる理由をまとめて。",
211
+ "HPの一般説明と5本柱・38 Lensの技術説明を初心者にも分かるように比較して。",
212
+ ],
213
+ ["主役AI"],
214
+ )
215
+ add(
216
+ [
217
+ "AIに外から材料を足す仕組みって何?",
218
+ "質問をそのまま投げず下ごしらえする機能ですか?",
219
+ "目的、抜け、事実、危険、反論、選択肢を揃えるのは何のため?",
220
+ "最後にAIへ渡すPromptまで作るの?",
221
+ ],
222
+ ["判断"],
223
+ )
224
+
225
+ cases.extend(
226
+ [
227
+ {
228
+ "type": "known",
229
+ "message": "Form、API、Webhookはもう全部完成していますか?",
230
+ "expected_terms": ["本番提供済み"],
231
+ },
232
+ {
233
+ "type": "known",
234
+ "message": "公開HPからPrivate HFへBrowserが直接接続しますか?",
235
+ "expected_terms": ["接続しません", "Cloudflare"],
236
+ },
237
+ {
238
+ "type": "known",
239
+ "message": "Webhook GatewayをCustomer AI専用に改造しましたか?",
240
+ "expected_terms": ["専用", "汎用"],
241
+ },
242
+ {
243
+ "type": "known",
244
+ "message": "KBにないHPの新説明をModel知識で補って答えますか?",
245
+ "expected_terms": ["補いません"],
246
+ },
247
+ ]
248
+ )
249
+ cases.append(
250
+ {
251
+ "type": "free_model_multi_task",
252
+ "message": (
253
+ "Asteraを初めて見る一般利用者向けに、外付けAI強化外装、Google V8、"
254
+ "判断素材8項目、主役AIへ渡す方法を一つの流れで説明し、技術者向けには"
255
+ "完全同時並列ではなく依存順序があることも補足してください。"
256
+ ),
257
+ "expected_terms": [],
258
+ }
259
+ )
260
+ if len(cases) != 100:
261
+ raise RuntimeError(f"hp_public_story_suite_count_invalid:{len(cases)}")
262
+ return cases
263
+
264
+
265
+ def main() -> None:
266
+ if not base.HF_TOKEN:
267
+ raise SystemExit("HF_TOKEN_MISSING")
268
+
269
+ api = base.HfApi(token=base.HF_TOKEN)
270
+ base_url = base._private_space_base_url(api)
271
+ github_sha = os.environ.get("GITHUB_SHA", "manual")
272
+ payload = {
273
+ "run_token": (
274
+ f"hp{os.environ.get('GITHUB_RUN_ID', 'manual')}"
275
+ f"{int(base.time.time())}"
276
+ ),
277
+ "cases": _build_cases(),
278
+ }
279
+ REPORT_PATH.parent.mkdir(parents=True, exist_ok=True)
280
+
281
+ try:
282
+ with httpx.Client(
283
+ timeout=httpx.Timeout(1200.0, connect=60.0),
284
+ follow_redirects=True,
285
+ ) as client:
286
+ response = client.post(
287
+ f"{base_url}/internal/self-test/run",
288
+ json=payload,
289
+ headers={
290
+ "authorization": f"Bearer {base.HF_TOKEN}",
291
+ "x-deployed-github-commit": github_sha,
292
+ "content-type": "application/json",
293
+ },
294
+ )
295
+ if response.status_code != 200:
296
+ failure = {
297
+ "accepted": False,
298
+ "total": 0,
299
+ "passed": 0,
300
+ "failed": 0,
301
+ "score_percent": 0.0,
302
+ "free_model_invoked": False,
303
+ "failure_stage": "hp_public_private_space_self_test_request",
304
+ "http_status": response.status_code,
305
+ "response": response.text[:10000],
306
+ "space_id": base.SPACE_ID,
307
+ "github_sha": github_sha,
308
+ "finished_at": datetime.now(UTC).isoformat(),
309
+ }
310
+ REPORT_PATH.write_text(
311
+ json.dumps(failure, ensure_ascii=False, indent=2),
312
+ encoding="utf-8",
313
+ )
314
+ print(json.dumps(failure, ensure_ascii=False, indent=2))
315
+ raise SystemExit("HP_PUBLIC_PRIVATE_SPACE_SELF_TEST_REQUEST_FAILED")
316
+ report = response.json()
317
+ except Exception as error:
318
+ if not REPORT_PATH.exists():
319
+ failure = {
320
+ "accepted": False,
321
+ "total": 0,
322
+ "passed": 0,
323
+ "failed": 0,
324
+ "score_percent": 0.0,
325
+ "free_model_invoked": False,
326
+ "failure_stage": "hp_public_private_space_self_test_transport",
327
+ "error": f"{type(error).__name__}:{error}",
328
+ "space_id": base.SPACE_ID,
329
+ "github_sha": github_sha,
330
+ "finished_at": datetime.now(UTC).isoformat(),
331
+ }
332
+ REPORT_PATH.write_text(
333
+ json.dumps(failure, ensure_ascii=False, indent=2),
334
+ encoding="utf-8",
335
+ )
336
+ print(json.dumps(failure, ensure_ascii=False, indent=2))
337
+ raise
338
+
339
+ report.update(
340
+ {
341
+ "suite": "hp-public-ai-v2",
342
+ "source_sha256": "8c2de4259b00a4c64dc175bb76ed7187387db1c127e2f3de66fc21278490d8f5",
343
+ "space_id": base.SPACE_ID,
344
+ "base_url": base_url,
345
+ "github_sha": github_sha,
346
+ "verification_mode": "private_space_hp_public_kb_story",
347
+ }
348
+ )
349
+ REPORT_PATH.write_text(
350
+ json.dumps(report, ensure_ascii=False, indent=2),
351
+ encoding="utf-8",
352
+ )
353
+ print(json.dumps(report, ensure_ascii=False, indent=2))
354
+ if not report.get("accepted"):
355
+ raise SystemExit(
356
+ "HP_PUBLIC_LIVE_STORY_FAILED "
357
+ f"passed={report.get('passed')} total={report.get('total')} "
358
+ f"score={report.get('score_percent')}"
359
+ )
360
+ print(
361
+ "HP_PUBLIC_LIVE_STORY_OK "
362
+ f"passed={report['passed']} total={report['total']} "
363
+ f"score={report['score_percent']:.2f} "
364
+ f"model_invoked={report['free_model_invoked']}"
365
+ )
366
+
367
+
368
+ if __name__ == "__main__":
369
+ main()