@poncho-ai/cli 0.13.0 → 0.14.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/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +23 -0
- package/dist/{chunk-CUCEDHME.js → chunk-A32BXZKP.js} +1467 -208
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{run-interactive-ink-VZBOYJYS.js → run-interactive-ink-SLWDVTDX.js} +1 -1
- package/package.json +2 -2
- package/src/api-docs.ts +674 -0
- package/src/index.ts +295 -52
- package/src/init-onboarding.ts +14 -1
- package/src/web-ui.ts +559 -155
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
resolveStateConfig,
|
|
25
25
|
type CronJobConfig,
|
|
26
26
|
type PonchoConfig,
|
|
27
|
+
type Conversation,
|
|
27
28
|
type ConversationStore,
|
|
28
29
|
type UploadStore,
|
|
29
30
|
} from "@poncho-ai/harness";
|
|
@@ -31,6 +32,7 @@ import type { AgentEvent, FileInput, Message, RunInput } from "@poncho-ai/sdk";
|
|
|
31
32
|
import { getTextContent } from "@poncho-ai/sdk";
|
|
32
33
|
import {
|
|
33
34
|
AgentBridge,
|
|
35
|
+
ResendAdapter,
|
|
34
36
|
SlackAdapter,
|
|
35
37
|
type AgentRunner,
|
|
36
38
|
type MessagingAdapter,
|
|
@@ -53,6 +55,7 @@ import {
|
|
|
53
55
|
setCookie,
|
|
54
56
|
verifyPassphrase,
|
|
55
57
|
} from "./web-ui.js";
|
|
58
|
+
import { buildOpenApiSpec, renderApiDocsHtml } from "./api-docs.js";
|
|
56
59
|
import { createInterface } from "node:readline/promises";
|
|
57
60
|
import {
|
|
58
61
|
runInitOnboarding,
|
|
@@ -374,7 +377,7 @@ cp .env.example .env
|
|
|
374
377
|
poncho dev
|
|
375
378
|
\`\`\`
|
|
376
379
|
|
|
377
|
-
Open \`http://localhost:3000\` for the web UI.
|
|
380
|
+
Open \`http://localhost:3000\` for the web UI, or \`http://localhost:3000/api/docs\` for interactive API documentation.
|
|
378
381
|
|
|
379
382
|
On your first interactive session, the agent introduces its configurable capabilities.
|
|
380
383
|
While a response is streaming, you can stop it:
|
|
@@ -496,7 +499,7 @@ Core files:
|
|
|
496
499
|
|
|
497
500
|
- \`AGENT.md\`: behavior, model selection, runtime guidance
|
|
498
501
|
- \`poncho.config.js\`: runtime config (storage, auth, telemetry, MCP, tools)
|
|
499
|
-
- \`.env\`: secrets and environment variables
|
|
502
|
+
- \`.env\`: secrets and environment variables (loaded before the harness starts, so \`process.env\` is available in skill scripts)
|
|
500
503
|
|
|
501
504
|
Example \`poncho.config.js\`:
|
|
502
505
|
|
|
@@ -522,18 +525,20 @@ export default {
|
|
|
522
525
|
auth: { type: "bearer", tokenEnv: "GITHUB_TOKEN" },
|
|
523
526
|
},
|
|
524
527
|
],
|
|
528
|
+
// Tool access: true (available), false (disabled), 'approval' (requires human approval)
|
|
525
529
|
tools: {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
read_file: true,
|
|
529
|
-
write_file: true, // still gated by environment/policy
|
|
530
|
-
},
|
|
530
|
+
write_file: true, // gated by environment for writes
|
|
531
|
+
send_email: 'approval', // requires human approval
|
|
531
532
|
byEnvironment: {
|
|
532
533
|
production: {
|
|
533
|
-
|
|
534
|
+
write_file: false,
|
|
535
|
+
},
|
|
536
|
+
development: {
|
|
537
|
+
send_email: true, // skip approval in dev
|
|
534
538
|
},
|
|
535
539
|
},
|
|
536
540
|
},
|
|
541
|
+
// webUi: false, // Disable built-in UI for API-only deployments
|
|
537
542
|
};
|
|
538
543
|
\`\`\`
|
|
539
544
|
|
|
@@ -592,6 +597,26 @@ Connect your agent to Slack so it responds to @mentions:
|
|
|
592
597
|
messaging: [{ platform: 'slack' }]
|
|
593
598
|
\`\`\`
|
|
594
599
|
|
|
600
|
+
## Messaging (Email via Resend)
|
|
601
|
+
|
|
602
|
+
Connect your agent to email so users can interact by sending emails:
|
|
603
|
+
|
|
604
|
+
1. Set up a domain and enable Inbound at [resend.com](https://resend.com)
|
|
605
|
+
2. Create a webhook for \`email.received\` pointing to \`https://<your-url>/api/messaging/resend\`
|
|
606
|
+
3. Install the Resend SDK: \`npm install resend\`
|
|
607
|
+
4. Set env vars:
|
|
608
|
+
\`\`\`
|
|
609
|
+
RESEND_API_KEY=re_...
|
|
610
|
+
RESEND_WEBHOOK_SECRET=whsec_...
|
|
611
|
+
RESEND_FROM=Agent <agent@yourdomain.com>
|
|
612
|
+
\`\`\`
|
|
613
|
+
5. Add to \`poncho.config.js\`:
|
|
614
|
+
\`\`\`javascript
|
|
615
|
+
messaging: [{ platform: 'resend' }]
|
|
616
|
+
\`\`\`
|
|
617
|
+
|
|
618
|
+
For full control over outbound emails, use **tool mode** (\`mode: 'tool'\`) — the agent gets a \`send_email\` tool instead of auto-replying. See the repo README for details.
|
|
619
|
+
|
|
595
620
|
## Deployment
|
|
596
621
|
|
|
597
622
|
\`\`\`bash
|
|
@@ -1430,21 +1455,188 @@ export const createRequestHandler = async (options?: {
|
|
|
1430
1455
|
return { messages: [] };
|
|
1431
1456
|
},
|
|
1432
1457
|
async run(conversationId, input) {
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1458
|
+
console.log("[messaging-runner] starting run for", conversationId, "task:", input.task.slice(0, 80));
|
|
1459
|
+
|
|
1460
|
+
const historyMessages = [...input.messages];
|
|
1461
|
+
const userContent = input.task;
|
|
1462
|
+
|
|
1463
|
+
// Read-modify-write helper: always fetches the latest version from
|
|
1464
|
+
// the store before writing, so concurrent writers (e.g. the approval
|
|
1465
|
+
// handler's persistConversationPendingApprovals) don't get clobbered.
|
|
1466
|
+
const updateConversation = async (
|
|
1467
|
+
patch: (conv: Conversation) => void,
|
|
1468
|
+
): Promise<void> => {
|
|
1469
|
+
const fresh = await conversationStore.get(conversationId);
|
|
1470
|
+
if (!fresh) return;
|
|
1471
|
+
patch(fresh);
|
|
1472
|
+
fresh.updatedAt = Date.now();
|
|
1473
|
+
await conversationStore.update(fresh);
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
// Persist user turn immediately so the web UI shows it while the agent runs.
|
|
1477
|
+
await updateConversation((c) => {
|
|
1478
|
+
c.messages = [...historyMessages, { role: "user" as const, content: userContent }];
|
|
1436
1479
|
});
|
|
1437
|
-
const response = output.result.response ?? "";
|
|
1438
1480
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1481
|
+
let latestRunId = "";
|
|
1482
|
+
let assistantResponse = "";
|
|
1483
|
+
const toolTimeline: string[] = [];
|
|
1484
|
+
const sections: Array<{ type: "text" | "tools"; content: string | string[] }> = [];
|
|
1485
|
+
let currentTools: string[] = [];
|
|
1486
|
+
let currentText = "";
|
|
1487
|
+
|
|
1488
|
+
const buildMessages = (): Message[] => {
|
|
1489
|
+
const draftSections: Array<{ type: "text" | "tools"; content: string | string[] }> = [
|
|
1490
|
+
...sections.map((s) => ({
|
|
1491
|
+
type: s.type,
|
|
1492
|
+
content: Array.isArray(s.content) ? [...s.content] : s.content,
|
|
1493
|
+
})),
|
|
1445
1494
|
];
|
|
1446
|
-
|
|
1495
|
+
if (currentTools.length > 0) {
|
|
1496
|
+
draftSections.push({ type: "tools", content: [...currentTools] });
|
|
1497
|
+
}
|
|
1498
|
+
if (currentText.length > 0) {
|
|
1499
|
+
draftSections.push({ type: "text", content: currentText });
|
|
1500
|
+
}
|
|
1501
|
+
const hasDraftContent =
|
|
1502
|
+
assistantResponse.length > 0 || toolTimeline.length > 0 || draftSections.length > 0;
|
|
1503
|
+
if (!hasDraftContent) {
|
|
1504
|
+
return [...historyMessages, { role: "user" as const, content: userContent }];
|
|
1505
|
+
}
|
|
1506
|
+
return [
|
|
1507
|
+
...historyMessages,
|
|
1508
|
+
{ role: "user" as const, content: userContent },
|
|
1509
|
+
{
|
|
1510
|
+
role: "assistant" as const,
|
|
1511
|
+
content: assistantResponse,
|
|
1512
|
+
metadata:
|
|
1513
|
+
toolTimeline.length > 0 || draftSections.length > 0
|
|
1514
|
+
? ({
|
|
1515
|
+
toolActivity: [...toolTimeline],
|
|
1516
|
+
sections: draftSections.length > 0 ? draftSections : undefined,
|
|
1517
|
+
} as Message["metadata"])
|
|
1518
|
+
: undefined,
|
|
1519
|
+
},
|
|
1520
|
+
];
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1523
|
+
const persistDraftAssistantTurn = async (): Promise<void> => {
|
|
1524
|
+
if (assistantResponse.length === 0 && toolTimeline.length === 0) return;
|
|
1525
|
+
await updateConversation((c) => {
|
|
1526
|
+
c.messages = buildMessages();
|
|
1527
|
+
});
|
|
1528
|
+
};
|
|
1529
|
+
|
|
1530
|
+
const runInput = {
|
|
1531
|
+
task: input.task,
|
|
1532
|
+
conversationId,
|
|
1533
|
+
messages: input.messages,
|
|
1534
|
+
files: input.files,
|
|
1535
|
+
parameters: input.metadata ? {
|
|
1536
|
+
__messaging_platform: input.metadata.platform,
|
|
1537
|
+
__messaging_sender_id: input.metadata.sender.id,
|
|
1538
|
+
__messaging_sender_name: input.metadata.sender.name ?? "",
|
|
1539
|
+
__messaging_thread_id: input.metadata.threadId,
|
|
1540
|
+
} : undefined,
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1543
|
+
try {
|
|
1544
|
+
for await (const event of harness.runWithTelemetry(runInput)) {
|
|
1545
|
+
if (event.type === "run:started") {
|
|
1546
|
+
latestRunId = event.runId;
|
|
1547
|
+
runOwners.set(event.runId, "local-owner");
|
|
1548
|
+
runConversations.set(event.runId, conversationId);
|
|
1549
|
+
}
|
|
1550
|
+
if (event.type === "model:chunk") {
|
|
1551
|
+
if (currentTools.length > 0) {
|
|
1552
|
+
sections.push({ type: "tools", content: currentTools });
|
|
1553
|
+
currentTools = [];
|
|
1554
|
+
}
|
|
1555
|
+
assistantResponse += event.content;
|
|
1556
|
+
currentText += event.content;
|
|
1557
|
+
}
|
|
1558
|
+
if (event.type === "tool:started") {
|
|
1559
|
+
if (currentText.length > 0) {
|
|
1560
|
+
sections.push({ type: "text", content: currentText });
|
|
1561
|
+
currentText = "";
|
|
1562
|
+
}
|
|
1563
|
+
const toolText = `- start \`${event.tool}\``;
|
|
1564
|
+
toolTimeline.push(toolText);
|
|
1565
|
+
currentTools.push(toolText);
|
|
1566
|
+
}
|
|
1567
|
+
if (event.type === "tool:completed") {
|
|
1568
|
+
const toolText = `- done \`${event.tool}\` (${event.duration}ms)`;
|
|
1569
|
+
toolTimeline.push(toolText);
|
|
1570
|
+
currentTools.push(toolText);
|
|
1571
|
+
}
|
|
1572
|
+
if (event.type === "tool:error") {
|
|
1573
|
+
const toolText = `- error \`${event.tool}\`: ${event.error}`;
|
|
1574
|
+
toolTimeline.push(toolText);
|
|
1575
|
+
currentTools.push(toolText);
|
|
1576
|
+
}
|
|
1577
|
+
if (event.type === "step:completed") {
|
|
1578
|
+
await persistDraftAssistantTurn();
|
|
1579
|
+
}
|
|
1580
|
+
if (event.type === "tool:approval:required") {
|
|
1581
|
+
const toolText = `- approval required \`${event.tool}\``;
|
|
1582
|
+
toolTimeline.push(toolText);
|
|
1583
|
+
currentTools.push(toolText);
|
|
1584
|
+
await persistDraftAssistantTurn();
|
|
1585
|
+
await persistConversationPendingApprovals(conversationId);
|
|
1586
|
+
}
|
|
1587
|
+
if (event.type === "tool:approval:granted") {
|
|
1588
|
+
const toolText = `- approval granted (${event.approvalId})`;
|
|
1589
|
+
toolTimeline.push(toolText);
|
|
1590
|
+
currentTools.push(toolText);
|
|
1591
|
+
await persistDraftAssistantTurn();
|
|
1592
|
+
}
|
|
1593
|
+
if (event.type === "tool:approval:denied") {
|
|
1594
|
+
const toolText = `- approval denied (${event.approvalId})`;
|
|
1595
|
+
toolTimeline.push(toolText);
|
|
1596
|
+
currentTools.push(toolText);
|
|
1597
|
+
await persistDraftAssistantTurn();
|
|
1598
|
+
}
|
|
1599
|
+
if (
|
|
1600
|
+
event.type === "run:completed" &&
|
|
1601
|
+
assistantResponse.length === 0 &&
|
|
1602
|
+
event.result.response
|
|
1603
|
+
) {
|
|
1604
|
+
assistantResponse = event.result.response;
|
|
1605
|
+
}
|
|
1606
|
+
if (event.type === "run:error") {
|
|
1607
|
+
assistantResponse = assistantResponse || `[Error: ${event.error.message}]`;
|
|
1608
|
+
}
|
|
1609
|
+
broadcastEvent(conversationId, event);
|
|
1610
|
+
}
|
|
1611
|
+
} catch (err) {
|
|
1612
|
+
console.error("[messaging-runner] run failed:", err instanceof Error ? err.message : err);
|
|
1613
|
+
assistantResponse = assistantResponse || `[Error: ${err instanceof Error ? err.message : "Unknown error"}]`;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// Finalize sections (clear after pushing so buildMessages doesn't re-add)
|
|
1617
|
+
if (currentTools.length > 0) {
|
|
1618
|
+
sections.push({ type: "tools", content: currentTools });
|
|
1619
|
+
currentTools = [];
|
|
1447
1620
|
}
|
|
1621
|
+
if (currentText.length > 0) {
|
|
1622
|
+
sections.push({ type: "text", content: currentText });
|
|
1623
|
+
currentText = "";
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
await updateConversation((c) => {
|
|
1627
|
+
c.messages = buildMessages();
|
|
1628
|
+
c.runtimeRunId = latestRunId || c.runtimeRunId;
|
|
1629
|
+
c.pendingApprovals = [];
|
|
1630
|
+
});
|
|
1631
|
+
finishConversationStream(conversationId);
|
|
1632
|
+
await persistConversationPendingApprovals(conversationId);
|
|
1633
|
+
if (latestRunId) {
|
|
1634
|
+
runOwners.delete(latestRunId);
|
|
1635
|
+
runConversations.delete(latestRunId);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
console.log("[messaging-runner] run complete, response length:", assistantResponse.length);
|
|
1639
|
+
const response = assistantResponse;
|
|
1448
1640
|
|
|
1449
1641
|
return { response };
|
|
1450
1642
|
},
|
|
@@ -1475,6 +1667,7 @@ export const createRequestHandler = async (options?: {
|
|
|
1475
1667
|
adapter,
|
|
1476
1668
|
runner: messagingRunner,
|
|
1477
1669
|
waitUntil: waitUntilHook,
|
|
1670
|
+
ownerId: "local-owner",
|
|
1478
1671
|
});
|
|
1479
1672
|
adapter.registerRoutes(messagingRouteRegistrar);
|
|
1480
1673
|
try {
|
|
@@ -1486,6 +1679,37 @@ export const createRequestHandler = async (options?: {
|
|
|
1486
1679
|
` Slack messaging disabled: ${err instanceof Error ? err.message : String(err)}`,
|
|
1487
1680
|
);
|
|
1488
1681
|
}
|
|
1682
|
+
} else if (channelConfig.platform === "resend") {
|
|
1683
|
+
const adapter = new ResendAdapter({
|
|
1684
|
+
apiKeyEnv: channelConfig.apiKeyEnv,
|
|
1685
|
+
webhookSecretEnv: channelConfig.webhookSecretEnv,
|
|
1686
|
+
fromEnv: channelConfig.fromEnv,
|
|
1687
|
+
allowedSenders: channelConfig.allowedSenders,
|
|
1688
|
+
mode: channelConfig.mode,
|
|
1689
|
+
allowedRecipients: channelConfig.allowedRecipients,
|
|
1690
|
+
maxSendsPerRun: channelConfig.maxSendsPerRun,
|
|
1691
|
+
});
|
|
1692
|
+
const bridge = new AgentBridge({
|
|
1693
|
+
adapter,
|
|
1694
|
+
runner: messagingRunner,
|
|
1695
|
+
waitUntil: waitUntilHook,
|
|
1696
|
+
ownerId: "local-owner",
|
|
1697
|
+
});
|
|
1698
|
+
adapter.registerRoutes(messagingRouteRegistrar);
|
|
1699
|
+
try {
|
|
1700
|
+
await bridge.start();
|
|
1701
|
+
messagingBridges.push(bridge);
|
|
1702
|
+
const adapterTools = adapter.getToolDefinitions?.() ?? [];
|
|
1703
|
+
if (adapterTools.length > 0) {
|
|
1704
|
+
harness.registerTools(adapterTools);
|
|
1705
|
+
}
|
|
1706
|
+
const modeLabel = channelConfig.mode === "tool" ? "tool" : "auto-reply";
|
|
1707
|
+
console.log(` Resend email messaging enabled at /api/messaging/resend (mode: ${modeLabel})`);
|
|
1708
|
+
} catch (err) {
|
|
1709
|
+
console.warn(
|
|
1710
|
+
` Resend email messaging disabled: ${err instanceof Error ? err.message : String(err)}`,
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1489
1713
|
}
|
|
1490
1714
|
}
|
|
1491
1715
|
}
|
|
@@ -1498,6 +1722,7 @@ export const createRequestHandler = async (options?: {
|
|
|
1498
1722
|
const authRequired = config?.auth?.required ?? false;
|
|
1499
1723
|
const requireAuth = authRequired && authToken.length > 0;
|
|
1500
1724
|
|
|
1725
|
+
const webUiEnabled = config?.webUi !== false;
|
|
1501
1726
|
const isProduction = resolveHarnessEnvironment() === "production";
|
|
1502
1727
|
const secureCookies = isProduction;
|
|
1503
1728
|
|
|
@@ -1523,41 +1748,52 @@ export const createRequestHandler = async (options?: {
|
|
|
1523
1748
|
}
|
|
1524
1749
|
const [pathname] = request.url.split("?");
|
|
1525
1750
|
|
|
1526
|
-
if (
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1751
|
+
if (webUiEnabled) {
|
|
1752
|
+
if (request.method === "GET" && (pathname === "/" || pathname.startsWith("/c/"))) {
|
|
1753
|
+
writeHtml(response, 200, renderWebUiHtml({ agentName }));
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1530
1756
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1757
|
+
if (pathname === "/manifest.json" && request.method === "GET") {
|
|
1758
|
+
response.writeHead(200, { "Content-Type": "application/manifest+json" });
|
|
1759
|
+
response.end(renderManifest({ agentName }));
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1536
1762
|
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1763
|
+
if (pathname === "/sw.js" && request.method === "GET") {
|
|
1764
|
+
response.writeHead(200, {
|
|
1765
|
+
"Content-Type": "application/javascript",
|
|
1766
|
+
"Service-Worker-Allowed": "/",
|
|
1767
|
+
});
|
|
1768
|
+
response.end(renderServiceWorker());
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
if (pathname === "/icon.svg" && request.method === "GET") {
|
|
1773
|
+
response.writeHead(200, { "Content-Type": "image/svg+xml" });
|
|
1774
|
+
response.end(renderIconSvg({ agentName }));
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
if ((pathname === "/icon-192.png" || pathname === "/icon-512.png") && request.method === "GET") {
|
|
1779
|
+
response.writeHead(302, { Location: "/icon.svg" });
|
|
1780
|
+
response.end();
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1544
1783
|
}
|
|
1545
1784
|
|
|
1546
|
-
if (pathname === "/
|
|
1547
|
-
response
|
|
1548
|
-
response.end(renderIconSvg({ agentName }));
|
|
1785
|
+
if (pathname === "/health" && request.method === "GET") {
|
|
1786
|
+
writeJson(response, 200, { status: "ok" });
|
|
1549
1787
|
return;
|
|
1550
1788
|
}
|
|
1551
1789
|
|
|
1552
|
-
if (
|
|
1553
|
-
|
|
1554
|
-
response.writeHead(302, { Location: "/icon.svg" });
|
|
1555
|
-
response.end();
|
|
1790
|
+
if (pathname === "/api/openapi.json" && request.method === "GET") {
|
|
1791
|
+
writeJson(response, 200, buildOpenApiSpec({ agentName }));
|
|
1556
1792
|
return;
|
|
1557
1793
|
}
|
|
1558
1794
|
|
|
1559
|
-
if (pathname === "/
|
|
1560
|
-
|
|
1795
|
+
if (pathname === "/api/docs" && request.method === "GET") {
|
|
1796
|
+
writeHtml(response, 200, renderApiDocsHtml("/api/openapi.json"));
|
|
1561
1797
|
return;
|
|
1562
1798
|
}
|
|
1563
1799
|
|
|
@@ -1779,18 +2015,19 @@ export const createRequestHandler = async (options?: {
|
|
|
1779
2015
|
});
|
|
1780
2016
|
const stream = conversationEventStreams.get(conversationId);
|
|
1781
2017
|
if (!stream) {
|
|
1782
|
-
// No active run — close immediately
|
|
1783
2018
|
response.write("event: stream:end\ndata: {}\n\n");
|
|
1784
2019
|
response.end();
|
|
1785
2020
|
return;
|
|
1786
2021
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
2022
|
+
const liveOnly = (request.url ?? "").includes("live_only=true");
|
|
2023
|
+
if (!liveOnly) {
|
|
2024
|
+
for (const bufferedEvent of stream.buffer) {
|
|
2025
|
+
try {
|
|
2026
|
+
response.write(formatSseEvent(bufferedEvent));
|
|
2027
|
+
} catch {
|
|
2028
|
+
response.end();
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
1794
2031
|
}
|
|
1795
2032
|
}
|
|
1796
2033
|
if (stream.finished) {
|
|
@@ -1841,11 +2078,14 @@ export const createRequestHandler = async (options?: {
|
|
|
1841
2078
|
for (const approval of livePending) {
|
|
1842
2079
|
mergedPendingById.set(approval.approvalId, approval);
|
|
1843
2080
|
}
|
|
2081
|
+
const activeStream = conversationEventStreams.get(conversationId);
|
|
2082
|
+
const hasActiveRun = !!activeStream && !activeStream.finished;
|
|
1844
2083
|
writeJson(response, 200, {
|
|
1845
2084
|
conversation: {
|
|
1846
2085
|
...conversation,
|
|
1847
2086
|
pendingApprovals: Array.from(mergedPendingById.values()),
|
|
1848
2087
|
},
|
|
2088
|
+
hasActiveRun,
|
|
1849
2089
|
});
|
|
1850
2090
|
return;
|
|
1851
2091
|
}
|
|
@@ -2124,6 +2364,7 @@ export const createRequestHandler = async (options?: {
|
|
|
2124
2364
|
|
|
2125
2365
|
for await (const event of harness.runWithTelemetry({
|
|
2126
2366
|
task: messageText,
|
|
2367
|
+
conversationId,
|
|
2127
2368
|
parameters: {
|
|
2128
2369
|
...(bodyParameters ?? {}),
|
|
2129
2370
|
__conversationRecallCorpus: recallCorpus,
|
|
@@ -2403,6 +2644,7 @@ export const createRequestHandler = async (options?: {
|
|
|
2403
2644
|
|
|
2404
2645
|
for await (const event of harness.runWithTelemetry({
|
|
2405
2646
|
task: cronJob.task,
|
|
2647
|
+
conversationId: conversation.conversationId,
|
|
2406
2648
|
parameters: { __activeConversationId: conversation.conversationId },
|
|
2407
2649
|
messages: historyMessages,
|
|
2408
2650
|
abortSignal: abortController.signal,
|
|
@@ -2589,6 +2831,7 @@ export const startDevServer = async (
|
|
|
2589
2831
|
let currentText = "";
|
|
2590
2832
|
for await (const event of harness.runWithTelemetry({
|
|
2591
2833
|
task: config.task,
|
|
2834
|
+
conversationId: conversation.conversationId,
|
|
2592
2835
|
parameters: { __activeConversationId: conversation.conversationId },
|
|
2593
2836
|
messages: [],
|
|
2594
2837
|
})) {
|
package/src/init-onboarding.ts
CHANGED
|
@@ -349,7 +349,20 @@ export const buildConfigFromOnboardingAnswers = (
|
|
|
349
349
|
};
|
|
350
350
|
|
|
351
351
|
if (messagingPlatform !== "none") {
|
|
352
|
-
|
|
352
|
+
const channelConfig: NonNullable<PonchoConfig["messaging"]>[number] = {
|
|
353
|
+
platform: messagingPlatform as "slack" | "resend",
|
|
354
|
+
};
|
|
355
|
+
if (messagingPlatform === "resend") {
|
|
356
|
+
const mode = String(answers["messaging.resend.mode"] ?? "auto-reply");
|
|
357
|
+
if (mode === "tool") {
|
|
358
|
+
channelConfig.mode = "tool";
|
|
359
|
+
}
|
|
360
|
+
const recipientsRaw = String(answers["messaging.resend.allowedRecipients"] ?? "");
|
|
361
|
+
if (recipientsRaw.trim().length > 0) {
|
|
362
|
+
channelConfig.allowedRecipients = recipientsRaw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
config.messaging = [channelConfig];
|
|
353
366
|
}
|
|
354
367
|
|
|
355
368
|
return config;
|