pi-roundtable 0.1.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/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/docs/plugins.md +924 -0
- package/examples/channels.test.ts +13 -0
- package/examples/channels.ts +27 -0
- package/examples/dashboard.test.ts +11 -0
- package/examples/dashboard.ts +9 -0
- package/examples/events.test.ts +26 -0
- package/examples/events.ts +25 -0
- package/examples/guide.test.ts +52 -0
- package/examples/holds.test.ts +16 -0
- package/examples/holds.ts +30 -0
- package/examples/http.test.ts +12 -0
- package/examples/http.ts +17 -0
- package/examples/interactions.test.ts +25 -0
- package/examples/interactions.ts +28 -0
- package/examples/migrations.test.ts +31 -0
- package/examples/migrations.ts +42 -0
- package/examples/packages.test.ts +9 -0
- package/examples/packages.ts +9 -0
- package/examples/preflight.test.ts +11 -0
- package/examples/preflight.ts +19 -0
- package/examples/prompt.test.ts +25 -0
- package/examples/prompt.ts +20 -0
- package/examples/providers.test.ts +10 -0
- package/examples/providers.ts +17 -0
- package/examples/seeds.test.ts +12 -0
- package/examples/seeds.ts +18 -0
- package/examples/selection.test.ts +13 -0
- package/examples/selection.ts +14 -0
- package/examples/services.test.ts +20 -0
- package/examples/services.ts +30 -0
- package/examples/session-tools.test.ts +24 -0
- package/examples/session-tools.ts +34 -0
- package/examples/tools.test.ts +18 -0
- package/examples/tools.ts +28 -0
- package/package.json +55 -0
- package/src/cli/add-plugin.test.ts +107 -0
- package/src/cli/add-plugin.ts +75 -0
- package/src/cli/checks/basic.test.ts +276 -0
- package/src/cli/checks/bun.ts +26 -0
- package/src/cli/checks/configuration.ts +28 -0
- package/src/cli/checks/database.test.ts +117 -0
- package/src/cli/checks/database.ts +100 -0
- package/src/cli/checks/discord.test.ts +200 -0
- package/src/cli/checks/discord.ts +218 -0
- package/src/cli/checks/environment.ts +27 -0
- package/src/cli/checks/model.ts +28 -0
- package/src/cli/checks/public-url.ts +40 -0
- package/src/cli/cli.test.ts +122 -0
- package/src/cli/cli.ts +166 -0
- package/src/cli/config-edit.test.ts +130 -0
- package/src/cli/config-edit.ts +199 -0
- package/src/cli/discord-api.ts +96 -0
- package/src/cli/doctor.test.ts +184 -0
- package/src/cli/doctor.ts +92 -0
- package/src/cli/http.ts +23 -0
- package/src/cli/init.test.ts +127 -0
- package/src/cli/init.ts +82 -0
- package/src/cli/main.ts +13 -0
- package/src/cli/project.ts +123 -0
- package/src/cli/report.ts +68 -0
- package/src/cli/roundtable.mjs +22 -0
- package/src/cli/runtime.ts +53 -0
- package/src/cli/size.test.ts +9 -0
- package/src/cli/start.ts +33 -0
- package/src/cli/templates.test.ts +129 -0
- package/src/cli/templates.ts +119 -0
- package/src/cli/testing/fixtures.ts +106 -0
- package/src/core/agents/agent-claim.test.ts +142 -0
- package/src/core/agents/agent-claim.ts +170 -0
- package/src/core/agents/agent-dashboard.test.ts +120 -0
- package/src/core/agents/agent-dashboard.ts +185 -0
- package/src/core/agents/agent-guild.test.ts +124 -0
- package/src/core/agents/agent-messages.ts +189 -0
- package/src/core/agents/agent-ports.ts +103 -0
- package/src/core/agents/agent-prompt.ts +163 -0
- package/src/core/agents/agent-rules.ts +106 -0
- package/src/core/agents/agent-schema.ts +115 -0
- package/src/core/agents/agent-settings.ts +49 -0
- package/src/core/agents/agent-store.test.ts +205 -0
- package/src/core/agents/agent-store.ts +384 -0
- package/src/core/agents/agent-team.ts +445 -0
- package/src/core/agents/agent-tools.ts +386 -0
- package/src/core/agents/avatar-studio.test.ts +88 -0
- package/src/core/agents/avatar-studio.ts +147 -0
- package/src/core/agents/group-messages.ts +99 -0
- package/src/core/agents/group-round.test.ts +143 -0
- package/src/core/agents/group-round.ts +117 -0
- package/src/core/agents/group-turns.ts +132 -0
- package/src/core/agents/owner-identity.test.ts +172 -0
- package/src/core/agents/team-editing.ts +205 -0
- package/src/core/agents/team-keys.ts +40 -0
- package/src/core/agents/team-layout.ts +135 -0
- package/src/core/agents/team-lifecycle.ts +188 -0
- package/src/core/agents/team-options.ts +52 -0
- package/src/core/agents/team-status.ts +80 -0
- package/src/core/agents/team-text.ts +60 -0
- package/src/core/agents/team-turn-types.ts +107 -0
- package/src/core/agents/team-turns.test.ts +278 -0
- package/src/core/agents/team-turns.ts +323 -0
- package/src/core/assets/neutral.png +0 -0
- package/src/core/assets/prompts/shared-guest.md +11 -0
- package/src/core/assets/prompts/shared.md +11 -0
- package/src/core/assets/skills/writing-skills/SKILL.md +21 -0
- package/src/core/attachments/attachment-dir.ts +15 -0
- package/src/core/attachments/attachment-fetcher.ts +83 -0
- package/src/core/attachments/attachments.test.ts +85 -0
- package/src/core/attachments/image-prep.ts +50 -0
- package/src/core/attachments/prompt-block.ts +37 -0
- package/src/core/attachments/turn-attachments.ts +79 -0
- package/src/core/boundary.test.ts +45 -0
- package/src/core/builtin/agent-server.ts +275 -0
- package/src/core/builtin/discord.ts +95 -0
- package/src/core/builtin/modules.test.ts +127 -0
- package/src/core/builtin/modules.ts +176 -0
- package/src/core/builtin/seeds.ts +10 -0
- package/src/core/builtin/stores.ts +42 -0
- package/src/core/config/config.test.ts +135 -0
- package/src/core/config/config.ts +285 -0
- package/src/core/config/schema.ts +181 -0
- package/src/core/contract/channels.ts +152 -0
- package/src/core/contract/discord.ts +33 -0
- package/src/core/contract/providers.ts +67 -0
- package/src/core/db/guild-scope.ts +53 -0
- package/src/core/db/migrations.test.ts +237 -0
- package/src/core/db/migrations.ts +37 -0
- package/src/core/define-roundtable.test.ts +134 -0
- package/src/core/define-roundtable.ts +195 -0
- package/src/core/define.test.ts +144 -0
- package/src/core/define.ts +154 -0
- package/src/core/discord/agent-commands.test.ts +58 -0
- package/src/core/discord/agent-commands.ts +385 -0
- package/src/core/discord/agent-discord.test.ts +70 -0
- package/src/core/discord/agent-discord.ts +367 -0
- package/src/core/discord/channel-executor.ts +404 -0
- package/src/core/discord/channel-operations.ts +329 -0
- package/src/core/discord/discord-surface.ts +431 -0
- package/src/core/discord/dispatch-thread-host.test.ts +114 -0
- package/src/core/discord/dispatch-thread-host.ts +72 -0
- package/src/core/discord/dispatch-threads.test.ts +94 -0
- package/src/core/discord/dispatch-threads.ts +180 -0
- package/src/core/discord/interaction-module.ts +1 -0
- package/src/core/discord/owner-cards.test.ts +435 -0
- package/src/core/discord/owner-cards.ts +463 -0
- package/src/core/discord/owner-command.ts +126 -0
- package/src/core/discord/owner-discord-access.ts +183 -0
- package/src/core/discord/owner-discord-threads.ts +160 -0
- package/src/core/discord/owner-discord.test.ts +325 -0
- package/src/core/discord/owner-discord.ts +282 -0
- package/src/core/discord/owner-panel.ts +103 -0
- package/src/core/discord/schedule-commands.ts +149 -0
- package/src/core/discord/stop-button.ts +20 -0
- package/src/core/domain/attachment.ts +39 -0
- package/src/core/domain/conversation.ts +42 -0
- package/src/core/domain/errors.ts +31 -0
- package/src/core/domain/expression.ts +21 -0
- package/src/core/domain/owner-prompts.ts +45 -0
- package/src/core/domain/ports.ts +91 -0
- package/src/core/domain/profile.ts +32 -0
- package/src/core/drain.test.ts +46 -0
- package/src/core/drain.ts +33 -0
- package/src/core/errors.ts +29 -0
- package/src/core/events.test.ts +81 -0
- package/src/core/events.ts +55 -0
- package/src/core/holds.test.ts +54 -0
- package/src/core/holds.ts +46 -0
- package/src/core/host.test.ts +536 -0
- package/src/core/host.ts +297 -0
- package/src/core/http/listeners.test.ts +164 -0
- package/src/core/http/listeners.ts +151 -0
- package/src/core/i18n/agent-panel.ts +96 -0
- package/src/core/i18n/cards.ts +64 -0
- package/src/core/i18n/channels.ts +28 -0
- package/src/core/i18n/conversation.ts +49 -0
- package/src/core/i18n/dashboard.ts +72 -0
- package/src/core/i18n/discord.ts +23 -0
- package/src/core/i18n/en.ts +27 -0
- package/src/core/i18n/i18n.test.ts +139 -0
- package/src/core/i18n/index.ts +58 -0
- package/src/core/i18n/owner.ts +35 -0
- package/src/core/i18n/schedules.ts +92 -0
- package/src/core/i18n/time-zones.ts +27 -0
- package/src/core/i18n/types.ts +7 -0
- package/src/core/i18n/zh-tw.ts +26 -0
- package/src/core/identity.test.ts +18 -0
- package/src/core/identity.ts +31 -0
- package/src/core/judging/confirmation-judge.ts +68 -0
- package/src/core/judging/effort-judge.test.ts +112 -0
- package/src/core/judging/effort-judge.ts +158 -0
- package/src/core/judging/model-judge.test.ts +126 -0
- package/src/core/judging/model-judge.ts +193 -0
- package/src/core/log.ts +45 -0
- package/src/core/models.ts +52 -0
- package/src/core/modules/background/background-turns.ts +78 -0
- package/src/core/modules/delegation/delegate.ts +54 -0
- package/src/core/modules/delegation/delegator.test.ts +170 -0
- package/src/core/modules/delegation/delegator.ts +191 -0
- package/src/core/modules/delegation/sol-worker.ts +78 -0
- package/src/core/modules/discord-admin/discord-admin.ts +288 -0
- package/src/core/modules/host-shell/shell-policy.ts +386 -0
- package/src/core/modules/memory/owner-memory-store.test.ts +244 -0
- package/src/core/modules/memory/owner-memory-store.ts +228 -0
- package/src/core/modules/memory/owner-memory.ts +153 -0
- package/src/core/modules/notify/notify.ts +26 -0
- package/src/core/modules/schedules/recurrence.ts +206 -0
- package/src/core/modules/schedules/schedule-store.ts +213 -0
- package/src/core/modules/schedules/schedule-tools.ts +196 -0
- package/src/core/modules/schedules/schedule.test.ts +358 -0
- package/src/core/modules/schedules/scheduler.ts +121 -0
- package/src/core/modules/schedules/schedules.ts +87 -0
- package/src/core/modules/skills/repo-name.ts +11 -0
- package/src/core/modules/skills/skill-kind.test.ts +55 -0
- package/src/core/modules/skills/skill-link.ts +69 -0
- package/src/core/modules/skills/skill-listing.ts +128 -0
- package/src/core/modules/skills/skill-registry.test.ts +376 -0
- package/src/core/modules/skills/skill-registry.ts +323 -0
- package/src/core/modules/skills/skill-rules.ts +120 -0
- package/src/core/modules/skills/skill-store.ts +285 -0
- package/src/core/modules/skills/skill-tools.ts +207 -0
- package/src/core/ops/error-reporter.test.ts +283 -0
- package/src/core/ops/error-reporter.ts +271 -0
- package/src/core/plugin.ts +200 -0
- package/src/core/presentation/card-cadence.ts +41 -0
- package/src/core/presentation/headline.ts +34 -0
- package/src/core/presentation/presentation.test.ts +166 -0
- package/src/core/presentation/quiet-links.ts +36 -0
- package/src/core/presentation/reply-splitter.ts +110 -0
- package/src/core/presentation/thinking-line.ts +24 -0
- package/src/core/public-entry.test.ts +59 -0
- package/src/core/registry/contributions.test.ts +215 -0
- package/src/core/registry/contributions.ts +249 -0
- package/src/core/registry/interactions.test.ts +87 -0
- package/src/core/registry/interactions.ts +55 -0
- package/src/core/registry/providers.test.ts +103 -0
- package/src/core/registry/providers.ts +55 -0
- package/src/core/routing/channel-queue.test.ts +31 -0
- package/src/core/routing/channel-queue.ts +44 -0
- package/src/core/routing/channel-router.test.ts +326 -0
- package/src/core/routing/channel-router.ts +157 -0
- package/src/core/routing/conversation-kind.ts +14 -0
- package/src/core/routing/forward-join.ts +65 -0
- package/src/core/routing/message-text.ts +16 -0
- package/src/core/routing/settle-turn.test.ts +21 -0
- package/src/core/routing/settle-turn.ts +26 -0
- package/src/core/runtime/compaction-tiers.test.ts +227 -0
- package/src/core/runtime/compaction-tiers.ts +203 -0
- package/src/core/runtime/conversation-sessions.ts +162 -0
- package/src/core/runtime/extensions/agent-prompt.ts +16 -0
- package/src/core/runtime/extensions/ask-user.test.ts +114 -0
- package/src/core/runtime/extensions/ask-user.ts +98 -0
- package/src/core/runtime/extensions/confirmation-gate.ts +247 -0
- package/src/core/runtime/extensions/self-compact-guard.test.ts +50 -0
- package/src/core/runtime/extensions/self-compact-guard.ts +23 -0
- package/src/core/runtime/mcp.ts +23 -0
- package/src/core/runtime/pending-confirmation-store.test.ts +52 -0
- package/src/core/runtime/pending-confirmation-store.ts +75 -0
- package/src/core/runtime/pi-agent-runtime.ts +477 -0
- package/src/core/runtime/prompt-slot.ts +81 -0
- package/src/core/runtime/runtime-types.ts +150 -0
- package/src/core/runtime/session-archive.test.ts +20 -0
- package/src/core/runtime/session-archive.ts +17 -0
- package/src/core/runtime/session-factory.ts +291 -0
- package/src/core/runtime/steerable-run.test.ts +264 -0
- package/src/core/runtime/steerable-run.ts +109 -0
- package/src/core/runtime/text-tools.test.ts +110 -0
- package/src/core/runtime/text-tools.ts +66 -0
- package/src/core/runtime/turn-answer.test.ts +72 -0
- package/src/core/runtime/turn-answer.ts +79 -0
- package/src/core/runtime/worker-task.test.ts +82 -0
- package/src/core/runtime/worker-task.ts +65 -0
- package/src/core/services.test.ts +28 -0
- package/src/core/services.ts +107 -0
- package/src/core/sessions.test.ts +85 -0
- package/src/core/sessions.ts +149 -0
- package/src/core/shared/attachment-reader.ts +91 -0
- package/src/core/shared/delegate-tool.ts +15 -0
- package/src/core/shared/mcp-adapter.ts +58 -0
- package/src/core/shared/package-dir.ts +9 -0
- package/src/core/shared/profile-tools.ts +16 -0
- package/src/core/shared/read-attachment-tool.ts +43 -0
- package/src/core/shared/schedule-tools.ts +118 -0
- package/src/core/shared/session-messages.ts +50 -0
- package/src/core/shared/tool-result.ts +9 -0
- package/src/core/shared/unix-server.ts +18 -0
- package/src/core/size.test.ts +9 -0
- package/src/core/speakers.test.ts +78 -0
- package/src/core/speakers.ts +143 -0
- package/src/core/testing/database.ts +52 -0
- package/src/core/testing/file-size.ts +34 -0
- package/src/core/testing/locale.ts +8 -0
- package/src/core/testing/modules.ts +97 -0
- package/src/core/testing/owner.ts +15 -0
- package/src/core/testing/thread-host.ts +60 -0
- package/src/core/time.test.ts +166 -0
- package/src/core/time.ts +67 -0
- package/src/core/tool-tiers.test.ts +117 -0
- package/src/core/tool-tiers.ts +127 -0
- package/src/entries.test.ts +112 -0
- package/src/index.ts +28 -0
- package/src/testing.test.ts +156 -0
- package/src/testing.ts +182 -0
- package/templates/.env.example +22 -0
- package/templates/README.md +11 -0
- package/templates/_gitignore +3 -0
- package/templates/agents.ts +12 -0
- package/templates/biome.json.tmpl +7 -0
- package/templates/docker-compose.yml +16 -0
- package/templates/package.json.tmpl +24 -0
- package/templates/persona/shared.md +2 -0
- package/templates/plugin/plugin.test.ts.tmpl +13 -0
- package/templates/plugin/plugin.ts +18 -0
- package/templates/roundtable.config.ts +24 -0
- package/templates/tsconfig.json.tmpl +16 -0
package/src/testing.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { SQL } from "bun";
|
|
3
|
+
import type { ConversationPort } from "./core/contract/channels.ts";
|
|
4
|
+
import type { Providers } from "./core/contract/providers.ts";
|
|
5
|
+
import { NotLinkedError, PluginError } from "./core/errors.ts";
|
|
6
|
+
import { EventBus } from "./core/events.ts";
|
|
7
|
+
import { silentLogger } from "./core/log.ts";
|
|
8
|
+
import type {
|
|
9
|
+
Contribution,
|
|
10
|
+
LinkedSessions,
|
|
11
|
+
PluginContext,
|
|
12
|
+
RoundtablePlugin,
|
|
13
|
+
TurnEndEvent,
|
|
14
|
+
TurnEvent,
|
|
15
|
+
} from "./core/plugin.ts";
|
|
16
|
+
import {
|
|
17
|
+
collectContributions,
|
|
18
|
+
linkSessions,
|
|
19
|
+
} from "./core/registry/contributions.ts";
|
|
20
|
+
import { resolveProviders } from "./core/registry/providers.ts";
|
|
21
|
+
import { ChannelQueue } from "./core/routing/channel-queue.ts";
|
|
22
|
+
import { CoreRegistry } from "./core/services.ts";
|
|
23
|
+
import type { SessionContext } from "./core/sessions.ts";
|
|
24
|
+
import type { Speaker } from "./core/speakers.ts";
|
|
25
|
+
import { type ToolTierTable, toolTiers } from "./core/tool-tiers.ts";
|
|
26
|
+
|
|
27
|
+
export interface TestPluginOptions {
|
|
28
|
+
database?: SQL;
|
|
29
|
+
providers?: Partial<Providers>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RecordedEvent {
|
|
33
|
+
name: "turnStarted" | "turnEnded" | "changed";
|
|
34
|
+
turn?: TurnEvent | TurnEndEvent;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TestPluginResult {
|
|
38
|
+
contribution: Contribution;
|
|
39
|
+
tools: readonly string[];
|
|
40
|
+
tiers: ToolTierTable;
|
|
41
|
+
events: RecordedEvent[];
|
|
42
|
+
runTool(
|
|
43
|
+
name: string,
|
|
44
|
+
args: Record<string, unknown>,
|
|
45
|
+
options?: { speaker?: Speaker },
|
|
46
|
+
): Promise<string>;
|
|
47
|
+
stop(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The same pre-link failures and wording the host exposes during setup. */
|
|
51
|
+
const NOT_LINKED = {
|
|
52
|
+
conversations:
|
|
53
|
+
"conversations are linked once every plugin is set up. Use them from a service's start or from a handler, not during setup.",
|
|
54
|
+
sessions:
|
|
55
|
+
"session parts are linked once every plugin is set up. Call sessions() from a service's start or from a handler, not during setup.",
|
|
56
|
+
dashboard:
|
|
57
|
+
"dashboard lines are linked once every plugin is set up. Call dashboard() from a service's start or from a handler, not during setup.",
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function unlinked(part: keyof typeof NOT_LINKED): never {
|
|
61
|
+
throw new NotLinkedError(NOT_LINKED[part]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Build one plugin without Discord or PostgreSQL, retaining the host's validation and tier logic. */
|
|
65
|
+
export async function testPlugin(
|
|
66
|
+
plugin: RoundtablePlugin,
|
|
67
|
+
options: TestPluginOptions = {},
|
|
68
|
+
): Promise<TestPluginResult> {
|
|
69
|
+
const logger = silentLogger();
|
|
70
|
+
const tiers = toolTiers();
|
|
71
|
+
const bus = new EventBus(logger);
|
|
72
|
+
const events: RecordedEvent[] = [];
|
|
73
|
+
const core = new CoreRegistry();
|
|
74
|
+
let linked: LinkedSessions | undefined;
|
|
75
|
+
const conversations: ConversationPort = {
|
|
76
|
+
handle: async () => unlinked("conversations"),
|
|
77
|
+
background: async () => unlinked("conversations"),
|
|
78
|
+
startFresh: async () => unlinked("conversations"),
|
|
79
|
+
deleteConversation: async () => unlinked("conversations"),
|
|
80
|
+
stop: () => unlinked("conversations"),
|
|
81
|
+
postsInPlace: () => unlinked("conversations"),
|
|
82
|
+
};
|
|
83
|
+
const context: PluginContext = {
|
|
84
|
+
logger,
|
|
85
|
+
sessions: () => linked ?? unlinked("sessions"),
|
|
86
|
+
queue: new ChannelQueue(),
|
|
87
|
+
toolTiers: tiers,
|
|
88
|
+
events: {
|
|
89
|
+
turnStarted: (turn) => {
|
|
90
|
+
events.push({ name: "turnStarted", turn });
|
|
91
|
+
bus.sink.turnStarted(turn);
|
|
92
|
+
},
|
|
93
|
+
turnEnded: (turn) => {
|
|
94
|
+
events.push({ name: "turnEnded", turn });
|
|
95
|
+
bus.sink.turnEnded(turn);
|
|
96
|
+
},
|
|
97
|
+
changed: () => {
|
|
98
|
+
events.push({ name: "changed" });
|
|
99
|
+
bus.sink.changed();
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
conversations,
|
|
103
|
+
database: () => {
|
|
104
|
+
if (!options.database) throw new PluginError("no database is configured");
|
|
105
|
+
return options.database;
|
|
106
|
+
},
|
|
107
|
+
core,
|
|
108
|
+
providers: { ...resolveProviders([plugin]), ...options.providers },
|
|
109
|
+
dashboard: () => (linked ? registry.dashboard : unlinked("dashboard")),
|
|
110
|
+
};
|
|
111
|
+
const registry = await collectContributions([plugin], context, tiers);
|
|
112
|
+
linked = linkSessions(registry);
|
|
113
|
+
bus.link(registry.handlers);
|
|
114
|
+
const contribution: Contribution = {
|
|
115
|
+
services: registry.services,
|
|
116
|
+
events: registry.handlers[0]?.events,
|
|
117
|
+
interactions: registry.interactions,
|
|
118
|
+
http: registry.routes,
|
|
119
|
+
holdRules: registry.holdRules,
|
|
120
|
+
piPackages: registry.piPackages,
|
|
121
|
+
sessionTools: registry.sessionTools,
|
|
122
|
+
channels: registry.channels,
|
|
123
|
+
dashboard: registry.dashboard,
|
|
124
|
+
tools: registry.tools,
|
|
125
|
+
seeds: registry.seeds,
|
|
126
|
+
prompt: registry.prompt,
|
|
127
|
+
...(registry.agentSelections.length > 0
|
|
128
|
+
? { agentSelection: linked.agentSelection }
|
|
129
|
+
: {}),
|
|
130
|
+
};
|
|
131
|
+
for (const service of registry.services) await service.start?.();
|
|
132
|
+
let stopped = false;
|
|
133
|
+
return {
|
|
134
|
+
contribution,
|
|
135
|
+
tools: registry.tools.map((tool) => tool.name),
|
|
136
|
+
tiers,
|
|
137
|
+
events,
|
|
138
|
+
async runTool(name, args, runOptions) {
|
|
139
|
+
const tool = registry.tools.find((item) => item.name === name);
|
|
140
|
+
if (!tool) throw new PluginError(`tool ${name} is not registered`);
|
|
141
|
+
const registered: {
|
|
142
|
+
execute(
|
|
143
|
+
id: string,
|
|
144
|
+
params: Record<string, unknown>,
|
|
145
|
+
signal?: AbortSignal,
|
|
146
|
+
): Promise<{
|
|
147
|
+
content: readonly { type: string; text?: string }[];
|
|
148
|
+
isError?: boolean;
|
|
149
|
+
}>;
|
|
150
|
+
}[] = [];
|
|
151
|
+
const session = {
|
|
152
|
+
kind: "agent",
|
|
153
|
+
homeChannel: "test:1",
|
|
154
|
+
turnChannel: "test:1",
|
|
155
|
+
compaction: { wrap: (factory) => factory },
|
|
156
|
+
speaker: () => runOptions?.speaker,
|
|
157
|
+
runTask: async () => {
|
|
158
|
+
throw new Error("test session cannot run tasks");
|
|
159
|
+
},
|
|
160
|
+
} satisfies SessionContext;
|
|
161
|
+
const factory = tool.session.snapshot().factory(session);
|
|
162
|
+
// SAFETY: defineTool's session factory only calls registerTool; the fake captures its definition.
|
|
163
|
+
factory?.({
|
|
164
|
+
registerTool: (definition: (typeof registered)[number]) => {
|
|
165
|
+
registered.push(definition);
|
|
166
|
+
},
|
|
167
|
+
} as unknown as ExtensionAPI);
|
|
168
|
+
const execute = registered[0]?.execute;
|
|
169
|
+
if (!execute)
|
|
170
|
+
throw new PluginError(`tool ${name} did not register in the session`);
|
|
171
|
+
const result = await execute("test-call", args);
|
|
172
|
+
return result.content.map((item) => item.text ?? "").join("\n");
|
|
173
|
+
},
|
|
174
|
+
async stop() {
|
|
175
|
+
if (stopped) return;
|
|
176
|
+
stopped = true;
|
|
177
|
+
await bus.deliver("shutdown", []);
|
|
178
|
+
for (const service of registry.services.toReversed())
|
|
179
|
+
await service.stop?.();
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copy this file to .env and fill it in. Bun loads .env by itself; never commit it.
|
|
2
|
+
|
|
3
|
+
# Discord: https://discord.com/developers/applications (create an application, add a bot).
|
|
4
|
+
# The bot needs the Message Content intent (Bot page) and an invite to your server.
|
|
5
|
+
DISCORD_TOKEN=
|
|
6
|
+
# Turn on Developer Mode in Discord, then right-click the server and the channel to copy their ids.
|
|
7
|
+
DISCORD_GUILD_ID=
|
|
8
|
+
DISCORD_ENTRY_CHANNEL_ID=
|
|
9
|
+
|
|
10
|
+
# You: the one owner who can change everything (right-click your name, Copy User ID).
|
|
11
|
+
OWNER_ID=
|
|
12
|
+
OWNER_NAME=
|
|
13
|
+
|
|
14
|
+
# PostgreSQL. This matches docker-compose.yml: run `docker compose up -d`.
|
|
15
|
+
DATABASE_URL=postgres://roundtable:roundtable@localhost:5432/roundtable
|
|
16
|
+
|
|
17
|
+
# The agents' model as <provider>/<id>, and the provider's API key (or log in with Pi and leave the key out).
|
|
18
|
+
MODEL=anthropic/claude-sonnet-5-5
|
|
19
|
+
# ANTHROPIC_API_KEY=
|
|
20
|
+
|
|
21
|
+
# The address that reaches this process from the internet; it serves the agents' avatars.
|
|
22
|
+
PUBLIC_URL=
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# __PROJECT__
|
|
2
|
+
|
|
3
|
+
A Discord agent server built on [pi-roundtable](https://www.npmjs.com/package/pi-roundtable).
|
|
4
|
+
|
|
5
|
+
1. Install: `bun install`, then copy `.env.example` to `.env` and fill it in.
|
|
6
|
+
2. Check: `bunx roundtable doctor` says what is still missing and how to fix it.
|
|
7
|
+
3. Run: `bunx roundtable start`.
|
|
8
|
+
|
|
9
|
+
`roundtable.config.ts` holds the settings and lists the plugins; `plugins/` holds yours.
|
|
10
|
+
Add another with `bunx roundtable add plugin <name>`, and test it with `bun test`.
|
|
11
|
+
The plugin guide is in `node_modules/pi-roundtable/docs/plugins.md` and on the package's page.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentSeed } from "pi-roundtable";
|
|
2
|
+
|
|
3
|
+
// The first team. An agent that is already stored is never overwritten, so edit agents in Discord afterwards.
|
|
4
|
+
export const agents: AgentSeed[] = [
|
|
5
|
+
{
|
|
6
|
+
name: "guide",
|
|
7
|
+
displayName: "Guide",
|
|
8
|
+
prompt:
|
|
9
|
+
"You are Guide, a friendly assistant. Answer briefly and ask when a request is unclear.",
|
|
10
|
+
avatarPrompt: "A friendly lighthouse keeper with a warm lantern",
|
|
11
|
+
},
|
|
12
|
+
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.5.14/schema.json",
|
|
3
|
+
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
|
|
4
|
+
"formatter": { "indentStyle": "tab" },
|
|
5
|
+
"linter": { "rules": { "preset": "recommended" } },
|
|
6
|
+
"javascript": { "formatter": { "quoteStyle": "double" } }
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
# PostgreSQL for local use; `docker compose up -d` matches DATABASE_URL in .env.example.
|
|
3
|
+
services:
|
|
4
|
+
postgres:
|
|
5
|
+
image: postgres:17
|
|
6
|
+
restart: unless-stopped
|
|
7
|
+
environment:
|
|
8
|
+
POSTGRES_USER: roundtable
|
|
9
|
+
POSTGRES_PASSWORD: roundtable
|
|
10
|
+
POSTGRES_DB: roundtable
|
|
11
|
+
ports:
|
|
12
|
+
- "5432:5432"
|
|
13
|
+
volumes:
|
|
14
|
+
- postgres:/var/lib/postgresql/data
|
|
15
|
+
volumes:
|
|
16
|
+
postgres:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"engines": {
|
|
6
|
+
"bun": ">=1.3.0"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"doctor": "roundtable doctor",
|
|
10
|
+
"start": "roundtable start",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"lint": "biome check .",
|
|
13
|
+
"test": "bun test"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"pi-roundtable": "__VERSION__",
|
|
17
|
+
"typebox": "1.3.34"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@biomejs/biome": "2.5.14",
|
|
21
|
+
"@types/bun": "1.4.2",
|
|
22
|
+
"typescript": "7.0.2"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { testPlugin } from "pi-roundtable/testing";
|
|
3
|
+
import { __IDENT__ } from "./__NAME__.ts";
|
|
4
|
+
|
|
5
|
+
test("__NAME__ adds a greeting tool for members", async () => {
|
|
6
|
+
const harness = await testPlugin(__IDENT__);
|
|
7
|
+
expect(harness.tools).toEqual(["__TOOL___greet"]);
|
|
8
|
+
expect(harness.tiers.minTier("__TOOL___greet")).toBe("member");
|
|
9
|
+
expect(await harness.runTool("__TOOL___greet", { who: "Ada" })).toBe(
|
|
10
|
+
"Hello, Ada!",
|
|
11
|
+
);
|
|
12
|
+
await harness.stop();
|
|
13
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { definePlugin, defineTool } from "pi-roundtable";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
|
|
4
|
+
/** A plugin adds parts to the bot; this one adds a single tool the agents can call. */
|
|
5
|
+
export const __IDENT__ = definePlugin({
|
|
6
|
+
name: "__NAME__",
|
|
7
|
+
setup: () => ({
|
|
8
|
+
tools: [
|
|
9
|
+
defineTool({
|
|
10
|
+
name: "__TOOL___greet",
|
|
11
|
+
description: "Greet someone by name. Call it when asked to say hello.",
|
|
12
|
+
parameters: Type.Object({ who: Type.String() }),
|
|
13
|
+
minTier: "member",
|
|
14
|
+
run: ({ who }) => `Hello, ${who}!`,
|
|
15
|
+
}),
|
|
16
|
+
],
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RoundtableConfig } from "pi-roundtable";
|
|
2
|
+
import { agents } from "./agents.ts";
|
|
3
|
+
import { hello } from "./plugins/hello.ts";
|
|
4
|
+
|
|
5
|
+
// Credentials and ids come from .env, which Bun loads on its own; nothing secret belongs in this file.
|
|
6
|
+
const env = (name: string): string => process.env[name] ?? "";
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
name: "Roundtable",
|
|
10
|
+
owner: { id: env("OWNER_ID"), name: env("OWNER_NAME") },
|
|
11
|
+
discord: {
|
|
12
|
+
token: env("DISCORD_TOKEN"),
|
|
13
|
+
guild: env("DISCORD_GUILD_ID"),
|
|
14
|
+
entryChannel: env("DISCORD_ENTRY_CHANNEL_ID"),
|
|
15
|
+
},
|
|
16
|
+
database: { url: env("DATABASE_URL") },
|
|
17
|
+
// Paths are relative to the project directory, where the roundtable command runs.
|
|
18
|
+
dataDir: "./data",
|
|
19
|
+
model: env("MODEL"),
|
|
20
|
+
http: { publicUrl: env("PUBLIC_URL") },
|
|
21
|
+
prompts: { shared: "./persona/shared.md" },
|
|
22
|
+
agents,
|
|
23
|
+
plugins: [hello],
|
|
24
|
+
} satisfies RoundtableConfig;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "Preserve",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ESNext"],
|
|
7
|
+
"types": ["bun"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUncheckedIndexedAccess": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"noEmit": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["*.ts", "plugins"]
|
|
16
|
+
}
|