@pome-sh/cli 0.42.3 → 0.43.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/build-info.json +3 -3
- package/dist/{checks-BKMTBJSO.js → checks-QYUPKBPT.js} +9 -14
- package/dist/{chunk-VPXIGCZW.js → chunk-3YCX3KUL.js} +1 -1
- package/dist/{chunk-5NPGY73F.js → chunk-5A6HHA54.js} +1 -1
- package/dist/{chunk-6KJC4BTO.js → chunk-5KFDRR53.js} +2 -2
- package/dist/{chunk-NNXVR46L.js → chunk-CS7O2ZXB.js} +114 -2
- package/dist/{chunk-RPPF2KDQ.js → chunk-ELIEDNF3.js} +7 -7
- package/dist/{chunk-STMGQ7GU.js → chunk-OBFHOACQ.js} +1404 -171
- package/dist/{runTrialGroup-BP446HIE.js → runTrialGroup-4QL6S7QO.js} +19 -9
- package/dist/{server-GDK4TBTL.js → server-KC57K5AC.js} +1 -1
- package/dist/src/cli/main.js +511 -235
- package/dist/{src-FUPOFZI4.js → src-5F5OTVYT.js} +1 -1
- package/dist/{src-SNSK5ENY.js → src-7X62AGW7.js} +1 -1
- package/dist/{src-UY4Y75BD.js → src-E7NTZL2F.js} +1 -1
- package/dist/{src-V3RUKDMQ.js → src-ESRY2MC7.js} +1 -1
- package/dist/{src-Z4C4SSDR.js → src-Z63IOSCJ.js} +1 -1
- package/dist/twinHarness-WJFDLEAO.js +6 -0
- package/dist/{twinSeed-X6VHBOLM.js → twinSeed-4VQ7RRCL.js} +1 -1
- package/dist/{twinStart-QQU6OIO4.js → twinStart-QQ64EV3P.js} +4 -4
- package/package.json +1 -2
- package/dist/agent-Q2UTRJYL.js +0 -408
- package/dist/chunk-46POYRLY.js +0 -1240
- package/dist/chunk-DFOQGAKS.js +0 -116
- package/dist/chunk-JNXZBK3O.js +0 -17
- package/dist/chunk-WERG4AUH.js +0 -462
- package/dist/chunk-ZX4WNSZ5.js +0 -71
- package/dist/runDemo-DRDMCG25.js +0 -408
- package/dist/twinHarness-ATYQTDA5.js +0 -6
|
@@ -4,7 +4,7 @@ export { DEFAULT_LINEAR_CLOCK, DEFAULT_LINEAR_EMAIL, DEFAULT_LINEAR_PORT, DEFAUL
|
|
|
4
4
|
import './chunk-JWJYNAWI.js';
|
|
5
5
|
import { routeInputDeclarer, mountDeclaredRoute, UndeclaredInputError } from './chunk-IZFM7W2V.js';
|
|
6
6
|
import { loadMcpToolFixture, deriveMcpToolTable, openTwinDatabase, defineTwin, createApp } from './chunk-HRAD7MRX.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-5KFDRR53.js';
|
|
8
8
|
import './chunk-SG6ZTIMT.js';
|
|
9
9
|
import './chunk-FBSA5L36.js';
|
|
10
10
|
import { createHmac, timingSafeEqual, createHash, randomBytes } from 'node:crypto';
|
|
@@ -4,7 +4,7 @@ import { defaultSeedState, parseSeed } from './chunk-YBWG5JK2.js';
|
|
|
4
4
|
export { defaultSeedState, loadSeedFromEnv, parseSeed, seedSchema } from './chunk-YBWG5JK2.js';
|
|
5
5
|
import { routeInputDeclarer, booleanInput, integerInput, mountDeclaredRoute, UndeclaredInputError } from './chunk-IZFM7W2V.js';
|
|
6
6
|
import { loadMcpToolFixture, defineTwin, queryTokenResolver, formTokenResolver, deriveMcpToolTable, UnknownToolError, openTwinDatabase, createApp, typeDisagreements } from './chunk-HRAD7MRX.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-5KFDRR53.js';
|
|
8
8
|
import './chunk-SG6ZTIMT.js';
|
|
9
9
|
import './chunk-FBSA5L36.js';
|
|
10
10
|
import { z, ZodError } from 'zod';
|
|
@@ -3,7 +3,7 @@ import { defaultSeedState, parseSeed } from './chunk-NBOQN5VX.js';
|
|
|
3
3
|
export { defaultSeedState, parseSeed, seedSchema } from './chunk-NBOQN5VX.js';
|
|
4
4
|
import { routeInputDeclarer, integerInput, mountDeclaredRoute, UndeclaredInputError, MalformedBodyError } from './chunk-IZFM7W2V.js';
|
|
5
5
|
import { loadMcpToolFixture, defineTwin, twinBuildInfo, deriveMcpToolTable, UnknownToolError, openTwinDatabase, createApp, typeDisagreements } from './chunk-HRAD7MRX.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-5KFDRR53.js';
|
|
7
7
|
import './chunk-SG6ZTIMT.js';
|
|
8
8
|
import './chunk-FBSA5L36.js';
|
|
9
9
|
import { z, ZodError } from 'zod';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { routeInputDeclarer, bracketedQuery, integerInput, booleanInput, mountDeclaredRoute, UndeclaredInputError } from './chunk-IZFM7W2V.js';
|
|
2
2
|
import { loadMcpToolFixture, openTwinDatabase, defineTwin, twinBuildInfo, deriveMcpToolTable, failureInjectionMiddleware, createApp, recordedRequestHeaders, UnknownToolError } from './chunk-HRAD7MRX.js';
|
|
3
|
-
import './chunk-
|
|
3
|
+
import './chunk-5KFDRR53.js';
|
|
4
4
|
import './chunk-SG6ZTIMT.js';
|
|
5
5
|
import { defaultSeed, seedSchema } from './chunk-2K6BJ3PI.js';
|
|
6
6
|
export { DEFAULT_API_KEY, DEFAULT_SID, defaultSeed, loadSeedFromEnv, parseSeed, seedSchema } from './chunk-2K6BJ3PI.js';
|
|
@@ -4,7 +4,7 @@ export { DEFAULT_GMAIL_AGENT_EMAIL, GmailError, SEARCH_MAILBOX_MESSAGE_BUDGET, a
|
|
|
4
4
|
import './chunk-JWJYNAWI.js';
|
|
5
5
|
import { routeInputDeclarer, integerInput, booleanInput, repeatedInput, mountDeclaredRoute, UndeclaredInputError, MalformedBodyError } from './chunk-IZFM7W2V.js';
|
|
6
6
|
import { loadMcpToolFixture, deriveMcpToolTable, defineTwin, openTwinDatabase, createApp } from './chunk-HRAD7MRX.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-5KFDRR53.js';
|
|
8
8
|
import './chunk-SG6ZTIMT.js';
|
|
9
9
|
import './chunk-FBSA5L36.js';
|
|
10
10
|
import { createHash, createHmac, timingSafeEqual, randomBytes } from 'node:crypto';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { readSeedFileText, seedForTwin, parseSeedFileText, soleTwinOf, twinsNamedBy } from './chunk-
|
|
2
|
-
import { bootTwin } from './chunk-
|
|
3
|
-
import { TWIN_REGISTRY, isTwinName, TWIN_NAMES, defaultPortFor } from './chunk-
|
|
1
|
+
import { readSeedFileText, seedForTwin, parseSeedFileText, soleTwinOf, twinsNamedBy } from './chunk-3YCX3KUL.js';
|
|
2
|
+
import { bootTwin } from './chunk-5A6HHA54.js';
|
|
3
|
+
import { TWIN_REGISTRY, isTwinName, TWIN_NAMES, defaultPortFor } from './chunk-ELIEDNF3.js';
|
|
4
4
|
import './chunk-HRAD7MRX.js';
|
|
5
|
-
import './chunk-
|
|
5
|
+
import './chunk-5KFDRR53.js';
|
|
6
6
|
import './chunk-SG6ZTIMT.js';
|
|
7
7
|
import './chunk-FBSA5L36.js';
|
|
8
8
|
import { randomBytes } from 'node:crypto';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pome-sh/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "Test AI agents against digital twins of real SaaS APIs. Records tool-call traces and scores them on pome.sh.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
51
51
|
"gate:recorder-overhead": "tsx scripts/recorder-overhead-gate.ts",
|
|
52
52
|
"gate:agent-trace-overhead": "tsx scripts/overhead-gate.ts",
|
|
53
|
-
"gate:cas-adapter-acceptance": "tsx scripts/cas-adapter-acceptance.ts",
|
|
54
53
|
"emit:manifest-schema": "node scripts/emit-manifest-schema.mjs",
|
|
55
54
|
"check:manifest-schema": "node scripts/emit-manifest-schema.mjs --check"
|
|
56
55
|
},
|
package/dist/agent-Q2UTRJYL.js
DELETED
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
import { DemoCapacityError, capacityMarkerLine, capacityKindFrom, capacityLabel } from './chunk-ZX4WNSZ5.js';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { request } from 'node:http';
|
|
4
|
-
import { connect as connect$1 } from 'node:net';
|
|
5
|
-
import { connect } from 'node:tls';
|
|
6
|
-
|
|
7
|
-
function isLoopbackHost(host) {
|
|
8
|
-
const value = host.trim().toLowerCase();
|
|
9
|
-
if (value === "localhost" || value.endsWith(".localhost")) return true;
|
|
10
|
-
if (value === "::1" || value === "[::1]") return true;
|
|
11
|
-
return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(value);
|
|
12
|
-
}
|
|
13
|
-
function matchesNoProxy(host, noProxy) {
|
|
14
|
-
if (!noProxy) return false;
|
|
15
|
-
const candidate = host.trim().toLowerCase();
|
|
16
|
-
return noProxy.split(",").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0).some(
|
|
17
|
-
(entry) => entry === "*" || candidate === entry || candidate.endsWith(entry.startsWith(".") ? entry : `.${entry}`)
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
async function postJsonMaybeViaProxy(options) {
|
|
21
|
-
const target = new URL(options.url);
|
|
22
|
-
const useProxy = Boolean(options.proxyUrl) && (options.forceProxy === true || !isLoopbackHost(target.hostname) && !matchesNoProxy(target.hostname, options.noProxy));
|
|
23
|
-
if (!useProxy) {
|
|
24
|
-
const ctrl = new AbortController();
|
|
25
|
-
const timer = setTimeout(() => ctrl.abort(), options.timeoutMs ?? 6e4);
|
|
26
|
-
try {
|
|
27
|
-
const res = await fetch(options.url, {
|
|
28
|
-
method: "POST",
|
|
29
|
-
headers: { ...options.headers, "content-type": "application/json" },
|
|
30
|
-
body: JSON.stringify(options.body),
|
|
31
|
-
signal: ctrl.signal
|
|
32
|
-
});
|
|
33
|
-
return { status: res.status, bodyText: await res.text() };
|
|
34
|
-
} finally {
|
|
35
|
-
clearTimeout(timer);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return postJsonThroughConnectProxy(target, options);
|
|
39
|
-
}
|
|
40
|
-
async function postJsonThroughConnectProxy(target, options) {
|
|
41
|
-
const proxy = new URL(options.proxyUrl);
|
|
42
|
-
const targetPort = Number(target.port || (target.protocol === "https:" ? 443 : 80));
|
|
43
|
-
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
44
|
-
const rawSocket = await connectTunnel(
|
|
45
|
-
proxy.hostname,
|
|
46
|
-
Number(proxy.port || 80),
|
|
47
|
-
target.hostname,
|
|
48
|
-
targetPort,
|
|
49
|
-
timeoutMs
|
|
50
|
-
);
|
|
51
|
-
const socket = target.protocol === "https:" ? await new Promise((resolve, reject) => {
|
|
52
|
-
const tlsSocket = connect(
|
|
53
|
-
{ socket: rawSocket, servername: target.hostname },
|
|
54
|
-
() => resolve(tlsSocket)
|
|
55
|
-
);
|
|
56
|
-
tlsSocket.once("error", reject);
|
|
57
|
-
}) : rawSocket;
|
|
58
|
-
return new Promise((resolve, reject) => {
|
|
59
|
-
const payload = JSON.stringify(options.body);
|
|
60
|
-
const req = request(
|
|
61
|
-
{
|
|
62
|
-
createConnection: () => socket,
|
|
63
|
-
method: "POST",
|
|
64
|
-
host: target.hostname,
|
|
65
|
-
port: targetPort,
|
|
66
|
-
path: `${target.pathname}${target.search}`,
|
|
67
|
-
headers: {
|
|
68
|
-
...options.headers,
|
|
69
|
-
host: target.host,
|
|
70
|
-
"content-type": "application/json",
|
|
71
|
-
"content-length": Buffer.byteLength(payload),
|
|
72
|
-
connection: "close"
|
|
73
|
-
},
|
|
74
|
-
timeout: timeoutMs
|
|
75
|
-
},
|
|
76
|
-
(res) => {
|
|
77
|
-
let bodyText = "";
|
|
78
|
-
res.setEncoding("utf8");
|
|
79
|
-
res.on("data", (chunk) => {
|
|
80
|
-
bodyText += chunk;
|
|
81
|
-
});
|
|
82
|
-
res.on("end", () => {
|
|
83
|
-
resolve({ status: res.statusCode ?? 0, bodyText });
|
|
84
|
-
});
|
|
85
|
-
res.on("error", reject);
|
|
86
|
-
}
|
|
87
|
-
);
|
|
88
|
-
req.on("timeout", () => {
|
|
89
|
-
req.destroy(new Error(`request to ${target.host} timed out after ${timeoutMs}ms`));
|
|
90
|
-
});
|
|
91
|
-
req.on("error", (err) => {
|
|
92
|
-
socket.destroy();
|
|
93
|
-
reject(err);
|
|
94
|
-
});
|
|
95
|
-
req.end(payload);
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
function connectTunnel(proxyHost, proxyPort, targetHost, targetPort, timeoutMs) {
|
|
99
|
-
return new Promise((resolve, reject) => {
|
|
100
|
-
const sock = connect$1({ host: proxyHost, port: proxyPort });
|
|
101
|
-
let buf = "";
|
|
102
|
-
let settled = false;
|
|
103
|
-
const timer = setTimeout(() => {
|
|
104
|
-
if (settled) return;
|
|
105
|
-
settled = true;
|
|
106
|
-
sock.destroy();
|
|
107
|
-
reject(new Error(`CONNECT to ${targetHost}:${targetPort} timed out after ${timeoutMs}ms`));
|
|
108
|
-
}, timeoutMs);
|
|
109
|
-
const fail = (err) => {
|
|
110
|
-
if (settled) return;
|
|
111
|
-
settled = true;
|
|
112
|
-
clearTimeout(timer);
|
|
113
|
-
sock.destroy();
|
|
114
|
-
reject(err);
|
|
115
|
-
};
|
|
116
|
-
sock.once("error", fail);
|
|
117
|
-
const onData = (chunk) => {
|
|
118
|
-
buf += chunk.toString("utf8");
|
|
119
|
-
const headerEnd = buf.indexOf("\r\n\r\n");
|
|
120
|
-
if (headerEnd === -1) return;
|
|
121
|
-
sock.off("data", onData);
|
|
122
|
-
if (!/^HTTP\/1\.[01] 200/.test(buf)) {
|
|
123
|
-
fail(new Error(`CONNECT ${targetHost}:${targetPort} refused: ${buf.split("\r\n")[0]}`));
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
settled = true;
|
|
127
|
-
clearTimeout(timer);
|
|
128
|
-
sock.pause();
|
|
129
|
-
const rest = Buffer.from(buf.slice(headerEnd + 4), "utf8");
|
|
130
|
-
if (rest.length > 0) sock.unshift(rest);
|
|
131
|
-
sock.resume();
|
|
132
|
-
resolve(sock);
|
|
133
|
-
};
|
|
134
|
-
sock.on("data", onData);
|
|
135
|
-
sock.write(
|
|
136
|
-
`CONNECT ${targetHost}:${targetPort} HTTP/1.1\r
|
|
137
|
-
Host: ${targetHost}:${targetPort}\r
|
|
138
|
-
\r
|
|
139
|
-
`
|
|
140
|
-
);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// src/demo/gateway.ts
|
|
145
|
-
var gatewayResponseSchema = z.object({
|
|
146
|
-
text: z.string(),
|
|
147
|
-
tool_calls: z.array(
|
|
148
|
-
z.object({
|
|
149
|
-
id: z.string(),
|
|
150
|
-
name: z.string(),
|
|
151
|
-
input: z.unknown()
|
|
152
|
-
})
|
|
153
|
-
),
|
|
154
|
-
finish_reason: z.string(),
|
|
155
|
-
usage: z.object({
|
|
156
|
-
input_tokens: z.number(),
|
|
157
|
-
output_tokens: z.number()
|
|
158
|
-
}).optional()
|
|
159
|
-
});
|
|
160
|
-
var DemoGatewayError = class extends Error {
|
|
161
|
-
constructor(message, status) {
|
|
162
|
-
super(message);
|
|
163
|
-
this.status = status;
|
|
164
|
-
this.name = "DemoGatewayError";
|
|
165
|
-
}
|
|
166
|
-
status;
|
|
167
|
-
};
|
|
168
|
-
async function callDemoGateway(options) {
|
|
169
|
-
const { status, bodyText } = await postJsonMaybeViaProxy({
|
|
170
|
-
url: options.gatewayUrl,
|
|
171
|
-
headers: { authorization: `Bearer ${options.demoToken}` },
|
|
172
|
-
body: {
|
|
173
|
-
task_name: options.taskName,
|
|
174
|
-
messages: options.messages,
|
|
175
|
-
...options.tools && options.tools.length > 0 ? { tools: options.tools } : {}
|
|
176
|
-
},
|
|
177
|
-
proxyUrl: options.proxyUrl,
|
|
178
|
-
noProxy: options.noProxy,
|
|
179
|
-
timeoutMs: options.timeoutMs ?? 12e4,
|
|
180
|
-
forceProxy: options.forceProxyForTest
|
|
181
|
-
});
|
|
182
|
-
let json = {};
|
|
183
|
-
try {
|
|
184
|
-
json = bodyText.length ? JSON.parse(bodyText) : {};
|
|
185
|
-
} catch {
|
|
186
|
-
throw new DemoGatewayError(
|
|
187
|
-
`demo gateway returned non-JSON (status ${status})`,
|
|
188
|
-
status
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
if (status < 200 || status >= 300) {
|
|
192
|
-
const envelope = json.error;
|
|
193
|
-
const kind = capacityKindFrom(status, envelope?.details?.kind);
|
|
194
|
-
if (kind) {
|
|
195
|
-
throw new DemoCapacityError(kind, envelope?.message ?? capacityLabel(kind));
|
|
196
|
-
}
|
|
197
|
-
throw new DemoGatewayError(
|
|
198
|
-
envelope?.message ?? `demo gateway \u2192 HTTP ${status}`,
|
|
199
|
-
status
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
const parsed = gatewayResponseSchema.safeParse(json);
|
|
203
|
-
if (!parsed.success) {
|
|
204
|
-
throw new DemoGatewayError(
|
|
205
|
-
`demo gateway returned an unexpected shape: ${parsed.error.message}`,
|
|
206
|
-
status
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
return parsed.data;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// src/demo/agent.ts
|
|
213
|
-
var MAX_TURNS = 12;
|
|
214
|
-
var DEMO_AGENT_TOOLS = [
|
|
215
|
-
{
|
|
216
|
-
name: "list_open_issues",
|
|
217
|
-
description: "List the open issues in the repository you are triaging. Returns number, title, body, and current labels for each.",
|
|
218
|
-
input_schema: {
|
|
219
|
-
type: "object",
|
|
220
|
-
properties: {},
|
|
221
|
-
additionalProperties: false
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
name: "add_label",
|
|
226
|
-
description: "Apply an EXISTING label to an issue by number. Fails if the label does not exist in the repository.",
|
|
227
|
-
input_schema: {
|
|
228
|
-
type: "object",
|
|
229
|
-
properties: {
|
|
230
|
-
issue_number: { type: "number", description: "Issue number, e.g. 1" },
|
|
231
|
-
label: { type: "string", description: "Name of an existing label" }
|
|
232
|
-
},
|
|
233
|
-
required: ["issue_number", "label"],
|
|
234
|
-
additionalProperties: false
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
name: "comment_on_issue",
|
|
239
|
-
description: "Leave one comment on an issue by number.",
|
|
240
|
-
input_schema: {
|
|
241
|
-
type: "object",
|
|
242
|
-
properties: {
|
|
243
|
-
issue_number: { type: "number", description: "Issue number, e.g. 1" },
|
|
244
|
-
body: { type: "string", description: "Comment body (markdown)" }
|
|
245
|
-
},
|
|
246
|
-
required: ["issue_number", "body"],
|
|
247
|
-
additionalProperties: false
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
];
|
|
251
|
-
function readDemoAgentEnv(env) {
|
|
252
|
-
const required = (name) => {
|
|
253
|
-
const value = env[name]?.trim();
|
|
254
|
-
if (!value) throw new Error(`${name} is required for pome demo-agent`);
|
|
255
|
-
return value;
|
|
256
|
-
};
|
|
257
|
-
return {
|
|
258
|
-
task: required("POME_TASK"),
|
|
259
|
-
twinRestUrl: required("POME_GITHUB_REST_URL"),
|
|
260
|
-
twinAuthToken: required("POME_AUTH_TOKEN"),
|
|
261
|
-
gatewayUrl: required("POME_DEMO_LLM_URL"),
|
|
262
|
-
demoToken: required("POME_DEMO_TOKEN"),
|
|
263
|
-
taskName: required("POME_DEMO_TASK_NAME"),
|
|
264
|
-
repo: required("POME_DEMO_REPO"),
|
|
265
|
-
proxyUrl: env.HTTPS_PROXY ?? env.HTTP_PROXY,
|
|
266
|
-
noProxy: env.NO_PROXY
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
async function twinFetch(agentEnv, path, init) {
|
|
270
|
-
const res = await fetch(`${agentEnv.twinRestUrl}${path}`, {
|
|
271
|
-
method: init?.method ?? "GET",
|
|
272
|
-
headers: {
|
|
273
|
-
authorization: `Bearer ${agentEnv.twinAuthToken}`,
|
|
274
|
-
...init?.body !== void 0 ? { "content-type": "application/json" } : {}
|
|
275
|
-
},
|
|
276
|
-
body: init?.body !== void 0 ? JSON.stringify(init.body) : void 0
|
|
277
|
-
});
|
|
278
|
-
const text = await res.text();
|
|
279
|
-
if (!res.ok) {
|
|
280
|
-
throw new Error(
|
|
281
|
-
`${init?.method ?? "GET"} ${path} \u2192 ${res.status}: ${text.slice(0, 300)}`
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
return text.length ? JSON.parse(text) : {};
|
|
285
|
-
}
|
|
286
|
-
async function executeDemoTool(agentEnv, name, input) {
|
|
287
|
-
const [owner, repo] = agentEnv.repo.split("/");
|
|
288
|
-
const args = input ?? {};
|
|
289
|
-
try {
|
|
290
|
-
switch (name) {
|
|
291
|
-
case "list_open_issues": {
|
|
292
|
-
const issues = await twinFetch(
|
|
293
|
-
agentEnv,
|
|
294
|
-
`/repos/${owner}/${repo}/issues?state=open`
|
|
295
|
-
);
|
|
296
|
-
return {
|
|
297
|
-
output: issues.map((issue) => ({
|
|
298
|
-
number: issue.number,
|
|
299
|
-
title: issue.title,
|
|
300
|
-
body: issue.body,
|
|
301
|
-
labels: (issue.labels ?? []).map(
|
|
302
|
-
(label) => typeof label === "string" ? label : label.name
|
|
303
|
-
)
|
|
304
|
-
})),
|
|
305
|
-
isError: false
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
case "add_label": {
|
|
309
|
-
const issueNumber = Number(args.issue_number);
|
|
310
|
-
const label = String(args.label ?? "");
|
|
311
|
-
if (!Number.isInteger(issueNumber) || label.length === 0) {
|
|
312
|
-
return { output: "add_label requires issue_number and label", isError: true };
|
|
313
|
-
}
|
|
314
|
-
await twinFetch(agentEnv, `/repos/${owner}/${repo}/issues/${issueNumber}/labels`, {
|
|
315
|
-
method: "POST",
|
|
316
|
-
body: { labels: [label] }
|
|
317
|
-
});
|
|
318
|
-
return { output: `applied label "${label}" to issue #${issueNumber}`, isError: false };
|
|
319
|
-
}
|
|
320
|
-
case "comment_on_issue": {
|
|
321
|
-
const issueNumber = Number(args.issue_number);
|
|
322
|
-
const body = String(args.body ?? "");
|
|
323
|
-
if (!Number.isInteger(issueNumber) || body.length === 0) {
|
|
324
|
-
return { output: "comment_on_issue requires issue_number and body", isError: true };
|
|
325
|
-
}
|
|
326
|
-
await twinFetch(agentEnv, `/repos/${owner}/${repo}/issues/${issueNumber}/comments`, {
|
|
327
|
-
method: "POST",
|
|
328
|
-
body: { body }
|
|
329
|
-
});
|
|
330
|
-
return { output: `commented on issue #${issueNumber}`, isError: false };
|
|
331
|
-
}
|
|
332
|
-
default:
|
|
333
|
-
return { output: `unknown tool: ${name}`, isError: true };
|
|
334
|
-
}
|
|
335
|
-
} catch (err) {
|
|
336
|
-
return {
|
|
337
|
-
output: err instanceof Error ? err.message : String(err),
|
|
338
|
-
isError: true
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
async function runDemoAgent(agentEnv, io) {
|
|
343
|
-
const messages = [{ role: "user", content: agentEnv.task }];
|
|
344
|
-
try {
|
|
345
|
-
for (let turn = 0; turn < MAX_TURNS; turn += 1) {
|
|
346
|
-
const response = await callDemoGateway({
|
|
347
|
-
gatewayUrl: agentEnv.gatewayUrl,
|
|
348
|
-
demoToken: agentEnv.demoToken,
|
|
349
|
-
taskName: agentEnv.taskName,
|
|
350
|
-
messages,
|
|
351
|
-
tools: DEMO_AGENT_TOOLS,
|
|
352
|
-
proxyUrl: agentEnv.proxyUrl,
|
|
353
|
-
noProxy: agentEnv.noProxy
|
|
354
|
-
});
|
|
355
|
-
if (response.tool_calls.length === 0) {
|
|
356
|
-
io.log(response.text.trim().length > 0 ? response.text.trim() : "(done)");
|
|
357
|
-
return 0;
|
|
358
|
-
}
|
|
359
|
-
const assistantParts = [];
|
|
360
|
-
if (response.text.trim().length > 0) {
|
|
361
|
-
assistantParts.push({ type: "text", text: response.text });
|
|
362
|
-
}
|
|
363
|
-
for (const call of response.tool_calls) {
|
|
364
|
-
assistantParts.push({
|
|
365
|
-
type: "tool-call",
|
|
366
|
-
toolCallId: call.id,
|
|
367
|
-
toolName: call.name,
|
|
368
|
-
input: call.input
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
messages.push({ role: "assistant", content: assistantParts });
|
|
372
|
-
const resultParts = [];
|
|
373
|
-
for (const call of response.tool_calls) {
|
|
374
|
-
const result = await executeDemoTool(agentEnv, call.name, call.input);
|
|
375
|
-
resultParts.push({
|
|
376
|
-
type: "tool-result",
|
|
377
|
-
toolCallId: call.id,
|
|
378
|
-
toolName: call.name,
|
|
379
|
-
output: result.isError ? { type: "error-text", value: String(result.output) } : { type: "json", value: result.output }
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
messages.push({ role: "tool", content: resultParts });
|
|
383
|
-
}
|
|
384
|
-
io.error(`demo agent gave up after ${MAX_TURNS} model calls without finishing`);
|
|
385
|
-
return 1;
|
|
386
|
-
} catch (err) {
|
|
387
|
-
if (err instanceof DemoCapacityError) {
|
|
388
|
-
io.error(capacityMarkerLine(err.kind));
|
|
389
|
-
io.error(err.message);
|
|
390
|
-
return 42;
|
|
391
|
-
}
|
|
392
|
-
io.error(err instanceof Error ? err.message : String(err));
|
|
393
|
-
return 1;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
async function runDemoAgentCommand() {
|
|
397
|
-
if (process.env.POME_PREFLIGHT === "1") {
|
|
398
|
-
console.log("preflight ok");
|
|
399
|
-
return 0;
|
|
400
|
-
}
|
|
401
|
-
const agentEnv = readDemoAgentEnv(process.env);
|
|
402
|
-
return runDemoAgent(agentEnv, {
|
|
403
|
-
log: (line) => console.log(line),
|
|
404
|
-
error: (line) => console.error(line)
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
export { DEMO_AGENT_TOOLS, executeDemoTool, readDemoAgentEnv, runDemoAgent, runDemoAgentCommand };
|