opencode-swarm 7.88.2 → 7.88.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.
- package/.opencode/skills/phase-wrap/SKILL.md +23 -6
- package/.opencode/skills/swarm-pr-feedback/SKILL.md +32 -8
- package/dist/agents/agent-output-schema.d.ts +1 -1
- package/dist/agents/curator-agent.d.ts +1 -1
- package/dist/agents/explorer.d.ts +1 -0
- package/dist/cli/{config-doctor-jzbgpbdh.js → config-doctor-g04wdz19.js} +2 -2
- package/dist/cli/{explorer-gz70sm9b.js → explorer-h2fnj343.js} +4 -2
- package/dist/cli/{guardrail-explain-qd243wrm.js → guardrail-explain-xe0wjnxz.js} +7 -7
- package/dist/cli/{guardrail-log-c7egm5km.js → guardrail-log-m3285thy.js} +3 -3
- package/dist/cli/{index-0asbrmdx.js → index-123s7kjc.js} +88 -2
- package/dist/cli/{index-tjr1m8wf.js → index-5p1gvn98.js} +8 -8
- package/dist/cli/{index-g00qm2gf.js → index-6tnmt41c.js} +1 -1
- package/dist/cli/{index-yhsmmv2z.js → index-bm4f0nme.js} +25 -1
- package/dist/cli/{index-819xp49y.js → index-bywt2171.js} +1 -1
- package/dist/cli/{index-09smngfp.js → index-d4hpgf63.js} +2 -2
- package/dist/cli/{index-vjsr9bqt.js → index-gg589mfw.js} +1 -1
- package/dist/cli/{index-y72bw1wb.js → index-hs2knbfq.js} +520 -375
- package/dist/cli/{index-32axfg6h.js → index-rh53rrpt.js} +82 -12
- package/dist/cli/index.js +6 -6
- package/dist/cli/{schema-vb6jkxgg.js → schema-t9th7frq.js} +1 -1
- package/dist/cli/{skill-generator-kz4q8e49.js → skill-generator-s0spm65v.js} +1 -1
- package/dist/commands/memory.d.ts +1 -0
- package/dist/commands/registry.d.ts +8 -0
- package/dist/config/agent-names.d.ts +2 -2
- package/dist/config/schema.d.ts +60 -0
- package/dist/hooks/curator-llm-factory.d.ts +1 -1
- package/dist/index.js +1971 -1077
- package/dist/memory/config.d.ts +35 -0
- package/dist/memory/consolidation-log.d.ts +29 -0
- package/dist/memory/consolidation.d.ts +124 -0
- package/dist/memory/decay.d.ts +24 -0
- package/dist/memory/gateway.d.ts +14 -2
- package/dist/memory/maintenance.d.ts +18 -0
- package/dist/memory/run-log.d.ts +8 -1
- package/dist/memory/schema.d.ts +3 -3
- package/dist/memory/scoring.d.ts +45 -0
- package/dist/memory/sentinel.d.ts +15 -0
- package/dist/services/memory-consolidation.d.ts +32 -0
- package/dist/services/skill-generator.d.ts +8 -1
- package/dist/state.d.ts +4 -2
- package/package.json +1 -1
package/dist/memory/config.d.ts
CHANGED
|
@@ -26,12 +26,47 @@ export interface MemoryConfig {
|
|
|
26
26
|
rejectDurableSecrets: boolean;
|
|
27
27
|
};
|
|
28
28
|
maintenance: {
|
|
29
|
+
/** @deprecated superseded by `maintenance.importance` (issue #1464); retained for back-compat. */
|
|
29
30
|
lowUtilityMaxConfidence: number;
|
|
31
|
+
/** @deprecated superseded by `maintenance.importance` (issue #1464); retained for back-compat. */
|
|
30
32
|
lowUtilityMinAgeDays: number;
|
|
31
33
|
autoCompactEveryNRecalls?: number;
|
|
34
|
+
/** Importance-formula weights + low-utility threshold (DD-11). */
|
|
35
|
+
importance: ImportanceConfig;
|
|
32
36
|
};
|
|
37
|
+
/** Reflection / consolidation pass (issue #1464, Phase 3). */
|
|
38
|
+
consolidation: ConsolidationConfig;
|
|
33
39
|
hardDelete: boolean;
|
|
34
40
|
}
|
|
41
|
+
export interface ImportanceConfig {
|
|
42
|
+
wRecency: number;
|
|
43
|
+
wFrequency: number;
|
|
44
|
+
wFreshness: number;
|
|
45
|
+
wConfidence: number;
|
|
46
|
+
lambda: number;
|
|
47
|
+
mu: number;
|
|
48
|
+
n: number;
|
|
49
|
+
/** A memory is low-utility when importance < threshold. */
|
|
50
|
+
threshold: number;
|
|
51
|
+
}
|
|
52
|
+
export interface ConsolidationConfig {
|
|
53
|
+
/** Run episodic→semantic consolidation at phase_complete. Gated by `enabled` too. */
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
/** Max LLM-distilled clusters processed per pass (cost control). */
|
|
56
|
+
maxClustersPerPass: number;
|
|
57
|
+
/** Jaccard token-overlap threshold for lexical clustering. */
|
|
58
|
+
jaccardThreshold: number;
|
|
59
|
+
/** Distilled facts below this confidence are filed as proposals, not auto-applied. */
|
|
60
|
+
autoApplyMinConfidence: number;
|
|
61
|
+
/**
|
|
62
|
+
* Kind-specific decay half-lives in days. A value of 0 means "never auto-expire"
|
|
63
|
+
* (the issue's "365+ days, no decay unless superseded" durable kinds).
|
|
64
|
+
*/
|
|
65
|
+
decayHalfLifeDays: Record<MemoryKind, number>;
|
|
66
|
+
}
|
|
67
|
+
export declare const DEFAULT_DECAY_HALF_LIFE_DAYS: Record<MemoryKind, number>;
|
|
68
|
+
export declare const DEFAULT_IMPORTANCE_CONFIG: ImportanceConfig;
|
|
69
|
+
export declare const DEFAULT_CONSOLIDATION_CONFIG: ConsolidationConfig;
|
|
35
70
|
export declare const DEFAULT_MEMORY_CONFIG: MemoryConfig;
|
|
36
71
|
export declare const DURABLE_MEMORY_KINDS: ReadonlySet<MemoryKind>;
|
|
37
72
|
export declare const EVIDENCE_REQUIRED_KINDS: ReadonlySet<MemoryKind>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable, append-only record of a completed consolidation pass. Persisted to
|
|
3
|
+
* `.swarm/memory/consolidation-log.jsonl` (invariant #4: runtime state stays
|
|
4
|
+
* under `.swarm/`). Serves two purposes:
|
|
5
|
+
* - idempotency: a pass for a `phaseNumber` already present here is a no-op;
|
|
6
|
+
* - observability: the `/swarm memory consolidation-log` CLI reads it.
|
|
7
|
+
*/
|
|
8
|
+
export interface ConsolidationLogRecord {
|
|
9
|
+
phaseNumber: number;
|
|
10
|
+
/** Session/run that produced this pass, for multi-session observability.
|
|
11
|
+
* Idempotency remains keyed on phaseNumber (the memory store is per
|
|
12
|
+
* directory), so this is informational only. */
|
|
13
|
+
runId?: string;
|
|
14
|
+
startedAt: string;
|
|
15
|
+
completedAt: string;
|
|
16
|
+
clusterCount: number;
|
|
17
|
+
clustersDeferred: number;
|
|
18
|
+
decisionsEmitted: number;
|
|
19
|
+
added: number;
|
|
20
|
+
superseded: number;
|
|
21
|
+
contradictionsDetected: number;
|
|
22
|
+
deduped: number;
|
|
23
|
+
proposed: number;
|
|
24
|
+
memoriesDecayed: number;
|
|
25
|
+
errored: number;
|
|
26
|
+
processedProposalIds: string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function readConsolidationLog(directory: string): Promise<ConsolidationLogRecord[]>;
|
|
29
|
+
export declare function appendConsolidationLog(directory: string, record: ConsolidationLogRecord): Promise<void>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type MemoryConfig } from './config';
|
|
3
|
+
import type { ConsolidationLogRecord } from './consolidation-log';
|
|
4
|
+
import type { ProposeMemoryInput } from './gateway';
|
|
5
|
+
import type { MemoryRunLogEvent } from './run-log';
|
|
6
|
+
import type { AppliedMemoryChange, CuratorMemoryDecision, MemoryListFilter, MemoryProposal, MemoryRecord } from './types';
|
|
7
|
+
/** Agent role stamped on consolidation-emitted proposals (used to exclude them
|
|
8
|
+
* from the engine's own episodic input — see reviewer finding #3). The
|
|
9
|
+
* fire-and-forget wrapper sets this as the gateway context's agentRole. */
|
|
10
|
+
export declare const CONSOLIDATION_AGENT_ROLE = "curator_consolidation";
|
|
11
|
+
/** Narrow gateway surface the engine depends on (MemoryGateway satisfies it). */
|
|
12
|
+
export interface ConsolidationGateway {
|
|
13
|
+
isEnabled(): boolean;
|
|
14
|
+
listProposals(filter?: {
|
|
15
|
+
status?: MemoryProposal['status'];
|
|
16
|
+
limit?: number;
|
|
17
|
+
}): Promise<MemoryProposal[]>;
|
|
18
|
+
listMemories(filter?: MemoryListFilter): Promise<MemoryRecord[]>;
|
|
19
|
+
propose(input: ProposeMemoryInput): Promise<MemoryProposal>;
|
|
20
|
+
applyCuratorDecision(decision: CuratorMemoryDecision): Promise<AppliedMemoryChange>;
|
|
21
|
+
upsertCurated(record: MemoryRecord): Promise<MemoryRecord>;
|
|
22
|
+
}
|
|
23
|
+
export type DistillLLMDelegate = (systemPrompt: string, userInput: string, signal?: AbortSignal) => Promise<string>;
|
|
24
|
+
export interface ConsolidationDeps {
|
|
25
|
+
gateway: ConsolidationGateway;
|
|
26
|
+
llmDelegate?: DistillLLMDelegate;
|
|
27
|
+
now: () => Date;
|
|
28
|
+
logEvent: (event: MemoryRunLogEvent) => Promise<void>;
|
|
29
|
+
readLog: () => Promise<ConsolidationLogRecord[]>;
|
|
30
|
+
appendLog: (record: ConsolidationLogRecord) => Promise<void>;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
export interface ConsolidationInput {
|
|
34
|
+
directory: string;
|
|
35
|
+
phaseNumber: number;
|
|
36
|
+
runId?: string;
|
|
37
|
+
config: MemoryConfig;
|
|
38
|
+
}
|
|
39
|
+
export interface ConsolidationResult {
|
|
40
|
+
skipped: boolean;
|
|
41
|
+
skipReason?: 'disabled' | 'already_consolidated' | 'no_llm_delegate_decay_only' | 'aborted';
|
|
42
|
+
phaseNumber: number;
|
|
43
|
+
clusterCount: number;
|
|
44
|
+
clustersDeferred: number;
|
|
45
|
+
decisionsEmitted: number;
|
|
46
|
+
added: number;
|
|
47
|
+
superseded: number;
|
|
48
|
+
contradictionsDetected: number;
|
|
49
|
+
deduped: number;
|
|
50
|
+
proposed: number;
|
|
51
|
+
memoriesDecayed: number;
|
|
52
|
+
errored: number;
|
|
53
|
+
}
|
|
54
|
+
declare const DistilledFactSchema: z.ZodObject<{
|
|
55
|
+
text: z.ZodString;
|
|
56
|
+
kind: z.ZodEnum<{
|
|
57
|
+
evidence: "evidence";
|
|
58
|
+
user_preference: "user_preference";
|
|
59
|
+
project_fact: "project_fact";
|
|
60
|
+
architecture_decision: "architecture_decision";
|
|
61
|
+
repo_convention: "repo_convention";
|
|
62
|
+
api_finding: "api_finding";
|
|
63
|
+
code_pattern: "code_pattern";
|
|
64
|
+
test_pattern: "test_pattern";
|
|
65
|
+
failure_pattern: "failure_pattern";
|
|
66
|
+
security_note: "security_note";
|
|
67
|
+
todo: "todo";
|
|
68
|
+
scratch: "scratch";
|
|
69
|
+
}>;
|
|
70
|
+
confidence: z.ZodNumber;
|
|
71
|
+
contradictsMemoryId: z.ZodOptional<z.ZodString>;
|
|
72
|
+
}, z.core.$strip>;
|
|
73
|
+
export type DistilledFact = z.infer<typeof DistilledFactSchema>;
|
|
74
|
+
/**
|
|
75
|
+
* Parse the curator LLM's distillation output. Tolerant of ```json fences and
|
|
76
|
+
* surrounding prose. Returns [] on any parse/validation failure (caller counts
|
|
77
|
+
* the cluster as skipped rather than aborting the pass).
|
|
78
|
+
*/
|
|
79
|
+
export declare function parseDistillationOutput(raw: string): DistilledFact[];
|
|
80
|
+
export type DecisionPlan = {
|
|
81
|
+
type: 'add';
|
|
82
|
+
fact: DistilledFact;
|
|
83
|
+
} | {
|
|
84
|
+
type: 'supersede';
|
|
85
|
+
fact: DistilledFact;
|
|
86
|
+
oldMemoryId: string;
|
|
87
|
+
} | {
|
|
88
|
+
type: 'proposal';
|
|
89
|
+
fact: DistilledFact;
|
|
90
|
+
reason: string;
|
|
91
|
+
} | {
|
|
92
|
+
type: 'dedup';
|
|
93
|
+
fact: DistilledFact;
|
|
94
|
+
duplicateOf: string;
|
|
95
|
+
} | {
|
|
96
|
+
type: 'skip';
|
|
97
|
+
fact: DistilledFact;
|
|
98
|
+
reason: string;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Pure decision derivation for a single distilled fact against existing items.
|
|
102
|
+
* Encapsulates the auto-apply eligibility rules so they are unit-testable
|
|
103
|
+
* without a gateway:
|
|
104
|
+
* - sentinel-bearing text is skipped (defense in depth; the write guard also
|
|
105
|
+
* rejects it);
|
|
106
|
+
* - `scratch` is never promoted to semantic memory;
|
|
107
|
+
* - only DURABLE_MEMORY_KINDS, ≤500-char, ≥autoApplyMinConfidence facts are
|
|
108
|
+
* auto-applied; everything else is filed as a pending proposal;
|
|
109
|
+
* - a contradiction (explicit `contradictsMemoryId` that resolves to an
|
|
110
|
+
* existing active memory) becomes a supersede;
|
|
111
|
+
* - a near-duplicate (Jaccard ≥ threshold) becomes a no-op dedup.
|
|
112
|
+
*/
|
|
113
|
+
export declare function deriveDecision(fact: DistilledFact, existing: MemoryRecord[], options: {
|
|
114
|
+
autoApplyMinConfidence: number;
|
|
115
|
+
jaccardThreshold: number;
|
|
116
|
+
}): DecisionPlan;
|
|
117
|
+
/**
|
|
118
|
+
* Run one episodic→semantic consolidation pass for a completed phase.
|
|
119
|
+
* Idempotent per `phaseNumber` (a completed log record short-circuits a rerun).
|
|
120
|
+
* All IO is injected via {@link ConsolidationDeps} so the orchestration is
|
|
121
|
+
* deterministically testable with a fake gateway and fake LLM delegate.
|
|
122
|
+
*/
|
|
123
|
+
export declare function runConsolidationPass(input: ConsolidationInput, deps: ConsolidationDeps): Promise<ConsolidationResult>;
|
|
124
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MemoryKind, MemoryRecord } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Compute the kind-specific decay expiry for a memory (issue #1464).
|
|
4
|
+
*
|
|
5
|
+
* Returns the new `expiresAt` ISO string to apply, or `undefined` when no
|
|
6
|
+
* change should be made. Rules:
|
|
7
|
+
* - `scratch` is never re-decayed here — it already receives a ≤7-day expiry
|
|
8
|
+
* at creation time and is bounded by `validateMemoryRecordRules`.
|
|
9
|
+
* - A half-life of `0` means "never auto-expire" (the durable 365+ kinds).
|
|
10
|
+
* - Decay sets `expiresAt = createdAt + halfLifeDays`, but never SHORTENS an
|
|
11
|
+
* existing earlier expiry (a memory already set to expire sooner keeps that
|
|
12
|
+
* sooner expiry).
|
|
13
|
+
*
|
|
14
|
+
* Pure and deterministic: callers pass the existing record and apply the
|
|
15
|
+
* returned expiry by patching only `expiresAt` (preserving id/hash/timestamps).
|
|
16
|
+
*/
|
|
17
|
+
export declare function computeDecayExpiry(memory: Pick<MemoryRecord, 'kind' | 'createdAt' | 'expiresAt'>, halfLifeDays: Record<MemoryKind, number>, _now?: Date): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Check whether a record's natural half-life date is in the past (i.e., the record
|
|
20
|
+
* is older than its decay horizon). Used to guard against upgrade-time auto-expiry
|
|
21
|
+
* when migrating from pre-decay code: a record written under a previous config
|
|
22
|
+
* without decay should not be silently expired on the first consolidation pass.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isPastDecayHorizon(memory: Pick<MemoryRecord, 'kind' | 'createdAt'>, halfLifeDays: Record<MemoryKind, number>, now?: Date): boolean;
|
package/dist/memory/gateway.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type MemoryConfig } from './config';
|
|
2
|
-
import type { MemoryProposalStore, MemoryProvider } from './provider';
|
|
3
|
-
import type { AppliedMemoryChange, CuratorMemoryDecision, MemoryContext, MemoryKind, MemoryProposal, MemoryRecord, MemoryScopeRef, MemorySource, RecallBundle, RecallMode } from './types';
|
|
2
|
+
import type { MemoryProposalStore, MemoryProvider, MemoryRecallUsageEvent, MemoryRecallUsageFilter } from './provider';
|
|
3
|
+
import type { AppliedMemoryChange, CuratorMemoryDecision, MemoryContext, MemoryKind, MemoryListFilter, MemoryProposal, MemoryRecord, MemoryScopeRef, MemorySource, RecallBundle, RecallMode } from './types';
|
|
4
4
|
export interface MemoryGatewayOptions {
|
|
5
5
|
config?: Partial<MemoryConfig>;
|
|
6
6
|
provider?: MemoryProvider & Partial<MemoryProposalStore>;
|
|
@@ -39,6 +39,18 @@ export declare class MemoryGateway {
|
|
|
39
39
|
deriveAllowedScopes(): MemoryScopeRef[];
|
|
40
40
|
recall(input: RecallMemoryInput): Promise<RecallBundle>;
|
|
41
41
|
propose(input: ProposeMemoryInput): Promise<MemoryProposal>;
|
|
42
|
+
/**
|
|
43
|
+
* Read-only passthroughs used by the consolidation engine. They assert the
|
|
44
|
+
* feature is enabled and that the underlying provider supports the
|
|
45
|
+
* capability (mirroring the `createProposal` guard), so the engine can
|
|
46
|
+
* depend on a stable gateway surface rather than the `Partial` provider.
|
|
47
|
+
*/
|
|
48
|
+
listMemories(filter?: MemoryListFilter): Promise<MemoryRecord[]>;
|
|
49
|
+
listProposals(filter?: {
|
|
50
|
+
status?: MemoryProposal['status'];
|
|
51
|
+
limit?: number;
|
|
52
|
+
}): Promise<MemoryProposal[]>;
|
|
53
|
+
listRecallUsage(filter?: MemoryRecallUsageFilter): Promise<MemoryRecallUsageEvent[]>;
|
|
42
54
|
upsertCurated(record: MemoryRecord): Promise<MemoryRecord>;
|
|
43
55
|
applyCuratorDecision(decision: CuratorMemoryDecision): Promise<AppliedMemoryChange>;
|
|
44
56
|
createRecord(input: {
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { MemoryProposalStore, MemoryProvider } from './provider';
|
|
2
|
+
import { type ImportanceWeights } from './scoring';
|
|
2
3
|
import type { MemoryProposal, MemoryRecord } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Default importance-formula weights (issue #1464). Match the zod and runtime
|
|
6
|
+
* config defaults; used when the maintenance report is built without explicit
|
|
7
|
+
* importance options (e.g. legacy callers).
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEFAULT_IMPORTANCE_WEIGHTS: ImportanceWeights;
|
|
10
|
+
/**
|
|
11
|
+
* A never-recalled memory's importance is driven by freshness+confidence
|
|
12
|
+
* (recency/frequency terms are 0). 0.2 keeps high-confidence durable facts
|
|
13
|
+
* above the line regardless of age (the DD-11 fix) while still flagging
|
|
14
|
+
* low-confidence and very stale never-recalled memories. Pinned by tests.
|
|
15
|
+
*/
|
|
16
|
+
export declare const DEFAULT_IMPORTANCE_THRESHOLD = 0.2;
|
|
3
17
|
export interface MemoryRecallUsageByMemory {
|
|
4
18
|
memoryId: string;
|
|
5
19
|
count: number;
|
|
@@ -38,6 +52,10 @@ export interface MemoryMaintenanceReportOptions {
|
|
|
38
52
|
limit?: number;
|
|
39
53
|
lowUtilityMaxConfidence?: number;
|
|
40
54
|
lowUtilityMinAgeDays?: number;
|
|
55
|
+
/** Importance-formula weights (DD-11). Defaults to DEFAULT_IMPORTANCE_WEIGHTS. */
|
|
56
|
+
importanceWeights?: ImportanceWeights;
|
|
57
|
+
/** A memory is low-utility when importance < threshold. Defaults to DEFAULT_IMPORTANCE_THRESHOLD. */
|
|
58
|
+
importanceThreshold?: number;
|
|
41
59
|
}
|
|
42
60
|
type ObservableProvider = MemoryProvider & Partial<MemoryProposalStore> & {
|
|
43
61
|
listRecallUsage?: MemoryProvider['listRecallUsage'];
|
package/dist/memory/run-log.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type MemoryRunLogEventName = 'recall_requested' | 'recall_returned' | 'prompt_injection_skipped' | 'prompt_injected' | 'proposal_created' | 'proposal_rejected_by_validation' | 'curator_decision_applied' | 'curator_decision_rejected_by_validation';
|
|
1
|
+
export type MemoryRunLogEventName = 'recall_requested' | 'recall_returned' | 'prompt_injection_skipped' | 'prompt_injected' | 'proposal_created' | 'proposal_rejected_by_validation' | 'curator_decision_applied' | 'curator_decision_rejected_by_validation' | 'consolidation_started' | 'cluster_count' | 'decisions_emitted' | 'contradictions_detected' | 'memories_decayed' | 'consolidation_completed';
|
|
2
2
|
export interface MemoryRunLogEvent {
|
|
3
3
|
event: MemoryRunLogEventName;
|
|
4
4
|
runId: string;
|
|
@@ -11,6 +11,13 @@ export interface MemoryRunLogEvent {
|
|
|
11
11
|
proposalId?: string;
|
|
12
12
|
rejectionReason?: string;
|
|
13
13
|
timestamp?: string;
|
|
14
|
+
/** Consolidation pass identifier (phase boundary that triggered the pass). */
|
|
15
|
+
phaseNumber?: number;
|
|
16
|
+
/** Consolidation metrics (issue #1464). */
|
|
17
|
+
clusterCount?: number;
|
|
18
|
+
decisionsEmitted?: number;
|
|
19
|
+
contradictionsDetected?: number;
|
|
20
|
+
memoriesDecayed?: number;
|
|
14
21
|
metadata?: Record<string, unknown>;
|
|
15
22
|
}
|
|
16
23
|
export declare function appendMemoryRunLog(directory: string, runId: string | undefined, event: MemoryRunLogEvent): Promise<void>;
|
package/dist/memory/schema.d.ts
CHANGED
|
@@ -27,7 +27,6 @@ export declare const MemoryScopeRefSchema: z.ZodObject<{
|
|
|
27
27
|
}, z.core.$strict>;
|
|
28
28
|
export declare const MemoryKindSchema: z.ZodEnum<{
|
|
29
29
|
evidence: "evidence";
|
|
30
|
-
todo: "todo";
|
|
31
30
|
user_preference: "user_preference";
|
|
32
31
|
project_fact: "project_fact";
|
|
33
32
|
architecture_decision: "architecture_decision";
|
|
@@ -37,6 +36,7 @@ export declare const MemoryKindSchema: z.ZodEnum<{
|
|
|
37
36
|
test_pattern: "test_pattern";
|
|
38
37
|
failure_pattern: "failure_pattern";
|
|
39
38
|
security_note: "security_note";
|
|
39
|
+
todo: "todo";
|
|
40
40
|
scratch: "scratch";
|
|
41
41
|
}>;
|
|
42
42
|
export declare const MemorySourceSchema: z.ZodObject<{
|
|
@@ -78,7 +78,6 @@ export declare const MemoryRecordSchema: z.ZodObject<{
|
|
|
78
78
|
}, z.core.$strict>;
|
|
79
79
|
kind: z.ZodEnum<{
|
|
80
80
|
evidence: "evidence";
|
|
81
|
-
todo: "todo";
|
|
82
81
|
user_preference: "user_preference";
|
|
83
82
|
project_fact: "project_fact";
|
|
84
83
|
architecture_decision: "architecture_decision";
|
|
@@ -88,6 +87,7 @@ export declare const MemoryRecordSchema: z.ZodObject<{
|
|
|
88
87
|
test_pattern: "test_pattern";
|
|
89
88
|
failure_pattern: "failure_pattern";
|
|
90
89
|
security_note: "security_note";
|
|
90
|
+
todo: "todo";
|
|
91
91
|
scratch: "scratch";
|
|
92
92
|
}>;
|
|
93
93
|
text: z.ZodString;
|
|
@@ -156,7 +156,6 @@ export declare const MemoryProposalSchema: z.ZodObject<{
|
|
|
156
156
|
}, z.core.$strict>;
|
|
157
157
|
kind: z.ZodEnum<{
|
|
158
158
|
evidence: "evidence";
|
|
159
|
-
todo: "todo";
|
|
160
159
|
user_preference: "user_preference";
|
|
161
160
|
project_fact: "project_fact";
|
|
162
161
|
architecture_decision: "architecture_decision";
|
|
@@ -166,6 +165,7 @@ export declare const MemoryProposalSchema: z.ZodObject<{
|
|
|
166
165
|
test_pattern: "test_pattern";
|
|
167
166
|
failure_pattern: "failure_pattern";
|
|
168
167
|
security_note: "security_note";
|
|
168
|
+
todo: "todo";
|
|
169
169
|
scratch: "scratch";
|
|
170
170
|
}>;
|
|
171
171
|
text: z.ZodString;
|
package/dist/memory/scoring.d.ts
CHANGED
|
@@ -25,6 +25,51 @@ export declare const SCORING_WEIGHTS: {
|
|
|
25
25
|
readonly roleBoost: 0.05;
|
|
26
26
|
readonly confidence: 0.08;
|
|
27
27
|
};
|
|
28
|
+
export declare function tokenize(text: string): Set<string>;
|
|
29
|
+
/**
|
|
30
|
+
* True Jaccard similarity |A∩B| / |A∪B| over two token sets. Distinct from the
|
|
31
|
+
* recall-scoring `overlap` helper (which is a precision-like |A∩B|/max(|A|,|B|)).
|
|
32
|
+
* Consolidation clustering uses Jaccard per the issue spec (threshold 0.30).
|
|
33
|
+
*/
|
|
34
|
+
export declare function jaccard(a: Set<string>, b: Set<string>): number;
|
|
35
|
+
/**
|
|
36
|
+
* Single-pass greedy lexical clustering by Jaccard token overlap. Each item is
|
|
37
|
+
* compared against the representative (first member) of each existing cluster;
|
|
38
|
+
* it joins the first cluster whose representative meets `threshold`, else seeds
|
|
39
|
+
* a new cluster. Deterministic for a given input order. Sufficient for v1
|
|
40
|
+
* (embedding-based clustering is Phase 4, out of scope).
|
|
41
|
+
*/
|
|
42
|
+
export declare function clusterByJaccard<T>(items: T[], getText: (item: T) => string, threshold: number): T[][];
|
|
43
|
+
/**
|
|
44
|
+
* Continuous importance score in [0, sum-of-weights]. Replaces the boolean
|
|
45
|
+
* `isLowUtility` heuristic (DD-11). Implements the issue formula:
|
|
46
|
+
*
|
|
47
|
+
* importance = w_recency · exp(-λ · days_since_last_recall)
|
|
48
|
+
* + w_frequency · log1p(retrieval_count) / log1p(N)
|
|
49
|
+
* + w_freshness · exp(-μ · days_since_created)
|
|
50
|
+
* + w_confidence · confidence
|
|
51
|
+
*
|
|
52
|
+
* A never-recalled memory contributes 0 to the recency and frequency terms
|
|
53
|
+
* (days_since_last_recall is null, retrieval_count is 0), so for never-recalled
|
|
54
|
+
* items importance is driven by freshness and confidence — which is exactly why
|
|
55
|
+
* a high-confidence, never-recalled, aged memory is no longer mislabeled
|
|
56
|
+
* low-utility under the old OR condition.
|
|
57
|
+
*/
|
|
58
|
+
export interface ImportanceWeights {
|
|
59
|
+
wRecency: number;
|
|
60
|
+
wFrequency: number;
|
|
61
|
+
wFreshness: number;
|
|
62
|
+
wConfidence: number;
|
|
63
|
+
lambda: number;
|
|
64
|
+
mu: number;
|
|
65
|
+
n: number;
|
|
66
|
+
}
|
|
67
|
+
export declare function importanceScore(input: {
|
|
68
|
+
confidence: number;
|
|
69
|
+
retrievalCount: number;
|
|
70
|
+
daysSinceLastRecall: number | null;
|
|
71
|
+
daysSinceCreated: number;
|
|
72
|
+
}, weights: ImportanceWeights): number;
|
|
28
73
|
export declare function sameScope(a: MemoryScopeRef, b: MemoryScopeRef): boolean;
|
|
29
74
|
export declare function scopeAllowed(recordScope: MemoryScopeRef, allowedScopes: MemoryScopeRef[]): boolean;
|
|
30
75
|
export declare function scoreMemoryRecord(record: MemoryRecord, request: RecallRequest): RecallResultItem | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for the recall-injection sentinel header.
|
|
3
|
+
*
|
|
4
|
+
* DEPENDENCY-FREE leaf module. The injector emits this header to mark an
|
|
5
|
+
* injected "## Retrieved Swarm Memory" block, and `messagesContainRecall`
|
|
6
|
+
* uses it to avoid double-injection. Because that check trusts the substring,
|
|
7
|
+
* stored memory text must never be allowed to contain it (DD-14): a memory
|
|
8
|
+
* whose text embeds the sentinel, once injected, would make a later injection
|
|
9
|
+
* believe recall already happened and silently skip it.
|
|
10
|
+
*
|
|
11
|
+
* Both the emitter (`prompt-block.ts`) and the write-time guard
|
|
12
|
+
* (`schema.ts:validateMemoryRecordRules`) import from here so the header and
|
|
13
|
+
* the guard can never drift apart.
|
|
14
|
+
*/
|
|
15
|
+
export declare const MEMORY_RECALL_SENTINEL = "## Retrieved Swarm Memory";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory consolidation trigger (issue #1464, Phase 3).
|
|
3
|
+
*
|
|
4
|
+
* Thin, fail-open wrapper that runs the episodic→semantic consolidation engine
|
|
5
|
+
* at a phase boundary. Mirrors `runSkillConsolidationFireAndForget`: it is
|
|
6
|
+
* launched off the phase_complete success path, holds a per-directory in-flight
|
|
7
|
+
* guard, and never throws into the caller.
|
|
8
|
+
*
|
|
9
|
+
* Cancellation is cooperative: a deadline aborts an AbortController whose signal
|
|
10
|
+
* the engine checks before each write, and the wrapper always AWAITS the pass to
|
|
11
|
+
* settle before disposing the gateway and releasing the in-flight guard. This
|
|
12
|
+
* avoids orphaning the pass (using the gateway after dispose / racing a second
|
|
13
|
+
* pass on the same store) that a bare Promise.race timeout would cause.
|
|
14
|
+
*/
|
|
15
|
+
import type { MemoryConfig } from '../memory/config.js';
|
|
16
|
+
import { type ConsolidationResult } from '../memory/consolidation.js';
|
|
17
|
+
export interface MemoryConsolidationRequest {
|
|
18
|
+
directory: string;
|
|
19
|
+
config: MemoryConfig;
|
|
20
|
+
phase: number;
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface MemoryConsolidationOutcome {
|
|
24
|
+
started: boolean;
|
|
25
|
+
reason?: string;
|
|
26
|
+
result?: ConsolidationResult;
|
|
27
|
+
}
|
|
28
|
+
export declare function runMemoryConsolidation(req: MemoryConsolidationRequest): Promise<MemoryConsolidationOutcome>;
|
|
29
|
+
export declare function runMemoryConsolidationFireAndForget(req: MemoryConsolidationRequest, onComplete?: (outcome: MemoryConsolidationOutcome) => void, onError?: (error: unknown) => void): void;
|
|
30
|
+
export declare const _internals: {
|
|
31
|
+
runningByDirectory: Map<string, Promise<MemoryConsolidationOutcome>>;
|
|
32
|
+
};
|
|
@@ -80,6 +80,7 @@ export interface GenerateResult {
|
|
|
80
80
|
path: string;
|
|
81
81
|
mode: GenerateMode;
|
|
82
82
|
sourceKnowledgeIds: string[];
|
|
83
|
+
missingSourceKnowledgeIds?: string[];
|
|
83
84
|
preserved: boolean;
|
|
84
85
|
evaluation?: SkillEvaluationResult;
|
|
85
86
|
}>;
|
|
@@ -95,8 +96,14 @@ export declare function generateSkills(req: GenerateRequest): Promise<GenerateRe
|
|
|
95
96
|
* `generated_skill_path` metadata. Refactored in Phase G′ to take
|
|
96
97
|
* `(directory, slug, ids)` so it can be called both from direct active-mode
|
|
97
98
|
* generation AND from `activateProposal` after parsing the draft frontmatter.
|
|
99
|
+
*
|
|
100
|
+
* Returns the IDs that were successfully stamped and the IDs that were not
|
|
101
|
+
* found in swarm/hive knowledge (so callers can surface staleness).
|
|
98
102
|
*/
|
|
99
|
-
declare function stampSourceEntries(directory: string, slug: string, ids: string[]): Promise<
|
|
103
|
+
declare function stampSourceEntries(directory: string, slug: string, ids: string[]): Promise<{
|
|
104
|
+
stamped: string[];
|
|
105
|
+
missing: string[];
|
|
106
|
+
}>;
|
|
100
107
|
/**
|
|
101
108
|
* Bounded YAML frontmatter parser for generated drafts. Recognises the exact
|
|
102
109
|
* shape we emit in renderSkillMarkdown — no full YAML lib required.
|
package/dist/state.d.ts
CHANGED
|
@@ -316,6 +316,7 @@ export declare const swarmState: {
|
|
|
316
316
|
curatorInitAgentNames: string[];
|
|
317
317
|
curatorPhaseAgentNames: string[];
|
|
318
318
|
curatorPostmortemAgentNames: string[];
|
|
319
|
+
curatorConsolidationAgentNames: string[];
|
|
319
320
|
/** All registered skill_improver / spec_writer agent names across swarms,
|
|
320
321
|
* mirroring curatorInitAgentNames so the LLM delegate factory can resolve
|
|
321
322
|
* the correct prefixed agent under multi-swarm configs. */
|
|
@@ -369,11 +370,12 @@ export declare function resetSwarmState(): void;
|
|
|
369
370
|
* The preserved fields are:
|
|
370
371
|
* - opencodeClient (SDK client for curator/full-auto delegation)
|
|
371
372
|
* - fullAutoEnabledInConfig (config flag read at init)
|
|
372
|
-
* - curatorInitAgentNames, curatorPhaseAgentNames, curatorPostmortemAgentNames
|
|
373
|
+
* - curatorInitAgentNames, curatorPhaseAgentNames, curatorPostmortemAgentNames,
|
|
374
|
+
* curatorConsolidationAgentNames (curator registry)
|
|
373
375
|
* - skillImproverAgentNames, specWriterAgentNames (skill/spec registry)
|
|
374
376
|
* - generatedAgentNames (full-auto delegation guard registry)
|
|
375
377
|
*
|
|
376
|
-
* Implementation: save all
|
|
378
|
+
* Implementation: save all to locals, call resetSwarmState(), restore all.
|
|
377
379
|
* Synchronous (matches resetSwarmState contract). Errors from resetSwarmState
|
|
378
380
|
* propagate to caller (no try/catch wrapper).
|
|
379
381
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.88.
|
|
3
|
+
"version": "7.88.4",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|