@ganglion/xacpx 0.13.0 → 0.14.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.
@@ -1,5 +1,5 @@
1
1
  import type { CommandRouterContext, RouterResponse, SessionInteractionOps, SessionLifecycleOps, SessionRenderRecoveryOps } from "../router-types";
2
- import type { PromptMediaInput, ResolvedSession } from "../../transport/types";
2
+ import type { AgentCommand, PromptMediaInput, PromptUsage, ResolvedSession } from "../../transport/types";
3
3
  import type { PlanEntry, ToolUseEvent } from "../../channels/types.js";
4
4
  import type { PerfSpan } from "../../perf/perf-tracer";
5
5
  import type { HelpTopicMetadata } from "../help/help-types";
@@ -39,11 +39,5 @@ export declare function handleSessionReset(context: SessionHandlerContext, chatK
39
39
  export declare function handleSessionTail(context: SessionHandlerContext, chatKey: string, lines?: number): Promise<RouterResponse>;
40
40
  export declare function handleSessionRemove(context: SessionHandlerContext, chatKey: string, alias: string): Promise<RouterResponse>;
41
41
  export declare function handleSessionArchive(context: SessionHandlerContext, chatKey: string, alias: string, archive: (internalAlias: string) => Promise<void>): Promise<RouterResponse>;
42
- export declare function handlePromptWithSession(context: SessionHandlerContext, session: ResolvedSession, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: {
43
- used: number;
44
- size: number;
45
- }) => void | Promise<void>): Promise<RouterResponse>;
46
- export declare function handlePrompt(context: SessionHandlerContext, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: {
47
- used: number;
48
- size: number;
49
- }) => void | Promise<void>): Promise<RouterResponse>;
42
+ export declare function handlePromptWithSession(context: SessionHandlerContext, session: ResolvedSession, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: PromptUsage) => void | Promise<void>, onCommands?: (commands: AgentCommand[]) => void | Promise<void>): Promise<RouterResponse>;
43
+ export declare function handlePrompt(context: SessionHandlerContext, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: PromptUsage) => void | Promise<void>, onCommands?: (commands: AgentCommand[]) => void | Promise<void>): Promise<RouterResponse>;
@@ -3,7 +3,7 @@ import type { AppConfig } from "../config/types";
3
3
  import type { AppLogger } from "../logging/app-logger";
4
4
  import type { OrchestrationService } from "../orchestration/orchestration-service";
5
5
  import type { SessionService } from "../sessions/session-service";
6
- import type { PromptMediaInput, ReplyQuotaContext, SessionTransport } from "../transport/types";
6
+ import type { AgentCommand, PromptMediaInput, PromptUsage, ReplyQuotaContext, SessionTransport } from "../transport/types";
7
7
  import type { QuotaManager } from "../weixin/messaging/quota-manager.js";
8
8
  import type { PlanEntry, ToolUseEvent } from "../channels/types.js";
9
9
  import type { PerfSpan } from "../perf/perf-tracer";
@@ -113,10 +113,7 @@ export interface SessionInteractionOps {
113
113
  cancelled: boolean;
114
114
  message: string;
115
115
  }>;
116
- promptTransportSession: (session: import("../transport/types").ResolvedSession, text: string, reply?: (text: string) => Promise<void>, replyContext?: ReplyQuotaContext, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: {
117
- used: number;
118
- size: number;
119
- }) => void | Promise<void>) => Promise<{
116
+ promptTransportSession: (session: import("../transport/types").ResolvedSession, text: string, reply?: (text: string) => Promise<void>, replyContext?: ReplyQuotaContext, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: PromptUsage) => void | Promise<void>, onCommands?: (commands: AgentCommand[]) => void | Promise<void>) => Promise<{
120
117
  text: string;
121
118
  }>;
122
119
  }
@@ -1,5 +1,6 @@
1
1
  import type { AppLogger } from "../logging/app-logger";
2
2
  import type { ToolUseEvent, PlanEntry } from "../channels/types";
3
+ import type { AgentCommand, UsageBreakdown, UsageCost } from "../transport/types";
3
4
  import type { NativeHistoryMessage } from "../transport/native-session-history";
4
5
  export interface ScheduledOrigin {
5
6
  taskId: string;
@@ -37,6 +38,13 @@ export type ControlEvent = {
37
38
  sessionAlias: string;
38
39
  used: number;
39
40
  size: number;
41
+ cost?: UsageCost;
42
+ breakdown?: UsageBreakdown;
43
+ } | {
44
+ type: "agent-commands";
45
+ chatKey: string;
46
+ sessionAlias: string;
47
+ commands: AgentCommand[];
40
48
  } | {
41
49
  type: "turn-finished";
42
50
  chatKey: string;
@@ -46,6 +54,8 @@ export type ControlEvent = {
46
54
  cancelled?: boolean;
47
55
  } | {
48
56
  type: "sessions-changed";
57
+ } | {
58
+ type: "workspaces-changed";
49
59
  } | {
50
60
  type: "scheduled-changed";
51
61
  chatKey: string;
@@ -9,6 +9,8 @@ import type { OrchestrationTaskRecord } from "../orchestration/orchestration-typ
9
9
  import type { ControlEventBus } from "./control-event-bus";
10
10
  import type { AgentCatalogEntry } from "../config/agent-catalog";
11
11
  import { type DirListing, type FileContent, type SearchResult, type WorkspaceDiff } from "./workspace-fs";
12
+ import type { PromptAttachmentRef } from "@ganglion/xacpx-relay-protocol";
13
+ import type { UploadStore } from "./upload-store.js";
12
14
  export interface ControlSessionInfo {
13
15
  alias: string;
14
16
  agent: string;
@@ -63,6 +65,7 @@ export interface ControlServiceDeps {
63
65
  create(name: string, cwd: string, description?: string): Promise<ControlWorkspaceInfo>;
64
66
  remove(name: string): Promise<void>;
65
67
  };
68
+ uploadStore: UploadStore;
66
69
  }
67
70
  export interface ControlPromptInput {
68
71
  chatKey: string;
@@ -71,6 +74,7 @@ export interface ControlPromptInput {
71
74
  accountId?: string;
72
75
  senderId: string;
73
76
  isOwner?: boolean;
77
+ media?: PromptAttachmentRef[];
74
78
  }
75
79
  export interface ControlPromptResult {
76
80
  ok: boolean;
@@ -105,6 +109,17 @@ export declare class ControlService {
105
109
  readWorkspaceFile(workspace: string, path: string): Promise<FileContent>;
106
110
  workspaceGitDiff(workspace: string, path?: string): Promise<WorkspaceDiff>;
107
111
  searchWorkspace(workspace: string, query: string): Promise<SearchResult>;
112
+ uploadFile(input: {
113
+ filename: string;
114
+ content: string;
115
+ mimeType: string;
116
+ }): Promise<{
117
+ id: string;
118
+ path: string;
119
+ filename: string;
120
+ mimeType: string;
121
+ size: number;
122
+ }>;
108
123
  /** Read a session's current model and the agent-advertised available ids. */
109
124
  getSessionModel(chatKey: string, alias: string): Promise<{
110
125
  current?: string;
@@ -0,0 +1,28 @@
1
+ export interface UploadStoreOptions {
2
+ rootDir?: string;
3
+ maxBytes?: number;
4
+ ttlMs?: number;
5
+ now?: () => Date;
6
+ }
7
+ export interface SavedUpload {
8
+ id: string;
9
+ path: string;
10
+ filename: string;
11
+ mimeType: string;
12
+ size: number;
13
+ }
14
+ /** Strip directory components and traversal segments, leaving a safe basename. */
15
+ export declare function sanitizeUploadFilename(raw: string): string;
16
+ export declare class UploadStore {
17
+ private readonly rootDir;
18
+ private readonly maxBytes;
19
+ private readonly ttlMs;
20
+ private readonly now;
21
+ constructor(opts?: UploadStoreOptions);
22
+ /** Sandbox root all uploads are written under. Callers may use this to verify a
23
+ * media filePath actually originated from a control.upload (defense-in-depth). */
24
+ get root(): string;
25
+ save(filename: string, base64: string, mimeType: string): Promise<SavedUpload>;
26
+ /** Remove upload dirs whose mtime is older than the TTL. Returns count removed. */
27
+ cleanup(): Promise<number>;
28
+ }
@@ -809,6 +809,7 @@ export interface MiscMessages {
809
809
  defaultHomeWorkspaceDescription: string;
810
810
  pluginChannelFeishu: string;
811
811
  pluginChannelYuanbao: string;
812
+ pluginChannelRelay: string;
812
813
  pluginChannelInstallHint: (channelType: string, packageName: string) => string;
813
814
  orchestrationSuggestion1: string;
814
815
  orchestrationSuggestion2: string;
@@ -1050,6 +1050,7 @@ var init_misc = __esm(() => {
1050
1050
  defaultHomeWorkspaceDescription: "Home directory",
1051
1051
  pluginChannelFeishu: "Feishu channel",
1052
1052
  pluginChannelYuanbao: "Tencent Yuanbao channel",
1053
+ pluginChannelRelay: "Relay hub connector (drive this instance from a self-hosted relay hub)",
1053
1054
  pluginChannelInstallHint: (channelType, packageName) => `Channel ${channelType} requires a plugin: xacpx plugin add ${packageName}`,
1054
1055
  orchestrationSuggestion1: "Run /tasks --stuck to locate stuck tasks",
1055
1056
  orchestrationSuggestion2: "/task <id> shows the full timeline to locate errors",
@@ -2146,6 +2147,7 @@ var init_misc2 = __esm(() => {
2146
2147
  defaultHomeWorkspaceDescription: "用户主目录",
2147
2148
  pluginChannelFeishu: "飞书频道",
2148
2149
  pluginChannelYuanbao: "腾讯元宝频道",
2150
+ pluginChannelRelay: "Relay hub 连接器(从自托管 relay hub 遥控这台实例)",
2149
2151
  pluginChannelInstallHint: (channelType, packageName) => `频道 ${channelType} 需要安装插件:xacpx plugin add ${packageName}`,
2150
2152
  orchestrationSuggestion1: "查看 /tasks --stuck 定位卡住的任务",
2151
2153
  orchestrationSuggestion2: "/task <id> 可看完整时间线定位错误点",
@@ -3,6 +3,37 @@ import type { QuotaManager } from "../weixin/messaging/quota-manager.js";
3
3
  import type { PlanEntry, ToolUseEvent } from "../channels/types.js";
4
4
  import type { ToolEventMode } from "./tool-event-mode.js";
5
5
  export type { ToolEventMode } from "./tool-event-mode.js";
6
+ /** Cumulative session cost the agent reported (ACP `usage_update.cost`). Both optional. */
7
+ export interface UsageCost {
8
+ amount?: number;
9
+ currency?: string;
10
+ }
11
+ /**
12
+ * Per-turn token breakdown from ACP `usage_update._meta.usage` (Claude reports it;
13
+ * codex may omit). All fields optional — treat missing as "unknown", not zero.
14
+ */
15
+ export interface UsageBreakdown {
16
+ inputTokens?: number;
17
+ outputTokens?: number;
18
+ cachedReadTokens?: number;
19
+ cachedWriteTokens?: number;
20
+ thoughtTokens?: number;
21
+ totalTokens?: number;
22
+ }
23
+ /** Context-usage side-channel payload: window fill plus optional cost & token breakdown. */
24
+ export interface PromptUsage {
25
+ used: number;
26
+ size: number;
27
+ cost?: UsageCost;
28
+ breakdown?: UsageBreakdown;
29
+ }
30
+ /** An agent-advertised slash command (ACP `available_commands_update`). */
31
+ export interface AgentCommand {
32
+ name: string;
33
+ description?: string;
34
+ /** Whether the command accepts an argument (ACP advertised a non-null `input`). */
35
+ hasInput?: boolean;
36
+ }
6
37
  export interface ReplyQuotaContext {
7
38
  chatKey: string;
8
39
  quota: QuotaManager;
@@ -125,10 +156,12 @@ export interface PromptOptions {
125
156
  * scalar (re-sent during a turn). Optional — only agents that report it fire this
126
157
  * (e.g. claude does, codex does not), and text channels omit the handler.
127
158
  */
128
- onUsage?: (usage: {
129
- used: number;
130
- size: number;
131
- }) => void | Promise<void>;
159
+ onUsage?: (usage: PromptUsage) => void | Promise<void>;
160
+ /**
161
+ * Agent-advertised slash commands (ACP `available_commands_update`). Replace-latest
162
+ * list, re-sent when the agent updates it. Optional — not every adapter advertises.
163
+ */
164
+ onCommands?: (commands: AgentCommand[]) => void | Promise<void>;
132
165
  /**
133
166
  * How tool_call / tool_call_update events are surfaced for this prompt.
134
167
  *
@@ -1,5 +1,6 @@
1
1
  import type { ChannelMediaAttachment, OutboundChannelMedia } from "../../channels/media-types.js";
2
2
  import type { PlanEntry, ScheduledSessionDescriptor, ToolUseEvent } from "../../channels/types.js";
3
+ import type { AgentCommand, PromptUsage } from "../../transport/types.js";
3
4
  import type { PerfSpan } from "../../perf/perf-tracer.js";
4
5
  /**
5
6
  * Agent interface — any AI backend that can handle a chat message.
@@ -51,10 +52,9 @@ export interface ChatRequest {
51
52
  /** Structured plan/todo side-channel; see PromptOptions.onPlan. */
52
53
  onPlan?: (entries: PlanEntry[]) => void | Promise<void>;
53
54
  /** Context-usage side-channel; see PromptOptions.onUsage. */
54
- onUsage?: (usage: {
55
- used: number;
56
- size: number;
57
- }) => void | Promise<void>;
55
+ onUsage?: (usage: PromptUsage) => void | Promise<void>;
56
+ /** Agent-advertised slash commands; see PromptOptions.onCommands. */
57
+ onCommands?: (commands: AgentCommand[]) => void | Promise<void>;
58
58
  /**
59
59
  * Optional per-turn performance tracing span. When `logging.perf.enabled` is
60
60
  * true, the channel handler attaches a `PerfSpan` so downstream layers can
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ganglion/xacpx",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
5
5
  "keywords": [
6
6
  "acpx",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "dependencies": {
87
87
  "@modelcontextprotocol/sdk": "^1.29.0",
88
- "acpx": "^0.9.0",
88
+ "acpx": "^0.11.0",
89
89
  "node-pty": "^1.1.0",
90
90
  "proper-lockfile": "^4.1.2",
91
91
  "protobufjs": "^7.5.6",