@rubytech/taskmaster 1.14.2 → 1.16.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/agents/apply-patch.js +3 -1
- package/dist/agents/bash-tools.exec.js +3 -1
- package/dist/agents/bash-tools.process.js +3 -1
- package/dist/agents/skills/frontmatter.js +1 -0
- package/dist/agents/skills/workspace.js +64 -22
- package/dist/agents/system-prompt.js +1 -1
- package/dist/agents/taskmaster-tools.js +6 -4
- package/dist/agents/tool-policy.js +2 -1
- package/dist/agents/tools/contact-create-tool.js +4 -3
- package/dist/agents/tools/contact-delete-tool.js +3 -2
- package/dist/agents/tools/contact-lookup-tool.js +5 -4
- package/dist/agents/tools/contact-update-tool.js +6 -3
- package/dist/agents/tools/memory-tool.js +3 -1
- package/dist/agents/tools/qr-generate-tool.js +45 -0
- package/dist/agents/workspace-migrations.js +351 -0
- package/dist/build-info.json +3 -3
- package/dist/config/agent-tools-reconcile.js +47 -0
- package/dist/control-ui/assets/{index-B3nkSwMP.js → index-Bd75cI7J.js} +547 -573
- package/dist/control-ui/assets/index-Bd75cI7J.js.map +1 -0
- package/dist/control-ui/assets/index-BkymP95Y.css +1 -0
- package/dist/control-ui/index.html +2 -2
- package/dist/gateway/server-http.js +5 -0
- package/dist/gateway/server-methods/web.js +13 -0
- package/dist/gateway/server.impl.js +15 -1
- package/dist/hooks/bundled/ride-dispatch/HOOK.md +57 -0
- package/dist/hooks/bundled/ride-dispatch/handler.js +450 -0
- package/dist/hooks/bundled/ride-dispatch/stripe-webhook.js +191 -0
- package/dist/memory/internal.js +24 -1
- package/dist/memory/manager.js +3 -3
- package/dist/records/records-manager.js +7 -2
- package/package.json +1 -1
- package/skills/business-assistant/SKILL.md +1 -1
- package/skills/qr-code/SKILL.md +63 -0
- package/skills/sales-closer/SKILL.md +1 -1
- package/templates/beagle-zanzibar/agents/admin/AGENTS.md +67 -1
- package/templates/beagle-zanzibar/agents/public/AGENTS.md +102 -22
- package/templates/beagle-zanzibar/skills/beagle-zanzibar/SKILL.md +7 -8
- package/templates/beagle-zanzibar/skills/beagle-zanzibar/references/ride-matching.md +46 -55
- package/templates/customer/agents/admin/BOOTSTRAP.md +5 -1
- package/templates/customer/agents/public/AGENTS.md +1 -2
- package/templates/real-agent/skills/buyer-feedback/SKILL.md +111 -0
- package/templates/real-agent/skills/property-enquiry/SKILL.md +126 -0
- package/templates/real-agent/skills/valuation-booking/SKILL.md +182 -0
- package/templates/real-agent/skills/vendor-updates/SKILL.md +153 -0
- package/templates/real-agent/skills/viewing-management/SKILL.md +111 -0
- package/templates/taskmaster/agents/public/AGENTS.md +1 -1
- package/templates/taskmaster/agents/public/IDENTITY.md +1 -1
- package/templates/taskmaster/agents/public/SOUL.md +2 -2
- package/dist/control-ui/assets/index-B3nkSwMP.js.map +0 -1
- package/dist/control-ui/assets/index-l54GcTyj.css +0 -1
|
@@ -285,6 +285,352 @@ async function patchBeagleSkillRename(agentsPath, content) {
|
|
|
285
285
|
return null;
|
|
286
286
|
return content.replaceAll("zanzi-taxi", "beagle-zanzibar");
|
|
287
287
|
}
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
// Migration: Beagle Zanzibar — prescribed ride request workflow (v1.14)
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
//
|
|
292
|
+
// The old "## Ride Request Flow" was a brief summary that left the agent
|
|
293
|
+
// guessing at tool calls. Replaced with a 12-step prescribed workflow with
|
|
294
|
+
// explicit tool invocations at each stage.
|
|
295
|
+
const OLD_RIDE_FLOW_HEADER = "## Ride Request Flow";
|
|
296
|
+
const NEW_RIDE_WORKFLOW_HEADER = "## Ride Request Workflow";
|
|
297
|
+
const BEAGLE_RIDE_WORKFLOW = `## Ride Request Workflow
|
|
298
|
+
|
|
299
|
+
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.
|
|
300
|
+
|
|
301
|
+
### Step 1 — Capture the request
|
|
302
|
+
|
|
303
|
+
Gather: pickup location, destination, date/time, number of passengers. If the tourist gave everything in one message, proceed immediately. If anything is missing, ask — then resume from Step 2 when they reply.
|
|
304
|
+
|
|
305
|
+
### Step 2 — Check knowledge base
|
|
306
|
+
|
|
307
|
+
Call \`memory_search\` for the route. Note the fare range and journey time if found. If the route is not covered, note that — but proceed to Step 3 regardless. Never stop here.
|
|
308
|
+
|
|
309
|
+
### Step 3 — Get the driver roster
|
|
310
|
+
|
|
311
|
+
Call \`contact_lookup\` with \`driver: true\`. This returns all registered drivers.
|
|
312
|
+
|
|
313
|
+
### Step 4 — Check driver availability
|
|
314
|
+
|
|
315
|
+
For each driver returned in Step 3, call \`memory_get\` on \`memory/drivers/{name}.md\` to read their current \`status\`. Collect a list of drivers whose status is \`idle\`. Skip any driver whose status is \`awaiting_response\` or \`engaged\`.
|
|
316
|
+
|
|
317
|
+
### Step 5 — Contact drivers
|
|
318
|
+
|
|
319
|
+
For up to 3 idle drivers from Step 4, call \`message\` to send each a negotiation request in Swahili. Include: the route, pickup time, number of passengers, and the job ID (\`[BGL-XXXX]\`). Before each send, call \`memory_write\` to set that driver's status to \`awaiting_response\`.
|
|
320
|
+
|
|
321
|
+
If no idle drivers are available, tell the tourist honestly and offer to try again later. This is the only permitted early exit other than tourist cancellation.
|
|
322
|
+
|
|
323
|
+
### Step 6 — Notify the tourist
|
|
324
|
+
|
|
325
|
+
After sending all driver messages, respond to the tourist: confirm you've contacted drivers and are waiting for quotes. Do not send this message before completing Steps 3–5.
|
|
326
|
+
|
|
327
|
+
### Step 7 — Present offers
|
|
328
|
+
|
|
329
|
+
When drivers respond with quotes, present up to 3 competing offers: fare, driver rating, vehicle type, estimated journey time. No driver personal details at this stage. See \`references/ride-matching.md\` for formatting.
|
|
330
|
+
|
|
331
|
+
### Step 8 — Confirm booking
|
|
332
|
+
|
|
333
|
+
When the tourist chooses an offer, confirm the details and generate a Stripe payment link for the booking fee. See \`references/ride-matching.md\` Phase 4.
|
|
334
|
+
|
|
335
|
+
### Step 9 — Post-payment
|
|
336
|
+
|
|
337
|
+
Once payment clears, send the tourist: driver name, phone number, vehicle details, plate number, and the pickup PIN. Send the driver: passenger details, pickup location, fare, and QR code. See \`references/pin-qr.md\`.
|
|
338
|
+
|
|
339
|
+
### Step 10 — Record the booking
|
|
340
|
+
|
|
341
|
+
Call \`memory_write\` to create a structured record at \`memory/bookings/{job-id}.md\`. Update at each lifecycle event. See \`references/ride-matching.md\` Phase 7.
|
|
342
|
+
|
|
343
|
+
### Step 11 — Driver reminders
|
|
344
|
+
|
|
345
|
+
For advance bookings, send tiered reminders via \`message\` (evening-before, 2-hour, 30-minute). Escalate immediately if a driver doesn't confirm. See \`references/ride-matching.md\` Phase 6.
|
|
346
|
+
|
|
347
|
+
### Step 12 — Follow up
|
|
348
|
+
|
|
349
|
+
After estimated journey completion, prompt the tourist for feedback and collect ratings. See \`references/post-ride.md\`.`;
|
|
350
|
+
async function patchBeagleRideWorkflow(_agentsPath, content) {
|
|
351
|
+
if (!isBeaglePublicAgent(content))
|
|
352
|
+
return null;
|
|
353
|
+
// Already migrated?
|
|
354
|
+
if (content.includes(NEW_RIDE_WORKFLOW_HEADER))
|
|
355
|
+
return null;
|
|
356
|
+
// Old section not present?
|
|
357
|
+
if (!content.includes(OLD_RIDE_FLOW_HEADER))
|
|
358
|
+
return null;
|
|
359
|
+
// Find the old section boundaries: from "## Ride Request Flow" to the next "---"
|
|
360
|
+
const startIdx = content.indexOf(OLD_RIDE_FLOW_HEADER);
|
|
361
|
+
const separatorIdx = content.indexOf("\n---", startIdx + OLD_RIDE_FLOW_HEADER.length);
|
|
362
|
+
if (separatorIdx === -1)
|
|
363
|
+
return null;
|
|
364
|
+
return content.slice(0, startIdx) + BEAGLE_RIDE_WORKFLOW + content.slice(separatorIdx);
|
|
365
|
+
}
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
// Migration: Narrow escalation clause (v1.14)
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
//
|
|
370
|
+
// "Anything you're uncertain about" in escalation sections gives public agents
|
|
371
|
+
// a blanket excuse to defer any uncomfortable moment (including closing a sale).
|
|
372
|
+
// Replaced with a specific, bounded criterion.
|
|
373
|
+
const BLANKET_ESCALATION = "Anything you're uncertain about";
|
|
374
|
+
const NARROW_ESCALATION = "Technical questions you cannot answer from memory or product knowledge";
|
|
375
|
+
function hasBlanketEscalation(content) {
|
|
376
|
+
return content.toLowerCase().includes(BLANKET_ESCALATION.toLowerCase());
|
|
377
|
+
}
|
|
378
|
+
async function patchEscalationClause(_agentsPath, content) {
|
|
379
|
+
if (!isPublicAgent(content))
|
|
380
|
+
return null;
|
|
381
|
+
if (!hasBlanketEscalation(content))
|
|
382
|
+
return null;
|
|
383
|
+
// Replace all case-insensitive occurrences of the blanket clause
|
|
384
|
+
return content.replace(new RegExp(BLANKET_ESCALATION.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi"), NARROW_ESCALATION);
|
|
385
|
+
}
|
|
386
|
+
// ---------------------------------------------------------------------------
|
|
387
|
+
// Migration: Beagle Zanzibar — Dispatch-based workflow (v1.15)
|
|
388
|
+
// ---------------------------------------------------------------------------
|
|
389
|
+
//
|
|
390
|
+
// Replaces the 12-step workflow that used `contact_lookup` and `message`
|
|
391
|
+
// directly with a 10-step dispatch-based workflow. The public agent now
|
|
392
|
+
// writes dispatch files; the admin agent handles privileged operations.
|
|
393
|
+
const DISPATCH_WORKFLOW_MARKER = "shared/dispatch/";
|
|
394
|
+
const BEAGLE_DISPATCH_WORKFLOW = `## Ride Request Workflow
|
|
395
|
+
|
|
396
|
+
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.
|
|
397
|
+
|
|
398
|
+
### Step 1 — Capture the request
|
|
399
|
+
|
|
400
|
+
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.
|
|
401
|
+
|
|
402
|
+
### Step 2 — Check knowledge base
|
|
403
|
+
|
|
404
|
+
Call \`memory_search\` for the route. Note the fare range and journey time if found. If the route is not covered, note that — but proceed to Step 3 regardless. Never stop here.
|
|
405
|
+
|
|
406
|
+
### Step 3 — Generate job ID
|
|
407
|
+
|
|
408
|
+
Create a booking job ID in the format \`BGL-XXXX\` (e.g. \`BGL-0042\`). Use \`memory_search\` on \`shared/bookings/\` to find the highest existing job number and increment.
|
|
409
|
+
|
|
410
|
+
### Step 4 — Dispatch trip request
|
|
411
|
+
|
|
412
|
+
Write a dispatch file via \`memory_write\` to \`shared/dispatch/{job-id}-trip-request.md\` with the following format:
|
|
413
|
+
|
|
414
|
+
\\\`\\\`\\\`
|
|
415
|
+
# Dispatch: Trip Request
|
|
416
|
+
job_id: BGL-XXXX
|
|
417
|
+
phase: trip-request
|
|
418
|
+
tourist_phone: +XXXXXXXXXXX
|
|
419
|
+
tourist_name: [name if given]
|
|
420
|
+
pickup: [pickup location]
|
|
421
|
+
destination: [destination]
|
|
422
|
+
date: [date]
|
|
423
|
+
time: [time]
|
|
424
|
+
passengers: [count]
|
|
425
|
+
luggage: [description]
|
|
426
|
+
special_requests: [any requests or "none"]
|
|
427
|
+
fare_estimate: [range from knowledge base or "unknown"]
|
|
428
|
+
account_id: [your account ID]
|
|
429
|
+
\\\`\\\`\\\`
|
|
430
|
+
|
|
431
|
+
### Step 5 — Notify the tourist
|
|
432
|
+
|
|
433
|
+
After writing the dispatch file, tell the tourist: "I'm reaching out to our drivers now. I'll have quotes for you shortly." Do not send this before writing the dispatch file.
|
|
434
|
+
|
|
435
|
+
### Step 6 — Present offers
|
|
436
|
+
|
|
437
|
+
When driver offers appear in your conversation (injected by the operations agent), 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.
|
|
438
|
+
|
|
439
|
+
### Step 7 — Confirm booking
|
|
440
|
+
|
|
441
|
+
When the tourist chooses an offer, confirm the details and write a booking confirmation dispatch via \`memory_write\` to \`shared/dispatch/{job-id}-booking-confirm.md\`.
|
|
442
|
+
|
|
443
|
+
### Step 8 — Payment
|
|
444
|
+
|
|
445
|
+
The operations agent will generate a Stripe payment link and send it directly to the tourist. Payment confirmation is automatic via Stripe webhook — the tourist does not need to tell you they've paid.
|
|
446
|
+
|
|
447
|
+
### Step 9 — Post-payment
|
|
448
|
+
|
|
449
|
+
Once payment is confirmed (the operations agent will inject driver details and pickup PIN into the conversation), acknowledge the details to the tourist. Explain the PIN verification process.
|
|
450
|
+
|
|
451
|
+
### Step 10 — Record and follow up
|
|
452
|
+
|
|
453
|
+
After estimated journey completion, prompt the tourist for feedback and collect ratings. See \`references/post-ride.md\`.`;
|
|
454
|
+
async function patchBeaglePublicDispatchWorkflow(_agentsPath, content) {
|
|
455
|
+
if (!isBeaglePublicAgent(content))
|
|
456
|
+
return null;
|
|
457
|
+
// Already migrated to dispatch model?
|
|
458
|
+
if (content.includes(DISPATCH_WORKFLOW_MARKER))
|
|
459
|
+
return null;
|
|
460
|
+
// Must have the old workflow to replace
|
|
461
|
+
if (!content.includes(NEW_RIDE_WORKFLOW_HEADER))
|
|
462
|
+
return null;
|
|
463
|
+
// Find the workflow section boundaries
|
|
464
|
+
const startIdx = content.indexOf(NEW_RIDE_WORKFLOW_HEADER);
|
|
465
|
+
if (startIdx === -1)
|
|
466
|
+
return null;
|
|
467
|
+
// Find the end: next "---" separator or "## " heading at same level
|
|
468
|
+
const afterHeader = startIdx + NEW_RIDE_WORKFLOW_HEADER.length;
|
|
469
|
+
const nextSeparator = content.indexOf("\n---", afterHeader);
|
|
470
|
+
const nextH2 = content.indexOf("\n## ", afterHeader);
|
|
471
|
+
let endIdx;
|
|
472
|
+
if (nextSeparator !== -1 && (nextH2 === -1 || nextSeparator < nextH2)) {
|
|
473
|
+
endIdx = nextSeparator;
|
|
474
|
+
}
|
|
475
|
+
else if (nextH2 !== -1) {
|
|
476
|
+
endIdx = nextH2;
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
endIdx = content.length;
|
|
480
|
+
}
|
|
481
|
+
return content.slice(0, startIdx) + BEAGLE_DISPATCH_WORKFLOW + content.slice(endIdx);
|
|
482
|
+
}
|
|
483
|
+
// ---------------------------------------------------------------------------
|
|
484
|
+
// Migration: Beagle Zanzibar — Public agent tools dispatch (v1.15)
|
|
485
|
+
// ---------------------------------------------------------------------------
|
|
486
|
+
//
|
|
487
|
+
// Replaces the public agent's tools table to remove `contact_lookup` and
|
|
488
|
+
// `message`. These are now handled by the admin agent via dispatch.
|
|
489
|
+
const DISPATCH_TOOLS_MARKER = "dispatch requests";
|
|
490
|
+
const BEAGLE_DISPATCH_TOOLS_SECTION = `## Tools
|
|
491
|
+
|
|
492
|
+
| Tool | Use |
|
|
493
|
+
|------|-----|
|
|
494
|
+
| \`memory_search\` | Find bookings, knowledge base content |
|
|
495
|
+
| \`memory_get\` | Read specific files (bookings, knowledge base) |
|
|
496
|
+
| \`memory_write\` | Write dispatch requests, update booking state, store tourist preferences |
|
|
497
|
+
| \`memory_save_media\` | Save media files sent by tourists |
|
|
498
|
+
| \`web_search\` | Search the web for tourist queries |
|
|
499
|
+
| \`web_fetch\` | Fetch web content |
|
|
500
|
+
| \`current_time\` | Timestamps for booking records |
|
|
501
|
+
|
|
502
|
+
You do not have \`message\` or \`contact_lookup\` tools. Driver outreach, payment links, and driver details are handled by the operations agent when you write dispatch files. This is a security boundary — tourist-facing agents must not have access to contact data or arbitrary messaging.`;
|
|
503
|
+
async function patchBeaglePublicToolsDispatch(_agentsPath, content) {
|
|
504
|
+
if (!isBeaglePublicAgent(content))
|
|
505
|
+
return null;
|
|
506
|
+
// Already migrated?
|
|
507
|
+
if (content.includes(DISPATCH_TOOLS_MARKER))
|
|
508
|
+
return null;
|
|
509
|
+
// Must have a ## Tools section to replace
|
|
510
|
+
if (!content.includes("## Tools"))
|
|
511
|
+
return null;
|
|
512
|
+
// Find the tools section
|
|
513
|
+
const toolsStart = content.indexOf("## Tools");
|
|
514
|
+
if (toolsStart === -1)
|
|
515
|
+
return null;
|
|
516
|
+
// Find end of tools section: next "---" or next "## " heading
|
|
517
|
+
const afterTools = toolsStart + "## Tools".length;
|
|
518
|
+
const nextSeparator = content.indexOf("\n---", afterTools);
|
|
519
|
+
const nextH2 = content.indexOf("\n## ", afterTools);
|
|
520
|
+
let endIdx;
|
|
521
|
+
if (nextSeparator !== -1 && (nextH2 === -1 || nextSeparator < nextH2)) {
|
|
522
|
+
endIdx = nextSeparator;
|
|
523
|
+
}
|
|
524
|
+
else if (nextH2 !== -1) {
|
|
525
|
+
endIdx = nextH2;
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
endIdx = content.length;
|
|
529
|
+
}
|
|
530
|
+
return content.slice(0, toolsStart) + BEAGLE_DISPATCH_TOOLS_SECTION + content.slice(endIdx);
|
|
531
|
+
}
|
|
532
|
+
// ---------------------------------------------------------------------------
|
|
533
|
+
// Migration: Beagle Zanzibar — Admin dispatch instructions (v1.15)
|
|
534
|
+
// ---------------------------------------------------------------------------
|
|
535
|
+
//
|
|
536
|
+
// Adds the "Ride Dispatch Processing" section to the admin agent and
|
|
537
|
+
// the `message` tool to its tools table.
|
|
538
|
+
const ADMIN_DISPATCH_MARKER = "## Ride Dispatch Processing";
|
|
539
|
+
const BEAGLE_ADMIN_DISPATCH_SECTION = `## Ride Dispatch Processing
|
|
540
|
+
|
|
541
|
+
Messages prefixed with \`[System: Ride Dispatch — ...]\` are automated dispatches from the ride-dispatch hook. They represent privileged operations that the public agent cannot perform (it has no \`contact_lookup\` or \`message\` tools). Process each dispatch type as instructed.
|
|
542
|
+
|
|
543
|
+
### Trip Request
|
|
544
|
+
|
|
545
|
+
When you receive \`[System: Ride Dispatch — Trip Request]\`:
|
|
546
|
+
|
|
547
|
+
1. Call \`contact_lookup\` to get the driver roster
|
|
548
|
+
2. For each driver, call \`memory_get\` on \`drivers/{name}.md\` to check their status
|
|
549
|
+
3. Select up to 3 idle drivers, preferring those with route history for the requested route
|
|
550
|
+
4. For each selected driver:
|
|
551
|
+
- Update their status to \`awaiting_response\` via \`memory_write\`
|
|
552
|
+
- Write \`shared/active-negotiations/{driver-phone-digits}.md\` with \`job_id\`, \`driver_name\`, and \`contacted_at\`
|
|
553
|
+
5. Message each driver in Swahili via the \`message\` tool with route details, pickup time, passengers, and job ID
|
|
554
|
+
6. Message the tourist confirming drivers have been contacted and quotes are being gathered
|
|
555
|
+
7. When driver replies arrive (dispatched as \`[System: Ride Dispatch — Driver Reply]\`), compile offers
|
|
556
|
+
8. Message the tourist with up to 3 competing offers — fare, rating, vehicle type, journey time. Do NOT reveal driver name, phone, or plate (gated by payment)
|
|
557
|
+
|
|
558
|
+
### Booking Confirmation
|
|
559
|
+
|
|
560
|
+
When you receive \`[System: Ride Dispatch — Booking Confirmation]\`:
|
|
561
|
+
|
|
562
|
+
1. Load the \`stripe\` skill and generate a Checkout Session for the booking fee
|
|
563
|
+
- Set metadata: \`booking_id\`, \`tourist_phone\`, \`account_id\` (for webhook routing)
|
|
564
|
+
2. Message the tourist with the payment link and booking terms
|
|
565
|
+
3. Record booking details in \`shared/bookings/{job-id}.md\` via \`memory_write\`
|
|
566
|
+
4. Clear \`shared/active-negotiations/{phone}.md\` for drivers NOT selected
|
|
567
|
+
|
|
568
|
+
### Payment Confirmed
|
|
569
|
+
|
|
570
|
+
When you receive \`[System: Ride Dispatch — Payment Confirmed]\`:
|
|
571
|
+
|
|
572
|
+
1. Read the booking record at \`shared/bookings/{job-id}.md\` for driver details
|
|
573
|
+
2. Generate the pickup PIN and QR code (see \`references/pin-qr.md\`)
|
|
574
|
+
3. Message the tourist with: driver name, phone, vehicle details, plate, and pickup PIN
|
|
575
|
+
4. Message the driver with: passenger name, pickup time/location, fare, and QR code URL
|
|
576
|
+
5. Update the booking record status to \`confirmed\`
|
|
577
|
+
6. Clear the active negotiation file for the confirmed driver
|
|
578
|
+
|
|
579
|
+
### Driver Reply
|
|
580
|
+
|
|
581
|
+
When you receive \`[System: Ride Dispatch — Driver Reply]\`:
|
|
582
|
+
|
|
583
|
+
Process the driver's message in the context of the ongoing negotiation. If it's a fare quote, note it. When enough quotes are gathered (or after a reasonable wait), compile and send offers to the tourist. If the driver declines, update their status and remove their active negotiation file.
|
|
584
|
+
|
|
585
|
+
### Active Negotiation Index
|
|
586
|
+
|
|
587
|
+
When contacting drivers, write \`shared/active-negotiations/{phone-digits}.md\` for each:
|
|
588
|
+
|
|
589
|
+
\\\`\\\`\\\`
|
|
590
|
+
job_id: BGL-XXXX
|
|
591
|
+
driver_name: [name]
|
|
592
|
+
contacted_at: [timestamp]
|
|
593
|
+
\\\`\\\`\\\`
|
|
594
|
+
|
|
595
|
+
Clear these files when:
|
|
596
|
+
- A driver declines or is not selected
|
|
597
|
+
- The booking is confirmed (keep only the selected driver's file until pickup completes)
|
|
598
|
+
- A negotiation expires with no response
|
|
599
|
+
|
|
600
|
+
This index enables the hook to route driver WhatsApp replies to the correct ride session without requiring drivers to include job IDs in their messages.`;
|
|
601
|
+
const ADMIN_MESSAGE_TOOL_ROW = `| \`message\` | Send WhatsApp messages to drivers and tourists (ride dispatch, reminders, payment links) |`;
|
|
602
|
+
async function patchBeagleAdminDispatchInstructions(_agentsPath, content) {
|
|
603
|
+
if (!isBeagleTaxiAdmin(content))
|
|
604
|
+
return null;
|
|
605
|
+
// Already migrated?
|
|
606
|
+
if (content.includes(ADMIN_DISPATCH_MARKER))
|
|
607
|
+
return null;
|
|
608
|
+
let result = content;
|
|
609
|
+
// Add `message` tool if not present
|
|
610
|
+
if (!result.includes("`message`")) {
|
|
611
|
+
const sessionsListRow = "| `sessions_list`";
|
|
612
|
+
const idx = result.indexOf(sessionsListRow);
|
|
613
|
+
if (idx !== -1) {
|
|
614
|
+
result = result.slice(0, idx) + ADMIN_MESSAGE_TOOL_ROW + "\n" + result.slice(idx);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
// Insert dispatch section before "## Operational Focus Areas"
|
|
618
|
+
const insertBefore = "## Operational Focus Areas";
|
|
619
|
+
const idx = result.indexOf(insertBefore);
|
|
620
|
+
if (idx !== -1) {
|
|
621
|
+
result =
|
|
622
|
+
result.slice(0, idx) + BEAGLE_ADMIN_DISPATCH_SECTION + "\n\n---\n\n" + result.slice(idx);
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
result = result.trimEnd() + "\n\n---\n\n" + BEAGLE_ADMIN_DISPATCH_SECTION + "\n";
|
|
626
|
+
}
|
|
627
|
+
// Update boundaries: remove "Interact with tourists directly" if present
|
|
628
|
+
const oldBoundary = "- Interact with tourists directly\n";
|
|
629
|
+
if (result.includes(oldBoundary)) {
|
|
630
|
+
result = result.replace(oldBoundary, "- Message tourists outside of ride dispatch processing (dispatch messages are sent on behalf of the system, not as conversational interaction)\n");
|
|
631
|
+
}
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
288
634
|
const MIGRATIONS = [
|
|
289
635
|
{ name: "skill-recommendations", apply: patchSkillRecommendations },
|
|
290
636
|
{ name: "owner-learning", apply: patchOwnerLearning },
|
|
@@ -294,6 +640,11 @@ const MIGRATIONS = [
|
|
|
294
640
|
{ name: "beagle-driver-substitution", apply: patchBeagleDriverSubstitution },
|
|
295
641
|
{ name: "beagle-public-tools", apply: patchBeaglePublicTools },
|
|
296
642
|
{ name: "beagle-skill-rename", apply: patchBeagleSkillRename },
|
|
643
|
+
{ name: "beagle-ride-workflow", apply: patchBeagleRideWorkflow },
|
|
644
|
+
{ name: "narrow-escalation", apply: patchEscalationClause },
|
|
645
|
+
{ name: "beagle-public-dispatch-workflow", apply: patchBeaglePublicDispatchWorkflow },
|
|
646
|
+
{ name: "beagle-public-tools-dispatch", apply: patchBeaglePublicToolsDispatch },
|
|
647
|
+
{ name: "beagle-admin-dispatch-instructions", apply: patchBeagleAdminDispatchInstructions },
|
|
297
648
|
];
|
|
298
649
|
/**
|
|
299
650
|
* Run all workspace migrations for every configured agent.
|
package/dist/build-info.json
CHANGED
|
@@ -19,6 +19,12 @@ function isAdminAgent(agent) {
|
|
|
19
19
|
const id = agent.id?.trim() ?? "";
|
|
20
20
|
return id === "admin" || id.endsWith("-admin");
|
|
21
21
|
}
|
|
22
|
+
/** Tools that must be removed from Beagle public agents (privilege separation). */
|
|
23
|
+
const BEAGLE_PUBLIC_RESTRICTED_TOOLS = ["message", "contact_lookup", "group:contacts"];
|
|
24
|
+
function isBeaglePublicAgent(agent) {
|
|
25
|
+
const id = (agent.id ?? "").trim().toLowerCase();
|
|
26
|
+
return id.includes("beagle") && id.endsWith("-public");
|
|
27
|
+
}
|
|
22
28
|
/**
|
|
23
29
|
* Ensure admin agents use `group:contacts` instead of individual contact tools.
|
|
24
30
|
*
|
|
@@ -118,3 +124,44 @@ export function reconcileStaleToolEntries(params) {
|
|
|
118
124
|
}
|
|
119
125
|
return { config, changes };
|
|
120
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Remove privileged tools (`message`, `contact_lookup`, `group:contacts`) from
|
|
129
|
+
* Beagle public agent allow lists.
|
|
130
|
+
*
|
|
131
|
+
* The public agent dispatches ride requests via memory files; the admin agent
|
|
132
|
+
* handles all privileged operations. Keeping `message` or contact tools on the
|
|
133
|
+
* public agent exposes driver PII to prompt injection.
|
|
134
|
+
*
|
|
135
|
+
* Runs unconditionally on gateway startup. Idempotent — skips agents that
|
|
136
|
+
* don't have any restricted tools.
|
|
137
|
+
*/
|
|
138
|
+
export function reconcileBeaglePublicTools(params) {
|
|
139
|
+
const config = structuredClone(params.config);
|
|
140
|
+
const changes = [];
|
|
141
|
+
const agents = config.agents?.list;
|
|
142
|
+
if (!Array.isArray(agents))
|
|
143
|
+
return { config, changes };
|
|
144
|
+
for (const agent of agents) {
|
|
145
|
+
if (!agent || !isBeaglePublicAgent(agent))
|
|
146
|
+
continue;
|
|
147
|
+
const allow = agent.tools?.allow;
|
|
148
|
+
if (!Array.isArray(allow))
|
|
149
|
+
continue;
|
|
150
|
+
for (const tool of BEAGLE_PUBLIC_RESTRICTED_TOOLS) {
|
|
151
|
+
const idx = allow.indexOf(tool);
|
|
152
|
+
if (idx !== -1) {
|
|
153
|
+
allow.splice(idx, 1);
|
|
154
|
+
changes.push(`Removed ${tool} from agent "${agent.id}" tools.allow (privilege separation).`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Also remove individual contact tools that might have been added directly
|
|
158
|
+
for (const tool of INDIVIDUAL_CONTACT_TOOLS) {
|
|
159
|
+
const idx = allow.indexOf(tool);
|
|
160
|
+
if (idx !== -1) {
|
|
161
|
+
allow.splice(idx, 1);
|
|
162
|
+
changes.push(`Removed ${tool} from agent "${agent.id}" tools.allow (privilege separation).`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { config, changes };
|
|
167
|
+
}
|