@rubytech/taskmaster 1.17.0 → 1.17.4
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/agents/workspace-migrations.js +61 -0
- package/dist/build-info.json +3 -3
- package/dist/config/agent-tools-reconcile.js +58 -0
- package/dist/control-ui/assets/{index-Beuhzjy_.js → index-koe4eKhk.js} +4 -4
- package/dist/control-ui/assets/index-koe4eKhk.js.map +1 -0
- package/dist/control-ui/index.html +1 -1
- package/dist/cron/service/timer.js +5 -1
- package/dist/gateway/server-methods/apikeys.js +2 -0
- package/dist/gateway/server.impl.js +16 -1
- package/dist/hooks/bundled/ride-dispatch/handler.js +23 -9
- package/package.json +1 -1
- package/templates/beagle-zanzibar/agents/admin/AGENTS.md +16 -8
- package/templates/beagle-zanzibar/agents/public/AGENTS.md +10 -5
- package/dist/control-ui/assets/index-Beuhzjy_.js.map +0 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>Taskmaster Control</title>
|
|
7
7
|
<meta name="color-scheme" content="dark light" />
|
|
8
8
|
<link rel="icon" type="image/png" href="./favicon.png" />
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-koe4eKhk.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="./assets/index-XqRo9tNW.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
@@ -103,7 +103,11 @@ export async function executeJob(state, job, nowMs, opts) {
|
|
|
103
103
|
}
|
|
104
104
|
if (job.sessionTarget === "isolated") {
|
|
105
105
|
const prefix = job.isolation?.postToMainPrefix?.trim() || "Cron";
|
|
106
|
-
const
|
|
106
|
+
const configuredMode = job.isolation?.postToMainMode ?? "summary";
|
|
107
|
+
// When delivery was skipped (best-effort, no external channel configured),
|
|
108
|
+
// promote to "full" so the admin sees the actual report in their main chat
|
|
109
|
+
// instead of a delivery-error summary.
|
|
110
|
+
const mode = status === "skipped" && outputText ? "full" : configuredMode;
|
|
107
111
|
let body = (summary ?? err ?? status).trim();
|
|
108
112
|
if (mode === "full") {
|
|
109
113
|
// Prefer full agent output if available; fall back to summary.
|
|
@@ -27,6 +27,8 @@ const PROVIDER_CATALOG = [
|
|
|
27
27
|
{ id: "brave", name: "Brave", category: "Web Search" },
|
|
28
28
|
{ id: "elevenlabs", name: "ElevenLabs", category: "Voice" },
|
|
29
29
|
{ id: "brevo", name: "Brevo", category: "Email" },
|
|
30
|
+
{ id: "stripe", name: "Stripe", category: "Payments" },
|
|
31
|
+
{ id: "stripe_webhook_secret", name: "Stripe Webhook Secret", category: "Payments" },
|
|
30
32
|
];
|
|
31
33
|
const VALID_PROVIDER_IDS = new Set(PROVIDER_CATALOG.map((p) => p.id));
|
|
32
34
|
export const apikeysHandlers = {
|
|
@@ -10,7 +10,7 @@ import { CONFIG_PATH_TASKMASTER, isNixMode, loadConfig, migrateLegacyConfig, rea
|
|
|
10
10
|
import { VERSION } from "../version.js";
|
|
11
11
|
import { isDiagnosticsEnabled } from "../infra/diagnostic-events.js";
|
|
12
12
|
import { logAcceptedEnvOption } from "../infra/env.js";
|
|
13
|
-
import { reconcileAgentContactTools, reconcileBeaglePublicTools, reconcileQrGenerateTool, reconcileStaleToolEntries, } from "../config/agent-tools-reconcile.js";
|
|
13
|
+
import { reconcileAgentContactTools, reconcileBeaglePublicTools, reconcileControlPanelTools, reconcileQrGenerateTool, reconcileStaleToolEntries, } from "../config/agent-tools-reconcile.js";
|
|
14
14
|
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
|
|
15
15
|
import { clearAgentRunContext, onAgentEvent } from "../infra/agent-events.js";
|
|
16
16
|
import { onHeartbeatEvent } from "../infra/heartbeat-events.js";
|
|
@@ -198,6 +198,21 @@ export async function startGatewayServer(port = 18789, opts = {}) {
|
|
|
198
198
|
log.warn(`gateway: failed to persist qr_generate tool reconciliation: ${String(err)}`);
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
|
+
// Upgrade admin agents from individual control-panel tools to group:control-panel.
|
|
202
|
+
// Agents set up before the group existed miss tools added to it later (e.g. logs_read).
|
|
203
|
+
const cpReconcile = reconcileControlPanelTools({ config: configSnapshot.config });
|
|
204
|
+
if (cpReconcile.changes.length > 0) {
|
|
205
|
+
try {
|
|
206
|
+
await writeConfigFile(cpReconcile.config);
|
|
207
|
+
configSnapshot = await readConfigFileSnapshot();
|
|
208
|
+
log.info(`gateway: reconciled control-panel tools:\n${cpReconcile.changes
|
|
209
|
+
.map((entry) => `- ${entry}`)
|
|
210
|
+
.join("\n")}`);
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
log.warn(`gateway: failed to persist control-panel tools reconciliation: ${String(err)}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
201
216
|
// Stamp config with running version on startup so upgrades keep the stamp current.
|
|
202
217
|
const storedVersion = configSnapshot.config.meta?.lastTouchedVersion;
|
|
203
218
|
if (configSnapshot.exists && storedVersion !== VERSION) {
|
|
@@ -253,12 +253,15 @@ function buildTripRequestInstruction(fields, resolvedAccountId) {
|
|
|
253
253
|
`4. For each selected driver, update their status to awaiting_response via memory_write\n` +
|
|
254
254
|
`5. Write shared/active-negotiations/{driver-phone}.md with job_id: ${jobId} for each driver\n` +
|
|
255
255
|
`6. Message each driver in Swahili with the route details, pickup time, passengers, and job ID [${jobId}]\n` +
|
|
256
|
-
` Use the message tool with accountId: "${accountId}"\n` +
|
|
256
|
+
` Use the message tool with channel: "whatsapp", accountId: "${accountId}"\n` +
|
|
257
257
|
`7. Message the tourist at ${touristPhone} confirming you've contacted drivers and are waiting for quotes\n` +
|
|
258
|
-
` Use the message tool with accountId: "${accountId}"\n` +
|
|
258
|
+
` Use the message tool with channel: "whatsapp", accountId: "${accountId}"\n` +
|
|
259
259
|
`8. When drivers reply with quotes (dispatched to this session), compile the offers\n` +
|
|
260
|
-
`9. Message the tourist with up to 3 competing offers: fare,
|
|
261
|
-
`
|
|
260
|
+
`9. Message the tourist at ${touristPhone} with up to 3 competing offers: fare, vehicle type, driver rating, estimated journey time\n` +
|
|
261
|
+
` Use the message tool with channel: "whatsapp", accountId: "${accountId}"\n` +
|
|
262
|
+
` Cross-agent echo will relay the message to the tourist's active session automatically\n` +
|
|
263
|
+
` Do NOT reveal driver name, phone, or plate — those are gated by payment\n` +
|
|
264
|
+
` NOTE: Do NOT write a dispatch file for the offers — message the tourist directly\n`);
|
|
262
265
|
}
|
|
263
266
|
function buildBookingConfirmInstruction(fields, resolvedAccountId) {
|
|
264
267
|
const jobId = fields.job_id ?? "UNKNOWN";
|
|
@@ -278,7 +281,7 @@ function buildBookingConfirmInstruction(fields, resolvedAccountId) {
|
|
|
278
281
|
`1. Load the stripe skill and generate a Checkout Session for the booking fee\n` +
|
|
279
282
|
` Set metadata: booking_id="${jobId}", tourist_phone="${touristPhone}"\n` +
|
|
280
283
|
`2. Message the tourist at ${touristPhone} with the payment link and booking terms\n` +
|
|
281
|
-
` Use the message tool with accountId: "${accountId}"\n` +
|
|
284
|
+
` Use the message tool with channel: "whatsapp", accountId: "${accountId}"\n` +
|
|
282
285
|
`3. Record the booking details in shared/bookings/${jobId}.md via memory_write\n` +
|
|
283
286
|
`4. Clear the active negotiation files for drivers NOT selected (delete their shared/active-negotiations/{phone}.md)\n`);
|
|
284
287
|
}
|
|
@@ -293,9 +296,9 @@ function buildPaymentConfirmedInstruction(params) {
|
|
|
293
296
|
`1. Read the booking record at shared/bookings/${bookingId}.md for driver details\n` +
|
|
294
297
|
`2. Generate the pickup PIN and QR code (see references/pin-qr.md)\n` +
|
|
295
298
|
`3. Message the tourist at ${touristPhone} with: driver name, phone, vehicle details, plate, and pickup PIN\n` +
|
|
296
|
-
` Use the message tool with accountId: "${accountId}"\n` +
|
|
299
|
+
` Use the message tool with channel: "whatsapp", accountId: "${accountId}"\n` +
|
|
297
300
|
`4. Message the driver with: passenger name, pickup time/location, fare, and QR code URL\n` +
|
|
298
|
-
` Use the message tool with accountId: "${accountId}"\n` +
|
|
301
|
+
` Use the message tool with channel: "whatsapp", accountId: "${accountId}"\n` +
|
|
299
302
|
`5. Update the booking record status to "confirmed"\n` +
|
|
300
303
|
`6. Clear the active negotiation file for the driver (shared/active-negotiations/{phone}.md)\n`);
|
|
301
304
|
}
|
|
@@ -337,6 +340,10 @@ async function handleMemoryAdd(event) {
|
|
|
337
340
|
return;
|
|
338
341
|
}
|
|
339
342
|
const fields = parseDispatchFile(content);
|
|
343
|
+
// Normalize: public agents may write tourist_id instead of tourist_phone
|
|
344
|
+
if (!fields.tourist_phone && fields.tourist_id) {
|
|
345
|
+
fields.tourist_phone = fields.tourist_id;
|
|
346
|
+
}
|
|
340
347
|
// Load config (memory:add events don't carry cfg)
|
|
341
348
|
let cfg;
|
|
342
349
|
try {
|
|
@@ -427,8 +434,15 @@ async function handleDriverReply(event) {
|
|
|
427
434
|
`Driver phone: ${senderPhone}\n` +
|
|
428
435
|
`Message: ${text}\n\n` +
|
|
429
436
|
`Process this reply in the context of the ongoing negotiation for ${jobId}.\n` +
|
|
430
|
-
`If this is a fare quote
|
|
431
|
-
`
|
|
437
|
+
`If this is a fare quote:\n` +
|
|
438
|
+
` - Record the quote in the driver's memory profile\n` +
|
|
439
|
+
` - When all expected quotes are in (or after a reasonable wait), compile the offers\n` +
|
|
440
|
+
` - Message the tourist directly using the message tool with the compiled offers\n` +
|
|
441
|
+
` The tourist phone is in the earlier trip-request message in this session\n` +
|
|
442
|
+
` Use the message tool with channel: "whatsapp", accountId: "${accountId}"\n` +
|
|
443
|
+
` Do NOT write a dispatch file — use the message tool to send the offers directly\n` +
|
|
444
|
+
` Cross-agent echo will relay it to the tourist's active session automatically\n` +
|
|
445
|
+
`If the driver is declining, update their status in memory and delete their shared/active-negotiations/{phone-digits}.md file.\n`;
|
|
432
446
|
console.log(`[ride-dispatch] Driver reply from ${senderPhone} for ${jobId}, dispatching to admin agent "${adminAgentId}"`);
|
|
433
447
|
// Fire and forget — suppress is already set, caller will skip processForRoute
|
|
434
448
|
dispatchToAdmin({
|
package/package.json
CHANGED
|
@@ -77,9 +77,12 @@ When you receive `[System: Ride Dispatch — Trip Request]`:
|
|
|
77
77
|
- Update their status to `awaiting_response` via `memory_write`
|
|
78
78
|
- Write `shared/active-negotiations/{driver-phone-digits}.md` with `job_id`, `driver_name`, and `contacted_at`
|
|
79
79
|
5. Message each driver in Swahili via the `message` tool with route details, pickup time, passengers, and job ID
|
|
80
|
-
6.
|
|
81
|
-
7.
|
|
82
|
-
|
|
80
|
+
6. When driver replies arrive (dispatched as `[System: Ride Dispatch — Driver Reply]`), compile offers
|
|
81
|
+
7. Message the tourist at `tourist_phone` using the `message` tool with `accountId` from this dispatch
|
|
82
|
+
- Include up to 3 offers: fare, vehicle type, driver rating, estimated journey time
|
|
83
|
+
- Do NOT reveal driver name, phone, or plate — those are gated by payment
|
|
84
|
+
- Cross-agent echo will relay the WhatsApp message to the tourist's active session automatically
|
|
85
|
+
- Do NOT write a dispatch file for the offers — message directly
|
|
83
86
|
|
|
84
87
|
### Booking Confirmation
|
|
85
88
|
|
|
@@ -87,18 +90,21 @@ When you receive `[System: Ride Dispatch — Booking Confirmation]`:
|
|
|
87
90
|
|
|
88
91
|
1. Load the `stripe` skill and generate a Checkout Session for the booking fee
|
|
89
92
|
- Set metadata: `booking_id`, `tourist_phone`, `account_id` (for webhook routing)
|
|
90
|
-
2. Message the tourist with the payment link and booking terms
|
|
93
|
+
2. Message the tourist at `tourist_phone` using the `message` tool with the payment link and booking terms
|
|
94
|
+
- Cross-agent echo relays the message to the tourist's active session automatically
|
|
91
95
|
3. Record booking details in `shared/bookings/{job-id}.md` via `memory_write`
|
|
96
|
+
- Include `tourist_phone` for post-payment messaging
|
|
92
97
|
4. Clear `shared/active-negotiations/{phone}.md` for drivers NOT selected
|
|
93
98
|
|
|
94
99
|
### Payment Confirmed
|
|
95
100
|
|
|
96
101
|
When you receive `[System: Ride Dispatch — Payment Confirmed]`:
|
|
97
102
|
|
|
98
|
-
1. Read the booking record at `shared/bookings/{job-id}.md` for driver details
|
|
103
|
+
1. Read the booking record at `shared/bookings/{job-id}.md` for driver details and `tourist_session_key`
|
|
99
104
|
2. Generate the pickup PIN and QR code (see `references/pin-qr.md`)
|
|
100
|
-
3. Message the tourist
|
|
101
|
-
|
|
105
|
+
3. Message the tourist at `tourist_phone` (from the booking record) using the `message` tool with driver details and pickup PIN
|
|
106
|
+
- Cross-agent echo relays to the tourist's active session automatically
|
|
107
|
+
4. Message the driver with passenger name, pickup time/location, fare, and QR code URL
|
|
102
108
|
5. Update the booking record status to `confirmed`
|
|
103
109
|
6. Clear the active negotiation file for the confirmed driver
|
|
104
110
|
|
|
@@ -106,7 +112,9 @@ When you receive `[System: Ride Dispatch — Payment Confirmed]`:
|
|
|
106
112
|
|
|
107
113
|
When you receive `[System: Ride Dispatch — Driver Reply]`:
|
|
108
114
|
|
|
109
|
-
|
|
115
|
+
1. If the driver is quoting a fare: record it in their memory profile (`memory_write` on `drivers/{name}.md`)
|
|
116
|
+
2. When all expected quotes are received (or after a reasonable wait): compile the offers and message the tourist directly using the `message` tool at the `tourist_phone` from the trip-request earlier in this session — do NOT write a dispatch file
|
|
117
|
+
3. If the driver is declining: update their status in memory to `idle` and delete their `shared/active-negotiations/{phone-digits}.md` file
|
|
110
118
|
|
|
111
119
|
### Active Negotiation Index
|
|
112
120
|
|
|
@@ -23,6 +23,7 @@ Before responding:
|
|
|
23
23
|
- Proactively look up contact details for people mentioned in system messages
|
|
24
24
|
|
|
25
25
|
If a user asks for information about another person, politely decline — it would violate strict security protocols.
|
|
26
|
+
**Declined conversations stay declined.** When you've correctly identified a message as misdirected or outside your scope and responded accordingly, that conversation is concluded. If the same sender follows up with requests of any kind, decline and end the conversation. Performing services for someone you've already turned away contradicts your own assessment and opens the service to general-purpose misuse.
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -54,6 +55,10 @@ The knowledge base is the single source of truth. If it doesn't cover what's bei
|
|
|
54
55
|
|
|
55
56
|
This is a **prescribed workflow**. When a tourist requests a ride, execute every step in order. Do not stop, skip, or defer any step. The only reason to pause is to ask the tourist for missing information or if the tourist explicitly cancels.
|
|
56
57
|
|
|
58
|
+
### Step 0 — Confirm identification
|
|
59
|
+
|
|
60
|
+
All users are verified before they reach you — WhatsApp users by their phone number, webchat users by OTP verification. The tourist's phone number is their session identifier. Use it as `tourist_phone` in dispatch files.
|
|
61
|
+
|
|
57
62
|
### Step 1 — Capture the request
|
|
58
63
|
|
|
59
64
|
Gather: pickup location, destination, date/time, number of passengers, luggage, special requests. If the tourist gave everything in one message, proceed immediately. If anything is missing, ask — then resume from Step 2 when they reply.
|
|
@@ -74,7 +79,7 @@ Write a dispatch file via `memory_write` to `shared/dispatch/{job-id}-trip-reque
|
|
|
74
79
|
# Dispatch: Trip Request
|
|
75
80
|
job_id: BGL-XXXX
|
|
76
81
|
phase: trip-request
|
|
77
|
-
tourist_phone:
|
|
82
|
+
tourist_phone: [the tourist's phone number — from WhatsApp session or OTP-verified phone]
|
|
78
83
|
tourist_name: [name if given]
|
|
79
84
|
pickup: [pickup location]
|
|
80
85
|
destination: [destination]
|
|
@@ -93,7 +98,7 @@ After writing the dispatch file, tell the tourist: "I'm reaching out to our driv
|
|
|
93
98
|
|
|
94
99
|
### Step 6 — Present offers
|
|
95
100
|
|
|
96
|
-
When driver offers appear in your conversation
|
|
101
|
+
When driver offers appear in your conversation as a `[System: Ride Dispatch — Driver Offers]` message, present up to 3 competing offers to the tourist: fare, driver rating, vehicle type, estimated journey time. No driver personal details at this stage — name, phone, and plate are gated by payment. See `references/ride-matching.md` for formatting.
|
|
97
102
|
|
|
98
103
|
### Step 7 — Confirm booking
|
|
99
104
|
|
|
@@ -103,7 +108,7 @@ When the tourist chooses an offer, confirm the details and write a booking confi
|
|
|
103
108
|
# Dispatch: Booking Confirmation
|
|
104
109
|
job_id: BGL-XXXX
|
|
105
110
|
phase: booking-confirm
|
|
106
|
-
tourist_phone:
|
|
111
|
+
tourist_phone: [same phone used in trip-request]
|
|
107
112
|
tourist_name: [name]
|
|
108
113
|
driver_name: [selected driver name from offer]
|
|
109
114
|
driver_phone: [selected driver phone from offer]
|
|
@@ -113,11 +118,11 @@ account_id: [your account ID]
|
|
|
113
118
|
|
|
114
119
|
### Step 8 — Payment
|
|
115
120
|
|
|
116
|
-
The operations agent will generate a Stripe payment link and
|
|
121
|
+
The operations agent will generate a Stripe payment link and relay it to your conversation as a `[System: Ride Dispatch — Payment Link]` message. Present the payment link and terms to the tourist. If the tourist has questions about payment, explain the booking fee. Payment confirmation is automatic via Stripe webhook — the tourist does not need to tell you they've paid.
|
|
117
122
|
|
|
118
123
|
### Step 9 — Post-payment
|
|
119
124
|
|
|
120
|
-
Once payment is confirmed
|
|
125
|
+
Once payment is confirmed, the operations agent will relay driver details and the pickup PIN to your conversation as a `[System: Ride Dispatch — Booking Complete]` message. Present the driver details to the tourist and explain the PIN verification process: "Your driver has a QR code. You have the PIN. Scan the QR or ask the driver to quote your PIN — works without internet."
|
|
121
126
|
|
|
122
127
|
### Step 10 — Record and follow up
|
|
123
128
|
|