@tpsdev-ai/agent 0.4.2 → 0.5.1
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/bin.js +41 -15
- package/dist/bin.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +27 -1
- package/dist/config.js.map +1 -1
- package/dist/runtime/agent.d.ts +1 -0
- package/dist/runtime/agent.d.ts.map +1 -1
- package/dist/runtime/agent.js +22 -1
- package/dist/runtime/agent.js.map +1 -1
- package/dist/runtime/event-loop.d.ts.map +1 -1
- package/dist/runtime/event-loop.js +17 -19
- package/dist/runtime/event-loop.js.map +1 -1
- package/package.json +2 -2
- package/src/bin.ts +42 -22
- package/src/config.ts +32 -1
- package/src/runtime/agent.ts +24 -1
- package/src/runtime/event-loop.ts +19 -31
- package/test/config.test.ts +67 -0
package/dist/bin.js
CHANGED
|
@@ -2,31 +2,57 @@
|
|
|
2
2
|
import { AgentRuntime } from "./runtime/agent.js";
|
|
3
3
|
import { loadAgentConfig } from "./config.js";
|
|
4
4
|
function usage() {
|
|
5
|
-
console.error("Usage:
|
|
5
|
+
console.error("Usage:");
|
|
6
|
+
console.error(" tps-agent run --config <agent.yaml> --message <text>");
|
|
7
|
+
console.error(" tps-agent start --config <agent.yaml>");
|
|
8
|
+
console.error(" tps-agent health --config <agent.yaml>");
|
|
6
9
|
process.exit(1);
|
|
7
10
|
}
|
|
11
|
+
function parseArg(name, args) {
|
|
12
|
+
const idx = args.indexOf(name);
|
|
13
|
+
if (idx >= 0 && idx + 1 < args.length)
|
|
14
|
+
return args[idx + 1];
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
function parseConfig(args) {
|
|
18
|
+
const command = args[0];
|
|
19
|
+
const configPath = parseArg("--config", args);
|
|
20
|
+
return { command, configPath };
|
|
21
|
+
}
|
|
8
22
|
async function main() {
|
|
9
23
|
const args = process.argv.slice(2);
|
|
10
|
-
const
|
|
11
|
-
if (
|
|
24
|
+
const { command, configPath } = parseConfig(args);
|
|
25
|
+
if (!command || command === "--help" || command === "-h")
|
|
12
26
|
usage();
|
|
13
|
-
|
|
14
|
-
const configIdx = args.indexOf("--config");
|
|
15
|
-
const msgIdx = args.indexOf("--message");
|
|
16
|
-
if (configIdx < 0 || msgIdx < 0) {
|
|
27
|
+
if (!configPath)
|
|
17
28
|
usage();
|
|
18
|
-
}
|
|
19
|
-
const configPath = args[configIdx + 1];
|
|
20
|
-
const message = args.slice(msgIdx + 1).join(" ");
|
|
21
|
-
if (!configPath || !message) {
|
|
22
|
-
usage();
|
|
23
|
-
}
|
|
24
29
|
const config = loadAgentConfig(configPath);
|
|
25
30
|
const runtime = new AgentRuntime(config);
|
|
26
|
-
|
|
31
|
+
switch (command) {
|
|
32
|
+
case "run": {
|
|
33
|
+
const messageIdx = args.indexOf("--message");
|
|
34
|
+
const message = messageIdx >= 0 ? args.slice(messageIdx + 1).join(" ") : process.env.TPS_AGENT_MESSAGE;
|
|
35
|
+
if (!message)
|
|
36
|
+
usage();
|
|
37
|
+
await runtime.runOnce(message);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
case "start": {
|
|
41
|
+
await runtime.start();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
case "health": {
|
|
45
|
+
const healthy = runtime.isHealthy();
|
|
46
|
+
process.stdout.write(healthy ? "healthy\n" : "unhealthy\n");
|
|
47
|
+
process.exit(healthy ? 0 : 1);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
usage();
|
|
52
|
+
}
|
|
27
53
|
}
|
|
28
54
|
main().catch((err) => {
|
|
29
|
-
console.error(err?.message || err);
|
|
55
|
+
console.error(String(err?.message || err));
|
|
30
56
|
process.exit(1);
|
|
31
57
|
});
|
|
32
58
|
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,SAAS,KAAK;IACZ,OAAO,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE;QACH,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;QACvD,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC;IAC3D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE;QACH,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;QACvD,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC;IAC3D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAgCD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CA4BzD;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAKxE"}
|
package/dist/config.js
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import yaml from "js-yaml";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
|
+
function interpolateEnvInString(raw) {
|
|
5
|
+
return raw.replace(/\$\{([A-Z0-9_]+)\}/g, (_match, varName) => {
|
|
6
|
+
const resolved = process.env[varName];
|
|
7
|
+
if (resolved === undefined) {
|
|
8
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
9
|
+
}
|
|
10
|
+
return resolved;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function interpolateEnvVars(value) {
|
|
14
|
+
if (typeof value === "string") {
|
|
15
|
+
return interpolateEnvInString(value);
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
return value.map((item) => interpolateEnvVars(item));
|
|
19
|
+
}
|
|
20
|
+
if (value && typeof value === "object") {
|
|
21
|
+
const out = {};
|
|
22
|
+
for (const [k, v] of Object.entries(value)) {
|
|
23
|
+
out[k] = interpolateEnvVars(v);
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
4
29
|
export function loadAgentConfig(path) {
|
|
5
30
|
const raw = readFileSync(path, "utf-8");
|
|
6
|
-
const
|
|
31
|
+
const parsedRaw = (yaml.load(raw) ?? {});
|
|
32
|
+
const parsed = interpolateEnvVars(parsedRaw);
|
|
7
33
|
const workspace = String(parsed.workspace || parsed.repo || process.cwd());
|
|
8
34
|
const memoryPath = parsed.memoryPath || `${workspace}/.openclaw/agent.memory.jsonl`;
|
|
9
35
|
const agent = {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAsBzC,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/agent.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/runtime/agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/runtime/agent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C,qBAAa,YAAY;aAKK,MAAM,EAAE,WAAW;IAJ/C,OAAO,CAAC,IAAI,CAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;gBAEf,MAAM,EAAE,WAAW;IAkBzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,OAAO;IAIpB,kBAAkB,IAAI,MAAM;CAG7B"}
|
package/dist/runtime/agent.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
1
3
|
import { EventLoop } from "./event-loop.js";
|
|
2
4
|
import { MailClient } from "../io/mail.js";
|
|
3
5
|
import { MemoryStore } from "../io/memory.js";
|
|
@@ -28,7 +30,23 @@ export class AgentRuntime {
|
|
|
28
30
|
}
|
|
29
31
|
async start() {
|
|
30
32
|
const checkInbox = async () => this.mail.checkNewMail();
|
|
31
|
-
|
|
33
|
+
const pidPath = join(this.config.workspace, ".tps-agent.pid");
|
|
34
|
+
mkdirSync(dirname(pidPath), { recursive: true });
|
|
35
|
+
writeFileSync(pidPath, `${process.pid}\n`, "utf-8");
|
|
36
|
+
const shutdown = new Promise((resolve) => {
|
|
37
|
+
const onStop = async () => {
|
|
38
|
+
await this.loop.stop();
|
|
39
|
+
resolve();
|
|
40
|
+
};
|
|
41
|
+
process.once("SIGINT", onStop);
|
|
42
|
+
process.once("SIGTERM", onStop);
|
|
43
|
+
});
|
|
44
|
+
try {
|
|
45
|
+
await Promise.race([this.loop.run(checkInbox), shutdown]);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
rmSync(pidPath, { force: true });
|
|
49
|
+
}
|
|
32
50
|
}
|
|
33
51
|
async stop() {
|
|
34
52
|
await this.loop.stop();
|
|
@@ -39,6 +57,9 @@ export class AgentRuntime {
|
|
|
39
57
|
getState() {
|
|
40
58
|
return this.loop.getState();
|
|
41
59
|
}
|
|
60
|
+
isHealthy() {
|
|
61
|
+
return this.getState() !== "stopped";
|
|
62
|
+
}
|
|
42
63
|
describeBoundaries() {
|
|
43
64
|
return this.boundary.describeCapabilities();
|
|
44
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/runtime/agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/runtime/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-loop.d.ts","sourceRoot":"","sources":["../../src/runtime/event-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"event-loop.d.ts","sourceRoot":"","sources":["../../src/runtime/event-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAyC,UAAU,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE1D,UAAU,aAAa;IACrB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAMD,qBAAa,SAAS;IAIR,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAiB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzE,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,OAAO,CAAS;gBAEK,IAAI,EAAE,aAAa,EAAmB,MAAM,SAAM;IAEzE,GAAG,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B5D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,QAAQ,IAAI,UAAU;IAIhB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAI9B,WAAW;YAKX,cAAc;YA6Gd,iBAAiB;YAiBjB,WAAW;CAQ1B"}
|
|
@@ -48,7 +48,8 @@ export class EventLoop {
|
|
|
48
48
|
await this.processMessage(prompt);
|
|
49
49
|
}
|
|
50
50
|
async processMail(message) {
|
|
51
|
-
|
|
51
|
+
const body = typeof message.body === "string" ? message.body : JSON.stringify(message.body);
|
|
52
|
+
await this.processMessage(body);
|
|
52
53
|
}
|
|
53
54
|
async processMessage(promptRaw) {
|
|
54
55
|
const prompt = String(promptRaw).trim();
|
|
@@ -68,14 +69,13 @@ export class EventLoop {
|
|
|
68
69
|
ts: new Date().toISOString(),
|
|
69
70
|
data: { direction: "in", body: prompt },
|
|
70
71
|
});
|
|
71
|
-
|
|
72
|
+
let completion = await this.deps.provider.complete({
|
|
72
73
|
systemPrompt: await this.buildSystemPrompt(),
|
|
73
74
|
messages: [{ role: "user", content: prompt }],
|
|
74
75
|
tools,
|
|
75
76
|
toolChoice: "auto",
|
|
76
77
|
maxTokens: this.deps.config.maxTokens ?? 1024,
|
|
77
|
-
};
|
|
78
|
-
let completion = await this.deps.provider.complete(request);
|
|
78
|
+
});
|
|
79
79
|
let turns = 0;
|
|
80
80
|
while (true) {
|
|
81
81
|
if (completion.content) {
|
|
@@ -89,9 +89,8 @@ export class EventLoop {
|
|
|
89
89
|
},
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
-
if (!completion.toolCalls || completion.toolCalls.length === 0)
|
|
92
|
+
if (!completion.toolCalls || completion.toolCalls.length === 0)
|
|
93
93
|
return;
|
|
94
|
-
}
|
|
95
94
|
if (turns++ > 8) {
|
|
96
95
|
await this.deps.memory.append({
|
|
97
96
|
type: "error",
|
|
@@ -107,7 +106,8 @@ export class EventLoop {
|
|
|
107
106
|
ts: new Date().toISOString(),
|
|
108
107
|
data: { tool: call.name, args: call.input },
|
|
109
108
|
});
|
|
110
|
-
|
|
109
|
+
const reviewBlocked = this.deps.reviewGate?.isHighRisk(call.name) ?? false;
|
|
110
|
+
if (reviewBlocked) {
|
|
111
111
|
await this.deps.reviewGate.requestApproval(call.name, call.input);
|
|
112
112
|
await this.deps.memory.append({
|
|
113
113
|
type: "approval_request",
|
|
@@ -135,14 +135,13 @@ export class EventLoop {
|
|
|
135
135
|
content: JSON.stringify(result),
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
|
-
const nextMessages = [
|
|
139
|
-
...request.messages,
|
|
140
|
-
{ role: "assistant", content: completion.content ?? "" },
|
|
141
|
-
...toolMessages,
|
|
142
|
-
];
|
|
143
138
|
completion = await this.deps.provider.complete({
|
|
144
|
-
systemPrompt:
|
|
145
|
-
messages:
|
|
139
|
+
systemPrompt: await this.buildSystemPrompt(),
|
|
140
|
+
messages: [
|
|
141
|
+
{ role: "user", content: prompt },
|
|
142
|
+
{ role: "assistant", content: completion.content ?? "" },
|
|
143
|
+
...toolMessages,
|
|
144
|
+
],
|
|
146
145
|
tools,
|
|
147
146
|
toolChoice: "auto",
|
|
148
147
|
maxTokens: this.deps.config.maxTokens ?? 1024,
|
|
@@ -150,20 +149,19 @@ export class EventLoop {
|
|
|
150
149
|
}
|
|
151
150
|
}
|
|
152
151
|
async buildSystemPrompt() {
|
|
153
|
-
const fs = await import("node:fs/promises");
|
|
154
152
|
const docs = await Promise.all([
|
|
155
153
|
this.fileOrEmpty(`${this.deps.config.workspace}/SOUL.md`),
|
|
156
154
|
this.fileOrEmpty(`${this.deps.config.workspace}/AGENTS.md`),
|
|
157
155
|
this.fileOrEmpty(`${this.deps.config.workspace}/IDENTITY.md`),
|
|
158
156
|
Promise.resolve(this.deps.config.systemPrompt || ""),
|
|
159
157
|
]);
|
|
160
|
-
const
|
|
158
|
+
const docBlock = docs.filter(Boolean).join("\n\n");
|
|
159
|
+
return [
|
|
160
|
+
docBlock,
|
|
161
161
|
`Role: ${this.deps.config.name}`,
|
|
162
162
|
`Tools: ${this.deps.tools.list().map((t) => t.name).join(", ") || "(none)"}`,
|
|
163
163
|
`Context: ${this.deps.config.agentId}`,
|
|
164
|
-
];
|
|
165
|
-
const docBlock = docs.filter(Boolean).join("\n\n");
|
|
166
|
-
return `${docBlock}\n\n${sections.join("\n")}`;
|
|
164
|
+
].join("\n");
|
|
167
165
|
}
|
|
168
166
|
async fileOrEmpty(path) {
|
|
169
167
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-loop.js","sourceRoot":"","sources":["../../src/runtime/event-loop.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event-loop.js","sourceRoot":"","sources":["../../src/runtime/event-loop.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpsdev-ai/agent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Native TPS Agent Runtime
|
|
3
|
+
"version": "0.5.1",
|
|
4
|
+
"description": "Native TPS Agent Runtime — headless, mail-driven, nono-sandboxed",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
package/src/bin.ts
CHANGED
|
@@ -3,38 +3,58 @@ import { AgentRuntime } from "./runtime/agent.js";
|
|
|
3
3
|
import { loadAgentConfig } from "./config.js";
|
|
4
4
|
|
|
5
5
|
function usage(): never {
|
|
6
|
-
console.error("Usage:
|
|
6
|
+
console.error("Usage:");
|
|
7
|
+
console.error(" tps-agent run --config <agent.yaml> --message <text>");
|
|
8
|
+
console.error(" tps-agent start --config <agent.yaml>");
|
|
9
|
+
console.error(" tps-agent health --config <agent.yaml>");
|
|
7
10
|
process.exit(1);
|
|
8
11
|
}
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
usage();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const configIdx = args.indexOf("--config");
|
|
19
|
-
const msgIdx = args.indexOf("--message");
|
|
20
|
-
|
|
21
|
-
if (configIdx < 0 || msgIdx < 0) {
|
|
22
|
-
usage();
|
|
23
|
-
}
|
|
13
|
+
function parseArg(name: string, args: string[]): string | undefined {
|
|
14
|
+
const idx = args.indexOf(name);
|
|
15
|
+
if (idx >= 0 && idx + 1 < args.length) return args[idx + 1];
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
const
|
|
19
|
+
function parseConfig(args: string[]): { configPath?: string; command?: string } {
|
|
20
|
+
const command = args[0];
|
|
21
|
+
const configPath = parseArg("--config", args);
|
|
22
|
+
return { command, configPath };
|
|
23
|
+
}
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
25
|
+
async function main() {
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const { command, configPath } = parseConfig(args);
|
|
28
|
+
if (!command || command === "--help" || command === "-h") usage();
|
|
29
|
+
if (!configPath) usage();
|
|
31
30
|
|
|
32
31
|
const config = loadAgentConfig(configPath);
|
|
33
32
|
const runtime = new AgentRuntime(config);
|
|
34
|
-
|
|
33
|
+
|
|
34
|
+
switch (command) {
|
|
35
|
+
case "run": {
|
|
36
|
+
const messageIdx = args.indexOf("--message");
|
|
37
|
+
const message = messageIdx >= 0 ? args.slice(messageIdx + 1).join(" ") : process.env.TPS_AGENT_MESSAGE;
|
|
38
|
+
if (!message) usage();
|
|
39
|
+
await runtime.runOnce(message);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
case "start": {
|
|
43
|
+
await runtime.start();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
case "health": {
|
|
47
|
+
const healthy = runtime.isHealthy();
|
|
48
|
+
process.stdout.write(healthy ? "healthy\n" : "unhealthy\n");
|
|
49
|
+
process.exit(healthy ? 0 : 1);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
usage();
|
|
54
|
+
}
|
|
35
55
|
}
|
|
36
56
|
|
|
37
57
|
main().catch((err) => {
|
|
38
|
-
console.error(err?.message || err);
|
|
58
|
+
console.error(String(err?.message || err));
|
|
39
59
|
process.exit(1);
|
|
40
60
|
});
|
package/src/config.ts
CHANGED
|
@@ -22,9 +22,40 @@ export interface AgentRuntimeConfig {
|
|
|
22
22
|
execAllowlist?: string[];
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function interpolateEnvInString(raw: string): string {
|
|
26
|
+
return raw.replace(/\$\{([A-Z0-9_]+)\}/g, (_match, varName: string) => {
|
|
27
|
+
const resolved = process.env[varName];
|
|
28
|
+
if (resolved === undefined) {
|
|
29
|
+
throw new Error(`Missing environment variable: ${varName}`);
|
|
30
|
+
}
|
|
31
|
+
return resolved;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function interpolateEnvVars<T>(value: T): T {
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
return interpolateEnvInString(value) as T;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
return value.map((item) => interpolateEnvVars(item)) as T;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (value && typeof value === "object") {
|
|
45
|
+
const out: Record<string, unknown> = {};
|
|
46
|
+
for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
|
|
47
|
+
out[k] = interpolateEnvVars(v);
|
|
48
|
+
}
|
|
49
|
+
return out as T;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
|
|
25
55
|
export function loadAgentConfig(path: string): AgentConfig {
|
|
26
56
|
const raw = readFileSync(path, "utf-8");
|
|
27
|
-
const
|
|
57
|
+
const parsedRaw = (yaml.load(raw) ?? {}) as Record<string, any>;
|
|
58
|
+
const parsed = interpolateEnvVars(parsedRaw);
|
|
28
59
|
|
|
29
60
|
const workspace = String(parsed.workspace || parsed.repo || process.cwd());
|
|
30
61
|
const memoryPath = parsed.memoryPath || `${workspace}/.openclaw/agent.memory.jsonl`;
|
package/src/runtime/agent.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
1
3
|
import type { AgentConfig } from "./types.js";
|
|
2
4
|
import { EventLoop } from "./event-loop.js";
|
|
3
5
|
import { MailClient } from "../io/mail.js";
|
|
@@ -32,7 +34,24 @@ export class AgentRuntime {
|
|
|
32
34
|
|
|
33
35
|
async start(): Promise<void> {
|
|
34
36
|
const checkInbox = async () => this.mail.checkNewMail();
|
|
35
|
-
|
|
37
|
+
const pidPath = join(this.config.workspace, ".tps-agent.pid");
|
|
38
|
+
mkdirSync(dirname(pidPath), { recursive: true });
|
|
39
|
+
writeFileSync(pidPath, `${process.pid}\n`, "utf-8");
|
|
40
|
+
|
|
41
|
+
const shutdown = new Promise<void>((resolve) => {
|
|
42
|
+
const onStop = async () => {
|
|
43
|
+
await this.loop.stop();
|
|
44
|
+
resolve();
|
|
45
|
+
};
|
|
46
|
+
process.once("SIGINT", onStop);
|
|
47
|
+
process.once("SIGTERM", onStop);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await Promise.race([this.loop.run(checkInbox), shutdown]);
|
|
52
|
+
} finally {
|
|
53
|
+
rmSync(pidPath, { force: true });
|
|
54
|
+
}
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
async stop(): Promise<void> {
|
|
@@ -47,6 +66,10 @@ export class AgentRuntime {
|
|
|
47
66
|
return this.loop.getState();
|
|
48
67
|
}
|
|
49
68
|
|
|
69
|
+
isHealthy(): boolean {
|
|
70
|
+
return this.getState() !== "stopped";
|
|
71
|
+
}
|
|
72
|
+
|
|
50
73
|
describeBoundaries(): string {
|
|
51
74
|
return this.boundary.describeCapabilities();
|
|
52
75
|
}
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { MailMessage } from "../io/mail.js";
|
|
2
|
-
import type {
|
|
3
|
-
AgentConfig,
|
|
4
|
-
AgentState,
|
|
5
|
-
CompletionRequest,
|
|
6
|
-
CompletionResponse,
|
|
7
|
-
ToolCall,
|
|
8
|
-
ToolSpec,
|
|
9
|
-
} from "./types.js";
|
|
2
|
+
import type { AgentConfig, CompletionRequest, ToolCall, ToolSpec, AgentState } from "./types.js";
|
|
10
3
|
import type { MemoryStore } from "../io/memory.js";
|
|
11
4
|
import type { ContextManager } from "../io/context.js";
|
|
12
5
|
import type { ProviderManager } from "../llm/provider.js";
|
|
@@ -72,7 +65,8 @@ export class EventLoop {
|
|
|
72
65
|
}
|
|
73
66
|
|
|
74
67
|
private async processMail(message: MailMessage): Promise<void> {
|
|
75
|
-
|
|
68
|
+
const body = typeof message.body === "string" ? message.body : JSON.stringify(message.body);
|
|
69
|
+
await this.processMessage(body);
|
|
76
70
|
}
|
|
77
71
|
|
|
78
72
|
private async processMessage(promptRaw: string): Promise<void> {
|
|
@@ -96,15 +90,14 @@ export class EventLoop {
|
|
|
96
90
|
data: { direction: "in", body: prompt },
|
|
97
91
|
});
|
|
98
92
|
|
|
99
|
-
|
|
93
|
+
let completion = await this.deps.provider.complete({
|
|
100
94
|
systemPrompt: await this.buildSystemPrompt(),
|
|
101
95
|
messages: [{ role: "user", content: prompt }],
|
|
102
96
|
tools,
|
|
103
97
|
toolChoice: "auto",
|
|
104
98
|
maxTokens: this.deps.config.maxTokens ?? 1024,
|
|
105
|
-
};
|
|
99
|
+
});
|
|
106
100
|
|
|
107
|
-
let completion = await this.deps.provider.complete(request);
|
|
108
101
|
let turns = 0;
|
|
109
102
|
|
|
110
103
|
while (true) {
|
|
@@ -120,9 +113,7 @@ export class EventLoop {
|
|
|
120
113
|
});
|
|
121
114
|
}
|
|
122
115
|
|
|
123
|
-
if (!completion.toolCalls || completion.toolCalls.length === 0)
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
116
|
+
if (!completion.toolCalls || completion.toolCalls.length === 0) return;
|
|
126
117
|
|
|
127
118
|
if (turns++ > 8) {
|
|
128
119
|
await this.deps.memory.append({
|
|
@@ -141,8 +132,9 @@ export class EventLoop {
|
|
|
141
132
|
data: { tool: call.name, args: call.input },
|
|
142
133
|
});
|
|
143
134
|
|
|
144
|
-
|
|
145
|
-
|
|
135
|
+
const reviewBlocked = this.deps.reviewGate?.isHighRisk(call.name) ?? false;
|
|
136
|
+
if (reviewBlocked) {
|
|
137
|
+
await this.deps.reviewGate!.requestApproval(call.name, call.input);
|
|
146
138
|
await this.deps.memory.append({
|
|
147
139
|
type: "approval_request",
|
|
148
140
|
ts: new Date().toISOString(),
|
|
@@ -172,15 +164,13 @@ export class EventLoop {
|
|
|
172
164
|
});
|
|
173
165
|
}
|
|
174
166
|
|
|
175
|
-
const nextMessages = [
|
|
176
|
-
...request.messages,
|
|
177
|
-
{ role: "assistant", content: completion.content ?? "" },
|
|
178
|
-
...toolMessages,
|
|
179
|
-
];
|
|
180
|
-
|
|
181
167
|
completion = await this.deps.provider.complete({
|
|
182
|
-
systemPrompt:
|
|
183
|
-
messages:
|
|
168
|
+
systemPrompt: await this.buildSystemPrompt(),
|
|
169
|
+
messages: [
|
|
170
|
+
{ role: "user", content: prompt },
|
|
171
|
+
{ role: "assistant", content: completion.content ?? "" },
|
|
172
|
+
...toolMessages,
|
|
173
|
+
] as any,
|
|
184
174
|
tools,
|
|
185
175
|
toolChoice: "auto",
|
|
186
176
|
maxTokens: this.deps.config.maxTokens ?? 1024,
|
|
@@ -189,7 +179,6 @@ export class EventLoop {
|
|
|
189
179
|
}
|
|
190
180
|
|
|
191
181
|
private async buildSystemPrompt(): Promise<string> {
|
|
192
|
-
const fs = await import("node:fs/promises");
|
|
193
182
|
const docs = await Promise.all([
|
|
194
183
|
this.fileOrEmpty(`${this.deps.config.workspace}/SOUL.md`),
|
|
195
184
|
this.fileOrEmpty(`${this.deps.config.workspace}/AGENTS.md`),
|
|
@@ -197,14 +186,13 @@ export class EventLoop {
|
|
|
197
186
|
Promise.resolve(this.deps.config.systemPrompt || ""),
|
|
198
187
|
]);
|
|
199
188
|
|
|
200
|
-
const
|
|
189
|
+
const docBlock = docs.filter(Boolean).join("\n\n");
|
|
190
|
+
return [
|
|
191
|
+
docBlock,
|
|
201
192
|
`Role: ${this.deps.config.name}`,
|
|
202
193
|
`Tools: ${this.deps.tools.list().map((t) => t.name).join(", ") || "(none)"}`,
|
|
203
194
|
`Context: ${this.deps.config.agentId}`,
|
|
204
|
-
];
|
|
205
|
-
|
|
206
|
-
const docBlock = docs.filter(Boolean).join("\n\n");
|
|
207
|
-
return `${docBlock}\n\n${sections.join("\n")}`;
|
|
195
|
+
].join("\n");
|
|
208
196
|
}
|
|
209
197
|
|
|
210
198
|
private async fileOrEmpty(path: string): Promise<string> {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { loadAgentConfig } from "../src/config.js";
|
|
6
|
+
|
|
7
|
+
describe("agent config env interpolation", () => {
|
|
8
|
+
let dir: string;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
dir = mkdtempSync(join(tmpdir(), "tps-agent-config-"));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
rmSync(dir, { recursive: true, force: true });
|
|
16
|
+
delete process.env.ANTHROPIC_API_KEY;
|
|
17
|
+
delete process.env.AGENT_WORKSPACE;
|
|
18
|
+
delete process.env.AGENT_NAME;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("resolves ${VAR_NAME} placeholders in string values", () => {
|
|
22
|
+
process.env.ANTHROPIC_API_KEY = "test-key";
|
|
23
|
+
process.env.AGENT_WORKSPACE = "/tmp/ws";
|
|
24
|
+
process.env.AGENT_NAME = "Coder";
|
|
25
|
+
|
|
26
|
+
const cfg = join(dir, "agent.yaml");
|
|
27
|
+
writeFileSync(
|
|
28
|
+
cfg,
|
|
29
|
+
[
|
|
30
|
+
"agentId: coder",
|
|
31
|
+
"name: ${AGENT_NAME}",
|
|
32
|
+
"workspace: ${AGENT_WORKSPACE}",
|
|
33
|
+
"mailDir: ${AGENT_WORKSPACE}/mail",
|
|
34
|
+
"llm:",
|
|
35
|
+
" provider: anthropic",
|
|
36
|
+
" model: claude-sonnet-4-6",
|
|
37
|
+
" apiKey: ${ANTHROPIC_API_KEY}",
|
|
38
|
+
].join("\n"),
|
|
39
|
+
"utf-8"
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const parsed = loadAgentConfig(cfg);
|
|
43
|
+
expect(parsed.name).toBe("Coder");
|
|
44
|
+
expect(parsed.workspace).toBe("/tmp/ws");
|
|
45
|
+
expect(parsed.mailDir).toBe("/tmp/ws/mail");
|
|
46
|
+
expect(parsed.llm.apiKey).toBe("test-key");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("throws when referenced env var is missing", () => {
|
|
50
|
+
const cfg = join(dir, "agent-missing.yaml");
|
|
51
|
+
writeFileSync(
|
|
52
|
+
cfg,
|
|
53
|
+
[
|
|
54
|
+
"agentId: coder",
|
|
55
|
+
"name: Coder",
|
|
56
|
+
"workspace: /tmp/ws",
|
|
57
|
+
"llm:",
|
|
58
|
+
" provider: anthropic",
|
|
59
|
+
" model: claude-sonnet-4-6",
|
|
60
|
+
" apiKey: ${MISSING_API_KEY}",
|
|
61
|
+
].join("\n"),
|
|
62
|
+
"utf-8"
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
expect(() => loadAgentConfig(cfg)).toThrow("Missing environment variable: MISSING_API_KEY");
|
|
66
|
+
});
|
|
67
|
+
});
|