pi-roundtable 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +115 -0
- package/README.md +35 -11
- package/README.zh-TW.md +27 -10
- package/docs/migration-0.9.md +247 -0
- package/docs/plugins.md +618 -86
- package/examples/channel-context.test.ts +88 -0
- package/examples/channel-context.ts +62 -0
- package/examples/echo-runtime.test.ts +1 -0
- package/examples/fake-surface.test.ts +69 -6
- package/examples/fake-surface.ts +73 -7
- package/examples/headless.ts +5 -1
- package/examples/prechecks.test.ts +1 -0
- package/examples/principals.test.ts +60 -0
- package/examples/principals.ts +48 -0
- package/examples/prompt.test.ts +1 -1
- package/examples/study-room.test.ts +29 -1
- package/examples/study-room.ts +16 -19
- package/examples/support-desk.test.ts +3 -1
- package/examples/tools.test.ts +6 -1
- package/package.json +5 -2
- package/src/cli/checks/database.ts +11 -0
- package/src/cli/checks/identity.ts +225 -0
- package/src/cli/checks/model.ts +21 -3
- package/src/cli/cli.ts +115 -1
- package/src/cli/config-edit.ts +83 -13
- package/src/cli/doctor.ts +7 -0
- package/src/cli/line-diff.ts +72 -0
- package/src/cli/principal.ts +412 -0
- package/src/cli/project.ts +5 -0
- package/src/cli/report.ts +12 -3
- package/src/cli/upgrade-rewrite.ts +102 -0
- package/src/cli/upgrade-source.ts +430 -0
- package/src/cli/upgrade.ts +176 -0
- package/src/core/agents/agent-claim.ts +56 -34
- package/src/core/agents/team-turns.ts +8 -4
- package/src/core/builtin/agent-server.ts +9 -7
- package/src/core/builtin/discord-admin.ts +4 -1
- package/src/core/builtin/discord.ts +71 -13
- package/src/core/builtin/modules.ts +150 -86
- package/src/core/builtin/stores.ts +40 -21
- package/src/core/config/access.ts +229 -0
- package/src/core/config/adapters.ts +64 -1
- package/src/core/config/config.ts +87 -41
- package/src/core/contract/channel-context.ts +53 -0
- package/src/core/contract/channels.ts +82 -9
- package/src/core/contract/runtime.ts +23 -7
- package/src/core/contract/surface.ts +22 -6
- package/src/core/conversations/conversation-registry.ts +14 -0
- package/src/core/conversations/conversation-store.ts +13 -0
- package/src/core/define-roundtable.ts +42 -11
- package/src/core/discord/agent-panel.ts +2 -2
- package/src/core/discord/card-audience.ts +148 -0
- package/src/core/discord/channel-context.ts +348 -0
- package/src/core/discord/connection.ts +15 -3
- package/src/core/discord/direct-channel.ts +54 -0
- package/src/core/discord/discord-owners.ts +133 -0
- package/src/core/discord/discord-surface.ts +69 -14
- package/src/core/discord/fresh-marker.ts +24 -0
- package/src/core/discord/inbound-message.ts +21 -7
- package/src/core/discord/interaction-module.ts +11 -1
- package/src/core/discord/owner-cards-fixture.ts +80 -0
- package/src/core/discord/owner-cards.ts +58 -97
- package/src/core/discord/owner-command.ts +27 -13
- package/src/core/discord/stop-button.ts +4 -4
- package/src/core/domain/conversation.ts +7 -2
- package/src/core/domain/errors.ts +5 -0
- package/src/core/domain/ports.ts +27 -2
- package/src/core/drain.ts +56 -5
- package/src/core/errors.ts +13 -0
- package/src/core/host-background.ts +56 -0
- package/src/core/host.ts +52 -68
- package/src/core/i18n/cards.ts +8 -4
- package/src/core/i18n/conversation.ts +2 -0
- package/src/core/identity/access-policy.ts +227 -0
- package/src/core/identity/actor-facts.ts +65 -0
- package/src/core/identity/caching-principal-store.ts +111 -0
- package/src/core/identity/config-owner.ts +145 -0
- package/src/core/identity/contact.ts +27 -0
- package/src/core/identity/identity-plugin.ts +56 -0
- package/src/core/identity/identity-schema.ts +282 -0
- package/src/core/identity/identity-service.ts +489 -0
- package/src/core/identity/identity-view.ts +77 -0
- package/src/core/identity/plugin-identities.ts +109 -0
- package/src/core/identity/principal-reads.ts +38 -0
- package/src/core/identity/principal-store.ts +478 -0
- package/src/core/identity/principal-tables.ts +53 -0
- package/src/core/identity/seen-throttle.ts +57 -0
- package/src/core/identity/ulid.ts +36 -0
- package/src/core/identity.ts +34 -5
- package/src/core/interactions/prompts.ts +127 -0
- package/src/core/modules/background/background-turns.ts +56 -17
- package/src/core/modules/background/personal-target.ts +50 -0
- package/src/core/modules/delegation/delegate.ts +28 -14
- package/src/core/modules/delegation/delegator.ts +23 -7
- package/src/core/modules/memory/owner-memory.ts +123 -50
- package/src/core/modules/notify/notify.ts +53 -13
- package/src/core/modules/notify/session-notify.ts +110 -0
- package/src/core/modules/schedules/prechecks.ts +8 -2
- package/src/core/modules/schedules/schedule-prechecks.ts +4 -1
- package/src/core/modules/schedules/schedule-store.ts +51 -20
- package/src/core/modules/schedules/schedule-tools.ts +122 -12
- package/src/core/modules/schedules/scheduler.ts +56 -4
- package/src/core/modules/schedules/schedules.ts +43 -14
- package/src/core/plugin.ts +48 -0
- package/src/core/presence/direct-channels.ts +104 -0
- package/src/core/registry/contributions.ts +63 -3
- package/src/core/routing/channel-queue.ts +18 -1
- package/src/core/routing/channel-router.ts +274 -21
- package/src/core/routing/conversation-turns.ts +45 -10
- package/src/core/routing/surface-port.ts +32 -2
- package/src/core/routing/system-turns.ts +29 -0
- package/src/core/runtime/abort-guard.ts +58 -0
- package/src/core/runtime/bridge-guard.ts +225 -0
- package/src/core/runtime/compaction-tiers.ts +5 -1
- package/src/core/runtime/conversation-sessions.ts +139 -12
- package/src/core/runtime/extensions/ask-user.ts +1 -1
- package/src/core/runtime/extensions/confirmation-gate.ts +28 -14
- package/src/core/runtime/extensions/private-memory.ts +447 -0
- package/src/core/runtime/pending-confirmation-store.ts +30 -5
- package/src/core/runtime/pi-agent-runtime.ts +174 -190
- package/src/core/runtime/preflight-tools.ts +47 -0
- package/src/core/runtime/prompt-slot.ts +4 -4
- package/src/core/runtime/reader-history.ts +129 -0
- package/src/core/runtime/runtime-plugin.ts +51 -5
- package/src/core/runtime/runtime-types.ts +48 -12
- package/src/core/runtime/session-conversation.ts +143 -0
- package/src/core/runtime/session-factory.ts +115 -15
- package/src/core/runtime/session-scope.ts +78 -0
- package/src/core/runtime/steerable-run.ts +21 -3
- package/src/core/runtime/thinking-level.ts +47 -0
- package/src/core/runtime/tool-call-scope.ts +43 -0
- package/src/core/runtime/turn-answer.ts +30 -1
- package/src/core/runtime/turn-wrapup.ts +63 -0
- package/src/core/services.ts +27 -1
- package/src/core/sessions.ts +30 -0
- package/src/core/speakers.ts +21 -19
- package/src/core/testing/background.ts +31 -0
- package/src/core/testing/fixture-database.ts +55 -0
- package/src/core/testing/map-identity.ts +76 -0
- package/src/core/testing/module-sessions.ts +134 -0
- package/src/core/testing/modules.ts +108 -21
- package/src/core/testing/owner.ts +17 -0
- package/src/core/testing/surface-contract.ts +118 -41
- package/src/core/testing/test-host.ts +79 -16
- package/src/core/testing/tool-set.ts +32 -0
- package/src/core/tool-set.snapshot.json +4 -4
- package/src/core/tool-tiers.ts +57 -3
- package/src/discord/index.ts +8 -0
- package/src/index.ts +48 -8
- package/src/kit/compaction.ts +13 -0
- package/src/kit/index.ts +10 -0
- package/src/kit/support.ts +1 -1
- package/src/testing.ts +55 -16
- package/templates/.env.example +1 -1
- package/templates/adapters/web/README.md +7 -0
- package/templates/adapters/web/roundtable.config.ts +14 -10
- package/templates/roundtable.config.ts +12 -1
- package/src/core/domain/owner-prompts.ts +0 -45
package/src/index.ts
CHANGED
|
@@ -20,8 +20,14 @@ export {
|
|
|
20
20
|
AGENT_SERVER_PLUGIN,
|
|
21
21
|
AGENT_TEAM_SERVICE,
|
|
22
22
|
} from "./core/builtin/agent-server.ts";
|
|
23
|
+
export type {
|
|
24
|
+
AccessConfig,
|
|
25
|
+
AccessOwnerConfig,
|
|
26
|
+
AccessTierConfig,
|
|
27
|
+
} from "./core/config/access.ts";
|
|
23
28
|
export type {
|
|
24
29
|
AdapterConfig,
|
|
30
|
+
BackgroundConfig,
|
|
25
31
|
DiscordConfig,
|
|
26
32
|
Pronouns,
|
|
27
33
|
RoundtableConfig,
|
|
@@ -30,6 +36,7 @@ export type {
|
|
|
30
36
|
export type {
|
|
31
37
|
Admission,
|
|
32
38
|
AttachmentRef,
|
|
39
|
+
BackgroundRunsAs,
|
|
33
40
|
BackgroundTarget,
|
|
34
41
|
BackgroundTurn,
|
|
35
42
|
ChannelClaim,
|
|
@@ -93,6 +100,7 @@ export {
|
|
|
93
100
|
AgentRunError,
|
|
94
101
|
ConfigError,
|
|
95
102
|
DelegationError,
|
|
103
|
+
IdentityError,
|
|
96
104
|
MemoryError,
|
|
97
105
|
ScheduleError,
|
|
98
106
|
} from "./core/domain/errors.ts";
|
|
@@ -101,17 +109,11 @@ export type {
|
|
|
101
109
|
InterimPosts,
|
|
102
110
|
InterimTextMode,
|
|
103
111
|
} from "./core/domain/interim.ts";
|
|
104
|
-
export type {
|
|
105
|
-
Approval,
|
|
106
|
-
AskOption,
|
|
107
|
-
OwnerAnswer,
|
|
108
|
-
OwnerPrompts,
|
|
109
|
-
OwnerQuestion,
|
|
110
|
-
} from "./core/domain/owner-prompts.ts";
|
|
111
|
-
export type { TurnRequest } from "./core/domain/ports.ts";
|
|
112
|
+
export type { TurnConversation, TurnRequest } from "./core/domain/ports.ts";
|
|
112
113
|
export type { TurnProgress } from "./core/domain/progress.ts";
|
|
113
114
|
export type { DrainOptions } from "./core/drain.ts";
|
|
114
115
|
export {
|
|
116
|
+
HostStoppingError,
|
|
115
117
|
JudgeError,
|
|
116
118
|
MigrationError,
|
|
117
119
|
NotLinkedError,
|
|
@@ -133,9 +135,39 @@ export type {
|
|
|
133
135
|
WebSocketSendResult,
|
|
134
136
|
} from "./core/http/websocket.ts";
|
|
135
137
|
export type { Locale } from "./core/i18n/index.ts";
|
|
138
|
+
export type {
|
|
139
|
+
AccessOwner,
|
|
140
|
+
AccessRules,
|
|
141
|
+
AccessTier,
|
|
142
|
+
} from "./core/identity/access-policy.ts";
|
|
143
|
+
export type { ActorFacts } from "./core/identity/actor-facts.ts";
|
|
144
|
+
export type { IdentityService } from "./core/identity/identity-service.ts";
|
|
145
|
+
export type {
|
|
146
|
+
IdentityLink,
|
|
147
|
+
IdentityRef,
|
|
148
|
+
LinkSource,
|
|
149
|
+
Principal,
|
|
150
|
+
RoleGrant,
|
|
151
|
+
RoleSource,
|
|
152
|
+
} from "./core/identity/principal-store.ts";
|
|
153
|
+
export { SYSTEM_PRINCIPAL } from "./core/identity/principal-store.ts";
|
|
154
|
+
export type {
|
|
155
|
+
Approval,
|
|
156
|
+
AskOption,
|
|
157
|
+
OwnerAnswer,
|
|
158
|
+
OwnerPrompts,
|
|
159
|
+
OwnerQuestion,
|
|
160
|
+
PromptScope,
|
|
161
|
+
Prompts,
|
|
162
|
+
} from "./core/interactions/prompts.ts";
|
|
163
|
+
export { promptScope } from "./core/interactions/prompts.ts";
|
|
136
164
|
export type { JudgeModel } from "./core/judging/model-judge.ts";
|
|
137
165
|
export type { LogEntry, LogFn, Logger } from "./core/log.ts";
|
|
138
166
|
export type { ThinkingLevel, ThinkingSetting } from "./core/models.ts";
|
|
167
|
+
export {
|
|
168
|
+
PERSONAL_TARGET,
|
|
169
|
+
type PerPrincipalLimits,
|
|
170
|
+
} from "./core/modules/background/personal-target.ts";
|
|
139
171
|
export type {
|
|
140
172
|
DelegationJob,
|
|
141
173
|
DelegationOutcome,
|
|
@@ -184,6 +216,7 @@ export type {
|
|
|
184
216
|
LinkedSessions,
|
|
185
217
|
Persona,
|
|
186
218
|
PluginContext,
|
|
219
|
+
PluginIdentity,
|
|
187
220
|
PromptSection,
|
|
188
221
|
PromptTurn,
|
|
189
222
|
RoundtablePlugin,
|
|
@@ -194,6 +227,11 @@ export type {
|
|
|
194
227
|
TurnEvent,
|
|
195
228
|
TurnProgressEvent,
|
|
196
229
|
} from "./core/plugin.ts";
|
|
230
|
+
export type {
|
|
231
|
+
DirectChannelProvider,
|
|
232
|
+
DirectChannels,
|
|
233
|
+
DirectReach,
|
|
234
|
+
} from "./core/presence/direct-channels.ts";
|
|
197
235
|
export {
|
|
198
236
|
attachReplyFile,
|
|
199
237
|
REPLY_FILE_LIMITS,
|
|
@@ -223,6 +261,7 @@ export {
|
|
|
223
261
|
BACKGROUND_TURNS,
|
|
224
262
|
CONVERSATIONS,
|
|
225
263
|
DELEGATION,
|
|
264
|
+
IDENTITY,
|
|
226
265
|
MEMORY,
|
|
227
266
|
PRECHECKS,
|
|
228
267
|
RUNTIME,
|
|
@@ -233,6 +272,7 @@ export type {
|
|
|
233
272
|
AgentTurnScope,
|
|
234
273
|
ChannelKey,
|
|
235
274
|
SessionContext,
|
|
275
|
+
SessionConversation,
|
|
236
276
|
SessionPlan,
|
|
237
277
|
SessionTool,
|
|
238
278
|
SessionToolSnapshot,
|
package/src/kit/compaction.ts
CHANGED
|
@@ -12,3 +12,16 @@ export {
|
|
|
12
12
|
HARD_COMPACT_TOKENS,
|
|
13
13
|
SOFT_COMPACT_TOKENS,
|
|
14
14
|
} from "../core/runtime/compaction-tiers.ts";
|
|
15
|
+
export type { MemoryView } from "../core/runtime/extensions/private-memory.ts";
|
|
16
|
+
export {
|
|
17
|
+
hidesPrivateExchange,
|
|
18
|
+
memoryProjection,
|
|
19
|
+
privateCompaction,
|
|
20
|
+
summaryProjection,
|
|
21
|
+
} from "../core/runtime/extensions/private-memory.ts";
|
|
22
|
+
export {
|
|
23
|
+
bridgeHistoryHidesMemory,
|
|
24
|
+
carriesMemory,
|
|
25
|
+
MEMORY_TURN_ENTRY,
|
|
26
|
+
recordMemoryTurn,
|
|
27
|
+
} from "../core/runtime/reader-history.ts";
|
package/src/kit/index.ts
CHANGED
|
@@ -18,13 +18,22 @@ export type {
|
|
|
18
18
|
CompactionEngine,
|
|
19
19
|
CompactionHistory,
|
|
20
20
|
LatestCompaction,
|
|
21
|
+
MemoryView,
|
|
21
22
|
} from "./compaction.ts";
|
|
22
23
|
export {
|
|
24
|
+
bridgeHistoryHidesMemory,
|
|
23
25
|
COMPACT_HEADROOM_TOKENS,
|
|
24
26
|
CompactionTiers,
|
|
27
|
+
carriesMemory,
|
|
25
28
|
compactionEngine,
|
|
26
29
|
HARD_COMPACT_TOKENS,
|
|
30
|
+
hidesPrivateExchange,
|
|
31
|
+
MEMORY_TURN_ENTRY,
|
|
32
|
+
memoryProjection,
|
|
33
|
+
privateCompaction,
|
|
34
|
+
recordMemoryTurn,
|
|
27
35
|
SOFT_COMPACT_TOKENS,
|
|
36
|
+
summaryProjection,
|
|
28
37
|
} from "./compaction.ts";
|
|
29
38
|
export { scrubDiagnostic } from "./diagnostics.ts";
|
|
30
39
|
export type {
|
|
@@ -122,6 +131,7 @@ export type {
|
|
|
122
131
|
DashboardBoard,
|
|
123
132
|
DelegationWorker,
|
|
124
133
|
GroupMessage,
|
|
134
|
+
Notifier,
|
|
125
135
|
OwnerNotifier,
|
|
126
136
|
SpeakerFacts,
|
|
127
137
|
SpeakerPolicy,
|
package/src/kit/support.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type {
|
|
|
13
13
|
export type { Backlog, GroupMessage } from "../core/agents/agent-rules.ts";
|
|
14
14
|
export type { AgentOps } from "../core/agents/agent-tools.ts";
|
|
15
15
|
export type { ThreadHost } from "../core/discord/dispatch-threads.ts";
|
|
16
|
-
export type { OwnerNotifier } from "../core/domain/ports.ts";
|
|
16
|
+
export type { Notifier, OwnerNotifier } from "../core/domain/ports.ts";
|
|
17
17
|
export type { ThinkingPicker } from "../core/models.ts";
|
|
18
18
|
export type { DelegationWorker } from "../core/modules/delegation/delegator.ts";
|
|
19
19
|
export type { AgentChannelLookup } from "../core/modules/schedules/schedules.ts";
|
package/src/testing.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
5
5
|
import type { SQL } from "bun";
|
|
6
|
-
import { agentClaim
|
|
7
|
-
import { DISCORD } from "./core/builtin/discord.ts";
|
|
6
|
+
import { agentClaim } from "./core/agents/agent-claim.ts";
|
|
7
|
+
import { DISCORD, type DiscordServices } from "./core/builtin/discord.ts";
|
|
8
8
|
import type {
|
|
9
9
|
ConversationPort,
|
|
10
10
|
InboundMessage,
|
|
@@ -24,7 +24,10 @@ import type {
|
|
|
24
24
|
CommandRegistrar,
|
|
25
25
|
InteractionContribution,
|
|
26
26
|
} from "./core/discord/interaction-module.ts";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
commandGuard,
|
|
29
|
+
ownerRootCommand,
|
|
30
|
+
} from "./core/discord/owner-command.ts";
|
|
28
31
|
import type {
|
|
29
32
|
PendingConfirmation,
|
|
30
33
|
ReplyFile,
|
|
@@ -32,10 +35,12 @@ import type {
|
|
|
32
35
|
import { NotLinkedError, PluginError } from "./core/errors.ts";
|
|
33
36
|
import { EventBus } from "./core/events.ts";
|
|
34
37
|
import type { HoldCheck } from "./core/holds.ts";
|
|
38
|
+
import { contactsOf } from "./core/identity/identity-view.ts";
|
|
35
39
|
import type { OwnerIdentity } from "./core/identity.ts";
|
|
36
40
|
import { ConfirmationJudge } from "./core/judging/confirmation-judge.ts";
|
|
37
41
|
import { silentLogger } from "./core/log.ts";
|
|
38
42
|
import { ConversationBackgroundTurns } from "./core/modules/background/background-turns.ts";
|
|
43
|
+
import { PERSONAL_TARGET } from "./core/modules/background/personal-target.ts";
|
|
39
44
|
import type {
|
|
40
45
|
Contribution,
|
|
41
46
|
HostEnv,
|
|
@@ -69,10 +74,12 @@ import {
|
|
|
69
74
|
type AgentServer,
|
|
70
75
|
BACKGROUND_TURNS,
|
|
71
76
|
CONVERSATIONS,
|
|
77
|
+
IDENTITY,
|
|
72
78
|
RUNTIME,
|
|
73
79
|
} from "./core/services.ts";
|
|
74
80
|
import type { ChannelKey, SessionContext } from "./core/sessions.ts";
|
|
75
|
-
import { type Speaker,
|
|
81
|
+
import { type Speaker, THE_SPEAKER } from "./core/speakers.ts";
|
|
82
|
+
import { mapIdentity } from "./core/testing/map-identity.ts";
|
|
76
83
|
import { type ToolTierTable, toolTiers } from "./core/tool-tiers.ts";
|
|
77
84
|
|
|
78
85
|
// Fixtures for plugin tests.
|
|
@@ -107,6 +114,7 @@ export type {
|
|
|
107
114
|
} from "./core/testing/recording-logger.ts";
|
|
108
115
|
export { recordingLogger } from "./core/testing/recording-logger.ts";
|
|
109
116
|
export type {
|
|
117
|
+
SurfaceContractAnswerer,
|
|
110
118
|
SurfaceContractFailure,
|
|
111
119
|
SurfaceContractSubject,
|
|
112
120
|
SurfaceObservation,
|
|
@@ -155,20 +163,30 @@ export interface FakeDiscord {
|
|
|
155
163
|
/**
|
|
156
164
|
* A `DISCORD` service for a plugin that adds slash commands, without a Discord connection: the
|
|
157
165
|
* plugin's `commands.add` calls are recorded, and `compose()` shows the tree Discord would get.
|
|
158
|
-
* `rootCommand` is the root command's name, `roundtable` by default.
|
|
166
|
+
* `rootCommand` is the root command's name, `roundtable` by default. `channelContext` is what
|
|
167
|
+
* `DISCORD.channelContext` answers, by default no context, as on a host with it off. Only
|
|
168
|
+
* `commands`, `guard`, and `channelContext` are given; reading another member throws.
|
|
159
169
|
*/
|
|
160
170
|
export function fakeDiscord(
|
|
161
|
-
options: {
|
|
171
|
+
options: {
|
|
172
|
+
ownerId?: string;
|
|
173
|
+
rootCommand?: string;
|
|
174
|
+
channelContext?: DiscordServices["channelContext"];
|
|
175
|
+
} = {},
|
|
162
176
|
): FakeDiscord {
|
|
163
177
|
const collection = new CommandCollection();
|
|
164
178
|
const { rootCommand = "roundtable" } = options;
|
|
165
|
-
const guard =
|
|
166
|
-
options.ownerId ?? "owner",
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
);
|
|
179
|
+
const guard = commandGuard({
|
|
180
|
+
ownerId: options.ownerId ?? "owner",
|
|
181
|
+
root: rootCommand,
|
|
182
|
+
logger: silentLogger(),
|
|
183
|
+
});
|
|
170
184
|
return {
|
|
171
|
-
service: servicePair(DISCORD, {
|
|
185
|
+
service: servicePair(DISCORD, {
|
|
186
|
+
commands: collection.registrar,
|
|
187
|
+
guard,
|
|
188
|
+
channelContext: options.channelContext ?? (async () => undefined),
|
|
189
|
+
}),
|
|
172
190
|
commands: collection.registrar,
|
|
173
191
|
guard,
|
|
174
192
|
added: () => collection.added(),
|
|
@@ -201,7 +219,9 @@ export interface TestPluginOptions {
|
|
|
201
219
|
* host supplies anyway: `BACKGROUND_TURNS`, the real background turns over the test's router,
|
|
202
220
|
* and, once `AGENTS` is given, its `approvals` (the real confirmation judge over
|
|
203
221
|
* `providers.judge`, when the test gives a judge). Giving `AGENTS` a `team` adds the agent
|
|
204
|
-
* server's own claim to the router, answering as the host's would for the `owner`.
|
|
222
|
+
* server's own claim to the router, answering as the host's would for the `owner`. The router
|
|
223
|
+
* resolves who wrote each message through a given `IDENTITY`; without one only the `owner` is
|
|
224
|
+
* anyone, at the owner tier, their principal their id.
|
|
205
225
|
*/
|
|
206
226
|
services?: readonly ServicePair[];
|
|
207
227
|
/**
|
|
@@ -333,6 +353,7 @@ export async function testPlugin(
|
|
|
333
353
|
(router ?? unlinked("conversations")).handle(message),
|
|
334
354
|
background: async (turn) =>
|
|
335
355
|
(router ?? unlinked("conversations")).background(turn),
|
|
356
|
+
runsAs: async (turn) => (router ?? unlinked("conversations")).runsAs(turn),
|
|
336
357
|
target: (name) => (router ?? unlinked("conversations")).target(name),
|
|
337
358
|
startFresh: async (channel) =>
|
|
338
359
|
(router ?? unlinked("conversations")).startFresh(channel),
|
|
@@ -344,6 +365,8 @@ export async function testPlugin(
|
|
|
344
365
|
owns: (channel) => (router ?? unlinked("conversations")).owns(channel),
|
|
345
366
|
takesBackground: (channel) =>
|
|
346
367
|
(router ?? unlinked("conversations")).takesBackground(channel),
|
|
368
|
+
takesSystemReports: (channel) =>
|
|
369
|
+
(router ?? unlinked("conversations")).takesSystemReports(channel),
|
|
347
370
|
...options.conversations,
|
|
348
371
|
};
|
|
349
372
|
const surfaces = surfacePort(() =>
|
|
@@ -463,7 +486,7 @@ export async function testPlugin(
|
|
|
463
486
|
}),
|
|
464
487
|
);
|
|
465
488
|
services.checkRequires();
|
|
466
|
-
const context: Omit<PluginContext, "services"> = {
|
|
489
|
+
const context: Omit<PluginContext, "services" | "directChannels"> = {
|
|
467
490
|
logger,
|
|
468
491
|
env,
|
|
469
492
|
sessions: () => linked ?? unlinked("sessions"),
|
|
@@ -496,13 +519,17 @@ export async function testPlugin(
|
|
|
496
519
|
const team = given.get(AGENTS.id)?.given;
|
|
497
520
|
const agentServer = team && "team" in team ? services.get(AGENTS) : undefined;
|
|
498
521
|
const attachmentDir = mkdtempSync(join(tmpdir(), "roundtable-test-plugin-"));
|
|
522
|
+
const identity = services.find(IDENTITY);
|
|
523
|
+
// Who wrote a message, and whom a background turn runs as: by the given IDENTITY, else the owner alone, at the owner tier.
|
|
524
|
+
const people = mapIdentity({ owners: [owner.id] });
|
|
499
525
|
router = new ChannelRouter({
|
|
526
|
+
contacts: identity ? contactsOf(identity) : people,
|
|
527
|
+
principals: identity ?? people,
|
|
500
528
|
claims: [
|
|
501
529
|
...(agentServer
|
|
502
530
|
? [
|
|
503
531
|
agentClaim({
|
|
504
532
|
owner,
|
|
505
|
-
speakers: speakerPolicy({ owners: [owner.id] }),
|
|
506
533
|
// SAFETY: the claim reads the concrete team's members (guildId, owns, answerOwner, answerGroup, answerBackground, startFresh), which a test that gives a team for it supplies.
|
|
507
534
|
team: agentServer.team as unknown as Parameters<
|
|
508
535
|
typeof agentClaim
|
|
@@ -514,6 +541,13 @@ export async function testPlugin(
|
|
|
514
541
|
surface: surfaces,
|
|
515
542
|
attachmentDir: () => attachmentDir,
|
|
516
543
|
logger,
|
|
544
|
+
// As on a host: the given DISCORD's channel context, when the test gives one.
|
|
545
|
+
channelContext: async (message) =>
|
|
546
|
+
(
|
|
547
|
+
given.get(DISCORD.id)?.given as
|
|
548
|
+
| Partial<DiscordServices>
|
|
549
|
+
| undefined
|
|
550
|
+
)?.channelContext?.(message),
|
|
517
551
|
}),
|
|
518
552
|
]
|
|
519
553
|
: []),
|
|
@@ -521,7 +555,9 @@ export async function testPlugin(
|
|
|
521
555
|
],
|
|
522
556
|
targets: (name) =>
|
|
523
557
|
registry.backgroundTargets.find((t) => t.name === name) ??
|
|
524
|
-
(agentServer && name ===
|
|
558
|
+
(agentServer && name === PERSONAL_TARGET.name
|
|
559
|
+
? PERSONAL_TARGET
|
|
560
|
+
: undefined),
|
|
525
561
|
queue,
|
|
526
562
|
logger,
|
|
527
563
|
...(options.forwardJoinMs === undefined
|
|
@@ -586,6 +622,9 @@ export async function testPlugin(
|
|
|
586
622
|
homeChannel: channel,
|
|
587
623
|
turnChannel: channel,
|
|
588
624
|
compaction: { wrap: (factory) => factory },
|
|
625
|
+
conversation: { visibility: "shared" },
|
|
626
|
+
addressee: THE_SPEAKER,
|
|
627
|
+
memory: "speaker",
|
|
589
628
|
speaker: () => runOptions?.speaker,
|
|
590
629
|
runTask: async () => {
|
|
591
630
|
throw new Error("test session cannot run tasks");
|
package/templates/.env.example
CHANGED
|
@@ -7,7 +7,7 @@ DISCORD_TOKEN=
|
|
|
7
7
|
DISCORD_GUILD_ID=
|
|
8
8
|
DISCORD_ENTRY_CHANNEL_ID=
|
|
9
9
|
|
|
10
|
-
# You: the
|
|
10
|
+
# You: the owner, who can change everything; OWNER_ID is your Discord user id (right-click your name, Copy User ID).
|
|
11
11
|
OWNER_ID=
|
|
12
12
|
OWNER_NAME=
|
|
13
13
|
|
|
@@ -9,6 +9,13 @@ People your OpenID Connect provider signs in chat with the assistant in private
|
|
|
9
9
|
|
|
10
10
|
The chat is under `/chat`: a web page gets a one-time ticket from `POST /chat/tickets` with the person's token, and opens `/chat/socket` with it.
|
|
11
11
|
The protocol is in `node_modules/pi-roundtable-webchat/README.md`.
|
|
12
|
+
Core `access` in `roundtable.config.ts` decides admission; token roles are prefixed with `web:role:` there.
|
|
13
|
+
New admitted users get principals, and linked Discord/web identities share private memory and quotas.
|
|
14
|
+
Link identities with `bunx roundtable principal link <principal> <identity>`; use `principal list` to inspect them.
|
|
15
|
+
|
|
16
|
+
The private inbox is `GET /chat/notices`, with `POST /chat/notices/<id>/read` to acknowledge an entry.
|
|
17
|
+
Online connections also receive additive `notice` frames.
|
|
18
|
+
Schedules and delegated reports can answer in their creator's private conversation; enable their tools in the persona selection only where intended and allowed by tier.
|
|
12
19
|
|
|
13
20
|
`roundtable.config.ts` holds the settings and lists the plugins; `plugins/` holds yours, and `persona/assistant.md` is the assistant's prompt.
|
|
14
21
|
Add another plugin with `bunx roundtable add plugin <name>`, and test it with `bun test`.
|
|
@@ -14,8 +14,17 @@ const list = (name: string): string[] =>
|
|
|
14
14
|
|
|
15
15
|
export default {
|
|
16
16
|
name: "Roundtable",
|
|
17
|
-
// The operator who runs this host. People sign in through your OpenID
|
|
18
|
-
|
|
17
|
+
// The operator who runs this host, as the host's owner. People sign in through your OpenID
|
|
18
|
+
// Connect provider instead; core access maps their verified, surface-prefixed roles to tiers.
|
|
19
|
+
access: {
|
|
20
|
+
owners: [{ name: env("OWNER_NAME"), principal: "operator" }],
|
|
21
|
+
members: {
|
|
22
|
+
roles: list("CHAT_MEMBER_ROLES").map((role) => `web:role:${role}`),
|
|
23
|
+
},
|
|
24
|
+
admins: {
|
|
25
|
+
roles: list("CHAT_ADMIN_ROLES").map((role) => `web:role:${role}`),
|
|
26
|
+
},
|
|
27
|
+
},
|
|
19
28
|
database: { url: env("DATABASE_URL") },
|
|
20
29
|
// Paths are relative to the project directory, where the roundtable command runs.
|
|
21
30
|
dataDir: "./data",
|
|
@@ -33,20 +42,15 @@ export default {
|
|
|
33
42
|
issuers: [env("OIDC_ISSUER")],
|
|
34
43
|
audiences: [env("OIDC_AUDIENCE")],
|
|
35
44
|
}),
|
|
36
|
-
// Members and admins come from the token's roles; owners only from speaker ids you list.
|
|
37
|
-
access: {
|
|
38
|
-
members: { roles: list("CHAT_MEMBER_ROLES") },
|
|
39
|
-
admins: { roles: list("CHAT_ADMIN_ROLES") },
|
|
40
|
-
},
|
|
41
45
|
origins: list("CHAT_ORIGINS"),
|
|
42
46
|
personas: [
|
|
43
47
|
{
|
|
44
48
|
kind: "assistant",
|
|
45
49
|
label: "Assistant",
|
|
46
50
|
prompt: () => readFileSync("./persona/assistant.md", "utf8"),
|
|
47
|
-
// The tools of its turns, by name.
|
|
48
|
-
// conversation
|
|
49
|
-
// may make
|
|
51
|
+
// The tools of its turns, by name. Schedules, delegated reports and notify can reach
|
|
52
|
+
// this private conversation; add those tools only where intended and permitted by tier.
|
|
53
|
+
// Leave out web_search and fetch_content unless people may make the server fetch any address.
|
|
50
54
|
selection: { tools: ["hello_greet"], groups: [] },
|
|
51
55
|
},
|
|
52
56
|
],
|
|
@@ -8,7 +8,18 @@ const env = (name: string): string => process.env[name] ?? "";
|
|
|
8
8
|
|
|
9
9
|
export default {
|
|
10
10
|
name: "Roundtable",
|
|
11
|
-
owner:
|
|
11
|
+
// Who the host serves. You are the owner: your principal and your Discord identity are your
|
|
12
|
+
// Discord user id. Add admins and members by Discord user or role, such as
|
|
13
|
+
// members: { roles: ["discord:role:<role id>"] }.
|
|
14
|
+
access: {
|
|
15
|
+
owners: [
|
|
16
|
+
{
|
|
17
|
+
name: env("OWNER_NAME"),
|
|
18
|
+
principal: env("OWNER_ID"),
|
|
19
|
+
identities: [`discord:${env("OWNER_ID")}`],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
12
23
|
discord: {
|
|
13
24
|
token: env("DISCORD_TOKEN"),
|
|
14
25
|
guild: env("DISCORD_GUILD_ID"),
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { Tier } from "../speakers.ts";
|
|
2
|
-
/**
|
|
3
|
-
* The owner answering inside a running turn: a card in the turn's channel that only they may
|
|
4
|
-
* answer. Unanswered cards expire; a stopped turn cancels its open cards.
|
|
5
|
-
*/
|
|
6
|
-
export type Approval = "approved" | "declined" | "expired" | "cancelled";
|
|
7
|
-
|
|
8
|
-
export interface AskOption {
|
|
9
|
-
label: string;
|
|
10
|
-
description?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface OwnerQuestion {
|
|
14
|
-
question: string;
|
|
15
|
-
/** Up to 25; none means a free-text answer. */
|
|
16
|
-
options: readonly AskOption[];
|
|
17
|
-
/** More than one option may be chosen. */
|
|
18
|
-
multi: boolean;
|
|
19
|
-
/** They may write an answer of their own besides the options. */
|
|
20
|
-
allowOther: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface OwnerAnswer {
|
|
24
|
-
/** The chosen options' labels, in the order they were offered. */
|
|
25
|
-
choices: string[];
|
|
26
|
-
/** What they wrote himself, if anything. */
|
|
27
|
-
text?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface OwnerPrompts {
|
|
31
|
-
/** Asks them to approve an action; `signal` cancels the card when the turn stops. */
|
|
32
|
-
confirm(
|
|
33
|
-
title: string,
|
|
34
|
-
message: string,
|
|
35
|
-
signal?: AbortSignal,
|
|
36
|
-
/** The tier the turn's speaker needs to approve it themselves; the owner may always approve, and only the owner when absent. */
|
|
37
|
-
minTier?: Tier,
|
|
38
|
-
): Promise<Approval>;
|
|
39
|
-
/** Asks them a question; undefined when it expired or was cancelled. */
|
|
40
|
-
ask(
|
|
41
|
-
title: string,
|
|
42
|
-
question: OwnerQuestion,
|
|
43
|
-
signal?: AbortSignal,
|
|
44
|
-
): Promise<OwnerAnswer | undefined>;
|
|
45
|
-
}
|