jeopi-cli 16.6.11 → 16.6.13
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 +22 -0
- package/README.md +34 -9
- package/dist/cli.js +3662 -3649
- package/dist/types/cli/update-cli.d.ts +9 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/messenger/activity.d.ts +7 -0
- package/dist/types/messenger/artifacts.d.ts +12 -0
- package/dist/types/messenger/gateway.d.ts +5 -1
- package/dist/types/messenger/live-session.d.ts +4 -0
- package/dist/types/messenger/types.d.ts +18 -1
- package/dist/types/session/agent-session.d.ts +3 -1
- package/package.json +12 -12
- package/src/cli/update-cli.ts +13 -3
- package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +2 -0
- package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +8 -0
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/main.ts +12 -2
- package/src/messenger/activity.ts +24 -0
- package/src/messenger/artifacts.ts +167 -0
- package/src/messenger/config.ts +14 -2
- package/src/messenger/discord.ts +330 -22
- package/src/messenger/gateway.ts +225 -8
- package/src/messenger/http.ts +1 -0
- package/src/messenger/live-session.ts +219 -24
- package/src/messenger/session.ts +14 -2
- package/src/messenger/types.ts +23 -1
- package/src/modes/controllers/input-controller.ts +26 -4
- package/src/prompts/system/messenger-artifacts.md +4 -0
- package/src/session/agent-session.ts +14 -10
- package/src/slash-commands/builtin-registry.ts +25 -2
package/src/messenger/types.ts
CHANGED
|
@@ -8,14 +8,30 @@ export interface MessengerMessage {
|
|
|
8
8
|
messageId: string;
|
|
9
9
|
text: string;
|
|
10
10
|
threadId?: string;
|
|
11
|
+
parentChannelId?: string;
|
|
11
12
|
direct: boolean;
|
|
12
13
|
mentioned: boolean;
|
|
14
|
+
attachments?: { url: string; filename: string; size: number }[];
|
|
13
15
|
}
|
|
14
16
|
|
|
17
|
+
/** Report a short, human-readable description of the work in progress. */
|
|
18
|
+
export type MessengerActivityReporter = (text: string) => void;
|
|
19
|
+
|
|
15
20
|
export interface MessengerAdapter {
|
|
16
21
|
platform: MessengerPlatform;
|
|
17
22
|
start(onMessage: (message: MessengerMessage) => Promise<void>, signal: AbortSignal): Promise<void>;
|
|
18
23
|
send(message: MessengerMessage, text: string, signal?: AbortSignal): Promise<void>;
|
|
24
|
+
prepare?(message: MessengerMessage, signal?: AbortSignal): Promise<MessengerMessage>;
|
|
25
|
+
status?(
|
|
26
|
+
message: MessengerMessage,
|
|
27
|
+
status: "processing" | "success" | "failure",
|
|
28
|
+
signal?: AbortSignal,
|
|
29
|
+
): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Show `text` (one sanitized line) as the request's single in-progress status, editing it in place on
|
|
32
|
+
* later calls; `undefined` removes it. The gateway serializes and throttles calls per request.
|
|
33
|
+
*/
|
|
34
|
+
activity?(message: MessengerMessage, text: string | undefined, signal?: AbortSignal): Promise<void>;
|
|
19
35
|
}
|
|
20
36
|
|
|
21
37
|
export interface MessengerPlatformConfig {
|
|
@@ -23,6 +39,8 @@ export interface MessengerPlatformConfig {
|
|
|
23
39
|
appTokenEnv?: string;
|
|
24
40
|
allowedUserIds: string[];
|
|
25
41
|
allowedChannelIds?: string[];
|
|
42
|
+
/** Dedicated operator-approved directory for Discord output files. */
|
|
43
|
+
artifactDir?: string;
|
|
26
44
|
}
|
|
27
45
|
|
|
28
46
|
export interface MessengerConfig {
|
|
@@ -37,7 +55,11 @@ export interface MessengerTransportDeps {
|
|
|
37
55
|
WebSocket?: typeof WebSocket;
|
|
38
56
|
}
|
|
39
57
|
|
|
40
|
-
export type MessengerReply = (
|
|
58
|
+
export type MessengerReply = (
|
|
59
|
+
message: MessengerMessage,
|
|
60
|
+
signal: AbortSignal,
|
|
61
|
+
onActivity?: MessengerActivityReporter,
|
|
62
|
+
) => Promise<string>;
|
|
41
63
|
/** A partially initialized SDK must not be retried inside a live gateway. */
|
|
42
64
|
export class MessengerFatalError extends Error {
|
|
43
65
|
constructor() {
|
|
@@ -903,7 +903,19 @@ export class InputController {
|
|
|
903
903
|
try {
|
|
904
904
|
await this.ctx.withLocalSubmission(
|
|
905
905
|
text,
|
|
906
|
-
() =>
|
|
906
|
+
() => {
|
|
907
|
+
const submit = () => this.ctx.session.prompt(text, { streamingBehavior: "steer", images });
|
|
908
|
+
const bridge = this.ctx.liveDiscordBridge;
|
|
909
|
+
return bridge?.active
|
|
910
|
+
? bridge.withLocalTurn(text, onPreparedUserMessage =>
|
|
911
|
+
this.ctx.session.prompt(text, {
|
|
912
|
+
streamingBehavior: "steer",
|
|
913
|
+
images,
|
|
914
|
+
onPreparedUserMessage,
|
|
915
|
+
}),
|
|
916
|
+
)
|
|
917
|
+
: submit();
|
|
918
|
+
},
|
|
907
919
|
{
|
|
908
920
|
imageCount: images?.length ?? 0,
|
|
909
921
|
},
|
|
@@ -1229,9 +1241,19 @@ export class InputController {
|
|
|
1229
1241
|
// Not streaming — just submit normally
|
|
1230
1242
|
this.ctx.editor.clearDraft(text);
|
|
1231
1243
|
try {
|
|
1232
|
-
await this.ctx.withLocalSubmission(
|
|
1233
|
-
|
|
1234
|
-
|
|
1244
|
+
await this.ctx.withLocalSubmission(
|
|
1245
|
+
text,
|
|
1246
|
+
() => {
|
|
1247
|
+
const submit = () => this.ctx.session.prompt(text, { images });
|
|
1248
|
+
const bridge = this.ctx.liveDiscordBridge;
|
|
1249
|
+
return bridge?.active
|
|
1250
|
+
? bridge.withLocalTurn(text, onPreparedUserMessage =>
|
|
1251
|
+
this.ctx.session.prompt(text, { images, onPreparedUserMessage }),
|
|
1252
|
+
)
|
|
1253
|
+
: submit();
|
|
1254
|
+
},
|
|
1255
|
+
{ imageCount: images?.length ?? 0 },
|
|
1256
|
+
);
|
|
1235
1257
|
} catch (error) {
|
|
1236
1258
|
restoreOnError(error);
|
|
1237
1259
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
To deliver a requested file, write it inside {{directory}} and put [artifact:relative/path] on its own line in your final response. Only files in that directory can be uploaded; each must be at most 8 MiB. Never include credentials or secrets in output files.
|
|
2
|
+
{{#if inputs}}
|
|
3
|
+
Incoming files: {{inputs}}
|
|
4
|
+
{{/if}}
|
|
@@ -97,6 +97,7 @@ import type {
|
|
|
97
97
|
ToolChoice,
|
|
98
98
|
Usage,
|
|
99
99
|
UsageReport,
|
|
100
|
+
UserMessage,
|
|
100
101
|
} from "jeopi-ai";
|
|
101
102
|
import {
|
|
102
103
|
calculateRateLimitBackoffMs,
|
|
@@ -944,6 +945,8 @@ export interface PromptOptions {
|
|
|
944
945
|
userInitiated?: boolean;
|
|
945
946
|
/** Explicit billing/initiator attribution for the prompt. Defaults to user prompts as `user` and synthetic prompts as `agent`. */
|
|
946
947
|
attribution?: MessageAttribution;
|
|
948
|
+
/** Observe the exact user message prepared for this submission, including queued messages. */
|
|
949
|
+
onPreparedUserMessage?: (message: UserMessage) => void;
|
|
947
950
|
/** Skip pre-send compaction checks for this prompt (internal use for maintenance flows). */
|
|
948
951
|
skipCompactionCheck?: boolean;
|
|
949
952
|
}
|
|
@@ -7539,9 +7542,9 @@ export class AgentSession {
|
|
|
7539
7542
|
await this.sendCustomMessage(notice, { deliverAs: options.streamingBehavior });
|
|
7540
7543
|
}
|
|
7541
7544
|
if (options.streamingBehavior === "followUp") {
|
|
7542
|
-
await this.#queueUserMessage(expandedText, options?.images, "followUp");
|
|
7545
|
+
await this.#queueUserMessage(expandedText, options?.images, "followUp", options?.onPreparedUserMessage);
|
|
7543
7546
|
} else {
|
|
7544
|
-
await this.#queueUserMessage(expandedText, options?.images, "steer");
|
|
7547
|
+
await this.#queueUserMessage(expandedText, options?.images, "steer", options?.onPreparedUserMessage);
|
|
7545
7548
|
}
|
|
7546
7549
|
return true;
|
|
7547
7550
|
}
|
|
@@ -7568,6 +7571,7 @@ export class AgentSession {
|
|
|
7568
7571
|
const message = options?.synthetic
|
|
7569
7572
|
? { role: "developer" as const, content: userContent, attribution: promptAttribution, timestamp: Date.now() }
|
|
7570
7573
|
: { role: "user" as const, content: userContent, attribution: promptAttribution, timestamp: Date.now() };
|
|
7574
|
+
if (message.role === "user") options?.onPreparedUserMessage?.(message);
|
|
7571
7575
|
|
|
7572
7576
|
const preludeMessages: AgentMessage[] = [];
|
|
7573
7577
|
if (eagerTodoPrelude) {
|
|
@@ -8021,6 +8025,7 @@ export class AgentSession {
|
|
|
8021
8025
|
text: string,
|
|
8022
8026
|
images: ImageContent[] | undefined,
|
|
8023
8027
|
mode: "steer" | "followUp",
|
|
8028
|
+
onPreparedUserMessage?: (message: UserMessage) => void,
|
|
8024
8029
|
): Promise<void> {
|
|
8025
8030
|
// A queued user message (RPC/SDK/collab steer or follow-up, or a typed message
|
|
8026
8031
|
// while streaming) is a deliberate resume; re-enable advisor auto-resume that
|
|
@@ -8038,21 +8043,20 @@ export class AgentSession {
|
|
|
8038
8043
|
: undefined;
|
|
8039
8044
|
if (mode === "followUp") {
|
|
8040
8045
|
if (imageDescriptionNotice) this.agent.followUp(imageDescriptionNotice);
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
attribution: "user",
|
|
8045
|
-
timestamp: Date.now(),
|
|
8046
|
-
});
|
|
8046
|
+
const message: UserMessage = { role: "user", content, attribution: "user", timestamp: Date.now() };
|
|
8047
|
+
onPreparedUserMessage?.(message);
|
|
8048
|
+
this.agent.followUp(message);
|
|
8047
8049
|
} else {
|
|
8048
8050
|
if (imageDescriptionNotice) this.agent.steer(imageDescriptionNotice);
|
|
8049
|
-
|
|
8051
|
+
const message: UserMessage = {
|
|
8050
8052
|
role: "user",
|
|
8051
8053
|
content,
|
|
8052
8054
|
steering: true,
|
|
8053
8055
|
attribution: "user",
|
|
8054
8056
|
timestamp: Date.now(),
|
|
8055
|
-
}
|
|
8057
|
+
};
|
|
8058
|
+
onPreparedUserMessage?.(message);
|
|
8059
|
+
this.agent.steer(message);
|
|
8056
8060
|
}
|
|
8057
8061
|
this.#scheduleIdleQueueDrain();
|
|
8058
8062
|
}
|
|
@@ -661,9 +661,10 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
661
661
|
{
|
|
662
662
|
name: "discord",
|
|
663
663
|
description: "Opt in to this session from an authorized Discord channel",
|
|
664
|
-
inlineHint: "[live|stop|status] [configPath] [--allow-full-control]",
|
|
664
|
+
inlineHint: "[live|relay|stop|status] [configPath|channelId|off] [--allow-full-control]",
|
|
665
665
|
subcommands: [
|
|
666
666
|
{ name: "live", description: "Start the live Discord bridge with a private config file" },
|
|
667
|
+
{ name: "relay", description: "Relay local responses to an allowed channel, or turn relay off" },
|
|
667
668
|
{ name: "status", description: "Show live Discord bridge status" },
|
|
668
669
|
{ name: "stop", description: "Stop the live Discord bridge" },
|
|
669
670
|
],
|
|
@@ -682,10 +683,32 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
682
683
|
const approvalMode = String(ctx.session.settings.get("tools.approvalMode"));
|
|
683
684
|
const activeTools = ctx.session.getActiveToolNames();
|
|
684
685
|
ctx.showStatus(
|
|
685
|
-
`Discord live bridge is active with full host control acknowledged. Approval mode: ${approvalMode}; active tools: ${activeTools.length > 0 ? activeTools.join(", ") : "none"}.`,
|
|
686
|
+
`Discord live bridge is active with full host control acknowledged. Approval mode: ${approvalMode}; active tools: ${activeTools.length > 0 ? activeTools.join(", ") : "none"}. Local response relay: ${ctx.liveDiscordBridge.relayDestination ?? "off"}.`,
|
|
686
687
|
);
|
|
687
688
|
return;
|
|
688
689
|
}
|
|
690
|
+
if (verb === "relay") {
|
|
691
|
+
const bridge = ctx.liveDiscordBridge;
|
|
692
|
+
if (!bridge?.active) {
|
|
693
|
+
ctx.showError("Start the Discord live bridge before enabling relay");
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (!rest || /\s/.test(rest)) {
|
|
697
|
+
ctx.showError("Usage: /discord relay <allowed-channel-id|off>");
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
try {
|
|
701
|
+
bridge.setRelayDestination(rest === "off" ? undefined : rest);
|
|
702
|
+
ctx.showStatus(
|
|
703
|
+
rest === "off"
|
|
704
|
+
? "Discord local response relay is off"
|
|
705
|
+
: `Discord local responses will be sent to channel ${rest}; /discord relay off revokes relay.`,
|
|
706
|
+
);
|
|
707
|
+
} catch (error) {
|
|
708
|
+
ctx.showError(`Failed to configure Discord relay: ${errorMessage(error)}`);
|
|
709
|
+
}
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
689
712
|
if (verb === "stop") {
|
|
690
713
|
const bridge = ctx.liveDiscordBridge;
|
|
691
714
|
const start = liveDiscordStarts.get(ctx);
|