agent-anywhere-gateway 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.
@@ -0,0 +1,157 @@
1
+ const { spawn } = require("node:child_process");
2
+ const readline = require("node:readline");
3
+ const { EventEmitter } = require("node:events");
4
+ const { resolveCodexExecutable } = require("./codex-runtime");
5
+
6
+ const DEFAULT_CLIENT_INFO = {
7
+ name: "agent_anywhere",
8
+ title: "Agent Anywhere",
9
+ version: "0.1.0"
10
+ };
11
+
12
+ class CodexAppServerClient extends EventEmitter {
13
+ constructor({
14
+ codexPathOverride,
15
+ spawnImpl = spawn,
16
+ clientInfo = DEFAULT_CLIENT_INFO
17
+ } = {}) {
18
+ super();
19
+ this.codexPathOverride = codexPathOverride || process.env.CODEX_CLI_PATH || undefined;
20
+ this.spawnImpl = spawnImpl;
21
+ this.clientInfo = clientInfo;
22
+ this.nextRequestId = 1;
23
+ this.pendingRequests = new Map();
24
+ this.process = null;
25
+ this.reader = null;
26
+ this.closed = false;
27
+ }
28
+
29
+ start() {
30
+ if (this.process) {
31
+ return;
32
+ }
33
+ const codexPath = resolveCodexExecutable(this.codexPathOverride);
34
+ this.process = this.spawnImpl(codexPath, ["app-server"], {
35
+ env: process.env,
36
+ stdio: ["pipe", "pipe", "inherit"]
37
+ });
38
+
39
+ this.reader = readline.createInterface({ input: this.process.stdout });
40
+ this.reader.on("line", (line) => this.handleLine(line));
41
+ this.process.on("error", (error) => this.failPending(error));
42
+ this.process.on("exit", (code, signal) => {
43
+ this.closed = true;
44
+ const suffix = signal ? `signal ${signal}` : `code ${code}`;
45
+ this.failPending(new Error(`codex app-server 已退出:${suffix}`));
46
+ this.emit("exit", { code, signal });
47
+ });
48
+ }
49
+
50
+ async initialize() {
51
+ this.start();
52
+ const result = await this.request("initialize", {
53
+ clientInfo: this.clientInfo,
54
+ capabilities: {
55
+ experimentalApi: true
56
+ }
57
+ });
58
+ this.notify("initialized", {});
59
+ return result;
60
+ }
61
+
62
+ request(method, params = {}) {
63
+ this.start();
64
+ const id = this.nextRequestId++;
65
+ this.write({ method, id, params });
66
+ return new Promise((resolve, reject) => {
67
+ this.pendingRequests.set(id, { resolve, reject, method });
68
+ });
69
+ }
70
+
71
+ notify(method, params = {}) {
72
+ this.start();
73
+ this.write({ method, params });
74
+ }
75
+
76
+ respond(id, result = {}) {
77
+ this.write({ id, result });
78
+ }
79
+
80
+ respondError(id, error) {
81
+ this.write({
82
+ id,
83
+ error: {
84
+ code: error?.code || -32000,
85
+ message: error?.message || String(error || "request failed")
86
+ }
87
+ });
88
+ }
89
+
90
+ close() {
91
+ this.closed = true;
92
+ this.reader?.close();
93
+ if (this.process && !this.process.killed) {
94
+ this.process.kill();
95
+ }
96
+ this.failPending(new Error("codex app-server client closed"));
97
+ }
98
+
99
+ write(message) {
100
+ if (!this.process || this.closed) {
101
+ throw new Error("codex app-server client is not running");
102
+ }
103
+ this.process.stdin.write(`${JSON.stringify(message)}\n`);
104
+ }
105
+
106
+ handleLine(line) {
107
+ let message;
108
+ try {
109
+ message = JSON.parse(line);
110
+ } catch (error) {
111
+ this.emit("error", new Error(`codex app-server 输出不是合法 JSON:${error.message}`));
112
+ return;
113
+ }
114
+
115
+ if (message && Object.prototype.hasOwnProperty.call(message, "id") && !message.method) {
116
+ const pending = this.pendingRequests.get(message.id);
117
+ if (!pending) {
118
+ this.emit("unknownResponse", message);
119
+ return;
120
+ }
121
+ this.pendingRequests.delete(message.id);
122
+ if (message.error) {
123
+ const error = new Error(message.error.message || `codex app-server 请求失败:${pending.method}`);
124
+ error.code = message.error.code;
125
+ error.data = message.error.data;
126
+ pending.reject(error);
127
+ return;
128
+ }
129
+ pending.resolve(message.result);
130
+ return;
131
+ }
132
+
133
+ if (message && Object.prototype.hasOwnProperty.call(message, "id") && message.method) {
134
+ this.emit("request", message);
135
+ return;
136
+ }
137
+
138
+ if (message?.method) {
139
+ this.emit("notification", message);
140
+ return;
141
+ }
142
+
143
+ this.emit("unknownMessage", message);
144
+ }
145
+
146
+ failPending(error) {
147
+ for (const pending of this.pendingRequests.values()) {
148
+ pending.reject(error);
149
+ }
150
+ this.pendingRequests.clear();
151
+ }
152
+ }
153
+
154
+ module.exports = {
155
+ CodexAppServerClient,
156
+ DEFAULT_CLIENT_INFO
157
+ };