@ganglion/xacpx 0.10.0 → 0.11.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/README.md +22 -0
- package/dist/bridge/bridge-main.js +126 -9
- package/dist/channels/types.d.ts +16 -0
- package/dist/cli.js +2480 -542
- package/dist/commands/handlers/agent-handler.d.ts +1 -1
- package/dist/commands/handlers/session-handler.d.ts +7 -4
- package/dist/commands/parse-command.d.ts +7 -0
- package/dist/commands/router-types.d.ts +7 -2
- package/dist/config/agent-catalog.d.ts +14 -0
- package/dist/config/local-agent-bin.d.ts +17 -0
- package/dist/config/resolve-agent-command.d.ts +11 -0
- package/dist/config/types.d.ts +10 -0
- package/dist/control/control-event-bus.d.ts +59 -0
- package/dist/control/control-service.d.ts +147 -0
- package/dist/control/workspace-fs.d.ts +52 -0
- package/dist/i18n/types.d.ts +12 -0
- package/dist/plugin-api.d.ts +3 -0
- package/dist/plugin-api.js +53 -0
- package/dist/scheduled/scheduled-service.d.ts +3 -0
- package/dist/sessions/active-turn-registry.d.ts +2 -0
- package/dist/sessions/session-service.d.ts +4 -0
- package/dist/state/types.d.ts +2 -0
- package/dist/transport/native-session-history.d.ts +34 -0
- package/dist/transport/types.d.ts +27 -1
- package/dist/weixin/agent/interface.d.ts +3 -1
- package/package.json +17 -2
|
@@ -2,5 +2,5 @@ import type { HelpTopicMetadata } from "../help/help-types";
|
|
|
2
2
|
import type { CommandRouterContext, RouterResponse } from "../router-types";
|
|
3
3
|
export declare function agentHelp(): HelpTopicMetadata;
|
|
4
4
|
export declare function handleAgents(context: CommandRouterContext): RouterResponse;
|
|
5
|
-
export declare function handleAgentAdd(context: CommandRouterContext, templateName: string): Promise<RouterResponse>;
|
|
5
|
+
export declare function handleAgentAdd(context: CommandRouterContext, templateName: string, model?: string): Promise<RouterResponse>;
|
|
6
6
|
export declare function handleAgentRemove(context: CommandRouterContext, agentName: string): Promise<RouterResponse>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommandRouterContext, RouterResponse, SessionInteractionOps, SessionLifecycleOps, SessionRenderRecoveryOps } from "../router-types";
|
|
2
2
|
import type { PromptMediaInput, ResolvedSession } from "../../transport/types";
|
|
3
|
-
import type { ToolUseEvent } from "../../channels/types.js";
|
|
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";
|
|
6
6
|
import type { ChatRequestMetadata } from "../../weixin/agent/interface";
|
|
@@ -13,11 +13,12 @@ export interface SessionHandlerContext extends CommandRouterContext {
|
|
|
13
13
|
export declare function sessionHelp(): HelpTopicMetadata;
|
|
14
14
|
export declare function nativeSessionHelp(): HelpTopicMetadata;
|
|
15
15
|
export declare function modeHelp(): HelpTopicMetadata;
|
|
16
|
+
export declare function modelHelp(): HelpTopicMetadata;
|
|
16
17
|
export declare function replyModeHelp(): HelpTopicMetadata;
|
|
17
18
|
export declare function statusHelp(): HelpTopicMetadata;
|
|
18
19
|
export declare function cancelHelp(): HelpTopicMetadata;
|
|
19
20
|
export declare function handleSessions(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
20
|
-
export declare function handleSessionNew(context: SessionHandlerContext, chatKey: string, alias: string, agent: string, workspace: string): Promise<RouterResponse>;
|
|
21
|
+
export declare function handleSessionNew(context: SessionHandlerContext, chatKey: string, alias: string, agent: string, workspace: string, model?: string): Promise<RouterResponse>;
|
|
21
22
|
export declare function handleSessionShortcut(context: SessionHandlerContext, chatKey: string, agent: string, target: {
|
|
22
23
|
cwd?: string;
|
|
23
24
|
workspace?: string;
|
|
@@ -27,6 +28,8 @@ export declare function handleSessionUse(context: SessionHandlerContext, chatKey
|
|
|
27
28
|
export declare function handleSessionUsePrevious(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
28
29
|
export declare function handleModeShow(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
29
30
|
export declare function handleModeSet(context: SessionHandlerContext, chatKey: string, modeId: string): Promise<RouterResponse>;
|
|
31
|
+
export declare function handleModelShow(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
32
|
+
export declare function handleModelSet(context: SessionHandlerContext, chatKey: string, modelId: string): Promise<RouterResponse>;
|
|
30
33
|
export declare function handleReplyModeShow(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
31
34
|
export declare function handleReplyModeSet(context: SessionHandlerContext, chatKey: string, replyMode: "stream" | "final" | "verbose"): Promise<RouterResponse>;
|
|
32
35
|
export declare function handleReplyModeReset(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
@@ -35,5 +38,5 @@ export declare function handleCancel(context: SessionHandlerContext, chatKey: st
|
|
|
35
38
|
export declare function handleSessionReset(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
36
39
|
export declare function handleSessionTail(context: SessionHandlerContext, chatKey: string, lines?: number): Promise<RouterResponse>;
|
|
37
40
|
export declare function handleSessionRemove(context: SessionHandlerContext, chatKey: string, alias: string): Promise<RouterResponse>;
|
|
38
|
-
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): Promise<RouterResponse>;
|
|
39
|
-
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): Promise<RouterResponse>;
|
|
41
|
+
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>): Promise<RouterResponse>;
|
|
42
|
+
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>): Promise<RouterResponse>;
|
|
@@ -19,6 +19,7 @@ export type ParsedCommand = {
|
|
|
19
19
|
} | {
|
|
20
20
|
kind: "agent.add";
|
|
21
21
|
template: string;
|
|
22
|
+
model?: string;
|
|
22
23
|
} | {
|
|
23
24
|
kind: "agent.rm";
|
|
24
25
|
name: string;
|
|
@@ -109,6 +110,11 @@ export type ParsedCommand = {
|
|
|
109
110
|
} | {
|
|
110
111
|
kind: "mode.set";
|
|
111
112
|
modeId: string;
|
|
113
|
+
} | {
|
|
114
|
+
kind: "model.show";
|
|
115
|
+
} | {
|
|
116
|
+
kind: "model.set";
|
|
117
|
+
modelId: string;
|
|
112
118
|
} | {
|
|
113
119
|
kind: "replymode.show";
|
|
114
120
|
} | {
|
|
@@ -126,6 +132,7 @@ export type ParsedCommand = {
|
|
|
126
132
|
alias: string;
|
|
127
133
|
agent: string;
|
|
128
134
|
workspace: string;
|
|
135
|
+
model?: string;
|
|
129
136
|
} | {
|
|
130
137
|
kind: "session.shortcut";
|
|
131
138
|
agent: string;
|
|
@@ -5,7 +5,7 @@ import type { OrchestrationService } from "../orchestration/orchestration-servic
|
|
|
5
5
|
import type { SessionService } from "../sessions/session-service";
|
|
6
6
|
import type { PromptMediaInput, ReplyQuotaContext, SessionTransport } from "../transport/types";
|
|
7
7
|
import type { QuotaManager } from "../weixin/messaging/quota-manager.js";
|
|
8
|
-
import type { ToolUseEvent } from "../channels/types.js";
|
|
8
|
+
import type { PlanEntry, ToolUseEvent } from "../channels/types.js";
|
|
9
9
|
import type { PerfSpan } from "../perf/perf-tracer";
|
|
10
10
|
export interface RouterResponse {
|
|
11
11
|
text?: string;
|
|
@@ -104,11 +104,16 @@ export interface SessionLifecycleOps {
|
|
|
104
104
|
}
|
|
105
105
|
export interface SessionInteractionOps {
|
|
106
106
|
setModeTransportSession: (session: import("../transport/types").ResolvedSession, modeId: string) => Promise<void>;
|
|
107
|
+
setModelTransportSession: (session: import("../transport/types").ResolvedSession, modelId: string) => Promise<void>;
|
|
108
|
+
getModelTransportSession: (session: import("../transport/types").ResolvedSession) => Promise<{
|
|
109
|
+
current?: string;
|
|
110
|
+
available: string[];
|
|
111
|
+
}>;
|
|
107
112
|
cancelTransportSession: (session: import("../transport/types").ResolvedSession) => Promise<{
|
|
108
113
|
cancelled: boolean;
|
|
109
114
|
message: string;
|
|
110
115
|
}>;
|
|
111
|
-
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) => 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>) => Promise<{
|
|
112
117
|
text: string;
|
|
113
118
|
}>;
|
|
114
119
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AppConfig } from "./types";
|
|
2
|
+
export interface AgentCatalogEntry {
|
|
3
|
+
driver: string;
|
|
4
|
+
configured: boolean;
|
|
5
|
+
installed: "builtin" | "yes" | "unknown";
|
|
6
|
+
}
|
|
7
|
+
/** True if `binary` is found in any PATH directory (no extension assumptions on POSIX). */
|
|
8
|
+
export declare function isBinaryOnPath(binary: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Catalog of every acpx driver xacpx knows (from `listAgentTemplates()`), each
|
|
11
|
+
* tagged with whether it's already configured and a best-effort install hint.
|
|
12
|
+
* `probe` is injectable for tests; defaults to a real PATH lookup.
|
|
13
|
+
*/
|
|
14
|
+
export declare function listAgentCatalog(config: AppConfig, probe?: (binary: string) => boolean): AgentCatalogEntry[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executable-file extensions to try for a bare command name. POSIX: just the name;
|
|
3
|
+
* Windows: the PATHEXT list (executability there is decided by extension, not a mode bit).
|
|
4
|
+
*/
|
|
5
|
+
export declare function executableExtensions(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string[];
|
|
6
|
+
/**
|
|
7
|
+
* Is `name` an executable on PATH? Cross-platform: honours PATHEXT on Windows so
|
|
8
|
+
* `opencode` matches `opencode.cmd`/`.exe`. `env`/`isExecutableFile` are injectable for tests.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isExecutableOnPath(name: string, env?: NodeJS.ProcessEnv, isExecutableFile?: (p: string) => boolean): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* If `driver` is a known npx-fallback agent AND its native CLI is on PATH, return the
|
|
13
|
+
* native command (e.g. `"opencode acp"`) to hand acpx via `--agent`; otherwise undefined
|
|
14
|
+
* (let acpx fall back to its npx default). Returns the bare bin name — acpx resolves it
|
|
15
|
+
* on PATH at spawn time, sidestepping any path-with-spaces quoting concerns.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveLocalAgentCommand(driver: string, onPath?: (name: string) => boolean): string | undefined;
|
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
export declare function resolveAgentCommand(driver: string, command: string | undefined): string | undefined;
|
|
2
|
+
/**
|
|
3
|
+
* Agent command for the RUNTIME spawn/reap paths. An explicit per-agent `command`
|
|
4
|
+
* always wins; otherwise, when `preferLocal` (default true), prefer a locally-installed
|
|
5
|
+
* native CLI over acpx's npx fallback; otherwise undefined (acpx resolves the driver).
|
|
6
|
+
*
|
|
7
|
+
* Use this — not bare resolveAgentCommand — wherever an agentCommand is built to spawn
|
|
8
|
+
* OR reap a queue owner, so both resolve identically (a mismatch would orphan the owner).
|
|
9
|
+
* It is deliberately NOT used on the config-persistence paths (load/ensure-config), so a
|
|
10
|
+
* machine-specific local binary is never baked into the shareable config file.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveRuntimeAgentCommand(driver: string, command: string | undefined, preferLocal?: boolean): string | undefined;
|
|
2
13
|
export declare function isLegacyCodexCommand(command: string): boolean;
|
package/dist/config/types.d.ts
CHANGED
|
@@ -33,6 +33,14 @@ export interface TransportConfig {
|
|
|
33
33
|
* `0` keeps the owner alive forever. Defaults to 1800 (30 min).
|
|
34
34
|
*/
|
|
35
35
|
queueOwnerTtlSeconds?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Prefer a locally-installed native agent CLI over acpx's `npx -y <pkg>` fallback
|
|
38
|
+
* when one is on PATH (currently the unpinned-npx drivers: opencode, kilocode). This
|
|
39
|
+
* avoids a per-cold-start npm-registry fetch — faster and immune to network blips
|
|
40
|
+
* (e.g. ECONNRESET during agent init). Defaults to `true`; set `false` to always use
|
|
41
|
+
* acpx's default resolution. A per-agent `command` override still takes precedence.
|
|
42
|
+
*/
|
|
43
|
+
preferLocalAgents?: boolean;
|
|
36
44
|
}
|
|
37
45
|
export type LoggingLevel = "error" | "info" | "debug";
|
|
38
46
|
export interface PerfLogConfig {
|
|
@@ -51,6 +59,8 @@ export interface LoggingConfig {
|
|
|
51
59
|
export interface AgentConfig {
|
|
52
60
|
driver: string;
|
|
53
61
|
command?: string;
|
|
62
|
+
/** Default LLM model id for sessions of this agent (e.g. `gpt-5.2[high]`); a session-level model overrides it. */
|
|
63
|
+
model?: string;
|
|
54
64
|
}
|
|
55
65
|
export interface WorkspaceConfig {
|
|
56
66
|
cwd: string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { AppLogger } from "../logging/app-logger";
|
|
2
|
+
import type { ToolUseEvent, PlanEntry } from "../channels/types";
|
|
3
|
+
import type { NativeHistoryMessage } from "../transport/native-session-history";
|
|
4
|
+
export interface ScheduledOrigin {
|
|
5
|
+
taskId: string;
|
|
6
|
+
executeAt: string;
|
|
7
|
+
}
|
|
8
|
+
export type ControlEvent = {
|
|
9
|
+
type: "turn-output";
|
|
10
|
+
chatKey: string;
|
|
11
|
+
sessionAlias: string;
|
|
12
|
+
chunk: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: "turn-started";
|
|
15
|
+
chatKey: string;
|
|
16
|
+
sessionAlias: string;
|
|
17
|
+
prompt?: string;
|
|
18
|
+
scheduled?: ScheduledOrigin;
|
|
19
|
+
} | {
|
|
20
|
+
type: "tool-event";
|
|
21
|
+
chatKey: string;
|
|
22
|
+
sessionAlias: string;
|
|
23
|
+
event: ToolUseEvent;
|
|
24
|
+
} | {
|
|
25
|
+
type: "turn-thought";
|
|
26
|
+
chatKey: string;
|
|
27
|
+
sessionAlias: string;
|
|
28
|
+
chunk: string;
|
|
29
|
+
} | {
|
|
30
|
+
type: "plan";
|
|
31
|
+
chatKey: string;
|
|
32
|
+
sessionAlias: string;
|
|
33
|
+
entries: PlanEntry[];
|
|
34
|
+
} | {
|
|
35
|
+
type: "turn-finished";
|
|
36
|
+
chatKey: string;
|
|
37
|
+
sessionAlias: string;
|
|
38
|
+
ok: boolean;
|
|
39
|
+
errorMessage?: string;
|
|
40
|
+
cancelled?: boolean;
|
|
41
|
+
} | {
|
|
42
|
+
type: "sessions-changed";
|
|
43
|
+
} | {
|
|
44
|
+
type: "scheduled-changed";
|
|
45
|
+
chatKey: string;
|
|
46
|
+
} | {
|
|
47
|
+
type: "session-history";
|
|
48
|
+
chatKey: string;
|
|
49
|
+
sessionAlias: string;
|
|
50
|
+
messages: NativeHistoryMessage[];
|
|
51
|
+
} | {
|
|
52
|
+
type: "orchestration-changed";
|
|
53
|
+
};
|
|
54
|
+
export type ControlEventListener = (event: ControlEvent) => void;
|
|
55
|
+
export interface ControlEventBus {
|
|
56
|
+
subscribe(listener: ControlEventListener): () => void;
|
|
57
|
+
emit(event: ControlEvent): void;
|
|
58
|
+
}
|
|
59
|
+
export declare function createControlEventBus(logger?: AppLogger): ControlEventBus;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { Agent as ChatAgent } from "../weixin/agent/interface";
|
|
2
|
+
import type { SessionService } from "../sessions/session-service";
|
|
3
|
+
import type { AgentSession, ResolvedSession, SessionTransport } from "../transport/types";
|
|
4
|
+
import type { ActiveTurnRegistry } from "../sessions/active-turn-registry";
|
|
5
|
+
import type { CreateScheduledTaskInput, ScheduledTaskService } from "../scheduled/scheduled-service";
|
|
6
|
+
import type { ScheduledTaskRecord } from "../scheduled/scheduled-types";
|
|
7
|
+
import type { CancelTaskInput, OrchestrationService, OrchestrationTaskFilter } from "../orchestration/orchestration-service";
|
|
8
|
+
import type { OrchestrationTaskRecord } from "../orchestration/orchestration-types";
|
|
9
|
+
import type { ControlEventBus } from "./control-event-bus";
|
|
10
|
+
import type { AgentCatalogEntry } from "../config/agent-catalog";
|
|
11
|
+
import { type DirListing, type FileContent, type SearchResult, type WorkspaceDiff } from "./workspace-fs";
|
|
12
|
+
export interface ControlSessionInfo {
|
|
13
|
+
alias: string;
|
|
14
|
+
agent: string;
|
|
15
|
+
workspace: string;
|
|
16
|
+
transportSession: string;
|
|
17
|
+
running: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface ControlAgentInfo {
|
|
20
|
+
name: string;
|
|
21
|
+
driver: string;
|
|
22
|
+
}
|
|
23
|
+
/** An agent-native (acpx-owned) session available to attach as a new logical session. */
|
|
24
|
+
export interface ControlNativeSessionInfo {
|
|
25
|
+
sessionId: string;
|
|
26
|
+
title?: string | null;
|
|
27
|
+
updatedAt?: string;
|
|
28
|
+
cwd?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ControlWorkspaceInfo {
|
|
31
|
+
name: string;
|
|
32
|
+
cwd: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface ControlServiceDeps {
|
|
36
|
+
agent: Pick<ChatAgent, "chat">;
|
|
37
|
+
sessions: Pick<SessionService, "listAllResolvedSessions" | "removeSession" | "useSession" | "resolveAliasForChat" | "getSession" | "setSessionModel">;
|
|
38
|
+
transport: Pick<SessionTransport, "setModel" | "getSessionModel">;
|
|
39
|
+
createSessionWithTransport: (internalAlias: string, agent: string, workspace: string, model?: string) => Promise<ResolvedSession>;
|
|
40
|
+
listNativeSessions: (agent: string, workspace: string) => Promise<AgentSession[]>;
|
|
41
|
+
attachNativeSessionWithTransport: (internalAlias: string, agent: string, workspace: string, agentSessionId: string, nativeMeta?: {
|
|
42
|
+
title?: string | null;
|
|
43
|
+
updatedAt?: string;
|
|
44
|
+
}) => Promise<ResolvedSession>;
|
|
45
|
+
activeTurns: Pick<ActiveTurnRegistry, "isActiveAnywhere">;
|
|
46
|
+
scheduled: Pick<ScheduledTaskService, "listPending" | "listRecentForChat" | "createTask" | "cancelPending">;
|
|
47
|
+
orchestration: Pick<OrchestrationService, "listTasks" | "getTask" | "requestTaskCancellation">;
|
|
48
|
+
events: ControlEventBus;
|
|
49
|
+
agents: {
|
|
50
|
+
list(): ControlAgentInfo[];
|
|
51
|
+
catalog(): AgentCatalogEntry[];
|
|
52
|
+
create(name: string, driver: string): Promise<ControlAgentInfo>;
|
|
53
|
+
remove(name: string): Promise<void>;
|
|
54
|
+
};
|
|
55
|
+
workspaces: {
|
|
56
|
+
list(): ControlWorkspaceInfo[];
|
|
57
|
+
create(name: string, cwd: string, description?: string): Promise<ControlWorkspaceInfo>;
|
|
58
|
+
remove(name: string): Promise<void>;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export interface ControlPromptInput {
|
|
62
|
+
chatKey: string;
|
|
63
|
+
sessionAlias: string;
|
|
64
|
+
text: string;
|
|
65
|
+
accountId?: string;
|
|
66
|
+
senderId: string;
|
|
67
|
+
isOwner?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface ControlPromptResult {
|
|
70
|
+
ok: boolean;
|
|
71
|
+
text?: string;
|
|
72
|
+
errorMessage?: string;
|
|
73
|
+
}
|
|
74
|
+
/** A turn started by a fired scheduled task. Runs through the same agent + turn-event
|
|
75
|
+
* machinery as a normal prompt, so it streams live and persists to history — but it
|
|
76
|
+
* also carries the prompt text + schedule origin in turn-started, so the hub can
|
|
77
|
+
* persist the inbound message and the web can badge the run. */
|
|
78
|
+
export interface ControlScheduledTurnInput {
|
|
79
|
+
chatKey: string;
|
|
80
|
+
sessionAlias: string;
|
|
81
|
+
promptText: string;
|
|
82
|
+
taskId: string;
|
|
83
|
+
executeAt: string;
|
|
84
|
+
accountId?: string;
|
|
85
|
+
abortSignal?: AbortSignal;
|
|
86
|
+
}
|
|
87
|
+
export interface ControlExecuteCommandInput {
|
|
88
|
+
chatKey: string;
|
|
89
|
+
text: string;
|
|
90
|
+
accountId?: string;
|
|
91
|
+
senderId: string;
|
|
92
|
+
isOwner?: boolean;
|
|
93
|
+
}
|
|
94
|
+
export declare class ControlService {
|
|
95
|
+
private readonly deps;
|
|
96
|
+
constructor(deps: ControlServiceDeps);
|
|
97
|
+
private readonly workspaceFs;
|
|
98
|
+
listDirectory(workspace: string, path?: string): Promise<DirListing>;
|
|
99
|
+
readWorkspaceFile(workspace: string, path: string): Promise<FileContent>;
|
|
100
|
+
workspaceGitDiff(workspace: string, path?: string): Promise<WorkspaceDiff>;
|
|
101
|
+
searchWorkspace(workspace: string, query: string): Promise<SearchResult>;
|
|
102
|
+
/** Read a session's current model and the agent-advertised available ids. */
|
|
103
|
+
getSessionModel(chatKey: string, alias: string): Promise<{
|
|
104
|
+
current?: string;
|
|
105
|
+
available: string[];
|
|
106
|
+
}>;
|
|
107
|
+
/** Switch a session's model (acpx validates the id) and persist the override. */
|
|
108
|
+
setSessionModel(chatKey: string, alias: string, modelId: string): Promise<void>;
|
|
109
|
+
/** Resolve a chat-scoped display alias to its ResolvedSession, or null. */
|
|
110
|
+
private resolveControlSession;
|
|
111
|
+
get events(): ControlEventBus;
|
|
112
|
+
listSessions(chatKey: string): ControlSessionInfo[];
|
|
113
|
+
/**
|
|
114
|
+
* List the agent-native (acpx-owned) sessions for an agent + workspace, so the web
|
|
115
|
+
* add-session dialog can offer "attach an existing native session". These are the
|
|
116
|
+
* agent's own rollouts on disk (per-cwd), not chat-scoped — chatKey is accepted only
|
|
117
|
+
* for call-shape symmetry with the other session control methods.
|
|
118
|
+
*/
|
|
119
|
+
listNativeSessions(_chatKey: string, agent: string, workspace: string): Promise<ControlNativeSessionInfo[]>;
|
|
120
|
+
createSession(chatKey: string, alias: string, agent: string, workspace: string, agentSessionId?: string, model?: string): Promise<ControlSessionInfo>;
|
|
121
|
+
removeSession(chatKey: string, alias: string): Promise<{
|
|
122
|
+
wasActive: boolean;
|
|
123
|
+
}>;
|
|
124
|
+
listAgents(): ControlAgentInfo[];
|
|
125
|
+
listWorkspaces(): ControlWorkspaceInfo[];
|
|
126
|
+
createWorkspace(name: string, cwd: string, description?: string): Promise<ControlWorkspaceInfo>;
|
|
127
|
+
listAgentCatalog(): AgentCatalogEntry[];
|
|
128
|
+
createAgent(name: string, driver: string): Promise<ControlAgentInfo>;
|
|
129
|
+
removeAgent(name: string): Promise<void>;
|
|
130
|
+
removeWorkspace(name: string): Promise<void>;
|
|
131
|
+
listScheduledTasks(chatKey: string): ScheduledTaskRecord[];
|
|
132
|
+
createScheduledTask(input: CreateScheduledTaskInput): Promise<ScheduledTaskRecord>;
|
|
133
|
+
cancelScheduledTask(id: string, chatKey: string): Promise<boolean>;
|
|
134
|
+
listOrchestrationTasks(filter?: OrchestrationTaskFilter): Promise<OrchestrationTaskRecord[]>;
|
|
135
|
+
getOrchestrationTask(taskId: string): Promise<OrchestrationTaskRecord | null>;
|
|
136
|
+
cancelOrchestrationTask(input: CancelTaskInput): Promise<OrchestrationTaskRecord>;
|
|
137
|
+
private readonly inFlight;
|
|
138
|
+
prompt(input: ControlPromptInput): Promise<ControlPromptResult>;
|
|
139
|
+
/** Run a fired scheduled task as a real turn through the same machinery as a manual
|
|
140
|
+
* prompt — so it streams live and persists to history — while tagging turn-started
|
|
141
|
+
* with the prompt text + schedule origin so the hub records the inbound message and
|
|
142
|
+
* the web can badge it. Owner-authorized: the task was owner-gated at creation. */
|
|
143
|
+
runScheduledTurn(input: ControlScheduledTurnInput): Promise<ControlPromptResult>;
|
|
144
|
+
private executeTurn;
|
|
145
|
+
cancelTurn(chatKey: string, sessionAlias: string): boolean;
|
|
146
|
+
executeCommand(input: ControlExecuteCommandInput): Promise<string>;
|
|
147
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface FsEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
type: "dir" | "file";
|
|
4
|
+
size?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface DirListing {
|
|
7
|
+
workspace: string;
|
|
8
|
+
path: string;
|
|
9
|
+
entries: FsEntry[];
|
|
10
|
+
}
|
|
11
|
+
export interface FileContent {
|
|
12
|
+
workspace: string;
|
|
13
|
+
path: string;
|
|
14
|
+
content: string;
|
|
15
|
+
size: number;
|
|
16
|
+
truncated: boolean;
|
|
17
|
+
binary: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface DiffFile {
|
|
20
|
+
path: string;
|
|
21
|
+
status: string;
|
|
22
|
+
}
|
|
23
|
+
export interface SearchResult {
|
|
24
|
+
workspace: string;
|
|
25
|
+
query: string;
|
|
26
|
+
matches: string[];
|
|
27
|
+
truncated: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface WorkspaceDiff {
|
|
30
|
+
workspace: string;
|
|
31
|
+
files: DiffFile[];
|
|
32
|
+
diff: string;
|
|
33
|
+
truncated: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface WorkspaceRef {
|
|
36
|
+
name: string;
|
|
37
|
+
cwd: string;
|
|
38
|
+
}
|
|
39
|
+
export declare class WorkspaceFs {
|
|
40
|
+
private readonly listWorkspaces;
|
|
41
|
+
constructor(listWorkspaces: () => WorkspaceRef[]);
|
|
42
|
+
/** Resolve `relPath` within a named workspace, symlink-safe and contained. Throws
|
|
43
|
+
* on unknown workspace, missing target, or any path that escapes the root. */
|
|
44
|
+
private resolve;
|
|
45
|
+
listDirectory(workspace: string, relPath?: string): Promise<DirListing>;
|
|
46
|
+
readFile(workspace: string, relPath: string): Promise<FileContent>;
|
|
47
|
+
/** Find files whose relative path contains `query` (case-insensitive). Walks the
|
|
48
|
+
* tree breadth-first, skipping `.git`/`node_modules` and never following symlinks
|
|
49
|
+
* (so it stays contained), bounded by a scan budget and a result cap. */
|
|
50
|
+
search(workspace: string, query: string): Promise<SearchResult>;
|
|
51
|
+
gitDiff(workspace: string, relPath?: string): Promise<WorkspaceDiff>;
|
|
52
|
+
}
|
package/dist/i18n/types.d.ts
CHANGED
|
@@ -25,6 +25,13 @@ export interface SessionMessages {
|
|
|
25
25
|
modeModeLabel: (modeId: string) => string;
|
|
26
26
|
modeNotSet: string;
|
|
27
27
|
modeSet: (modeId: string) => string;
|
|
28
|
+
modelHeader: string;
|
|
29
|
+
modelSessionLabel: (alias: string) => string;
|
|
30
|
+
modelModelLabel: (modelId: string) => string;
|
|
31
|
+
modelNotSet: string;
|
|
32
|
+
modelAvailableLabel: (models: string) => string;
|
|
33
|
+
modelSet: (modelId: string) => string;
|
|
34
|
+
modelSetFailed: (modelId: string, detail: string) => string;
|
|
28
35
|
replyModeHeader: string;
|
|
29
36
|
replyModeSessionLabel: (alias: string) => string;
|
|
30
37
|
replyModeGlobalDefault: (value: string) => string;
|
|
@@ -101,6 +108,11 @@ export interface SessionMessages {
|
|
|
101
108
|
modeHelpCmdShowDesc: string;
|
|
102
109
|
modeHelpCmdSet: string;
|
|
103
110
|
modeHelpCmdSetDesc: string;
|
|
111
|
+
modelHelpSummary: string;
|
|
112
|
+
modelHelpCmdShow: string;
|
|
113
|
+
modelHelpCmdShowDesc: string;
|
|
114
|
+
modelHelpCmdSet: string;
|
|
115
|
+
modelHelpCmdSetDesc: string;
|
|
104
116
|
replyModeHelpSummary: string;
|
|
105
117
|
replyModeHelpCmdShow: string;
|
|
106
118
|
replyModeHelpCmdShowDesc: string;
|
package/dist/plugin-api.d.ts
CHANGED
|
@@ -18,3 +18,6 @@ export type { BackgroundResult } from "./state/types.js";
|
|
|
18
18
|
export type { ChatRequestMetadata } from "./weixin/agent/interface.js";
|
|
19
19
|
export { getLocale } from "./i18n/index.js";
|
|
20
20
|
export type { Locale } from "./i18n/index.js";
|
|
21
|
+
export type { ControlExecuteCommandInput, ControlPromptInput, ControlPromptResult, ControlService, ControlSessionInfo, } from "./control/control-service.js";
|
|
22
|
+
export type { ControlEvent, ControlEventBus, ControlEventListener } from "./control/control-event-bus.js";
|
|
23
|
+
export { coreHomeDir } from "./runtime/core-home.js";
|
package/dist/plugin-api.js
CHANGED
|
@@ -90,6 +90,14 @@ var init_session = __esm(() => {
|
|
|
90
90
|
modeModeLabel: (modeId) => `- mode: ${modeId}`,
|
|
91
91
|
modeNotSet: "not set",
|
|
92
92
|
modeSet: (modeId) => `Current session mode set to: ${modeId}`,
|
|
93
|
+
modelHeader: "Current model:",
|
|
94
|
+
modelSessionLabel: (alias) => `- Session: ${alias}`,
|
|
95
|
+
modelModelLabel: (modelId) => `- model: ${modelId}`,
|
|
96
|
+
modelNotSet: "not set (using agent default)",
|
|
97
|
+
modelAvailableLabel: (models) => `- available: ${models}`,
|
|
98
|
+
modelSet: (modelId) => `Current session model switched to: ${modelId}`,
|
|
99
|
+
modelSetFailed: (modelId, detail) => `Failed to switch model: ${modelId}
|
|
100
|
+
${detail}`,
|
|
93
101
|
replyModeHeader: "Current reply mode:",
|
|
94
102
|
replyModeSessionLabel: (alias) => `- Session: ${alias}`,
|
|
95
103
|
replyModeGlobalDefault: (value) => `- Global default: ${value}`,
|
|
@@ -166,6 +174,11 @@ var init_session = __esm(() => {
|
|
|
166
174
|
modeHelpCmdShowDesc: "Show the saved mode of the current session",
|
|
167
175
|
modeHelpCmdSet: "/mode <id>",
|
|
168
176
|
modeHelpCmdSetDesc: "Set the current session mode",
|
|
177
|
+
modelHelpSummary: "View or switch the LLM model for the current session.",
|
|
178
|
+
modelHelpCmdShow: "/model",
|
|
179
|
+
modelHelpCmdShowDesc: "Show the current session model and the available ones",
|
|
180
|
+
modelHelpCmdSet: "/model <id>",
|
|
181
|
+
modelHelpCmdSetDesc: "Switch the current session model (e.g. gpt-5.2[high])",
|
|
169
182
|
replyModeHelpSummary: "View or set the reply output mode for the current logical session.",
|
|
170
183
|
replyModeHelpCmdShow: "/replymode",
|
|
171
184
|
replyModeHelpCmdShowDesc: "Show global default, current override, and effective value",
|
|
@@ -1169,6 +1182,14 @@ var init_session2 = __esm(() => {
|
|
|
1169
1182
|
modeModeLabel: (modeId) => `- mode:${modeId}`,
|
|
1170
1183
|
modeNotSet: "未设置",
|
|
1171
1184
|
modeSet: (modeId) => `已设置当前会话 mode:${modeId}`,
|
|
1185
|
+
modelHeader: "当前 model:",
|
|
1186
|
+
modelSessionLabel: (alias) => `- 会话:${alias}`,
|
|
1187
|
+
modelModelLabel: (modelId) => `- model:${modelId}`,
|
|
1188
|
+
modelNotSet: "未设置(使用 agent 默认)",
|
|
1189
|
+
modelAvailableLabel: (models) => `- 可选:${models}`,
|
|
1190
|
+
modelSet: (modelId) => `已切换当前会话 model:${modelId}`,
|
|
1191
|
+
modelSetFailed: (modelId, detail) => `切换 model 失败:${modelId}
|
|
1192
|
+
${detail}`,
|
|
1172
1193
|
replyModeHeader: "当前 reply mode:",
|
|
1173
1194
|
replyModeSessionLabel: (alias) => `- 会话:${alias}`,
|
|
1174
1195
|
replyModeGlobalDefault: (value) => `- 全局默认:${value}`,
|
|
@@ -1245,6 +1266,11 @@ var init_session2 = __esm(() => {
|
|
|
1245
1266
|
modeHelpCmdShowDesc: "查看当前会话已保存的 mode",
|
|
1246
1267
|
modeHelpCmdSet: "/mode <id>",
|
|
1247
1268
|
modeHelpCmdSetDesc: "设置当前会话 mode",
|
|
1269
|
+
modelHelpSummary: "查看或切换当前会话的 LLM model。",
|
|
1270
|
+
modelHelpCmdShow: "/model",
|
|
1271
|
+
modelHelpCmdShowDesc: "查看当前会话 model 及可选项",
|
|
1272
|
+
modelHelpCmdSet: "/model <id>",
|
|
1273
|
+
modelHelpCmdSetDesc: "切换当前会话 model(如 gpt-5.2[high])",
|
|
1248
1274
|
replyModeHelpSummary: "查看或设置当前逻辑会话的回复输出模式。",
|
|
1249
1275
|
replyModeHelpCmdShow: "/replymode",
|
|
1250
1276
|
replyModeHelpCmdShowDesc: "查看全局默认、当前覆盖和实际生效值",
|
|
@@ -2444,6 +2470,13 @@ function createActiveTurnRegistry() {
|
|
|
2444
2470
|
},
|
|
2445
2471
|
isActive(chatKey, alias) {
|
|
2446
2472
|
return byChat.get(chatKey)?.has(alias) ?? false;
|
|
2473
|
+
},
|
|
2474
|
+
isActiveAnywhere(alias) {
|
|
2475
|
+
for (const set of byChat.values()) {
|
|
2476
|
+
if (set.has(alias))
|
|
2477
|
+
return true;
|
|
2478
|
+
}
|
|
2479
|
+
return false;
|
|
2447
2480
|
}
|
|
2448
2481
|
};
|
|
2449
2482
|
}
|
|
@@ -2527,6 +2560,24 @@ var init_channel_scope = __esm(() => {
|
|
|
2527
2560
|
KNOWN_CHANNEL_IDS = new Set(["weixin"]);
|
|
2528
2561
|
});
|
|
2529
2562
|
|
|
2563
|
+
// src/runtime/core-home.ts
|
|
2564
|
+
import { existsSync } from "node:fs";
|
|
2565
|
+
import { join } from "node:path";
|
|
2566
|
+
function coreHomeDir(home) {
|
|
2567
|
+
const primary = join(home, CORE_HOME_DIR_NAME);
|
|
2568
|
+
if (existsSync(primary))
|
|
2569
|
+
return primary;
|
|
2570
|
+
const legacy = join(home, CORE_HOME_LEGACY_DIR_NAME);
|
|
2571
|
+
if (existsSync(legacy))
|
|
2572
|
+
return legacy;
|
|
2573
|
+
return primary;
|
|
2574
|
+
}
|
|
2575
|
+
function coreHomeDisplayPath(...segments) {
|
|
2576
|
+
return ["~", CORE_HOME_DIR_NAME, ...segments].join("/");
|
|
2577
|
+
}
|
|
2578
|
+
var CORE_HOME_DIR_NAME = ".xacpx", CORE_HOME_LEGACY_DIR_NAME = ".weacpx";
|
|
2579
|
+
var init_core_home = () => {};
|
|
2580
|
+
|
|
2530
2581
|
// src/plugin-api.ts
|
|
2531
2582
|
init_types();
|
|
2532
2583
|
|
|
@@ -2540,12 +2591,14 @@ function resolveTurnLane(text) {
|
|
|
2540
2591
|
// src/plugin-api.ts
|
|
2541
2592
|
init_channel_scope();
|
|
2542
2593
|
init_i18n();
|
|
2594
|
+
init_core_home();
|
|
2543
2595
|
export {
|
|
2544
2596
|
toDisplaySessionAlias,
|
|
2545
2597
|
resolveTurnLane,
|
|
2546
2598
|
getLocale,
|
|
2547
2599
|
createConversationExecutor,
|
|
2548
2600
|
createActiveTurnRegistry,
|
|
2601
|
+
coreHomeDir,
|
|
2549
2602
|
XACPX_PLUGIN_MIN_CORE_VERSION,
|
|
2550
2603
|
XACPX_PLUGIN_API_VERSION,
|
|
2551
2604
|
XACPX_PLUGIN_API_SUPPORTED_VERSIONS,
|
|
@@ -29,6 +29,9 @@ export declare class ScheduledTaskService {
|
|
|
29
29
|
constructor(state: AppState, stateStore: Pick<StateStore, "save">, options?: ScheduledTaskServiceOptions);
|
|
30
30
|
createTask(input: CreateScheduledTaskInput): Promise<ScheduledTaskRecord>;
|
|
31
31
|
listPending(chatKey: string): ScheduledTaskRecord[];
|
|
32
|
+
listRecentForChat(chatKey: string, opts?: {
|
|
33
|
+
terminalLimit?: number;
|
|
34
|
+
}): ScheduledTaskRecord[];
|
|
32
35
|
listPendingAllChats(): ScheduledTaskRecord[];
|
|
33
36
|
cancelPending(inputId: string, chatKey: string): Promise<boolean>;
|
|
34
37
|
cancelPendingAnyChat(inputId: string): Promise<boolean>;
|
|
@@ -2,5 +2,7 @@ export interface ActiveTurnRegistry {
|
|
|
2
2
|
markActive(chatKey: string, alias: string): void;
|
|
3
3
|
markInactive(chatKey: string, alias: string): void;
|
|
4
4
|
isActive(chatKey: string, alias: string): boolean;
|
|
5
|
+
/** True when any chat currently has a turn running for this alias. */
|
|
6
|
+
isActiveAnywhere(alias: string): boolean;
|
|
5
7
|
}
|
|
6
8
|
export declare function createActiveTurnRegistry(): ActiveTurnRegistry;
|
|
@@ -113,6 +113,10 @@ export declare class SessionService {
|
|
|
113
113
|
getNativeSessionList(chatKey: string, ttlMs?: number): Promise<NativeSessionListResult | null>;
|
|
114
114
|
private deleteNativeSessionListIfCurrent;
|
|
115
115
|
private toResolvedSession;
|
|
116
|
+
/** Persist (or clear) a session's model override by internal alias. */
|
|
117
|
+
setSessionModel(alias: string, modelId: string | undefined): Promise<void>;
|
|
118
|
+
/** Persist (or clear) the model override of the chat's current session. */
|
|
119
|
+
setCurrentSessionModel(chatKey: string, modelId: string | undefined): Promise<void>;
|
|
116
120
|
setSessionTransportAgentCommand(alias: string, transportAgentCommand: string | undefined): Promise<void>;
|
|
117
121
|
private mutate;
|
|
118
122
|
private persist;
|
package/dist/state/types.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export interface LogicalSession {
|
|
|
27
27
|
attached_at?: string;
|
|
28
28
|
transport_agent_command?: string;
|
|
29
29
|
mode_id?: string;
|
|
30
|
+
/** Per-session LLM model override (e.g. `gpt-5.2[high]`); falls back to the agent config default. */
|
|
31
|
+
model?: string;
|
|
30
32
|
reply_mode?: "stream" | "final" | "verbose";
|
|
31
33
|
created_at: string;
|
|
32
34
|
last_used_at: string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ToolUseEvent } from "../channels/types";
|
|
2
|
+
export type NativeHistoryPart = {
|
|
3
|
+
kind: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "reasoning";
|
|
7
|
+
text: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "tool";
|
|
10
|
+
tool: ToolUseEvent;
|
|
11
|
+
};
|
|
12
|
+
export interface NativeHistoryMessage {
|
|
13
|
+
role: "user" | "agent";
|
|
14
|
+
/** Flattened text (the `out`/`in` body); `parts` carries the ordered transcript for agents. */
|
|
15
|
+
text: string;
|
|
16
|
+
/** Ordered transcript for agent turns (text / reasoning / tool), as the agent produced it. */
|
|
17
|
+
parts?: NativeHistoryPart[];
|
|
18
|
+
}
|
|
19
|
+
/** Map an acpx SessionMessage[] (the persisted conversation) to neutral history. The
|
|
20
|
+
* `"Resume"` marker entries are dropped. Pure + defensive: unknown shapes are skipped. */
|
|
21
|
+
export declare function mapAcpxMessagesToHistory(raw: unknown): NativeHistoryMessage[];
|
|
22
|
+
export interface ReadNativeHistoryOptions {
|
|
23
|
+
agentSessionId: string;
|
|
24
|
+
agentCommand?: string;
|
|
25
|
+
/** Override for the acpx sessions dir (tests). Defaults to `<home>/.acpx/sessions`. */
|
|
26
|
+
sessionsDir?: string;
|
|
27
|
+
homeDir?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Recover a native (agent-side) session's prior conversation from acpx's own persisted
|
|
30
|
+
* record. Best-effort: any I/O or shape problem yields `[]` so a native attach never
|
|
31
|
+
* fails just because history couldn't be read. When several records share the same
|
|
32
|
+
* acp_session_id (the source record + the freshly-created empty attach record), the
|
|
33
|
+
* one with the most messages wins — i.e. the real history, not the empty stub. */
|
|
34
|
+
export declare function readNativeSessionHistory(opts: ReadNativeHistoryOptions): Promise<NativeHistoryMessage[]>;
|