pi-roundtable-webchat 0.25.0 → 0.26.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 +8 -0
- package/README.md +1 -1
- package/package.json +3 -3
- package/src/oidc.ts +4 -7
- package/src/plugin.ts +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.26.1] - 2026-10-30
|
|
9
|
+
|
|
10
|
+
- Release in lockstep with pi-roundtable 0.26.1; no package-specific behavior changes. The core peer range stays `>=0.26.0 <0.27.0`.
|
|
11
|
+
|
|
12
|
+
## [0.26.0] - 2026-10-30
|
|
13
|
+
|
|
14
|
+
The core peer range is now `>=0.26.0 <0.27.0`.
|
|
15
|
+
|
|
8
16
|
## [0.25.0] - 2026-10-29
|
|
9
17
|
|
|
10
18
|
- Release in lockstep with pi-roundtable 0.25.0; no package-specific behavior changes. The core peer range is now `>=0.25.0 <0.26.0`.
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ It needs no Discord: a host whose `roundtable.config.ts` has no `discord` key an
|
|
|
21
21
|
|
|
22
22
|
## Requirements
|
|
23
23
|
|
|
24
|
-
- Bun 1.4.4 or later, and pi-roundtable `>=0.
|
|
24
|
+
- Bun 1.4.4 or later, and pi-roundtable `>=0.26.0 <0.27.0` as a peer dependency. Uploading files needs `context.attachments`, which pi-roundtable added in 0.9.2: the plugin refuses to set up on an earlier core and names the version to install.
|
|
25
25
|
- An HTTP listener on the host (`http` in the configuration), behind a reverse proxy that serves it over HTTPS.
|
|
26
26
|
- An OpenID Connect provider that issues access tokens for this API, with signing keys published as a JWKS.
|
|
27
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-roundtable-webchat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.1",
|
|
4
4
|
"description": "A WebSocket chat adapter for pi-roundtable: private web conversations for people an OpenID Connect provider signs in, with live progress and approval cards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,14 +38,14 @@
|
|
|
38
38
|
"jose": "6.2.12"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"pi-roundtable": ">=0.
|
|
41
|
+
"pi-roundtable": ">=0.26.0 <0.27.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@biomejs/biome": "2.5.15",
|
|
45
45
|
"@earendil-works/pi-ai": ">=1.0.0 <2",
|
|
46
46
|
"@earendil-works/pi-coding-agent": ">=1.0.0 <2",
|
|
47
47
|
"@types/bun": "1.4.3",
|
|
48
|
-
"pi-roundtable": "0.
|
|
48
|
+
"pi-roundtable": "0.26.1",
|
|
49
49
|
"typebox": "1.3.37",
|
|
50
50
|
"typescript": "7.0.2"
|
|
51
51
|
}
|
package/src/oidc.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
jwtVerify,
|
|
7
7
|
} from "jose";
|
|
8
8
|
import type { ActorFacts } from "pi-roundtable";
|
|
9
|
+
import { oidcIdentity, oidcProvider } from "pi-roundtable/kit";
|
|
9
10
|
|
|
10
11
|
/** Who a verified token names, and until when it may be trusted. */
|
|
11
12
|
export interface WebIdentity {
|
|
@@ -38,15 +39,13 @@ export class TokenRefused extends Error {
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const PREFIX = "oidc";
|
|
42
|
-
|
|
43
42
|
/**
|
|
44
43
|
* The speaker id of an OpenID subject: `oidc:<base64url(issuer)>:<subject>`. The issuer is
|
|
45
44
|
* encoded so its own colons stay apart from the subject's, and the id can be turned back into the
|
|
46
45
|
* pair with `parseOidcSpeakerId`. It never looks like a Discord id.
|
|
47
46
|
*/
|
|
48
47
|
export function oidcSpeakerId(issuer: string, subject: string): string {
|
|
49
|
-
return
|
|
48
|
+
return oidcIdentity(issuer, subject);
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
/** The issuer and subject of an id `oidcSpeakerId` made; undefined for any other id. */
|
|
@@ -79,9 +78,7 @@ export function identityActor(
|
|
|
79
78
|
const oidc = parseOidcSpeakerId(identity.id);
|
|
80
79
|
return {
|
|
81
80
|
...(identity.actor ?? {
|
|
82
|
-
provider: oidc
|
|
83
|
-
? `oidc:${Buffer.from(oidc.issuer).toString("base64url")}`
|
|
84
|
-
: surface,
|
|
81
|
+
provider: oidc ? oidcProvider(oidc.issuer) : surface,
|
|
85
82
|
subject: oidc?.subject ?? identity.id,
|
|
86
83
|
legacyId: identity.id,
|
|
87
84
|
}),
|
|
@@ -264,7 +261,7 @@ export function oidcJwtVerifier(
|
|
|
264
261
|
: [];
|
|
265
262
|
return {
|
|
266
263
|
actor: {
|
|
267
|
-
provider:
|
|
264
|
+
provider: oidcProvider(issuer),
|
|
268
265
|
subject,
|
|
269
266
|
name,
|
|
270
267
|
surface: "web",
|
package/src/plugin.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CONVERSATIONS,
|
|
3
|
+
ConfigError,
|
|
3
4
|
definePlugin,
|
|
4
5
|
type HttpRoute,
|
|
5
6
|
IDENTITY,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
type WebSocketAccept,
|
|
10
11
|
type WebSocketRoute,
|
|
11
12
|
} from "pi-roundtable";
|
|
13
|
+
import { SHELL_TOOLS } from "pi-roundtable/kit";
|
|
12
14
|
import {
|
|
13
15
|
type Admitted,
|
|
14
16
|
checkPersonas,
|
|
@@ -260,6 +262,9 @@ export function webChat(options: WebChatOptions): RoundtablePlugin {
|
|
|
260
262
|
throw new Error(
|
|
261
263
|
"webChat: this version keeps uploaded files with context.attachments, which pi-roundtable 0.9.2 added. Update pi-roundtable to 0.9.2 or later.",
|
|
262
264
|
);
|
|
265
|
+
// A chat-only host (pi-roundtable 0.26) withholds the shell from every turn; say so at start, not at the first turn.
|
|
266
|
+
if (context.env?.agentTools === "chat-only")
|
|
267
|
+
refuseShellPersonas(options.personas);
|
|
263
268
|
const chat = new WebChat({
|
|
264
269
|
surface,
|
|
265
270
|
...(options.formatting === undefined
|
|
@@ -409,3 +414,16 @@ export function webChat(options: WebChatOptions): RoundtablePlugin {
|
|
|
409
414
|
},
|
|
410
415
|
});
|
|
411
416
|
}
|
|
417
|
+
|
|
418
|
+
/** Refuses a persona whose own selection names a shell or file tool, which a chat-only host withholds. */
|
|
419
|
+
function refuseShellPersonas(personas: readonly WebPersona[]): void {
|
|
420
|
+
for (const persona of personas) {
|
|
421
|
+
const shell = (persona.selection?.tools ?? []).filter((tool) =>
|
|
422
|
+
(SHELL_TOOLS as readonly string[]).includes(tool),
|
|
423
|
+
);
|
|
424
|
+
if (shell.length > 0)
|
|
425
|
+
throw new ConfigError(
|
|
426
|
+
`webChat: persona "${persona.kind}" selects ${shell.join(", ")}, which agentServer: { tools: "chat-only" } withholds from every turn. Take the tool out of the persona's selection.`,
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
}
|