openclaw-engram 3.7.5 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/client.d.ts +55 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +380 -11
- package/dist/client.js.map +1 -1
- package/dist/commands/remember.d.ts.map +1 -1
- package/dist/commands/remember.js +6 -3
- package/dist/commands/remember.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/hooks/after-tool-call.d.ts +1 -1
- package/dist/hooks/after-tool-call.d.ts.map +1 -1
- package/dist/hooks/after-tool-call.js +9 -5
- package/dist/hooks/after-tool-call.js.map +1 -1
- package/dist/hooks/before-agent-start.d.ts.map +1 -1
- package/dist/hooks/before-agent-start.js +8 -4
- package/dist/hooks/before-agent-start.js.map +1 -1
- package/dist/hooks/before-compaction.d.ts +1 -1
- package/dist/hooks/before-compaction.d.ts.map +1 -1
- package/dist/hooks/before-compaction.js +9 -5
- package/dist/hooks/before-compaction.js.map +1 -1
- package/dist/hooks/before-prompt-build.d.ts.map +1 -1
- package/dist/hooks/before-prompt-build.js +7 -3
- package/dist/hooks/before-prompt-build.js.map +1 -1
- package/dist/hooks/before-tool-call.d.ts.map +1 -1
- package/dist/hooks/before-tool-call.js +18 -5
- package/dist/hooks/before-tool-call.js.map +1 -1
- package/dist/hooks/session-end.d.ts +1 -1
- package/dist/hooks/session-end.d.ts.map +1 -1
- package/dist/hooks/session-end.js +13 -5
- package/dist/hooks/session-end.js.map +1 -1
- package/dist/hooks/session-start.d.ts.map +1 -1
- package/dist/hooks/session-start.js +8 -4
- package/dist/hooks/session-start.js.map +1 -1
- package/dist/identity.d.ts +29 -8
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +274 -5
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -19
- package/dist/index.js.map +1 -1
- package/dist/project-identity-v3.d.ts +49 -0
- package/dist/project-identity-v3.d.ts.map +1 -0
- package/dist/project-identity-v3.js +228 -0
- package/dist/project-identity-v3.js.map +1 -0
- package/dist/project-identity-v3.test.d.ts +2 -0
- package/dist/project-identity-v3.test.d.ts.map +1 -0
- package/dist/project-identity-v3.test.js +160 -0
- package/dist/project-identity-v3.test.js.map +1 -0
- package/dist/services/file-watcher.d.ts +1 -1
- package/dist/services/file-watcher.d.ts.map +1 -1
- package/dist/services/file-watcher.js +9 -3
- package/dist/services/file-watcher.js.map +1 -1
- package/dist/tools/engram-decisions.d.ts.map +1 -1
- package/dist/tools/engram-decisions.js +6 -3
- package/dist/tools/engram-decisions.js.map +1 -1
- package/dist/tools/engram-issues.d.ts.map +1 -1
- package/dist/tools/engram-issues.js +11 -7
- package/dist/tools/engram-issues.js.map +1 -1
- package/dist/tools/engram-outcome.d.ts.map +1 -1
- package/dist/tools/engram-outcome.js +6 -2
- package/dist/tools/engram-outcome.js.map +1 -1
- package/dist/tools/engram-presets.d.ts.map +1 -1
- package/dist/tools/engram-presets.js +6 -3
- package/dist/tools/engram-presets.js.map +1 -1
- package/dist/tools/engram-remember.d.ts.map +1 -1
- package/dist/tools/engram-remember.js +6 -3
- package/dist/tools/engram-remember.js.map +1 -1
- package/dist/tools/engram-search.d.ts.map +1 -1
- package/dist/tools/engram-search.js +6 -3
- package/dist/tools/engram-search.js.map +1 -1
- package/dist/tools/engram-timeline.d.ts.map +1 -1
- package/dist/tools/engram-timeline.js +6 -3
- package/dist/tools/engram-timeline.js.map +1 -1
- package/dist/tools/engram-vault.d.ts.map +1 -1
- package/dist/tools/engram-vault.js +6 -3
- package/dist/tools/engram-vault.js.map +1 -1
- package/dist/tools/memory-get.d.ts.map +1 -1
- package/dist/tools/memory-get.js +11 -5
- package/dist/tools/memory-get.js.map +1 -1
- package/dist/tools/memory-migrate.d.ts.map +1 -1
- package/dist/tools/memory-migrate.js +6 -3
- package/dist/tools/memory-migrate.js.map +1 -1
- package/openclaw.plugin.json +21 -5
- package/package.json +1 -1
- package/scripts/check-publish-version.mjs +45 -0
- package/dist/tools/engram-find-by-file.d.ts +0 -12
- package/dist/tools/engram-find-by-file.d.ts.map +0 -1
- package/dist/tools/engram-find-by-file.js +0 -63
- package/dist/tools/engram-find-by-file.js.map +0 -1
package/README.md
CHANGED
|
@@ -68,6 +68,7 @@ All fields are set under `plugins.entries.engram.config`:
|
|
|
68
68
|
| `url` | string | `http://localhost:37777` | Engram server base URL |
|
|
69
69
|
| `token` | string | *(required)* | Bearer token for API authentication |
|
|
70
70
|
| `project` | string | *(auto-detected)* | Project scope override; defaults to workspace identity |
|
|
71
|
+
| `clientInstanceId` | string | *(optional)* | Opaque non-secret installation reference that enables V3 identity |
|
|
71
72
|
| `contextLimit` | number | `10` | Maximum observations injected per prompt turn |
|
|
72
73
|
| `sessionContextLimit` | number | `20` | Maximum observations injected at session start |
|
|
73
74
|
| `tokenBudget` | number | `2000` | Token budget for context injection (~4 chars/token) |
|
package/dist/client.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { AvailabilityTracker } from './availability.js';
|
|
8
8
|
import type { PluginConfig } from './config.js';
|
|
9
|
+
import { type ProjectIdentity, type ProjectIdentityV2 } from './identity.js';
|
|
10
|
+
import { type ProjectIdentityV3 } from './project-identity-v3.js';
|
|
9
11
|
export interface Observation {
|
|
10
12
|
id: number;
|
|
11
13
|
title: string;
|
|
@@ -91,6 +93,42 @@ export interface BulkImportResponse {
|
|
|
91
93
|
export interface BulkDeleteResponse {
|
|
92
94
|
deleted: number;
|
|
93
95
|
}
|
|
96
|
+
export interface ProjectRegistrationSuccess {
|
|
97
|
+
ok: true;
|
|
98
|
+
canonicalProject: string;
|
|
99
|
+
}
|
|
100
|
+
export interface ResolvedProjectRegistrationSuccess extends ProjectRegistrationSuccess {
|
|
101
|
+
projectSelector: string;
|
|
102
|
+
projectIdentityV2?: ProjectIdentityV2;
|
|
103
|
+
projectIdentityV3?: ProjectIdentityV3;
|
|
104
|
+
}
|
|
105
|
+
export interface ProjectRegistrationFailure {
|
|
106
|
+
ok: false;
|
|
107
|
+
error: {
|
|
108
|
+
code: string;
|
|
109
|
+
message: string;
|
|
110
|
+
upgradeAction: string;
|
|
111
|
+
httpStatus: number;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export type ProjectRegistrationResult = ProjectRegistrationSuccess | ProjectRegistrationFailure;
|
|
115
|
+
export type ResolvedProjectRegistrationResult = ResolvedProjectRegistrationSuccess | ProjectRegistrationFailure;
|
|
116
|
+
export interface OutcomeRetirement {
|
|
117
|
+
contract_version: 'engram.outcome-retirement.v1';
|
|
118
|
+
code: 'OUTCOME_CALLBACK_RETIRED';
|
|
119
|
+
action: 'upgrade_outcome_adapter';
|
|
120
|
+
}
|
|
121
|
+
export type OutcomeRecordingResult = boolean | OutcomeRetirement;
|
|
122
|
+
export declare function isOutcomeRetirement(result: OutcomeRecordingResult): result is OutcomeRetirement;
|
|
123
|
+
export interface ProjectRegistrationClient {
|
|
124
|
+
registerAndResolveProject(identity: ProjectIdentity, selector: string): Promise<ProjectRegistrationResult>;
|
|
125
|
+
readonly clientInstanceId?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Register an explicit project override as a selector-only shared scope.
|
|
129
|
+
* Without an override, resolve and register the workspace's full identity.
|
|
130
|
+
*/
|
|
131
|
+
export declare function resolveAndRegisterProject(client: ProjectRegistrationClient, agentId: string, workspaceDir: string | undefined, configuredProject?: string): Promise<ResolvedProjectRegistrationResult>;
|
|
94
132
|
/** A single observation returned by the decisions search endpoint. */
|
|
95
133
|
export interface DecisionSearchObservation {
|
|
96
134
|
title?: string;
|
|
@@ -157,13 +195,28 @@ export declare class EngramRestClient {
|
|
|
157
195
|
private readonly baseUrl;
|
|
158
196
|
private readonly token;
|
|
159
197
|
private readonly defaultTimeoutMs;
|
|
198
|
+
private readonly completedProjectRegistrations;
|
|
199
|
+
private readonly inFlightProjectRegistrations;
|
|
200
|
+
private readonly v3ContextDescriptors;
|
|
160
201
|
readonly availability: AvailabilityTracker;
|
|
202
|
+
readonly clientInstanceId?: string;
|
|
161
203
|
constructor(config: PluginConfig);
|
|
204
|
+
/**
|
|
205
|
+
* Registration barrier for every project-scoped OpenClaw access.
|
|
206
|
+
*
|
|
207
|
+
* The full identity and outer compatibility selector are resolved before a
|
|
208
|
+
* caller sends its first data request. Concurrent and late calls reuse the
|
|
209
|
+
* same result. Project metadata routes a namespace; the bearer header remains
|
|
210
|
+
* the independent authorization gate.
|
|
211
|
+
*/
|
|
212
|
+
registerAndResolveProject(identity: ProjectIdentity, selector: string): Promise<ProjectRegistrationResult>;
|
|
213
|
+
private performProjectRegistration;
|
|
214
|
+
private scopedProjectRequest;
|
|
162
215
|
/**
|
|
163
216
|
* Fetch session context for injection (static session-level context).
|
|
164
217
|
* POST /api/context/inject
|
|
165
218
|
*/
|
|
166
|
-
getContextInject(agentId: string, cwd?: string): Promise<ContextInjectResponse | null>;
|
|
219
|
+
getContextInject(agentId: string, cwd?: string, project?: string, projectIdentityV2?: ProjectIdentityV2): Promise<ContextInjectResponse | null>;
|
|
167
220
|
/**
|
|
168
221
|
* Per-turn context search.
|
|
169
222
|
* POST /api/context/search
|
|
@@ -275,7 +328,7 @@ export declare class EngramRestClient {
|
|
|
275
328
|
* POST /api/sessions/{sessionId}/outcome { outcome, reason }
|
|
276
329
|
* sessionId is the Claude session ID string (not numeric DB ID).
|
|
277
330
|
*/
|
|
278
|
-
setSessionOutcome(sessionId: string, outcome: string, reason?: string): Promise<
|
|
331
|
+
setSessionOutcome(sessionId: string, outcome: string, reason?: string): Promise<OutcomeRecordingResult>;
|
|
279
332
|
/**
|
|
280
333
|
* Get file-context observations for a specific file.
|
|
281
334
|
* GET /api/context/by-file?path={file}&project={project}&limit={limit}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -7,7 +7,64 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.EngramRestClient = void 0;
|
|
10
|
+
exports.isOutcomeRetirement = isOutcomeRetirement;
|
|
11
|
+
exports.resolveAndRegisterProject = resolveAndRegisterProject;
|
|
12
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
13
|
const availability_js_1 = require("./availability.js");
|
|
14
|
+
const identity_js_1 = require("./identity.js");
|
|
15
|
+
const project_identity_v3_js_1 = require("./project-identity-v3.js");
|
|
16
|
+
function isOutcomeRetirement(result) {
|
|
17
|
+
return typeof result !== 'boolean';
|
|
18
|
+
}
|
|
19
|
+
function parseOutcomeRetirement(payload) {
|
|
20
|
+
if (payload === null || typeof payload !== 'object')
|
|
21
|
+
return null;
|
|
22
|
+
const { contract_version, code, action } = payload;
|
|
23
|
+
if (contract_version !== 'engram.outcome-retirement.v1' ||
|
|
24
|
+
code !== 'OUTCOME_CALLBACK_RETIRED' ||
|
|
25
|
+
action !== 'upgrade_outcome_adapter')
|
|
26
|
+
return null;
|
|
27
|
+
return { contract_version, code, action };
|
|
28
|
+
}
|
|
29
|
+
function parseOutcomeRetirementPayload(text) {
|
|
30
|
+
try {
|
|
31
|
+
return parseOutcomeRetirement(JSON.parse(text));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register an explicit project override as a selector-only shared scope.
|
|
39
|
+
* Without an override, resolve and register the workspace's full identity.
|
|
40
|
+
*/
|
|
41
|
+
async function resolveAndRegisterProject(client, agentId, workspaceDir, configuredProject) {
|
|
42
|
+
try {
|
|
43
|
+
const clientInstanceId = client.clientInstanceId;
|
|
44
|
+
const identity = clientInstanceId !== undefined
|
|
45
|
+
? (0, identity_js_1.resolveIdentity)(agentId, workspaceDir, clientInstanceId)
|
|
46
|
+
: configuredProject !== undefined
|
|
47
|
+
? { projectId: configuredProject, agentId }
|
|
48
|
+
: (0, identity_js_1.resolveIdentity)(agentId, workspaceDir);
|
|
49
|
+
const selector = clientInstanceId !== undefined ? identity.projectId : configuredProject ?? identity.projectId;
|
|
50
|
+
const registration = await client.registerAndResolveProject(identity, selector);
|
|
51
|
+
if (!registration.ok)
|
|
52
|
+
return registration;
|
|
53
|
+
return {
|
|
54
|
+
...registration,
|
|
55
|
+
projectSelector: selector,
|
|
56
|
+
...(identity.projectIdentityV3 ? { projectIdentityV3: identity.projectIdentityV3 } : {}),
|
|
57
|
+
...(identity.projectIdentityV2 ? { projectIdentityV2: identity.projectIdentityV2 } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
62
|
+
if (message === 'PROJECT_DESCRIPTOR_INVALID')
|
|
63
|
+
return projectDescriptorFailure();
|
|
64
|
+
const invalid = message.startsWith('PROJECT_IDENTITY_INVALID:');
|
|
65
|
+
return projectRegistrationFailure(invalid ? 'PROJECT_IDENTITY_INVALID' : 'PROJECT_IDENTITY_UNAVAILABLE', message, invalid ? 'regenerate_project_identity_v2' : 'retry_project_identity_registration', invalid ? 400 : 503);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
11
68
|
// ---------------------------------------------------------------------------
|
|
12
69
|
// Client
|
|
13
70
|
// ---------------------------------------------------------------------------
|
|
@@ -15,28 +72,172 @@ class EngramRestClient {
|
|
|
15
72
|
baseUrl;
|
|
16
73
|
token;
|
|
17
74
|
defaultTimeoutMs;
|
|
75
|
+
completedProjectRegistrations = new Map();
|
|
76
|
+
inFlightProjectRegistrations = new Map();
|
|
77
|
+
v3ContextDescriptors = new Map();
|
|
18
78
|
availability;
|
|
79
|
+
clientInstanceId;
|
|
19
80
|
constructor(config) {
|
|
20
81
|
// Extract origin from potentially path-bearing URL
|
|
21
82
|
this.baseUrl = extractOrigin(config.url);
|
|
22
83
|
this.token = config.token;
|
|
23
84
|
this.defaultTimeoutMs = config.timeoutMs;
|
|
24
85
|
this.availability = new availability_js_1.AvailabilityTracker();
|
|
86
|
+
this.clientInstanceId = config.clientInstanceId;
|
|
25
87
|
}
|
|
26
88
|
// ---------------------------------------------------------------------------
|
|
27
89
|
// Endpoints
|
|
28
90
|
// ---------------------------------------------------------------------------
|
|
91
|
+
/**
|
|
92
|
+
* Registration barrier for every project-scoped OpenClaw access.
|
|
93
|
+
*
|
|
94
|
+
* The full identity and outer compatibility selector are resolved before a
|
|
95
|
+
* caller sends its first data request. Concurrent and late calls reuse the
|
|
96
|
+
* same result. Project metadata routes a namespace; the bearer header remains
|
|
97
|
+
* the independent authorization gate.
|
|
98
|
+
*/
|
|
99
|
+
async registerAndResolveProject(identity, selector) {
|
|
100
|
+
const requestedDescriptor = identity.projectIdentityV3;
|
|
101
|
+
let descriptor;
|
|
102
|
+
let validatedIdentity = identity;
|
|
103
|
+
if (requestedDescriptor !== undefined) {
|
|
104
|
+
const validatedDescriptor = validateProjectDescriptorV3(requestedDescriptor);
|
|
105
|
+
if (!validatedDescriptor)
|
|
106
|
+
return projectDescriptorFailure();
|
|
107
|
+
descriptor = validatedDescriptor;
|
|
108
|
+
validatedIdentity = { ...identity, projectIdentityV3: descriptor };
|
|
109
|
+
}
|
|
110
|
+
let validatedSelector = selector;
|
|
111
|
+
if (!descriptor) {
|
|
112
|
+
try {
|
|
113
|
+
validatedSelector = (0, identity_js_1.validateProjectSelectorV2)(selector);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return {
|
|
117
|
+
ok: false,
|
|
118
|
+
error: {
|
|
119
|
+
code: 'PROJECT_IDENTITY_INVALID',
|
|
120
|
+
message: 'project selector is empty or malformed',
|
|
121
|
+
upgradeAction: 'regenerate_project_identity_v2',
|
|
122
|
+
httpStatus: 400,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const key = JSON.stringify(descriptor ?? [validatedSelector, identity.projectIdentityV2 ?? null]);
|
|
128
|
+
const completed = this.completedProjectRegistrations.get(key);
|
|
129
|
+
if (completed)
|
|
130
|
+
return completed;
|
|
131
|
+
const inFlight = this.inFlightProjectRegistrations.get(key);
|
|
132
|
+
if (inFlight)
|
|
133
|
+
return inFlight;
|
|
134
|
+
const registration = this.performProjectRegistration(validatedIdentity, validatedSelector);
|
|
135
|
+
this.inFlightProjectRegistrations.set(key, registration);
|
|
136
|
+
try {
|
|
137
|
+
const result = await registration;
|
|
138
|
+
if (result.ok && descriptor) {
|
|
139
|
+
this.v3ContextDescriptors.set(selector, descriptor);
|
|
140
|
+
this.v3ContextDescriptors.set(result.canonicalProject, descriptor);
|
|
141
|
+
}
|
|
142
|
+
if (result.ok || result.error.httpStatus === 400 || result.error.httpStatus === 409) {
|
|
143
|
+
this.completedProjectRegistrations.set(key, result);
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
this.inFlightProjectRegistrations.delete(key);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async performProjectRegistration(identity, selector) {
|
|
152
|
+
if (!this.availability.isAvailable()) {
|
|
153
|
+
return projectRegistrationFailure('PROJECT_IDENTITY_UNAVAILABLE', 'engram is temporarily unavailable', 'retry_project_identity_registration', 503);
|
|
154
|
+
}
|
|
155
|
+
const path = '/api/context/inject';
|
|
156
|
+
const url = this.baseUrl + path;
|
|
157
|
+
const controller = new AbortController();
|
|
158
|
+
const timer = setTimeout(() => controller.abort(), this.defaultTimeoutMs);
|
|
159
|
+
const body = identity.projectIdentityV3
|
|
160
|
+
? {
|
|
161
|
+
project_descriptor: identity.projectIdentityV3,
|
|
162
|
+
identity_only: true,
|
|
163
|
+
}
|
|
164
|
+
: {
|
|
165
|
+
project: selector,
|
|
166
|
+
...(identity.projectIdentityV2 ? { project_identity: identity.projectIdentityV2 } : {}),
|
|
167
|
+
identity_only: true,
|
|
168
|
+
};
|
|
169
|
+
try {
|
|
170
|
+
const response = await fetch(url, {
|
|
171
|
+
method: 'POST',
|
|
172
|
+
headers: {
|
|
173
|
+
'Authorization': `Bearer ${this.token}`,
|
|
174
|
+
'Content-Type': 'application/json',
|
|
175
|
+
'X-Engram-Project-Identity-Adapter': 'openclaw',
|
|
176
|
+
'X-Request-ID': (0, node_crypto_1.randomUUID)(),
|
|
177
|
+
},
|
|
178
|
+
body: JSON.stringify(body),
|
|
179
|
+
signal: controller.signal,
|
|
180
|
+
});
|
|
181
|
+
const text = await response.text();
|
|
182
|
+
let payload = {};
|
|
183
|
+
if (text) {
|
|
184
|
+
try {
|
|
185
|
+
payload = JSON.parse(text);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
payload = {};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (!response.ok) {
|
|
192
|
+
if (response.status >= 500 || response.status === 401 || response.status === 403) {
|
|
193
|
+
this.availability.recordFailure();
|
|
194
|
+
}
|
|
195
|
+
const parsed = parseProjectRegistrationError(payload, response.status);
|
|
196
|
+
return projectRegistrationFailure(parsed.code, parsed.message, parsed.upgradeAction, response.status);
|
|
197
|
+
}
|
|
198
|
+
const canonical = readCanonicalProject(payload, identity.projectIdentityV3);
|
|
199
|
+
if (!canonical) {
|
|
200
|
+
this.availability.recordFailure();
|
|
201
|
+
return projectRegistrationFailure('PROJECT_IDENTITY_UNAVAILABLE', 'project identity registration response is malformed', 'retry_project_identity_registration', 503);
|
|
202
|
+
}
|
|
203
|
+
this.availability.recordSuccess();
|
|
204
|
+
return { ok: true, canonicalProject: canonical };
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
this.availability.recordFailure();
|
|
208
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
209
|
+
return projectRegistrationFailure('PROJECT_IDENTITY_UNAVAILABLE', message, 'retry_project_identity_registration', 503);
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
clearTimeout(timer);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
scopedProjectRequest(body) {
|
|
216
|
+
if (this.clientInstanceId === undefined)
|
|
217
|
+
return body;
|
|
218
|
+
const descriptor = this.v3ContextDescriptors.get(body.project);
|
|
219
|
+
if (!descriptor)
|
|
220
|
+
return null;
|
|
221
|
+
const { project: _, agent_id: _agentID, ...request } = body;
|
|
222
|
+
return { ...request, project_descriptor: descriptor };
|
|
223
|
+
}
|
|
29
224
|
/**
|
|
30
225
|
* Fetch session context for injection (static session-level context).
|
|
31
226
|
* POST /api/context/inject
|
|
32
227
|
*/
|
|
33
|
-
async getContextInject(agentId, cwd) {
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
228
|
+
async getContextInject(agentId, cwd, project, projectIdentityV2) {
|
|
229
|
+
// A V3 context request only reuses the descriptor carried through successful registration.
|
|
230
|
+
const projectDescriptor = project ? this.v3ContextDescriptors.get(project) : undefined;
|
|
231
|
+
if (this.clientInstanceId !== undefined && !projectDescriptor)
|
|
232
|
+
return null;
|
|
233
|
+
return this.post('/api/context/inject', projectDescriptor
|
|
234
|
+
? { project_descriptor: projectDescriptor }
|
|
235
|
+
: {
|
|
236
|
+
agent_id: agentId,
|
|
237
|
+
...(cwd ? { cwd } : {}),
|
|
238
|
+
...(project ? { project } : {}),
|
|
239
|
+
...(projectIdentityV2 ? { project_identity: projectIdentityV2 } : {}),
|
|
240
|
+
}, 15_000);
|
|
40
241
|
}
|
|
41
242
|
/**
|
|
42
243
|
* Per-turn context search.
|
|
@@ -44,7 +245,8 @@ class EngramRestClient {
|
|
|
44
245
|
*/
|
|
45
246
|
async searchContext(body) {
|
|
46
247
|
// Context search does vector query (embedding + pgvector) — needs more than default 5s.
|
|
47
|
-
|
|
248
|
+
const request = this.scopedProjectRequest(body);
|
|
249
|
+
return request ? this.post('/api/context/search', request, 15_000) : null;
|
|
48
250
|
}
|
|
49
251
|
/**
|
|
50
252
|
* Search for relevant decisions.
|
|
@@ -113,6 +315,8 @@ class EngramRestClient {
|
|
|
113
315
|
* synthetic one per call, preventing phantom session proliferation.
|
|
114
316
|
*/
|
|
115
317
|
async bulkImport(observations, sessionId) {
|
|
318
|
+
if (this.clientInstanceId !== undefined)
|
|
319
|
+
return null;
|
|
116
320
|
if (observations.length === 0)
|
|
117
321
|
return { imported: 0, skipped_duplicates: 0 };
|
|
118
322
|
// All observations in a batch must share the same project.
|
|
@@ -197,8 +401,49 @@ class EngramRestClient {
|
|
|
197
401
|
* sessionId is the Claude session ID string (not numeric DB ID).
|
|
198
402
|
*/
|
|
199
403
|
async setSessionOutcome(sessionId, outcome, reason) {
|
|
200
|
-
|
|
201
|
-
|
|
404
|
+
if (!this.availability.isAvailable())
|
|
405
|
+
return false;
|
|
406
|
+
const path = `/api/sessions/${encodeURIComponent(sessionId)}/outcome`;
|
|
407
|
+
const timeout = 3000;
|
|
408
|
+
const controller = new AbortController();
|
|
409
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
410
|
+
const startMs = Date.now();
|
|
411
|
+
try {
|
|
412
|
+
const response = await fetch(this.baseUrl + path, {
|
|
413
|
+
method: 'POST',
|
|
414
|
+
headers: {
|
|
415
|
+
Authorization: `Bearer ${this.token}`,
|
|
416
|
+
'Content-Type': 'application/json',
|
|
417
|
+
'X-Engram-Project-Identity-Adapter': 'openclaw',
|
|
418
|
+
'X-Request-ID': (0, node_crypto_1.randomUUID)(),
|
|
419
|
+
},
|
|
420
|
+
body: JSON.stringify({ outcome, reason: reason ?? '' }),
|
|
421
|
+
signal: controller.signal,
|
|
422
|
+
});
|
|
423
|
+
const text = await response.text();
|
|
424
|
+
if (response.status === 410) {
|
|
425
|
+
const retirement = parseOutcomeRetirementPayload(text);
|
|
426
|
+
if (retirement)
|
|
427
|
+
return retirement;
|
|
428
|
+
}
|
|
429
|
+
if (!response.ok) {
|
|
430
|
+
throw new Error(`HTTP ${response.status} ${response.statusText} (${Date.now() - startMs}ms): ${text.slice(0, 200)}`);
|
|
431
|
+
}
|
|
432
|
+
this.availability.recordSuccess();
|
|
433
|
+
return text ? JSON.parse(text) !== null : false;
|
|
434
|
+
}
|
|
435
|
+
catch (err) {
|
|
436
|
+
const elapsedMs = Date.now() - startMs;
|
|
437
|
+
this.availability.recordFailure();
|
|
438
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
439
|
+
const isAbort = err instanceof Error && err.name === 'AbortError';
|
|
440
|
+
console.error(`[engram] POST ${path} failed after ${elapsedMs}ms` +
|
|
441
|
+
`${isAbort ? ` (timeout=${timeout}ms)` : ''}: ${msg}`);
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
clearTimeout(timer);
|
|
446
|
+
}
|
|
202
447
|
}
|
|
203
448
|
/**
|
|
204
449
|
* Get file-context observations for a specific file.
|
|
@@ -221,7 +466,8 @@ class EngramRestClient {
|
|
|
221
466
|
body.anchor_id = params.anchor_id;
|
|
222
467
|
if (params?.limit)
|
|
223
468
|
body.limit = params.limit;
|
|
224
|
-
const
|
|
469
|
+
const request = this.scopedProjectRequest(body);
|
|
470
|
+
const resp = request ? await this.post('/api/context/search', request, 15_000) : null;
|
|
225
471
|
return resp?.observations ?? [];
|
|
226
472
|
}
|
|
227
473
|
/**
|
|
@@ -295,6 +541,8 @@ class EngramRestClient {
|
|
|
295
541
|
try {
|
|
296
542
|
const headers = {
|
|
297
543
|
'Authorization': `Bearer ${this.token}`,
|
|
544
|
+
'X-Engram-Project-Identity-Adapter': 'openclaw',
|
|
545
|
+
'X-Request-ID': (0, node_crypto_1.randomUUID)(),
|
|
298
546
|
};
|
|
299
547
|
if (body !== undefined) {
|
|
300
548
|
headers['Content-Type'] = 'application/json';
|
|
@@ -347,4 +595,125 @@ function extractOrigin(rawUrl) {
|
|
|
347
595
|
return trimmed.replace(/\/$/, '');
|
|
348
596
|
}
|
|
349
597
|
}
|
|
598
|
+
function projectRegistrationFailure(code, message, upgradeAction, httpStatus) {
|
|
599
|
+
return { ok: false, error: { code, message, upgradeAction, httpStatus } };
|
|
600
|
+
}
|
|
601
|
+
function projectDescriptorFailure() {
|
|
602
|
+
return projectRegistrationFailure('PROJECT_DESCRIPTOR_INVALID', 'project descriptor is invalid', 'repair_project_descriptor', 400);
|
|
603
|
+
}
|
|
604
|
+
const V3_DESCRIPTOR_FIELDS = {
|
|
605
|
+
version: true,
|
|
606
|
+
anchor_project_id: true,
|
|
607
|
+
name: true,
|
|
608
|
+
scope: true,
|
|
609
|
+
normalized_git_remotes: true,
|
|
610
|
+
legacy_identifiers: true,
|
|
611
|
+
client_instance_id: true,
|
|
612
|
+
};
|
|
613
|
+
const V3_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
614
|
+
const V3_PROJECT_RESOLUTION_FIELDS = {
|
|
615
|
+
outcome: true,
|
|
616
|
+
project_key: true,
|
|
617
|
+
resolved_scope: true,
|
|
618
|
+
correlation: true,
|
|
619
|
+
redirect_reference: true,
|
|
620
|
+
};
|
|
621
|
+
function isValidOpaqueReferenceV3(value) {
|
|
622
|
+
return typeof value === 'string' &&
|
|
623
|
+
value.length > 0 &&
|
|
624
|
+
Array.from(value).length <= 256 &&
|
|
625
|
+
!/[\p{White_Space}\p{Cc}\/\\@]/u.test(value);
|
|
626
|
+
}
|
|
627
|
+
function validateProjectDescriptorV3(descriptor) {
|
|
628
|
+
try {
|
|
629
|
+
if (typeof descriptor !== 'object' || descriptor === null || Array.isArray(descriptor))
|
|
630
|
+
return null;
|
|
631
|
+
const keys = Object.keys(descriptor);
|
|
632
|
+
if (keys.length !== 7 || keys.some((key) => !Object.hasOwn(V3_DESCRIPTOR_FIELDS, key)))
|
|
633
|
+
return null;
|
|
634
|
+
if (!('version' in descriptor) ||
|
|
635
|
+
!('anchor_project_id' in descriptor) ||
|
|
636
|
+
!('name' in descriptor) ||
|
|
637
|
+
!('scope' in descriptor) ||
|
|
638
|
+
!('normalized_git_remotes' in descriptor) ||
|
|
639
|
+
!('legacy_identifiers' in descriptor) ||
|
|
640
|
+
!('client_instance_id' in descriptor))
|
|
641
|
+
return null;
|
|
642
|
+
return (0, project_identity_v3_js_1.buildProjectIdentityV3)({
|
|
643
|
+
anchor: {
|
|
644
|
+
version: descriptor.version,
|
|
645
|
+
project_id: descriptor.anchor_project_id,
|
|
646
|
+
name: descriptor.name,
|
|
647
|
+
scope: descriptor.scope,
|
|
648
|
+
},
|
|
649
|
+
version: descriptor.version,
|
|
650
|
+
anchor_project_id: descriptor.anchor_project_id,
|
|
651
|
+
name: descriptor.name,
|
|
652
|
+
scope: descriptor.scope,
|
|
653
|
+
normalized_git_remotes: descriptor.normalized_git_remotes,
|
|
654
|
+
legacy_identifiers: descriptor.legacy_identifiers,
|
|
655
|
+
client_instance_id: descriptor.client_instance_id,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
catch {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
function readCanonicalProject(payload, descriptor) {
|
|
663
|
+
if (!payload || typeof payload !== 'object')
|
|
664
|
+
return '';
|
|
665
|
+
if (descriptor) {
|
|
666
|
+
if (!Object.hasOwn(payload, 'project_resolution_v3') || !('project_resolution_v3' in payload))
|
|
667
|
+
return '';
|
|
668
|
+
const resolution = payload.project_resolution_v3;
|
|
669
|
+
if (!resolution || typeof resolution !== 'object' || Array.isArray(resolution))
|
|
670
|
+
return '';
|
|
671
|
+
const typedResolution = resolution;
|
|
672
|
+
const keys = Object.keys(typedResolution);
|
|
673
|
+
if (keys.some((key) => !Object.hasOwn(V3_PROJECT_RESOLUTION_FIELDS, key)) ||
|
|
674
|
+
!Object.hasOwn(typedResolution, 'outcome') ||
|
|
675
|
+
!Object.hasOwn(typedResolution, 'project_key') ||
|
|
676
|
+
!Object.hasOwn(typedResolution, 'resolved_scope') ||
|
|
677
|
+
!Object.hasOwn(typedResolution, 'correlation'))
|
|
678
|
+
return '';
|
|
679
|
+
const { outcome, project_key, resolved_scope, correlation, redirect_reference: redirectReference } = typedResolution;
|
|
680
|
+
if ((outcome !== 'PROJECT_RESOLVED' && outcome !== 'PROJECT_REDIRECTED') ||
|
|
681
|
+
keys.length !== (outcome === 'PROJECT_REDIRECTED' ? 5 : 4) ||
|
|
682
|
+
typeof project_key !== 'string' ||
|
|
683
|
+
!V3_UUID.test(project_key) ||
|
|
684
|
+
resolved_scope !== descriptor.scope ||
|
|
685
|
+
!isValidOpaqueReferenceV3(correlation) ||
|
|
686
|
+
(outcome === 'PROJECT_REDIRECTED' && !isValidOpaqueReferenceV3(redirectReference)))
|
|
687
|
+
return '';
|
|
688
|
+
return project_key;
|
|
689
|
+
}
|
|
690
|
+
if (!('canonical_project' in payload))
|
|
691
|
+
return '';
|
|
692
|
+
try {
|
|
693
|
+
return (0, identity_js_1.validateCanonicalProjectV2)(payload.canonical_project);
|
|
694
|
+
}
|
|
695
|
+
catch {
|
|
696
|
+
return '';
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
function parseProjectRegistrationError(payload, status) {
|
|
700
|
+
const fallback = status === 400
|
|
701
|
+
? { code: 'PROJECT_IDENTITY_INVALID', upgradeAction: 'regenerate_project_identity_v2' }
|
|
702
|
+
: status === 409
|
|
703
|
+
? { code: 'PROJECT_IDENTITY_AMBIGUOUS', upgradeAction: 'send_project_identity_v2' }
|
|
704
|
+
: { code: 'PROJECT_IDENTITY_UNAVAILABLE', upgradeAction: 'retry_project_identity_registration' };
|
|
705
|
+
if (!payload || typeof payload !== 'object') {
|
|
706
|
+
return { ...fallback, message: `HTTP ${status} project identity registration failed` };
|
|
707
|
+
}
|
|
708
|
+
const error = payload.error;
|
|
709
|
+
if (!error || typeof error !== 'object') {
|
|
710
|
+
return { ...fallback, message: `HTTP ${status} project identity registration failed` };
|
|
711
|
+
}
|
|
712
|
+
const typed = error;
|
|
713
|
+
return {
|
|
714
|
+
code: typeof typed.code === 'string' ? typed.code : fallback.code,
|
|
715
|
+
message: typeof typed.message === 'string' ? typed.message : `HTTP ${status} project identity registration failed`,
|
|
716
|
+
upgradeAction: typeof typed.upgrade_action === 'string' ? typed.upgrade_action : fallback.upgradeAction,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
350
719
|
//# sourceMappingURL=client.js.map
|