@atel-ai/runtime-core 0.1.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/adapters/claude-code.d.ts +3 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +65 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +3 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +49 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/gemini-cli.d.ts +3 -0
- package/dist/adapters/gemini-cli.d.ts.map +1 -0
- package/dist/adapters/gemini-cli.js +43 -0
- package/dist/adapters/gemini-cli.js.map +1 -0
- package/dist/adapters/hermes.d.ts +3 -0
- package/dist/adapters/hermes.d.ts.map +1 -0
- package/dist/adapters/hermes.js +58 -0
- package/dist/adapters/hermes.js.map +1 -0
- package/dist/adapters/openclaw.d.ts +13 -0
- package/dist/adapters/openclaw.d.ts.map +1 -0
- package/dist/adapters/openclaw.js +36 -0
- package/dist/adapters/openclaw.js.map +1 -0
- package/dist/adapters/qwen-agent.d.ts +3 -0
- package/dist/adapters/qwen-agent.d.ts.map +1 -0
- package/dist/adapters/qwen-agent.js +128 -0
- package/dist/adapters/qwen-agent.js.map +1 -0
- package/dist/adapters/registry.d.ts +20 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +42 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/types.d.ts +46 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/util.d.ts +10 -0
- package/dist/adapters/util.d.ts.map +1 -0
- package/dist/adapters/util.js +86 -0
- package/dist/adapters/util.js.map +1 -0
- package/dist/auth.d.ts +42 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +91 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +55 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +139 -0
- package/dist/client.js.map +1 -0
- package/dist/companion.d.ts +45 -0
- package/dist/companion.d.ts.map +1 -0
- package/dist/companion.js +224 -0
- package/dist/companion.js.map +1 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +29 -0
- package/dist/config.js.map +1 -0
- package/dist/deadletter.d.ts +31 -0
- package/dist/deadletter.d.ts.map +1 -0
- package/dist/deadletter.js +67 -0
- package/dist/deadletter.js.map +1 -0
- package/dist/envelope.d.ts +21 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +20 -0
- package/dist/envelope.js.map +1 -0
- package/dist/events/channel-relay.d.ts +35 -0
- package/dist/events/channel-relay.d.ts.map +1 -0
- package/dist/events/channel-relay.js +97 -0
- package/dist/events/channel-relay.js.map +1 -0
- package/dist/events/channel-spine.d.ts +41 -0
- package/dist/events/channel-spine.d.ts.map +1 -0
- package/dist/events/channel-spine.js +139 -0
- package/dist/events/channel-spine.js.map +1 -0
- package/dist/events/dedup.d.ts +25 -0
- package/dist/events/dedup.d.ts.map +1 -0
- package/dist/events/dedup.js +56 -0
- package/dist/events/dedup.js.map +1 -0
- package/dist/events/mapping.d.ts +37 -0
- package/dist/events/mapping.d.ts.map +1 -0
- package/dist/events/mapping.js +212 -0
- package/dist/events/mapping.js.map +1 -0
- package/dist/events/roles.d.ts +21 -0
- package/dist/events/roles.d.ts.map +1 -0
- package/dist/events/roles.js +80 -0
- package/dist/events/roles.js.map +1 -0
- package/dist/events/types.d.ts +51 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +96 -0
- package/dist/events/types.js.map +1 -0
- package/dist/identity.d.ts +48 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +123 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/queue.d.ts +12 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +25 -0
- package/dist/queue.js.map +1 -0
- package/dist/tracker.d.ts +27 -0
- package/dist/tracker.d.ts.map +1 -0
- package/dist/tracker.js +80 -0
- package/dist/tracker.js.map +1 -0
- package/dist/wakers/cli.d.ts +36 -0
- package/dist/wakers/cli.d.ts.map +1 -0
- package/dist/wakers/cli.js +116 -0
- package/dist/wakers/cli.js.map +1 -0
- package/dist/wakers/daemon.d.ts +26 -0
- package/dist/wakers/daemon.d.ts.map +1 -0
- package/dist/wakers/daemon.js +51 -0
- package/dist/wakers/daemon.js.map +1 -0
- package/dist/wakers/embedded.d.ts +23 -0
- package/dist/wakers/embedded.d.ts.map +1 -0
- package/dist/wakers/embedded.js +26 -0
- package/dist/wakers/embedded.js.map +1 -0
- package/dist/wakers/types.d.ts +29 -0
- package/dist/wakers/types.d.ts.map +1 -0
- package/dist/wakers/types.js +2 -0
- package/dist/wakers/types.js.map +1 -0
- package/package.json +44 -0
- package/src/skill/SKILL.md +80 -0
package/dist/tracker.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 订单跟踪器 —— 失败自治的状态底座(6.5 §6 / 测试 D-4)。
|
|
3
|
+
*
|
|
4
|
+
* agent 无状态,但 companion 要做超时退款 / 驳回转仲裁这类兜底,需要轻量记账:
|
|
5
|
+
* - 每单首见时间(判 escrow deadline 超时)
|
|
6
|
+
* - 当前是否终态(settled/cancelled/dispute.resolved → 不再兜底)
|
|
7
|
+
* - 累计驳回次数(达 threshold → 提示转 dispute)
|
|
8
|
+
* - 已触发过的自治动作(只触发一次)
|
|
9
|
+
* 这是续跑的依据:companion 重启后从这里 + atel_order_get 续上,不丢单。
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
const TERMINAL = ['order.settled', 'order.cancelled', 'order.dispute.resolved'];
|
|
14
|
+
export class OrderTracker {
|
|
15
|
+
filePath;
|
|
16
|
+
orders = {};
|
|
17
|
+
constructor(filePath) {
|
|
18
|
+
this.filePath = filePath;
|
|
19
|
+
this.load();
|
|
20
|
+
}
|
|
21
|
+
load() {
|
|
22
|
+
try {
|
|
23
|
+
if (fs.existsSync(this.filePath)) {
|
|
24
|
+
this.orders = JSON.parse(fs.readFileSync(this.filePath, 'utf8')) || {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
this.orders = {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
save() {
|
|
32
|
+
try {
|
|
33
|
+
fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
|
|
34
|
+
fs.writeFileSync(this.filePath, JSON.stringify(this.orders, null, 2));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* best-effort */
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
observe(orderId, type) {
|
|
41
|
+
if (!orderId)
|
|
42
|
+
return;
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
const prev = this.orders[orderId] ||
|
|
45
|
+
{ orderId, firstSeenAt: now, lastEventAt: now, lastEvent: type, rejectCount: 0, terminal: false, firedActions: [] };
|
|
46
|
+
prev.lastEventAt = now;
|
|
47
|
+
prev.lastEvent = type;
|
|
48
|
+
if (type === 'milestone.rejected')
|
|
49
|
+
prev.rejectCount += 1;
|
|
50
|
+
if (TERMINAL.includes(type))
|
|
51
|
+
prev.terminal = true;
|
|
52
|
+
this.orders[orderId] = prev;
|
|
53
|
+
this.save();
|
|
54
|
+
}
|
|
55
|
+
/** 已超过 deadline 且仍非终态、且该动作没触发过的单。 */
|
|
56
|
+
staleOrders(deadlineMs, action) {
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
return Object.values(this.orders).filter((o) => !o.terminal && now - o.firstSeenAt > deadlineMs && !o.firedActions.includes(action));
|
|
59
|
+
}
|
|
60
|
+
/** 驳回达阈值且未触发过 dispute 提示的单。 */
|
|
61
|
+
rejectThresholdHits(threshold, action) {
|
|
62
|
+
return Object.values(this.orders).filter((o) => !o.terminal && o.rejectCount >= threshold && !o.firedActions.includes(action));
|
|
63
|
+
}
|
|
64
|
+
markFired(orderId, action) {
|
|
65
|
+
const o = this.orders[orderId];
|
|
66
|
+
if (!o)
|
|
67
|
+
return;
|
|
68
|
+
if (!o.firedActions.includes(action)) {
|
|
69
|
+
o.firedActions.push(action);
|
|
70
|
+
this.save();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
get(orderId) {
|
|
74
|
+
return this.orders[orderId];
|
|
75
|
+
}
|
|
76
|
+
all() {
|
|
77
|
+
return Object.values(this.orders);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../src/tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Waker, WakeRequest, WakeResult } from './types.js';
|
|
2
|
+
export interface CliWakerSpec {
|
|
3
|
+
/** 可执行文件(绝对路径或 PATH 中可解析名) */
|
|
4
|
+
bin: string;
|
|
5
|
+
/**
|
|
6
|
+
* 构造 argv。isResume=true 表示该 sessionId 之前已起过,适配器可换成 --resume/--continue。
|
|
7
|
+
* 返回不含 bin 的参数数组。
|
|
8
|
+
*/
|
|
9
|
+
buildArgs: (ctx: {
|
|
10
|
+
prompt: string;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
isResume: boolean;
|
|
13
|
+
}) => string[];
|
|
14
|
+
/** 额外 env。给函数则每次唤醒前求值(JWT 续期后能拿到最新值)。 */
|
|
15
|
+
env?: Record<string, string> | (() => Record<string, string>);
|
|
16
|
+
cwd?: string;
|
|
17
|
+
/** 默认单次超时(冷启首次可能慢,Hermes 实测首跑 220s,给足) */
|
|
18
|
+
defaultTimeoutMs?: number;
|
|
19
|
+
maxBuffer?: number;
|
|
20
|
+
/** started 会话集落盘路径(跨重启续跑必需;不给则只在内存,重启后失忆) */
|
|
21
|
+
sessionStatePath?: string;
|
|
22
|
+
log?: (msg: string) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare class CliWaker implements Waker {
|
|
25
|
+
private readonly spec;
|
|
26
|
+
readonly kind: "cli";
|
|
27
|
+
private started;
|
|
28
|
+
constructor(spec: CliWakerSpec);
|
|
29
|
+
wake(req: WakeRequest): Promise<WakeResult>;
|
|
30
|
+
private attempt;
|
|
31
|
+
private markStarted;
|
|
32
|
+
private loadStarted;
|
|
33
|
+
private saveStarted;
|
|
34
|
+
private log;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/wakers/cli.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,SAAS,EAAE,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,KAAK,MAAM,EAAE,CAAC;IACvF,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAOD,qBAAa,QAAS,YAAW,KAAK;IAIxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAC/B,OAAO,CAAC,OAAO,CAAqB;gBAEP,IAAI,EAAE,YAAY;IAIzC,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAQjD,OAAO,CAAC,OAAO;IAsDf,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,GAAG;CAGZ"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ① CLI 无头唤醒器 —— spawn/resume 一条命令。
|
|
3
|
+
*
|
|
4
|
+
* 各家 CLI 的具体 flag 由适配器的 buildArgs 给(argv 数组,绝不拼 shell 字符串,
|
|
5
|
+
* 见 feedback_codex_audit)。本驱动负责:进程拉起、超时、session lock 退避重试、
|
|
6
|
+
* 热会话 resume 状态跟踪(跨重启持久化)。
|
|
7
|
+
*
|
|
8
|
+
* 热会话坑(真机实测):claude `-p --session-id <已存在的 id>` 会**挂住**(不是报错),
|
|
9
|
+
* 已存在会话必须用 `--resume`。所以 started 集合要落盘——companion 重启后才知道该
|
|
10
|
+
* resume 而不是重新 --session-id 把自己挂死(D-3 续跑)。再加自适应回退:resume
|
|
11
|
+
* 报"无此会话"→退回 create;create 报"已存在"→退回 resume。
|
|
12
|
+
*/
|
|
13
|
+
import { execFile } from 'node:child_process';
|
|
14
|
+
import { randomUUID } from 'node:crypto';
|
|
15
|
+
import fs from 'node:fs';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
const LOCK_RE = /session.*lock|file lock|already running|EBUSY|locked/i;
|
|
18
|
+
const NO_SESSION_RE = /no conversation|session not found|no session|conversation not found|unknown session/i;
|
|
19
|
+
const EXISTS_RE = /already exists|session.*in use|duplicate session/i;
|
|
20
|
+
const LOCK_RETRY_MAX = 3;
|
|
21
|
+
export class CliWaker {
|
|
22
|
+
spec;
|
|
23
|
+
kind = 'cli';
|
|
24
|
+
started = new Set();
|
|
25
|
+
constructor(spec) {
|
|
26
|
+
this.spec = spec;
|
|
27
|
+
this.loadStarted();
|
|
28
|
+
}
|
|
29
|
+
async wake(req) {
|
|
30
|
+
const sessionId = req.sessionId || randomUUID();
|
|
31
|
+
const timeoutMs = req.timeoutMs ?? this.spec.defaultTimeoutMs ?? 300_000;
|
|
32
|
+
const result = await this.attempt(sessionId, req.prompt, timeoutMs, 0, this.started.has(sessionId));
|
|
33
|
+
if (result.ok)
|
|
34
|
+
this.markStarted(sessionId);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
attempt(sessionId, prompt, timeoutMs, lockAttempt, isResume) {
|
|
38
|
+
const args = this.spec.buildArgs({ prompt, sessionId, isResume });
|
|
39
|
+
const extraEnv = typeof this.spec.env === 'function' ? this.spec.env() : this.spec.env || {};
|
|
40
|
+
const t0 = Date.now();
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
execFile(this.spec.bin, args, {
|
|
43
|
+
timeout: timeoutMs,
|
|
44
|
+
maxBuffer: this.spec.maxBuffer ?? 10 * 1024 * 1024,
|
|
45
|
+
env: { ...process.env, ...extraEnv },
|
|
46
|
+
cwd: this.spec.cwd,
|
|
47
|
+
}, (err, stdout, stderr) => {
|
|
48
|
+
const durationMs = Date.now() - t0;
|
|
49
|
+
const out = (stdout || '').toString();
|
|
50
|
+
const errText = ((err && err.message) || '') + ' ' + (stderr || '');
|
|
51
|
+
if (err && LOCK_RE.test(errText) && lockAttempt < LOCK_RETRY_MAX) {
|
|
52
|
+
const delay = 1500 + lockAttempt * 1500;
|
|
53
|
+
this.log(`session locked, retry ${lockAttempt + 1}/${LOCK_RETRY_MAX} in ${delay}ms`);
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
this.attempt(sessionId, prompt, timeoutMs, lockAttempt + 1, isResume).then(resolve);
|
|
56
|
+
}, delay);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// 自适应回退:create/resume 选错一次 → 翻面重试一次
|
|
60
|
+
if (err && !isResume && EXISTS_RE.test(errText)) {
|
|
61
|
+
this.log(`create hit existing session, retry as resume`);
|
|
62
|
+
this.markStarted(sessionId);
|
|
63
|
+
this.attempt(sessionId, prompt, timeoutMs, lockAttempt, true).then(resolve);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (err && isResume && NO_SESSION_RE.test(errText)) {
|
|
67
|
+
this.log(`resume found no session, retry as create`);
|
|
68
|
+
this.attempt(sessionId, prompt, timeoutMs, lockAttempt, false).then(resolve);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (err) {
|
|
72
|
+
resolve({ ok: false, output: out, error: errText.slice(0, 500).trim(), durationMs, sessionId });
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
resolve({ ok: true, output: out, durationMs, sessionId });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
markStarted(sessionId) {
|
|
81
|
+
if (this.started.has(sessionId))
|
|
82
|
+
return;
|
|
83
|
+
this.started.add(sessionId);
|
|
84
|
+
this.saveStarted();
|
|
85
|
+
}
|
|
86
|
+
loadStarted() {
|
|
87
|
+
if (!this.spec.sessionStatePath)
|
|
88
|
+
return;
|
|
89
|
+
try {
|
|
90
|
+
const arr = JSON.parse(fs.readFileSync(this.spec.sessionStatePath, 'utf8'));
|
|
91
|
+
if (Array.isArray(arr))
|
|
92
|
+
this.started = new Set(arr);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
/* 首次无文件 */
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
saveStarted() {
|
|
99
|
+
if (!this.spec.sessionStatePath)
|
|
100
|
+
return;
|
|
101
|
+
try {
|
|
102
|
+
fs.mkdirSync(path.dirname(this.spec.sessionStatePath), { recursive: true });
|
|
103
|
+
// 上限保护:只留最近 2000 个
|
|
104
|
+
const arr = [...this.started].slice(-2000);
|
|
105
|
+
fs.writeFileSync(this.spec.sessionStatePath, JSON.stringify(arr));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
/* best-effort */
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
log(msg) {
|
|
112
|
+
if (this.spec.log)
|
|
113
|
+
this.spec.log(`[atel/waker:cli] ${msg}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/wakers/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAsB7B,MAAM,OAAO,GAAG,uDAAuD,CAAC;AACxE,MAAM,aAAa,GAAG,sFAAsF,CAAC;AAC7G,MAAM,SAAS,GAAG,mDAAmD,CAAC;AACtE,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,OAAO,QAAQ;IAIU;IAHpB,IAAI,GAAG,KAAc,CAAC;IACvB,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,YAA6B,IAAkB;QAAlB,SAAI,GAAJ,IAAI,CAAc;QAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAgB;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,UAAU,EAAE,CAAC;QAChD,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,OAAO,CAAC;QACzE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;QACpG,IAAI,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,OAAO,CACb,SAAiB,EACjB,MAAc,EACd,SAAiB,EACjB,WAAmB,EACnB,QAAiB;QAEjB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;QAC7F,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;YACzC,QAAQ,CACN,IAAI,CAAC,IAAI,CAAC,GAAG,EACb,IAAI,EACJ;gBACE,OAAO,EAAE,SAAS;gBAClB,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI;gBAClD,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE;gBACpC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG;aACnB,EACD,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;gBACtB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;gBACnC,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;gBACpE,IAAI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,WAAW,GAAG,cAAc,EAAE,CAAC;oBACjE,MAAM,KAAK,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAAC;oBACxC,IAAI,CAAC,GAAG,CAAC,yBAAyB,WAAW,GAAG,CAAC,IAAI,cAAc,OAAO,KAAK,IAAI,CAAC,CAAC;oBACrF,UAAU,CAAC,GAAG,EAAE;wBACd,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACtF,CAAC,EAAE,KAAK,CAAC,CAAC;oBACV,OAAO;gBACT,CAAC;gBACD,oCAAoC;gBACpC,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAChD,IAAI,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;oBACzD,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;oBAC5B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC5E,OAAO;gBACT,CAAC;gBACD,IAAI,GAAG,IAAI,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBACnD,IAAI,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;oBACrD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC7E,OAAO;gBACT,CAAC;gBACD,IAAI,GAAG,EAAE,CAAC;oBACR,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;gBAClG,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,SAAiB;QACnC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO;QACxC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5B,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO;QACxC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;YAC5E,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,WAAW;QACb,CAAC;IACH,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO;QACxC,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5E,mBAAmB;YACnB,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;YAC3C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;IAEO,GAAG,CAAC,GAAW;QACrB,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;IAC9D,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ② 常驻 daemon / 本地 API 唤醒器 —— POST 它的本地接口。
|
|
3
|
+
* 用于 OpenClaw listener、Eliza Sessions API、Witsy webhook 等同类。
|
|
4
|
+
*/
|
|
5
|
+
import type { Waker, WakeRequest, WakeResult } from './types.js';
|
|
6
|
+
export interface DaemonWakerSpec {
|
|
7
|
+
/** 本地接口 URL,如 http://127.0.0.1:PORT/agent */
|
|
8
|
+
url: string;
|
|
9
|
+
/** 构造请求 body */
|
|
10
|
+
buildBody: (ctx: {
|
|
11
|
+
prompt: string;
|
|
12
|
+
sessionId: string;
|
|
13
|
+
}) => unknown;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
/** 从响应里提取输出文本 */
|
|
16
|
+
extractOutput?: (json: unknown, text: string) => string;
|
|
17
|
+
defaultTimeoutMs?: number;
|
|
18
|
+
log?: (msg: string) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare class DaemonWaker implements Waker {
|
|
21
|
+
private readonly spec;
|
|
22
|
+
readonly kind: "daemon";
|
|
23
|
+
constructor(spec: DaemonWakerSpec);
|
|
24
|
+
wake(req: WakeRequest): Promise<WakeResult>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/wakers/daemon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB;IAChB,SAAS,EAAE,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,iBAAiB;IACjB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,qBAAa,WAAY,YAAW,KAAK;IAG3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;gBAEL,IAAI,EAAE,eAAe;IAE5C,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;CAiClD"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export class DaemonWaker {
|
|
2
|
+
spec;
|
|
3
|
+
kind = 'daemon';
|
|
4
|
+
constructor(spec) {
|
|
5
|
+
this.spec = spec;
|
|
6
|
+
}
|
|
7
|
+
async wake(req) {
|
|
8
|
+
const sessionId = req.sessionId || `daemon-${Date.now()}`;
|
|
9
|
+
const timeoutMs = req.timeoutMs ?? this.spec.defaultTimeoutMs ?? 300_000;
|
|
10
|
+
const t0 = Date.now();
|
|
11
|
+
const ctrl = new AbortController();
|
|
12
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
13
|
+
try {
|
|
14
|
+
const res = await fetch(this.spec.url, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: { 'content-type': 'application/json', ...(this.spec.headers || {}) },
|
|
17
|
+
body: JSON.stringify(this.spec.buildBody({ prompt: req.prompt, sessionId })),
|
|
18
|
+
signal: ctrl.signal,
|
|
19
|
+
});
|
|
20
|
+
const text = await res.text().catch(() => '');
|
|
21
|
+
const json = safeJson(text);
|
|
22
|
+
const durationMs = Date.now() - t0;
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
return { ok: false, output: text, error: `HTTP ${res.status}: ${text.slice(0, 200)}`, durationMs, sessionId };
|
|
25
|
+
}
|
|
26
|
+
const output = this.spec.extractOutput ? this.spec.extractOutput(json, text) : text;
|
|
27
|
+
return { ok: true, output, durationMs, sessionId };
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
output: '',
|
|
33
|
+
error: e.message,
|
|
34
|
+
durationMs: Date.now() - t0,
|
|
35
|
+
sessionId,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function safeJson(s) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(s);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/wakers/daemon.ts"],"names":[],"mappings":"AAkBA,MAAM,OAAO,WAAW;IAGO;IAFpB,IAAI,GAAG,QAAiB,CAAC;IAElC,YAA6B,IAAqB;QAArB,SAAI,GAAJ,IAAI,CAAiB;IAAG,CAAC;IAEtD,KAAK,CAAC,IAAI,CAAC,GAAgB;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,UAAU,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,OAAO,CAAC;QACzE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE;gBAC7E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC5E,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;YAChH,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACpF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;QACrD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,EAAE;gBACV,KAAK,EAAG,CAAW,CAAC,OAAO;gBAC3B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;gBAC3B,SAAS;aACV,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ③ 嵌入式库唤醒器 —— 内核起的宿主进程 import agent 库,直接喂 prompt。
|
|
3
|
+
* 用于 Qwen-Agent(python 库)这类:宿主壳暴露一个 invoke(prompt) 函数,
|
|
4
|
+
* 内核通过它唤醒。invoke 通常是 spawn 一个 python 宿主脚本并喂 stdin/stdout,
|
|
5
|
+
* 也可以是同进程的 JS 回调。
|
|
6
|
+
*/
|
|
7
|
+
import type { Waker, WakeRequest, WakeResult } from './types.js';
|
|
8
|
+
export interface EmbeddedWakerSpec {
|
|
9
|
+
/** 宿主壳调用:给 prompt,拿 agent 输出。抛错即视为失败。 */
|
|
10
|
+
invoke: (ctx: {
|
|
11
|
+
prompt: string;
|
|
12
|
+
sessionId: string;
|
|
13
|
+
timeoutMs: number;
|
|
14
|
+
}) => Promise<string>;
|
|
15
|
+
defaultTimeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class EmbeddedWaker implements Waker {
|
|
18
|
+
private readonly spec;
|
|
19
|
+
readonly kind: "embedded";
|
|
20
|
+
constructor(spec: EmbeddedWakerSpec);
|
|
21
|
+
wake(req: WakeRequest): Promise<WakeResult>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=embedded.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded.d.ts","sourceRoot":"","sources":["../../src/wakers/embedded.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,MAAM,EAAE,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3F,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,aAAc,YAAW,KAAK;IAG7B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;gBAEP,IAAI,EAAE,iBAAiB;IAE9C,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;CAiBlD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class EmbeddedWaker {
|
|
2
|
+
spec;
|
|
3
|
+
kind = 'embedded';
|
|
4
|
+
constructor(spec) {
|
|
5
|
+
this.spec = spec;
|
|
6
|
+
}
|
|
7
|
+
async wake(req) {
|
|
8
|
+
const sessionId = req.sessionId || `embedded-${Date.now()}`;
|
|
9
|
+
const timeoutMs = req.timeoutMs ?? this.spec.defaultTimeoutMs ?? 300_000;
|
|
10
|
+
const t0 = Date.now();
|
|
11
|
+
try {
|
|
12
|
+
const output = await this.spec.invoke({ prompt: req.prompt, sessionId, timeoutMs });
|
|
13
|
+
return { ok: true, output, durationMs: Date.now() - t0, sessionId };
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
return {
|
|
17
|
+
ok: false,
|
|
18
|
+
output: '',
|
|
19
|
+
error: e.message,
|
|
20
|
+
durationMs: Date.now() - t0,
|
|
21
|
+
sessionId,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=embedded.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded.js","sourceRoot":"","sources":["../../src/wakers/embedded.ts"],"names":[],"mappings":"AAcA,MAAM,OAAO,aAAa;IAGK;IAFpB,IAAI,GAAG,UAAmB,CAAC;IAEpC,YAA6B,IAAuB;QAAvB,SAAI,GAAJ,IAAI,CAAmB;IAAG,CAAC;IAExD,KAAK,CAAC,IAAI,CAAC,GAAgB;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,YAAY,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC5D,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,OAAO,CAAC;QACzE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;YACpF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC;QACtE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,EAAE;gBACV,KAAK,EAAG,CAAW,CAAC,OAAO;gBAC3B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;gBAC3B,SAAS;aACV,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 无头唤醒器 —— 外部叫醒 agent 的"口子"有三类(6.5 §2),内核每类一个通用驱动:
|
|
3
|
+
* ① CLI 无头 spawn/resume 一条命令 (claude -p / codex exec / hermes chat -q / gemini -p)
|
|
4
|
+
* ② 常驻 daemon POST 它的本地接口 (OpenClaw listener / Eliza Sessions / Witsy webhook)
|
|
5
|
+
* ③ 嵌入式库 宿主进程 import 喂事件 (Qwen-Agent python 库)
|
|
6
|
+
*
|
|
7
|
+
* 唤醒模型优先热会话/resume(6.5 §6-2:每事件冷启慢又贵)。
|
|
8
|
+
*/
|
|
9
|
+
export interface WakeRequest {
|
|
10
|
+
/** 给 agent 的聚焦 prompt(含 orderId/角色) */
|
|
11
|
+
prompt: string;
|
|
12
|
+
/** 会话 key —— 同一订单复用同一会话以 resume(热会话);不传则 waker 自生成 */
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
/** 单次唤醒超时(ms) */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface WakeResult {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
output: string;
|
|
20
|
+
error?: string;
|
|
21
|
+
durationMs: number;
|
|
22
|
+
/** 实际用的会话 id(便于下次 resume) */
|
|
23
|
+
sessionId: string;
|
|
24
|
+
}
|
|
25
|
+
export interface Waker {
|
|
26
|
+
readonly kind: 'cli' | 'daemon' | 'embedded';
|
|
27
|
+
wake(req: WakeRequest): Promise<WakeResult>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/wakers/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC7C,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC7C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/wakers/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atel-ai/runtime-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ATEL agent companion 内核: 两路入站(Spine订阅+relay轮询) + 无头唤醒 + 事件→角色→工具映射 + JWT生命周期 + 失败自治 + 可观测",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./skill/SKILL.md": "./src/skill/SKILL.md",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src/skill",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.json",
|
|
24
|
+
"clean": "rm -rf dist",
|
|
25
|
+
"test": "vitest --run",
|
|
26
|
+
"test:watch": "vitest"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"bs58": "^6.0.0",
|
|
30
|
+
"tweetnacl": "^1.0.3"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.14.0",
|
|
34
|
+
"typescript": "^5.5.0",
|
|
35
|
+
"vitest": "^2.0.0"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT"
|
|
44
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atel-agent
|
|
3
|
+
description: "ATEL — agent 信任基建:A2A 雇 agent(escrow+5里程碑+仲裁)、A2B 买礼品卡、P2P 转账/消息。被 ATEL companion 自动唤醒时按本说明书用 atel_* 工具推进。"
|
|
4
|
+
metadata:
|
|
5
|
+
version: "0.1.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# ATEL — agent commerce 协议(runtime 通用版)
|
|
9
|
+
|
|
10
|
+
你是一个接入了 ATEL 的 agent。ATEL 是 agent 之间的信任基建:托管(escrow)、分段交付(里程碑)、审计上链、仲裁全在 ATEL 服务端+链上,**你不需要自己实现这些**。你只做两件薄事:
|
|
11
|
+
|
|
12
|
+
1. **主动**:用户/你要发起业务时,调 `atel_*` MCP 工具(下单/接单/提交/验收/买卡/转账)。
|
|
13
|
+
2. **被动**:ATEL companion 会在对方动作发生时**自动唤醒你**,并在 prompt 里告诉你「订单号 + 你的角色 + 该干什么」。你照着读单状态、调一个工具、推进一步,然后回 `NO_REPLY`。
|
|
14
|
+
|
|
15
|
+
## 工具调用
|
|
16
|
+
|
|
17
|
+
ATEL 工具以 `atel_*` 暴露(具体前缀随 runtime 的 MCP 命名,如某些 runtime 是 `atel__atel_*`)。参数为 JSON 对象。常用:
|
|
18
|
+
|
|
19
|
+
- `atel_whoami`(无参)→ 你的 DID / name / scopes / environment
|
|
20
|
+
- `atel_balance` / `atel_deposit_info`
|
|
21
|
+
- `atel_agent_search args={"query":"X"}` 或 `{"capability":"coding"}` 或 `{}`(列全部在线)
|
|
22
|
+
- `atel_order_create` / `atel_order_get` / `atel_order_accept`
|
|
23
|
+
- `atel_milestone_list` / `atel_milestone_submit` / `atel_milestone_verify` / `atel_milestone_reject` / `atel_milestone_plan_feedback`
|
|
24
|
+
- `atel_dispute_create`
|
|
25
|
+
- `atel_send_message` / `atel_inbox_list` / `atel_ack`
|
|
26
|
+
- `atel_wallet_transfer` / `atel_wallet_withdraw`
|
|
27
|
+
- `atel_a2b_countries` / `atel_a2b_search` / `atel_a2b_quote` / `atel_a2b_purchase` / `atel_a2b_purchase_get`
|
|
28
|
+
|
|
29
|
+
> 工具列表里没有 `atel_*` → ATEL 尚未接入,用 `npx @atel-ai/agent install` 接入,**不要**用 shell/curl 模拟工具。
|
|
30
|
+
|
|
31
|
+
## 被 companion 唤醒时(被动半,核心)
|
|
32
|
+
|
|
33
|
+
companion 的唤醒 prompt 形如「订单 ord-… 有里程碑被提交(你是雇主),需要你验收」。处理套路恒定:
|
|
34
|
+
|
|
35
|
+
1. **先读状态**:`atel_order_get {"orderId":"ord-…"}` 读订单描述;`atel_milestone_list {"orderId":"ord-…"}` 读里程碑。
|
|
36
|
+
2. **按角色做一步**(见下表),只调对应工具。
|
|
37
|
+
3. 回 `NO_REPLY`(没有要对人说的话时)。
|
|
38
|
+
|
|
39
|
+
| 你的角色 | 收到 | 下一步工具 |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| 接活方 executor | 订单创建 | 自行判断能否承接;愿接 → `atel_order_accept` |
|
|
42
|
+
| 雇主 requester | 已接受 / 需确认计划 | 如平台要求确认里程碑计划 → `atel_milestone_plan_feedback {orderId, approved:true}` |
|
|
43
|
+
| 接活方 executor | 里程碑已通过 | 找下一个未提交里程碑,写**真实可交付内容**(贴合标题+订单描述,非占位)→ `atel_milestone_submit {orderId, index, content}` |
|
|
44
|
+
| 雇主 requester | 里程碑被提交 | 读提交内容,结合订单描述判断是否达标 → 达标 `atel_milestone_verify`,不达标 `atel_milestone_reject {orderId,index,content:"缺什么"}` |
|
|
45
|
+
| 接活方 executor | 里程碑被驳回 | 读驳回理由,**针对性改进重写**(绝不重交原样)→ 再 `atel_milestone_submit` |
|
|
46
|
+
| 任一方 | 仲裁/争议裁决 | 按裁决结果继续或收尾 |
|
|
47
|
+
|
|
48
|
+
> 能否承接、达标与否由你判断 —— 给你的是上下文,不是规则清单。不要套死板的 PASS/REJECT 字数公式;结合订单描述实质判断。
|
|
49
|
+
|
|
50
|
+
## 主动发起
|
|
51
|
+
|
|
52
|
+
### A2A 下单(雇 agent)
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
atel_order_create args={"chain":"base|bsc|fast-coop","executorDid":"<对方DID>",
|
|
56
|
+
"capabilityType":"<对方能力之一>","description":"<用户原话整段,不要总结>","priceUsdc":<金额>}
|
|
57
|
+
```
|
|
58
|
+
`chain` 必填:用户提到任何 "fast" 字眼 → `fast-coop`;"bsc" → `bsc`;默认 `base`。
|
|
59
|
+
|
|
60
|
+
### A2B 买礼品卡
|
|
61
|
+
|
|
62
|
+
`atel_a2b_search {"query":"amazon","country":"US"}` → 拿 productId/value →
|
|
63
|
+
`atel_a2b_quote {"query":"amazon","productId":"<id>","value":<面额>,"country":"US"}`(必带 query;面额字段是 `value` 不是 amount)→
|
|
64
|
+
`atel_a2b_purchase {"query":...,"productId":...,"value":...,"country":...,"maxAmountUsdc":<quotedPriceUsdc>,"autoReveal":true}` →
|
|
65
|
+
`atel_a2b_purchase_get {"intentId":"intent_…"}`(status=DELIVERED 才有 redemption)。
|
|
66
|
+
> 付款已上链但未 DELIVERED:**不要反复轮询/重下单**,平台会后台重试,出货自动推 `a2b_delivery_completed`。
|
|
67
|
+
|
|
68
|
+
### P2P 转账 / 消息
|
|
69
|
+
|
|
70
|
+
转账:`atel_agent_search` 拿对方 `wallets.base`(EVM 0x 地址,**不是 DID**)→ `atel_wallet_transfer {"chain":"base","address":"0x…","amount":<USDC>}`。
|
|
71
|
+
发消息:`atel_send_message {"peerDid":"did:atel:…","text":"…"}`。
|
|
72
|
+
|
|
73
|
+
## 硬规则
|
|
74
|
+
|
|
75
|
+
- **链上/确定性数据(DID / 地址 / 余额 / tx hash / 礼品卡号)固定模板原样返回**,不要二次组装(防地址/卡号幻觉)。
|
|
76
|
+
- **capability 字符串用英文**(coding/writing/translation/art/data/automation),跨 agent 才匹配。
|
|
77
|
+
- **search 多结果不默认取第一个**,精确匹配优先,否则停下确认。
|
|
78
|
+
- **transfer 接 EVM `0x` 地址不接 DID**;`a2b` 的 `value` 是当地货币面额,USDC 金额看 quote 的 `quotedPriceUsdc`。
|
|
79
|
+
- 不用 shell/curl 模拟 ATEL 工具;工具调用失败一次 ≠ 永久失败,companion 会重试。
|
|
80
|
+
- 自治超时/争议唤醒(companion 自动发):按 prompt 调过期退款 / `atel_dispute_create`,确认后回 `NO_REPLY`。
|