qlogicagent 2.18.2 → 2.18.4

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.
Files changed (91) hide show
  1. package/dist/agent.js +38 -24
  2. package/dist/cli.js +1 -1
  3. package/dist/index.js +553 -485
  4. package/dist/orchestration.js +11 -11
  5. package/dist/protocol.js +1 -1
  6. package/dist/skills/mcp/astraclaw-native-mcp-server.js +8 -6
  7. package/dist/types/agent/memory-recall-injection.d.ts +2 -1
  8. package/dist/types/agent/tool-loop/budget-continuation-policy.d.ts +4 -0
  9. package/dist/types/agent/tool-loop/completion-action-policy.d.ts +9 -1
  10. package/dist/types/cli/credential-vault.d.ts +6 -0
  11. package/dist/types/cli/handlers/community-handler.d.ts +1 -2
  12. package/dist/types/cli/handlers/memory-handler.d.ts +7 -0
  13. package/dist/types/cli/handlers/turn-handler.d.ts +50 -1
  14. package/dist/types/cli/memory-coordinator.d.ts +4 -0
  15. package/dist/types/cli/pet-runtime.d.ts +2 -0
  16. package/dist/types/cli/rpc-registry.d.ts +11 -0
  17. package/dist/types/cli/runtime-hook-bootstrap.d.ts +2 -0
  18. package/dist/types/cli/skill-tools-bootstrap.d.ts +5 -0
  19. package/dist/types/cli/stdio-acp-request-host.d.ts +2 -1
  20. package/dist/types/cli/stdio-rpc-handler-hosts.d.ts +1 -0
  21. package/dist/types/cli/stdio-server.d.ts +4 -0
  22. package/dist/types/cli/task-distillation-coordinator.d.ts +79 -0
  23. package/dist/types/cli/tool-bootstrap-core-registration.d.ts +24 -0
  24. package/dist/types/cli/turn-core.d.ts +0 -6
  25. package/dist/types/cli/turn-project-router.d.ts +9 -0
  26. package/dist/types/contracts/hooks.d.ts +3 -0
  27. package/dist/types/contracts/turn-event.d.ts +8 -4
  28. package/dist/types/orchestration/agent-instance.d.ts +4 -0
  29. package/dist/types/orchestration/context/reactive-compact.d.ts +4 -6
  30. package/dist/types/orchestration/error-handling/retry-loop.d.ts +0 -22
  31. package/dist/types/orchestration/goal-loop-coordinator.d.ts +6 -0
  32. package/dist/types/orchestration/goal-mode-adapters.d.ts +20 -1
  33. package/dist/types/orchestration/goal-run-types.d.ts +10 -0
  34. package/dist/types/orchestration/skill-improvement.d.ts +7 -2
  35. package/dist/types/orchestration/workflow/run-history-store.d.ts +2 -0
  36. package/dist/types/orchestration/workflow/workflow-runtime.d.ts +8 -0
  37. package/dist/types/protocol/methods.d.ts +0 -26
  38. package/dist/types/protocol/wire/acp-agent-management.d.ts +3 -0
  39. package/dist/types/protocol/wire/agent-events.d.ts +2 -2
  40. package/dist/types/protocol/wire/agent-methods.d.ts +0 -11
  41. package/dist/types/protocol/wire/gateway-rpc.d.ts +1 -0
  42. package/dist/types/protocol/wire/memory-provider-lifecycle.d.ts +3 -0
  43. package/dist/types/protocol/wire/notification-payloads.d.ts +27 -0
  44. package/dist/types/runtime/community/community-consent-client.d.ts +0 -21
  45. package/dist/types/runtime/config/tunable-defaults.d.ts +6 -0
  46. package/dist/types/runtime/execution/memory-decay.d.ts +5 -1
  47. package/dist/types/runtime/hooks/context-compression.d.ts +5 -0
  48. package/dist/types/runtime/hooks/memory-hooks.d.ts +16 -0
  49. package/dist/types/runtime/infra/acp-detector.d.ts +8 -0
  50. package/dist/types/runtime/infra/acp-protocol-adapter.d.ts +10 -0
  51. package/dist/types/runtime/infra/agent-paths.d.ts +9 -7
  52. package/dist/types/runtime/infra/agent-process.d.ts +6 -0
  53. package/dist/types/runtime/infra/astraclaw-capabilities.d.ts +9 -6
  54. package/dist/types/runtime/infra/checkpoint-backend.d.ts +1 -1
  55. package/dist/types/runtime/infra/migrate-device-scope.d.ts +49 -0
  56. package/dist/types/runtime/infra/project-data-paths.d.ts +4 -3
  57. package/dist/types/runtime/infra/project-skill-manifest.d.ts +3 -2
  58. package/dist/types/runtime/infra/working-materials-store.d.ts +8 -14
  59. package/dist/types/runtime/pet/pet-profile-service.d.ts +7 -0
  60. package/dist/types/runtime/pet/petdex-forge-service.d.ts +3 -1
  61. package/dist/types/runtime/ports/memory-provider.d.ts +23 -0
  62. package/dist/types/runtime/ports/project-memory-store.d.ts +2 -0
  63. package/dist/types/runtime/prompt/environment-context.d.ts +15 -3
  64. package/dist/types/runtime/prompt/fresh-workspace-evidence.d.ts +7 -0
  65. package/dist/types/runtime/prompt/instruction-loader.d.ts +0 -1
  66. package/dist/types/runtime/session/inbound-upload-persistence.d.ts +4 -0
  67. package/dist/types/runtime/session/session-catalog.d.ts +8 -0
  68. package/dist/types/runtime/session/session-resume.d.ts +5 -0
  69. package/dist/types/runtime/session/session-transcript-store.d.ts +8 -1
  70. package/dist/types/skills/mcp/mcp-manager.d.ts +25 -1
  71. package/dist/types/skills/memory/fts-segment.d.ts +20 -0
  72. package/dist/types/skills/memory/local-memory-provider.d.ts +66 -4
  73. package/dist/types/skills/memory/local-store-records.d.ts +6 -1
  74. package/dist/types/skills/memory/local-store.d.ts +63 -10
  75. package/dist/types/skills/memory/memdir.d.ts +17 -4
  76. package/dist/types/skills/memory/memory-consolidation.d.ts +7 -0
  77. package/dist/types/skills/memory/proposal-consumer.d.ts +51 -0
  78. package/dist/types/skills/memory/sqlite-memory-mappers.d.ts +2 -1
  79. package/dist/types/skills/memory/sqlite-memory-schema.d.ts +9 -1
  80. package/dist/types/skills/memory/task-distillation.d.ts +148 -0
  81. package/dist/types/skills/tools/search-tool.d.ts +6 -0
  82. package/dist/types/skills/tools/shell/task-output.d.ts +2 -0
  83. package/package.json +3 -2
  84. package/dist/types/agent/tool-loop/skill-instruction-policy.d.ts +0 -7
  85. package/dist/types/agent/tool-loop/tool-guardrails.d.ts +0 -24
  86. package/dist/types/cli/tool-bootstrap-community-registration.d.ts +0 -9
  87. package/dist/types/cli/turn-skill-autopersist.d.ts +0 -22
  88. package/dist/types/runtime/community/community-discovery-cache.d.ts +0 -24
  89. package/dist/types/runtime/community/community-discovery-coordinator.d.ts +0 -33
  90. package/dist/types/runtime/hooks/community-discovery-hook.d.ts +0 -18
  91. package/dist/types/skills/tools/community-seek-tool.d.ts +0 -49
@@ -55,12 +55,24 @@ export declare function shellGuidanceLines(shellInfo: ShellInfo | undefined, she
55
55
  */
56
56
  export declare function createEnvironmentContextSection(cwdOverride?: string, shellInfo?: ShellInfo): SystemPromptSection;
57
57
  /**
58
- * Create the task guidance system prompt section.
59
- * Domain-aware: selects appropriate guidance based on detected or overridden task domain.
58
+ * Domain-specific guidance ONLY — the small, genuinely per-turn-variable block.
59
+ * Excludes universalGuidance() (which is domain-INVARIANT and lives in its own
60
+ * stable section, see createUniversalGuidanceSection). This is the single source
61
+ * of truth for domain content, so the combined section and the split sections
62
+ * never drift.
60
63
  *
61
64
  * @param domain - Task domain from auto-detection or host override.
62
65
  */
63
- export declare function createTaskGuidanceSection(domain?: TaskDomain): SystemPromptSection;
66
+ export declare function renderDomainGuidanceBlock(domain?: TaskDomain): string[];
67
+ /**
68
+ * Universal (domain-INVARIANT) working-approach guidance as a STABLE (memoized)
69
+ * system section. Byte-identical every turn regardless of the detected domain, so
70
+ * it belongs in the cacheable system-prompt prefix. The per-turn domain block
71
+ * (renderDomainGuidanceBlock) is deliberately NOT part of this section — it is
72
+ * injected as a system message right before the last user message so the system
73
+ * prompt stays byte-stable when the detected domain switches.
74
+ */
75
+ export declare function createUniversalGuidanceSection(): SystemPromptSection;
64
76
  /**
65
77
  * Create a system prompt section that provides tool usage guidance.
66
78
  * CC parity: matches claude-code's getUsingYourToolsSection().
@@ -33,4 +33,11 @@ export declare function isExplicitNoToolTurn(messages: readonly PromptMessageLik
33
33
  * stay subject to the normal evidence filter.)
34
34
  */
35
35
  export declare function selectFreshWorkspaceEvidenceTools<TTool extends ToolNameLike>(tools: readonly TTool[], policy: FreshWorkspaceEvidencePolicy): TTool[];
36
+ /**
37
+ * Prompt notice for an explicit "don't use tools" instruction. This INFORMS the
38
+ * model and leaves the judgment to it — the engine no longer strips the tool list
39
+ * (toolChoice="none"), which also silently disabled the reactive guards and
40
+ * misfired on quoted/reported speech ("he said don't use tools").
41
+ */
42
+ export declare function createExplicitNoToolNoticeSection(): SystemPromptSection;
36
43
  export declare function createFreshWorkspaceEvidenceSection(policy: FreshWorkspaceEvidencePolicy): SystemPromptSection | null;
@@ -54,7 +54,6 @@ export declare function loadInstructions(cwd: string, hooks?: HookRegistry): Pro
54
54
  */
55
55
  export declare function buildInstructionsPrompt(files: InstructionFileInfo[]): string;
56
56
  export declare function extractLiteralResponseRequirements(files: InstructionFileInfo[]): LiteralResponseRequirement[];
57
- export declare function applyLiteralResponseRequirements(content: string, requirements: readonly LiteralResponseRequirement[]): string;
58
57
  /**
59
58
  * Get conditional rules that match a target file path.
60
59
  * CC parity: getManagedAndUserConditionalRules() + getMemoryFilesForNestedDirectory()
@@ -34,6 +34,10 @@ export declare function persistInboundUploadUrl(url: string, projectId: string,
34
34
  /**
35
35
  * Persist + rewrite the inbound uploads on the LAST user message of a turn (the new message;
36
36
  * resumed history already carries persisted local URLs). Mutates and returns the message array.
37
+ *
38
+ * Failure parity with the document path (appendLocalDocumentNotesToText): when a media upload
39
+ * could NOT be persisted, the message gets a model-visible note instead of silently keeping a
40
+ * transport URL that expires with the turn — the model must know the reference is short-lived.
37
41
  */
38
42
  export declare function persistInboundUploadsForTurn(messages: ChatMessage[], projectId: string | undefined, sessionId: string | undefined): Promise<ChatMessage[]>;
39
43
  /**
@@ -1,4 +1,12 @@
1
1
  import type { SessionListEntry } from "./session-types.js";
2
2
  export declare function listSessions(limit: number | undefined, projectRoot: string): Promise<SessionListEntry[]>;
3
3
  export declare function deleteSession(sessionId: string, projectRoot: string): Promise<void>;
4
+ /**
5
+ * ⚠️ Destructive cascade with NO user-visible confirmation: every pruned session goes through
6
+ * deleteSession, which permanently removes its transcript + metadata + checkpoints + uploads.
7
+ * Currently has NO caller. If you wire this up, the deletions must be surfaced to the user
8
+ * (count + which sessions) — silently reaping MAX_SESSIONS-overflow would be exactly the kind of
9
+ * invisible data loss docs/judgment-over-mechanism.md forbids. Also note listSessions skips
10
+ * unreadable-metadata sessions, so a prune pass under fs errors could mis-rank what "oldest" is.
11
+ */
4
12
  export declare function pruneOldSessions(projectRoot: string): Promise<number>;
@@ -1,4 +1,9 @@
1
1
  import type { PersistedSession } from "./session-types.js";
2
+ /** Coded error: the session's project root cannot be read at all (deleted dir, unplugged drive,
3
+ * permissions). Distinguishable from the `null` return, which strictly means "this session has no
4
+ * persisted transcript" — conflating the two made every caller silently start a NEW empty session
5
+ * on a read failure (docs/judgment-over-mechanism.md: "read failed" ≠ "does not exist"). */
6
+ export declare const PROJECT_ROOT_UNAVAILABLE = "PROJECT_ROOT_UNAVAILABLE";
2
7
  export declare function loadSessionForResume(sessionId: string, projectRoot: string, options?: {
3
8
  includeDisplayMetadata?: boolean;
4
9
  }): Promise<PersistedSession | null>;
@@ -6,10 +6,17 @@ export interface TranscriptLoadResult {
6
6
  /** 1-based line numbers that failed to parse (bounded to the first MAX_REPORTED_CORRUPT_LINES). */
7
7
  corruptLineNumbers: number[];
8
8
  }
9
+ /**
10
+ * Outcome of an appendMessage call. "skipped-deleted" (the session was deleted — a LEGAL late-write
11
+ * no-op) is deliberately distinguishable from "failed" (the write itself failed — the message is
12
+ * LOST and callers must leave a trace / surface it), per docs/judgment-over-mechanism.md:
13
+ * "does not exist" and "write failed" must never be conflated into one silent boolean.
14
+ */
15
+ export type AppendMessageOutcome = "appended" | "skipped-deleted" | "failed";
9
16
  export declare function appendMessage(sessionId: string, message: ChatMessage, projectRoot: string, turnId?: string, metadata?: {
10
17
  usage?: TokenUsage;
11
18
  displayMetadata?: MessageDisplayMetadata;
12
- }): Promise<boolean>;
19
+ }): Promise<AppendMessageOutcome>;
13
20
  export declare function countTranscriptMessages(sessionId: string, projectRoot: string): Promise<number | null>;
14
21
  export declare function loadTranscript(sessionId: string, projectRoot: string, options?: {
15
22
  includeDisplayMetadata?: boolean;
@@ -1,4 +1,4 @@
1
- import type { PortableTool } from "../portable-tool.js";
1
+ import type { PortableTool, PortableToolResult } from "../portable-tool.js";
2
2
  interface ToolRegistryLike {
3
3
  addTools(tools: PortableTool[]): void;
4
4
  getToolNames(): string[];
@@ -35,6 +35,17 @@ export interface McpSecurityIssue {
35
35
  code: "dangerous_egress" | "persistence" | "ioc_public_key";
36
36
  message: string;
37
37
  }
38
+ /**
39
+ * A configured server that is NOT serving tools this session. Surfaced (not just logged)
40
+ * so capability queries (e.g. mcp_connectors_list) can disclose "configured but unavailable"
41
+ * instead of the server silently vanishing from the tool pool.
42
+ */
43
+ export interface McpServerFailure {
44
+ name: string;
45
+ /** "config" = entry invalid, skipped before connect; "connect" = every connect attempt failed. */
46
+ phase: "config" | "connect";
47
+ error: string;
48
+ }
38
49
  export interface McpManagerConfig {
39
50
  servers: McpServerEntry[];
40
51
  log?: {
@@ -67,7 +78,10 @@ export declare class McpManager {
67
78
  private toolCatalog?;
68
79
  private serverToolFilters;
69
80
  private serverOAuth;
81
+ private failedServers;
70
82
  constructor(config: McpManagerConfig);
83
+ /** Record (and loudly report) a server that will serve NO tools this session. */
84
+ private markServerFailed;
71
85
  private toServerDefinition;
72
86
  /**
73
87
  * Connect to all configured MCP servers and snapshot their tools.
@@ -81,6 +95,8 @@ export declare class McpManager {
81
95
  refreshServerTools(serverName: string): Promise<number>;
82
96
  /** Get names of all connected servers. */
83
97
  getConnectedServers(): string[];
98
+ /** Configured servers serving NO tools this session (invalid config or terminal connect failure). */
99
+ getFailedServers(): McpServerFailure[];
84
100
  /** Get total number of MCP tools across all servers. */
85
101
  getToolCount(): number;
86
102
  /**
@@ -95,6 +111,14 @@ export declare class McpManager {
95
111
  private registerTools;
96
112
  private removeRegisteredTool;
97
113
  }
114
+ /**
115
+ * Flatten an MCP CallToolResult into a text-bearing PortableToolResult.
116
+ * Non-text blocks (image/audio/resource…) cannot be dropped silently: content is
117
+ * the only channel the model sees, so the omission is disclosed in the text —
118
+ * "(no text output)" for a result that DID produce blocks is a lie.
119
+ * Exported for unit tests only.
120
+ */
121
+ export declare function toPortableResult(result: unknown): PortableToolResult;
98
122
  export declare function validateMcpToolWorkspaceBoundary(toolName: string, args: unknown, workspaceRoot: string | undefined): string | null;
99
123
  export declare function parseMcpConfig(json: unknown): McpServerEntry[];
100
124
  export declare function filterMcpTools<T extends {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * FTS pre-segmentation for CJK-aware keyword search.
3
+ *
4
+ * SQLite FTS5's unicode61 tokenizer does not segment CJK: a run of Chinese
5
+ * characters indexes as ONE token, so a query like 咖啡 can never match a
6
+ * memory containing 用户喜欢喝美式咖啡. Instead of switching tokenizers
7
+ * (trigram misses 2-char Chinese words, ICU is not bundled), we index a
8
+ * pre-segmented shadow column (`memories.text_seg`) and segment queries with
9
+ * the SAME function:
10
+ * - Latin/digit runs stay whole words ("docker", "v2")
11
+ * - CJK runs become character bigrams (咖啡, 啡因) + the single char for
12
+ * 1-char runs — the same scheme the near-duplicate gate already uses.
13
+ *
14
+ * Index side and query side MUST share this function; drift between them
15
+ * silently zeroes recall.
16
+ */
17
+ /** Segment text into FTS-friendly tokens (lowercased). */
18
+ export declare function segmentForFts(text: string): string[];
19
+ /** Render the segmented shadow text stored in memories.text_seg. */
20
+ export declare function segmentTextForFts(text: string): string;
@@ -9,7 +9,7 @@
9
9
  * - Without embedding: FTS-only search (still useful for exact/keyword matches)
10
10
  */
11
11
  import type { MemoryProvider, MemorySearchResult, MemorySearchOptions, MemoryIngestMessage, MemoryIngestOptions } from "../../protocol/wire/index.js";
12
- import type { MemoryClaimRecord, MemoryConflictRecord, MemoryUpdateInput, SqliteDatabase } from "./local-store.js";
12
+ import type { MemoryClaimRecord, MemoryConflictRecord, MemoryProposalRecord, MemoryUpdateInput, SqliteDatabase } from "./local-store.js";
13
13
  import { type AdoptedAttachment } from "./memory-attachment-store.js";
14
14
  import { type LocalEmbeddingConfig } from "./local-embedding.js";
15
15
  import { type ExtractedMemoryItem, type MemoryConsolidationResult } from "./memory-consolidation.js";
@@ -32,6 +32,12 @@ export declare class LocalMemoryProvider implements MemoryProvider {
32
32
  private attachmentStore;
33
33
  private userIdPrefix;
34
34
  private dbPath;
35
+ private attachmentsDir;
36
+ /** Active embedding model id — stamped onto stored vectors and used to skip
37
+ * incomparable vectors at search time (model switch = silent noise otherwise). */
38
+ private embeddingModelId;
39
+ /** One-shot flag: the embedding-degradation trace is logged once per provider instance. */
40
+ private embeddingFailureLogged;
35
41
  constructor(config: LocalMemoryProviderConfig);
36
42
  /** Persist an uploaded attachment (orphan until linked at commit). */
37
43
  adoptAttachment(input: {
@@ -57,9 +63,18 @@ export declare class LocalMemoryProvider implements MemoryProvider {
57
63
  /** Persist the understood/extracted text on an attachment row. */
58
64
  setAttachmentText(id: string, text: string): void;
59
65
  private resolveUserId;
66
+ /**
67
+ * The embedding API failing silently downgrades every search to FTS-only —
68
+ * leave one error-level trace per provider instance (deduped so a broken
69
+ * endpoint does not flood the log on every query).
70
+ */
71
+ private noteEmbeddingFailure;
60
72
  private buildEmbedding;
61
73
  search(query: string, userId: string, options?: MemorySearchOptions): Promise<MemorySearchResult[]>;
62
74
  ingest(messages: MemoryIngestMessage[], userId: string, options?: MemoryIngestOptions): Promise<void>;
75
+ /** Public embedding access for task-distillation signatures (R3). Null when
76
+ * the embedding provider is unavailable — callers must degrade, not throw. */
77
+ embedText(text: string): Promise<Float32Array | null>;
63
78
  addText(text: string, userId: string, options?: MemoryIngestOptions & {
64
79
  category?: string;
65
80
  importance?: number;
@@ -68,12 +83,47 @@ export declare class LocalMemoryProvider implements MemoryProvider {
68
83
  }>;
69
84
  remove(memoryId: string): Promise<boolean>;
70
85
  update(memoryId: string, input: MemoryUpdateInput): Promise<boolean>;
86
+ /**
87
+ * Prompt-injection screen for L2 writes. The memory-tool path already checks
88
+ * this, but implicit extraction / distillation / RPC ingestion used to write
89
+ * UNSCREENED — recalled memories land in a system message, so this is the
90
+ * last write-side gate. Rejections are traced, never silent.
91
+ */
92
+ private screenUnsafeItems;
71
93
  /**
72
94
  * Commit extracted memory items through the single consolidation pipeline.
73
95
  */
74
96
  ingestExtracted(items: ExtractedMemoryItem[], userId: string, options?: MemoryIngestOptions): Promise<MemoryConsolidationResult>;
75
97
  observeExtracted(items: ExtractedMemoryItem[], userId: string, options?: MemoryIngestOptions): Promise<MemoryConsolidationResult>;
76
98
  proposeExtracted(items: ExtractedMemoryItem[], userId: string, options?: MemoryIngestOptions): Promise<MemoryConsolidationResult>;
99
+ /**
100
+ * Consume the pending-proposal backlog (the "proposals black hole" fix).
101
+ *
102
+ * Trust ladder, mirroring V3's graduated autonomy:
103
+ * - CORROBORATED facts — the same fact proposed again from an independent
104
+ * context (different session or different source) — commit automatically,
105
+ * with a trace. Evidence, not a confidence score, is the auto gate.
106
+ * - Feedback-distillation proposals commit alone: their >=2-evidence bar
107
+ * was already enforced upstream (idempotency-keyed sweep, §10).
108
+ * - dream-source proposals never commit alone; they only corroborate.
109
+ * - Everything else waits for corroboration and EXPIRES after the TTL —
110
+ * visibly (status=expired), not by silent deletion.
111
+ */
112
+ consumePendingProposals(userId: string, opts?: {
113
+ now?: number;
114
+ ttlMs?: number;
115
+ maxCommitsPerPass?: number;
116
+ }): Promise<{
117
+ committed: number;
118
+ merged: number;
119
+ expiredIds: string[];
120
+ pendingLeft: number;
121
+ }>;
122
+ /** Proposals for the memory candidate surface: pending (default) or the
123
+ * read-only expired history. Other statuses stay internal. */
124
+ listPendingProposals(userId: string, limit?: number, status?: "pending" | "expired"): MemoryProposalRecord[];
125
+ /** Resolve one pending proposal from the UI: confirm -> commit now; dismiss -> rejected. */
126
+ resolveProposal(userId: string, proposalId: string, action: "confirm" | "dismiss"): Promise<boolean>;
77
127
  listClaims(userId: string): MemoryClaimRecord[];
78
128
  listConflicts(userId: string): MemoryConflictRecord[];
79
129
  /**
@@ -95,13 +145,16 @@ export declare class LocalMemoryProvider implements MemoryProvider {
95
145
  * Trigger memory decay - multi-strategy (temporal + staleness + noise).
96
146
  * Also enforces capacity limit and runs vacuum for space reclamation.
97
147
  */
98
- triggerDecay(userId: string, _maxAgeDays?: number): Promise<{
148
+ triggerDecay(userId: string): Promise<{
99
149
  decayed: number;
100
150
  }>;
101
151
  /**
102
152
  * Apply feedback to a memory (useful/irrelevant/outdated/wrong).
103
153
  * Adjusts importance or archives/deletes based on signal.
104
154
  */
155
+ /** V3 promote/demote: archive(技能接棒,记忆退役)与 unarchive(降格回归)成对。
156
+ * claims 状态随动,防 archived 记忆的 claim 继续参与冲突/召回。 */
157
+ setMemoryArchived(memoryId: string, archived: boolean): boolean;
105
158
  feedback(memoryIds: string[], signal: "useful" | "irrelevant" | "outdated" | "wrong"): Promise<{
106
159
  affected: number;
107
160
  }>;
@@ -230,7 +283,8 @@ export declare class LocalMemoryProvider implements MemoryProvider {
230
283
  metadata?: Record<string, unknown>;
231
284
  }>;
232
285
  /**
233
- * Health check - always healthy for local store.
286
+ * Health check a real probe, not a constant: reports the actual active row
287
+ * count and turns DB access errors into status "error" instead of "healthy".
234
288
  */
235
289
  health(): Promise<{
236
290
  status: string;
@@ -242,7 +296,15 @@ export declare class LocalMemoryProvider implements MemoryProvider {
242
296
  */
243
297
  count(userId: string): number;
244
298
  /**
245
- * Reset all memories for a user.
299
+ * Reset ALL long-term memory state for a user: every SQLite table (memories,
300
+ * observations, proposals, claims, conflicts, attachments index, profile KV),
301
+ * the attachment files on disk, and the task-distillation working stores
302
+ * (candidate prompts are stored in clear text — they are memory-domain data
303
+ * and must not survive a "clear my memory"). promotion-proposals.json is
304
+ * deliberately KEPT: it is the audit trail of the user's own promote/demote
305
+ * decisions and the demote map for already-created skills.
306
+ *
307
+ * Returns the number of memory rows removed (wire-compat with the old shape).
246
308
  */
247
309
  resetUser(userId: string): Promise<number>;
248
310
  /**
@@ -38,6 +38,9 @@ export interface MemoryInsertInput {
38
38
  eventDate?: string;
39
39
  tags?: string[];
40
40
  embedding?: Float32Array;
41
+ /** Provenance of `embedding` (model id). Vectors from different models are not
42
+ * comparable; search skips rows whose model/dims mismatch the query's. */
43
+ embeddingModel?: string;
41
44
  }
42
45
  export interface MemoryUpdateInput {
43
46
  text?: string;
@@ -47,6 +50,8 @@ export interface MemoryUpdateInput {
47
50
  eventDate?: string;
48
51
  tags?: string[];
49
52
  embedding?: Float32Array | null;
53
+ /** Provenance of the replacement embedding (see MemoryInsertInput). */
54
+ embeddingModel?: string;
50
55
  }
51
56
  export interface MemorySearchHit {
52
57
  id: string;
@@ -97,7 +102,7 @@ export interface MemoryAtlasResult {
97
102
  }
98
103
  export type MemorySourceKind = "manual" | "explicit" | "document" | "image" | "video" | "auto" | "turn" | "dream" | "agent" | "feedback";
99
104
  export type MemoryClaimStatus = "active" | "superseded" | "conflicted" | "archived" | "pending_confirmation";
100
- export type MemoryProposalStatus = "pending" | "accepted" | "merged" | "conflicted" | "rejected";
105
+ export type MemoryProposalStatus = "pending" | "accepted" | "merged" | "conflicted" | "rejected" | "expired";
101
106
  export interface MemoryObservationInput {
102
107
  userId: string;
103
108
  text: string;
@@ -12,7 +12,7 @@
12
12
  * - memories_fts: FTS5 full-text index for keyword search
13
13
  * - profiles: user profile KV (future)
14
14
  */
15
- import type { MemoryAtlasResult, MemoryClaimInput, MemoryClaimRecord, MemoryClaimStatus, MemoryConflictRecord, MemoryInsertInput, MemoryObservationInput, MemoryProposalInput, MemoryProposalStatus, MemoryRecord, MemorySearchHit, MemoryUpdateInput, SqliteDatabase } from "./local-store-records.js";
15
+ import type { MemoryAtlasResult, MemoryClaimInput, MemoryClaimRecord, MemoryClaimStatus, MemoryConflictRecord, MemoryInsertInput, MemoryObservationInput, MemoryProposalInput, MemoryProposalRecord, MemoryProposalStatus, MemoryRecord, MemorySearchHit, MemoryUpdateInput, SqliteDatabase } from "./local-store-records.js";
16
16
  export { resolveMemoryDbPath } from "./memory-db-path.js";
17
17
  export type { MemoryAtlasBucket, MemoryAtlasCluster, MemoryAtlasResult, MemoryAtlasWindowCursor, MemoryAttachmentRef, MemoryClaimInput, MemoryClaimRecord, MemoryClaimStatus, MemoryConflictRecord, MemoryInsertInput, MemoryObservationInput, MemoryObservationRecord, MemoryProposalInput, MemoryProposalRecord, MemoryProposalStatus, MemoryRecord, MemorySearchHit, MemorySourceKind, MemoryUpdateInput, SqliteDatabase, SqliteStatement, } from "./local-store-records.js";
18
18
  /** Full attachment index row (DB-backed; file bytes live on disk under the attachments dir). */
@@ -41,7 +41,11 @@ export interface MemoryAttachmentInsert {
41
41
  }
42
42
  export declare class LocalMemoryStore {
43
43
  private db;
44
+ /** Stamped onto rows whose embedding arrives without explicit provenance
45
+ * (the consolidation pipeline passes bare vectors). Set by the provider. */
46
+ private defaultEmbeddingModel;
44
47
  constructor(db: SqliteDatabase);
48
+ setDefaultEmbeddingModel(model: string): void;
45
49
  private initSchema;
46
50
  /**
47
51
  * Insert a new memory record. Returns the generated ID.
@@ -51,15 +55,23 @@ export declare class LocalMemoryStore {
51
55
  * Full-text search using FTS5. Returns ranked results.
52
56
  */
53
57
  searchFts(query: string, userId: string, limit?: number): MemorySearchHit[];
58
+ /** One-shot flag: embedding provenance mismatches are traced once per store instance. */
59
+ private embeddingMismatchLogged;
54
60
  /**
55
61
  * Vector similarity search using pre-computed embeddings.
56
62
  * Performs brute-force cosine similarity (efficient for <100k records per user).
63
+ *
64
+ * Rows whose embedding provenance (dims, and model when both sides are known)
65
+ * differs from the query's are SKIPPED, not scored: cosine between vectors of
66
+ * different models/dims is numeric noise, and truncated dot products silently
67
+ * corrupt ranking. Legacy rows (no provenance columns) are accepted when their
68
+ * dimension happens to match — dropping them all would blank historical recall.
57
69
  */
58
- searchVector(queryEmbedding: Float32Array, userId: string, limit?: number, minScore?: number): MemorySearchHit[];
70
+ searchVector(queryEmbedding: Float32Array, userId: string, limit?: number, minScore?: number, expectedModel?: string): MemorySearchHit[];
59
71
  /**
60
72
  * Hybrid search: FTS5 + vector similarity, de-duplicated and merged.
61
73
  */
62
- searchHybrid(query: string, queryEmbedding: Float32Array | null, userId: string, limit?: number): MemorySearchHit[];
74
+ searchHybrid(query: string, queryEmbedding: Float32Array | null, userId: string, limit?: number, expectedModel?: string): MemorySearchHit[];
63
75
  /**
64
76
  * Get all memories for a user (paginated).
65
77
  */
@@ -89,7 +101,7 @@ export declare class LocalMemoryStore {
89
101
  /**
90
102
  * Update memory text and bump updatedAt.
91
103
  */
92
- updateText(id: string, text: string, embedding?: Float32Array): boolean;
104
+ updateText(id: string, text: string, embedding?: Float32Array, embeddingModel?: string): boolean;
93
105
  /**
94
106
  * Update editable memory fields and bump updatedAt.
95
107
  */
@@ -103,6 +115,8 @@ export declare class LocalMemoryStore {
103
115
  * Used by dedup gate when a similar but newer memory supersedes an older one.
104
116
  */
105
117
  archive(id: string): boolean;
118
+ /** V3 demote(降格)恢复:archived procedure 回归召回池,与 archive 成对。 */
119
+ unarchive(id: string): boolean;
106
120
  /**
107
121
  * Temporal expiry: archive event/plan memories whose event_date has passed
108
122
  * beyond a grace period (e.g., "meeting tomorrow" 3 days after it happened).
@@ -118,6 +132,15 @@ export declare class LocalMemoryStore {
118
132
  * Memories written by the agent but never recalled are likely noise.
119
133
  */
120
134
  decayNoiseArchival(userId: string, minAgeDays?: number, maxImportance?: number): number;
135
+ /**
136
+ * Observation retention: memory_observations is an append-only audit trail
137
+ * (every propose/commit writes one) with NO reader of its own — without a
138
+ * retention window it grows forever, the same disease the proposals table
139
+ * had before the consumer existed. Delete rows older than the window that
140
+ * are NOT referenced by any claim's evidence_ids or proposal's
141
+ * observation_ids (referenced rows are live audit evidence and stay).
142
+ */
143
+ decayObservations(userId: string, retentionDays?: number): number;
121
144
  /**
122
145
  * Run all decay strategies. Returns total affected count.
123
146
  */
@@ -203,14 +226,30 @@ export declare class LocalMemoryStore {
203
226
  * Record an access (for importance/relevance boosting).
204
227
  */
205
228
  recordAccess(id: string): void;
229
+ /** Total active memory rows across ALL users (health reporting). */
230
+ countAll(): number;
206
231
  /**
207
232
  * Get total memory count for a user.
208
233
  */
209
234
  count(userId: string, activeOnly?: boolean): number;
210
235
  /**
211
- * Delete all memories for a user.
212
- */
213
- resetUser(userId: string): number;
236
+ * Delete ALL long-term memory state for a user — every table, not just
237
+ * `memories`. Claims carry entity/predicate/value facts in clear text and
238
+ * observations carry raw conversation excerpts; leaving them behind after a
239
+ * "clear my memory" is a broken privacy promise, not a smaller reset.
240
+ *
241
+ * Returns the attachment rel_paths so the caller can delete the on-disk
242
+ * files (the store only owns the index rows).
243
+ */
244
+ resetUser(userId: string): {
245
+ memories: number;
246
+ observations: number;
247
+ proposals: number;
248
+ claims: number;
249
+ conflicts: number;
250
+ profiles: number;
251
+ attachmentRelPaths: string[];
252
+ };
214
253
  /**
215
254
  * Run SQLite VACUUM to reclaim space after deletions/archival.
216
255
  * Should be called periodically (e.g. after decay cycles).
@@ -226,10 +265,13 @@ export declare class LocalMemoryStore {
226
265
  freePages: number;
227
266
  };
228
267
  /**
229
- * Export archived memories as JSONL (for cold storage / backup).
230
- * Deletes exported records from the database to reclaim space.
268
+ * List the oldest archived memories for cold-storage export. Read-only:
269
+ * purging is a SEPARATE step (purgeMemoriesByIds) the caller performs only
270
+ * after the export has durably landed on disk. The old fused
271
+ * export-then-delete shape destroyed data whenever the caller dropped the
272
+ * return value.
231
273
  */
232
- exportAndPurgeArchived(userId: string, maxExport?: number): Array<{
274
+ listArchivedForExport(userId: string, maxExport?: number): Array<{
233
275
  id: string;
234
276
  text: string;
235
277
  category: string;
@@ -238,6 +280,8 @@ export declare class LocalMemoryStore {
238
280
  archivedAt: number;
239
281
  tags: string[];
240
282
  }>;
283
+ /** Physically delete memory rows by id (post-export purge step). */
284
+ purgeMemoriesByIds(ids: string[]): number;
241
285
  /**
242
286
  * Enforce capacity limit: if active memories exceed maxCount,
243
287
  * archive the oldest lowest-importance ones.
@@ -251,6 +295,15 @@ export declare class LocalMemoryStore {
251
295
  * a duplicate crash-safely (the key survives a worker restart mid-sweep).
252
296
  */
253
297
  findProposalByIdempotencyKey(userId: string, idempotencyKey: string): string | null;
298
+ /**
299
+ * List proposals by status (oldest first) — the read side of the proposal
300
+ * consumer. Pending proposals from implicit-extract / feedback / dream used
301
+ * to have NO reader at all: they accumulated forever and never became
302
+ * searchable memories.
303
+ */
304
+ listProposalsByStatus(userId: string, status: MemoryProposalStatus, limit?: number): MemoryProposalRecord[];
305
+ /** Bulk status transition for the proposal consumer (corroborated / expired). */
306
+ markProposalsStatus(ids: string[], status: MemoryProposalStatus): number;
254
307
  updateProposalStatus(id: string, status: MemoryProposalStatus, relatedClaimIds?: string[]): boolean;
255
308
  insertClaim(input: MemoryClaimInput): string;
256
309
  listClaims(userId: string, statuses?: MemoryClaimStatus[]): MemoryClaimRecord[];
@@ -1,4 +1,4 @@
1
- /** Max bytes (UTF-8) for INDEX.md to inject into system prompt (CC uses 25KB, we use 12KB). */
1
+ /** Max bytes (UTF-8) for INDEX.md to inject into system prompt. */
2
2
  export declare const INDEX_MAX_CHARS = 12288;
3
3
  /** Max lines for INDEX.md injection. */
4
4
  export declare const INDEX_MAX_LINES = 200;
@@ -8,6 +8,14 @@ export declare const TOPIC_FILE_MAX_CHARS = 8192;
8
8
  export declare function getMemdirPath(projectRoot: string): string;
9
9
  /** Full path to INDEX.md */
10
10
  export declare function getIndexPath(projectRoot: string): string;
11
+ /** Global-layer size budget: a cheat-sheet, not a memory store. */
12
+ export declare const USER_INDEX_MAX_CHARS = 2048;
13
+ export declare const USER_INDEX_MAX_LINES = 40;
14
+ /** Full path to the user-level global INDEX.md (owner profile scoped). */
15
+ export declare function getUserIndexPath(): string;
16
+ /** Read the global layer for prompt injection, capped by the cheat-sheet budget.
17
+ * Returns null when absent/empty — the section simply doesn't render. */
18
+ export declare function readUserIndexForPrompt(): string | null;
11
19
  export interface MemdirFileInfo {
12
20
  name: string;
13
21
  /** Size in bytes */
@@ -25,10 +33,9 @@ export interface MemdirResult {
25
33
  /** Current INDEX.md char usage */
26
34
  indexUsage?: string;
27
35
  }
28
- export declare function isMemoryContentSafe(text: string): boolean;
36
+ export { isMemoryContentSafe } from "./memory-tool.js";
29
37
  export declare class Memdir {
30
38
  private readonly root;
31
- private indexCache;
32
39
  constructor(projectRoot: string);
33
40
  /** Get the root directory path of this MEMDIR. */
34
41
  getRootPath(): string;
@@ -89,6 +96,12 @@ export declare class Memdir {
89
96
  private writeIndex;
90
97
  private writeIndexUnlocked;
91
98
  private ensureDir;
92
- /** Append an entry to the file listing section of INDEX.md (idempotent). */
99
+ /**
100
+ * Append an entry to the file listing section of INDEX.md (idempotent).
101
+ * Returns whether the entry is present afterwards. On overflow it first
102
+ * tries the same auto-compaction as addToIndex; a false return means the
103
+ * file exists but is INVISIBLE to recall — callers must surface that
104
+ * (the old behavior skipped silently and quietly orphaned topic files).
105
+ */
93
106
  private appendIndexEntry;
94
107
  }
@@ -54,4 +54,11 @@ export declare class MemoryConsolidator {
54
54
  */
55
55
  private findNearDuplicateMemory;
56
56
  }
57
+ /** Containment threshold above which two texts count as the same memory.
58
+ * Exported: the proposal consumer uses the SAME bar to group same-fact proposals. */
59
+ export declare const NEAR_DUPLICATE_CONTAINMENT = 0.82;
60
+ /** Latin/digit words plus CJK character bigrams from normalized text. */
61
+ export declare function dedupTokens(text: string): Set<string>;
62
+ /** True when either side has a digit-bearing token the other side lacks. */
63
+ export declare function digitTokensDiffer(a: Set<string>, b: Set<string>): boolean;
57
64
  export declare function sourcePriorityOf(source: string): number;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Proposal consumer (P0 — the factual-memory half of the promotion ladder).
3
+ *
4
+ * implicit-extract / feedback-distillation / dream all write PROPOSALS
5
+ * (status=pending). Before this module existed nothing ever read them back:
6
+ * the three automatic learning paths burned model calls writing dead rows.
7
+ *
8
+ * Trust ladder — evidence gates autonomy, mirroring the V3 skill-promotion
9
+ * doctrine (automatic only when the data says so; visible; revertible):
10
+ * - CORROBORATED: the same fact proposed >=2 times from independent
11
+ * contexts (different session, or different source) -> auto-commit as
12
+ * source "corroborated" (priority 70, so it actually becomes an active
13
+ * searchable memory — committing with the original implicit-extract
14
+ * priority 40 would just create another pending claim, i.e. the black
15
+ * hole one level deeper).
16
+ * - feedback-distillation proposals commit ALONE: their >=2-evidence bar
17
+ * was already enforced upstream (MIN_EVIDENCE + idempotency key, §10).
18
+ * - dream-tier sources (priority <= 20) never commit alone; they only
19
+ * corroborate facts seen elsewhere.
20
+ * - Everything else waits, and past the TTL flips to status "expired" —
21
+ * a visible terminal state, not a silent delete; the memory surface can
22
+ * still show expired proposals for manual rescue.
23
+ *
24
+ * Pure planning logic — no I/O; the provider executes the plan.
25
+ */
26
+ import type { MemoryProposalRecord } from "./local-store-records.js";
27
+ import type { ExtractedMemoryItem } from "./memory-consolidation.js";
28
+ /** Uncorroborated proposals older than this flip to "expired". */
29
+ export declare const PROPOSAL_TTL_MS: number;
30
+ /** Independent contexts required for auto-commit. */
31
+ export declare const PROPOSAL_MIN_CORROBORATION = 2;
32
+ /** Idle-pass work cap; the rest stays pending for the next pass. */
33
+ export declare const PROPOSAL_MAX_COMMITS_PER_PASS = 20;
34
+ /** Source stamped on corroborated commits — registered in sourcePriorityOf. */
35
+ export declare const CORROBORATED_SOURCE = "corroborated";
36
+ export interface ProposalCommitGroup {
37
+ proposalIds: string[];
38
+ item: ExtractedMemoryItem;
39
+ /** Source used for the commit (drives claim authority). */
40
+ source: string;
41
+ }
42
+ export interface ProposalConsumptionSummary {
43
+ commitGroups: ProposalCommitGroup[];
44
+ expiredIds: string[];
45
+ }
46
+ export interface ProposalConsumptionOptions {
47
+ now?: number;
48
+ ttlMs?: number;
49
+ maxCommitsPerPass?: number;
50
+ }
51
+ export declare function planProposalConsumption(pending: readonly MemoryProposalRecord[], opts?: ProposalConsumptionOptions): ProposalConsumptionSummary;
@@ -1,6 +1,7 @@
1
- import type { MemoryClaimRecord, MemoryConflictRecord, MemoryRecord } from "./local-store-records.js";
1
+ import type { MemoryClaimRecord, MemoryConflictRecord, MemoryProposalRecord, MemoryRecord } from "./local-store-records.js";
2
2
  export declare function rowToRecord(row: unknown): MemoryRecord;
3
3
  export declare function rowToClaimRecord(row: unknown): MemoryClaimRecord;
4
+ export declare function rowToProposalRecord(row: unknown): MemoryProposalRecord;
4
5
  export declare function rowToConflictRecord(row: unknown): MemoryConflictRecord;
5
6
  export declare function parseJsonObject(raw: unknown): Record<string, unknown>;
6
7
  export declare function parseJsonArray(raw: unknown): string[];