qlogicagent 2.14.1 → 2.14.3
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/agent.js +9 -9
- package/dist/cli.js +311 -317
- package/dist/index.js +310 -316
- package/dist/types/agent/tool-loop/completion-action-policy.d.ts +1 -1
- package/dist/types/agent/tool-loop/loop-helpers.d.ts +1 -0
- package/dist/types/agent/tool-loop/tool-budget-continuation-policy.d.ts +45 -0
- package/dist/types/cli/acp-session-host.d.ts +0 -1
- package/dist/types/cli/handlers/session-handler.d.ts +0 -2
- package/dist/types/cli/session-context.d.ts +0 -3
- package/dist/types/cli/stdio-acp-request-host.d.ts +2 -2
- package/dist/types/cli/stdio-rpc-handler-hosts.d.ts +0 -1
- package/dist/types/cli/stdio-server.d.ts +0 -3
- package/dist/types/cli/turn-lifecycle.d.ts +0 -1
- package/dist/types/protocol/wire/chat-types.d.ts +2 -0
- package/dist/types/runtime/prompt/fresh-workspace-evidence.d.ts +1 -0
- package/dist/types/runtime/prompt/index.d.ts +1 -1
- package/dist/types/runtime/prompt/task-domain.d.ts +16 -55
- package/dist/types/runtime/session/session-title.d.ts +9 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentLogger, ChatMessage, ThinkingBlock, ToolLoopTransition } from "../types.js";
|
|
2
|
-
export type CompletionActionPolicyReason = "file_action_verification" | "explicit_required_file_verification" | "explicit_extra_file_verification" | "final_marker_verification" | "multi_file_skeleton_verification";
|
|
2
|
+
export type CompletionActionPolicyReason = "file_action_verification" | "explicit_required_file_verification" | "explicit_extra_file_verification" | "artifact_index_evidence_verification" | "final_marker_verification" | "multi_file_skeleton_verification";
|
|
3
3
|
export interface CompletionActionPolicyInput {
|
|
4
4
|
inputMessages: readonly ChatMessage[];
|
|
5
5
|
messages: unknown[];
|
|
@@ -4,6 +4,7 @@ export declare function isEmptyToolResult(r: {
|
|
|
4
4
|
message: unknown;
|
|
5
5
|
}): boolean;
|
|
6
6
|
export declare function findLastToolError(messages: unknown[], _toolName: string): string | undefined;
|
|
7
|
+
export declare function looksLikeBuildRequest(messages?: readonly ChatMessage[]): boolean;
|
|
7
8
|
export declare function resolveToolLoopBudget(requested?: number, messages?: readonly ChatMessage[]): number;
|
|
8
9
|
export declare function countExplicitOutputArtifacts(messages?: readonly ChatMessage[]): number;
|
|
9
10
|
export declare function resolveTotalToolCallBudget(requested?: number, messages?: readonly ChatMessage[]): number;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工具/轮数预算的「进度门控续跑」策略(A)。
|
|
3
|
+
*
|
|
4
|
+
* 默认工具预算(DEFAULT_TOOL_BUDGET)和轮数预算(DEFAULT_MAX_ROUNDS)对「建一个完整 app/游戏」这类
|
|
5
|
+
* 任务偏低,撞上就被迫收尾、任务半成品。本策略把预算从「写死的硬停」改成「软检查点 + 可续跑」:
|
|
6
|
+
* 预算耗尽时,若本轮窗口**确有进度**(产出了新的成功工具结果)且**没卡在循环里**(AP5 同款:同一文件
|
|
7
|
+
* 反复读),就再续一个窗口;否则停。续跑次数和绝对硬顶(MAX_*_CAP)双重封顶,杜绝失控。
|
|
8
|
+
*
|
|
9
|
+
* 与既有 token 预算续跑(budget-continuation-policy.ts)同构,只是进度信号换成「成功工具调用增量」、
|
|
10
|
+
* 失控信号换成「读循环」。纯函数,便于单测。
|
|
11
|
+
*/
|
|
12
|
+
/** 一轮 turn 内最多续跑次数 —— 与 token 续跑的 MAX_BUDGET_CONTINUATIONS 对齐。 */
|
|
13
|
+
export declare const MAX_TOOL_BUDGET_CONTINUATIONS = 5;
|
|
14
|
+
export interface ToolBudgetContinuationInput {
|
|
15
|
+
/** 当前工具调用预算(可能已被前几次续跑抬高过)。 */
|
|
16
|
+
currentToolBudget: number;
|
|
17
|
+
/** 当前轮数预算。 */
|
|
18
|
+
currentRoundBudget: number;
|
|
19
|
+
/** 工具调用绝对硬顶(失控兜底)。 */
|
|
20
|
+
toolHardCap: number;
|
|
21
|
+
/** 轮数绝对硬顶。 */
|
|
22
|
+
roundHardCap: number;
|
|
23
|
+
/** 已续跑次数。 */
|
|
24
|
+
continuationCount: number;
|
|
25
|
+
/** 上个检查点以来新增的「成功且非空」工具结果数 —— 进度信号。 */
|
|
26
|
+
successfulSinceLastCheck: number;
|
|
27
|
+
/** 文件读取计数(AP5 读循环检测,失控信号)。 */
|
|
28
|
+
fileReadCounts: ReadonlyMap<string, number>;
|
|
29
|
+
/** 每次续跑给工具预算加的窗口(= DEFAULT_TOOL_BUDGET)。 */
|
|
30
|
+
windowTools: number;
|
|
31
|
+
/** 每次续跑给轮数预算加的窗口(= DEFAULT_MAX_ROUNDS)。 */
|
|
32
|
+
windowRounds: number;
|
|
33
|
+
}
|
|
34
|
+
export interface ToolBudgetContinuationDecision {
|
|
35
|
+
nextToolBudget: number;
|
|
36
|
+
nextRoundBudget: number;
|
|
37
|
+
continuationCount: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 决定是否续跑。返回 null = 不续(应停下并诚实收尾);返回 decision = 续跑(把预算抬到 next*)。
|
|
41
|
+
*
|
|
42
|
+
* 停的条件(任一):①续跑次数用满;②两个预算都已到硬顶;③本窗口零进度(没新增成功结果);
|
|
43
|
+
* ④卡在读循环。其余情况续跑,但每个预算都不超过各自硬顶。
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveToolBudgetContinuation(input: ToolBudgetContinuationInput): ToolBudgetContinuationDecision | null;
|
|
@@ -28,7 +28,6 @@ export interface AcpSessionHost {
|
|
|
28
28
|
memoryPrefetchState: ReturnType<typeof createMemoryPrefetchState>;
|
|
29
29
|
sessionHistory: Pick<SessionHistoryCoordinator, "saveResumedSession" | "withResumedHistory">;
|
|
30
30
|
sessionState: SessionState | null;
|
|
31
|
-
sessionTaskDomain: unknown;
|
|
32
31
|
cancelIdleDreamTimer(): void;
|
|
33
32
|
disposeSessionRuntime?(): void;
|
|
34
33
|
enableIdleDream(): void;
|
|
@@ -14,12 +14,10 @@ import { SessionState } from "../../runtime/session/session-state.js";
|
|
|
14
14
|
import { createMemoryPrefetchState } from "../../runtime/hooks/memory-hooks.js";
|
|
15
15
|
import { type AgentRpcError, type AgentRpcErrorCode, type AgentRpcRequest } from "../../protocol/wire/index.js";
|
|
16
16
|
import type { SessionHistoryCoordinator } from "../session-history-coordinator.js";
|
|
17
|
-
import type { TaskDomain } from "../../runtime/prompt/task-domain.js";
|
|
18
17
|
export interface SessionHandlerHost {
|
|
19
18
|
currentSessionId?: string;
|
|
20
19
|
currentModel?: string;
|
|
21
20
|
sessionState?: SessionState | null;
|
|
22
|
-
sessionTaskDomain?: TaskDomain;
|
|
23
21
|
memoryPrefetchState?: ReturnType<typeof createMemoryPrefetchState>;
|
|
24
22
|
sessionHistory: Pick<SessionHistoryCoordinator, "saveResumedSession">;
|
|
25
23
|
log(message: string): void;
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { SessionState } from "../runtime/session/session-state.js";
|
|
16
16
|
import type { SessionLlmConfig } from "./acp-session-host.js";
|
|
17
|
-
import type { TaskDomain } from "../runtime/prompt/task-domain.js";
|
|
18
17
|
export declare class SessionContext {
|
|
19
18
|
/** Active session id (chatId for desktop; group key pattern for groups). */
|
|
20
19
|
sessionId: string;
|
|
@@ -22,8 +21,6 @@ export declare class SessionContext {
|
|
|
22
21
|
turnId: string;
|
|
23
22
|
/** Session cost/state snapshot (null until a session is resolved). */
|
|
24
23
|
state: SessionState | null;
|
|
25
|
-
/** Session-level task domain stickiness — survives across turns within a session. */
|
|
26
|
-
taskDomain: TaskDomain | undefined;
|
|
27
24
|
/** Host-pinned per-session LLM config (session/set_config_option · set_model · /model).
|
|
28
25
|
* NEVER wiped by ModelRegistry churn — distinct from the DERIVED ResolvedAgentCache. */
|
|
29
26
|
llmConfig: SessionLlmConfig;
|
|
@@ -6,7 +6,7 @@ import type { CliAcpRequestHandlerHost } from "./cli-acp-request-handler.js";
|
|
|
6
6
|
* (`this: any`), so members it touches must be forwarded here explicitly;
|
|
7
7
|
* see TURN_PIPELINE_HOST_MEMBERS for the regression-tested list.
|
|
8
8
|
*/
|
|
9
|
-
export type StdioAcpRequestHostSource = Pick<CliAcpRequestHandlerHost, "activeTurn" | "acpSessionMeta" | "currentHooks" | "currentSessionId" | "currentTurnId" | "memoryPrefetchState" | "permissionChecker" | "sessionHistory" | "sessionLlmConfig" | "sessionState" | "
|
|
9
|
+
export type StdioAcpRequestHostSource = Pick<CliAcpRequestHandlerHost, "activeTurn" | "acpSessionMeta" | "currentHooks" | "currentSessionId" | "currentTurnId" | "memoryPrefetchState" | "permissionChecker" | "sessionHistory" | "sessionLlmConfig" | "sessionState" | "cancelIdleDreamTimer" | "disposeSessionRuntime" | "enableIdleDream" | "ensureDefaultProject" | "ensureModelRegistryHydrated" | "getActiveProjectRoot" | "log" | "sendNotification" | "setActiveWorkdir"> & {
|
|
10
10
|
currentModel: string | undefined;
|
|
11
11
|
lastAssistantMessageForExtract: string | undefined;
|
|
12
12
|
lastUserMessageForAutoExtract: string | undefined;
|
|
@@ -24,5 +24,5 @@ export type StdioAcpRequestHostSource = Pick<CliAcpRequestHandlerHost, "activeTu
|
|
|
24
24
|
};
|
|
25
25
|
/** Host members the shared turn pipeline reads/writes — keep in sync with
|
|
26
26
|
* `grep -oE "this\.[a-zA-Z]+" src/cli/handlers/turn-handler.ts | sort -u`. */
|
|
27
|
-
export declare const TURN_PIPELINE_HOST_MEMBERS: readonly ["activeTurn", "configureTurnMedia", "currentHooks", "currentModel", "currentTurnId", "drainPendingTaskNotifications", "getActiveProjectRoot", "lastAssistantMessageForExtract", "lastUserMessageForAutoExtract", "log", "mcpReady", "memdir", "pendingAskUser", "permissionChecker", "petRuntime", "projectMemoryStoreFactory", "resolveAgent", "resolveClientForPurpose", "sendNotification", "sendResponse", "sessionHistory", "sessionState", "
|
|
27
|
+
export declare const TURN_PIPELINE_HOST_MEMBERS: readonly ["activeTurn", "configureTurnMedia", "currentHooks", "currentModel", "currentTurnId", "drainPendingTaskNotifications", "getActiveProjectRoot", "lastAssistantMessageForExtract", "lastUserMessageForAutoExtract", "log", "mcpReady", "memdir", "pendingAskUser", "permissionChecker", "petRuntime", "projectMemoryStoreFactory", "resolveAgent", "resolveClientForPurpose", "sendNotification", "sendResponse", "sessionHistory", "sessionState", "setActiveWorkdir", "toolCatalog"];
|
|
28
28
|
export declare function createStdioAcpRequestHandlerHost(host: StdioAcpRequestHostSource): CliAcpRequestHandlerHost;
|
|
@@ -10,7 +10,6 @@ type StdioRpcAdapterSource = DirectStdioRpcHost & {
|
|
|
10
10
|
currentSessionId: NonNullable<RpcHandlerHosts["session"]["currentSessionId"]>;
|
|
11
11
|
currentModel: NonNullable<RpcHandlerHosts["session"]["currentModel"]>;
|
|
12
12
|
sessionState: RpcHandlerHosts["session"]["sessionState"];
|
|
13
|
-
sessionTaskDomain: RpcHandlerHosts["session"]["sessionTaskDomain"];
|
|
14
13
|
memoryPrefetchState: NonNullable<RpcHandlerHosts["session"]["memoryPrefetchState"]>;
|
|
15
14
|
sessionHistory: RpcHandlerHosts["session"]["sessionHistory"];
|
|
16
15
|
currentHooks: RpcHandlerHosts["dream"]["currentHooks"];
|
|
@@ -16,7 +16,6 @@ import { type MemoryPrefetchState } from "../runtime/hooks/memory-hooks.js";
|
|
|
16
16
|
import { SessionState } from "../runtime/session/session-state.js";
|
|
17
17
|
import { TaskStore } from "../runtime/infra/task-runtime.js";
|
|
18
18
|
import { BackgroundTaskManager } from "../runtime/infra/background-tasks.js";
|
|
19
|
-
import { type TaskDomain } from "../runtime/prompt/task-domain.js";
|
|
20
19
|
import { type AgentRpcError } from "../protocol/wire/index.js";
|
|
21
20
|
import type { AcpServer } from "../transport/acp-server.js";
|
|
22
21
|
import type { NotificationMethod, NotificationMethodMap } from "../protocol/notifications.js";
|
|
@@ -109,8 +108,6 @@ export declare class StdioServer {
|
|
|
109
108
|
set currentTurnId(v: string);
|
|
110
109
|
get sessionState(): SessionState | null;
|
|
111
110
|
set sessionState(v: SessionState | null);
|
|
112
|
-
get sessionTaskDomain(): TaskDomain | undefined;
|
|
113
|
-
set sessionTaskDomain(v: TaskDomain | undefined);
|
|
114
111
|
get sessionLlmConfig(): SessionLlmConfig;
|
|
115
112
|
set sessionLlmConfig(v: SessionLlmConfig);
|
|
116
113
|
get acpSessionMeta(): Record<string, unknown> | null;
|
|
@@ -61,6 +61,8 @@ export interface ChatMessage {
|
|
|
61
61
|
mimeType?: string;
|
|
62
62
|
size?: number;
|
|
63
63
|
}>;
|
|
64
|
+
/** UI-facing structured blocks persisted with transcripts; ignored by model transports. */
|
|
65
|
+
blocks?: Array<Record<string, unknown>>;
|
|
64
66
|
}
|
|
65
67
|
export type ToolCapabilityCategory = "orchestration" | "filesystem" | "web" | "search" | "memory" | "media" | "developer" | "mcp" | "automation" | "system" | "other";
|
|
66
68
|
export interface LocalizedToolText {
|
|
@@ -13,6 +13,7 @@ export interface FreshWorkspaceEvidencePolicy {
|
|
|
13
13
|
requiresFreshTool: boolean;
|
|
14
14
|
reason?: "file-read" | "file-mutation" | "memory-mutation" | "media-generation" | "directory-list" | "content-search" | "shell" | "web";
|
|
15
15
|
mediaKind?: "image" | "tts" | "music";
|
|
16
|
+
workflowKind?: "artifact-index";
|
|
16
17
|
allowedToolNames: string[];
|
|
17
18
|
}
|
|
18
19
|
export declare function getFreshWorkspaceEvidencePolicy(messages: readonly PromptMessageLike[] | string): FreshWorkspaceEvidencePolicy;
|
|
@@ -2,4 +2,4 @@ export { assembleSystemPrompt, clearSystemPromptSections, systemPromptSection, t
|
|
|
2
2
|
export { PROMPT_POLICY_REGISTRY, PROMPT_POLICY_VERSION, createPromptPolicyHeader, type PromptPolicyRegistry, type PromptPolicyRegistryEntry, } from "./prompt-policy.js";
|
|
3
3
|
export { getInstructions, buildInstructionsPrompt, resetInstructionCache, } from "./instruction-loader.js";
|
|
4
4
|
export { createEnvironmentContextSection, createTaskGuidanceSection, createToolGuidanceSection, createLanguageSection } from "./environment-context.js";
|
|
5
|
-
export { detectTaskDomain, resolveTaskDomain,
|
|
5
|
+
export { detectTaskDomain, resolveTaskDomain, type TaskDomain, type DomainResolutionContext } from "./task-domain.js";
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Task Domain Detection —
|
|
2
|
+
* Task Domain Detection — selects which system prompt guidance is injected.
|
|
3
3
|
*
|
|
4
|
-
* qlogicagent handles coding, office, AND creative tasks
|
|
5
|
-
*
|
|
4
|
+
* qlogicagent handles coding, office, AND creative tasks; a coding-only prompt
|
|
5
|
+
* hurts non-coding performance, so the per-domain CONTENT blocks are kept.
|
|
6
6
|
*
|
|
7
|
-
* Resolution
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* 2.
|
|
11
|
-
* Set by Electron/Hub per-request.
|
|
12
|
-
* 3. Session sticky: once a domain is established in a session,
|
|
13
|
-
* keep it unless a new turn has a STRONG signal for a different domain.
|
|
14
|
-
* 4. Auto-detect: regex keyword matching on the current user message.
|
|
15
|
-
* Falls back to "general" if ambiguous.
|
|
7
|
+
* Resolution is STATELESS and recomputed every turn (CC-aligned — no hidden
|
|
8
|
+
* session/disk state, no stickiness latch, no auto-persisted guesses):
|
|
9
|
+
* 1. Host override: `config.taskDomain` from thread.turn params (explicit).
|
|
10
|
+
* 2. Auto-detect: keyword match on the current user message; "general" if ambiguous.
|
|
16
11
|
*
|
|
17
|
-
* The
|
|
18
|
-
*
|
|
12
|
+
* The universal BEHAVIORAL rules (answer-directly, tools-not-default, conciseness)
|
|
13
|
+
* live in universalGuidance() and apply in every domain, so misclassifying a turn
|
|
14
|
+
* as "general" degrades only the domain-tailored content, never the core behavior.
|
|
19
15
|
*/
|
|
20
16
|
/**
|
|
21
17
|
* Task domain determines which system prompt sections are injected.
|
|
@@ -27,56 +23,21 @@
|
|
|
27
23
|
*/
|
|
28
24
|
export type TaskDomain = "coding" | "office" | "creative" | "general";
|
|
29
25
|
/**
|
|
30
|
-
*
|
|
31
|
-
* Returns undefined if file doesn't exist or doesn't contain a valid domain.
|
|
32
|
-
*
|
|
33
|
-
* Uses sync I/O — called once per turn, file is tiny (<1KB).
|
|
34
|
-
* Simple key:value parser (no YAML dependency needed for this).
|
|
35
|
-
*/
|
|
36
|
-
export declare function loadProjectTaskDomain(cwd: string): TaskDomain | undefined;
|
|
37
|
-
/**
|
|
38
|
-
* Detect task domain from user message text (tier 4 — lowest priority).
|
|
39
|
-
* Uses keyword matching — fast, no LLM call.
|
|
26
|
+
* Detect task domain from user message text. Keyword matching — fast, no LLM call.
|
|
40
27
|
*/
|
|
41
28
|
export declare function detectTaskDomain(userText: string): TaskDomain;
|
|
42
29
|
export interface DomainResolutionContext {
|
|
43
|
-
/**
|
|
44
|
-
cwd: string;
|
|
45
|
-
/** Host-provided override from config.taskDomain. */
|
|
30
|
+
/** Host-provided override from config.taskDomain (explicit, per-request). */
|
|
46
31
|
hostOverride?: TaskDomain;
|
|
47
|
-
/** Previous session domain (for stickiness). */
|
|
48
|
-
sessionDomain?: TaskDomain;
|
|
49
32
|
/** Current turn's user message text. */
|
|
50
33
|
userText: string;
|
|
51
34
|
}
|
|
52
35
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* 3. Session stickiness (keep previous domain unless strong signal)
|
|
57
|
-
* 4. Auto-detect from keywords
|
|
58
|
-
*
|
|
59
|
-
* Returns both the resolved domain and a "source" tag for debugging.
|
|
36
|
+
* Resolve task domain, stateless and per-turn: explicit host override, else fresh
|
|
37
|
+
* keyword auto-detect on this turn's message. No project file, no session stickiness,
|
|
38
|
+
* no disk persistence.
|
|
60
39
|
*/
|
|
61
40
|
export declare function resolveTaskDomain(ctx: DomainResolutionContext): {
|
|
62
41
|
domain: TaskDomain;
|
|
63
|
-
source: "
|
|
42
|
+
source: "host-override" | "auto-detect";
|
|
64
43
|
};
|
|
65
|
-
/**
|
|
66
|
-
* Persist the detected task domain to `.qlogicagent/settings.yaml`.
|
|
67
|
-
*
|
|
68
|
-
* This runs once per workspace — subsequent sessions skip auto-detect
|
|
69
|
-
* and hit Tier 1 (project file) directly.
|
|
70
|
-
*
|
|
71
|
-
* Conditions for writing:
|
|
72
|
-
* - `domain` is NOT "general" (ambiguous → don't commit)
|
|
73
|
-
* - No existing `settings.yaml` with a `taskDomain` line
|
|
74
|
-
* - The auto-detect score was above the confidence threshold
|
|
75
|
-
*
|
|
76
|
-
* The written file is user-editable and meant to be checked into the repo.
|
|
77
|
-
*/
|
|
78
|
-
export declare function persistTaskDomain(cwd: string, domain: TaskDomain): boolean;
|
|
79
|
-
/**
|
|
80
|
-
* Check if auto-detect scored high enough to justify persisting.
|
|
81
|
-
*/
|
|
82
|
-
export declare function shouldPersistDomain(userText: string, domain: TaskDomain): boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function hasLikelyMojibake(text: string): boolean;
|
|
2
|
+
export declare function cleanSessionTitleCandidate(title: string | undefined | null, options?: {
|
|
3
|
+
maxLength?: number;
|
|
4
|
+
}): string | undefined;
|
|
5
|
+
export declare function titleFromPromptFallback(prompt: string, fallback: string, options?: {
|
|
6
|
+
maxLength?: number;
|
|
7
|
+
ellipsis?: string;
|
|
8
|
+
}): string;
|
|
9
|
+
export declare function deterministicSessionTitleForPrompt(prompt: string): string | null;
|