create-workframe 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/SECURITY.md +3 -3
- package/bin/create-workframe.js +3 -3
- package/package.json +1 -1
- package/workframe-api/README.md +3 -5
- package/workframe-api/concierge.py +173 -0
- package/workframe-api/llm_error_glossary.py +236 -0
- package/workframe-api/llm_proxy.py +3 -0
- package/workframe-api/openrouter_catalog.py +114 -0
- package/workframe-api/package.json +1 -1
- package/workframe-api/server.py +144 -48
- package/workframe-ui/public/assets/{arc-COAT3laO.js → arc-CRhulRPr.js} +1 -1
- package/workframe-ui/public/assets/architecture-7EHR7CIX-CwxC-UJz.js +1 -0
- package/workframe-ui/public/assets/{architectureDiagram-3BPJPVTR-BFjWV24l.js → architectureDiagram-3BPJPVTR-B1Gq5onc.js} +1 -1
- package/workframe-ui/public/assets/{blockDiagram-GPEHLZMM-DSQLPfrj.js → blockDiagram-GPEHLZMM-DtXEetq-.js} +1 -1
- package/workframe-ui/public/assets/{c4Diagram-AAUBKEIU-DKEHv1t2.js → c4Diagram-AAUBKEIU-Bw7NEN3_.js} +1 -1
- package/workframe-ui/public/assets/channel-BaZSQvmW.js +1 -0
- package/workframe-ui/public/assets/{chunk-2J33WTMH-DHZg-DUi.js → chunk-2J33WTMH-91lObBre.js} +1 -1
- package/workframe-ui/public/assets/{chunk-3OPIFGDE-BB-OYTfp.js → chunk-3OPIFGDE-D5IopWdW.js} +1 -1
- package/workframe-ui/public/assets/{chunk-4BX2VUAB-C93q0YIm.js → chunk-4BX2VUAB-DRHbh4Yd.js} +1 -1
- package/workframe-ui/public/assets/{chunk-55IACEB6-MAYniqik.js → chunk-55IACEB6-DcfKoh86.js} +1 -1
- package/workframe-ui/public/assets/{chunk-5ZQYHXKU-ChgN6YJs.js → chunk-5ZQYHXKU-BMtcWXOU.js} +1 -1
- package/workframe-ui/public/assets/{chunk-727SXJPM-B_FYwdAv.js → chunk-727SXJPM-BW7tTfej.js} +1 -1
- package/workframe-ui/public/assets/{chunk-AQP2D5EJ-1_Hw_h1A.js → chunk-AQP2D5EJ-CGoSQAgm.js} +1 -1
- package/workframe-ui/public/assets/{chunk-BSJP7CBP-CFiDQ1Rv.js → chunk-BSJP7CBP-RW1Jng9K.js} +1 -1
- package/workframe-ui/public/assets/{chunk-CSCIHK7Q-DZ9UMTlB.js → chunk-CSCIHK7Q-D8PwFfuF.js} +1 -1
- package/workframe-ui/public/assets/{chunk-FMBD7UC4-DlMlyFgw.js → chunk-FMBD7UC4-rUp_DSZ2.js} +1 -1
- package/workframe-ui/public/assets/{chunk-KSCS5N6A-DHXtQ_Hf.js → chunk-KSCS5N6A-C3eMeGne.js} +1 -1
- package/workframe-ui/public/assets/{chunk-L5ZTLDWV-CuQzg-QG.js → chunk-L5ZTLDWV-DaE5LwXn.js} +1 -1
- package/workframe-ui/public/assets/{chunk-LZXEDZCA-BHzjzCGg.js → chunk-LZXEDZCA-Cmn67nL3.js} +2 -2
- package/workframe-ui/public/assets/{chunk-ND2GUHAM-DHXx05n2.js → chunk-ND2GUHAM-Bg-FPAN5.js} +1 -1
- package/workframe-ui/public/assets/{chunk-NZK2D7GU-CV5pmDM_.js → chunk-NZK2D7GU-orlL5R9g.js} +1 -1
- package/workframe-ui/public/assets/{chunk-O5CBEL6O-6tkCHxsV.js → chunk-O5CBEL6O-BaPyh9SK.js} +1 -1
- package/workframe-ui/public/assets/chunk-QZHKN3VN-DXcsnu-x.js +1 -0
- package/workframe-ui/public/assets/chunk-WU5MYG2G-B2O0DZxu.js +1 -0
- package/workframe-ui/public/assets/{chunk-XPW4576I-BClwIiCp.js → chunk-XPW4576I-CXYFE8tT.js} +1 -1
- package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-C_TyUBYX.js +1 -0
- package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-C_TyUBYX.js +1 -0
- package/workframe-ui/public/assets/{cose-bilkent-S5V4N54A-DOrGV6DQ.js → cose-bilkent-S5V4N54A-DDzKMTbp.js} +1 -1
- package/workframe-ui/public/assets/{dagre-BM42HDAG-DXTPvJkX.js → dagre-BM42HDAG-DCa6EvS3.js} +1 -1
- package/workframe-ui/public/assets/{diagram-2AECGRRQ-xX_v-pbf.js → diagram-2AECGRRQ-C-WIQoE_.js} +1 -1
- package/workframe-ui/public/assets/{diagram-5GNKFQAL-Cd2pXbBe.js → diagram-5GNKFQAL-UDk1nRH6.js} +1 -1
- package/workframe-ui/public/assets/{diagram-KO2AKTUF-Df3XvUtk.js → diagram-KO2AKTUF-DjLxUTPx.js} +1 -1
- package/workframe-ui/public/assets/{diagram-LMA3HP47-CsijIPaD.js → diagram-LMA3HP47-DNA9GSwJ.js} +1 -1
- package/workframe-ui/public/assets/{diagram-OG6HWLK6-aq5fmfHd.js → diagram-OG6HWLK6-DO2nQu2f.js} +1 -1
- package/workframe-ui/public/assets/{dist-D1c0mkbB.js → dist-DyW8oFIW.js} +1 -1
- package/workframe-ui/public/assets/{erDiagram-TEJ5UH35-DnFysVRY.js → erDiagram-TEJ5UH35-DFtJLZx1.js} +1 -1
- package/workframe-ui/public/assets/eventmodeling-FCH6USID-BTmiKS74.js +1 -0
- package/workframe-ui/public/assets/{flowDiagram-I6XJVG4X-C6Ebi3su.js → flowDiagram-I6XJVG4X-B6K6EnPA.js} +1 -1
- package/workframe-ui/public/assets/{ganttDiagram-6RSMTGT7-BQXQtUpa.js → ganttDiagram-6RSMTGT7-CbuWdupl.js} +1 -1
- package/workframe-ui/public/assets/{gitGraph-WXDBUCRP-Dt0zIs_M.js → gitGraph-WXDBUCRP-BW_jwUPU.js} +1 -1
- package/workframe-ui/public/assets/{gitGraphDiagram-PVQCEYII-BF8gHzRn.js → gitGraphDiagram-PVQCEYII-B4MYuP9j.js} +1 -1
- package/workframe-ui/public/assets/index-BYacg3Nj.js +133 -0
- package/workframe-ui/public/assets/{info-J43DQDTF-CSmszQJT.js → info-J43DQDTF-Xa61PMDn.js} +1 -1
- package/workframe-ui/public/assets/{infoDiagram-5YYISTIA-CVTKGW6p.js → infoDiagram-5YYISTIA-BNbQgdUG.js} +1 -1
- package/workframe-ui/public/assets/{ishikawaDiagram-YF4QCWOH-Z8pT09Lv.js → ishikawaDiagram-YF4QCWOH-BDfiCzHo.js} +1 -1
- package/workframe-ui/public/assets/{journeyDiagram-JHISSGLW-r3wD68_T.js → journeyDiagram-JHISSGLW-Dn52B8tT.js} +1 -1
- package/workframe-ui/public/assets/{kanban-definition-UN3LZRKU-Il8VglqN.js → kanban-definition-UN3LZRKU-rhwkS_g6.js} +1 -1
- package/workframe-ui/public/assets/{line-oyjpfz2A.js → line-BQJgrj-x.js} +1 -1
- package/workframe-ui/public/assets/{linear-Cf7p5tVp.js → linear-Bq2ZvWSJ.js} +1 -1
- package/workframe-ui/public/assets/{mermaid-parser.core-YmbZ-AfY.js → mermaid-parser.core-CwFK_i8p.js} +2 -2
- package/workframe-ui/public/assets/{mermaid.core-BFdCAqCo.js → mermaid.core-C9CAm83c.js} +3 -3
- package/workframe-ui/public/assets/{mindmap-definition-RKZ34NQL-Cy2iCtEl.js → mindmap-definition-RKZ34NQL-BXwEccNZ.js} +1 -1
- package/workframe-ui/public/assets/{packet-YPE3B663-DwOBZL6K.js → packet-YPE3B663-D754iSKT.js} +1 -1
- package/workframe-ui/public/assets/{pie-LRSECV5Y-04PPhnKK.js → pie-LRSECV5Y-BQ2V4UWk.js} +1 -1
- package/workframe-ui/public/assets/{pieDiagram-4H26LBE5-LxIpgHqi.js → pieDiagram-4H26LBE5-CNHecl4C.js} +1 -1
- package/workframe-ui/public/assets/{quadrantDiagram-W4KKPZXB-0nBYfYm4.js → quadrantDiagram-W4KKPZXB-Bu6ciL2O.js} +1 -1
- package/workframe-ui/public/assets/{radar-GUYGQ44K-D2-vBqps.js → radar-GUYGQ44K-Dr8b9Qak.js} +1 -1
- package/workframe-ui/public/assets/{requirementDiagram-4Y6WPE33-DbuU0nlu.js → requirementDiagram-4Y6WPE33-Beua6Xju.js} +1 -1
- package/workframe-ui/public/assets/{sankeyDiagram-5OEKKPKP-B2hQ6B2x.js → sankeyDiagram-5OEKKPKP-CSDFJ0P_.js} +1 -1
- package/workframe-ui/public/assets/{sequenceDiagram-3UESZ5HK-BBrU30e1.js → sequenceDiagram-3UESZ5HK-KKziodNI.js} +1 -1
- package/workframe-ui/public/assets/{src-BJEDmV70.js → src-PKTIkQR0.js} +1 -1
- package/workframe-ui/public/assets/{stateDiagram-AJRCARHV-7FGO4kkH.js → stateDiagram-AJRCARHV-Bu8FNMcj.js} +1 -1
- package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-E9A5RCa9.js +1 -0
- package/workframe-ui/public/assets/{timeline-definition-PNZ67QCA-ptDm4rCN.js → timeline-definition-PNZ67QCA-DMa-RPqy.js} +1 -1
- package/workframe-ui/public/assets/{treeView-BLDUP644-CS6Z-0q8.js → treeView-BLDUP644-CzQeUY7D.js} +1 -1
- package/workframe-ui/public/assets/{treemap-LRROVOQU-DqV4Y2VA.js → treemap-LRROVOQU-BT4RYAhY.js} +1 -1
- package/workframe-ui/public/assets/{vennDiagram-CIIHVFJN-C0UrZJYt.js → vennDiagram-CIIHVFJN-nKaUH6GG.js} +1 -1
- package/workframe-ui/public/assets/{wardley-L42UT6IY-bNDN3_Sa.js → wardley-L42UT6IY-eSpvH7au.js} +1 -1
- package/workframe-ui/public/assets/{wardleyDiagram-YWT4CUSO-jWiJsefM.js → wardleyDiagram-YWT4CUSO-B5u4s4a5.js} +1 -1
- package/workframe-ui/public/assets/{xychartDiagram-2RQKCTM6-Dsh_fLCy.js → xychartDiagram-2RQKCTM6-DcXo5hDi.js} +1 -1
- package/workframe-ui/public/index.html +1 -1
- package/workframe-ui/public/assets/architecture-7EHR7CIX-DUyH3hWG.js +0 -1
- package/workframe-ui/public/assets/channel-g7r_RGaY.js +0 -1
- package/workframe-ui/public/assets/chunk-QZHKN3VN-C5UQehWY.js +0 -1
- package/workframe-ui/public/assets/chunk-WU5MYG2G-DhWllrI8.js +0 -1
- package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-BBM_8T8E.js +0 -1
- package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-BBM_8T8E.js +0 -1
- package/workframe-ui/public/assets/eventmodeling-FCH6USID-Ci8mdb44.js +0 -1
- package/workframe-ui/public/assets/index-lRpzpNPT.js +0 -133
- package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-DLTSizMg.js +0 -1
package/workframe-api/server.py
CHANGED
|
@@ -46,6 +46,9 @@ import turn_credentials
|
|
|
46
46
|
import llm_proxy
|
|
47
47
|
import action_proxy
|
|
48
48
|
import internal_proxy_auth
|
|
49
|
+
import concierge
|
|
50
|
+
import llm_error_glossary
|
|
51
|
+
import openrouter_catalog
|
|
49
52
|
import updates as stack_updates
|
|
50
53
|
|
|
51
54
|
HERMES_DATA = Path(os.environ.get("HERMES_DATA", "/opt/data"))
|
|
@@ -12302,8 +12305,9 @@ def _provider_pool_entry(provider: str, env_var: str, *, base_url: str = "") ->
|
|
|
12302
12305
|
|
|
12303
12306
|
|
|
12304
12307
|
def _runtime_provider_pool_entry(provider: str, env_var: str) -> dict[str, Any]:
|
|
12305
|
-
"""Credential pool row for u-* profiles —
|
|
12306
|
-
|
|
12308
|
+
"""Credential pool row for u-* profiles — lease token lives in OPENAI_API_KEY."""
|
|
12309
|
+
lease_env = "OPENAI_API_KEY"
|
|
12310
|
+
return _provider_pool_entry(provider, lease_env, base_url=_llm_proxy_base_url(provider))
|
|
12307
12311
|
|
|
12308
12312
|
|
|
12309
12313
|
def _provider_pool_has_entries(auth: dict[str, Any], provider: str) -> bool:
|
|
@@ -13313,23 +13317,75 @@ def _enrich_room_chat_payload(payload: dict[str, Any], user_id: str) -> dict[str
|
|
|
13313
13317
|
return body
|
|
13314
13318
|
|
|
13315
13319
|
|
|
13316
|
-
def _emit_stream_chat_error(
|
|
13317
|
-
|
|
13318
|
-
|
|
13319
|
-
|
|
13320
|
+
def _emit_stream_chat_error(
|
|
13321
|
+
handler: BaseHTTPRequestHandler,
|
|
13322
|
+
message: str = "",
|
|
13323
|
+
*,
|
|
13324
|
+
entry: dict[str, Any] | None = None,
|
|
13325
|
+
) -> None:
|
|
13326
|
+
"""SSE error frame — structured playbook when entry supplied."""
|
|
13327
|
+
payload = llm_error_glossary.notice_payload(entry) if entry else {}
|
|
13328
|
+
if not payload:
|
|
13329
|
+
text = str(message or "").strip() or "Chat failed."
|
|
13330
|
+
payload = {"error": text, "text": text, "message": text}
|
|
13320
13331
|
try:
|
|
13321
13332
|
handler.send_response(200)
|
|
13322
13333
|
handler.send_header("Content-Type", "text/event-stream; charset=utf-8")
|
|
13323
13334
|
handler.send_header("Cache-Control", "no-cache")
|
|
13324
13335
|
handler.send_header("Connection", "keep-alive")
|
|
13325
13336
|
handler.end_headers()
|
|
13326
|
-
|
|
13337
|
+
body = json.dumps(payload)
|
|
13338
|
+
handler.wfile.write(f"event: error\ndata: {body}\n\n".encode("utf-8"))
|
|
13327
13339
|
handler.wfile.write(b"event: done\ndata: {}\n\n")
|
|
13328
13340
|
handler.wfile.flush()
|
|
13329
13341
|
except (BrokenPipeError, ConnectionResetError, OSError):
|
|
13330
13342
|
return
|
|
13331
13343
|
|
|
13332
13344
|
|
|
13345
|
+
def _emit_stream_concierge(handler: BaseHTTPRequestHandler, entry: dict[str, Any]) -> None:
|
|
13346
|
+
"""Deterministic assistant reply when LLM path is unavailable."""
|
|
13347
|
+
payload = llm_error_glossary.notice_payload(entry)
|
|
13348
|
+
text = str(payload.get("message") or "")
|
|
13349
|
+
hint = str(payload.get("hint") or "").strip()
|
|
13350
|
+
if hint:
|
|
13351
|
+
text = f"{text}\n\n{hint}"
|
|
13352
|
+
try:
|
|
13353
|
+
handler.send_response(200)
|
|
13354
|
+
handler.send_header("Content-Type", "text/event-stream; charset=utf-8")
|
|
13355
|
+
handler.send_header("Cache-Control", "no-cache")
|
|
13356
|
+
handler.send_header("Connection", "keep-alive")
|
|
13357
|
+
handler.end_headers()
|
|
13358
|
+
handler.wfile.write(
|
|
13359
|
+
f"event: concierge\ndata: {json.dumps(payload)}\n\n".encode("utf-8"),
|
|
13360
|
+
)
|
|
13361
|
+
handler.wfile.write(
|
|
13362
|
+
f"event: message.complete\ndata: {json.dumps({'content': text, 'text': text})}\n\n".encode(
|
|
13363
|
+
"utf-8",
|
|
13364
|
+
),
|
|
13365
|
+
)
|
|
13366
|
+
handler.wfile.write(b"event: done\ndata: {}\n\n")
|
|
13367
|
+
handler.wfile.flush()
|
|
13368
|
+
except (BrokenPipeError, ConnectionResetError, OSError):
|
|
13369
|
+
return
|
|
13370
|
+
|
|
13371
|
+
|
|
13372
|
+
def _log_llm_failure(
|
|
13373
|
+
handler: BaseHTTPRequestHandler,
|
|
13374
|
+
code: str,
|
|
13375
|
+
*,
|
|
13376
|
+
provider: str = "",
|
|
13377
|
+
model: str = "",
|
|
13378
|
+
profile: str = "",
|
|
13379
|
+
) -> None:
|
|
13380
|
+
if hasattr(handler, "_log_audit"):
|
|
13381
|
+
handler._log_audit( # type: ignore[attr-defined]
|
|
13382
|
+
"llm_failure",
|
|
13383
|
+
"llm",
|
|
13384
|
+
profile or provider or "unknown",
|
|
13385
|
+
f"code={code} provider={provider} model={model}",
|
|
13386
|
+
)
|
|
13387
|
+
|
|
13388
|
+
|
|
13333
13389
|
def stream_profile_chat(handler: BaseHTTPRequestHandler, profile: str, payload: dict[str, Any]) -> None:
|
|
13334
13390
|
_triggering_user = str(payload.get("user_id", "") or "")
|
|
13335
13391
|
_workspace_id = str(payload.get("workspace_id", "") or "")
|
|
@@ -13345,6 +13401,15 @@ def stream_profile_chat(handler: BaseHTTPRequestHandler, profile: str, payload:
|
|
|
13345
13401
|
if not text:
|
|
13346
13402
|
raise ValueError("text required")
|
|
13347
13403
|
llm_provider = _llm_billing_provider(prof)
|
|
13404
|
+
llm_ready = bool(
|
|
13405
|
+
_triggering_user
|
|
13406
|
+
and _user_can_use_llm(_triggering_user, _workspace_id, llm_provider)
|
|
13407
|
+
)
|
|
13408
|
+
if _triggering_user and not llm_ready:
|
|
13409
|
+
entry = concierge.respond(text, situation="no_provider")
|
|
13410
|
+
_log_llm_failure(handler, str(entry.get("code") or "no_llm_provider"), provider=llm_provider, profile=prof)
|
|
13411
|
+
_emit_stream_concierge(handler, entry)
|
|
13412
|
+
return
|
|
13348
13413
|
try:
|
|
13349
13414
|
lifecycle = ensure_profile_api(
|
|
13350
13415
|
prof,
|
|
@@ -13358,7 +13423,15 @@ def stream_profile_chat(handler: BaseHTTPRequestHandler, profile: str, payload:
|
|
|
13358
13423
|
)
|
|
13359
13424
|
_overlay_turn_user_env(prof, _triggering_user, _workspace_id, _turn_run_id)
|
|
13360
13425
|
except ValueError as exc:
|
|
13361
|
-
|
|
13426
|
+
err_text = str(exc)
|
|
13427
|
+
if "no_llm_provider_for_user" in err_text:
|
|
13428
|
+
entry = concierge.respond(text, situation="no_provider")
|
|
13429
|
+
_log_llm_failure(handler, "no_llm_provider", provider=llm_provider, profile=prof)
|
|
13430
|
+
_emit_stream_concierge(handler, entry)
|
|
13431
|
+
return
|
|
13432
|
+
entry = llm_error_glossary.classify_exception_text(err_text)
|
|
13433
|
+
_log_llm_failure(handler, str(entry.get("code") or ""), provider=llm_provider, profile=prof)
|
|
13434
|
+
_emit_stream_chat_error(handler, entry=entry)
|
|
13362
13435
|
return
|
|
13363
13436
|
upstream_body = json.dumps(_profile_turn_payload(prof, text, _room_id)).encode("utf-8")
|
|
13364
13437
|
|
|
@@ -13487,34 +13560,21 @@ def stream_profile_chat(handler: BaseHTTPRequestHandler, profile: str, payload:
|
|
|
13487
13560
|
handler.wfile.flush()
|
|
13488
13561
|
if not saw_complete or not complete_text:
|
|
13489
13562
|
config_key = _read_config_model_api_key(prof)
|
|
13563
|
+
_, model_name = _read_model_from_config(prof)
|
|
13490
13564
|
if config_key.startswith(turn_credentials.LEASE_PREFIX) and not turn_credentials.validate_lease(
|
|
13491
13565
|
config_key,
|
|
13492
13566
|
):
|
|
13493
|
-
|
|
13494
|
-
"Turn credential expired before the model replied. "
|
|
13495
|
-
"Send the message again."
|
|
13496
|
-
)
|
|
13497
|
-
err_code = "invalid_lease"
|
|
13498
|
-
elif not saw_complete:
|
|
13499
|
-
err_text = (
|
|
13500
|
-
"Model provider returned no reply. "
|
|
13501
|
-
"The request may have failed at the gateway or provider."
|
|
13502
|
-
)
|
|
13503
|
-
err_code = "provider_empty_reply"
|
|
13567
|
+
entry = llm_error_glossary.playbook_entry("invalid_lease")
|
|
13504
13568
|
else:
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
)
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
|
|
13512
|
-
"error": err_text,
|
|
13513
|
-
"text": err_text,
|
|
13514
|
-
"message": err_text,
|
|
13515
|
-
"code": err_code,
|
|
13516
|
-
},
|
|
13569
|
+
entry = llm_error_glossary.playbook_entry("provider_empty_reply")
|
|
13570
|
+
_log_llm_failure(
|
|
13571
|
+
handler,
|
|
13572
|
+
str(entry.get("code") or "provider_empty_reply"),
|
|
13573
|
+
provider=llm_provider,
|
|
13574
|
+
model=str(model_name or ""),
|
|
13575
|
+
profile=prof,
|
|
13517
13576
|
)
|
|
13577
|
+
err_payload = json.dumps(llm_error_glossary.notice_payload(entry))
|
|
13518
13578
|
handler.wfile.write(f"event: error\ndata: {err_payload}\n\n".encode("utf-8"))
|
|
13519
13579
|
handler.wfile.flush()
|
|
13520
13580
|
handler.wfile.write(b"event: done\ndata: {}\n\n")
|
|
@@ -14252,16 +14312,16 @@ def _resolve_command(token: str) -> dict[str, Any] | None:
|
|
|
14252
14312
|
# overrides live in the profile's config.yaml under `model.default` and
|
|
14253
14313
|
# `fallback_providers`; this constant is the install-wide default the
|
|
14254
14314
|
# migration writes when a profile is missing either field.
|
|
14255
|
-
HERMES_DEFAULT_PRIMARY = "
|
|
14315
|
+
HERMES_DEFAULT_PRIMARY = "google/gemini-2.5-flash"
|
|
14256
14316
|
HERMES_DEFAULT_FALLBACK_CHAIN: list[dict[str, str]] = [
|
|
14257
|
-
{"provider": "openrouter", "model": "
|
|
14258
|
-
{"provider": "openrouter", "model": "
|
|
14317
|
+
{"provider": "openrouter", "model": "anthropic/claude-sonnet-4.5"},
|
|
14318
|
+
{"provider": "openrouter", "model": "meta-llama/llama-3.3-70b-instruct:free"},
|
|
14259
14319
|
]
|
|
14260
14320
|
|
|
14261
14321
|
# ponytail: minimum-viable agentic models per LLM provider; user can escalate in settings.
|
|
14262
14322
|
PROVIDER_MVP_MODELS: dict[str, dict[str, Any]] = {
|
|
14263
14323
|
"openrouter": {
|
|
14264
|
-
"primary": "
|
|
14324
|
+
"primary": "google/gemini-2.5-flash",
|
|
14265
14325
|
"fallbacks": list(HERMES_DEFAULT_FALLBACK_CHAIN),
|
|
14266
14326
|
},
|
|
14267
14327
|
"openai": {
|
|
@@ -14273,8 +14333,8 @@ PROVIDER_MVP_MODELS: dict[str, dict[str, Any]] = {
|
|
|
14273
14333
|
"fallbacks": [{"provider": "anthropic", "model": "claude-3-5-haiku-20241022"}],
|
|
14274
14334
|
},
|
|
14275
14335
|
"google": {
|
|
14276
|
-
"primary": "gemini-2.
|
|
14277
|
-
"fallbacks": [{"provider": "google", "model": "gemini-2.
|
|
14336
|
+
"primary": "gemini-2.5-flash",
|
|
14337
|
+
"fallbacks": [{"provider": "google", "model": "gemini-2.5-flash-lite"}],
|
|
14278
14338
|
},
|
|
14279
14339
|
"deepseek": {
|
|
14280
14340
|
"primary": "deepseek-chat",
|
|
@@ -14285,8 +14345,8 @@ PROVIDER_MVP_MODELS: dict[str, dict[str, Any]] = {
|
|
|
14285
14345
|
"fallbacks": [{"provider": "openai-codex", "model": "gpt-5.4-medium"}],
|
|
14286
14346
|
},
|
|
14287
14347
|
"nous": {
|
|
14288
|
-
"primary": "
|
|
14289
|
-
"fallbacks": [{"provider": "nous", "model": "
|
|
14348
|
+
"primary": "nousresearch/hermes-4-70b",
|
|
14349
|
+
"fallbacks": [{"provider": "nous", "model": "nousresearch/hermes-4-70b"}],
|
|
14290
14350
|
},
|
|
14291
14351
|
}
|
|
14292
14352
|
|
|
@@ -14394,15 +14454,21 @@ HERMES_MODEL_CATALOG: list[dict[str, str]] = [
|
|
|
14394
14454
|
{"provider": "OpenRouter", "model": "openrouter/auto",
|
|
14395
14455
|
"label": "OpenRouter Auto",
|
|
14396
14456
|
"description": "OpenRouter picks the best model per prompt."},
|
|
14397
|
-
{"provider": "OpenRouter", "model": "
|
|
14398
|
-
"label": "
|
|
14399
|
-
"description": "
|
|
14400
|
-
{"provider": "OpenRouter", "model": "
|
|
14401
|
-
"label": "
|
|
14402
|
-
"description": "
|
|
14403
|
-
{"provider": "OpenRouter", "model": "
|
|
14404
|
-
"label": "
|
|
14405
|
-
"description": "
|
|
14457
|
+
{"provider": "OpenRouter", "model": "google/gemini-2.5-flash",
|
|
14458
|
+
"label": "Gemini 2.5 Flash",
|
|
14459
|
+
"description": "Fast, capable default for OpenRouter BYOK."},
|
|
14460
|
+
{"provider": "OpenRouter", "model": "anthropic/claude-sonnet-4.5",
|
|
14461
|
+
"label": "Claude Sonnet 4.5 (via OR)",
|
|
14462
|
+
"description": "Strong agentic fallback on OpenRouter."},
|
|
14463
|
+
{"provider": "OpenRouter", "model": "meta-llama/llama-3.3-70b-instruct:free",
|
|
14464
|
+
"label": "Llama 3.3 70B (free)",
|
|
14465
|
+
"description": "Free-tier OpenRouter fallback when available."},
|
|
14466
|
+
{"provider": "OpenRouter", "model": "z-ai/glm-5.1",
|
|
14467
|
+
"label": "GLM 5.1",
|
|
14468
|
+
"description": "High-availability model on OpenRouter."},
|
|
14469
|
+
{"provider": "OpenRouter", "model": "nousresearch/hermes-4-70b",
|
|
14470
|
+
"label": "Hermes 4 70B",
|
|
14471
|
+
"description": "Agent-tuned model on OpenRouter."},
|
|
14406
14472
|
{"provider": "OpenRouter", "model": "openrouter/nvidia/llama-3.1-nemotron-70b-instruct",
|
|
14407
14473
|
"label": "Nemotron 70B Instruct",
|
|
14408
14474
|
"description": "NVIDIA Nemotron via OpenRouter."},
|
|
@@ -14780,6 +14846,17 @@ def hermes_models(profile: str = "", user_id: str = "", workspace_id: str = "")
|
|
|
14780
14846
|
] if (picker_llm or connected) else [],
|
|
14781
14847
|
block,
|
|
14782
14848
|
)
|
|
14849
|
+
if user_id and "openrouter" in {n.lower() for n in (picker_llm or connected)}:
|
|
14850
|
+
resolved = _resolve_credential(user_id, workspace_id, "openrouter", user_only=True)
|
|
14851
|
+
secret = _credential_secret(resolved or {}, user_id) if resolved else ""
|
|
14852
|
+
live = openrouter_catalog.live_suggestions(secret, limit=30)
|
|
14853
|
+
if live:
|
|
14854
|
+
seen = {str(r.get("model") or "") for r in suggestions}
|
|
14855
|
+
suggestions = [
|
|
14856
|
+
{**row, "label": f"Live · {row.get('label', row.get('model', ''))}"}
|
|
14857
|
+
for row in live
|
|
14858
|
+
if str(row.get("model") or "") not in seen
|
|
14859
|
+
] + suggestions
|
|
14783
14860
|
return {
|
|
14784
14861
|
"ok": True,
|
|
14785
14862
|
"profile": primary_profile,
|
|
@@ -17391,11 +17468,29 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
17391
17468
|
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)""",
|
|
17392
17469
|
(cred_id, None, user_id, None, provider, credential_type, cred_ref, label, 1, user_id, now, now),
|
|
17393
17470
|
)
|
|
17471
|
+
conn.execute(
|
|
17472
|
+
"""UPDATE credential_bindings
|
|
17473
|
+
SET is_active = 0, deleted_at = ?, updated_at = ?
|
|
17474
|
+
WHERE user_id = ? AND provider = ? AND deleted_at IS NULL AND id != ?""",
|
|
17475
|
+
(now, now, user_id, provider, cred_id),
|
|
17476
|
+
)
|
|
17394
17477
|
conn.commit()
|
|
17395
17478
|
conn.close()
|
|
17396
17479
|
except sqlite3.Error as exc:
|
|
17397
17480
|
return self._json(500, {"ok": False, "error": f"db_error: {exc}"})
|
|
17398
17481
|
self._log_audit("credential_stored", "credential_binding", cred_id, f"provider={provider}")
|
|
17482
|
+
health: dict[str, Any] = {}
|
|
17483
|
+
if provider == "openrouter":
|
|
17484
|
+
secret_probe = _credential_secret(
|
|
17485
|
+
{
|
|
17486
|
+
"credential_ref": cred_ref,
|
|
17487
|
+
"scope": "user",
|
|
17488
|
+
"user_id": user_id,
|
|
17489
|
+
},
|
|
17490
|
+
user_id,
|
|
17491
|
+
)
|
|
17492
|
+
if secret_probe:
|
|
17493
|
+
health = openrouter_catalog.probe_account(secret_probe)
|
|
17399
17494
|
_bootstrap_model_after_llm_connect(user_id, str(body.get("workspace_id") or ""), provider)
|
|
17400
17495
|
return self._json(200, {
|
|
17401
17496
|
"ok": True,
|
|
@@ -17407,6 +17502,7 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
17407
17502
|
"user_id": user_id,
|
|
17408
17503
|
"created_at": now,
|
|
17409
17504
|
"updated_at": now,
|
|
17505
|
+
"health": health,
|
|
17410
17506
|
**payload,
|
|
17411
17507
|
})
|
|
17412
17508
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./path-BWPyau1x.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-
|
|
1
|
+
import{n as e,t}from"./path-BWPyau1x.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-DyW8oFIW.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i)if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-NNHCCRGN-DlpIbxXb.js";import{x as e}from"./mermaid-parser.core-CwFK_i8p.js";export{e as createArchitectureServices};
|