qlogicagent 1.3.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -8
- package/dist/agent.js +14 -14
- package/dist/cli.js +261 -224
- package/dist/index.js +260 -224
- package/dist/qlogicagent.cmd +2 -0
- package/dist/types/cli/main.d.ts +5 -1
- package/dist/types/cli/stdio-server.d.ts +62 -6
- package/dist/types/contracts/hooks.d.ts +3 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/llm/index.d.ts +1 -1
- package/dist/types/llm/transports/media-resolve.d.ts +25 -0
- package/dist/types/runtime/execution/dream-agent.d.ts +2 -0
- package/dist/types/runtime/execution/dream-category-context.d.ts +47 -0
- package/dist/types/runtime/execution/dream-category-context.test.d.ts +1 -0
- package/dist/types/runtime/execution/index.d.ts +1 -0
- package/dist/types/runtime/execution/memory-decay.d.ts +57 -0
- package/dist/types/runtime/execution/memory-decay.test.d.ts +1 -0
- package/dist/types/runtime/hooks/index.d.ts +1 -0
- package/dist/types/runtime/hooks/memory-hooks.d.ts +20 -0
- package/dist/types/runtime/hooks/skill-recall-hooks.d.ts +36 -0
- package/dist/types/runtime/infra/acp-protocol-adapter.d.ts +72 -18
- package/dist/types/runtime/infra/acp-types.d.ts +30 -17
- package/dist/types/runtime/infra/agent-paths.d.ts +15 -3
- package/dist/types/runtime/infra/disk-storage.d.ts +0 -16
- package/dist/types/runtime/infra/index.d.ts +4 -4
- package/dist/types/runtime/session/session-persistence.d.ts +3 -1
- package/dist/types/skills/index.d.ts +5 -5
- package/dist/types/skills/memory/find-relevant-memories.d.ts +70 -0
- package/dist/types/skills/memory/memdir.d.ts +80 -0
- package/dist/types/skills/memory/memory-tool.d.ts +16 -44
- package/dist/types/skills/memory/memory-write-gate.d.ts +46 -0
- package/dist/types/skills/memory/memory-write-hook.d.ts +44 -0
- package/dist/types/skills/memory/qmemory-adapter.d.ts +12 -0
- package/dist/types/skills/memory/recall-category-filter.d.ts +54 -0
- package/dist/types/skills/tools/skill-tool.d.ts +16 -3
- package/dist/types/transport/acp-event-emitter.d.ts +21 -0
- package/dist/types/transport/acp-server.d.ts +130 -0
- package/dist/types/transport/index.d.ts +6 -0
- package/package.json +1 -1
- package/dist/types/skills/memory/memory-store.d.ts +0 -86
- package/dist/types/skills/tools/skill-invoke-tool.d.ts +0 -46
- package/dist/types/skills/tools/skill-list-tool.d.ts +0 -33
- package/dist/types/skills/tools/skill-manage-tool.d.ts +0 -73
- package/dist/types/skills/tools/skill-view-tool.d.ts +0 -37
package/dist/types/cli/main.d.ts
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* All log/debug output goes to stderr (never pollutes the protocol).
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* qlogicagent [--verbose]
|
|
9
|
+
* qlogicagent [--verbose] [--acp]
|
|
10
|
+
*
|
|
11
|
+
* Flags:
|
|
12
|
+
* --verbose Enable debug logging to stderr
|
|
13
|
+
* --acp Enable ACP (Agent-Client Protocol) server alongside legacy protocol
|
|
10
14
|
*/
|
|
11
15
|
export {};
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* The physical I/O layer is abstracted via the Transport interface.
|
|
10
10
|
*/
|
|
11
11
|
import type { Transport } from "./transport.js";
|
|
12
|
+
import { AcpServer } from "../transport/acp-server.js";
|
|
12
13
|
export interface StdioServerConfig {
|
|
13
14
|
verbose: boolean;
|
|
14
15
|
transport?: Transport;
|
|
@@ -35,6 +36,8 @@ export declare class StdioServer {
|
|
|
35
36
|
private currentTransport;
|
|
36
37
|
private currentApiKey;
|
|
37
38
|
private currentModel;
|
|
39
|
+
private currentProvider;
|
|
40
|
+
private currentBaseUrl;
|
|
38
41
|
private sessionState;
|
|
39
42
|
private currentMediaApiKeys;
|
|
40
43
|
private taskStore;
|
|
@@ -43,6 +46,10 @@ export declare class StdioServer {
|
|
|
43
46
|
/** QMemory adapter (when QMEMORY_BASE_URL env is set). Used by Dream hippocampus bridge. */
|
|
44
47
|
private qmemoryAdapter;
|
|
45
48
|
private qmemoryUserId;
|
|
49
|
+
/** MEMDIR file-based memory (CC memdir parity). */
|
|
50
|
+
private memdir;
|
|
51
|
+
/** Memory write gate state (P2+P3: category gate + supersedes). */
|
|
52
|
+
private memoryWriteState;
|
|
46
53
|
private fileWatcher;
|
|
47
54
|
/** Pending ask_user requests waiting for host response */
|
|
48
55
|
private pendingAskUser;
|
|
@@ -59,6 +66,20 @@ export declare class StdioServer {
|
|
|
59
66
|
/** Process managers for solo/product (stored for agents.processes/kill). */
|
|
60
67
|
private soloProcessManager;
|
|
61
68
|
private productProcessManager;
|
|
69
|
+
/** ACP Server instance — handles ACP protocol alongside legacy protocol. */
|
|
70
|
+
private acpServer;
|
|
71
|
+
/** Idle dream timer — fires after configurable idle period to trigger memory consolidation. */
|
|
72
|
+
private idleDreamTimer;
|
|
73
|
+
/** Idle dream config (minutes). Default: 30 min idle = trigger dream. */
|
|
74
|
+
private idleDreamMinutes;
|
|
75
|
+
/** Whether idle dream is enabled. Requires LLM config + memory root to be set. */
|
|
76
|
+
private idleDreamEnabled;
|
|
77
|
+
/** Last dream timestamp to enforce cooldown. */
|
|
78
|
+
private lastDreamAt;
|
|
79
|
+
/** Dream cooldown (ms). Default: 4 hours. */
|
|
80
|
+
private dreamCooldownMs;
|
|
81
|
+
/** Max dream duration (ms). Default: 5 minutes. */
|
|
82
|
+
private dreamMaxDurationMs;
|
|
62
83
|
constructor(config: StdioServerConfig);
|
|
63
84
|
start(): void;
|
|
64
85
|
stop(): void;
|
|
@@ -104,15 +125,15 @@ export declare class StdioServer {
|
|
|
104
125
|
*/
|
|
105
126
|
private handleSessionGetInfo;
|
|
106
127
|
/**
|
|
107
|
-
* `memory.list` — Enumerate available memory sources (
|
|
128
|
+
* `memory.list` — Enumerate available memory sources (memdir + qmemory).
|
|
108
129
|
*/
|
|
109
130
|
private handleMemoryList;
|
|
110
131
|
/**
|
|
111
|
-
* `memory.read` — Read memory content from
|
|
132
|
+
* `memory.read` — Read memory content from memdir (INDEX.md or topic file).
|
|
112
133
|
*/
|
|
113
134
|
private handleMemoryRead;
|
|
114
135
|
/**
|
|
115
|
-
* `memory.write` — Write memory content to
|
|
136
|
+
* `memory.write` — Write memory content to memdir (INDEX.md or topic file).
|
|
116
137
|
*/
|
|
117
138
|
private handleMemoryWrite;
|
|
118
139
|
/**
|
|
@@ -157,12 +178,11 @@ export declare class StdioServer {
|
|
|
157
178
|
*/
|
|
158
179
|
private handleTodosList;
|
|
159
180
|
/**
|
|
160
|
-
* `memory.search` —
|
|
161
|
-
* Powers the memory page's search feature.
|
|
181
|
+
* `memory.search` — Search memory via QMemory (vector) or memdir (local keyword).
|
|
162
182
|
*/
|
|
163
183
|
private handleMemorySearch;
|
|
164
184
|
/**
|
|
165
|
-
* `memory.delete` — Remove
|
|
185
|
+
* `memory.delete` — Remove memory entry from memdir (INDEX.md line) or QMemory (by ID).
|
|
166
186
|
*/
|
|
167
187
|
private handleMemoryDelete;
|
|
168
188
|
/**
|
|
@@ -243,4 +263,40 @@ export declare class StdioServer {
|
|
|
243
263
|
private sendNotification;
|
|
244
264
|
private writeStdout;
|
|
245
265
|
private log;
|
|
266
|
+
/**
|
|
267
|
+
* Enable idle dream scheduling. Called after session setup when LLM config is available.
|
|
268
|
+
*/
|
|
269
|
+
enableIdleDream(minutes?: number): void;
|
|
270
|
+
private resetIdleDreamTimer;
|
|
271
|
+
private cancelIdleDreamTimer;
|
|
272
|
+
private triggerIdleDream;
|
|
273
|
+
/**
|
|
274
|
+
* Initialize the ACP server alongside the legacy protocol.
|
|
275
|
+
* Called once when the host is an ACP-compliant client.
|
|
276
|
+
*/
|
|
277
|
+
initAcpServer(): void;
|
|
278
|
+
/** Get the ACP server instance (for external wiring, e.g., main.ts). */
|
|
279
|
+
getAcpServer(): AcpServer | null;
|
|
280
|
+
private acpHandleInitialize;
|
|
281
|
+
private acpHandleSessionNew;
|
|
282
|
+
private acpHandleSessionPrompt;
|
|
283
|
+
/**
|
|
284
|
+
* Run a turn in ACP mode — streams events via session/update, returns final result.
|
|
285
|
+
* This duplicates the core logic of handleTurn but returns a promise with the final content.
|
|
286
|
+
*/
|
|
287
|
+
private runAcpTurn;
|
|
288
|
+
private acpHandleSessionEnd;
|
|
289
|
+
private acpHandleSessionSetConfig;
|
|
290
|
+
private acpHandleSessionSetModel;
|
|
291
|
+
private acpHandleSessionSetMode;
|
|
292
|
+
private acpHandlePermissionResponse;
|
|
293
|
+
private acpHandleAbort;
|
|
294
|
+
private acpHandleDream;
|
|
295
|
+
private acpHandleSoloStart;
|
|
296
|
+
private acpHandleSoloStatus;
|
|
297
|
+
private acpHandleSoloSelect;
|
|
298
|
+
private acpHandleProductCreate;
|
|
299
|
+
private acpHandleProductResume;
|
|
300
|
+
private acpHandleProductStatus;
|
|
301
|
+
private acpHandleTeamDelegate;
|
|
246
302
|
}
|
|
@@ -114,7 +114,10 @@ export interface HookContextMap {
|
|
|
114
114
|
recalledMemories?: Array<{
|
|
115
115
|
text: string;
|
|
116
116
|
score?: number;
|
|
117
|
+
category?: string | null;
|
|
117
118
|
}>;
|
|
119
|
+
preferredCategories?: string[];
|
|
120
|
+
deprioritizedCategories?: string[];
|
|
118
121
|
};
|
|
119
122
|
"memory.after_recall": HookTurnContext & {
|
|
120
123
|
blockCount?: number;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type { AgentConfig } from "./config/config.js";
|
|
|
10
10
|
export type { Transport } from "./cli/transport.js";
|
|
11
11
|
export { StdioTransport } from "./cli/transport.js";
|
|
12
12
|
export { StdioServer, type StdioServerConfig } from "./cli/stdio-server.js";
|
|
13
|
-
export { ProviderRegistry, createLLMClient,
|
|
13
|
+
export { ProviderRegistry, createLLMClient, } from "./llm/index.js";
|
|
14
14
|
export type { LLMTransport, LLMRequest, LLMChunk } from "./llm/index.js";
|
|
15
15
|
export { createHookRegistry } from "./runtime/hooks/hook-registry.js";
|
|
16
16
|
export { buildSkillInstruction, } from "./orchestration/index.js";
|
|
@@ -12,7 +12,7 @@ export { ProviderRegistry } from "./provider-registry.js";
|
|
|
12
12
|
export { BUILTIN_PROVIDERS } from "./builtin-providers.js";
|
|
13
13
|
export { ModelCatalog } from "./model-catalog.js";
|
|
14
14
|
export type { LLMClientConfig, LLMClient } from "./llm-client.js";
|
|
15
|
-
export { createLLMClient
|
|
15
|
+
export { createLLMClient } from "./llm-client.js";
|
|
16
16
|
export { OpenAIChatTransport } from "./transports/openai-chat.js";
|
|
17
17
|
export { AnthropicMessagesTransport } from "./transports/anthropic-messages.js";
|
|
18
18
|
export { GeminiGenerateContentTransport } from "./transports/gemini-generatecontent.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media URL Resolution — converts local/private URLs to inline base64 data URLs.
|
|
3
|
+
*
|
|
4
|
+
* Cloud LLM APIs (OpenAI, Anthropic, DeepSeek) cannot fetch content from
|
|
5
|
+
* localhost or private networks. This utility detects such URLs and resolves
|
|
6
|
+
* them to base64 data URLs that can be sent inline.
|
|
7
|
+
*
|
|
8
|
+
* URL-first design: the gateway stores media as HTTP URLs; this layer handles
|
|
9
|
+
* the last-mile transformation before sending to provider APIs.
|
|
10
|
+
*/
|
|
11
|
+
/** Check if a URL points to a local/private address that cloud APIs cannot reach. */
|
|
12
|
+
export declare function isLocalUrl(url: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a URL to a base64 data URL if it's a local address.
|
|
15
|
+
* Public URLs are returned as-is (the LLM API can fetch them directly).
|
|
16
|
+
*
|
|
17
|
+
* Returns the original URL for non-local addresses.
|
|
18
|
+
* Returns a `data:<mime>;base64,...` string for local addresses.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveMediaUrl(url: string, fallbackMime?: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Batch-resolve multiple URLs. Returns array in same order.
|
|
23
|
+
* Failures are logged and the original URL is kept (best-effort).
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveMediaUrls(urls: string[], fallbackMime?: string): Promise<string[]>;
|
|
@@ -72,9 +72,11 @@ export declare function canUseDreamTool(memoryRoot: string, restriction: DreamTo
|
|
|
72
72
|
* Build the 4-phase memory consolidation prompt.
|
|
73
73
|
*
|
|
74
74
|
* Adapted from CC's consolidationPrompt.ts with our project context.
|
|
75
|
+
* P5: Enhanced with category-aware merge rules from write gate taxonomy.
|
|
75
76
|
*/
|
|
76
77
|
export declare function buildConsolidationPrompt(memoryRoot: string, transcriptDir: string, sessionIds: string[], opts?: {
|
|
77
78
|
hasQMemory?: boolean;
|
|
79
|
+
categoryContext?: string;
|
|
78
80
|
}): string;
|
|
79
81
|
/**
|
|
80
82
|
* Check whether dream consolidation should run.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { QMemoryCategory } from "../../skills/memory/memory-write-gate.js";
|
|
2
|
+
/** A memory file with its inferred category and metadata. */
|
|
3
|
+
export interface CategorizedMemoryFile {
|
|
4
|
+
filename: string;
|
|
5
|
+
category: QMemoryCategory | "uncategorized";
|
|
6
|
+
/** First line description. */
|
|
7
|
+
description: string;
|
|
8
|
+
/** File size bytes. */
|
|
9
|
+
sizeBytes: number;
|
|
10
|
+
/** Count of entries/bullets in the file. */
|
|
11
|
+
entryCount: number;
|
|
12
|
+
}
|
|
13
|
+
/** Category statistics for the dream prompt. */
|
|
14
|
+
export interface CategoryManifest {
|
|
15
|
+
/** Per-category file groups. */
|
|
16
|
+
categories: Record<string, CategorizedMemoryFile[]>;
|
|
17
|
+
/** Total files scanned. */
|
|
18
|
+
totalFiles: number;
|
|
19
|
+
/** Files that couldn't be classified. */
|
|
20
|
+
uncategorizedCount: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Scan MEMDIR and classify all topic files by category.
|
|
24
|
+
*
|
|
25
|
+
* @param memoryRoot - The MEMDIR root directory
|
|
26
|
+
* @returns Category manifest with grouped files
|
|
27
|
+
*/
|
|
28
|
+
export declare function scanCategoryManifest(memoryRoot: string): Promise<CategoryManifest>;
|
|
29
|
+
/**
|
|
30
|
+
* Category-specific merge/conflict rules for the dream prompt.
|
|
31
|
+
*
|
|
32
|
+
* These rules tell the dream agent how to handle each category:
|
|
33
|
+
* - facts: supersede (newer replaces older when same topic)
|
|
34
|
+
* - lessons: accumulate (append new insights, don't delete old)
|
|
35
|
+
* - preferences: overwrite (latest preference wins)
|
|
36
|
+
* - patterns: merge (consolidate duplicates into one authoritative entry)
|
|
37
|
+
* - decisions: update (add "update" section if decision changed)
|
|
38
|
+
*/
|
|
39
|
+
export declare const CATEGORY_MERGE_RULES: Record<QMemoryCategory | "uncategorized", string>;
|
|
40
|
+
/**
|
|
41
|
+
* Format the category manifest and merge rules as an injection block
|
|
42
|
+
* for the dream consolidation prompt.
|
|
43
|
+
*
|
|
44
|
+
* This replaces the blind "grep transcripts" approach with structured
|
|
45
|
+
* guidance about what exists and how to handle each category.
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatCategoryContextBlock(manifest: CategoryManifest): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,4 +3,5 @@ export { createContentReplacementState, enforceToolResultBudget, maybePersistLar
|
|
|
3
3
|
export { resolveToolEligibility, type ToolEligibilityContext, type ToolEligibilityResult } from "./tool-eligibility.js";
|
|
4
4
|
export { runForkedAgent, type ForkedAgentParams, type CanUseToolFn } from "./forked-agent.js";
|
|
5
5
|
export { runDream, type DreamRunDeps } from "./dream-agent.js";
|
|
6
|
+
export { runDecayCycle, shouldTriggerDecay, markDecayComplete, type DecayCycleDeps, type DecayCycleResult, type DecayConfig } from "./memory-decay.js";
|
|
6
7
|
export { createProgressTracker, updateProgressFromUsage, recordToolUse, getProgressUpdate, type AgentProgress, } from "./progress-tracker.js";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { DecayOptions, DecayResult } from "../../skills/memory/qmemory-adapter.js";
|
|
2
|
+
export interface DecayConfig {
|
|
3
|
+
/** Minimum hours between decay cycles. Default: 24. */
|
|
4
|
+
minIntervalHours: number;
|
|
5
|
+
/** Enable temporal expiry (event/plan memories past grace period). Default: true. */
|
|
6
|
+
temporalExpiry: boolean;
|
|
7
|
+
/** Enable staleness decay (reduce importance of unaccessed memories). Default: true. */
|
|
8
|
+
stalenessDecay: boolean;
|
|
9
|
+
/** Enable noise archival (archive memories below threshold). Default: true. */
|
|
10
|
+
noiseArchival: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_DECAY_CONFIG: DecayConfig;
|
|
13
|
+
/**
|
|
14
|
+
* Check whether enough time has elapsed since last decay.
|
|
15
|
+
* Returns true if decay should run.
|
|
16
|
+
*/
|
|
17
|
+
export declare function shouldTriggerDecay(memoryRoot: string, config?: Partial<DecayConfig>): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* Mark decay as having just run (persist timestamp).
|
|
20
|
+
*/
|
|
21
|
+
export declare function markDecayComplete(memoryRoot: string): Promise<void>;
|
|
22
|
+
export interface DecayCycleDeps {
|
|
23
|
+
/** QMemory adapter with triggerDecay method. */
|
|
24
|
+
adapter: {
|
|
25
|
+
triggerDecay(userId: string, options?: DecayOptions): Promise<DecayResult>;
|
|
26
|
+
};
|
|
27
|
+
/** User ID for QMemory operations. */
|
|
28
|
+
userId: string;
|
|
29
|
+
/** Memory root directory (for gate marker). */
|
|
30
|
+
memoryRoot: string;
|
|
31
|
+
/** Decay configuration overrides. */
|
|
32
|
+
config?: Partial<DecayConfig>;
|
|
33
|
+
/** Logger. */
|
|
34
|
+
log?: {
|
|
35
|
+
info(msg: string): void;
|
|
36
|
+
debug?(msg: string): void;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface DecayCycleResult {
|
|
40
|
+
/** Whether decay actually ran (false = skipped by gate). */
|
|
41
|
+
ran: boolean;
|
|
42
|
+
/** Number of memories whose importance was reduced. */
|
|
43
|
+
decayed: number;
|
|
44
|
+
/** Number of memories archived (below threshold). */
|
|
45
|
+
archived: number;
|
|
46
|
+
/** Duration in ms. */
|
|
47
|
+
durationMs: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Run a full decay cycle with gate check.
|
|
51
|
+
*
|
|
52
|
+
* Lifecycle:
|
|
53
|
+
* 1. Check time gate (24h default)
|
|
54
|
+
* 2. Call QMemory /v1/admin/decay
|
|
55
|
+
* 3. Mark completion timestamp
|
|
56
|
+
*/
|
|
57
|
+
export declare function runDecayCycle(deps: DecayCycleDeps): Promise<DecayCycleResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { createHookRegistry, type RuntimeLogger } from "./hook-registry.js";
|
|
2
2
|
export { registerMemoryHooks, createMemoryPrefetchState, type MemoryHooksDeps, type MemoryPrefetchState, MEMORY_PREFETCH_CONFIG, } from "./memory-hooks.js";
|
|
3
3
|
export { registerContextCompressionHook, compressMessages } from "./context-compression.js";
|
|
4
|
+
export { registerSkillRecallHooks, detectRetrospectiveTrigger, invalidateSkillRecallCache, type SkillRecallHooksDeps, SKILL_RECALL_CONFIG, } from "./skill-recall-hooks.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HookRegistry } from "../../contracts/hooks.js";
|
|
2
2
|
import type { MemoryProvider } from "qlogicagent-runtime-contracts";
|
|
3
|
+
import type { Memdir } from "../../skills/memory/memdir.js";
|
|
3
4
|
export declare const MEMORY_PREFETCH_CONFIG: {
|
|
4
5
|
/** Max bytes of memory content to inject per session (CC: 60KB) */
|
|
5
6
|
readonly MAX_SESSION_BYTES: number;
|
|
@@ -47,3 +48,22 @@ export declare function createMemoryPrefetchState(): MemoryPrefetchState;
|
|
|
47
48
|
export declare function registerMemoryHooks(hooks: HookRegistry, deps: MemoryHooksDeps,
|
|
48
49
|
/** Shared state — pass the same object across hook re-registrations in a session. */
|
|
49
50
|
prefetchState?: MemoryPrefetchState): () => void;
|
|
51
|
+
export interface MemdirRecallHookDeps {
|
|
52
|
+
/** MEMDIR instance (lazy: may be null at registration time). */
|
|
53
|
+
getMemdir: () => Memdir | null;
|
|
54
|
+
/** Logger. */
|
|
55
|
+
log: {
|
|
56
|
+
debug(msg: string): void;
|
|
57
|
+
warn(msg: string): void;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Register the MEMDIR cross-file recall hook on `memory.before_recall`.
|
|
62
|
+
*
|
|
63
|
+
* - Priority 40 (before QMemory at 50)
|
|
64
|
+
* - Scans topic files, selects top-5 relevant
|
|
65
|
+
* - Injects content into recalledMemories (merged with QMemory results)
|
|
66
|
+
* - Respects session byte budget from shared MemoryPrefetchState
|
|
67
|
+
* - Dedup via surfacedPaths (shared with QMemory hook)
|
|
68
|
+
*/
|
|
69
|
+
export declare function registerMemdirRecallHook(hooks: HookRegistry, deps: MemdirRecallHookDeps, prefetchState?: MemoryPrefetchState): () => void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { HookRegistry } from "../../contracts/hooks.js";
|
|
2
|
+
export declare const SKILL_RECALL_CONFIG: {
|
|
3
|
+
/** Max number of cross-project skills to inject per turn. */
|
|
4
|
+
readonly MAX_RECALLED_SKILLS: 3;
|
|
5
|
+
/** Max chars of skill content to include in recall context. */
|
|
6
|
+
readonly MAX_SKILL_CONTENT_CHARS: 800;
|
|
7
|
+
/** Cache TTL for known project skill index (ms). */
|
|
8
|
+
readonly CACHE_TTL_MS: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Detect whether user message contains retrospective/cross-reference semantics.
|
|
12
|
+
* Returns extracted keywords for skill matching if triggered, or null.
|
|
13
|
+
*/
|
|
14
|
+
export declare function detectRetrospectiveTrigger(message: string): string[] | null;
|
|
15
|
+
export interface SkillRecallHooksDeps {
|
|
16
|
+
/** Current project cwd (to exclude from cross-project search). */
|
|
17
|
+
currentCwd?: string;
|
|
18
|
+
/** Logger. */
|
|
19
|
+
log: {
|
|
20
|
+
debug(msg: string): void;
|
|
21
|
+
warn(msg: string): void;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Register the cross-project skill recall hook on `memory.before_recall`.
|
|
26
|
+
* Runs at lower priority (60) than QMemory prefetch (50) so it supplements,
|
|
27
|
+
* not replaces, the standard memory recall.
|
|
28
|
+
*
|
|
29
|
+
* When triggered, injects cross-project skill metadata into recalledMemories.
|
|
30
|
+
*/
|
|
31
|
+
export declare function registerSkillRecallHooks(hooks: HookRegistry, deps: SkillRecallHooksDeps): () => void;
|
|
32
|
+
/**
|
|
33
|
+
* Invalidate the cross-project skill index cache.
|
|
34
|
+
* Call when skills are created/deleted/promoted to refresh.
|
|
35
|
+
*/
|
|
36
|
+
export declare function invalidateSkillRecallCache(): void;
|
|
@@ -2,17 +2,54 @@
|
|
|
2
2
|
* ACP Protocol Adapter — translates between qlogicagent's internal JSON-RPC
|
|
3
3
|
* protocol and the ACP (Agent-Client Protocol) wire format.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* session/new → create session with workspaceRoot + mcpServers
|
|
8
|
-
* prompt → send task
|
|
9
|
-
* session/close → abort
|
|
10
|
-
* message notifications → turn.delta / turn.end
|
|
5
|
+
* Aligned with @agentclientprotocol/sdk v0.18.2 (PROTOCOL_VERSION = 1).
|
|
6
|
+
* Reference: AionUI ClientSideConnection, @agentclientprotocol/sdk.
|
|
11
7
|
*
|
|
12
|
-
*
|
|
8
|
+
* ACP = JSON-RPC 2.0 over NDJSON stdio:
|
|
9
|
+
* HOST → AGENT (requests):
|
|
10
|
+
* initialize, session/new, session/prompt, session/close, session/resume
|
|
11
|
+
* AGENT → HOST (notifications):
|
|
12
|
+
* session/update — carries { sessionId, update: { sessionUpdate: "...", ...payload } }
|
|
13
|
+
* AGENT → HOST (requests, host must respond):
|
|
14
|
+
* fs/read_text_file, fs/write_text_file, session/request_permission,
|
|
15
|
+
* session/elicitation, terminal/create, terminal/output, terminal/release,
|
|
16
|
+
* terminal/wait_for_exit, terminal/kill
|
|
13
17
|
*/
|
|
14
18
|
import type { ChildProcess } from "node:child_process";
|
|
15
19
|
import type { AcpInitializeResult, AcpSessionResult, AcpPromptResponse, McpServerConfig } from "./acp-types.js";
|
|
20
|
+
/**
|
|
21
|
+
* Handler for agent→host requests (fs, terminal, permission, elicitation).
|
|
22
|
+
* Host implementations should implement the methods they support.
|
|
23
|
+
*/
|
|
24
|
+
export interface AcpHostRequestHandler {
|
|
25
|
+
/** Read a text file from the host filesystem. */
|
|
26
|
+
readTextFile?(params: {
|
|
27
|
+
path: string;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
content: string;
|
|
30
|
+
} | undefined>;
|
|
31
|
+
/** Write a text file on the host filesystem. */
|
|
32
|
+
writeTextFile?(params: {
|
|
33
|
+
path: string;
|
|
34
|
+
content: string;
|
|
35
|
+
}): Promise<Record<string, unknown> | undefined>;
|
|
36
|
+
/** Request permission for a tool call (return selected option). */
|
|
37
|
+
requestPermission?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
38
|
+
/** Elicitation request (ask user for input). */
|
|
39
|
+
elicitation?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
40
|
+
/** Create a terminal session. */
|
|
41
|
+
createTerminal?(params: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
|
|
42
|
+
/** Terminal output data. */
|
|
43
|
+
terminalOutput?(params: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
|
|
44
|
+
/** Release a terminal. */
|
|
45
|
+
releaseTerminal?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
46
|
+
/** Wait for terminal exit. */
|
|
47
|
+
waitForTerminalExit?(params: Record<string, unknown>): Promise<Record<string, unknown> | undefined>;
|
|
48
|
+
/** Kill a terminal. */
|
|
49
|
+
killTerminal?(params: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
50
|
+
/** Extension method (unknown method from agent). */
|
|
51
|
+
extMethod?(method: string, params: unknown): Promise<unknown>;
|
|
52
|
+
}
|
|
16
53
|
/** Internal representation of an ACP notification translated to qlogicagent format. */
|
|
17
54
|
export interface TranslatedNotification {
|
|
18
55
|
method: string;
|
|
@@ -21,45 +58,59 @@ export interface TranslatedNotification {
|
|
|
21
58
|
export declare class AcpProtocolAdapter {
|
|
22
59
|
private pendingRpcs;
|
|
23
60
|
private rl;
|
|
61
|
+
private child;
|
|
24
62
|
private onNotification;
|
|
63
|
+
private hostHandler;
|
|
25
64
|
/**
|
|
26
65
|
* Attach to a child process's stdio for ACP communication.
|
|
27
66
|
* Must be called before any RPC methods.
|
|
67
|
+
*
|
|
68
|
+
* @param child The spawned ACP agent process
|
|
69
|
+
* @param onNotification Callback for agent notifications (session/update, etc.)
|
|
70
|
+
* @param hostHandler Optional handler for agent→host requests (fs, terminal, permission)
|
|
71
|
+
*/
|
|
72
|
+
attach(child: ChildProcess, onNotification?: (method: string, params: unknown) => void, hostHandler?: AcpHostRequestHandler): void;
|
|
73
|
+
/**
|
|
74
|
+
* Handle an incoming JSON-RPC request from the agent (reverse-RPC).
|
|
75
|
+
* Agent calls host for fs operations, terminal, permissions, etc.
|
|
28
76
|
*/
|
|
29
|
-
|
|
77
|
+
private handleAgentRequest;
|
|
30
78
|
/** Detach from the child process. */
|
|
31
79
|
detach(): void;
|
|
32
80
|
/** Send a raw JSON-RPC request and await response. */
|
|
33
81
|
sendRpc(child: ChildProcess, method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;
|
|
34
82
|
/**
|
|
35
83
|
* Perform ACP initialize handshake.
|
|
36
|
-
*
|
|
37
|
-
* Extracts `supportsResume` from capabilities for D-1 session resume.
|
|
84
|
+
* Sends standard clientInfo + clientCapabilities (aligned with SDK).
|
|
38
85
|
*/
|
|
39
86
|
initialize(child: ChildProcess): Promise<AcpInitializeResult>;
|
|
40
87
|
/**
|
|
41
88
|
* Create an ACP session.
|
|
42
|
-
*
|
|
89
|
+
* Official SDK params: { cwd, mcpServers, additionalDirectories? }
|
|
90
|
+
* Optionally injects system prompt as extension field.
|
|
43
91
|
*/
|
|
44
92
|
createSession(child: ChildProcess, options: {
|
|
45
|
-
|
|
93
|
+
cwd: string;
|
|
46
94
|
mcpServers?: McpServerConfig[];
|
|
95
|
+
additionalDirectories?: string[];
|
|
47
96
|
systemPrompt?: string;
|
|
48
97
|
}): Promise<AcpSessionResult>;
|
|
49
98
|
/**
|
|
50
99
|
* Send a prompt to a running ACP session.
|
|
51
|
-
*
|
|
100
|
+
* Official SDK params: { sessionId, prompt: ContentBlock[], messageId? }
|
|
101
|
+
* Official SDK response: { stopReason, usage?, userMessageId? }
|
|
102
|
+
*
|
|
103
|
+
* Note: Actual content is delivered via session/update notifications DURING
|
|
104
|
+
* the prompt execution. The response only signals completion.
|
|
52
105
|
*/
|
|
53
106
|
sendPrompt(child: ChildProcess, sessionId: string, content: string, timeoutMs?: number): Promise<AcpPromptResponse>;
|
|
54
107
|
/**
|
|
55
|
-
* Resume an existing ACP session (
|
|
56
|
-
*
|
|
57
|
-
* Falls back to createSession + summary injection if session/resume fails.
|
|
108
|
+
* Resume an existing ACP session (loadSession capability).
|
|
109
|
+
* Official SDK method: session/load (same schema as session/new + sessionId).
|
|
58
110
|
*/
|
|
59
111
|
resumeSession(child: ChildProcess, sessionId: string, options?: {
|
|
60
|
-
|
|
112
|
+
cwd?: string;
|
|
61
113
|
mcpServers?: McpServerConfig[];
|
|
62
|
-
summary?: string;
|
|
63
114
|
}): Promise<AcpSessionResult>;
|
|
64
115
|
/**
|
|
65
116
|
* Close an ACP session.
|
|
@@ -68,6 +119,9 @@ export declare class AcpProtocolAdapter {
|
|
|
68
119
|
/**
|
|
69
120
|
* Translate an ACP notification into qlogicagent's internal format.
|
|
70
121
|
* Returns null if the notification is not translatable (handled separately).
|
|
122
|
+
*
|
|
123
|
+
* Standard ACP: agent sends "session/update" notification with
|
|
124
|
+
* params: { sessionId, update: { sessionUpdate: "<type>", ...payload } }
|
|
71
125
|
*/
|
|
72
126
|
static translateNotification(method: string, params: unknown): TranslatedNotification | null;
|
|
73
127
|
}
|
|
@@ -136,39 +136,52 @@ export interface AgentConfigStoreData {
|
|
|
136
136
|
/** ACP initialize result (from agent's response). */
|
|
137
137
|
export interface AcpInitializeResult {
|
|
138
138
|
protocolVersion: number;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
/** Standard ACP agentCapabilities (official SDK field). */
|
|
140
|
+
agentCapabilities: {
|
|
141
|
+
loadSession?: boolean;
|
|
142
|
+
mcpCapabilities?: {
|
|
143
|
+
http?: boolean;
|
|
144
|
+
sse?: boolean;
|
|
145
|
+
};
|
|
146
|
+
promptCapabilities?: {
|
|
147
|
+
audio?: boolean;
|
|
148
|
+
embeddedContext?: boolean;
|
|
149
|
+
image?: boolean;
|
|
150
|
+
};
|
|
151
|
+
sessionCapabilities?: Record<string, unknown>;
|
|
143
152
|
[key: string]: unknown;
|
|
144
153
|
};
|
|
145
|
-
|
|
154
|
+
/** Standard ACP agentInfo (official SDK field). */
|
|
155
|
+
agentInfo?: {
|
|
146
156
|
name: string;
|
|
147
157
|
version?: string;
|
|
148
158
|
};
|
|
159
|
+
authMethods?: Array<{
|
|
160
|
+
type: string;
|
|
161
|
+
[key: string]: unknown;
|
|
162
|
+
}>;
|
|
149
163
|
}
|
|
150
|
-
/** ACP session/new result. */
|
|
164
|
+
/** ACP session/new result (official: { sessionId, configOptions?, models?, modes? }). */
|
|
151
165
|
export interface AcpSessionResult {
|
|
152
|
-
|
|
166
|
+
sessionId: string;
|
|
153
167
|
}
|
|
154
|
-
/** ACP
|
|
155
|
-
export
|
|
156
|
-
|
|
157
|
-
text?: string;
|
|
158
|
-
data?: string;
|
|
159
|
-
mimeType?: string;
|
|
160
|
-
}
|
|
161
|
-
/** ACP prompt response. */
|
|
168
|
+
/** Standard ACP stopReason. */
|
|
169
|
+
export type AcpStopReason = "end_turn" | "max_tokens" | "max_turn_requests" | "refusal" | "cancelled";
|
|
170
|
+
/** ACP prompt response (official: { stopReason, usage?, userMessageId? }). */
|
|
162
171
|
export interface AcpPromptResponse {
|
|
163
|
-
|
|
172
|
+
stopReason: AcpStopReason;
|
|
164
173
|
usage?: AcpPromptResponseUsage;
|
|
174
|
+
userMessageId?: string;
|
|
175
|
+
/** Aggregated text from session/update notifications (populated by adapter). */
|
|
176
|
+
text?: string;
|
|
165
177
|
}
|
|
166
|
-
/** ACP per-turn usage stats. */
|
|
178
|
+
/** ACP per-turn usage stats (aligned with SDK zUsage). */
|
|
167
179
|
export interface AcpPromptResponseUsage {
|
|
168
180
|
inputTokens?: number;
|
|
169
181
|
outputTokens?: number;
|
|
170
182
|
totalTokens?: number;
|
|
171
183
|
cachedReadTokens?: number;
|
|
184
|
+
cachedWriteTokens?: number;
|
|
172
185
|
thoughtTokens?: number;
|
|
173
186
|
}
|
|
174
187
|
/** ACP usage_update notification payload (session-level). */
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/** Dot-directory name used for both user-level and project-level storage. */
|
|
9
9
|
export declare const AGENT_DOT_DIR = ".qlogicagent";
|
|
10
|
-
/** `~/.qlogicagent/` */
|
|
10
|
+
/** `~/.qlogicagent/` (or QLOGICAGENT_HOME override) */
|
|
11
11
|
export declare function getUserAgentHome(): string;
|
|
12
12
|
/** `~/.qlogicagent/sessions/` */
|
|
13
13
|
export declare function getUserSessionsRoot(): string;
|
|
@@ -59,7 +59,19 @@ export declare function getProjectSessionsRoot(cwd: string): string;
|
|
|
59
59
|
export declare function getProjectSessionDir(cwd: string, sessionId: string): string;
|
|
60
60
|
/** `<cwd>/.qlogicagent/checkpoints/` or `<cwd>/.qlogicagent/checkpoints/{sessionId}` */
|
|
61
61
|
export declare function getProjectCheckpointsDir(cwd: string, sessionId?: string): string;
|
|
62
|
-
/** `<cwd>/.qlogicagent/memory.json` */
|
|
63
|
-
export declare function getProjectMemoryPath(cwd: string): string;
|
|
64
62
|
/** `<gitRoot>/.qlogicagent/hooks/` */
|
|
65
63
|
export declare function getGitRootHooksDir(gitRoot: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Discover all known project directories from session history.
|
|
66
|
+
* Scans `~/.qlogicagent/sessions/` metadata to extract unique `cwd` paths.
|
|
67
|
+
* Used for cross-project skill recall (read-only, never writes to foreign projects).
|
|
68
|
+
*
|
|
69
|
+
* @param excludeCwd - Current project cwd to exclude from results
|
|
70
|
+
* @returns Array of absolute paths to project roots that have been worked on
|
|
71
|
+
*/
|
|
72
|
+
export declare function getKnownProjectDirs(excludeCwd?: string): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Get skill directories from all known projects (excluding current).
|
|
75
|
+
* Returns paths to `<project>/.qlogicagent/skills/` for recall-only access.
|
|
76
|
+
*/
|
|
77
|
+
export declare function getAllProjectSkillDirs(excludeCwd?: string): string[];
|