tewip-ai 0.70.4 → 0.70.5
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/engine/a2a/serve.js +29 -4
- package/package.json +1 -1
package/dist/engine/a2a/serve.js
CHANGED
|
@@ -112,15 +112,15 @@ export function handleRpc(cmd, body) {
|
|
|
112
112
|
}
|
|
113
113
|
const choice = chooseSkill(message);
|
|
114
114
|
if (choice.kind === 'ask') {
|
|
115
|
-
record(cmd.root, { method, outcome: 'asked-back', why: choice.why });
|
|
115
|
+
record(cmd.root, { http: 'POST', path: JSONRPC_PATH, method, outcome: 'asked-back', why: choice.why });
|
|
116
116
|
return { status: 200, payload: { jsonrpc: '2.0', id, result: needsInput(askWhich(choice.why)) } };
|
|
117
117
|
}
|
|
118
118
|
if (choice.kind === 'unknown') {
|
|
119
|
-
record(cmd.root, { method, outcome: 'unknown-skill', asked: choice.asked });
|
|
119
|
+
record(cmd.root, { http: 'POST', path: JSONRPC_PATH, method, outcome: 'unknown-skill', asked: choice.asked });
|
|
120
120
|
return { status: 200, payload: { jsonrpc: '2.0', id, result: needsInput(askWhich(`"${choice.asked}" is not a skill Tewip has`)) } };
|
|
121
121
|
}
|
|
122
122
|
const answered = runSkill(cmd.root, choice.skill, []);
|
|
123
|
-
record(cmd.root, { method, outcome: 'answered', skill: choice.skill.id, verb: choice.skill.verb, failed: answered.failed });
|
|
123
|
+
record(cmd.root, { http: 'POST', path: JSONRPC_PATH, method, outcome: 'answered', skill: choice.skill.id, verb: choice.skill.verb, failed: answered.failed });
|
|
124
124
|
return { status: 200, payload: { jsonrpc: '2.0', id, result: completedTask(answered.text, answered.failed) } };
|
|
125
125
|
}
|
|
126
126
|
/** True of an address that only this machine can reach. */
|
|
@@ -130,11 +130,26 @@ export function serveA2A(cmd) {
|
|
|
130
130
|
const url = `http://${cmd.host}:${cmd.port}${JSONRPC_PATH}`;
|
|
131
131
|
const server = createServer((req, res) => {
|
|
132
132
|
const path = (req.url ?? '').split('?')[0];
|
|
133
|
+
// What reaches the port, not only what gets answered.
|
|
134
|
+
//
|
|
135
|
+
// `record` was called from the three places inside the answering path, so the log held
|
|
136
|
+
// successful answers and nothing else. Measured by sending four requests and finding one: a POST
|
|
137
|
+
// to the wrong path, a JSON-RPC call for a method this agent does not have, and a malformed body
|
|
138
|
+
// all left **no trace at all**. On a port with no authentication those are the entries worth
|
|
139
|
+
// keeping - a peer probing for methods is exactly what an operator needs to see - and the file's
|
|
140
|
+
// own comment promises "a record of what another agent asked for and what it was told". A
|
|
141
|
+
// rejected request is still something another agent asked for.
|
|
142
|
+
//
|
|
143
|
+
// The request's body is never recorded, only what it asked for and how it was answered, because
|
|
144
|
+
// a body from another agent can contain anything.
|
|
145
|
+
const seen = (outcome, extra = {}) => record(root, { http: req.method ?? '', path, outcome, ...extra });
|
|
133
146
|
if (req.method === 'GET' && path === CARD_PATH) {
|
|
147
|
+
seen('card-read');
|
|
134
148
|
send(res, 200, agentCard(url, cmd.tewipRoot));
|
|
135
149
|
return;
|
|
136
150
|
}
|
|
137
151
|
if (req.method !== 'POST' || path !== JSONRPC_PATH) {
|
|
152
|
+
seen('no-such-endpoint');
|
|
138
153
|
send(res, 404, { error: `nothing here. The card is at ${CARD_PATH} and calls go to ${JSONRPC_PATH}` });
|
|
139
154
|
return;
|
|
140
155
|
}
|
|
@@ -145,13 +160,23 @@ export function serveA2A(cmd) {
|
|
|
145
160
|
parsed = JSON.parse(raw);
|
|
146
161
|
}
|
|
147
162
|
catch {
|
|
163
|
+
seen('body-not-json');
|
|
148
164
|
send(res, 400, rpcError(null, INVALID_PARAMS, 'the body is not JSON'));
|
|
149
165
|
return;
|
|
150
166
|
}
|
|
151
167
|
const { status, payload } = handleRpc({ ...cmd, root }, parsed);
|
|
168
|
+
// A JSON-RPC error rides in a 200 response - the transport worked, the call did not - so the
|
|
169
|
+
// HTTP status cannot be the test. Checking it missed exactly the entry worth having: a peer
|
|
170
|
+
// asking for a method this agent does not implement.
|
|
171
|
+
const rpc = payload ?? {};
|
|
172
|
+
if (rpc.error)
|
|
173
|
+
seen('refused', { why: rpc.error.message ?? '' });
|
|
152
174
|
send(res, status, payload);
|
|
153
175
|
})
|
|
154
|
-
.catch((error) =>
|
|
176
|
+
.catch((error) => {
|
|
177
|
+
seen('body-rejected', { why: error.message });
|
|
178
|
+
send(res, 413, rpcError(null, INVALID_PARAMS, error.message));
|
|
179
|
+
});
|
|
155
180
|
});
|
|
156
181
|
server.listen(cmd.port, cmd.host, () => {
|
|
157
182
|
console.log(`Tewip is answering other agents about ${root}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tewip-ai",
|
|
3
|
-
"version": "0.70.
|
|
3
|
+
"version": "0.70.5",
|
|
4
4
|
"mcpName": "io.github.hmamut39/tewip",
|
|
5
5
|
"description": "Tewip finds why each failing test failed - real bug, flaky test, environment, test data or changed selector - for any stack, from the command line, CI, or your editor.",
|
|
6
6
|
"keywords": [
|