@cjhyy/code-shell-core 0.8.7 → 0.8.9
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/cli/agent-server-stdio.js +7 -5
- package/dist/context/manager.js +10 -2
- package/dist/engine/engine.d.ts +60 -8
- package/dist/engine/engine.js +187 -35
- package/dist/engine/run-finalize.js +8 -6
- package/dist/engine/run-session-open.js +1 -1
- package/dist/engine/run-setup.d.ts +5 -0
- package/dist/engine/run-setup.js +6 -1
- package/dist/engine/run-tooling.js +7 -1
- package/dist/engine/run-types.d.ts +31 -0
- package/dist/engine/run-types.js +21 -0
- package/dist/engine/run-workspace.js +11 -5
- package/dist/engine/turn-loop.d.ts +0 -3
- package/dist/engine/turn-loop.js +1 -80
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/panel-apps/manifest.d.ts +11 -11
- package/dist/panel-apps/manifest.js +7 -3
- package/dist/prompt/composer.d.ts +15 -0
- package/dist/prompt/composer.js +23 -8
- package/dist/protocol/chat-session-manager.js +9 -0
- package/dist/protocol/server.js +77 -1
- package/dist/protocol/types.d.ts +26 -0
- package/dist/session/memory.d.ts +10 -0
- package/dist/session/memory.js +7 -1
- package/dist/session/session-manager.d.ts +3 -1
- package/dist/session/session-manager.js +42 -25
- package/dist/session/transcript.d.ts +36 -0
- package/dist/session/transcript.js +149 -4
- package/dist/tool-system/builtin/index.js +4 -1
- package/dist/tool-system/path-policy.js +25 -33
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -93,11 +93,17 @@ export async function resolveRunWorkspace(args) {
|
|
|
93
93
|
configCwd: args.configCwd,
|
|
94
94
|
processCwd: args.processCwd,
|
|
95
95
|
});
|
|
96
|
-
const profileState =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
const profileState = profile?.disableWorkspaceProfile
|
|
97
|
+
? {
|
|
98
|
+
workspaceProfile: undefined,
|
|
99
|
+
sessionProfileOverrides: undefined,
|
|
100
|
+
profileMemoryDir: undefined,
|
|
101
|
+
}
|
|
102
|
+
: resolveRunProfileState({
|
|
103
|
+
sessionWorkspaceProfile,
|
|
104
|
+
cwd,
|
|
105
|
+
settings: args.settings,
|
|
106
|
+
});
|
|
101
107
|
return {
|
|
102
108
|
ok: true,
|
|
103
109
|
resolution: {
|
|
@@ -202,9 +202,6 @@ export declare class TurnLoop {
|
|
|
202
202
|
* loop forces a stop so a stuck goal can't loop forever.
|
|
203
203
|
*/
|
|
204
204
|
private stopBlockCount;
|
|
205
|
-
/** Consecutive identical tool-call/result batches, ignoring provider call ids. */
|
|
206
|
-
private repeatedToolBatchFingerprint;
|
|
207
|
-
private repeatedToolBatchCount;
|
|
208
205
|
/**
|
|
209
206
|
* Run-scoped goal budget tracker (Goal mode). Hoisted to an instance field
|
|
210
207
|
* (not a run() local) so extend() can bump its budgets mid-run. Null when no
|
package/dist/engine/turn-loop.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Following Claude Code's po_() pattern:
|
|
5
5
|
* pre_check → model_call → post_check → tool_exec → context_mgmt → hook_notify → next turn
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
8
|
import { buildAgentDirectionMessage } from "../tool-system/builtin/agent-notifications.js";
|
|
9
9
|
import { newTurnId } from "./turn-state.js";
|
|
10
10
|
import { formatFriendlyError } from "./friendly-error.js";
|
|
@@ -40,39 +40,6 @@ export function toolResultToBlock(result) {
|
|
|
40
40
|
block.is_error = true;
|
|
41
41
|
return block;
|
|
42
42
|
}
|
|
43
|
-
const REPEATED_TOOL_BATCH_LIMIT = 3;
|
|
44
|
-
function canonicalToolValue(value) {
|
|
45
|
-
if (value === null)
|
|
46
|
-
return "null";
|
|
47
|
-
if (value === undefined)
|
|
48
|
-
return "undefined";
|
|
49
|
-
if (Array.isArray(value))
|
|
50
|
-
return `[${value.map(canonicalToolValue).join(",")}]`;
|
|
51
|
-
if (typeof value === "object") {
|
|
52
|
-
return `{${Object.entries(value)
|
|
53
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
54
|
-
.map(([key, entry]) => `${JSON.stringify(key)}:${canonicalToolValue(entry)}`)
|
|
55
|
-
.join(",")}}`;
|
|
56
|
-
}
|
|
57
|
-
return JSON.stringify(value);
|
|
58
|
-
}
|
|
59
|
-
function repeatedToolBatchFingerprint(toolCalls, results) {
|
|
60
|
-
// Hash immediately and never log the canonical source: tool results may
|
|
61
|
-
// contain credentials or large media payloads. Call ids are deliberately
|
|
62
|
-
// omitted because providers generate a fresh id for every identical retry.
|
|
63
|
-
return createHash("sha256")
|
|
64
|
-
.update(canonicalToolValue({
|
|
65
|
-
calls: toolCalls.map((call) => ({ toolName: call.toolName, args: call.args })),
|
|
66
|
-
results: results.map((result) => ({
|
|
67
|
-
toolName: result.toolName,
|
|
68
|
-
isError: result.isError === true || Boolean(result.error),
|
|
69
|
-
error: result.error,
|
|
70
|
-
result: result.result,
|
|
71
|
-
contentBlocks: result.contentBlocks,
|
|
72
|
-
})),
|
|
73
|
-
}))
|
|
74
|
-
.digest("hex");
|
|
75
|
-
}
|
|
76
43
|
export class TurnLoop {
|
|
77
44
|
deps;
|
|
78
45
|
config;
|
|
@@ -109,9 +76,6 @@ export class TurnLoop {
|
|
|
109
76
|
* loop forces a stop so a stuck goal can't loop forever.
|
|
110
77
|
*/
|
|
111
78
|
stopBlockCount = 0;
|
|
112
|
-
/** Consecutive identical tool-call/result batches, ignoring provider call ids. */
|
|
113
|
-
repeatedToolBatchFingerprint;
|
|
114
|
-
repeatedToolBatchCount = 0;
|
|
115
79
|
/**
|
|
116
80
|
* Run-scoped goal budget tracker (Goal mode). Hoisted to an instance field
|
|
117
81
|
* (not a run() local) so extend() can bump its budgets mid-run. Null when no
|
|
@@ -1445,49 +1409,6 @@ export class TurnLoop {
|
|
|
1445
1409
|
tlog.info("guard.stale_task", { cat: "guard", turn: this.turnCount });
|
|
1446
1410
|
}
|
|
1447
1411
|
}
|
|
1448
|
-
const toolBatchFingerprint = repeatedToolBatchFingerprint(toolCalls, results);
|
|
1449
|
-
if (toolBatchFingerprint === this.repeatedToolBatchFingerprint) {
|
|
1450
|
-
this.repeatedToolBatchCount++;
|
|
1451
|
-
}
|
|
1452
|
-
else {
|
|
1453
|
-
this.repeatedToolBatchFingerprint = toolBatchFingerprint;
|
|
1454
|
-
this.repeatedToolBatchCount = 1;
|
|
1455
|
-
}
|
|
1456
|
-
if (this.repeatedToolBatchCount >= REPEATED_TOOL_BATCH_LIMIT) {
|
|
1457
|
-
tlog.warn("turn.repeated_tool_batch_stopped", {
|
|
1458
|
-
cat: "turn",
|
|
1459
|
-
repeatedCount: this.repeatedToolBatchCount,
|
|
1460
|
-
tools: toolCalls.map((call) => call.toolName),
|
|
1461
|
-
});
|
|
1462
|
-
await this.emitHook("on_turn_end", {
|
|
1463
|
-
turnNumber: this.turnCount,
|
|
1464
|
-
hasToolUse: true,
|
|
1465
|
-
toolCallCount: toolCalls.length,
|
|
1466
|
-
});
|
|
1467
|
-
finalText =
|
|
1468
|
-
`检测到同一组工具调用及其结果连续重复 ${REPEATED_TOOL_BATCH_LIMIT} 次,` +
|
|
1469
|
-
"已自动停止,避免继续空转。请调整请求或让 Session 获取新的上下文后再试。";
|
|
1470
|
-
this.deps.transcript.appendMessage("assistant", finalText);
|
|
1471
|
-
messages.push({ role: "assistant", content: finalText });
|
|
1472
|
-
this.config.onStream?.({
|
|
1473
|
-
type: "assistant_message",
|
|
1474
|
-
messageId: assistantMessageId,
|
|
1475
|
-
message: { role: "assistant", content: finalText },
|
|
1476
|
-
});
|
|
1477
|
-
this.finalizeModelTurn();
|
|
1478
|
-
if (await this.consumeQueuedSteer(messages, "finalize_backfill")) {
|
|
1479
|
-
this.repeatedToolBatchFingerprint = undefined;
|
|
1480
|
-
this.repeatedToolBatchCount = 0;
|
|
1481
|
-
continue;
|
|
1482
|
-
}
|
|
1483
|
-
messages = this.redactConsumedSensitiveToolResults(messages);
|
|
1484
|
-
return {
|
|
1485
|
-
text: finalText,
|
|
1486
|
-
reason: "completed",
|
|
1487
|
-
messages,
|
|
1488
|
-
completionKind: "limit_stop",
|
|
1489
|
-
};
|
|
1490
|
-
}
|
|
1491
1412
|
// Hook: turn end
|
|
1492
1413
|
await this.emitHook("on_turn_end", {
|
|
1493
1414
|
turnNumber: this.turnCount,
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Public API exports.
|
|
5
5
|
*/
|
|
6
|
-
export declare const VERSION = "0.8.
|
|
6
|
+
export declare const VERSION = "0.8.9";
|
|
7
7
|
export type { Message, ContentBlock, ToolDefinition, ToolCall, ToolResult, RegisteredTool, TranscriptEvent, TranscriptEventType, SessionState, SessionKind, SessionWorkspace, SessionForkLineage, ContextUsageAnchor, SessionStatus, TokenUsage, CompiledInput, PermissionDecision, PermissionMode, PermissionRule, TurnPhase, TurnResult, TerminalReason, TurnCompletionKind, StreamEvent, StreamCallback, LLMConfig, ClientDefaults, LLMResponse, Settings, MCPServerConfig, } from "./types.js";
|
|
8
8
|
export type { GoalConfig, GoalLifecycleConfig, GoalLifecyclePhase, GoalLifecycleTerminalReason, GoalLifecycleV1, } from "./goal/lifecycle.js";
|
|
9
9
|
export { FrameworkError, LLMError, LLMRateLimitError, ContextLimitError, ToolError, ToolNotFoundError, ToolExecutionError, ToolTimeoutError, PermissionDeniedError, SessionError, TranscriptError, ConfigError, SandboxUnavailableError, } from "./exceptions.js";
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Public API exports.
|
|
5
5
|
*/
|
|
6
|
-
export const VERSION = "0.8.
|
|
6
|
+
export const VERSION = "0.8.9";
|
|
7
7
|
// ─── Exceptions ──────────────────────────────────────────────────
|
|
8
8
|
export { FrameworkError, LLMError, LLMRateLimitError, ContextLimitError, ToolError, ToolNotFoundError, ToolExecutionError, ToolTimeoutError, PermissionDeniedError, SessionError, TranscriptError, ConfigError, SandboxUnavailableError, } from "./exceptions.js";
|
|
9
9
|
// ─── Engine (primary API) ────────────────────────────────────────
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const PANEL_APP_MANIFEST_FILE = ".codeshell-panel/panel.json";
|
|
3
|
-
export declare const PANEL_APP_PERMISSIONS: readonly ["context.session", "context.workspace", "storage", "external.open", "agent.submitPrompt", "workspace.info", "workspace.read", "workspace.write", "notifications.send", "credentials.cookies", "automations.manage"];
|
|
3
|
+
export declare const PANEL_APP_PERMISSIONS: readonly ["context.session", "context.workspace", "storage", "external.open", "agent.submitPrompt", "agent.task", "workspace.info", "workspace.read", "workspace.write", "notifications.send", "audio.transcribe", "credentials.cookies", "automations.manage", "process"];
|
|
4
4
|
export declare const PANEL_APP_ICONS: readonly ["panel", "activity", "bar-chart-3", "chart", "file-text", "globe", "image", "layout-dashboard", "line-chart", "palette", "pie-chart", "table", "terminal"];
|
|
5
5
|
export declare const PanelAppAgentTool: z.ZodEffects<z.ZodObject<{
|
|
6
6
|
name: z.ZodString;
|
|
@@ -116,12 +116,12 @@ export declare const PanelAppManifest: z.ZodEffects<z.ZodDiscriminatedUnion<"sch
|
|
|
116
116
|
icon: z.ZodDefault<z.ZodEnum<["panel", "activity", "bar-chart-3", "chart", "file-text", "globe", "image", "layout-dashboard", "line-chart", "palette", "pie-chart", "table", "terminal"]>>;
|
|
117
117
|
placement: z.ZodDefault<z.ZodLiteral<"right-dock">>;
|
|
118
118
|
singleton: z.ZodDefault<z.ZodBoolean>;
|
|
119
|
-
permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<["context.session", "context.workspace", "storage", "external.open", "agent.submitPrompt", "workspace.info", "workspace.read", "workspace.write", "notifications.send", "credentials.cookies", "automations.manage"]>, "many">>;
|
|
119
|
+
permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<["context.session", "context.workspace", "storage", "external.open", "agent.submitPrompt", "agent.task", "workspace.info", "workspace.read", "workspace.write", "notifications.send", "audio.transcribe", "credentials.cookies", "automations.manage", "process"]>, "many">>;
|
|
120
120
|
schemaVersion: z.ZodLiteral<1>;
|
|
121
121
|
}, "strict", z.ZodTypeAny, {
|
|
122
122
|
id: string;
|
|
123
123
|
version: string;
|
|
124
|
-
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[];
|
|
124
|
+
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[];
|
|
125
125
|
entry: string;
|
|
126
126
|
title: {
|
|
127
127
|
default: string;
|
|
@@ -144,7 +144,7 @@ export declare const PanelAppManifest: z.ZodEffects<z.ZodDiscriminatedUnion<"sch
|
|
|
144
144
|
};
|
|
145
145
|
schemaVersion: 1;
|
|
146
146
|
description?: string | undefined;
|
|
147
|
-
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[] | undefined;
|
|
147
|
+
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[] | undefined;
|
|
148
148
|
icon?: "terminal" | "image" | "panel" | "activity" | "bar-chart-3" | "chart" | "file-text" | "globe" | "layout-dashboard" | "line-chart" | "palette" | "pie-chart" | "table" | undefined;
|
|
149
149
|
placement?: "right-dock" | undefined;
|
|
150
150
|
singleton?: boolean | undefined;
|
|
@@ -230,12 +230,12 @@ export declare const PanelAppManifest: z.ZodEffects<z.ZodDiscriminatedUnion<"sch
|
|
|
230
230
|
icon: z.ZodDefault<z.ZodEnum<["panel", "activity", "bar-chart-3", "chart", "file-text", "globe", "image", "layout-dashboard", "line-chart", "palette", "pie-chart", "table", "terminal"]>>;
|
|
231
231
|
placement: z.ZodDefault<z.ZodLiteral<"right-dock">>;
|
|
232
232
|
singleton: z.ZodDefault<z.ZodBoolean>;
|
|
233
|
-
permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<["context.session", "context.workspace", "storage", "external.open", "agent.submitPrompt", "workspace.info", "workspace.read", "workspace.write", "notifications.send", "credentials.cookies", "automations.manage"]>, "many">>;
|
|
233
|
+
permissions: z.ZodDefault<z.ZodArray<z.ZodEnum<["context.session", "context.workspace", "storage", "external.open", "agent.submitPrompt", "agent.task", "workspace.info", "workspace.read", "workspace.write", "notifications.send", "audio.transcribe", "credentials.cookies", "automations.manage", "process"]>, "many">>;
|
|
234
234
|
schemaVersion: z.ZodLiteral<2>;
|
|
235
235
|
}, "strict", z.ZodTypeAny, {
|
|
236
236
|
id: string;
|
|
237
237
|
version: string;
|
|
238
|
-
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[];
|
|
238
|
+
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[];
|
|
239
239
|
entry: string;
|
|
240
240
|
title: {
|
|
241
241
|
default: string;
|
|
@@ -276,14 +276,14 @@ export declare const PanelAppManifest: z.ZodEffects<z.ZodDiscriminatedUnion<"sch
|
|
|
276
276
|
}[] | undefined;
|
|
277
277
|
} | undefined;
|
|
278
278
|
description?: string | undefined;
|
|
279
|
-
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[] | undefined;
|
|
279
|
+
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[] | undefined;
|
|
280
280
|
icon?: "terminal" | "image" | "panel" | "activity" | "bar-chart-3" | "chart" | "file-text" | "globe" | "layout-dashboard" | "line-chart" | "palette" | "pie-chart" | "table" | undefined;
|
|
281
281
|
placement?: "right-dock" | undefined;
|
|
282
282
|
singleton?: boolean | undefined;
|
|
283
283
|
}>]>, {
|
|
284
284
|
id: string;
|
|
285
285
|
version: string;
|
|
286
|
-
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[];
|
|
286
|
+
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[];
|
|
287
287
|
entry: string;
|
|
288
288
|
title: {
|
|
289
289
|
default: string;
|
|
@@ -298,7 +298,7 @@ export declare const PanelAppManifest: z.ZodEffects<z.ZodDiscriminatedUnion<"sch
|
|
|
298
298
|
} | {
|
|
299
299
|
id: string;
|
|
300
300
|
version: string;
|
|
301
|
-
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[];
|
|
301
|
+
permissions: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[];
|
|
302
302
|
entry: string;
|
|
303
303
|
title: {
|
|
304
304
|
default: string;
|
|
@@ -330,7 +330,7 @@ export declare const PanelAppManifest: z.ZodEffects<z.ZodDiscriminatedUnion<"sch
|
|
|
330
330
|
};
|
|
331
331
|
schemaVersion: 1;
|
|
332
332
|
description?: string | undefined;
|
|
333
|
-
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[] | undefined;
|
|
333
|
+
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[] | undefined;
|
|
334
334
|
icon?: "terminal" | "image" | "panel" | "activity" | "bar-chart-3" | "chart" | "file-text" | "globe" | "layout-dashboard" | "line-chart" | "palette" | "pie-chart" | "table" | undefined;
|
|
335
335
|
placement?: "right-dock" | undefined;
|
|
336
336
|
singleton?: boolean | undefined;
|
|
@@ -354,7 +354,7 @@ export declare const PanelAppManifest: z.ZodEffects<z.ZodDiscriminatedUnion<"sch
|
|
|
354
354
|
}[] | undefined;
|
|
355
355
|
} | undefined;
|
|
356
356
|
description?: string | undefined;
|
|
357
|
-
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "credentials.cookies" | "automations.manage")[] | undefined;
|
|
357
|
+
permissions?: ("context.session" | "context.workspace" | "storage" | "external.open" | "agent.submitPrompt" | "agent.task" | "workspace.info" | "workspace.read" | "workspace.write" | "notifications.send" | "audio.transcribe" | "credentials.cookies" | "automations.manage" | "process")[] | undefined;
|
|
358
358
|
icon?: "terminal" | "image" | "panel" | "activity" | "bar-chart-3" | "chart" | "file-text" | "globe" | "layout-dashboard" | "line-chart" | "palette" | "pie-chart" | "table" | undefined;
|
|
359
359
|
placement?: "right-dock" | undefined;
|
|
360
360
|
singleton?: boolean | undefined;
|
|
@@ -7,12 +7,15 @@ export const PANEL_APP_PERMISSIONS = [
|
|
|
7
7
|
"storage",
|
|
8
8
|
"external.open",
|
|
9
9
|
"agent.submitPrompt",
|
|
10
|
+
"agent.task",
|
|
10
11
|
"workspace.info",
|
|
11
12
|
"workspace.read",
|
|
12
13
|
"workspace.write",
|
|
13
14
|
"notifications.send",
|
|
15
|
+
"audio.transcribe",
|
|
14
16
|
"credentials.cookies",
|
|
15
17
|
"automations.manage",
|
|
18
|
+
"process",
|
|
16
19
|
];
|
|
17
20
|
export const PANEL_APP_ICONS = [
|
|
18
21
|
"panel",
|
|
@@ -138,7 +141,7 @@ const PanelAppManifestFields = {
|
|
|
138
141
|
icon: z.enum(PANEL_APP_ICONS).default("panel"),
|
|
139
142
|
placement: z.literal("right-dock").default("right-dock"),
|
|
140
143
|
singleton: z.boolean().default(true),
|
|
141
|
-
permissions: z.array(z.enum(PANEL_APP_PERMISSIONS)).max(
|
|
144
|
+
permissions: z.array(z.enum(PANEL_APP_PERMISSIONS)).max(16).default([]),
|
|
142
145
|
};
|
|
143
146
|
/**
|
|
144
147
|
* Schema v2 keeps one installable Panel App identity while allowing it to
|
|
@@ -180,12 +183,13 @@ export const PanelAppManifest = z
|
|
|
180
183
|
});
|
|
181
184
|
}
|
|
182
185
|
if ((value.permissions.includes("workspace.read") ||
|
|
183
|
-
value.permissions.includes("workspace.write")
|
|
186
|
+
value.permissions.includes("workspace.write") ||
|
|
187
|
+
value.permissions.includes("audio.transcribe")) &&
|
|
184
188
|
!value.permissions.includes("context.workspace")) {
|
|
185
189
|
ctx.addIssue({
|
|
186
190
|
code: z.ZodIssueCode.custom,
|
|
187
191
|
path: ["permissions"],
|
|
188
|
-
message: "workspace.read
|
|
192
|
+
message: "workspace.read, workspace.write, and audio.transcribe require context.workspace",
|
|
189
193
|
});
|
|
190
194
|
}
|
|
191
195
|
if (value.permissions.includes("automations.manage") &&
|
|
@@ -89,6 +89,21 @@ export interface ComposerOptions {
|
|
|
89
89
|
* Undefined/0 → inject all.
|
|
90
90
|
*/
|
|
91
91
|
memoriesMaxAgeDays?: number;
|
|
92
|
+
/**
|
|
93
|
+
* When true (set from the active behavior profile, e.g. the Pet manager),
|
|
94
|
+
* the injected memory index keeps only memories relevant to this cwd —
|
|
95
|
+
* global-layer project/dream records tied to other projects are dropped.
|
|
96
|
+
* See MemoryManager.buildInjectionIndex(currentProjectOnly).
|
|
97
|
+
*/
|
|
98
|
+
memoryCurrentProjectOnly?: boolean;
|
|
99
|
+
/** Isolated runs can omit repository/user instruction discovery entirely. */
|
|
100
|
+
disableInstructions?: boolean;
|
|
101
|
+
/** Isolated runs can omit persistent-memory context entirely. */
|
|
102
|
+
disableMemoryContext?: boolean;
|
|
103
|
+
/** Isolated runs can omit capability-owned volatile context providers. */
|
|
104
|
+
disableCapabilityContext?: boolean;
|
|
105
|
+
/** Isolated runs can omit bound-source metadata. */
|
|
106
|
+
disableSourcesContext?: boolean;
|
|
92
107
|
}
|
|
93
108
|
export declare class PromptComposer {
|
|
94
109
|
private readonly options;
|
package/dist/prompt/composer.js
CHANGED
|
@@ -30,6 +30,8 @@ export class PromptComposer {
|
|
|
30
30
|
* Build the userContext prefix message (CLAUDE.md content as <system-reminder>).
|
|
31
31
|
*/
|
|
32
32
|
buildUserContextMessage() {
|
|
33
|
+
if (this.options.disableInstructions === true)
|
|
34
|
+
return null;
|
|
33
35
|
const instructions = this.getInstructions();
|
|
34
36
|
// NOTE: memory is intentionally NOT here. It used to be, but memory mutates
|
|
35
37
|
// constantly (extraction, recall usage++/lastUsed, approve/demote), and this
|
|
@@ -51,6 +53,8 @@ export class PromptComposer {
|
|
|
51
53
|
}
|
|
52
54
|
/** Build volatile context contributed by installed capability modules. */
|
|
53
55
|
async buildSystemContext() {
|
|
56
|
+
if (this.options.disableCapabilityContext === true)
|
|
57
|
+
return "";
|
|
54
58
|
const preset = this.options.preset ?? resolveAgentPreset();
|
|
55
59
|
const parts = await Promise.all((this.options.dynamicContextProviders ?? []).map(async (provider) => {
|
|
56
60
|
try {
|
|
@@ -102,18 +106,26 @@ export class PromptComposer {
|
|
|
102
106
|
});
|
|
103
107
|
const skillsListing = buildSkillListing(skills);
|
|
104
108
|
const declaredSkillGap = this.buildDeclaredSkillGap(skills);
|
|
105
|
-
|
|
109
|
+
// Capability and sources context are independent I/O — resolve them
|
|
110
|
+
// concurrently instead of serially.
|
|
111
|
+
const [capabilityContext, sourcesContext] = await Promise.all([
|
|
112
|
+
this.buildSystemContext(),
|
|
113
|
+
(async () => {
|
|
114
|
+
if (this.options.disableSourcesContext === true)
|
|
115
|
+
return "";
|
|
116
|
+
try {
|
|
117
|
+
return (await this.options.sourcesContextProvider?.()) ?? "";
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Optional metadata context must not make a turn fail.
|
|
121
|
+
return "";
|
|
122
|
+
}
|
|
123
|
+
})(),
|
|
124
|
+
]);
|
|
106
125
|
// Memory rides here (tail, past the cache breakpoint) — not the system
|
|
107
126
|
// prefix — so a memory change (extraction / recall usage++ / approve) never
|
|
108
127
|
// re-bills the cached prefix. See buildUserContextMessage for the rationale.
|
|
109
128
|
const memoryContext = this.getMemoryContext();
|
|
110
|
-
let sourcesContext = "";
|
|
111
|
-
try {
|
|
112
|
-
sourcesContext = (await this.options.sourcesContextProvider?.()) ?? "";
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
// Optional metadata context must not make a turn fail.
|
|
116
|
-
}
|
|
117
129
|
const goalToolContext = this.buildGoalToolContext();
|
|
118
130
|
const parts = [
|
|
119
131
|
skillsListing,
|
|
@@ -259,6 +271,8 @@ export class PromptComposer {
|
|
|
259
271
|
return this.cachedInstructions;
|
|
260
272
|
}
|
|
261
273
|
getMemoryContext() {
|
|
274
|
+
if (this.options.disableMemoryContext === true)
|
|
275
|
+
return "";
|
|
262
276
|
try {
|
|
263
277
|
// Three-layer injection (用户拍板): a compact index merging GLOBAL +
|
|
264
278
|
// DIGITAL-HUMAN + PROJECT memories. Global memories are surfaced every
|
|
@@ -268,6 +282,7 @@ export class PromptComposer {
|
|
|
268
282
|
projectDir: this.options.cwd,
|
|
269
283
|
profileDir: this.options.profileMemoryDir,
|
|
270
284
|
maxAgeDays: this.options.memoriesMaxAgeDays,
|
|
285
|
+
currentProjectOnly: this.options.memoryCurrentProjectOnly,
|
|
271
286
|
});
|
|
272
287
|
}
|
|
273
288
|
catch {
|
|
@@ -168,6 +168,9 @@ export class ChatSessionManager {
|
|
|
168
168
|
getLiveSessionSnapshot() {
|
|
169
169
|
const sessions = [];
|
|
170
170
|
this.forEachSession((session) => {
|
|
171
|
+
const sessionManager = this.engineSessionManager(session.engine);
|
|
172
|
+
if (sessionManager?.isEphemeralSession?.(session.id))
|
|
173
|
+
return;
|
|
171
174
|
sessions.push({
|
|
172
175
|
sessionId: session.id,
|
|
173
176
|
busy: session.isBusy(),
|
|
@@ -280,6 +283,12 @@ export class ChatSessionManager {
|
|
|
280
283
|
sweepIdle() {
|
|
281
284
|
const cutoff = Date.now() - this.idleTtlMs;
|
|
282
285
|
for (const [id, s] of [...this.sessions]) {
|
|
286
|
+
// Quick Chat transcripts are process-local by design. Closing one from
|
|
287
|
+
// the generic idle sweeper destroys its inherited context while the
|
|
288
|
+
// renderer still owns (and displays) the panel. Its explicit claim/
|
|
289
|
+
// panel lifecycle is the sole authority that may close it.
|
|
290
|
+
if (id.startsWith("qchat-"))
|
|
291
|
+
continue;
|
|
283
292
|
if (s.lastActivityAt >= cutoff)
|
|
284
293
|
continue;
|
|
285
294
|
if (s.isBusy())
|
package/dist/protocol/server.js
CHANGED
|
@@ -58,10 +58,39 @@ function runInputError(params) {
|
|
|
58
58
|
if (params.injected !== undefined && typeof params.injected !== "boolean") {
|
|
59
59
|
return "injected must be a boolean";
|
|
60
60
|
}
|
|
61
|
+
if (params.quickChatClaimId !== undefined &&
|
|
62
|
+
(typeof params.quickChatClaimId !== "string" || params.quickChatClaimId.length === 0)) {
|
|
63
|
+
return "quickChatClaimId must be a non-empty string";
|
|
64
|
+
}
|
|
61
65
|
if (params.behaviorMode !== undefined &&
|
|
62
66
|
(typeof params.behaviorMode !== "string" || params.behaviorMode.length === 0)) {
|
|
63
67
|
return `invalid behavior mode: ${String(params.behaviorMode)}`;
|
|
64
68
|
}
|
|
69
|
+
for (const [field, value, maxItems] of [
|
|
70
|
+
["toolAllowlist", params.toolAllowlist, 32],
|
|
71
|
+
["skillAllowlist", params.skillAllowlist, 8],
|
|
72
|
+
]) {
|
|
73
|
+
if (value === undefined)
|
|
74
|
+
continue;
|
|
75
|
+
if (!Array.isArray(value) ||
|
|
76
|
+
value.length > maxItems ||
|
|
77
|
+
value.some((name) => typeof name !== "string" || name.length === 0 || name.length > 128 || /[\r\n]/.test(name))) {
|
|
78
|
+
return `${field} must be an array of at most ${maxItems} bounded names`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (params.ephemeral !== undefined && typeof params.ephemeral !== "boolean") {
|
|
82
|
+
return "ephemeral must be a boolean";
|
|
83
|
+
}
|
|
84
|
+
if (params.maxTurns !== undefined &&
|
|
85
|
+
(!Number.isInteger(params.maxTurns) || params.maxTurns < 1 || params.maxTurns > 30)) {
|
|
86
|
+
return "maxTurns must be an integer from 1 to 30";
|
|
87
|
+
}
|
|
88
|
+
if (params.maxContextTokens !== undefined &&
|
|
89
|
+
(!Number.isInteger(params.maxContextTokens) ||
|
|
90
|
+
params.maxContextTokens < 4_096 ||
|
|
91
|
+
params.maxContextTokens > 131_072)) {
|
|
92
|
+
return "maxContextTokens must be an integer from 4096 to 131072";
|
|
93
|
+
}
|
|
65
94
|
if (params.kind !== undefined && (typeof params.kind !== "string" || params.kind.length === 0)) {
|
|
66
95
|
return `invalid session kind: ${String(params.kind)}`;
|
|
67
96
|
}
|
|
@@ -1080,6 +1109,8 @@ export class AgentServer {
|
|
|
1080
1109
|
const sessionConfig = {
|
|
1081
1110
|
cwd: params.cwd,
|
|
1082
1111
|
projectTrusted: params.projectTrusted,
|
|
1112
|
+
maxTurns: params.maxTurns,
|
|
1113
|
+
maxContextTokens: params.maxContextTokens,
|
|
1083
1114
|
goal: typeof params.goal === "string" || (params.goal != null && typeof params.goal === "object")
|
|
1084
1115
|
? params.goal
|
|
1085
1116
|
: undefined,
|
|
@@ -1163,6 +1194,9 @@ export class AgentServer {
|
|
|
1163
1194
|
permissionMode: params.permissionMode,
|
|
1164
1195
|
planMode: params.planMode,
|
|
1165
1196
|
behaviorMode: params.behaviorMode,
|
|
1197
|
+
toolAllowlist: params.toolAllowlist,
|
|
1198
|
+
skillAllowlist: params.skillAllowlist,
|
|
1199
|
+
ephemeral: params.ephemeral,
|
|
1166
1200
|
profileParams: params.profileParams,
|
|
1167
1201
|
workspaceProfile: params.workspaceProfile,
|
|
1168
1202
|
sessionBrief: params.sessionBrief,
|
|
@@ -1290,6 +1324,9 @@ export class AgentServer {
|
|
|
1290
1324
|
permissionMode: params.permissionMode,
|
|
1291
1325
|
planMode: params.planMode,
|
|
1292
1326
|
behaviorMode: params.behaviorMode,
|
|
1327
|
+
toolAllowlist: params.toolAllowlist,
|
|
1328
|
+
skillAllowlist: params.skillAllowlist,
|
|
1329
|
+
ephemeral: params.ephemeral,
|
|
1293
1330
|
profileParams: params.profileParams,
|
|
1294
1331
|
workspaceProfile: params.workspaceProfile,
|
|
1295
1332
|
sessionBrief: params.sessionBrief,
|
|
@@ -2240,7 +2277,17 @@ export class AgentServer {
|
|
|
2240
2277
|
if (!archiveEngine)
|
|
2241
2278
|
return;
|
|
2242
2279
|
try {
|
|
2243
|
-
const
|
|
2280
|
+
const toClientMessageId = typeof params.toClientMessageId === "string" ? params.toClientMessageId : undefined;
|
|
2281
|
+
const anchors = toClientMessageId
|
|
2282
|
+
? {
|
|
2283
|
+
toClientMessageId,
|
|
2284
|
+
...(typeof params.fromClientMessageId === "string"
|
|
2285
|
+
? { fromClientMessageId: params.fromClientMessageId }
|
|
2286
|
+
: {}),
|
|
2287
|
+
...(typeof params.segmentId === "string" ? { segmentId: params.segmentId } : {}),
|
|
2288
|
+
}
|
|
2289
|
+
: undefined;
|
|
2290
|
+
const result = await archiveEngine.archiveTurnRange(archiveSessionId, { start, end }, anchors);
|
|
2244
2291
|
if (result.before > result.after) {
|
|
2245
2292
|
const event = {
|
|
2246
2293
|
type: "context_compact",
|
|
@@ -2265,6 +2312,35 @@ export class AgentServer {
|
|
|
2265
2312
|
}
|
|
2266
2313
|
break;
|
|
2267
2314
|
}
|
|
2315
|
+
case "archive_marker": {
|
|
2316
|
+
const markerSessionId = typeof params.sessionId === "string" && params.sessionId.length > 0
|
|
2317
|
+
? params.sessionId
|
|
2318
|
+
: undefined;
|
|
2319
|
+
const summary = typeof params.summary === "string" ? params.summary : undefined;
|
|
2320
|
+
const toClientMessageId = typeof params.toClientMessageId === "string" ? params.toClientMessageId : undefined;
|
|
2321
|
+
if (!markerSessionId || !summary || !toClientMessageId) {
|
|
2322
|
+
this.transport.send(createErrorResponse(req.id, ErrorCodes.InvalidParams, "archive_marker requires sessionId, summary and toClientMessageId"));
|
|
2323
|
+
return;
|
|
2324
|
+
}
|
|
2325
|
+
const markerEngine = await this.resolveEngineForSessionQuery(req, markerSessionId, engine, "archive_marker");
|
|
2326
|
+
if (!markerEngine)
|
|
2327
|
+
return;
|
|
2328
|
+
try {
|
|
2329
|
+
const appended = await markerEngine.appendArchiveMarker(markerSessionId, {
|
|
2330
|
+
summary,
|
|
2331
|
+
toClientMessageId,
|
|
2332
|
+
...(typeof params.fromClientMessageId === "string"
|
|
2333
|
+
? { fromClientMessageId: params.fromClientMessageId }
|
|
2334
|
+
: {}),
|
|
2335
|
+
...(typeof params.segmentId === "string" ? { segmentId: params.segmentId } : {}),
|
|
2336
|
+
});
|
|
2337
|
+
this.transport.send(createResponse(req.id, { type: "archive_marker", data: { appended } }));
|
|
2338
|
+
}
|
|
2339
|
+
catch (err) {
|
|
2340
|
+
this.transport.send(createErrorResponse(req.id, ErrorCodes.InternalError, err.message));
|
|
2341
|
+
}
|
|
2342
|
+
break;
|
|
2343
|
+
}
|
|
2268
2344
|
case "models": {
|
|
2269
2345
|
if (!engine) {
|
|
2270
2346
|
this.transport.send(createErrorResponse(req.id, ErrorCodes.InternalError, "No engine available for models query"));
|
package/dist/protocol/types.d.ts
CHANGED
|
@@ -80,6 +80,8 @@ export interface RunParams {
|
|
|
80
80
|
attachments?: InputAttachmentMeta[];
|
|
81
81
|
/** Stable id for the user's submit intent; duplicate ids are idempotent. */
|
|
82
82
|
clientMessageId?: string;
|
|
83
|
+
/** Desktop host ownership generation for process-local Quick Chat runs. */
|
|
84
|
+
quickChatClaimId?: string;
|
|
83
85
|
/**
|
|
84
86
|
* Host-generated system reminder. Persisted with an injected marker so disk
|
|
85
87
|
* transcript readers hide it as a user bubble while retaining the assistant reply.
|
|
@@ -116,6 +118,16 @@ export interface RunParams {
|
|
|
116
118
|
planMode?: boolean;
|
|
117
119
|
/** Named behavior profile for a product-specific per-run interaction mode. */
|
|
118
120
|
behaviorMode?: RunBehaviorMode;
|
|
121
|
+
/** Host-authorized per-run hard tool allowlist. Empty means no tools. */
|
|
122
|
+
toolAllowlist?: string[];
|
|
123
|
+
/** Host-authorized per-run hard Skill allowlist. Empty means no Skills. */
|
|
124
|
+
skillAllowlist?: string[];
|
|
125
|
+
/** Keep a fresh run Session process-local and out of normal Session pickers. */
|
|
126
|
+
ephemeral?: boolean;
|
|
127
|
+
/** Optional fresh-session turn ceiling used by bounded host Tasks. */
|
|
128
|
+
maxTurns?: number;
|
|
129
|
+
/** Optional fresh-session context ceiling used by bounded host Tasks. */
|
|
130
|
+
maxContextTokens?: number;
|
|
119
131
|
/**
|
|
120
132
|
* Generic per-run parameters consumed by the active behavior profile
|
|
121
133
|
* (delivered as non-durable run context; never appended to the task or
|
|
@@ -342,6 +354,20 @@ export interface QueryParams {
|
|
|
342
354
|
start?: unknown;
|
|
343
355
|
/** Used by archive_range: half-open message-index window end (exclusive). */
|
|
344
356
|
end?: unknown;
|
|
357
|
+
/**
|
|
358
|
+
* Used by archive_range (optional) and archive_marker (required): the
|
|
359
|
+
* clientMessageId the archived/marked span ends at. archive_range only
|
|
360
|
+
* persists a boundary when this anchor is supplied and resolves to a live
|
|
361
|
+
* message; without it, archive_range behaves exactly as before (in-memory
|
|
362
|
+
* compaction only, no persisted range_archive event).
|
|
363
|
+
*/
|
|
364
|
+
toClientMessageId?: string;
|
|
365
|
+
/** Used by archive_range / archive_marker: optional start-of-span anchor. */
|
|
366
|
+
fromClientMessageId?: string;
|
|
367
|
+
/** Used by archive_range / archive_marker: optional idempotency key. */
|
|
368
|
+
segmentId?: string;
|
|
369
|
+
/** Used by archive_marker: the summary text to persist without a model call. */
|
|
370
|
+
summary?: string;
|
|
345
371
|
}
|
|
346
372
|
export interface QueryResult {
|
|
347
373
|
type: string;
|
package/dist/session/memory.d.ts
CHANGED
|
@@ -233,6 +233,16 @@ export declare class MemoryManager {
|
|
|
233
233
|
baseDir?: string;
|
|
234
234
|
maxAgeDays?: number;
|
|
235
235
|
now?: number;
|
|
236
|
+
/**
|
|
237
|
+
* Trim the global layer to what is relevant to this run's project:
|
|
238
|
+
* project-type and dream-scope records are per-project experience, so
|
|
239
|
+
* they are kept only when their origin metadata ties them to
|
|
240
|
+
* `projectDir`. General knowledge (user/feedback/reference in user
|
|
241
|
+
* scope) always stays; the project layer is untouched because it is
|
|
242
|
+
* already this project's own store. Set by behavior profiles whose runs
|
|
243
|
+
* never work inside other repos (e.g. a manager/dispatcher session).
|
|
244
|
+
*/
|
|
245
|
+
currentProjectOnly?: boolean;
|
|
236
246
|
}): string;
|
|
237
247
|
/**
|
|
238
248
|
* Load every entry belonging to the given scope, without changing the
|
package/dist/session/memory.js
CHANGED
|
@@ -651,7 +651,13 @@ export class MemoryManager {
|
|
|
651
651
|
const profile = opts.profileDir ? new MemoryManager({ baseDir: opts.profileDir }) : null;
|
|
652
652
|
const pinnedFirst = (a, b) => Number(b.pinned ?? false) - Number(a.pinned ?? false);
|
|
653
653
|
const collect = (mm) => filterByAge([...mm.loadScope("user"), ...mm.loadScope("dream")], opts.maxAgeDays, opts.now).sort(pinnedFirst);
|
|
654
|
-
|
|
654
|
+
let globalEntries = collect(global);
|
|
655
|
+
if (opts.currentProjectOnly) {
|
|
656
|
+
const tiedToProject = (e) => opts.projectDir !== undefined &&
|
|
657
|
+
(e.originProject === opts.projectDir ||
|
|
658
|
+
(e.originProjects?.includes(opts.projectDir) ?? false));
|
|
659
|
+
globalEntries = globalEntries.filter((e) => (e.type !== "project" && e.scope !== "dream") || tiedToProject(e));
|
|
660
|
+
}
|
|
655
661
|
const profileEntries = profile ? collect(profile) : [];
|
|
656
662
|
const projectEntries = project ? collect(project) : [];
|
|
657
663
|
if (globalEntries.length === 0 && profileEntries.length === 0 && projectEntries.length === 0) {
|
|
@@ -108,7 +108,7 @@ export declare class SessionManager {
|
|
|
108
108
|
* Create a session. `qchat-` sessions stay process-local; ordinary sessions
|
|
109
109
|
* materialize state.json + transcript.jsonl before return.
|
|
110
110
|
*/
|
|
111
|
-
create(cwd: string, model: string, provider: string, explicitSessionId?: string, parentSessionId?: string | null, origin?: import("../types.js").SessionOrigin, kind?: SessionKind): SessionBundle;
|
|
111
|
+
create(cwd: string, model: string, provider: string, explicitSessionId?: string, parentSessionId?: string | null, origin?: import("../types.js").SessionOrigin, kind?: SessionKind, ephemeral?: boolean): SessionBundle;
|
|
112
112
|
/** Whether a persisted or process-local session exists. */
|
|
113
113
|
exists(sessionId: string): boolean;
|
|
114
114
|
/**
|
|
@@ -236,6 +236,8 @@ export declare class SessionManager {
|
|
|
236
236
|
* workspace/profile metadata.
|
|
237
237
|
*/
|
|
238
238
|
readSessionState(sessionId: string): SessionState | undefined;
|
|
239
|
+
/** Whether a live or persisted Session is explicitly process-local. */
|
|
240
|
+
isEphemeralSession(sessionId: string): boolean;
|
|
239
241
|
/**
|
|
240
242
|
* Merge a field-level state update into the latest persisted snapshot.
|
|
241
243
|
*
|