dsh-mnemon-strategy-default-three-tier 0.5.11 → 0.5.13

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 CHANGED
@@ -69,6 +69,19 @@ the same role, the original ambiguity check applies rather than silently
69
69
  choosing a Source. Projection limits are not token limits or delta injection;
70
70
  capture guidance is not a background worker or a guarantee of model behavior.
71
71
 
72
+ ## Sources with another role
73
+
74
+ An installed Source whose role is not `working-context`, `narrative` or
75
+ `durable-evidence` is not a failure and is not admitted either: the strategy
76
+ keeps composing the three tiers and returns one `unsupported-source-role`
77
+ entry per such Source in `ViewSpec.diagnostics`. The Host validates those
78
+ entries and merges them into `view.diagnostics`, so the turn's
79
+ `MNEMON VIEW AVAILABILITY` line and the View inspection name the Source and its
80
+ role. A diagnostic is an explanation, never authority: the Source still gets no
81
+ projection, Route or ActionOffer. Select the general Strategy to compose it;
82
+ an explicit `selection` still rejects unsupported roles. An unavailable Source keeps
83
+ the Host's own diagnostic instead.
84
+
72
85
  Its own directory is a standalone project: install its declared dependencies,
73
86
  then run `pnpm verify`. When developing against an unreleased Mnemon, install a
74
87
  packed `dsh-mnemon` artifact as the peer instead of linking its source tree.
package/lib/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { MemoryAvailableSource, MemoryViewRequest, MemoryViewSpec } from "dsh-mnemon/contracts";
1
+ import * as projectionSDK from "dsh-mnemon/extension-sdk";
2
2
  import { Context } from "@deepseek-ai/cordis";
3
3
  //#region src/strategy.d.ts
4
4
  /** Pure View composition; no dependency on any Source implementation. */
5
5
  declare const DEFAULT_THREE_TIER_VIEW_STRATEGY: {
6
- createTurn: (view: import("dsh-mnemon/extension-sdk").ComposableMemoryView) => import("dsh-mnemon/extension-sdk").MemoryStrategyTurn;
6
+ createTurn: (view: projectionSDK.ComposableMemoryView) => projectionSDK.MemoryStrategyTurn;
7
7
  manifest: {
8
8
  apiVersion: "dsh-mnemon/v1";
9
9
  kind: "strategy";
@@ -17,7 +17,7 @@ declare const DEFAULT_THREE_TIER_VIEW_STRATEGY: {
17
17
  extensionSlots: string[];
18
18
  workflows: ("idle-review" | "runtime-capacity")[];
19
19
  };
20
- compose(request: MemoryViewRequest, sources: readonly MemoryAvailableSource[], contributions?: readonly import("dsh-mnemon/extension-sdk").MemoryStrategyContribution[] | undefined): MemoryViewSpec;
20
+ compose(request: projectionSDK.MemoryViewRequest, sources: readonly projectionSDK.MemoryAvailableSource[], contributions?: readonly projectionSDK.MemoryStrategyContribution[] | undefined): projectionSDK.MemoryViewSpec;
21
21
  };
22
22
  //#endregion
23
23
  //#region src/index.d.ts
package/lib/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { threeTierContributions } from "./extension-sdk.js";
2
+ import * as projectionSDK from "dsh-mnemon/extension-sdk";
2
3
  import { defineMemoryPlugin, defineMemoryStrategy, defineMemoryStrategyConfiguration, installMemory, memoryInputRecord, truncateMemoryText } from "dsh-mnemon/extension-sdk";
3
4
  import { COMPOSABLE_MEMORY_API_VERSION } from "dsh-mnemon/contracts";
4
5
  import { createHash, randomUUID } from "node:crypto";
@@ -510,11 +511,30 @@ const VIEW_ROLES = [
510
511
  "narrative",
511
512
  "durable-evidence"
512
513
  ];
514
+ /** The Host accepts at most 32 ViewSpec diagnostics; the summary keeps us inside it. */
515
+ const MAX_DIAGNOSTICS = 32;
513
516
  function soleSource(sources, role) {
514
517
  const matches = sources.filter((source) => source.role === role && source.availability !== "unavailable").sort((left, right) => left.sourceInstanceKey.localeCompare(right.sourceInstanceKey));
515
518
  if (matches.length > 1) throw new Error(`default-three-tier View Strategy found ambiguous ${role} Sources; select an explicit Strategy`);
516
519
  return matches[0];
517
520
  }
521
+ /**
522
+ * Why an installed Source stays out of this View (#504). A custom role is not a
523
+ * failure, so it is explained instead of silently dropped; an unavailable Source
524
+ * already carries the Host's own diagnostic. Sorted by instance key so repeated
525
+ * composition stays deterministic.
526
+ */
527
+ function unsupportedRoleDiagnostics(sources) {
528
+ const unsupported = sources.filter((source) => source.availability !== "unavailable" && !VIEW_ROLES.includes(source.role)).sort((left, right) => left.sourceInstanceKey.localeCompare(right.sourceInstanceKey));
529
+ const reported = unsupported.length <= MAX_DIAGNOSTICS ? unsupported : unsupported.slice(0, 31);
530
+ return [...reported.map((source) => ({
531
+ code: "unsupported-source-role",
532
+ message: `Installed Source ${source.sourceInstanceKey} declares the role "${source.role}", which the default-three-tier Strategy does not admit, so it contributes no projection, Routes or Actions to this View. Use the general Strategy to compose it.`
533
+ })), ...reported.length === unsupported.length ? [] : [{
534
+ code: "unsupported-source-role",
535
+ message: `${unsupported.length - reported.length} more installed Sources declare a role the default-three-tier Strategy does not admit.`
536
+ }]];
537
+ }
518
538
  /** Pure View composition; no dependency on any Source implementation. */
519
539
  const DEFAULT_THREE_TIER_VIEW_STRATEGY = defineMemoryStrategy({
520
540
  createTurn: createThreeTierTurn,
@@ -536,7 +556,16 @@ const DEFAULT_THREE_TIER_VIEW_STRATEGY = defineMemoryStrategy({
536
556
  workflows: ["idle-review", "runtime-capacity"]
537
557
  },
538
558
  compose(request, sources, contributions = []) {
539
- if (contributions.length === 0) return composeThreeTier(request, sources);
559
+ const diagnostics = unsupportedRoleDiagnostics(sources);
560
+ const explained = (spec, budget = request.budget.maxProjectionCharacters) => {
561
+ if (typeof projectionSDK.reserveMemoryProjection !== "function" && sources.some((source) => source.hints && typeof source.hints === "object" && !Array.isArray(source.hints) && Number(source.hints.minimumProjectionCharacters) > 0)) throw new Error("Pinned Runtime requires a newer dsh-mnemon Host; update the Host and official Strategies together.");
562
+ const reserved = projectionSDK.reserveMemoryProjection?.(spec, sources, budget) ?? spec;
563
+ return diagnostics.length === 0 ? reserved : {
564
+ ...reserved,
565
+ diagnostics
566
+ };
567
+ };
568
+ if (contributions.length === 0) return explained(composeThreeTier(request, sources));
540
569
  const policies = threeTierContributions(contributions);
541
570
  const boundedRequest = policies.projection === void 0 ? request : {
542
571
  ...request,
@@ -545,7 +574,7 @@ const DEFAULT_THREE_TIER_VIEW_STRATEGY = defineMemoryStrategy({
545
574
  maxProjectionCharacters: Math.min(request.budget.maxProjectionCharacters, policies.projection.maxProjectionCharacters)
546
575
  }
547
576
  };
548
- const spec = policies.selection === void 0 ? composeThreeTier(boundedRequest, sources) : composeSelected(boundedRequest, sources, policies.selection);
577
+ const spec = explained(policies.selection === void 0 ? composeThreeTier(boundedRequest, sources) : composeSelected(boundedRequest, sources, policies.selection), boundedRequest.budget.maxProjectionCharacters);
549
578
  if (policies.capture !== void 0) {
550
579
  const targets = spec.sources.filter((selected) => (policies.capture.sourceKeys === void 0 || policies.capture.sourceKeys.includes(selected.sourceInstanceKey)) && sources.some((source) => source.sourceInstanceKey === selected.sourceInstanceKey && source.actions.some((action) => selected.actionIds?.includes(action.id) && policies.capture.actionIds.includes(action.id) && action.authority === void 0 && ["write", "maintain"].includes(action.capability))));
551
580
  if (targets.length > 0) {
@@ -627,7 +656,7 @@ function composeSelected(request, sources, selection) {
627
656
  const selected = selection.sourceKeys.map((key) => {
628
657
  const source = sources.find((source) => source.sourceInstanceKey === key);
629
658
  if (source === void 0) throw new Error(`scoped three-tier Source is not installed: ${key}`);
630
- if (!VIEW_ROLES.includes(source.role)) throw new Error(`unsupported scoped three-tier Source role: ${source.role}`);
659
+ if (!VIEW_ROLES.includes(source.role)) throw new Error(`unsupported scoped three-tier Source role: ${source.role} (${source.sourceInstanceKey}); default-three-tier admits ${VIEW_ROLES.join(", ")} only, so remove it from the selection or select the general Strategy`);
631
660
  return source;
632
661
  }).filter((source) => source.availability !== "unavailable");
633
662
  const projected = selected.filter((source) => source.capabilities.includes("project"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mnemon-strategy-default-three-tier",
3
- "version": "0.5.11",
3
+ "version": "0.5.13",
4
4
  "description": "Explicit three-tier View Strategy for Composable View Memory.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -32,11 +32,11 @@
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@deepseek-ai/cordis": "^4.0.1",
35
- "dsh-mnemon": "^0.5.17"
35
+ "dsh-mnemon": "^0.5.43"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^22.0.0",
39
- "dsh-mnemon": "^0.5.35",
39
+ "dsh-mnemon": "^0.5.43",
40
40
  "tsdown": "^0.22.0",
41
41
  "typescript": "^5.9.0",
42
42
  "vitest": "^3.2.0"