@whyshu/argent-engine 0.7.7 → 0.8.0-rc.2
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/MANIFEST.json +19 -15
- package/engine/VERSION +1 -1
- package/engine/core/contracts/argent.contracts.json +1 -1
- package/engine/core/lib/argent-datadir.mjs +6 -0
- package/engine/scripts/capability-packs.lock.json +38 -37
- package/engine/scripts/daily-report.mjs +1 -1
- package/engine/scripts/flow-requirements.json +4 -4
- package/engine/scripts/flow-trigger-wake.mjs +6 -3
- package/engine/scripts/flow_config.py +2 -0
- package/engine/scripts/flow_failure.py +3 -0
- package/engine/scripts/fulfillment_sites.py +46 -0
- package/engine/scripts/lib/argent_datadir.py +5 -0
- package/engine/scripts/ml_hub_status.py +3 -3
- package/engine/scripts/orchestrator.py +34 -22
- package/engine/scripts/orchestrator_br.py +14307 -0
- package/engine/skills/ml-fulfillment-sop/SKILL.md +29 -0
- package/engine/skills/ml-fulfillment-sop/references/agentic-runtime-v3.md +39 -0
- package/engine/version.mjs +1 -1
- package/engine/verticals/mercadolibre/brazil-full-sop.json +47 -0
- package/engine/verticals/mercadolibre/flows.json +12 -4
- package/engine/verticals/mercadolibre/prompts/full.failure.md +39 -1
- package/package.json +1 -1
|
@@ -65,6 +65,8 @@ ENV_DATA_DIR = "ARGENT_DATA_DIR"
|
|
|
65
65
|
ENV_DSH_HOME = "DSH_HOME"
|
|
66
66
|
#: 隔离目录下**显式**放开失败回路的开关(必须精确等于 `1`)。
|
|
67
67
|
ENV_ALLOW_ISOLATED_PUMP = "ARGENT_ALLOW_ISOLATED_PUMP"
|
|
68
|
+
#: 部署方声明的本机规范数据目录(生产客户机用)。
|
|
69
|
+
ENV_CANONICAL_DATA_DIR = "ARGENT_CANONICAL_DATA_DIR"
|
|
68
70
|
|
|
69
71
|
#: **老机器**的数据目录(`~/.dsh/argent`):存在即沿用 —— 这一级同时是"客户机现状"。
|
|
70
72
|
DATA_DIR_SEGMENTS = (".dsh", "argent")
|
|
@@ -148,6 +150,9 @@ def default_data_dir(env=None, home=None) -> str:
|
|
|
148
150
|
与 JS 内核 `core/lib/argent-datadir.mjs#defaultDataDir` **同批、同夹具**对拍
|
|
149
151
|
(`scripts/tests/argent-datadir-parity.test.mjs`);优先级链**不变**。
|
|
150
152
|
"""
|
|
153
|
+
canonical = _get(_env(env), ENV_CANONICAL_DATA_DIR)
|
|
154
|
+
if canonical:
|
|
155
|
+
return _p.abspath(canonical) # 部署方显式规范目录
|
|
151
156
|
if legacy_data_dir_exists(env, home):
|
|
152
157
|
return legacy_data_dir(env, home) # ① 存在即沿用(老机器)
|
|
153
158
|
return _join(home or os_home(_env(env)), *NO_HOST_DATA_DIR_SEGMENTS) # ② 新装(无宿主)⇒ ~/.argent
|
|
@@ -88,7 +88,7 @@ units 页上都会出现 ⇒ 单凭它会把正常票判成尺寸阻塞。空间
|
|
|
88
88
|
本样本**不依赖它**(仅凭 hub 即可判 `true`)。
|
|
89
89
|
|
|
90
90
|
⚠️ `operationally_complete=True` ⇒ 货件**被视为已完成**(无论表里写什么),但
|
|
91
|
-
**⛔ 绝不是让引擎去改写 `FULL状态`** ——
|
|
91
|
+
**⛔ 绝不是让引擎去改写 `FULL状态`** —— 改写权在运营/用户;引擎只写「识别为已完成(依据 hub-v2 实测;来源未声明)」的备注。
|
|
92
92
|
|
|
93
93
|
## 容错(平台改版是常态)
|
|
94
94
|
|
|
@@ -1305,14 +1305,14 @@ def summary_zh(state: dict) -> str:
|
|
|
1305
1305
|
def completion_verdict(state: dict) -> dict:
|
|
1306
1306
|
"""完成度裁定(**确定性规则**,供收口/前置校验/失败现场三处共用)。
|
|
1307
1307
|
|
|
1308
|
-
`operationally_complete=True` ⇒
|
|
1308
|
+
`operationally_complete=True` ⇒ 「识别为已完成(依据 hub-v2 实测;来源未声明)」。
|
|
1309
1309
|
⛔ 本函数**不改任何数据**:它只给结论,写表与否由调用方按各自白名单决定。
|
|
1310
1310
|
"""
|
|
1311
1311
|
ok = bool(state.get("operationally_complete"))
|
|
1312
1312
|
return {
|
|
1313
1313
|
"operationally_complete": ok,
|
|
1314
1314
|
"identified_as": "manual-completion-by-hub" if ok else "",
|
|
1315
|
-
"note_zh": ("
|
|
1315
|
+
"note_zh": ("识别为已完成(依据 hub-v2 实测;来源未声明):" + summary_zh(state)) if ok else "",
|
|
1316
1316
|
"reason": state.get("complete_reason") or "",
|
|
1317
1317
|
"items": item_lines(state),
|
|
1318
1318
|
"shipment_id": state.get("shipment_id") or "",
|
|
@@ -2320,6 +2320,11 @@ BOX_LABEL_DL_ROUNDS = int(os.environ.get("BOX_LABEL_DL_ROUNDS", "") or 3)
|
|
|
2320
2320
|
# 现在:等待按"业务信号"轮询 + 分层预算,超时才落终态;预算可调(客户机也能按现场调)。
|
|
2321
2321
|
NAV_TIMEOUT_SEC = float(os.environ.get("NAV_TIMEOUT_SEC", "") or 90) # page.goto 单次
|
|
2322
2322
|
URL_TRANSITION_SEC = float(os.environ.get("URL_TRANSITION_SEC", "") or 120) # 等跳转(如 hub-v2)
|
|
2323
|
+
# 2026-10-24:平台把 hub 落地页从 `/hub-v2` 改为 `/hub`;历史判据只认 `hub-v2`
|
|
2324
|
+
# ⇒ 写操作明明生效也判失败(FULL 步骤4/5 假失败、误取消预约)。统一用正则接受两种形态。
|
|
2325
|
+
HUB_URL_RE = re.compile(r"/inbounds/\d+/hub(?:-v2)?(?:[/?#]|$)")
|
|
2326
|
+
def is_hub_url(url: str) -> bool:
|
|
2327
|
+
return bool(HUB_URL_RE.search(str(url or "")))
|
|
2323
2328
|
SLOW_GRACE_SEC = float(os.environ.get("SLOW_GRACE_SEC", "") or 60) # 慢渲染宽限(再等一轮)
|
|
2324
2329
|
# 错误弹窗(Algo salió mal)自愈的**退避**(2026-09-23):
|
|
2325
2330
|
# 旧行为:失败→重载→固定等 8s→再来一次,两次不成即判失败 ⇒ 平台慢时等于"连打同一页面"
|
|
@@ -7455,7 +7460,7 @@ class Orchestrator:
|
|
|
7455
7460
|
"""**唯一入口**:把 `FULL状态` 置为「已完成」。
|
|
7456
7461
|
|
|
7457
7462
|
2026-10-16:原先只有 `_finalize_ticket_complete`(引擎自己跑完)能置位;现在
|
|
7458
|
-
|
|
7463
|
+
「已完成(hub-v2 实测;来源未声明)」也要置位(用户口径「都要」)⇒ 抽出本入口,两条路径
|
|
7459
7464
|
**都走这里**,保持"表状态只有一个写点"的不变量(回归见 ticket-completion-criteria /
|
|
7460
7465
|
step-progress-realtime 的 AST 断言)。
|
|
7461
7466
|
"""
|
|
@@ -7881,7 +7886,7 @@ class Orchestrator:
|
|
|
7881
7886
|
"shipment_id": "", "url_inbound": "", "probe_ok": False}
|
|
7882
7887
|
|
|
7883
7888
|
# 需求 1a:hub 判定的**运营手动完成**在表里固定用这句话(运维与角色都按它对齐口径)
|
|
7884
|
-
HUB_MANUAL_NOTE = "
|
|
7889
|
+
HUB_MANUAL_NOTE = "识别为已完成(依据 hub-v2 实测;来源未声明)"
|
|
7885
7890
|
|
|
7886
7891
|
def _hub_manual_complete(self, verdict: dict[str, Any], *, status: str = "") -> dict[str, Any]:
|
|
7887
7892
|
"""hub-v2 判定「预约已取消 ∧ 产品标签已下载 ∧ 箱唛已下载」⇒ **认定为已完成**。
|
|
@@ -7890,7 +7895,7 @@ class Orchestrator:
|
|
|
7890
7895
|
三个派生结论**都必须是 `True`**(`None` 一律不算);只要有一个判不了 ⇒ 不是完成。
|
|
7891
7896
|
|
|
7892
7897
|
## 写什么 / ⛔ 不写什么(用户口径)
|
|
7893
|
-
- **写**:`FULL备注` ←
|
|
7898
|
+
- **写**:`FULL备注` ← 「识别为已完成(依据 hub-v2 实测;来源未声明):<逐项>」(同源同文,
|
|
7894
7899
|
与 `--mode hub-status` 打印、与 `failures.jsonl#hub_status` 完全一致);
|
|
7895
7900
|
`当前步骤` ← **「全部完成」**(2026-10-16 用户口径:表口径与"引擎自己跑完"一致);`就绪=false`(消费掉拾取位)。
|
|
7896
7901
|
**`FULL状态` ← 已完成**(2026-10-16 用户口径「都要」:认定即置位,否则票一直挂在"失败"里,
|
|
@@ -9299,7 +9304,7 @@ class Orchestrator:
|
|
|
9299
9304
|
while time.time() < deadline:
|
|
9300
9305
|
rounds += 1
|
|
9301
9306
|
try:
|
|
9302
|
-
if
|
|
9307
|
+
if is_hub_url(self.browser.page.url or ""):
|
|
9303
9308
|
break
|
|
9304
9309
|
except Exception:
|
|
9305
9310
|
pass
|
|
@@ -10094,7 +10099,7 @@ class Orchestrator:
|
|
|
10094
10099
|
for _ in range(38): # 0.4s × 38 ≈ 15s
|
|
10095
10100
|
try:
|
|
10096
10101
|
url = self.browser.page.url or ""
|
|
10097
|
-
if
|
|
10102
|
+
if is_hub_url(url):
|
|
10098
10103
|
submit_ok = True
|
|
10099
10104
|
break
|
|
10100
10105
|
hint = await self.browser.page.evaluate(
|
|
@@ -10754,7 +10759,7 @@ class Orchestrator:
|
|
|
10754
10759
|
self._log(" ✅ 已确认重新贴标弹窗")
|
|
10755
10760
|
return True
|
|
10756
10761
|
# 无弹窗时快速返回:正常提交路径已跳转 hub-v2 → 零额外延迟
|
|
10757
|
-
if
|
|
10762
|
+
if is_hub_url(self.browser.page.url or ""):
|
|
10758
10763
|
return False
|
|
10759
10764
|
except Exception:
|
|
10760
10765
|
return False
|
|
@@ -10877,12 +10882,24 @@ class Orchestrator:
|
|
|
10877
10882
|
recovery_attempted=["checkbox_mouseevent"])
|
|
10878
10883
|
await self.browser.click_with_fallback(5, "confirm_btn", "Confirmar")
|
|
10879
10884
|
await asyncio.sleep(3)
|
|
10880
|
-
# 提交后应跳转 hub-v2
|
|
10885
|
+
# 提交后应跳转 hub(平台 2026-10 已把 /hub-v2 改为 /hub);URL 判据只作快速路径。
|
|
10886
|
+
# 失败前必须用只读 hub 探针核验「包装确认」是否真的完成,平台慢渲染不得再判假失败。
|
|
10881
10887
|
try:
|
|
10882
|
-
await self.browser.page.wait_for_url(
|
|
10888
|
+
await self.browser.page.wait_for_url(
|
|
10889
|
+
re.compile(r".*/inbounds/\d+/hub(?:-v2)?(?:[?#].*)?$"),
|
|
10890
|
+
timeout=int(URL_TRANSITION_SEC * 1000),
|
|
10891
|
+
)
|
|
10883
10892
|
except Exception:
|
|
10884
|
-
|
|
10885
|
-
|
|
10893
|
+
hub = await self._hub_truth(navigate=False, step=5)
|
|
10894
|
+
items = (hub or {}).get("items") or []
|
|
10895
|
+
packaging_done = any(
|
|
10896
|
+
str((it or {}).get("key") or "") == "packaging" and (it or {}).get("done") is True
|
|
10897
|
+
for it in items
|
|
10898
|
+
)
|
|
10899
|
+
if not packaging_done:
|
|
10900
|
+
raise StepError(5, "business", "包装确认后未到 hub / 未确认包装完成",
|
|
10901
|
+
recovery_attempted=["check_procedures_state", "hub_probe"])
|
|
10902
|
+
self._log(" ✅ 包装确认已由 hub 只读探针核验为完成(URL 判据未命中,按 effective 继续)")
|
|
10886
10903
|
self._mark_done(5)
|
|
10887
10904
|
if self.state.record_id:
|
|
10888
10905
|
self.feishu.send_message(f"✅ 步骤5完成: 包装确认 - {self.state.sku}")
|
|
@@ -11837,7 +11854,7 @@ class Orchestrator:
|
|
|
11837
11854
|
self._log(" ✅ 取消生效(appointmentCancellationSuccess 成功标志)")
|
|
11838
11855
|
return True
|
|
11839
11856
|
# b. hub-v2 跳转(取消成功后的正常去向)
|
|
11840
|
-
if
|
|
11857
|
+
if is_hub_url(url):
|
|
11841
11858
|
self._log(" ✅ 取消生效(hub-v2 跳转)")
|
|
11842
11859
|
return True
|
|
11843
11860
|
# c. 按钮消失 且 无错误弹窗(排除侧栏)
|
|
@@ -12689,18 +12706,13 @@ class Orchestrator:
|
|
|
12689
12706
|
f"失败:{exc.message}"
|
|
12690
12707
|
f"({_capacity_defer_tag}·预检恢复即**当日**重试,最多 "
|
|
12691
12708
|
f"{_capacity_max_lift} 次)")
|
|
12692
|
-
#
|
|
12693
|
-
#
|
|
12694
|
-
#
|
|
12695
|
-
# dry_run
|
|
12696
|
-
# 提交、无残留,不触发。
|
|
12709
|
+
# ⛔ 2026-10-24 用户口径:失败分支**不再自动取消预约**。
|
|
12710
|
+
# 假失败(如 /hub-v2 → /hub 改版)下自动取消会毁掉本来成功的预约;
|
|
12711
|
+
# 预约是稀缺资源,必须先由评估/人工确认「确实需要取消」再走步骤8。
|
|
12712
|
+
# dry_run 同样不取消。
|
|
12697
12713
|
cancel_note = ""
|
|
12698
12714
|
if not dry_run and 4 in self.state.completed_steps:
|
|
12699
|
-
self._log("
|
|
12700
|
-
if await self._safe_cancel_appointment():
|
|
12701
|
-
cancel_note = "\n✅ 预约已自动取消,无超时罚款风险"
|
|
12702
|
-
else:
|
|
12703
|
-
cancel_note = "\n⚠️ 预约取消失败!请立即人工取消预约,避免超时罚款"
|
|
12715
|
+
self._log(" ⏸ 失败分支不自动取消预约:先核实 hub/门户真实状态;确认需要取消时再走步骤8")
|
|
12704
12716
|
if self.state.record_id:
|
|
12705
12717
|
if auto_retry is None and auto_reset_fail is None:
|
|
12706
12718
|
# 人工类 / 未触发自动恢复:客户群失败卡片(红底 ❌),失败降级文字
|
|
@@ -13801,7 +13813,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
13801
13813
|
"三态;⛔ 不点按钮、不写表、不改 defer 状态;需 --store-name)")
|
|
13802
13814
|
p.add_argument("--hub-write-note", action="store_true",
|
|
13803
13815
|
help="hub-status 模式:当 hub 判定为「运营手动完成」时,**只**写 FULL备注/当前步骤"
|
|
13804
|
-
"
|
|
13816
|
+
"(识别为已完成(依据 hub-v2 实测;来源未声明));⛔ 仍不改写 FULL状态")
|
|
13805
13817
|
p.add_argument("--no-heal", action="store_true",
|
|
13806
13818
|
help="cdp-preflight 模式:只检查不自愈(不重连/不重开店铺窗口,纯只读)")
|
|
13807
13819
|
p.add_argument("--step", type=int, choices=list(range(1, 9)),
|