@dawn-ai/core 0.8.7 → 0.8.9

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
@@ -6,7 +6,155 @@
6
6
 
7
7
  Filesystem-based route discovery, app config loading, state-field resolution, and typegen primitives that the Dawn CLI builds on.
8
8
 
9
- This is an internal Dawn workspace package, part of [Dawn the TypeScript meta-framework for LangGraph](https://github.com/cacheplane/dawnai). For documentation, see [dawnai.org/docs](https://dawnai.org/docs/getting-started).
9
+ This is part of [Dawn - the TypeScript meta-framework for LangGraph](https://github.com/cacheplane/dawnai).
10
+ Use this package for CLI/runtime integration points; application routes usually
11
+ import author-facing helpers from `@dawn-ai/sdk`.
12
+
13
+ Conceptual docs: [Routes](https://dawnai.org/docs/routes),
14
+ [Configuration](https://dawnai.org/docs/configuration),
15
+ [Workspace Filesystem](https://dawnai.org/docs/workspace),
16
+ [Memory](https://dawnai.org/docs/memory), and
17
+ [API Reference](https://dawnai.org/docs/api#dawn-aicore).
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pnpm add @dawn-ai/core
23
+ ```
24
+
25
+ ```ts
26
+ import {
27
+ createCapabilityRegistry,
28
+ createWorkspaceFs,
29
+ discoverRoutes,
30
+ loadDawnConfig,
31
+ renderDawnTypes,
32
+ type DawnConfig,
33
+ } from "@dawn-ai/core"
34
+ ```
35
+
36
+ ## Public Exports
37
+
38
+ ### Capability markers
39
+
40
+ - `createAgentsMdMarker()`
41
+ - `createMemoryMarker()`
42
+ - `createMemoryMdMarker()`
43
+ - `createPlanningMarker()`
44
+ - `createSkillsMarker()`
45
+ - `createSubagentsMarker()`
46
+ - `createWorkspaceMarker()`
47
+ - `BUILT_IN_TOOL_NAMES`
48
+
49
+ These markers detect route/app files and contribute prompt fragments, tools, or
50
+ stream transformers. `createMemoryMarker()` activates only when route memory
51
+ context is supplied; `createWorkspaceMarker()` activates when a `workspace/`
52
+ directory exists or a runtime `workspaceRoot` is supplied.
53
+
54
+ ### Capability registry and permission gating
55
+
56
+ - `createCapabilityRegistry(markers)` and `applyCapabilities()` collect marker
57
+ contributions for a route.
58
+ - `gateToolOp()` and `wrapToolWithApproval()` apply tool-level approval rules.
59
+ - Types include `CapabilityMarker`, `CapabilityMarkerContext`,
60
+ `CapabilityContribution`, `DawnToolDefinition`, `PromptFragment`,
61
+ `StreamTransformer`, `MemoryContext`, `MemoryStoreLike`, and registry result
62
+ types.
63
+
64
+ ### Workspace filesystem
65
+
66
+ - `createWorkspaceFs(options)` builds the `WorkspaceFs` handle used as `ctx.fs`.
67
+ - `CreateWorkspaceFsOptions` accepts `workspaceRoot`, a `FilesystemBackend`,
68
+ permissions, an `AbortSignal`, and `interruptCapable`.
69
+
70
+ The helper resolves paths relative to `workspaceRoot`, canonicalizes them with
71
+ the backend's `realPath`, and applies the same permission gate used by
72
+ agent-facing workspace tools.
73
+
74
+ ### Configuration and discovery
75
+
76
+ - `loadDawnConfig({ appRoot })` loads and normalizes `dawn.config.ts`.
77
+ - `config(value)` is the typed identity helper for config files.
78
+ - `discoverRoutes(options)` scans the Dawn app directory and returns a route
79
+ manifest.
80
+ - `findDawnApp(options)` locates app roots, and
81
+ `assertDawnRoutesDir(appRoot, routesDir?)` validates that a routes directory
82
+ exists, returning `Promise<void>`.
83
+ - `toRouteSegments()`, `isPrivateSegment()`, and `isRouteGroupSegment()` parse
84
+ file-system route segments.
85
+ - Types include `DawnConfig`, `LoadedDawnConfig`, `DiscoverRoutesOptions`,
86
+ `DiscoveredDawnApp`, `RouteDefinition`, `RouteManifest`, `RouteSegment`,
87
+ `RouteKind`, and `NormalizedRouteModule`.
88
+
89
+ ### State and typegen
90
+
91
+ - `resolveStateFields()` resolves route state reducers and defaults.
92
+ - `extractToolSchemasForRoute()` and `extractToolTypesForRoute()` inspect route
93
+ tools for schemas and generated type definitions.
94
+ - `renderDawnTypes()`, `renderRouteTypes()`, `renderStateTypes()`, and
95
+ `renderToolTypes()` render the generated `dawn:routes` declaration. Some docs
96
+ and audits refer to this group as `renderTypeDefinitions`; there is no single
97
+ exported function by that name.
98
+ - Types include `ResolveStateFieldsOptions`, `RouteStateFields`,
99
+ `ExtractToolSchemasOptions`, `ExtractToolTypesOptions`,
100
+ `RouteToolSchemas`, `RouteToolTypes`, `ExtractedToolSchema`,
101
+ `ExtractedToolType`, `ResolvedStateField`, and `StateFieldReducer`.
102
+
103
+ ### Tool scope
104
+
105
+ - `resolveToolScope()` and `toolOrigin()` decide whether a discovered tool is
106
+ visible to a route.
107
+ - Types include `ScopeInput` and `ToolOrigin`.
108
+
109
+ ### Storage type re-export
110
+
111
+ - `ThreadsStore` is re-exported from `@dawn-ai/sqlite-storage` for config typing.
112
+
113
+ ## Examples
114
+
115
+ Discover routes and render generated route types:
116
+
117
+ ```ts
118
+ import {
119
+ discoverRoutes,
120
+ extractToolTypesForRoute,
121
+ renderDawnTypes,
122
+ } from "@dawn-ai/core"
123
+
124
+ const manifest = await discoverRoutes({ appRoot: process.cwd() })
125
+ const toolTypes = await Promise.all(
126
+ manifest.routes.map(async (route) => ({
127
+ pathname: route.pathname,
128
+ tools: await extractToolTypesForRoute({
129
+ routeDir: route.routeDir,
130
+ sharedToolsDir: `${process.cwd()}/src`,
131
+ }),
132
+ })),
133
+ )
134
+
135
+ const dts = renderDawnTypes(manifest, toolTypes)
136
+ ```
137
+
138
+ Create a gated `WorkspaceFs` handle:
139
+
140
+ ```ts
141
+ import { createWorkspaceFs } from "@dawn-ai/core"
142
+ import { localFilesystem } from "@dawn-ai/workspace"
143
+
144
+ const fs = createWorkspaceFs({
145
+ workspaceRoot: `${process.cwd()}/workspace`,
146
+ backend: localFilesystem(),
147
+ permissions: undefined,
148
+ signal: new AbortController().signal,
149
+ interruptCapable: false,
150
+ })
151
+ ```
152
+
153
+ ## Notes
154
+
155
+ `@dawn-ai/core` is intentionally lower level than `@dawn-ai/sdk`. Prefer the SDK
156
+ for route code (`agent`, `defineMemory`, `DawnToolContext`, `RuntimeContext`),
157
+ and use core when building CLIs, adapters, tests, or runtime integrations.
10
158
 
11
159
  ## License
12
160
 
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/capabilities/built-in/memory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAA;AAanE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,gBAAgB,CAgLrD"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/capabilities/built-in/memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAA;AAanE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,gBAAgB,CAsPrD"}
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { z } from "zod";
3
+ import { gateMemorySupersede } from "../permission-gate.js";
3
4
  const DEFAULT_SEMANTIC_IDENTITY = ["subject", "predicate"];
4
5
  // A route's defineMemory() schema arrives as `unknown` (loaded via dynamic
5
6
  // import, validated structurally). Module-scoped (no closure deps) so it isn't
@@ -23,6 +24,7 @@ export function createMemoryMarker() {
23
24
  const mem = context.memory;
24
25
  if (!mem)
25
26
  return {};
27
+ const permissions = context.permissions;
26
28
  const indexEntries = await mem.store.search({
27
29
  namespace: mem.namespace,
28
30
  status: "active",
@@ -56,6 +58,25 @@ export function createMemoryMarker() {
56
58
  schema: recallSchema,
57
59
  run: async (input) => {
58
60
  const q = (input ?? {});
61
+ // Embed the query for the hybrid keyword+vector path when an embedder
62
+ // is configured. Embed FAILURE degrades to keyword-only — never throw,
63
+ // so a flaky/offline embedder can't break recall.
64
+ let queryVec;
65
+ if (mem.embedder && q.query) {
66
+ try {
67
+ ;
68
+ [queryVec] = await mem.embedder.embed([q.query]);
69
+ }
70
+ catch (err) {
71
+ // Gated: silent embed failures are an ops footgun (user thinks
72
+ // vector recall works while every embed errors). Mirrors the
73
+ // summarization hook's DAWN_DEBUG_SUMMARIZATION convention.
74
+ if (process.env.DAWN_DEBUG_MEMORY === "1") {
75
+ console.warn(`[dawn:memory] recall embed failed, falling back to keyword-only: ${String(err)}`);
76
+ }
77
+ queryVec = undefined;
78
+ }
79
+ }
59
80
  const rows = await mem.store.search({
60
81
  namespace: mem.namespace,
61
82
  ...(q.query ? { query: q.query } : {}),
@@ -65,10 +86,16 @@ export function createMemoryMarker() {
65
86
  // Recency reference for ranked recall — the per-request timestamp,
66
87
  // NOT Date.now() (determinism rule; see module docblock).
67
88
  now: mem.now,
89
+ ...(queryVec && mem.embedder
90
+ ? { queryEmbedding: queryVec, embedderId: mem.embedder.id, vector: mem.vector }
91
+ : {}),
68
92
  });
93
+ // Wrap in {result} so the langchain bridge uses the string verbatim as
94
+ // the ToolMessage content; a bare string hits unwrapToolResult's
95
+ // JSON.stringify path, quoting it and escaping the newlines below.
69
96
  if (rows.length === 0)
70
- return "(no memories found)";
71
- return rows.map((r) => `${r.id}: ${r.content}`).join("\n");
97
+ return { result: "(no memories found)" };
98
+ return { result: rows.map((r) => `${r.id}: ${r.content}`).join("\n") };
72
99
  },
73
100
  };
74
101
  const remember = {
@@ -78,8 +105,9 @@ export function createMemoryMarker() {
78
105
  run: async (input) => {
79
106
  const inp = (input ?? {});
80
107
  const validated = mem.validate(inp.data);
108
+ // All returns below wrap in {result} — see the recall tool's note.
81
109
  if (!validated.ok)
82
- return `Rejected: ${validated.errors}`;
110
+ return { result: `Rejected: ${validated.errors}` };
83
111
  const data = validated.value;
84
112
  const identityKeys = mem.defined.identity ?? DEFAULT_SEMANTIC_IDENTITY;
85
113
  // id is DATA-derived so contradicting values (same identity, different
@@ -88,7 +116,9 @@ export function createMemoryMarker() {
88
116
  .update(`${mem.namespace}|${JSON.stringify(data)}`)
89
117
  .digest("hex")
90
118
  .slice(0, 16)}`;
91
- const status = mem.writes === "auto" ? "active" : "candidate";
119
+ // "ask" shares auto's write semantics; only its SUPERSEDE branch gates.
120
+ const autoLike = mem.writes === "auto" || mem.writes === "ask";
121
+ const status = autoLike ? "active" : "candidate";
92
122
  const content = typeof inp.content === "string" && inp.content.length > 0
93
123
  ? inp.content
94
124
  : JSON.stringify(data);
@@ -107,7 +137,26 @@ export function createMemoryMarker() {
107
137
  createdAt: mem.now,
108
138
  updatedAt: mem.now,
109
139
  };
110
- if (mem.writes === "auto") {
140
+ // Embed the content for vector recall when an embedder is configured.
141
+ // Embed FAILURE degrades to keyword-only (putOpts stays undefined) —
142
+ // NEVER lose the write. Forwarded to EVERY put site below.
143
+ let putOpts;
144
+ if (mem.embedder) {
145
+ try {
146
+ const [ev] = await mem.embedder.embed([content]);
147
+ if (ev)
148
+ putOpts = { embedding: ev, embeddingModel: mem.embedder.id };
149
+ }
150
+ catch (err) {
151
+ // Gated warn — see the recall catch above. The write still lands
152
+ // keyword-only (putOpts undefined); we never lose the memory.
153
+ if (process.env.DAWN_DEBUG_MEMORY === "1") {
154
+ console.warn(`[dawn:memory] remember embed failed, storing keyword-only: ${String(err)}`);
155
+ }
156
+ putOpts = undefined;
157
+ }
158
+ }
159
+ if (autoLike) {
111
160
  // Inline identity key helper — avoids importing from @dawn-ai/memory
112
161
  const identityKey = (d) => identityKeys.map((k) => JSON.stringify(d[k] ?? null)).join(" ");
113
162
  const existing = await mem.store.search({
@@ -125,21 +174,41 @@ export function createMemoryMarker() {
125
174
  confidence,
126
175
  tags,
127
176
  });
128
- return `Updated memory ${target.id}.`;
177
+ return { result: `Updated memory ${target.id}.` };
178
+ }
179
+ // Same identity but different value — supersede. In "ask" mode this
180
+ // is the one write that gates: the agent is contradicting a prior
181
+ // belief. ADDs/idempotent UPDATEs above never reach the gate.
182
+ if (mem.writes === "ask") {
183
+ const gate = await gateMemorySupersede(permissions, {
184
+ namespace: mem.namespace,
185
+ // Human-readable display form for the prompt — deliberately NOT
186
+ // the `identityKey` match key above (which JSON.stringifies to
187
+ // stay unambiguous); do not merge the two.
188
+ identity: identityKeys.map((k) => String(data[k] ?? "")).join(" / "),
189
+ oldId: target.id,
190
+ oldContent: target.content,
191
+ newContent: content,
192
+ });
193
+ if (!gate.allowed) {
194
+ return {
195
+ result: `Kept existing memory ${target.id} ("${target.content}"); ` +
196
+ `your contradicting value was not stored (${gate.reason}).`,
197
+ };
198
+ }
129
199
  }
130
- // Same identity but different value — write new active row then supersede old
131
- await mem.store.put(record);
200
+ await mem.store.put(record, putOpts);
132
201
  await mem.store.supersede(target.id, id);
133
- return `Superseded ${target.id} with ${id}.`;
202
+ return { result: `Superseded ${target.id} with ${id}.` };
134
203
  }
135
204
  // No existing record with same identity — add new active row
136
- await mem.store.put(record);
137
- return `Stored memory ${id}.`;
205
+ await mem.store.put(record, putOpts);
206
+ return { result: `Stored memory ${id}.` };
138
207
  }
139
208
  // Candidate mode (and "off" never reaches here — remember tool absent):
140
209
  // write a candidate; reconciliation happens later at CLI approval.
141
- await mem.store.put(record);
142
- return `Stored memory candidate ${id} (pending approval).`;
210
+ await mem.store.put(record, putOpts);
211
+ return { result: `Stored memory candidate ${id} (pending approval).` };
143
212
  },
144
213
  };
145
214
  // Fingerprint the snapshot the render closure froze at load time. `id`
@@ -1,4 +1,5 @@
1
1
  import type { PermissionsStore } from "@dawn-ai/permissions";
2
+ import type { ConstraintPredicate } from "@dawn-ai/sdk";
2
3
  export type PathOperation = "readFile" | "writeFile" | "listDir";
3
4
  export type GateResult = {
4
5
  allowed: true;
@@ -19,6 +20,28 @@ export declare function gateBashOp(permissions: PermissionsStore | undefined, co
19
20
  export declare function gateToolOp(permissions: PermissionsStore | undefined, toolName: string, argsPreview: string, opts?: {
20
21
  readonly interruptCapable?: boolean;
21
22
  }): Promise<GateResult>;
23
+ export interface MemorySupersedeDetail {
24
+ readonly namespace: string;
25
+ readonly identity: string;
26
+ readonly oldId: string;
27
+ readonly oldContent: string;
28
+ readonly newContent: string;
29
+ }
30
+ /**
31
+ * Memory supersede gate (memory.writes: "ask"). Prompts ONLY when the agent
32
+ * contradicts an existing active memory — ADDs and idempotent UPDATEs never
33
+ * reach this gate. Persisted decisions live under the reserved "memory" key
34
+ * as workspace+route namespace prefixes; candidates are matched with a "|"
35
+ * terminator so sibling routes cannot prefix-collide.
36
+ *
37
+ * DELIBERATE DIVERGENCE from gateToolOp: on "unknown" with no interactive
38
+ * human (non-interactive mode), this gate ALLOWS the supersede — ask is a
39
+ * supervision affordance, not a security boundary; headless it behaves
40
+ * exactly as writes:"auto". Explicit deny rules are still honored headless.
41
+ * Only called from inside the memory capability's remember tool, which only
42
+ * exists on agent routes (in-graph), so interrupt() is safe here.
43
+ */
44
+ export declare function gateMemorySupersede(permissions: PermissionsStore | undefined, detail: MemorySupersedeDetail): Promise<GateResult>;
22
45
  /**
23
46
  * Wrap a tool so each call passes gateToolOp first (tools.approve). A blocked
24
47
  * call returns the denial reason AS THE TOOL RESULT — deliberately a different
@@ -43,4 +66,24 @@ export declare function wrapToolWithApproval<C, T extends {
43
66
  }>(tool: T, permissions: PermissionsStore, opts?: {
44
67
  readonly interruptCapable?: boolean;
45
68
  }): T;
69
+ /**
70
+ * Wrap a tool so each call is first evaluated by an argument-constraint predicate
71
+ * (tools.constrain). The predicate returns `true` (allow), a string (deny — the
72
+ * string is returned as the tool result, matching wrapToolWithApproval's
73
+ * return-not-throw contract), or `{ approve: true }` (escalate to the HITL gate
74
+ * via gateToolOp). A predicate that throws OR returns any off-contract value
75
+ * (false, undefined, `{ approve: false }`, …) fails closed (deny) — a broken
76
+ * policy never silently allows. Per-call identity (signal/threadId/params) is read from
77
+ * the LIVE run context, never closed over, so the wrapper is safe inside the
78
+ * per-descriptor-cached agent. `routeId` and `predicate` are stable per descriptor
79
+ * and closed over.
80
+ */
81
+ export declare function wrapToolWithConstraint<C extends {
82
+ readonly signal: AbortSignal;
83
+ readonly threadId?: string;
84
+ readonly params?: Readonly<Record<string, string>>;
85
+ }, T extends {
86
+ readonly name: string;
87
+ readonly run: (input: unknown, context: C) => Promise<unknown> | unknown;
88
+ }>(tool: T, predicate: ConstraintPredicate, permissions: PermissionsStore | undefined, routeId: string): T;
46
89
  //# sourceMappingURL=permission-gate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"permission-gate.d.ts","sourceRoot":"","sources":["../../src/capabilities/permission-gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAI5D,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAA;AAEhE,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E,wBAAsB,UAAU,CAC9B,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7C,OAAO,CAAC,UAAU,CAAC,CAwCrB;AAED,wBAAsB,UAAU,CAC9B,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,CAAC,CAqBrB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7C,OAAO,CAAC,UAAU,CAAC,CA+BrB;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EACD,CAAC,SAAS;IACR,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CACzE,EACD,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,CAAC,CAS3F"}
1
+ {"version":3,"file":"permission-gate.d.ts","sourceRoot":"","sources":["../../src/capabilities/permission-gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAM5D,OAAO,KAAK,EAAqB,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAG1E,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAA;AAEhE,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E,wBAAsB,UAAU,CAC9B,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7C,OAAO,CAAC,UAAU,CAAC,CAwCrB;AAED,wBAAsB,UAAU,CAC9B,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,CAAC,CAqBrB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7C,OAAO,CAAC,UAAU,CAAC,CA+BrB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAqBrB;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EACD,CAAC,SAAS;IACR,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CACzE,EACD,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,CAAC,CAS3F;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,CAAC,SAAS;IACR,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACnD,EACD,CAAC,SAAS;IACR,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CACzE,EAED,IAAI,EAAE,CAAC,EACP,SAAS,EAAE,mBAAmB,EAC9B,WAAW,EAAE,gBAAgB,GAAG,SAAS,EACzC,OAAO,EAAE,MAAM,GACd,CAAC,CAkCH"}
@@ -1,5 +1,5 @@
1
1
  import { sep } from "node:path";
2
- import { suggestedCommandPattern, suggestedPathPattern } from "@dawn-ai/permissions";
2
+ import { suggestedCommandPattern, suggestedMemoryPattern, suggestedPathPattern, } from "@dawn-ai/permissions";
3
3
  import { interrupt } from "@langchain/langgraph";
4
4
  export async function gatePathOp(permissions, operation, absPath, workspaceRoot, opts) {
5
5
  // If permissions store is absent, allow (legacy behavior — capability used without permissions context).
@@ -105,6 +105,44 @@ export async function gateToolOp(permissions, toolName, argsPreview, opts) {
105
105
  }
106
106
  return { allowed: true };
107
107
  }
108
+ /**
109
+ * Memory supersede gate (memory.writes: "ask"). Prompts ONLY when the agent
110
+ * contradicts an existing active memory — ADDs and idempotent UPDATEs never
111
+ * reach this gate. Persisted decisions live under the reserved "memory" key
112
+ * as workspace+route namespace prefixes; candidates are matched with a "|"
113
+ * terminator so sibling routes cannot prefix-collide.
114
+ *
115
+ * DELIBERATE DIVERGENCE from gateToolOp: on "unknown" with no interactive
116
+ * human (non-interactive mode), this gate ALLOWS the supersede — ask is a
117
+ * supervision affordance, not a security boundary; headless it behaves
118
+ * exactly as writes:"auto". Explicit deny rules are still honored headless.
119
+ * Only called from inside the memory capability's remember tool, which only
120
+ * exists on agent routes (in-graph), so interrupt() is safe here.
121
+ */
122
+ export async function gateMemorySupersede(permissions, detail) {
123
+ if (!permissions)
124
+ return { allowed: true };
125
+ if (permissions.mode === "bypass")
126
+ return { allowed: true };
127
+ const decision = permissions.match("memory", `${detail.namespace}|`);
128
+ if (decision === "allow")
129
+ return { allowed: true };
130
+ if (decision === "deny") {
131
+ return { allowed: false, reason: `approval denied for this route's memory overwrites` };
132
+ }
133
+ // unknown + headless → allow through (ask ≡ auto without a human).
134
+ if (permissions.mode === "non-interactive")
135
+ return { allowed: true };
136
+ const result = await emitPermissionInterrupt({
137
+ kind: "memory",
138
+ ...detail,
139
+ permissions,
140
+ });
141
+ if (result === "deny") {
142
+ return { allowed: false, reason: `approval denied` };
143
+ }
144
+ return { allowed: true };
145
+ }
108
146
  /** Best-effort display preview of a tool call's args. Never matched or persisted. */
109
147
  function buildArgsPreview(input) {
110
148
  try {
@@ -144,13 +182,65 @@ export function wrapToolWithApproval(tool, permissions, opts) {
144
182
  },
145
183
  };
146
184
  }
185
+ const CONSTRAINT_FAILED_REASON = "Blocked: the tool's argument constraint check failed (the policy predicate threw or returned an invalid verdict). Not run.";
186
+ /**
187
+ * Wrap a tool so each call is first evaluated by an argument-constraint predicate
188
+ * (tools.constrain). The predicate returns `true` (allow), a string (deny — the
189
+ * string is returned as the tool result, matching wrapToolWithApproval's
190
+ * return-not-throw contract), or `{ approve: true }` (escalate to the HITL gate
191
+ * via gateToolOp). A predicate that throws OR returns any off-contract value
192
+ * (false, undefined, `{ approve: false }`, …) fails closed (deny) — a broken
193
+ * policy never silently allows. Per-call identity (signal/threadId/params) is read from
194
+ * the LIVE run context, never closed over, so the wrapper is safe inside the
195
+ * per-descriptor-cached agent. `routeId` and `predicate` are stable per descriptor
196
+ * and closed over.
197
+ */
198
+ export function wrapToolWithConstraint(tool, predicate, permissions, routeId) {
199
+ return {
200
+ ...tool,
201
+ run: async (input, context) => {
202
+ const ctx = {
203
+ toolName: tool.name,
204
+ routeId,
205
+ signal: context.signal,
206
+ ...(context.threadId ? { threadId: context.threadId } : {}),
207
+ ...(context.params ? { params: context.params } : {}),
208
+ };
209
+ let verdict;
210
+ try {
211
+ verdict = await predicate(input, ctx);
212
+ }
213
+ catch {
214
+ return CONSTRAINT_FAILED_REASON;
215
+ }
216
+ if (verdict === true)
217
+ return tool.run(input, context);
218
+ if (typeof verdict === "string")
219
+ return verdict;
220
+ // Escalate to HITL ONLY on a genuine { approve: true } verdict.
221
+ if (typeof verdict === "object" &&
222
+ verdict !== null &&
223
+ verdict.approve === true) {
224
+ const gate = await gateToolOp(permissions, tool.name, buildArgsPreview(input));
225
+ if (!gate.allowed)
226
+ return gate.reason;
227
+ return tool.run(input, context);
228
+ }
229
+ // Any other value (false, undefined, { approve: false }, a number, …) is
230
+ // off-contract — fail closed rather than silently escalate or allow.
231
+ return CONSTRAINT_FAILED_REASON;
232
+ },
233
+ };
234
+ }
147
235
  async function emitPermissionInterrupt(args) {
148
236
  const interruptId = `perm-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
149
237
  const suggestedPattern = args.kind === "command"
150
238
  ? suggestedCommandPattern(args.command)
151
239
  : args.kind === "tool"
152
240
  ? args.toolName
153
- : suggestedPathPattern(args.path);
241
+ : args.kind === "memory"
242
+ ? suggestedMemoryPattern(args.namespace)
243
+ : suggestedPathPattern(args.path);
154
244
  const payload = {
155
245
  interruptId,
156
246
  type: "permission-request",
@@ -159,17 +249,28 @@ async function emitPermissionInterrupt(args) {
159
249
  ? { command: args.command, suggestedPattern }
160
250
  : args.kind === "tool"
161
251
  ? { toolName: args.toolName, argsPreview: args.argsPreview, suggestedPattern }
162
- : {
163
- operation: args.operation,
164
- path: args.path,
165
- suggestedPattern,
166
- },
252
+ : args.kind === "memory"
253
+ ? {
254
+ namespace: args.namespace,
255
+ identity: args.identity,
256
+ oldId: args.oldId,
257
+ oldContent: args.oldContent,
258
+ newContent: args.newContent,
259
+ suggestedPattern,
260
+ }
261
+ : { operation: args.operation, path: args.path, suggestedPattern },
167
262
  };
168
263
  const decision = interrupt(payload);
169
264
  if (decision === "deny")
170
265
  return "deny";
171
266
  if (decision === "always") {
172
- const tool = args.kind === "command" ? "bash" : args.kind === "tool" ? "tool" : args.operation;
267
+ const tool = args.kind === "command"
268
+ ? "bash"
269
+ : args.kind === "tool"
270
+ ? "tool"
271
+ : args.kind === "memory"
272
+ ? "memory"
273
+ : args.operation;
173
274
  await args.permissions.addAllow(tool, suggestedPattern);
174
275
  }
175
276
  return "allow";
@@ -19,8 +19,20 @@ export interface MemoryRecordLike {
19
19
  readonly updatedAt: string;
20
20
  readonly supersedes?: readonly string[];
21
21
  }
22
+ /**
23
+ * Pluggable text embedder for opt-in vector/semantic recall. Structural — the
24
+ * concrete implementations (`openaiEmbedder`, `fakeEmbedder`) live outside core.
25
+ */
26
+ export interface Embedder {
27
+ readonly id: string;
28
+ readonly dims: number;
29
+ embed(texts: readonly string[]): Promise<Float32Array[]>;
30
+ }
22
31
  export interface MemoryStoreLike {
23
- put(rec: MemoryRecordLike): Promise<void>;
32
+ put(rec: MemoryRecordLike, opts?: {
33
+ embedding?: Float32Array;
34
+ embeddingModel?: string;
35
+ }): Promise<void>;
24
36
  get(id: string): Promise<MemoryRecordLike | null>;
25
37
  search(q: {
26
38
  namespace: string;
@@ -31,14 +43,26 @@ export interface MemoryStoreLike {
31
43
  limit?: number;
32
44
  /** ISO recency reference for ranked searches; stores may ignore it. */
33
45
  now?: string;
46
+ /** When present, the store runs the hybrid keyword+vector path. */
47
+ queryEmbedding?: Float32Array;
48
+ /** Only rows whose stored embedding model equals this are vector-compared. */
49
+ embedderId?: string;
50
+ /** Hybrid ranking tuning; structural — the store validates. */
51
+ vector?: unknown;
34
52
  }): Promise<readonly MemoryRecordLike[]>;
35
53
  update(id: string, patch: Partial<MemoryRecordLike>): Promise<void>;
36
54
  supersede(id: string, bySupersedingId: string): Promise<void>;
37
55
  }
56
+ /**
57
+ * Memory write-governance mode. "ask" = auto's exact write semantics, except
58
+ * SUPERSEDEs (same identity, different value) pass a HITL gate first — a
59
+ * supervision affordance, not a security boundary (headless ≡ auto).
60
+ */
61
+ export type MemoryWritesMode = "off" | "candidate" | "auto" | "ask";
38
62
  export interface MemoryContext {
39
63
  readonly store: MemoryStoreLike;
40
64
  readonly namespace: string;
41
- readonly writes: "off" | "candidate" | "auto";
65
+ readonly writes: MemoryWritesMode;
42
66
  readonly defined: {
43
67
  readonly kind: string;
44
68
  readonly scope: readonly string[];
@@ -55,6 +79,21 @@ export interface MemoryContext {
55
79
  };
56
80
  readonly now: string;
57
81
  readonly indexMaxEntries?: number;
82
+ /** The resolved embedder when vector recall is enabled; the capability embeds
83
+ * writes + queries through it. Absent → keyword-only. */
84
+ readonly embedder?: Embedder;
85
+ /** Hybrid recall tuning threaded through to the store's search. All fields
86
+ * optional/defaulted; absent → store defaults. */
87
+ readonly vector?: {
88
+ readonly weights?: {
89
+ readonly keyword?: number;
90
+ readonly vector?: number;
91
+ };
92
+ readonly rrfK?: number;
93
+ readonly vectorK?: number;
94
+ readonly recencyWeight?: number;
95
+ readonly confidenceWeight?: number;
96
+ };
58
97
  }
59
98
  export interface CapabilityMarkerContext {
60
99
  readonly routeManifest: RouteManifest;
@@ -82,6 +121,8 @@ export interface DawnToolDefinition {
82
121
  readonly middleware?: Readonly<Record<string, unknown>>;
83
122
  readonly signal: AbortSignal;
84
123
  readonly fs?: WorkspaceFs;
124
+ readonly threadId?: string;
125
+ readonly params?: Readonly<Record<string, string>>;
85
126
  }) => Promise<unknown> | unknown;
86
127
  readonly schema?: unknown;
87
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/capabilities/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEpE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACtC,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IACjD,MAAM,CAAC,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QACxB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,uEAAuE;QACvE,GAAG,CAAC,EAAE,MAAM,CAAA;KACb,GAAG,OAAO,CAAC,SAAS,gBAAgB,EAAE,CAAC,CAAA;IACxC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,WAAW,GAAG,MAAM,CAAA;IAC7C,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;QACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KACtC,CAAA;IACD,6HAA6H;IAC7H,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,CACjB,IAAI,EAAE,OAAO,KAEX;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAC9D;QAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACnD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAA;IACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,SAAS,CAAA;IAC1C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAA;QACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAA;KAC5B,CAAA;IACD,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAA;IACvC,4IAA4I;IAC5I,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAA;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,CACZ,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;QACP,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACvD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;QAI5B,QAAQ,CAAC,EAAE,CAAC,EAAE,WAAW,CAAA;KAC1B,KACE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAA;IACvC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,MAAM,CAAA;IACrE;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAChC,QAAQ,CAAC,SAAS,EAAE,CAClB,KAAK,EAAE,sBAAsB,KAC1B,QAAQ,CAAC,uBAAuB,CAAC,GAAG,aAAa,CAAC,uBAAuB,CAAC,CAAA;CAChF;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;IAClD,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;IACxD,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAA;CAC/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACzF,QAAQ,CAAC,IAAI,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,KAC7B,OAAO,CAAC,sBAAsB,CAAC,CAAA;CACrC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/capabilities/types.ts"],"names":[],"mappings":"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"}