aismemory 0.7.0 → 0.7.2
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 +11 -2
- package/dist/__tests__/agent-key-mode-e2e.test.js +78 -0
- package/dist/__tests__/agent-key-mode-e2e.test.js.map +1 -1
- package/dist/__tests__/agent-key-mode.test.js +63 -0
- package/dist/__tests__/agent-key-mode.test.js.map +1 -1
- package/dist/__tests__/agent-load-session-override-e2e.test.js +7 -5
- package/dist/__tests__/agent-load-session-override-e2e.test.js.map +1 -1
- package/dist/__tests__/agent-preference.test.js +99 -2
- package/dist/__tests__/agent-preference.test.js.map +1 -1
- package/dist/__tests__/ais-http.test.d.ts +1 -0
- package/dist/__tests__/ais-http.test.js +119 -0
- package/dist/__tests__/ais-http.test.js.map +1 -0
- package/dist/__tests__/auto-enroll-key.test.js +20 -0
- package/dist/__tests__/auto-enroll-key.test.js.map +1 -1
- package/dist/__tests__/delegated-read-args.test.d.ts +9 -0
- package/dist/__tests__/delegated-read-args.test.js +80 -0
- package/dist/__tests__/delegated-read-args.test.js.map +1 -0
- package/dist/__tests__/inbox-client.test.d.ts +1 -0
- package/dist/__tests__/inbox-client.test.js +108 -0
- package/dist/__tests__/inbox-client.test.js.map +1 -0
- package/dist/__tests__/key-auth.test.js +7 -1
- package/dist/__tests__/key-auth.test.js.map +1 -1
- package/dist/__tests__/provisional-register-mcp-remember.test.d.ts +1 -0
- package/dist/__tests__/provisional-register-mcp-remember.test.js +192 -0
- package/dist/__tests__/provisional-register-mcp-remember.test.js.map +1 -0
- package/dist/__tests__/reconnect-survival-e2e.test.d.ts +1 -0
- package/dist/__tests__/reconnect-survival-e2e.test.js +248 -0
- package/dist/__tests__/reconnect-survival-e2e.test.js.map +1 -0
- package/dist/__tests__/silent-renewal-e2e.test.js +12 -9
- package/dist/__tests__/silent-renewal-e2e.test.js.map +1 -1
- package/dist/__tests__/split-brain-upgrade-e2e.test.d.ts +1 -0
- package/dist/__tests__/split-brain-upgrade-e2e.test.js +206 -0
- package/dist/__tests__/split-brain-upgrade-e2e.test.js.map +1 -0
- package/dist/__tests__/token-manager.test.js +158 -1
- package/dist/__tests__/token-manager.test.js.map +1 -1
- package/dist/__tests__/tool-args.test.js +68 -1
- package/dist/__tests__/tool-args.test.js.map +1 -1
- package/dist/agent-key-mode.js +39 -5
- package/dist/agent-key-mode.js.map +1 -1
- package/dist/agent-preference.d.ts +36 -1
- package/dist/agent-preference.js +79 -3
- package/dist/agent-preference.js.map +1 -1
- package/dist/ais-http.d.ts +6 -0
- package/dist/ais-http.js +75 -0
- package/dist/ais-http.js.map +1 -0
- package/dist/inbox-client.d.ts +9 -0
- package/dist/inbox-client.js +74 -0
- package/dist/inbox-client.js.map +1 -0
- package/dist/index.js +189 -79
- package/dist/index.js.map +1 -1
- package/dist/key-auth.js +12 -6
- package/dist/key-auth.js.map +1 -1
- package/dist/token-manager.d.ts +33 -6
- package/dist/token-manager.js +115 -44
- package/dist/token-manager.js.map +1 -1
- package/dist/tool-args.d.ts +42 -0
- package/dist/tool-args.js +70 -0
- package/dist/tool-args.js.map +1 -1
- package/package.json +1 -1
package/dist/agent-key-mode.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Server-side contract (packages/agent-identity-service/src/api/middleware/
|
|
14
14
|
* agentApiKeyAuth.ts): the key authenticates ONLY
|
|
15
|
-
* `/v1/agents/:agentId/{memory,goals,dream,full-context}`, and only when
|
|
15
|
+
* `/v1/agents/:agentId/{memory,goals,dream,full-context,inbox}`, and only when
|
|
16
16
|
* :agentId equals the key's own agent. Every other route (tenant-wide agent
|
|
17
17
|
* listing, handoff, personality, key management, ...) is 403'd server-side.
|
|
18
18
|
* This module honors that scope client-side too: tools that need an
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { AisHttpError } from './ais-http-error.js';
|
|
23
23
|
import { emitTelemetry } from './telemetry.js';
|
|
24
|
-
import { parseEmptyToolArgs, parseRecallArgs, parseRememberArgs, } from './tool-args.js';
|
|
24
|
+
import { parseEmptyToolArgs, parseRecallArgs, parseFullContextArgs, parseRememberArgs, parseInboxSendArgs, parseInboxReadArgs, } from './tool-args.js';
|
|
25
|
+
import { readInboxAndMaybeAck } from './inbox-client.js';
|
|
25
26
|
/** Thrown by loadAgentApiKeyConfig when AIS_AGENT_API_KEY is set without AIS_AGENT_ID. */
|
|
26
27
|
export class AgentApiKeyConfigError extends Error {
|
|
27
28
|
constructor(message) {
|
|
@@ -146,11 +147,22 @@ export async function dispatchToolKeyMode(aisUrl, config, name, rawArgs, fetchIm
|
|
|
146
147
|
params.set('limit', String(args.limit));
|
|
147
148
|
if (args.type !== undefined)
|
|
148
149
|
params.set('types', args.type);
|
|
150
|
+
if (args.principalAgentId !== undefined) {
|
|
151
|
+
params.set('principalAgentId', args.principalAgentId);
|
|
152
|
+
}
|
|
149
153
|
return aisKeyGet(aisUrl, `/v1/agents/${agentId}/memory?${params}`, apiKey, fetchImpl);
|
|
150
154
|
}
|
|
151
|
-
case 'full_context':
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
case 'full_context': {
|
|
156
|
+
const fcArgs = parseFullContextArgs(rawArgs);
|
|
157
|
+
const fcParams = new URLSearchParams();
|
|
158
|
+
if (fcArgs.principalAgentId !== undefined)
|
|
159
|
+
fcParams.set('principalAgentId', fcArgs.principalAgentId);
|
|
160
|
+
if (fcArgs.memoriesLimit !== undefined)
|
|
161
|
+
fcParams.set('memoriesLimit', String(fcArgs.memoriesLimit));
|
|
162
|
+
const fcQs = fcParams.toString();
|
|
163
|
+
const fcPath = `/v1/agents/${agentId}/full-context${fcQs ? `?${fcQs}` : ''}`;
|
|
164
|
+
return aisKeyGet(aisUrl, fcPath, apiKey, fetchImpl);
|
|
165
|
+
}
|
|
154
166
|
case 'dream':
|
|
155
167
|
parseEmptyToolArgs(rawArgs);
|
|
156
168
|
return aisKeyPost(aisUrl, `/v1/agents/${agentId}/dream`, apiKey, {}, fetchImpl);
|
|
@@ -171,6 +183,28 @@ export async function dispatchToolKeyMode(aisUrl, config, name, rawArgs, fetchIm
|
|
|
171
183
|
},
|
|
172
184
|
};
|
|
173
185
|
}
|
|
186
|
+
case 'inbox_send': {
|
|
187
|
+
const args = parseInboxSendArgs(rawArgs);
|
|
188
|
+
return aisKeyPost(aisUrl, `/v1/agents/${agentId}/inbox`, apiKey, {
|
|
189
|
+
recipientAgentId: args.recipientAgentId,
|
|
190
|
+
kind: args.kind,
|
|
191
|
+
body: args.body,
|
|
192
|
+
...(args.threadId !== undefined ? { threadId: args.threadId } : {}),
|
|
193
|
+
...(args.taskId !== undefined ? { taskId: args.taskId } : {}),
|
|
194
|
+
...(args.inReplyTo !== undefined ? { inReplyTo: args.inReplyTo } : {}),
|
|
195
|
+
...(args.messageId !== undefined ? { messageId: args.messageId } : {}),
|
|
196
|
+
...(args.ttlSeconds !== undefined ? { ttlSeconds: args.ttlSeconds } : {}),
|
|
197
|
+
}, fetchImpl);
|
|
198
|
+
}
|
|
199
|
+
case 'inbox_read': {
|
|
200
|
+
const args = parseInboxReadArgs(rawArgs);
|
|
201
|
+
const params = new URLSearchParams();
|
|
202
|
+
if (args.cursor !== undefined)
|
|
203
|
+
params.set('cursor', args.cursor);
|
|
204
|
+
params.set('limit', String(args.limit));
|
|
205
|
+
params.set('unreadOnly', String(args.unreadOnly));
|
|
206
|
+
return readInboxAndMaybeAck(args, () => aisKeyGet(aisUrl, `/v1/agents/${agentId}/inbox?${params}`, apiKey, fetchImpl), (messageIds) => aisKeyPost(aisUrl, `/v1/agents/${agentId}/inbox/ack`, apiKey, { messageIds }, fetchImpl));
|
|
207
|
+
}
|
|
174
208
|
case 'handoff':
|
|
175
209
|
throw new OutOfScopeToolError('handoff', "the handoff route is outside the key's allowed scope (memory, goals, dream, full-context).");
|
|
176
210
|
case 'agent_load':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-key-mode.js","sourceRoot":"","sources":["../src/agent-key-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,iBAAiB,
|
|
1
|
+
{"version":3,"file":"agent-key-mode.js","sourceRoot":"","sources":["../src/agent-key-mode.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,18 +7,53 @@ export interface AgentPreference {
|
|
|
7
7
|
* Persist agent preference (schemaVersion + ids, no secrets) under
|
|
8
8
|
* ~/.aismemory/credentials.json with restrictive POSIX permissions
|
|
9
9
|
* (dir 0700, file 0600). Replaces legacy token-based persistence.
|
|
10
|
+
*
|
|
11
|
+
* F6 (CORBOT-48DD2E25): writes via a tmp file + renameSync so a crash
|
|
12
|
+
* mid-write can never leave a truncated/corrupt credentials.json behind,
|
|
13
|
+
* and two processes racing this same path never interleave partial writes
|
|
14
|
+
* (mirrors the atomic-write pattern in config.ts:59-62).
|
|
10
15
|
*/
|
|
11
16
|
export declare function saveAgentPreference(pref: {
|
|
12
17
|
agentId: string;
|
|
13
18
|
tenantId: string;
|
|
14
19
|
}, home?: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Migrate a legacy v1 credentials.json (token/agentId/tenantId/expiresAt) to
|
|
22
|
+
* the v2 schema (schemaVersion + ids only) IN PLACE, atomically — but ONLY
|
|
23
|
+
* when a device key is enrolled.
|
|
24
|
+
*
|
|
25
|
+
* F5a (CORBOT-48DD2E25): once a device key exists, the TokenManager mints
|
|
26
|
+
* its own tokens via key auth and the disk bearer is no longer needed —
|
|
27
|
+
* it must not survive past the first process start that observes both the
|
|
28
|
+
* v1 file and the enrolled key ("zero secrets at rest" was false for that
|
|
29
|
+
* window before this fix; the bearer used to live on disk until the next
|
|
30
|
+
* unrelated write).
|
|
31
|
+
*
|
|
32
|
+
* F5b (CORBOT-48DD2E25): when NO device key is enrolled, migrating here
|
|
33
|
+
* would strand that cohort with neither a live disk token nor a key to
|
|
34
|
+
* silently re-auth with — every silent stdio respawn would then demand a
|
|
35
|
+
* fresh browser bond, which 0.6.2 never did (it kept the token on disk and
|
|
36
|
+
* reconnected silently). So the v1 token is deliberately left in place
|
|
37
|
+
* until a key gets enrolled (this same check migrates it on the very next
|
|
38
|
+
* load) or a fresh device-flow completion overwrites the file.
|
|
39
|
+
*
|
|
40
|
+
* Best-effort: any read/parse/write failure is swallowed — migration must
|
|
41
|
+
* never block startup or credential loading. `home`/`hasKey` are
|
|
42
|
+
* parameterized for tests; production callers use the defaults.
|
|
43
|
+
*/
|
|
44
|
+
export declare function migrateCredentialsFileIfNeeded(home?: string, hasKey?: () => boolean): void;
|
|
15
45
|
/**
|
|
16
46
|
* Load agent preference from ~/.aismemory/credentials.json.
|
|
17
47
|
* Handles both v2 files (agentId/tenantId only) and legacy v1 files
|
|
18
48
|
* (token/agentId/tenantId/expiresAt) — returns ids only.
|
|
19
49
|
* Returns null if file is missing or corrupt.
|
|
50
|
+
*
|
|
51
|
+
* Triggers migrateCredentialsFileIfNeeded() first (F5a/F5b) so every
|
|
52
|
+
* caller on this path — including the TokenManager's per-acquire
|
|
53
|
+
* resolveIdentity() in index.ts — helps migrate a v1 file left over from
|
|
54
|
+
* before the device key was enrolled.
|
|
20
55
|
*/
|
|
21
|
-
export declare function loadAgentPreference(home?: string): {
|
|
56
|
+
export declare function loadAgentPreference(home?: string, hasKey?: () => boolean): {
|
|
22
57
|
agentId: string;
|
|
23
58
|
tenantId: string;
|
|
24
59
|
} | null;
|
package/dist/agent-preference.js
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
3
4
|
import { credentialsDir, credentialsFilePath } from './oauth-credentials.js';
|
|
5
|
+
import { hasEnrolledKey } from './key-auth.js';
|
|
6
|
+
/** Default hasKey() check for `home`, wired to the real on-disk key store. */
|
|
7
|
+
function defaultHasKey(home) {
|
|
8
|
+
return () => hasEnrolledKey({ keysDir: join(home, '.aismemory', 'keys') });
|
|
9
|
+
}
|
|
4
10
|
/**
|
|
5
11
|
* Persist agent preference (schemaVersion + ids, no secrets) under
|
|
6
12
|
* ~/.aismemory/credentials.json with restrictive POSIX permissions
|
|
7
13
|
* (dir 0700, file 0600). Replaces legacy token-based persistence.
|
|
14
|
+
*
|
|
15
|
+
* F6 (CORBOT-48DD2E25): writes via a tmp file + renameSync so a crash
|
|
16
|
+
* mid-write can never leave a truncated/corrupt credentials.json behind,
|
|
17
|
+
* and two processes racing this same path never interleave partial writes
|
|
18
|
+
* (mirrors the atomic-write pattern in config.ts:59-62).
|
|
8
19
|
*/
|
|
9
20
|
export function saveAgentPreference(pref, home = homedir()) {
|
|
10
21
|
const dir = credentialsDir(home);
|
|
11
22
|
const file = credentialsFilePath(home);
|
|
23
|
+
const tmp = `${file}.tmp`;
|
|
12
24
|
// Create directory with restrictive permissions (0700)
|
|
13
25
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
14
26
|
// Write the file with schemaVersion + ids (no legacy token/expiresAt)
|
|
@@ -17,19 +29,83 @@ export function saveAgentPreference(pref, home = homedir()) {
|
|
|
17
29
|
agentId: pref.agentId,
|
|
18
30
|
tenantId: pref.tenantId,
|
|
19
31
|
};
|
|
20
|
-
writeFileSync(
|
|
32
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
33
|
+
renameSync(tmp, file);
|
|
21
34
|
// chmod is the reliable path on POSIX
|
|
22
35
|
if (process.platform !== 'win32') {
|
|
23
36
|
chmodSync(file, 0o600);
|
|
24
37
|
}
|
|
25
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Migrate a legacy v1 credentials.json (token/agentId/tenantId/expiresAt) to
|
|
41
|
+
* the v2 schema (schemaVersion + ids only) IN PLACE, atomically — but ONLY
|
|
42
|
+
* when a device key is enrolled.
|
|
43
|
+
*
|
|
44
|
+
* F5a (CORBOT-48DD2E25): once a device key exists, the TokenManager mints
|
|
45
|
+
* its own tokens via key auth and the disk bearer is no longer needed —
|
|
46
|
+
* it must not survive past the first process start that observes both the
|
|
47
|
+
* v1 file and the enrolled key ("zero secrets at rest" was false for that
|
|
48
|
+
* window before this fix; the bearer used to live on disk until the next
|
|
49
|
+
* unrelated write).
|
|
50
|
+
*
|
|
51
|
+
* F5b (CORBOT-48DD2E25): when NO device key is enrolled, migrating here
|
|
52
|
+
* would strand that cohort with neither a live disk token nor a key to
|
|
53
|
+
* silently re-auth with — every silent stdio respawn would then demand a
|
|
54
|
+
* fresh browser bond, which 0.6.2 never did (it kept the token on disk and
|
|
55
|
+
* reconnected silently). So the v1 token is deliberately left in place
|
|
56
|
+
* until a key gets enrolled (this same check migrates it on the very next
|
|
57
|
+
* load) or a fresh device-flow completion overwrites the file.
|
|
58
|
+
*
|
|
59
|
+
* Best-effort: any read/parse/write failure is swallowed — migration must
|
|
60
|
+
* never block startup or credential loading. `home`/`hasKey` are
|
|
61
|
+
* parameterized for tests; production callers use the defaults.
|
|
62
|
+
*/
|
|
63
|
+
export function migrateCredentialsFileIfNeeded(home = homedir(), hasKey = defaultHasKey(home)) {
|
|
64
|
+
const file = credentialsFilePath(home);
|
|
65
|
+
try {
|
|
66
|
+
if (!existsSync(file))
|
|
67
|
+
return;
|
|
68
|
+
const raw = readFileSync(file, 'utf-8');
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
// Already v2 (or an unrecognized shape) — nothing to migrate.
|
|
71
|
+
if (typeof parsed['token'] !== 'string')
|
|
72
|
+
return;
|
|
73
|
+
const agentId = parsed['agentId'];
|
|
74
|
+
const tenantId = parsed['tenantId'];
|
|
75
|
+
if (typeof agentId !== 'string' || typeof tenantId !== 'string')
|
|
76
|
+
return;
|
|
77
|
+
// F5b: do not strand the no-enrolled-key cohort.
|
|
78
|
+
if (!hasKey())
|
|
79
|
+
return;
|
|
80
|
+
const dir = credentialsDir(home);
|
|
81
|
+
const tmp = `${file}.tmp`;
|
|
82
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
83
|
+
const data = { schemaVersion: 2, agentId, tenantId };
|
|
84
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
85
|
+
renameSync(tmp, file);
|
|
86
|
+
if (process.platform !== 'win32') {
|
|
87
|
+
chmodSync(file, 0o600);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Best-effort — a migration failure must never block startup. The
|
|
92
|
+
// existing v1-tolerant parse in loadAgentPreference (below) and
|
|
93
|
+
// loadCredentials (index.ts) still work even if migration didn't run.
|
|
94
|
+
}
|
|
95
|
+
}
|
|
26
96
|
/**
|
|
27
97
|
* Load agent preference from ~/.aismemory/credentials.json.
|
|
28
98
|
* Handles both v2 files (agentId/tenantId only) and legacy v1 files
|
|
29
99
|
* (token/agentId/tenantId/expiresAt) — returns ids only.
|
|
30
100
|
* Returns null if file is missing or corrupt.
|
|
101
|
+
*
|
|
102
|
+
* Triggers migrateCredentialsFileIfNeeded() first (F5a/F5b) so every
|
|
103
|
+
* caller on this path — including the TokenManager's per-acquire
|
|
104
|
+
* resolveIdentity() in index.ts — helps migrate a v1 file left over from
|
|
105
|
+
* before the device key was enrolled.
|
|
31
106
|
*/
|
|
32
|
-
export function loadAgentPreference(home = homedir()) {
|
|
107
|
+
export function loadAgentPreference(home = homedir(), hasKey = defaultHasKey(home)) {
|
|
108
|
+
migrateCredentialsFileIfNeeded(home, hasKey);
|
|
33
109
|
const file = credentialsFilePath(home);
|
|
34
110
|
try {
|
|
35
111
|
if (!existsSync(file))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-preference.js","sourceRoot":"","sources":["../src/agent-preference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-preference.js","sourceRoot":"","sources":["../src/agent-preference.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIS HTTP helpers — extracted from index.ts for reuse without MCP side effects.
|
|
3
|
+
* CORBOT-282AE4FE
|
|
4
|
+
*/
|
|
5
|
+
export declare function aisPost(path: string, body: unknown, token?: string): Promise<unknown>;
|
|
6
|
+
export declare function aisGet(path: string, token: string): Promise<unknown>;
|
package/dist/ais-http.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIS HTTP helpers — extracted from index.ts for reuse without MCP side effects.
|
|
3
|
+
* CORBOT-282AE4FE
|
|
4
|
+
*/
|
|
5
|
+
import { isAuthErrorResult } from './auth-staleness.js';
|
|
6
|
+
import { AisHttpError } from './ais-http-error.js';
|
|
7
|
+
import { emitTelemetry } from './telemetry.js';
|
|
8
|
+
const AIS_URL = process.env['AIS_URL'] ?? 'https://ais.agentsandswarms.ai';
|
|
9
|
+
export async function aisPost(path, body, token) {
|
|
10
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
11
|
+
if (token)
|
|
12
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
13
|
+
let res;
|
|
14
|
+
try {
|
|
15
|
+
res = await fetch(`${AIS_URL}${path}`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers,
|
|
18
|
+
body: JSON.stringify(body),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
emitTelemetry({
|
|
23
|
+
event: 'ais.http.failure',
|
|
24
|
+
path,
|
|
25
|
+
error: err instanceof Error ? err.message : String(err),
|
|
26
|
+
});
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
const data = await res.json().catch(() => null);
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
emitTelemetry({
|
|
32
|
+
event: 'ais.http.failure',
|
|
33
|
+
path,
|
|
34
|
+
httpStatus: res.status,
|
|
35
|
+
error: `HTTP ${res.status}`,
|
|
36
|
+
});
|
|
37
|
+
// Token-rejection bodies feed the silent re-auth-and-retry loop; every
|
|
38
|
+
// other non-2xx must throw so a failed write surfaces as an MCP error
|
|
39
|
+
// instead of being mistaken for a successful one.
|
|
40
|
+
if (isAuthErrorResult(data))
|
|
41
|
+
return data;
|
|
42
|
+
throw new AisHttpError(res.status, path, data);
|
|
43
|
+
}
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
export async function aisGet(path, token) {
|
|
47
|
+
let res;
|
|
48
|
+
try {
|
|
49
|
+
res = await fetch(`${AIS_URL}${path}`, {
|
|
50
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
emitTelemetry({
|
|
55
|
+
event: 'ais.http.failure',
|
|
56
|
+
path,
|
|
57
|
+
error: err instanceof Error ? err.message : String(err),
|
|
58
|
+
});
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
const data = await res.json().catch(() => null);
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
emitTelemetry({
|
|
64
|
+
event: 'ais.http.failure',
|
|
65
|
+
path,
|
|
66
|
+
httpStatus: res.status,
|
|
67
|
+
error: `HTTP ${res.status}`,
|
|
68
|
+
});
|
|
69
|
+
if (isAuthErrorResult(data))
|
|
70
|
+
return data;
|
|
71
|
+
throw new AisHttpError(res.status, path, data);
|
|
72
|
+
}
|
|
73
|
+
return data;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=ais-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ais-http.js","sourceRoot":"","sources":["../src/ais-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InboxReadArgs } from './tool-args.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reads one inbox page via `getPage`, then acks the returned messageIds via
|
|
4
|
+
* `ackMessages` when `args.ack` is set. Both callbacks return AIS's raw
|
|
5
|
+
* response body (as `aisGet`/`aisPost`/`aisKeyGet`/`aisKeyPost` already do);
|
|
6
|
+
* an auth-error body from either call is returned as-is so the caller's
|
|
7
|
+
* existing re-auth-and-retry loop (`isAuthErrorResult`) still fires.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readInboxAndMaybeAck(args: InboxReadArgs, getPage: () => Promise<unknown>, ackMessages: (messageIds: string[]) => Promise<unknown>): Promise<unknown>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side composition for `inbox_read` (CORBOT-7115B8AE).
|
|
3
|
+
*
|
|
4
|
+
* AIS's own `inbox_read` MCP handler
|
|
5
|
+
* (agent-identity-service/src/mcp/handlers/agent-inbox-handlers.ts) folds a
|
|
6
|
+
* conditional ack into one call because it already holds the
|
|
7
|
+
* AgentMessageService in-process. This package instead talks to AIS over
|
|
8
|
+
* REST (GET /v1/agents/:agentId/inbox, POST .../inbox/ack), so the same
|
|
9
|
+
* "read a page, then ack what it returned" composition has to happen here —
|
|
10
|
+
* shaped to match handleInboxRead's result exactly (messages, nextCursor,
|
|
11
|
+
* unreadRemaining?, acked?) so a caller sees the same contract regardless of
|
|
12
|
+
* which AIS entrypoint served it.
|
|
13
|
+
*/
|
|
14
|
+
import { isAuthErrorResult } from './auth-staleness.js';
|
|
15
|
+
/** Mirrors AIS core/inbox/types.ts MAX_ACK_IDS. A page never exceeds it (MAX_PAGE_SIZE === MAX_ACK_IDS), so no chunking is needed. */
|
|
16
|
+
const MAX_ACK_IDS = 100;
|
|
17
|
+
function isInboxMessageArray(value) {
|
|
18
|
+
return (Array.isArray(value) &&
|
|
19
|
+
value.every((item) => typeof item === 'object' && item !== null && typeof item.messageId === 'string'));
|
|
20
|
+
}
|
|
21
|
+
function isInboxListResponse(value) {
|
|
22
|
+
if (typeof value !== 'object' || value === null)
|
|
23
|
+
return false;
|
|
24
|
+
const r = value;
|
|
25
|
+
if (r.success !== true || typeof r.data !== 'object' || r.data === null)
|
|
26
|
+
return false;
|
|
27
|
+
const d = r.data;
|
|
28
|
+
return isInboxMessageArray(d.messages) && (typeof d.nextCursor === 'string' || d.nextCursor === null) && typeof d.hasMore === 'boolean';
|
|
29
|
+
}
|
|
30
|
+
function isAckResponse(value) {
|
|
31
|
+
if (typeof value !== 'object' || value === null)
|
|
32
|
+
return false;
|
|
33
|
+
const r = value;
|
|
34
|
+
if (r.success !== true || typeof r.data !== 'object' || r.data === null)
|
|
35
|
+
return false;
|
|
36
|
+
const acked = r.data.acked;
|
|
37
|
+
return Array.isArray(acked) && acked.every((id) => typeof id === 'string');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Reads one inbox page via `getPage`, then acks the returned messageIds via
|
|
41
|
+
* `ackMessages` when `args.ack` is set. Both callbacks return AIS's raw
|
|
42
|
+
* response body (as `aisGet`/`aisPost`/`aisKeyGet`/`aisKeyPost` already do);
|
|
43
|
+
* an auth-error body from either call is returned as-is so the caller's
|
|
44
|
+
* existing re-auth-and-retry loop (`isAuthErrorResult`) still fires.
|
|
45
|
+
*/
|
|
46
|
+
export async function readInboxAndMaybeAck(args, getPage, ackMessages) {
|
|
47
|
+
const page = await getPage();
|
|
48
|
+
if (isAuthErrorResult(page))
|
|
49
|
+
return page;
|
|
50
|
+
if (!isInboxListResponse(page)) {
|
|
51
|
+
// AIS's response envelope changed shape underneath us — surface it
|
|
52
|
+
// verbatim rather than guessing, same as every other tool's `result`.
|
|
53
|
+
return page;
|
|
54
|
+
}
|
|
55
|
+
const { messages, nextCursor, hasMore } = page.data;
|
|
56
|
+
const result = { messages, nextCursor };
|
|
57
|
+
if (args.ack && messages.length > 0) {
|
|
58
|
+
const ids = messages.slice(0, MAX_ACK_IDS).map((m) => m.messageId);
|
|
59
|
+
const ackResult = await ackMessages(ids);
|
|
60
|
+
if (isAuthErrorResult(ackResult))
|
|
61
|
+
return ackResult;
|
|
62
|
+
result.acked = isAckResponse(ackResult) ? ackResult.data.acked : ids;
|
|
63
|
+
}
|
|
64
|
+
else if (args.ack) {
|
|
65
|
+
result.acked = [];
|
|
66
|
+
}
|
|
67
|
+
// Exact only when this read reached the end of the unread stream — see
|
|
68
|
+
// handleInboxRead's identical comment in agent-inbox-handlers.ts.
|
|
69
|
+
if (args.unreadOnly && !hasMore) {
|
|
70
|
+
result.unreadRemaining = args.ack ? 0 : messages.length;
|
|
71
|
+
}
|
|
72
|
+
return { success: true, data: result };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=inbox-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-client.js","sourceRoot":"","sources":["../src/inbox-client.ts"],"names":[],"mappings":"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"}
|