@honor-claw/yoyo 1.6.0-beta.4 → 1.6.0
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/dist/apis/http-client.mjs +2 -0
- package/dist/cloud-channel/message-handler.mjs +39 -2
- package/dist/gateway-client/admin-client.mjs +19 -8
- package/dist/gateway-client/protocol-client.mjs +38 -37
- package/dist/hooks/index.mjs +9 -3
- package/dist/index.mjs +3 -3
- package/dist/modules/configs/config-manager.mjs +85 -77
- package/dist/modules/configs/identity-persist.mjs +28 -30
- package/dist/modules/configs/index.mjs +1 -1
- package/dist/modules/configs/state-flags.mjs +3 -66
- package/dist/modules/device/providers/windows.mjs +1 -1
- package/dist/modules/device/registry.mjs +12 -12
- package/dist/utils/version.mjs +45 -13
- package/openclaw.plugin.json +4 -0
- package/package.json +7 -1
- package/skills/yoyo-control/SKILL.md +0 -2
- package/skills/yoyo-control/configs/sub-skills.json +0 -2
- package/skills/yoyo-control/references/flight-monitor-create.md +0 -233
- package/skills/yoyo-control/references/flight-monitor-search.md +0 -229
- package/skills/yoyo-control/scripts/time_infer.py +0 -99
|
@@ -4,70 +4,68 @@ import { safeReadFile as n, safeWriteFile as r } from "../../utils/fs-safe.mjs";
|
|
|
4
4
|
import { resolveEffectiveHomeDir as i } from "../../utils/home-dir.mjs";
|
|
5
5
|
import a from "node:path";
|
|
6
6
|
//#region src/modules/configs/identity-persist.ts
|
|
7
|
-
var o =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function d() {
|
|
11
|
-
return a.join(s, c, l);
|
|
7
|
+
var o = ".openclaw", s = "yoyo", c = "identity.json", l = 6e4;
|
|
8
|
+
function u() {
|
|
9
|
+
return a.join(o, s, c);
|
|
12
10
|
}
|
|
13
|
-
async function
|
|
14
|
-
let r =
|
|
11
|
+
async function d(t) {
|
|
12
|
+
let r = u();
|
|
15
13
|
try {
|
|
16
14
|
let e = (await n({
|
|
17
15
|
rootDir: t,
|
|
18
16
|
relativePath: r,
|
|
19
17
|
maxBytes: 10 * 1024
|
|
20
18
|
})).buffer.toString("utf8"), i = JSON.parse(e);
|
|
21
|
-
return typeof i != "object" || !i ?
|
|
22
|
-
...
|
|
19
|
+
return typeof i != "object" || !i ? _() : {
|
|
20
|
+
..._(),
|
|
23
21
|
...i
|
|
24
22
|
};
|
|
25
23
|
} catch (t) {
|
|
26
24
|
return e(t, "[yoyo-identity] failed to read identity"), null;
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
|
-
async function
|
|
27
|
+
async function f() {
|
|
30
28
|
let e = i();
|
|
31
|
-
return e ? await
|
|
29
|
+
return e ? await d(e) || null : (t().warn("[yoyo-identity] failed to find home dir"), null);
|
|
32
30
|
}
|
|
33
|
-
async function
|
|
31
|
+
async function p(e) {
|
|
34
32
|
let n = i();
|
|
35
33
|
if (!n) return t().warn("[yoyo-identity] failed to find home dir"), null;
|
|
36
|
-
let a = await
|
|
34
|
+
let a = await d(n), o = {
|
|
37
35
|
...a,
|
|
38
|
-
version: a?.version ||
|
|
36
|
+
version: a?.version || 2
|
|
39
37
|
};
|
|
40
|
-
return e.legacyDeviceId && (
|
|
38
|
+
return e.legacyDeviceId && (o.legacyDeviceId = e.legacyDeviceId), e.deviceId && (o.deviceId = e.deviceId, o.publicKeyPem = e.publicKeyPem, o.privateKeyPem = e.privateKeyPem, o.createdAtMs = e.createdAtMs), e.version && (o.version = e.version), "gatewayAuthMd5" in e && (o.gatewayAuthMd5 = e.gatewayAuthMd5), "pluginVersionCode" in e && (o.pluginVersionCode = e.pluginVersionCode), "authorizationCache" in e && (o.authorizationCache = e.authorizationCache), await r({
|
|
41
39
|
rootDir: n,
|
|
42
|
-
relativePath:
|
|
43
|
-
data: JSON.stringify(
|
|
40
|
+
relativePath: u(),
|
|
41
|
+
data: JSON.stringify(o, null, 2),
|
|
44
42
|
encoding: "utf8",
|
|
45
43
|
mkdir: !0
|
|
46
|
-
}),
|
|
44
|
+
}), o;
|
|
47
45
|
}
|
|
48
|
-
function
|
|
46
|
+
function m(e) {
|
|
49
47
|
let t = typeof e == "number" ? e : typeof e == "string" && e.trim() ? Number(e) : 0;
|
|
50
|
-
return !Number.isFinite(t) || t <
|
|
48
|
+
return !Number.isFinite(t) || t < l ? 0 : Math.floor(t);
|
|
51
49
|
}
|
|
52
|
-
async function
|
|
53
|
-
let r = await
|
|
50
|
+
async function h(e, t, n = Date.now()) {
|
|
51
|
+
let r = await p({ authorizationCache: {
|
|
54
52
|
jwtToken: e,
|
|
55
53
|
receivedAtMs: n,
|
|
56
|
-
expireMs:
|
|
54
|
+
expireMs: m(t)
|
|
57
55
|
} });
|
|
58
56
|
if (!r) throw Error("failed to write authorization cache");
|
|
59
57
|
return r;
|
|
60
58
|
}
|
|
61
|
-
async function
|
|
62
|
-
let e = await
|
|
63
|
-
return t?.jwtToken ?
|
|
59
|
+
async function g() {
|
|
60
|
+
let e = await f(), t = e?.authorizationCache;
|
|
61
|
+
return t?.jwtToken ? p({ authorizationCache: {
|
|
64
62
|
jwtToken: void 0,
|
|
65
63
|
receivedAtMs: t.receivedAtMs,
|
|
66
|
-
expireMs:
|
|
64
|
+
expireMs: m(t.expireMs)
|
|
67
65
|
} }) : e;
|
|
68
66
|
}
|
|
69
|
-
function
|
|
70
|
-
return { version:
|
|
67
|
+
function _() {
|
|
68
|
+
return { version: 2 };
|
|
71
69
|
}
|
|
72
70
|
//#endregion
|
|
73
|
-
export {
|
|
71
|
+
export { h as cacheAuthorizationToken, g as clearCachedAuthorizationToken, f as getPersistedIdentity, m as parseAuthorizationExpireMs, p as updatePersistedIdentity };
|
|
@@ -1,66 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import a from "node:path";
|
|
5
|
-
//#region src/modules/configs/state-flags.ts
|
|
6
|
-
var o = { DISABLE_SKILLS_LOAD_WATCH_MIGRATION_DONE: "disableSkillsLoadWatchMigrationDone" }, s = ".openclaw", c = "yoyo", l = "state.json", u = 64 * 1024;
|
|
7
|
-
function d() {
|
|
8
|
-
return a.join(s, c, l);
|
|
9
|
-
}
|
|
10
|
-
async function f(r) {
|
|
11
|
-
try {
|
|
12
|
-
let e = await n({
|
|
13
|
-
rootDir: r,
|
|
14
|
-
relativePath: d(),
|
|
15
|
-
maxBytes: u
|
|
16
|
-
});
|
|
17
|
-
return v(JSON.parse(e.buffer.toString("utf8")));
|
|
18
|
-
} catch (n) {
|
|
19
|
-
return n instanceof t && n.code === "not-found" || e().warn(`[yoyo-state] failed to read state: ${String(n)}`), null;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
async function p() {
|
|
23
|
-
let t = i();
|
|
24
|
-
return t ? f(t) : (e().warn("[yoyo-state] failed to find home dir"), null);
|
|
25
|
-
}
|
|
26
|
-
async function m(t) {
|
|
27
|
-
let n = i();
|
|
28
|
-
if (!n) return e().warn("[yoyo-state] failed to find home dir"), null;
|
|
29
|
-
let a = {
|
|
30
|
-
...await f(n) ?? _(),
|
|
31
|
-
version: 1
|
|
32
|
-
};
|
|
33
|
-
return t.flags && (a.flags = {
|
|
34
|
-
...a.flags,
|
|
35
|
-
...y(t.flags)
|
|
36
|
-
}), await r({
|
|
37
|
-
rootDir: n,
|
|
38
|
-
relativePath: d(),
|
|
39
|
-
data: JSON.stringify(a, null, 2),
|
|
40
|
-
encoding: "utf8",
|
|
41
|
-
mkdir: !0
|
|
42
|
-
}), a;
|
|
43
|
-
}
|
|
44
|
-
async function h(e) {
|
|
45
|
-
return (await p())?.flags?.[e] === !0;
|
|
46
|
-
}
|
|
47
|
-
async function g(e) {
|
|
48
|
-
return m({ flags: { [e]: !0 } });
|
|
49
|
-
}
|
|
50
|
-
function _() {
|
|
51
|
-
return { version: 1 };
|
|
52
|
-
}
|
|
53
|
-
function v(e) {
|
|
54
|
-
return !e || typeof e != "object" || Array.isArray(e) ? _() : {
|
|
55
|
-
..._(),
|
|
56
|
-
flags: y(e.flags)
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
function y(e) {
|
|
60
|
-
if (!e || typeof e != "object" || Array.isArray(e)) return;
|
|
61
|
-
let t = {};
|
|
62
|
-
for (let [n, r] of Object.entries(e)) typeof r == "boolean" && (t[n] = r);
|
|
63
|
-
return Object.keys(t).length > 0 ? t : void 0;
|
|
64
|
-
}
|
|
65
|
-
//#endregion
|
|
66
|
-
export { o as STATE_FLAG, p as getPersistedPluginState, h as hasPersistedStateFlag, g as markPersistedStateFlag, m as updatePersistedPluginState };
|
|
1
|
+
import "../../utils/fs-safe.mjs";
|
|
2
|
+
import "../../utils/home-dir.mjs";
|
|
3
|
+
import "node:path";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { useClawLogger as e } from "../../utils/logger.mjs";
|
|
2
|
+
import { getConfigManager as t } from "../configs/config-manager.mjs";
|
|
3
|
+
import { getYoyoPluginVersionCode as n } from "../../utils/version.mjs";
|
|
4
4
|
import { isOKResponse as r } from "../../apis/helpers.mjs";
|
|
5
5
|
import { createClawCloudClient as i } from "../../apis/claw-cloud.mjs";
|
|
6
6
|
import { getPersistedIdentity as a, updatePersistedIdentity as o } from "../configs/identity-persist.mjs";
|
|
@@ -9,28 +9,28 @@ import "../../apis/index.mjs";
|
|
|
9
9
|
import { formatHashForLog as s } from "../../utils/hash.mjs";
|
|
10
10
|
import { createGatewayAuthMd5 as c, isSameGatewayAuthMd5 as l } from "./gateway-auth.mjs";
|
|
11
11
|
//#region src/modules/device/registry.ts
|
|
12
|
-
async function u(
|
|
13
|
-
if (!
|
|
14
|
-
let o =
|
|
12
|
+
async function u(e, a) {
|
|
13
|
+
if (!e || !a) throw Error("设备信息或用户信息缺失");
|
|
14
|
+
let o = t().getGatewayAuthConfig(), s = c(o), l = n(), u = await i().registerDevice(e, a, o);
|
|
15
15
|
if (!r(u)) throw Error(`注册失败:${u.data?.cnMessage}`);
|
|
16
16
|
await f(s, l);
|
|
17
17
|
}
|
|
18
18
|
async function d(r, i) {
|
|
19
|
-
let o = c(
|
|
19
|
+
let o = c(t().getGatewayAuthConfig()), d = n(), f = await a(), p = f?.gatewayAuthMd5, m = f?.pluginVersionCode, h = e();
|
|
20
20
|
if (h.info(`[yoyoclaw-registry] checking registration state: gatewayAuth current=${s(o)}, persisted=${s(p)}; pluginVersionCode current=${d}, persisted=${m ?? "none"}`), l(p, o) && m === d) {
|
|
21
21
|
h.info("[yoyoclaw-registry] registration state unchanged, skipping device registration");
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
h.info("[yoyoclaw-registry] registration state changed, registering device"), await u(r, i), h.info(`[yoyoclaw-registry] device registration succeeded, pluginVersionCode=${d}`);
|
|
25
25
|
}
|
|
26
|
-
async function f(
|
|
26
|
+
async function f(t, n) {
|
|
27
27
|
try {
|
|
28
28
|
await o({
|
|
29
|
-
gatewayAuthMd5:
|
|
29
|
+
gatewayAuthMd5: t,
|
|
30
30
|
pluginVersionCode: n
|
|
31
|
-
}),
|
|
32
|
-
} catch (
|
|
33
|
-
|
|
31
|
+
}), e().info("[yoyoclaw-registry] registration state persisted after device registration");
|
|
32
|
+
} catch (t) {
|
|
33
|
+
e().warn(`[yoyoclaw-registry] failed to persist registration state: ${String(t)}`);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
//#endregion
|
package/dist/utils/version.mjs
CHANGED
|
@@ -1,27 +1,59 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getYoyoRuntime as e } from "../runtime.mjs";
|
|
2
|
+
import { findPackageRoot as t, readPackageJson as n } from "./package-json.mjs";
|
|
2
3
|
//#region src/utils/version.ts
|
|
3
|
-
var
|
|
4
|
-
function
|
|
5
|
-
|
|
4
|
+
var r = "@honor-claw/yoyo", i = 3;
|
|
5
|
+
function a() {
|
|
6
|
+
try {
|
|
7
|
+
let t = e().version;
|
|
8
|
+
return o(t);
|
|
9
|
+
} catch {
|
|
10
|
+
return i;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function o(e) {
|
|
14
|
+
let t = s(e);
|
|
15
|
+
return t && c(t, [
|
|
16
|
+
2026,
|
|
17
|
+
5,
|
|
18
|
+
12
|
|
19
|
+
]) >= 0 ? 4 : i;
|
|
20
|
+
}
|
|
21
|
+
function s(e) {
|
|
22
|
+
if (!e) return null;
|
|
23
|
+
let t = e.split("-", 1)[0].split(".");
|
|
24
|
+
if (t.length === 0) return null;
|
|
25
|
+
let n = t.map((e) => Number.parseInt(e, 10));
|
|
26
|
+
return n.some((e) => !Number.isFinite(e) || e < 0) ? null : n;
|
|
27
|
+
}
|
|
28
|
+
function c(e, t) {
|
|
29
|
+
let n = Math.max(e.length, t.length);
|
|
30
|
+
for (let r = 0; r < n; r += 1) {
|
|
31
|
+
let n = e[r] ?? 0, i = t[r] ?? 0;
|
|
32
|
+
if (n !== i) return n - i;
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
function l() {
|
|
37
|
+
let e = f();
|
|
6
38
|
return e.includes("beta") || e.includes("alpha");
|
|
7
39
|
}
|
|
8
|
-
function
|
|
40
|
+
function u(e) {
|
|
9
41
|
if (!e) return 0;
|
|
10
42
|
let t = Number.parseInt(e, 10);
|
|
11
43
|
return Number.isFinite(t) && t >= 0 ? t : 0;
|
|
12
44
|
}
|
|
13
|
-
function
|
|
14
|
-
let [e, t, n] =
|
|
15
|
-
return r * 1e6 +
|
|
45
|
+
function d() {
|
|
46
|
+
let [e, t, n] = f().split("-", 1)[0].split("."), r = u(e), i = u(t), a = u(n);
|
|
47
|
+
return r * 1e6 + i * 1e3 + a;
|
|
16
48
|
}
|
|
17
|
-
function
|
|
49
|
+
function f() {
|
|
18
50
|
try {
|
|
19
|
-
let
|
|
20
|
-
if (!
|
|
21
|
-
let i =
|
|
51
|
+
let e = t(import.meta.url, r);
|
|
52
|
+
if (!e) return "0.0.0";
|
|
53
|
+
let i = n(e)?.version;
|
|
22
54
|
if (typeof i == "string") return i;
|
|
23
55
|
} catch {}
|
|
24
56
|
return "0.0.0";
|
|
25
57
|
}
|
|
26
58
|
//#endregion
|
|
27
|
-
export { a as getYoyoPluginVersionCode,
|
|
59
|
+
export { a as getProtocolVersion, d as getYoyoPluginVersionCode, l as isBetaVersion };
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honor-claw/yoyo",
|
|
3
|
-
"version": "1.6.0
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "OpenClaw Honor Yoyo connection plugin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"build": "vite build",
|
|
28
28
|
"ci:check": "npx tsc --noEmit && npm run test:coverage",
|
|
29
|
+
"format": "oxfmt",
|
|
30
|
+
"format:fix": "oxfmt --write",
|
|
31
|
+
"lint": "oxlint src/",
|
|
32
|
+
"lint:fix": "oxlint --fix src/",
|
|
29
33
|
"publish:alpha": "npm run build && node scripts/publish.js --alpha",
|
|
30
34
|
"publish:beta": "npm run build && node scripts/publish.js",
|
|
31
35
|
"publish:latest": "npm run build && node scripts/publish.js --release",
|
|
@@ -49,6 +53,8 @@
|
|
|
49
53
|
"@types/node": "^25.0.10",
|
|
50
54
|
"@types/ws": "^8.5.13",
|
|
51
55
|
"@vitest/coverage-v8": "^2.1.8",
|
|
56
|
+
"oxfmt": "^0.55.0",
|
|
57
|
+
"oxlint": "^1.70.0",
|
|
52
58
|
"typescript": "^6.0.2",
|
|
53
59
|
"vite": "^8.0.10",
|
|
54
60
|
"vitest": "^2.1.8"
|
|
@@ -140,8 +140,6 @@ metadata: { "openclaw": { "emoji": "📱", "always": true } }
|
|
|
140
140
|
| `flashlight` | `references/flashlight.md` | 手电筒控制 |
|
|
141
141
|
| `airplane-mode` | `references/airplane-mode.md` | 飞行模式管理 |
|
|
142
142
|
| `clean-dirty` | `references/clean-dirty.md` | 扬声器清理 |
|
|
143
|
-
| `flight-monitor` | `references/flight-monitor-create.md` | 创建机票价格监控 |
|
|
144
|
-
| `flight-monitor` | `references/flight-monitor-search.md` | 查询机票监控任务 |
|
|
145
143
|
| `express` | `references/express-logistics-search.md` | 快递查询 |
|
|
146
144
|
| `countdown-timer` | `references/countdown-timer.md` | 倒计时计时器管理 |
|
|
147
145
|
| `desktop` | `references/desktop.md` | 手机桌面管理,支持查询桌面布局、打开桌面设置页,并对风格、应用角标、桌面图标、快捷方式、搜索入口、应用名称、通透模式与布局等进行配置。 |
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: flight-monitor.create
|
|
3
|
-
description: >
|
|
4
|
-
创建机票价格监控任务。支持设置目的地、出发地、监控时间段与目标价格,缺省或低于最低监控价时给出价格区间与建议价。
|
|
5
|
-
只支持飞机票价的监控任务创建,其余票务类型(如酒店、机票联程、火车票等)暂不支持。
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Create Flight Monitor Task 创建机票监控任务
|
|
9
|
-
|
|
10
|
-
## Tool Provider
|
|
11
|
-
```bash
|
|
12
|
-
com.hihonor.magicvoice
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Tool Command
|
|
16
|
-
```bash
|
|
17
|
-
create_flight_monitor_task
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## 3. 业务规则
|
|
21
|
-
|
|
22
|
-
### 适用场景及操作流程
|
|
23
|
-
1. 解析并提取目的地城市、出发地城市、监控时间段与目标价格
|
|
24
|
-
2. 未提供出发地时,默认使用用户当前位置城市
|
|
25
|
-
3. 未提供目的地时,提醒用户指定目的地
|
|
26
|
-
4. 对价格进行币种识别与人民币换算,并向下取整
|
|
27
|
-
5. 当未指定监控价格或设定价格低于最低可监控价时,工具返回可监控价格区间与建议价
|
|
28
|
-
6. 创建机票价格监控任务并开始持续监控
|
|
29
|
-
|
|
30
|
-
### 特定交互
|
|
31
|
-
- 币种默认人民币;如检测到外币(如 USD、美元),按实时汇率换算为人民币后取整
|
|
32
|
-
- 城市名必须为具体城市中文名,不支持省份或国家级地名
|
|
33
|
-
- 监控时间段使用用户原始的自然语言日期表述(如“下周二到下周三”“10月1日-10月7日”),不做改写
|
|
34
|
-
- 价格仅提取数值部分,取整为不大于该值的整数;“以内/不高于/低于”等等价于上限价
|
|
35
|
-
|
|
36
|
-
## 4. 集成工作流
|
|
37
|
-
|
|
38
|
-
### Step 1: 意图解析与参数组装
|
|
39
|
-
```
|
|
40
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
41
|
-
│ 意图识别与参数提取 │
|
|
42
|
-
│ - 识别操作意图: 创建 + 机票价格监控任务 │
|
|
43
|
-
│ - 提取目的地城市: 城市中文名(不含省/国家) │
|
|
44
|
-
│ - 提取出发地城市: 城市中文名(缺省为当前位置) │
|
|
45
|
-
│ - 提取监控时间段: 自然语言日期描述(直接保留) │
|
|
46
|
-
│ - 提取目标价格: 数字,币种识别与换算,向下取整 │
|
|
47
|
-
│ - 特殊处理: "飞/去/到" 等同义词统一识别为目的地 │
|
|
48
|
-
└─────────────────────────────────────────────────────────────┘
|
|
49
|
-
↓
|
|
50
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
51
|
-
│ 消歧与槽位填充 │
|
|
52
|
-
│ - 未指定出发地时,默认为用户当前位置城市 │
|
|
53
|
-
│ - 未指定监控价格时,返回价格区间与建议价 │
|
|
54
|
-
│ - 价格低于最低可监控价时,提示范围并给出建议价 │
|
|
55
|
-
│ - date_time 仅当 query 含时间表述时填写 │
|
|
56
|
-
│ - 验证规则: 目的地与出发地不能相同 │
|
|
57
|
-
│ - "从/出发地" → 映射为出发地槽位 │
|
|
58
|
-
└─────────────────────────────────────────────────────────────┘
|
|
59
|
-
↓
|
|
60
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
61
|
-
│ 生成工具调用 │
|
|
62
|
-
│ - 组装 destination_city 及可选参数(departure_city, │
|
|
63
|
-
│ date_time, price) │
|
|
64
|
-
│ - 生成平台特定的命令格式 │
|
|
65
|
-
└─────────────────────────────────────────────────────────────┘
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Step 2: 执行调用
|
|
69
|
-
- 根据操作系统选择对应的命令格式
|
|
70
|
-
- Windows: Cmd 格式(双引号需转义)
|
|
71
|
-
- Linux: Bash 格式(单引号包裹)
|
|
72
|
-
|
|
73
|
-
## 5. 参数定义
|
|
74
|
-
### 工具输入参数说明
|
|
75
|
-
```json
|
|
76
|
-
{
|
|
77
|
-
"destination_city": {
|
|
78
|
-
"type": "string",
|
|
79
|
-
"description": "必填参数,机票监控的目的地城市中文名称,不支持省份或国家。如:深圳、北京。"
|
|
80
|
-
},
|
|
81
|
-
"departure_city": {
|
|
82
|
-
"type": "string",
|
|
83
|
-
"description": "机票监控的出发地城市中文名称,默认为用户当前位置所在城市,不支持省份或国家。如:深圳、北京。"
|
|
84
|
-
},
|
|
85
|
-
"date_time": {
|
|
86
|
-
"type": "string",
|
|
87
|
-
"description": "监控时间段的自然语言描述,直接提取用户输入中日期的描述。如:下周、下周二到下周三、周一下午。"
|
|
88
|
-
},
|
|
89
|
-
"price": {
|
|
90
|
-
"type": "integer",
|
|
91
|
-
"description": "用户设定的监控目标最高价格。直接提取价格数字,向下取整。默认币种人民币,其他币种需换算人民币。如果没有指定币种,按照人民币处理。"
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### 工具输出参数说明
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"result_code": {
|
|
100
|
-
"type": "integer",
|
|
101
|
-
"description": "结果状态码。100:执行成功。201:用户没有指定价格时返回,追问用户需要设置的监控价格,同时返回价格区间(suggested_price_range)与推荐价格(suggested_price)。202:追问,没有出发地城市,同时当前城市查询失败时追问。304:未授权三方账号,用户拒绝授权三方。406:授权三方失败。500:出发地不在支持列表范围内。501:目的地不在支持列表范围内。502:监控日期超出监控范围。503:查询监控价格失败,当前航线未查询到直飞航班报价。504:用户设置的监控价格过低,低于最低可监控价格,同时返回价格区间(suggested_price_range)与推荐价格(suggested_price)。505:监控任务创建失败。506:已存在重复监控任务。507:监控任务已达上限。"
|
|
102
|
-
},
|
|
103
|
-
"result_content": {
|
|
104
|
-
"type": "string",
|
|
105
|
-
"description": "针对不同状态码场景下,详细的执行结果,包含错误原因等。"
|
|
106
|
-
},
|
|
107
|
-
"suggested_price_range": {
|
|
108
|
-
"type": "string",
|
|
109
|
-
"description": "工具根据历史数据建议的价格区间,货币单位为人民币,格式为最低可监控价格-最高监控价格,如:500-1000。"
|
|
110
|
-
},
|
|
111
|
-
"suggested_price": {
|
|
112
|
-
"type": "integer",
|
|
113
|
-
"description": "工具建议的监控目标价格,货币单位为人民币。"
|
|
114
|
-
},
|
|
115
|
-
"departure_city": {
|
|
116
|
-
"type": "string",
|
|
117
|
-
"description": "出发地城市中文名称。如:深圳、北京。"
|
|
118
|
-
},
|
|
119
|
-
"destination_city": {
|
|
120
|
-
"type": "string",
|
|
121
|
-
"description": "目的地城市中文名称。如:深圳、北京。"
|
|
122
|
-
},
|
|
123
|
-
"date_range": {
|
|
124
|
-
"type": "string",
|
|
125
|
-
"description": "监控的日期范围,格式为 YYYY-MM-DD~YYYY-MM-DD。"
|
|
126
|
-
},
|
|
127
|
-
"price": {
|
|
128
|
-
"type": "integer",
|
|
129
|
-
"description": "用户设置的监控价格,货币单位为人民币,未提供或小于最低可监控价格则设为0。"
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
### 参数注意事项
|
|
136
|
-
1. **默认值或缺省行为**: 未提供`departure_city`时默认取用户当前位置城市;未提供`price`时由工具返回可监控价格区间与建议价;未标明币种时按人民币处理。
|
|
137
|
-
2. **参数间关联/验证**: `destination_city`为必填且不得与`departure_city`相同;外币价格需先换算为人民币后再对`price`进行向下取整。
|
|
138
|
-
3. **可选参数填写条件**: `date_time`仅在用户明确提及时间/日期时填写,不做推断;`departure_city`仅在用户未使用默认定位或明确指定时填写。
|
|
139
|
-
|
|
140
|
-
### date_time 参数格式转换
|
|
141
|
-
1. 当用户输入包含时间表述时,工具会直接保留原始的自然语言日期表述,然后调用`scripts/time_infer.py`时间推理模型进行转换。具体执行指令如下:
|
|
142
|
-
```bash
|
|
143
|
-
python3 scripts/time_infer.py --query <date_time>
|
|
144
|
-
```
|
|
145
|
-
2. 拿到json-string格式的转换结果,重新改写`date_time`参数,并调用`openclaw nodes invoke`命令执行工具。
|
|
146
|
-
3. 注意:time_infer模型返回的结果格式如下:`{"data_time": {...}}`,用`{...}`JSONstring的完整内容重写`date_time`参数。**不能拆解{...}的内容**
|
|
147
|
-
|
|
148
|
-
## 6. Query 示例及输出
|
|
149
|
-
|
|
150
|
-
### 示例 1: 指定出发地、时间段与人民币价格上限
|
|
151
|
-
**用户输入**: "帮我监控一下去上海的机票,出发地是北京,时间是十月一号到十月七号,价格设为1000元以内"
|
|
152
|
-
|
|
153
|
-
**工具**: "create_flight_monitor_task"
|
|
154
|
-
|
|
155
|
-
**JSON 参数**:
|
|
156
|
-
```json
|
|
157
|
-
{
|
|
158
|
-
"destination_city": "上海",
|
|
159
|
-
"departure_city": "北京",
|
|
160
|
-
"date_time": "十月一号到十月七号",
|
|
161
|
-
"price": 1000
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
**调用时间推理模型**:
|
|
165
|
-
```bash
|
|
166
|
-
python3 scripts/time_infer.py --query "十月一号到十月七号"
|
|
167
|
-
```
|
|
168
|
-
返回结果: {"data_time": <json-string-data>} (注意字符串转义的问题!!!)
|
|
169
|
-
|
|
170
|
-
**Windows (Cmd) 执行命令**:
|
|
171
|
-
```bash
|
|
172
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"create_flight_monitor_task\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{\"destination_city\":\"上海\",\"departure_city\":\"北京\",\"date_time\":\"<json-string-data>\",\"price\":1000}}"'
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
**Linux (Bash) 执行命令**:
|
|
176
|
-
```bash
|
|
177
|
-
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"create_flight_monitor_task","appPkg":"com.hihonor.magicvoice","arguments":{"destination_city":"上海","departure_city":"北京","date_time":"<json-string-data>","price":1000}}'
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
### 示例 2: 仅目的地与美元价格(自动换算为人民币)
|
|
183
|
-
**用户输入**: "帮我监控飞广州的机票,价格低于200美元就提醒"
|
|
184
|
-
|
|
185
|
-
**工具**: "create_flight_monitor_task"
|
|
186
|
-
|
|
187
|
-
**JSON 参数**:
|
|
188
|
-
```json
|
|
189
|
-
{
|
|
190
|
-
"destination_city": "广州",
|
|
191
|
-
"price": 1440
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
**Windows (Cmd) 执行命令**:
|
|
196
|
-
```bash
|
|
197
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"create_flight_monitor_task\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{\"destination_city\":\"广州\",\"price\":1440}}"'
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
**Linux (Bash) 执行命令**:
|
|
201
|
-
```bash
|
|
202
|
-
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"create_flight_monitor_task","appPkg":"com.hihonor.magicvoice","arguments":{"destination_city":"广州","price":1440}}'
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
### 示例 3: 指定目的地与出发时段,不设价格(工具返回建议价)
|
|
208
|
-
**用户输入**: "帮我关注去杭州的机票,下周三下午出发"
|
|
209
|
-
|
|
210
|
-
**工具**: "create_flight_monitor_task"
|
|
211
|
-
|
|
212
|
-
**JSON 参数**:
|
|
213
|
-
```json
|
|
214
|
-
{
|
|
215
|
-
"destination_city": "杭州",
|
|
216
|
-
"date_time": "下周三下午"
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
**调用时间推理模型**:
|
|
220
|
-
```bash
|
|
221
|
-
python3 scripts/time_infer.py --query "下周三下午"
|
|
222
|
-
```
|
|
223
|
-
返回结果: {"data_time": <json-string-data>} (注意字符串转义的问题!!!)
|
|
224
|
-
|
|
225
|
-
**Windows (Cmd) 执行命令**:
|
|
226
|
-
```bash
|
|
227
|
-
cmd /c 'openclaw nodes invoke --node <ID> --command mcp.tool.call --params "{\"name\":\"create_flight_monitor_task\",\"appPkg\":\"com.hihonor.magicvoice\",\"arguments\":{\"destination_city\":\"杭州\",\"date_time\":\"<json-string-data>\"}}"'
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
**Linux (Bash) 执行命令**:
|
|
231
|
-
```bash
|
|
232
|
-
openclaw nodes invoke --node <ID> --command mcp.tool.call --params '{"name":"create_flight_monitor_task","appPkg":"com.hihonor.magicvoice","arguments":{"destination_city":"杭州","date_time":"<json-string-data>"}}'
|
|
233
|
-
```
|