@ganglion/xacpx 0.24.5 → 0.24.6-beta.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/dist/adapters/adapter-catalog.d.ts +2 -2
- package/dist/bots/bot-types.d.ts +31 -0
- package/dist/bridge/bridge-main.js +30 -4
- package/dist/bridge/engine/runtime/runtime-worker-main.js +30 -3
- package/dist/cli.js +86 -22
- package/dist/commands/session-remove-lifecycle.d.ts +9 -0
- package/dist/config/types.d.ts +1 -1
- package/dist/control/control-service.d.ts +23 -0
- package/dist/control/session-turn-runner.d.ts +2 -0
- package/dist/control/turn-queue.d.ts +8 -0
- package/dist/conversations/conversation-types.d.ts +67 -1
- package/dist/state/types.d.ts +13 -0
- package/package.json +3 -2
|
@@ -2,12 +2,12 @@ export declare const MANAGED_ADAPTERS: {
|
|
|
2
2
|
readonly codex: {
|
|
3
3
|
readonly packageName: "@agentclientprotocol/codex-acp";
|
|
4
4
|
readonly binName: "codex-acp";
|
|
5
|
-
readonly defaultVersion: "1.
|
|
5
|
+
readonly defaultVersion: "1.12.0";
|
|
6
6
|
};
|
|
7
7
|
readonly claude: {
|
|
8
8
|
readonly packageName: "@agentclientprotocol/claude-agent-acp";
|
|
9
9
|
readonly binName: "claude-agent-acp";
|
|
10
|
-
readonly defaultVersion: "0.
|
|
10
|
+
readonly defaultVersion: "0.78.0";
|
|
11
11
|
};
|
|
12
12
|
};
|
|
13
13
|
export type ManagedAdapterId = keyof typeof MANAGED_ADAPTERS;
|
package/dist/bots/bot-types.d.ts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
export type BotRuntimeScope = "bot-direct" | "group-member" | "group-controller";
|
|
2
|
+
export interface BotProfilePresentation {
|
|
3
|
+
name: string;
|
|
4
|
+
avatar?: string;
|
|
5
|
+
role?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BotProfileBehavior {
|
|
8
|
+
instructions?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface BotProfileExecution {
|
|
11
|
+
agent: string;
|
|
12
|
+
workspace: string;
|
|
13
|
+
model?: string;
|
|
14
|
+
effort?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Durable linearization of the Bot fields a Run was accepted against. */
|
|
17
|
+
export interface BotProfileSnapshot {
|
|
18
|
+
revision: number;
|
|
19
|
+
capturedAt: string;
|
|
20
|
+
presentation: BotProfilePresentation;
|
|
21
|
+
behavior: BotProfileBehavior;
|
|
22
|
+
execution: BotProfileExecution;
|
|
23
|
+
}
|
|
2
24
|
export interface BotProfile {
|
|
3
25
|
id: string;
|
|
4
26
|
name: string;
|
|
@@ -11,9 +33,18 @@ export interface BotProfile {
|
|
|
11
33
|
model?: string;
|
|
12
34
|
effort?: string;
|
|
13
35
|
enabled: boolean;
|
|
36
|
+
/** Monotonic Bot-config generation. Missing on PR2 records; parse defaults to 1. */
|
|
37
|
+
profileRevision: number;
|
|
14
38
|
createdAt: string;
|
|
15
39
|
updatedAt: string;
|
|
16
40
|
}
|
|
41
|
+
export declare function sessionMatchesExecution(session: {
|
|
42
|
+
agent: string;
|
|
43
|
+
workspace: string;
|
|
44
|
+
model?: string;
|
|
45
|
+
effort?: string;
|
|
46
|
+
}, execution: BotProfileExecution): boolean;
|
|
47
|
+
export declare function snapshotBotProfile(bot: BotProfile, capturedAt: string): BotProfileSnapshot;
|
|
17
48
|
interface BotRuntimeBindingBase {
|
|
18
49
|
id: string;
|
|
19
50
|
conversationId: string;
|
|
@@ -7254,12 +7254,12 @@ var init_adapter_catalog = __esm(() => {
|
|
|
7254
7254
|
codex: {
|
|
7255
7255
|
packageName: "@agentclientprotocol/codex-acp",
|
|
7256
7256
|
binName: "codex-acp",
|
|
7257
|
-
defaultVersion: "1.
|
|
7257
|
+
defaultVersion: "1.12.0"
|
|
7258
7258
|
},
|
|
7259
7259
|
claude: {
|
|
7260
7260
|
packageName: "@agentclientprotocol/claude-agent-acp",
|
|
7261
7261
|
binName: "claude-agent-acp",
|
|
7262
|
-
defaultVersion: "0.
|
|
7262
|
+
defaultVersion: "0.78.0"
|
|
7263
7263
|
}
|
|
7264
7264
|
};
|
|
7265
7265
|
EXACT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
@@ -14539,8 +14539,9 @@ class RuntimeEngine {
|
|
|
14539
14539
|
}
|
|
14540
14540
|
} else if (event.type === "status") {
|
|
14541
14541
|
if (event.tag === "plan") {
|
|
14542
|
-
|
|
14543
|
-
|
|
14542
|
+
const entries = toPromptPlanEntries(event.entries);
|
|
14543
|
+
if (entries)
|
|
14544
|
+
sink({ type: "prompt.plan", entries });
|
|
14544
14545
|
return;
|
|
14545
14546
|
}
|
|
14546
14547
|
if (typeof event.used === "number" && typeof event.size === "number") {
|
|
@@ -16255,6 +16256,31 @@ async function buildRuntimeAttachments(media) {
|
|
|
16255
16256
|
}
|
|
16256
16257
|
return attachments;
|
|
16257
16258
|
}
|
|
16259
|
+
var PROMPT_PLAN_STATUSES = new Set(["pending", "in_progress", "completed"]);
|
|
16260
|
+
var PROMPT_PLAN_PRIORITIES = new Set(["high", "medium", "low"]);
|
|
16261
|
+
function toPromptPlanEntries(value) {
|
|
16262
|
+
if (!Array.isArray(value))
|
|
16263
|
+
return;
|
|
16264
|
+
if (value.length === 0)
|
|
16265
|
+
return [];
|
|
16266
|
+
const entries = [];
|
|
16267
|
+
for (const item of value) {
|
|
16268
|
+
if (typeof item !== "object" || item === null)
|
|
16269
|
+
continue;
|
|
16270
|
+
const record = item;
|
|
16271
|
+
const content = typeof record.content === "string" ? record.content.trim() : "";
|
|
16272
|
+
const status = typeof record.status === "string" ? record.status.trim() : "";
|
|
16273
|
+
if (!content || !PROMPT_PLAN_STATUSES.has(status))
|
|
16274
|
+
continue;
|
|
16275
|
+
const priority = typeof record.priority === "string" ? record.priority.trim() : "";
|
|
16276
|
+
entries.push({
|
|
16277
|
+
content,
|
|
16278
|
+
status,
|
|
16279
|
+
...PROMPT_PLAN_PRIORITIES.has(priority) ? { priority } : {}
|
|
16280
|
+
});
|
|
16281
|
+
}
|
|
16282
|
+
return entries.length > 0 ? entries : undefined;
|
|
16283
|
+
}
|
|
16258
16284
|
function mapRuntimeToolEvent(event) {
|
|
16259
16285
|
const toolCallId = event.toolCallId || `tc-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
16260
16286
|
const title = (event.title ?? "").trim();
|
|
@@ -5872,12 +5872,12 @@ var init_adapter_catalog = __esm(() => {
|
|
|
5872
5872
|
codex: {
|
|
5873
5873
|
packageName: "@agentclientprotocol/codex-acp",
|
|
5874
5874
|
binName: "codex-acp",
|
|
5875
|
-
defaultVersion: "1.
|
|
5875
|
+
defaultVersion: "1.12.0"
|
|
5876
5876
|
},
|
|
5877
5877
|
claude: {
|
|
5878
5878
|
packageName: "@agentclientprotocol/claude-agent-acp",
|
|
5879
5879
|
binName: "claude-agent-acp",
|
|
5880
|
-
defaultVersion: "0.
|
|
5880
|
+
defaultVersion: "0.78.0"
|
|
5881
5881
|
}
|
|
5882
5882
|
};
|
|
5883
5883
|
EXACT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
@@ -7157,6 +7157,7 @@ async function* mapEvents(events) {
|
|
|
7157
7157
|
};
|
|
7158
7158
|
}
|
|
7159
7159
|
} else if (event.type === "status") {
|
|
7160
|
+
const planEntries = normalizeAdapterPlanEntries(event.entries);
|
|
7160
7161
|
yield {
|
|
7161
7162
|
type: "status",
|
|
7162
7163
|
text: event.text,
|
|
@@ -7165,7 +7166,8 @@ async function* mapEvents(events) {
|
|
|
7165
7166
|
...event.size !== undefined ? { size: event.size } : {},
|
|
7166
7167
|
...event.cost ? { cost: event.cost } : {},
|
|
7167
7168
|
...event.breakdown ? { breakdown: event.breakdown } : {},
|
|
7168
|
-
...event.availableCommands ? { availableCommands: event.availableCommands } : {}
|
|
7169
|
+
...event.availableCommands ? { availableCommands: event.availableCommands } : {},
|
|
7170
|
+
...planEntries !== undefined ? { entries: planEntries } : {}
|
|
7169
7171
|
};
|
|
7170
7172
|
} else if (event.type === "tool_call") {
|
|
7171
7173
|
const isInitialToolEvent = typeof event.toolCallId === "string" ? !toolCalls.has(event.toolCallId) : event.tag !== "tool_call_update";
|
|
@@ -7188,6 +7190,31 @@ async function* mapEvents(events) {
|
|
|
7188
7190
|
}
|
|
7189
7191
|
}
|
|
7190
7192
|
}
|
|
7193
|
+
var ADAPTER_PLAN_STATUSES = new Set(["pending", "in_progress", "completed"]);
|
|
7194
|
+
var ADAPTER_PLAN_PRIORITIES = new Set(["high", "medium", "low"]);
|
|
7195
|
+
function normalizeAdapterPlanEntries(value) {
|
|
7196
|
+
if (!Array.isArray(value))
|
|
7197
|
+
return;
|
|
7198
|
+
if (value.length === 0)
|
|
7199
|
+
return [];
|
|
7200
|
+
const entries = [];
|
|
7201
|
+
for (const entry of value) {
|
|
7202
|
+
if (typeof entry !== "object" || entry === null)
|
|
7203
|
+
continue;
|
|
7204
|
+
const record = entry;
|
|
7205
|
+
const content = typeof record.content === "string" ? record.content.trim() : "";
|
|
7206
|
+
const status = typeof record.status === "string" ? record.status.trim() : "";
|
|
7207
|
+
if (!content || !ADAPTER_PLAN_STATUSES.has(status))
|
|
7208
|
+
continue;
|
|
7209
|
+
const priority = typeof record.priority === "string" ? record.priority.trim() : "";
|
|
7210
|
+
entries.push({
|
|
7211
|
+
content,
|
|
7212
|
+
status,
|
|
7213
|
+
...ADAPTER_PLAN_PRIORITIES.has(priority) ? { priority } : {}
|
|
7214
|
+
});
|
|
7215
|
+
}
|
|
7216
|
+
return entries.length > 0 ? entries : undefined;
|
|
7217
|
+
}
|
|
7191
7218
|
async function mapResult(result) {
|
|
7192
7219
|
const settled = await result;
|
|
7193
7220
|
if (settled.status === "failed") {
|
package/dist/cli.js
CHANGED
|
@@ -4355,12 +4355,12 @@ var init_adapter_catalog = __esm(() => {
|
|
|
4355
4355
|
codex: {
|
|
4356
4356
|
packageName: "@agentclientprotocol/codex-acp",
|
|
4357
4357
|
binName: "codex-acp",
|
|
4358
|
-
defaultVersion: "1.
|
|
4358
|
+
defaultVersion: "1.12.0"
|
|
4359
4359
|
},
|
|
4360
4360
|
claude: {
|
|
4361
4361
|
packageName: "@agentclientprotocol/claude-agent-acp",
|
|
4362
4362
|
binName: "claude-agent-acp",
|
|
4363
|
-
defaultVersion: "0.
|
|
4363
|
+
defaultVersion: "0.78.0"
|
|
4364
4364
|
}
|
|
4365
4365
|
};
|
|
4366
4366
|
EXACT_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
@@ -30740,7 +30740,11 @@ function isLogicalSessionOwner(value) {
|
|
|
30740
30740
|
if (!isRecord4(value)) {
|
|
30741
30741
|
return false;
|
|
30742
30742
|
}
|
|
30743
|
-
|
|
30743
|
+
if (value.kind !== "bot-direct" && value.kind !== "group-member" && value.kind !== "group-controller" || !isString(value.bindingId) || value.bindingId.length === 0) {
|
|
30744
|
+
return false;
|
|
30745
|
+
}
|
|
30746
|
+
const optional3 = (field) => value[field] === undefined || isString(value[field]) && value[field].length > 0;
|
|
30747
|
+
return optional3("botId") && optional3("conversationId") && optional3("topicId");
|
|
30744
30748
|
}
|
|
30745
30749
|
function parseSessions(raw, dropped, migrated) {
|
|
30746
30750
|
const sessions = {};
|
|
@@ -30836,7 +30840,7 @@ function isBotProfile(value) {
|
|
|
30836
30840
|
if (!isRecord4(value)) {
|
|
30837
30841
|
return false;
|
|
30838
30842
|
}
|
|
30839
|
-
return isString(value.id) && isString(value.name) && isOptionalString(value.avatar) && isOptionalString(value.role) && isOptionalString(value.instructions) && isString(value.agent) && isString(value.workspace) && isOptionalString(value.cwd) && isOptionalString(value.model) && isOptionalString(value.effort) && typeof value.enabled === "boolean" && isString(value.createdAt) && isString(value.updatedAt);
|
|
30843
|
+
return isString(value.id) && isString(value.name) && isOptionalString(value.avatar) && isOptionalString(value.role) && isOptionalString(value.instructions) && isString(value.agent) && isString(value.workspace) && isOptionalString(value.cwd) && isOptionalString(value.model) && isOptionalString(value.effort) && typeof value.enabled === "boolean" && (value.profileRevision === undefined || typeof value.profileRevision === "number" && Number.isInteger(value.profileRevision) && value.profileRevision >= 1) && isString(value.createdAt) && isString(value.updatedAt);
|
|
30840
30844
|
}
|
|
30841
30845
|
function parseBotProfiles(raw, dropped) {
|
|
30842
30846
|
const source = sectionRecord(raw, "bots", dropped);
|
|
@@ -30846,7 +30850,10 @@ function parseBotProfiles(raw, dropped) {
|
|
|
30846
30850
|
dropped.push({ section: "bots", key: id, reason: "malformed bot profile" });
|
|
30847
30851
|
continue;
|
|
30848
30852
|
}
|
|
30849
|
-
bots[id] =
|
|
30853
|
+
bots[id] = {
|
|
30854
|
+
...value,
|
|
30855
|
+
profileRevision: value.profileRevision ?? 1
|
|
30856
|
+
};
|
|
30850
30857
|
}
|
|
30851
30858
|
return bots;
|
|
30852
30859
|
}
|
|
@@ -30860,6 +30867,9 @@ function isConversationRecord(value) {
|
|
|
30860
30867
|
if (!isString(value.id) || !isString(value.title) || !isOptionalString(value.description) || !isUniqueStringArray(value.botIds) || !isOptionalString(value.leadBotId) || !isString(value.createdAt) || !isString(value.updatedAt)) {
|
|
30861
30868
|
return false;
|
|
30862
30869
|
}
|
|
30870
|
+
if (value.lifecycle !== undefined && value.lifecycle !== "active" && value.lifecycle !== "deleting") {
|
|
30871
|
+
return false;
|
|
30872
|
+
}
|
|
30863
30873
|
if (value.leadBotId !== undefined && !value.botIds.includes(value.leadBotId)) {
|
|
30864
30874
|
return false;
|
|
30865
30875
|
}
|
|
@@ -30887,7 +30897,7 @@ function isConversationTopic(value) {
|
|
|
30887
30897
|
if (!isRecord4(value)) {
|
|
30888
30898
|
return false;
|
|
30889
30899
|
}
|
|
30890
|
-
return isString(value.id) && isString(value.conversationId) && isString(value.title) && (value.status === "active" || value.status === "archived") && isString(value.createdAt) && isString(value.updatedAt);
|
|
30900
|
+
return isString(value.id) && isString(value.conversationId) && isString(value.title) && (value.status === "active" || value.status === "archived" || value.status === "deleting") && isString(value.createdAt) && isString(value.updatedAt);
|
|
30891
30901
|
}
|
|
30892
30902
|
function parseConversationTopics(raw, dropped) {
|
|
30893
30903
|
const source = sectionRecord(raw, "conversation_topics", dropped);
|
|
@@ -42581,6 +42591,7 @@ function lockForPhysicalKey(physicalKey) {
|
|
|
42581
42591
|
}
|
|
42582
42592
|
async function removeAliasWithPhysicalLifecycle(options) {
|
|
42583
42593
|
const { sessions, transport, session: session3, internalAlias } = options;
|
|
42594
|
+
const policy = options.physicalFailurePolicy ?? "legacy-cli-best-effort";
|
|
42584
42595
|
const groupKey = physicalLifecycleKeyForResolvedSession(session3);
|
|
42585
42596
|
const isRuntime = session3.transportEngine === "runtime";
|
|
42586
42597
|
return lockForPhysicalKey(groupKey).run(async () => {
|
|
@@ -42610,9 +42621,14 @@ async function removeAliasWithPhysicalLifecycle(options) {
|
|
|
42610
42621
|
await transport.deleteSession(session3);
|
|
42611
42622
|
action = "deleted";
|
|
42612
42623
|
} catch (error2) {
|
|
42624
|
+
if (policy === "strict") {
|
|
42625
|
+
throw error2;
|
|
42626
|
+
}
|
|
42613
42627
|
transportTeardownWarning = error2 instanceof Error ? error2.message : String(error2);
|
|
42614
42628
|
action = "logical-only";
|
|
42615
42629
|
}
|
|
42630
|
+
} else if (remaining === 0 && policy === "strict") {
|
|
42631
|
+
throw new Error(`cannot hard-delete last CLI alias "${internalAlias}": transport has no deleteSession operation`);
|
|
42616
42632
|
} else {
|
|
42617
42633
|
action = "logical-only";
|
|
42618
42634
|
}
|
|
@@ -63134,6 +63150,7 @@ ${envelope}` : envelope;
|
|
|
63134
63150
|
return {
|
|
63135
63151
|
ok: false,
|
|
63136
63152
|
errorMessage,
|
|
63153
|
+
...!timedOut && signal.aborted ? { cancelled: true } : {},
|
|
63137
63154
|
...internalAlias && priorTransportSession ? { postTurnDetection: { internalAlias, priorTransportSession } } : {}
|
|
63138
63155
|
};
|
|
63139
63156
|
}
|
|
@@ -63558,10 +63575,13 @@ class TurnQueue {
|
|
|
63558
63575
|
return {
|
|
63559
63576
|
ok: result.ok,
|
|
63560
63577
|
...result.text !== undefined ? { text: result.text } : {},
|
|
63561
|
-
...result.errorMessage !== undefined ? { errorMessage: result.errorMessage } : {}
|
|
63578
|
+
...result.errorMessage !== undefined ? { errorMessage: result.errorMessage } : {},
|
|
63579
|
+
...result.cancelled ? { cancelled: true } : {}
|
|
63562
63580
|
};
|
|
63563
63581
|
}
|
|
63564
63582
|
advanceQueue(key) {
|
|
63583
|
+
const finished = this.inFlight.get(key);
|
|
63584
|
+
this.recordSettledRequestId(finished?.promptRequestId);
|
|
63565
63585
|
const interrupt = this.pendingInterrupts.get(key);
|
|
63566
63586
|
if (interrupt) {
|
|
63567
63587
|
this.pendingInterrupts.delete(key);
|
|
@@ -63616,6 +63636,26 @@ class TurnQueue {
|
|
|
63616
63636
|
entry.controller.abort();
|
|
63617
63637
|
return true;
|
|
63618
63638
|
}
|
|
63639
|
+
cancelTurnForPromptRequest(chatKey, sessionAlias, promptRequestId, concurrencyKey) {
|
|
63640
|
+
const key = this.resolveKey(chatKey, sessionAlias, concurrencyKey);
|
|
63641
|
+
const entry = this.inFlight.get(key);
|
|
63642
|
+
if (!entry || entry.promptRequestId !== promptRequestId) {
|
|
63643
|
+
return false;
|
|
63644
|
+
}
|
|
63645
|
+
entry.controller.abort();
|
|
63646
|
+
return true;
|
|
63647
|
+
}
|
|
63648
|
+
inspectPromptRequest(chatKey, sessionAlias, promptRequestId, concurrencyKey) {
|
|
63649
|
+
const key = this.resolveKey(chatKey, sessionAlias, concurrencyKey);
|
|
63650
|
+
const entry = this.inFlight.get(key);
|
|
63651
|
+
if (entry?.promptRequestId === promptRequestId) {
|
|
63652
|
+
return "in-flight";
|
|
63653
|
+
}
|
|
63654
|
+
if (this.hasSettledRequestId(promptRequestId)) {
|
|
63655
|
+
return "settled";
|
|
63656
|
+
}
|
|
63657
|
+
return "absent";
|
|
63658
|
+
}
|
|
63619
63659
|
async clearSession(chatKey, sessionAlias, concurrencyKey) {
|
|
63620
63660
|
const key = this.resolveKey(chatKey, sessionAlias, concurrencyKey);
|
|
63621
63661
|
const guardPreexisting = this.removing.has(key);
|
|
@@ -64202,26 +64242,40 @@ class ControlService {
|
|
|
64202
64242
|
return task;
|
|
64203
64243
|
}
|
|
64204
64244
|
async prompt(input) {
|
|
64245
|
+
return this.submitHumanPrompt(input, true);
|
|
64246
|
+
}
|
|
64247
|
+
async promptImmediate(input) {
|
|
64248
|
+
return this.submitHumanPrompt(input, false);
|
|
64249
|
+
}
|
|
64250
|
+
submitHumanPrompt(input, queueable) {
|
|
64205
64251
|
const channelId = getChannelIdFromChatKey(input.chatKey);
|
|
64206
64252
|
const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(input.sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, input.sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, input.sessionAlias);
|
|
64207
64253
|
const configTail = this.sessionConfigSetTails.get(internalAlias) ?? this.sessionConfigSetTails.get(input.sessionAlias);
|
|
64254
|
+
const turnOrigin = queueable ? "human" : input.executionOrigin === "human" ? "human" : "orchestration";
|
|
64255
|
+
const submit = () => {
|
|
64256
|
+
if (input.abortSignal?.aborted) {
|
|
64257
|
+
return Promise.resolve({ ok: false, cancelled: true, errorMessage: "cancelled" });
|
|
64258
|
+
}
|
|
64259
|
+
return this.turnQueue.submit({
|
|
64260
|
+
chatKey: input.chatKey,
|
|
64261
|
+
sessionAlias: input.sessionAlias,
|
|
64262
|
+
concurrencyKey: internalAlias,
|
|
64263
|
+
text: input.text,
|
|
64264
|
+
senderId: input.senderId,
|
|
64265
|
+
turnOrigin,
|
|
64266
|
+
queueable,
|
|
64267
|
+
...input.isOwner !== undefined ? { isOwner: input.isOwner } : {},
|
|
64268
|
+
...input.accountId !== undefined ? { accountId: input.accountId } : {},
|
|
64269
|
+
...input.media !== undefined ? { media: input.media } : {},
|
|
64270
|
+
...input.agentMentions !== undefined ? { agentMentions: input.agentMentions } : {},
|
|
64271
|
+
...input.promptRequestId !== undefined ? { promptRequestId: input.promptRequestId } : {},
|
|
64272
|
+
...input.abortSignal !== undefined ? { abortSignal: input.abortSignal } : {}
|
|
64273
|
+
});
|
|
64274
|
+
};
|
|
64208
64275
|
if (configTail) {
|
|
64209
|
-
|
|
64276
|
+
return configTail.catch(() => {}).then(submit);
|
|
64210
64277
|
}
|
|
64211
|
-
return
|
|
64212
|
-
chatKey: input.chatKey,
|
|
64213
|
-
sessionAlias: input.sessionAlias,
|
|
64214
|
-
concurrencyKey: internalAlias,
|
|
64215
|
-
text: input.text,
|
|
64216
|
-
senderId: input.senderId,
|
|
64217
|
-
turnOrigin: "human",
|
|
64218
|
-
queueable: true,
|
|
64219
|
-
...input.isOwner !== undefined ? { isOwner: input.isOwner } : {},
|
|
64220
|
-
...input.accountId !== undefined ? { accountId: input.accountId } : {},
|
|
64221
|
-
...input.media !== undefined ? { media: input.media } : {},
|
|
64222
|
-
...input.agentMentions !== undefined ? { agentMentions: input.agentMentions } : {},
|
|
64223
|
-
...input.promptRequestId !== undefined ? { promptRequestId: input.promptRequestId } : {}
|
|
64224
|
-
});
|
|
64278
|
+
return submit();
|
|
64225
64279
|
}
|
|
64226
64280
|
async runScheduledTurn(input) {
|
|
64227
64281
|
const channelId = getChannelIdFromChatKey(input.chatKey);
|
|
@@ -64260,6 +64314,16 @@ class ControlService {
|
|
|
64260
64314
|
const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, sessionAlias);
|
|
64261
64315
|
return this.turnQueue.cancelTurn(chatKey, sessionAlias, internalAlias);
|
|
64262
64316
|
}
|
|
64317
|
+
cancelTurnForPromptRequest(chatKey, sessionAlias, promptRequestId) {
|
|
64318
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
64319
|
+
const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, sessionAlias);
|
|
64320
|
+
return this.turnQueue.cancelTurnForPromptRequest(chatKey, sessionAlias, promptRequestId, internalAlias);
|
|
64321
|
+
}
|
|
64322
|
+
inspectPromptRequest(chatKey, sessionAlias, promptRequestId) {
|
|
64323
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
64324
|
+
const internalAlias = this.deps.sessions.getResolvedSessionByInternalAlias?.(sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, sessionAlias);
|
|
64325
|
+
return this.turnQueue.inspectPromptRequest(chatKey, sessionAlias, promptRequestId, internalAlias);
|
|
64326
|
+
}
|
|
64263
64327
|
async submitPeerTurn(input) {
|
|
64264
64328
|
const channelId = getChannelIdFromChatKey(input.chatKey);
|
|
64265
64329
|
const internalAlias = input.boundSessionAlias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(input.sessionAlias)?.alias ?? this.deps.sessions.getResolvedSessionByInternalAlias?.(toInternalSessionAlias(channelId, input.sessionAlias))?.alias ?? scopeDisplayAliasToInternal(channelId, input.sessionAlias);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SessionService } from "../sessions/session-service";
|
|
2
2
|
import type { ResolvedSession, SessionTransport } from "../transport/types";
|
|
3
|
+
export type PhysicalFailurePolicy = "legacy-cli-best-effort" | "strict";
|
|
3
4
|
export interface PhysicalRemoveOutcome {
|
|
4
5
|
wasActive: boolean;
|
|
5
6
|
/**
|
|
@@ -26,6 +27,14 @@ export declare function removeAliasWithPhysicalLifecycle(options: {
|
|
|
26
27
|
transport: Pick<SessionTransport, "releaseLogicalSession" | "deleteSession">;
|
|
27
28
|
session: ResolvedSession;
|
|
28
29
|
internalAlias: string;
|
|
30
|
+
/**
|
|
31
|
+
* Default `legacy-cli-best-effort` keeps `/session rm` semantics: a CLI
|
|
32
|
+
* last-owner `deleteSession` failure records a warning and still removes
|
|
33
|
+
* the LogicalSession. `strict` is the Bot/Conversation owned-session
|
|
34
|
+
* path: any Runtime or CLI physical failure throws BEFORE the logical row
|
|
35
|
+
* disappears so callers keep the retry handle.
|
|
36
|
+
*/
|
|
37
|
+
physicalFailurePolicy?: PhysicalFailurePolicy;
|
|
29
38
|
}): Promise<PhysicalRemoveOutcome>;
|
|
30
39
|
export interface ProvisionalSessionCleanup {
|
|
31
40
|
sessions: SessionService;
|
package/dist/config/types.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ export interface TransportConfig {
|
|
|
71
71
|
*/
|
|
72
72
|
turnIdleTimeoutSeconds?: number;
|
|
73
73
|
/**
|
|
74
|
-
* Advanced acpx embedding-host ceilings (acpx 0.15.1
|
|
74
|
+
* Advanced acpx embedding-host ceilings (acpx 0.15.1+, plan B5).
|
|
75
75
|
* `acpxMaxIncomingMessageBytes` overrides the 64 MiB default ceiling on
|
|
76
76
|
* agent → acpx inbound ACP messages (`0` = unlimited — avoid unless a real
|
|
77
77
|
* workload needs it); `acpxTerminalMaxOutputBytes` caps retained
|
|
@@ -7,6 +7,7 @@ import type { ScheduledTaskRecord } from "../scheduled/scheduled-types";
|
|
|
7
7
|
import type { CancelTaskInput, OrchestrationService, OrchestrationTaskFilter } from "../orchestration/orchestration-service";
|
|
8
8
|
import type { OrchestrationTaskRecord } from "../orchestration/orchestration-types";
|
|
9
9
|
import type { AgentMessageCompletion, AgentMessageMode } from "../orchestration/agent-messaging-types";
|
|
10
|
+
import type { PermissionInteractionOrigin } from "../permissions/permission-types.js";
|
|
10
11
|
import type { ControlEventBus } from "./control-event-bus";
|
|
11
12
|
import type { AgentCatalogEntry } from "../config/agent-catalog";
|
|
12
13
|
import { type BrowseDirsResult, type DirListing, type FileContent, type SearchOptions, type SearchResult, type WorkspaceDiff } from "./workspace-fs";
|
|
@@ -221,11 +222,23 @@ export interface ControlPromptInput {
|
|
|
221
222
|
* turn-started so the hub can tie a queued prompt back to its pre-written inbound
|
|
222
223
|
* row (see PromptPayload.promptRequestId). */
|
|
223
224
|
promptRequestId?: string;
|
|
225
|
+
/** Conversation pre-admission cancel. Checked after any config-tail wait and
|
|
226
|
+
* immediately before TurnQueue.submit so a cancelled Run never starts. */
|
|
227
|
+
abortSignal?: AbortSignal;
|
|
228
|
+
/**
|
|
229
|
+
* Conversation execution provenance, derived by ConversationStore at claim
|
|
230
|
+
* from the live authority epoch. `promptImmediate` fail-closes to
|
|
231
|
+
* orchestration unless this is exactly `"human"`. Interactive `prompt()`
|
|
232
|
+
* ignores it and is always human. Omitting it cannot mint human authority.
|
|
233
|
+
*/
|
|
234
|
+
executionOrigin?: PermissionInteractionOrigin;
|
|
224
235
|
}
|
|
225
236
|
export interface ControlPromptResult {
|
|
226
237
|
ok: boolean;
|
|
227
238
|
text?: string;
|
|
228
239
|
errorMessage?: string;
|
|
240
|
+
/** Proven cancellation (AbortSignal / user Stop), not an error string match. */
|
|
241
|
+
cancelled?: boolean;
|
|
229
242
|
/** True when this prompt did not run immediately and was instead appended to the
|
|
230
243
|
* per-session server-side queue (a turn was already in flight). */
|
|
231
244
|
queued?: boolean;
|
|
@@ -386,6 +399,14 @@ export declare class ControlService {
|
|
|
386
399
|
getOrchestrationTask(taskId: string): Promise<OrchestrationTaskRecord | null>;
|
|
387
400
|
cancelOrchestrationTask(input: CancelTaskInput): Promise<OrchestrationTaskRecord>;
|
|
388
401
|
prompt(input: ControlPromptInput): Promise<ControlPromptResult>;
|
|
402
|
+
/**
|
|
403
|
+
* Conversation execution seam: same TurnQueue / SessionTurnRunner path as
|
|
404
|
+
* `prompt()`, but never FIFO-enqueues when the session lane is busy.
|
|
405
|
+
* Turn origin is the store-derived `executionOrigin` (fail-closed to
|
|
406
|
+
* orchestration). ConversationStore already owns durable queuing.
|
|
407
|
+
*/
|
|
408
|
+
promptImmediate(input: ControlPromptInput): Promise<ControlPromptResult>;
|
|
409
|
+
private submitHumanPrompt;
|
|
389
410
|
/** Run a fired scheduled task as a real turn through the same machinery as a manual
|
|
390
411
|
* prompt — so it streams live and persists to history — while tagging turn-started
|
|
391
412
|
* with the prompt text + schedule origin so the hub records the inbound message and
|
|
@@ -395,6 +416,8 @@ export declare class ControlService {
|
|
|
395
416
|
isBusy(chatKey: string, sessionAlias: string): boolean;
|
|
396
417
|
isSessionBusy(internalAlias: string): boolean;
|
|
397
418
|
cancelTurn(chatKey: string, sessionAlias: string): boolean;
|
|
419
|
+
cancelTurnForPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string): boolean;
|
|
420
|
+
inspectPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string): "in-flight" | "settled" | "absent";
|
|
398
421
|
submitPeerTurn(input: {
|
|
399
422
|
chatKey: string;
|
|
400
423
|
sessionAlias: string;
|
|
@@ -36,6 +36,8 @@ export interface TurnResult {
|
|
|
36
36
|
ok: boolean;
|
|
37
37
|
text?: string;
|
|
38
38
|
errorMessage?: string;
|
|
39
|
+
/** Proven user-Stop / abort cancellation. Idle-timeout aborts omit this. */
|
|
40
|
+
cancelled?: boolean;
|
|
39
41
|
postTurnDetection?: {
|
|
40
42
|
internalAlias: string;
|
|
41
43
|
priorTransportSession: string;
|
|
@@ -150,6 +150,14 @@ export declare class TurnQueue {
|
|
|
150
150
|
private advanceQueue;
|
|
151
151
|
private drainQueuedPrompt;
|
|
152
152
|
cancelTurn(chatKey: string, sessionAlias: string, concurrencyKey?: string): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Abort the in-flight turn only when it is the given promptRequestId.
|
|
155
|
+
* A minted Conversation correlation id is not a lane-wide cancel: a later
|
|
156
|
+
* prompt on the same session must not be aborted, and a settled request
|
|
157
|
+
* must not be treated as cancelled just because Stop was pressed late.
|
|
158
|
+
*/
|
|
159
|
+
cancelTurnForPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string, concurrencyKey?: string): boolean;
|
|
160
|
+
inspectPromptRequest(chatKey: string, sessionAlias: string, promptRequestId: string, concurrencyKey?: string): "in-flight" | "settled" | "absent";
|
|
153
161
|
/** Tear down all turn state for a session that is being removed or archived: drop every
|
|
154
162
|
* queued prompt, abort a running turn, and wait (bounded) for it to unwind. The queue is
|
|
155
163
|
* cleared BEFORE the abort so the aborting turn's finally sees it empty and releases the
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import type { BotProfileSnapshot } from "../bots/bot-types";
|
|
1
2
|
export type ConversationKind = "bot" | "group";
|
|
2
|
-
export type
|
|
3
|
+
export type ConversationLifecycle = "active" | "deleting";
|
|
4
|
+
export type ConversationTopicStatus = "active" | "archived" | "deleting";
|
|
3
5
|
export type ConversationMessageRole = "human" | "bot" | "system";
|
|
4
6
|
export type GroupTurnOrigin = "human-explicit" | "controller" | "handoff" | "recovery";
|
|
5
7
|
export type GroupTurnState = "queued" | "running" | "completed" | "failed" | "cancelled";
|
|
8
|
+
export type ConversationRunMode = "explicit";
|
|
9
|
+
export type ConversationRunState = "queued" | "running" | "waiting-human" | "completed" | "failed" | "cancelled" | "indeterminate";
|
|
10
|
+
export type MemberTurnOrigin = "human" | "followup" | "retry" | "recovery";
|
|
11
|
+
export type MemberTurnState = "queued" | "dispatched" | "running" | "completed" | "failed" | "cancelled" | "indeterminate";
|
|
12
|
+
export type PendingDispatchState = "pending" | "claimed" | "completed";
|
|
6
13
|
export interface ConversationRecord {
|
|
7
14
|
id: string;
|
|
8
15
|
kind: ConversationKind;
|
|
@@ -10,6 +17,8 @@ export interface ConversationRecord {
|
|
|
10
17
|
description?: string;
|
|
11
18
|
botIds: string[];
|
|
12
19
|
leadBotId?: string;
|
|
20
|
+
/** Bounded AppState lifecycle flag. SQLite conversation_lifecycle is authoritative for dispatch. */
|
|
21
|
+
lifecycle?: ConversationLifecycle;
|
|
13
22
|
createdAt: string;
|
|
14
23
|
updatedAt: string;
|
|
15
24
|
}
|
|
@@ -25,17 +34,71 @@ export interface ConversationMessage {
|
|
|
25
34
|
id: string;
|
|
26
35
|
conversationId: string;
|
|
27
36
|
topicId: string;
|
|
37
|
+
seq: number;
|
|
28
38
|
role: ConversationMessageRole;
|
|
29
39
|
senderBotId?: string;
|
|
30
40
|
recipients?: string[];
|
|
31
41
|
content: string;
|
|
32
42
|
replyTo?: string;
|
|
43
|
+
runId?: string;
|
|
33
44
|
createdAt: string;
|
|
34
45
|
sourceTurn?: {
|
|
35
46
|
sessionAlias: string;
|
|
36
47
|
turnId?: string;
|
|
37
48
|
};
|
|
38
49
|
}
|
|
50
|
+
export interface ConversationRun {
|
|
51
|
+
id: string;
|
|
52
|
+
conversationId: string;
|
|
53
|
+
topicId: string;
|
|
54
|
+
requestMessageId: string;
|
|
55
|
+
requestId: string;
|
|
56
|
+
mode: ConversationRunMode;
|
|
57
|
+
state: ConversationRunState;
|
|
58
|
+
completionReason?: string;
|
|
59
|
+
generation: number;
|
|
60
|
+
maxMemberTurns: number;
|
|
61
|
+
consumedMemberTurns: number;
|
|
62
|
+
profileRevision: number;
|
|
63
|
+
profileSnapshot: BotProfileSnapshot;
|
|
64
|
+
createdAt: string;
|
|
65
|
+
startedAt?: string;
|
|
66
|
+
finishedAt?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface MemberTurnRecord {
|
|
69
|
+
id: string;
|
|
70
|
+
runId: string;
|
|
71
|
+
conversationId: string;
|
|
72
|
+
topicId: string;
|
|
73
|
+
botId: string;
|
|
74
|
+
sessionAlias?: string;
|
|
75
|
+
logicalSessionId?: string;
|
|
76
|
+
sourceTurnId?: string;
|
|
77
|
+
queueItemId?: string;
|
|
78
|
+
batch: number;
|
|
79
|
+
attempt: number;
|
|
80
|
+
origin: MemberTurnOrigin;
|
|
81
|
+
state: MemberTurnState;
|
|
82
|
+
triggerMessageIds: string[];
|
|
83
|
+
createdAt: string;
|
|
84
|
+
startedAt?: string;
|
|
85
|
+
finishedAt?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface PendingDispatch {
|
|
88
|
+
id: string;
|
|
89
|
+
runId: string;
|
|
90
|
+
memberTurnId: string;
|
|
91
|
+
generation: number;
|
|
92
|
+
state: PendingDispatchState;
|
|
93
|
+
owner?: string;
|
|
94
|
+
leaseExpiresAt?: string;
|
|
95
|
+
/** Live dispatcher epoch that accepted this work. Matching claim keeps human
|
|
96
|
+
* permission authority; mismatch or revoked epoch is recovery/orchestration. */
|
|
97
|
+
authorityEpoch?: string;
|
|
98
|
+
createdAt: string;
|
|
99
|
+
claimedAt?: string;
|
|
100
|
+
completedAt?: string;
|
|
101
|
+
}
|
|
39
102
|
export interface GroupTurnRecord {
|
|
40
103
|
id: string;
|
|
41
104
|
conversationId: string;
|
|
@@ -49,3 +112,6 @@ export interface GroupTurnRecord {
|
|
|
49
112
|
startedAt?: string;
|
|
50
113
|
finishedAt?: string;
|
|
51
114
|
}
|
|
115
|
+
export declare const ACTIVE_RUN_STATES: readonly ConversationRunState[];
|
|
116
|
+
export declare const TERMINAL_RUN_STATES: readonly ConversationRunState[];
|
|
117
|
+
export declare const TERMINAL_MEMBER_STATES: readonly MemberTurnState[];
|
package/dist/state/types.d.ts
CHANGED
|
@@ -7,7 +7,20 @@ export type LogicalSessionSource = "xacpx" | "agent-side";
|
|
|
7
7
|
export interface LogicalSessionOwner {
|
|
8
8
|
kind: "bot-direct" | "group-member" | "group-controller";
|
|
9
9
|
bindingId: string;
|
|
10
|
+
/**
|
|
11
|
+
* Explicit Bot id for scoped bot-direct ownership. Optional on PR2 records
|
|
12
|
+
* that only stored `bindingId` (the legacy deterministic default-Topic id).
|
|
13
|
+
*/
|
|
14
|
+
botId?: string;
|
|
15
|
+
conversationId?: string;
|
|
16
|
+
topicId?: string;
|
|
10
17
|
}
|
|
18
|
+
export declare function createBotDirectOwner(input: {
|
|
19
|
+
bindingId: string;
|
|
20
|
+
botId: string;
|
|
21
|
+
conversationId: string;
|
|
22
|
+
topicId: string;
|
|
23
|
+
}): LogicalSessionOwner;
|
|
11
24
|
export interface NativeSessionCacheEntry {
|
|
12
25
|
session_id: string;
|
|
13
26
|
cwd?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ganglion/xacpx",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.6-beta.0",
|
|
4
4
|
"description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acpx",
|
|
@@ -86,12 +86,13 @@
|
|
|
86
86
|
"test:unit": "node ./scripts/run-tests.mjs tests/unit",
|
|
87
87
|
"test:smoke": "node ./scripts/run-tests.mjs tests/smoke",
|
|
88
88
|
"test:compat:acpx": "node ./scripts/run-tests.mjs tests/compat",
|
|
89
|
+
"test:release-boundary": "node ./scripts/release-plan-boundary.mjs",
|
|
89
90
|
"lint:acpx-imports": "node ./scripts/lint-acpx-imports.mjs",
|
|
90
91
|
"smoke:local-install": "node ./scripts/smoke-local-install.mjs"
|
|
91
92
|
},
|
|
92
93
|
"dependencies": {
|
|
93
94
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
94
|
-
"acpx": "0.
|
|
95
|
+
"acpx": "0.16.0",
|
|
95
96
|
"node-pty": "^1.1.0",
|
|
96
97
|
"proper-lockfile": "^4.1.2",
|
|
97
98
|
"protobufjs": "^7.5.6",
|