doer-agent 0.6.9 → 0.7.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.
@@ -1,5 +1,62 @@
1
1
  import { StringCodec } from "nats";
2
2
  const codexAppRpcCodec = StringCodec();
3
+ const codexAppRpcOmitRules = [
4
+ {
5
+ method: "thread/turns/list",
6
+ itemType: "imageGeneration",
7
+ keys: ["result"],
8
+ },
9
+ ];
10
+ function recordValue(value) {
11
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
12
+ }
13
+ function omitKeysFromRecord(record, keys) {
14
+ const next = { ...record };
15
+ for (const key of keys) {
16
+ delete next[key];
17
+ }
18
+ return next;
19
+ }
20
+ function omitRulesForThreadTurnItem(method, item) {
21
+ return codexAppRpcOmitRules.filter((rule) => {
22
+ if (rule.method !== method) {
23
+ return false;
24
+ }
25
+ return !rule.itemType || item.type === rule.itemType;
26
+ });
27
+ }
28
+ function applyCodexAppRpcOmitRules(method, value) {
29
+ if (!codexAppRpcOmitRules.some((rule) => rule.method === method)) {
30
+ return value;
31
+ }
32
+ const response = recordValue(value);
33
+ if (!response || !Array.isArray(response.data)) {
34
+ return value;
35
+ }
36
+ return {
37
+ ...response,
38
+ data: response.data.map((turnValue) => {
39
+ const turn = recordValue(turnValue);
40
+ if (!turn || !Array.isArray(turn.items)) {
41
+ return turnValue;
42
+ }
43
+ return {
44
+ ...turn,
45
+ items: turn.items.map((itemValue) => {
46
+ const item = recordValue(itemValue);
47
+ if (!item) {
48
+ return itemValue;
49
+ }
50
+ const rules = omitRulesForThreadTurnItem(method, item);
51
+ if (rules.length === 0) {
52
+ return itemValue;
53
+ }
54
+ return rules.reduce((current, rule) => omitKeysFromRecord(current, rule.keys), item);
55
+ }),
56
+ };
57
+ }),
58
+ };
59
+ }
3
60
  function normalizeCodexAppRpcRequest(args) {
4
61
  const requestId = typeof args.request.requestId === "string" ? args.request.requestId.trim() : "";
5
62
  const requestAgentId = typeof args.request.agentId === "string" ? args.request.agentId.trim() : "";
@@ -21,7 +78,7 @@ async function handleCodexAppRpcMessage(args) {
21
78
  const payload = JSON.parse(codexAppRpcCodec.decode(args.msg.data));
22
79
  const request = normalizeCodexAppRpcRequest({ request: payload, agentId: args.agentId });
23
80
  requestId = request.requestId;
24
- const result = await args.manager.request(request.method, request.params);
81
+ const result = applyCodexAppRpcOmitRules(request.method, await args.manager.request(request.method, request.params));
25
82
  args.msg.respond(codexAppRpcCodec.encode(JSON.stringify({
26
83
  requestId,
27
84
  ok: true,
@@ -100,6 +100,18 @@ async function showMobileNotification(args) {
100
100
  url: args.url,
101
101
  });
102
102
  }
103
+ async function showMobileConfirmation(args) {
104
+ const config = getConfig();
105
+ const resolvedDeviceId = await resolveDeviceId(args.deviceId);
106
+ return await postJson(`/api/users/${encodeURIComponent(config.userId)}/agents/${encodeURIComponent(config.agentId)}/mobile-agents/${encodeURIComponent(resolvedDeviceId)}/show-confirmation`, {
107
+ title: args.title,
108
+ text: args.text,
109
+ requestId: args.requestId,
110
+ yesLabel: args.yesLabel,
111
+ noLabel: args.noLabel,
112
+ notificationId: args.notificationId,
113
+ });
114
+ }
103
115
  async function getMobileLogs(args) {
104
116
  const config = getConfig();
105
117
  const resolvedDeviceId = await resolveDeviceId(args.deviceId);
@@ -167,6 +179,9 @@ function extractLocationEvents(events) {
167
179
  function extractNotifications(events) {
168
180
  return events.filter((event) => event.kind.startsWith("notification."));
169
181
  }
182
+ function extractConfirmations(events) {
183
+ return events.filter((event) => event.kind.startsWith("confirmation."));
184
+ }
170
185
  async function main() {
171
186
  const server = new McpServer({
172
187
  name: "doer-mobile",
@@ -294,6 +309,44 @@ async function main() {
294
309
  structuredContent: result,
295
310
  };
296
311
  });
312
+ server.registerTool("mobile_show_confirmation", {
313
+ description: "Show a high-priority mobile confirmation notification with only Yes/No actions. Responses are stored in the mobile event log as confirmation.response.",
314
+ inputSchema: {
315
+ deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
316
+ requestId: z.string().optional().describe("Caller-provided id for matching the eventual confirmation.response log. Generated by the server when omitted."),
317
+ title: z.string().min(1).describe("Confirmation title."),
318
+ text: z.string().min(1).describe("Confirmation body text."),
319
+ yesLabel: z.string().optional().describe("Label for the affirmative action. Defaults to Yes."),
320
+ noLabel: z.string().optional().describe("Label for the negative action. Defaults to No."),
321
+ notificationId: z.number().int().optional().describe("Optional Android notification id. Reusing an id updates the existing confirmation notification."),
322
+ },
323
+ }, async ({ deviceId, requestId, title, text, yesLabel, noLabel, notificationId }) => {
324
+ const result = await showMobileConfirmation({ deviceId, requestId, title, text, yesLabel, noLabel, notificationId });
325
+ return {
326
+ content: [{ type: "text", text: formatJson(result) }],
327
+ structuredContent: result,
328
+ };
329
+ });
330
+ server.registerTool("mobile_search_confirmation_logs", {
331
+ description: "Return recent confirmation request/response/dismissed events stored in mobile logs.",
332
+ inputSchema: {
333
+ deviceId: z.string().optional().describe("Mobile device id. Defaults to the first registered mobile agent."),
334
+ limit: z.number().int().min(1).max(1000).optional().describe("How many recent events to scan."),
335
+ requestId: z.string().optional().describe("Optional confirmation request id to search for."),
336
+ },
337
+ }, async ({ deviceId, limit, requestId }) => {
338
+ const page = await searchMobileLogs({
339
+ deviceId,
340
+ kind: "confirmation.",
341
+ limit: limit ?? 200,
342
+ query: requestId?.trim() || undefined,
343
+ });
344
+ const events = extractConfirmations(page.events);
345
+ return {
346
+ content: [{ type: "text", text: formatJson({ events }) }],
347
+ structuredContent: { events },
348
+ };
349
+ });
297
350
  server.registerTool("mobile_search_notification_logs", {
298
351
  description: "Return recent notification events stored in mobile logs.",
299
352
  inputSchema: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doer-agent",
3
- "version": "0.6.9",
3
+ "version": "0.7.1",
4
4
  "description": "Reverse-polling agent runtime for doer",
5
5
  "type": "module",
6
6
  "main": "dist/agent.js",