@tpsdev-ai/flair 0.44.4 → 0.44.6
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/dist/cli.js +47 -10
- package/dist/doctor-client.js +75 -0
- package/dist/resources/mcp-tools.js +67 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ import { detectClients, renderWiringSummary, wireClaudeCode, wireCodex, wireGemi
|
|
|
23
23
|
import { flairCliVersion, clearFlairCliVersionCache, mcpServerSpec, unpinnedSpecWarning } from "./lib/mcp-spec.js";
|
|
24
24
|
import { resolveAgentKeyPath, loadEd25519PrivateKeyFromFile, signClientAssertion, buildTokenRequestForm, getMcpAccessToken, McpTokenRequestError, defaultMcpClientId, defaultMcpTokenEndpoint, defaultMcpResource, defaultMcpIssuer, MAX_ASSERTION_LIFETIME_SECONDS, } from "./mcp-client-assertion.js";
|
|
25
25
|
import { enableMcp, disableMcp, mcpStatus, checkLocalOriginRefusal, selfVerifyMcpMetadata, } from "./lib/mcp-enable.js";
|
|
26
|
-
import { readClientMcpBlock, checkClaudeMdBootstrap, inspectSessionStartHook, upgradeSessionStartHookCommand, fixClaudeMdBootstrap, fixSessionStartHook, applyOrReportClaudeMdBootstrap, applyOrReportSessionStartHook, resolveWireFlairUrl, planAgentIterations,
|
|
26
|
+
import { readClientMcpBlock, checkClaudeMdBootstrap, inspectSessionStartHook, upgradeSessionStartHookCommand, fixClaudeMdBootstrap, fixSessionStartHook, applyOrReportClaudeMdBootstrap, applyOrReportSessionStartHook, resolveWireFlairUrl, planAgentIterations, fixCommandAgentHint, isNodeKeyId, partitionKeyIds, resolveFixAgentId, describeAgentGateFinding, embeddingsSkipRemedy, classifyKeyFile, resolveCollisionSafeName, pruneDateStamp, PRUNED_DIR_NAME, } from "./doctor-client.js";
|
|
27
27
|
import { installHook, uninstallHook, hookStatus, isSupportedHarness, SUPPORTED_HARNESSES, } from "./hook-install.js";
|
|
28
28
|
import { readSecretFileSecure, readAdminPassFileSecure, defaultAdminPassPath, defaultKeysDir, resolveLocalAdminPass, resolveKeyPath, buildEd25519Auth, authFetch, KeyLoadError, isLocalBase, authedRequest, } from "./lib/auth-resolve.js";
|
|
29
29
|
import { resolveSigningIdentity, emitSigningIdentityDebug, } from "./lib/signing-identity.js";
|
|
@@ -1503,8 +1503,12 @@ export async function verifySemanticSearch(baseUrl, agentIdOpt, keysDir) {
|
|
|
1503
1503
|
if (!agentId) {
|
|
1504
1504
|
try {
|
|
1505
1505
|
const keyFiles = readdirSync(keysDir).filter((f) => f.endsWith(".key"));
|
|
1506
|
-
|
|
1507
|
-
|
|
1506
|
+
// Skip node-scoped federation keys (flair#1193): they can't sign, so
|
|
1507
|
+
// picking one here would fail the probe with a decode error that reads
|
|
1508
|
+
// like a semantic-search regression rather than "no agent to sign as".
|
|
1509
|
+
const agentKeyFile = keyFiles.find((f) => !isNodeKeyId(f.replace(/\.key$/, ""), keysDir));
|
|
1510
|
+
if (agentKeyFile)
|
|
1511
|
+
agentId = agentKeyFile.replace(/\.key$/, "");
|
|
1508
1512
|
}
|
|
1509
1513
|
catch { /* keysDir missing */ }
|
|
1510
1514
|
}
|
|
@@ -9796,8 +9800,12 @@ program
|
|
|
9796
9800
|
await (async () => {
|
|
9797
9801
|
const agentId = resolveAgentIdOrEnv({}) ?? (() => {
|
|
9798
9802
|
try {
|
|
9799
|
-
const
|
|
9800
|
-
|
|
9803
|
+
const kd = defaultKeysDir();
|
|
9804
|
+
const keyFiles = readdirSync(kd).filter((f) => f.endsWith(".key"));
|
|
9805
|
+
// Node-scoped federation keys aren't agents (flair#1193) — never
|
|
9806
|
+
// pin-refresh a connector as one.
|
|
9807
|
+
const agentKeyFile = keyFiles.find((f) => !isNodeKeyId(f.replace(/\.key$/, ""), kd));
|
|
9808
|
+
return agentKeyFile ? agentKeyFile.replace(/\.key$/, "") : null;
|
|
9801
9809
|
}
|
|
9802
9810
|
catch {
|
|
9803
9811
|
return null;
|
|
@@ -11843,9 +11851,27 @@ program
|
|
|
11843
11851
|
const keysDir = defaultKeysDir();
|
|
11844
11852
|
if (existsSync(keysDir)) {
|
|
11845
11853
|
const keyFiles = (await import("node:fs")).readdirSync(keysDir).filter((f) => f.endsWith(".key"));
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11854
|
+
// ~/.flair/keys is shared by agent Ed25519 signing keys and node-scoped
|
|
11855
|
+
// federation keys (flair#1193). Only agent keys are signing identities;
|
|
11856
|
+
// node keys are AES-GCM keystore blobs that must never be parsed as, or
|
|
11857
|
+
// inferred as, an agent. Partition them out here so every downstream
|
|
11858
|
+
// consumer of keyAgentIds (registration checks, --fix inference,
|
|
11859
|
+
// fixCommandAgentHint) is node-free by construction.
|
|
11860
|
+
const { agentKeyIds, nodeKeyIds } = partitionKeyIds(keyFiles.map((f) => f.replace(/\.key$/, "")), keysDir);
|
|
11861
|
+
keyAgentIds = agentKeyIds;
|
|
11862
|
+
if (agentKeyIds.length > 0) {
|
|
11863
|
+
console.log(` ${render.icons.ok} Keys found: ${render.wrap(render.c.bold, String(agentKeyIds.length))} agent(s) in ${render.wrap(render.c.dim, keysDir)}`);
|
|
11864
|
+
if (nodeKeyIds.length > 0) {
|
|
11865
|
+
console.log(` ${render.icons.info} ${render.wrap(render.c.dim, `${nodeKeyIds.length} node-scoped federation key(s) present — not agent signing keys; skipping`)}`);
|
|
11866
|
+
}
|
|
11867
|
+
}
|
|
11868
|
+
else if (nodeKeyIds.length > 0) {
|
|
11869
|
+
// Node keys but no agent key: functionally there is no agent identity
|
|
11870
|
+
// here. Report it plainly (not the old DECODER false alarm) and point
|
|
11871
|
+
// at the real remedy. Kept a warn — not an issues++ — so a genuine
|
|
11872
|
+
// federation-only host doesn't newly fail doctor's exit code.
|
|
11873
|
+
console.log(` ${render.icons.warn} No agent signing key found — only ${render.wrap(render.c.bold, String(nodeKeyIds.length))} node-scoped federation key(s) in ${render.wrap(render.c.dim, keysDir)}`);
|
|
11874
|
+
console.log(` ${render.wrap(render.c.dim, "These are Fabric node keys, not agent identities. Fix:")} flair init --agent-id <your-agent>`);
|
|
11849
11875
|
}
|
|
11850
11876
|
else {
|
|
11851
11877
|
console.log(` ${render.icons.error} Keys directory exists but no .key files found`);
|
|
@@ -12103,13 +12129,24 @@ program
|
|
|
12103
12129
|
// nothing else identifies one — the only case doctor can
|
|
12104
12130
|
// infer without being told (see inferSoleAgentId's doc
|
|
12105
12131
|
// comment in doctor-client.ts for why 0/2+ keys don't guess).
|
|
12106
|
-
|
|
12132
|
+
// flair#1193: resolveFixAgentId additionally refuses a
|
|
12133
|
+
// node-scoped federation id from ANY source (inference, env,
|
|
12134
|
+
// or a wired block a prior buggy run may have poisoned) — a
|
|
12135
|
+
// node id can't sign, so wiring it would authenticate the
|
|
12136
|
+
// connector as a phantom unregistered node.
|
|
12137
|
+
const fixAgentId = resolveFixAgentId({
|
|
12138
|
+
optsAgent: opts.agent,
|
|
12139
|
+
envAgentId: process.env.FLAIR_AGENT_ID,
|
|
12140
|
+
anyKnownAgentId,
|
|
12141
|
+
keyAgentIds,
|
|
12142
|
+
keysDir: defaultKeysDir(),
|
|
12143
|
+
});
|
|
12107
12144
|
if (!fixAgentId) {
|
|
12108
12145
|
if (keyAgentIds.length > 1) {
|
|
12109
12146
|
console.log(` ${render.icons.warn} Cannot auto-wire ${client.label}: multiple agents found (${[...keyAgentIds].sort().join(", ")}) — pass --agent <id> to choose which one`);
|
|
12110
12147
|
}
|
|
12111
12148
|
else {
|
|
12112
|
-
console.log(` ${render.icons.warn} Cannot auto-wire ${client.label}: no agent
|
|
12149
|
+
console.log(` ${render.icons.warn} Cannot auto-wire ${client.label}: no agent identity found in keys/ — run \`flair init --agent <name>\` or \`flair agent add <name>\` before wiring a connector`);
|
|
12113
12150
|
}
|
|
12114
12151
|
}
|
|
12115
12152
|
else {
|
package/dist/doctor-client.js
CHANGED
|
@@ -907,3 +907,78 @@ export function classifyKeyFile(agentId, seedValid, registration, baseUrl) {
|
|
|
907
907
|
reason: `agent '${agentId}' is not registered on ${baseUrl}${registration?.detail ? ` (${registration.detail})` : ""}`,
|
|
908
908
|
};
|
|
909
909
|
}
|
|
910
|
+
// ── Node-scoped federation keys vs agent signing keys (flair#1193) ─────────
|
|
911
|
+
//
|
|
912
|
+
// `~/.flair/keys/` is a namespace shared by two writers with two file shapes:
|
|
913
|
+
//
|
|
914
|
+
// • agent Ed25519 signing keys — a 32-byte raw seed at `<name>.key`, ALWAYS
|
|
915
|
+
// written together with a sibling `<name>.pub` (see the keypair write in
|
|
916
|
+
// src/cli.ts: the seed and the public key are emitted in the same block).
|
|
917
|
+
// • node-scoped federation keys — `flair_<hex8>.key`, an AES-256-GCM
|
|
918
|
+
// keystore blob written by FileKeyStore during Fabric provisioning
|
|
919
|
+
// (flair#1026). The id is minted as `flair_${randomBytes(4).toString("hex")}`
|
|
920
|
+
// in resources/Federation.ts, and NO `.pub` is ever written for it.
|
|
921
|
+
//
|
|
922
|
+
// Nothing used to tell them apart, so doctor tried to Ed25519-parse the node
|
|
923
|
+
// blob — a "DECODER routines::unsupported" warning that reads as agent-auth
|
|
924
|
+
// breakage when agent auth is fine — and `doctor --fix` could infer the node
|
|
925
|
+
// id as the sole "agent" and wire it as a connector identity, authenticating
|
|
926
|
+
// as a phantom, unregistered node whose key cannot sign (flair#1193).
|
|
927
|
+
//
|
|
928
|
+
// The guard is STRUCTURAL, not a parse attempt: a node id matches
|
|
929
|
+
// `flair_<hex8>` AND has no sibling `.pub`. We deliberately do NOT classify by
|
|
930
|
+
// parsing the file and treating a decode failure as "must be a node key" —
|
|
931
|
+
// that is the exact fails-open move flair#1026 warns against (a genuinely
|
|
932
|
+
// corrupt agent key would be misread as a node key and silently skipped).
|
|
933
|
+
// A real agent always has a `.pub`; a node key never does, so `.pub` presence
|
|
934
|
+
// is the primary, falsifiable signal and classification never depends on the
|
|
935
|
+
// parse-failure of the thing being classified.
|
|
936
|
+
/** The shape a Fabric node id always has: `flair_` + 8 lowercase hex chars. */
|
|
937
|
+
const NODE_KEY_ID_RE = /^flair_[0-9a-f]{8}$/;
|
|
938
|
+
/**
|
|
939
|
+
* True iff `id` names a node-scoped federation key rather than an agent
|
|
940
|
+
* signing key: it is shaped like a node id AND has no sibling `<id>.pub` in
|
|
941
|
+
* `keysDir`. Both conditions are required — an agent that happened to be named
|
|
942
|
+
* `flair_deadbeef` would still have a `.pub`, so it is never misclassified.
|
|
943
|
+
*/
|
|
944
|
+
export function isNodeKeyId(id, keysDir) {
|
|
945
|
+
if (!NODE_KEY_ID_RE.test(id))
|
|
946
|
+
return false;
|
|
947
|
+
return !existsSync(join(keysDir, `${id}.pub`));
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Partition `.key`-derived ids into agent signing keys and node-scoped
|
|
951
|
+
* federation keys (see isNodeKeyId). Node keys must never feed agent handling —
|
|
952
|
+
* Ed25519 parsing, registration checks, or connector-identity inference
|
|
953
|
+
* (flair#1193) — so callers keep only `agentKeyIds` for those paths and report
|
|
954
|
+
* `nodeKeyIds` informatively.
|
|
955
|
+
*/
|
|
956
|
+
export function partitionKeyIds(ids, keysDir) {
|
|
957
|
+
const agentKeyIds = [];
|
|
958
|
+
const nodeKeyIds = [];
|
|
959
|
+
for (const id of ids) {
|
|
960
|
+
(isNodeKeyId(id, keysDir) ? nodeKeyIds : agentKeyIds).push(id);
|
|
961
|
+
}
|
|
962
|
+
return { agentKeyIds, nodeKeyIds };
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Resolve the agent id `doctor --fix` should wire a connector as, or undefined
|
|
966
|
+
* when none can be safely determined. A node-scoped federation id is NEVER
|
|
967
|
+
* returned regardless of source (flair#1193): it cannot sign, so wiring it
|
|
968
|
+
* yields a connector that authenticates as a phantom unregistered node and
|
|
969
|
+
* fails every read/write. When this returns undefined the caller MUST refuse
|
|
970
|
+
* and tell the user to create/register an agent — never fall back to a node id.
|
|
971
|
+
*
|
|
972
|
+
* `keyAgentIds` is expected to already be node-free (its producer partitions
|
|
973
|
+
* node keys out at enumeration), so `inferSoleAgentId` never sees one; the
|
|
974
|
+
* explicit `isNodeKeyId` guard additionally covers `optsAgent` / `envAgentId` /
|
|
975
|
+
* `anyKnownAgentId`, since a prior buggy run may have poisoned a wired block
|
|
976
|
+
* with a node id that would otherwise be read back and re-propagated.
|
|
977
|
+
*/
|
|
978
|
+
export function resolveFixAgentId(args) {
|
|
979
|
+
const { optsAgent, envAgentId, anyKnownAgentId, keyAgentIds, keysDir } = args;
|
|
980
|
+
const candidate = optsAgent || envAgentId || anyKnownAgentId || inferSoleAgentId(keyAgentIds);
|
|
981
|
+
if (candidate && isNodeKeyId(candidate, keysDir))
|
|
982
|
+
return undefined;
|
|
983
|
+
return candidate;
|
|
984
|
+
}
|
|
@@ -115,6 +115,30 @@ async function unwrap(value) {
|
|
|
115
115
|
}
|
|
116
116
|
return value;
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* flair#1188 — remove the raw `embedding` vector from a record before it is
|
|
120
|
+
* returned over the MCP surface. A stored memory carries a 768-float
|
|
121
|
+
* `embedding` (the HNSW vector); inlined into a tool result that is thousands
|
|
122
|
+
* of noise tokens per record on chat connectors that have a fixed context
|
|
123
|
+
* budget, and the caller can never do anything useful with it. Returns a
|
|
124
|
+
* shallow copy WITHOUT `embedding` (never mutates the source record), and
|
|
125
|
+
* passes through anything that is not a plain record — null, primitives,
|
|
126
|
+
* arrays, and the `{ error, status }` shapes `unwrap` produces — untouched.
|
|
127
|
+
*
|
|
128
|
+
* `memory_search` already projects with an explicit select that omits
|
|
129
|
+
* `embedding` (resources/semantic-retrieval-core.ts's DEFAULT_SELECT), and
|
|
130
|
+
* `bootstrap` uses the same select-without-embedding pushdown, so this is only
|
|
131
|
+
* needed on the FULL-record read/write paths (memory_get, and the write
|
|
132
|
+
* responses that echo the stored row).
|
|
133
|
+
*/
|
|
134
|
+
function stripEmbedding(value) {
|
|
135
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
136
|
+
return value;
|
|
137
|
+
if (!("embedding" in value))
|
|
138
|
+
return value;
|
|
139
|
+
const { embedding, ...rest } = value;
|
|
140
|
+
return rest;
|
|
141
|
+
}
|
|
118
142
|
// ── Tool implementations (thin wrappers over existing handlers) ──────────────
|
|
119
143
|
//
|
|
120
144
|
// Each takes the resolved agent + the parsed tool arguments and returns a plain
|
|
@@ -190,7 +214,10 @@ async function memoryStore(agent, args) {
|
|
|
190
214
|
}
|
|
191
215
|
body.visibility = args.visibility;
|
|
192
216
|
}
|
|
193
|
-
|
|
217
|
+
// flair#1188 — memory_store's response goes through the same buildWriteResponse
|
|
218
|
+
// echo as memory_update; strip the server-regenerated embedding so no write
|
|
219
|
+
// tool ever inlines the vector. No-op when the response carries none.
|
|
220
|
+
return stripEmbedding(await unwrap(await h.post(body)));
|
|
194
221
|
}
|
|
195
222
|
/**
|
|
196
223
|
* memory_update — id-targeted, dedup-BYPASSED overwrite/version path (memory-
|
|
@@ -240,6 +267,20 @@ async function memoryUpdate(agent, args) {
|
|
|
240
267
|
delete record.validFrom;
|
|
241
268
|
delete record.validTo;
|
|
242
269
|
delete record.archivedAt;
|
|
270
|
+
// flair#1189 — retrievalCount and lastRetrieved are RECORD-scoped, not
|
|
271
|
+
// lineage-scoped: a brand-new successor record has no retrieval history of
|
|
272
|
+
// its OWN, so it must start with none. Inheriting them from the superseded
|
|
273
|
+
// record via the `...existing` spread produced a successor whose
|
|
274
|
+
// lastRetrieved PREDATED its own createdAt ("retrieved 8h before it
|
|
275
|
+
// existed"), silently corrupting any recency/usage-based ranking that reads
|
|
276
|
+
// these fields. Reset both here, at succession construction — NOT server-
|
|
277
|
+
// side, because `supersedes` is a PERMANENT property of every successor and
|
|
278
|
+
// legitimate later retrievalCount bumps route through put() on a record that
|
|
279
|
+
// still carries it. Usage/citation-ledger counters (usageCount, the #1147
|
|
280
|
+
// citation ledger) are a SEPARATE, arguably lineage-scoped question and are
|
|
281
|
+
// deliberately left untouched here (#1147's usage loop is currently inert).
|
|
282
|
+
record.retrievalCount = 0;
|
|
283
|
+
delete record.lastRetrieved;
|
|
243
284
|
// flair#718 authorship-provenance — see memoryStore's comment: forward
|
|
244
285
|
// the resolved OAuth client_id (never forgeable via args) so the NEW
|
|
245
286
|
// version's provenance records which client authored this update.
|
|
@@ -247,7 +288,10 @@ async function memoryUpdate(agent, args) {
|
|
|
247
288
|
record.claimedClient = agent.clientId;
|
|
248
289
|
// A create needs a COLLECTION-bound instance (see resources/in-process.ts).
|
|
249
290
|
const coll = await collectionResource(Cls, delegationContext(agent));
|
|
250
|
-
|
|
291
|
+
// flair#1188 — the write response echoes the stored row (Memory.post
|
|
292
|
+
// regenerates the embedding server-side), so strip the vector before it
|
|
293
|
+
// returns over the MCP surface. No-op when the response carries none.
|
|
294
|
+
return stripEmbedding(await unwrap(await coll.post(record)));
|
|
251
295
|
}
|
|
252
296
|
const merged = { ...existing, content, updatedAt: new Date().toISOString() };
|
|
253
297
|
delete merged.embedding;
|
|
@@ -264,7 +308,9 @@ async function memoryUpdate(agent, args) {
|
|
|
264
308
|
// the same unloaded-instance defect on the write. The static form loads the
|
|
265
309
|
// row by `merged.id` and threads the context, then dispatches through
|
|
266
310
|
// Memory.put()'s own ownership gate — no scope change, same as the read.
|
|
267
|
-
|
|
311
|
+
// flair#1188 — strip the embedding from the echoed write response (Memory.put
|
|
312
|
+
// regenerates the vector server-side); no-op when the response carries none.
|
|
313
|
+
return stripEmbedding(await unwrap(await Cls.put(merged, delegationContext(agent))));
|
|
268
314
|
}
|
|
269
315
|
async function memoryGet(agent, args) {
|
|
270
316
|
const Cls = await handler("Memory");
|
|
@@ -286,7 +332,13 @@ async function memoryGet(agent, args) {
|
|
|
286
332
|
// a plain `{ id, includeTrust }` property — Memory.get()'s wantsTrust() reads
|
|
287
333
|
// it there (the in-process shape alongside the HTTP query-param shape).
|
|
288
334
|
const target = args?.includeTrust === true ? { id: args?.id, includeTrust: true } : args?.id;
|
|
289
|
-
|
|
335
|
+
const result = await unwrap(await Cls.get(target, delegationContext(agent)));
|
|
336
|
+
// flair#1188 — a by-id get loads the FULL record, including the 768-float
|
|
337
|
+
// `embedding` vector (search/bootstrap project it out; a raw get does not).
|
|
338
|
+
// Strip it by default so a chat connector isn't flooded with thousands of
|
|
339
|
+
// useless tokens per record; return it only when the caller explicitly opts
|
|
340
|
+
// in via includeEmbedding.
|
|
341
|
+
return args?.includeEmbedding === true ? result : stripEmbedding(result);
|
|
290
342
|
}
|
|
291
343
|
async function memoryDelete(agent, args) {
|
|
292
344
|
const Cls = await handler("Memory");
|
|
@@ -324,7 +376,15 @@ async function bootstrap(agent, args) {
|
|
|
324
376
|
// flair#831 — attach the running Flair version to the RESPONSE (not the
|
|
325
377
|
// delegated request body) so the calling agent learns the server version
|
|
326
378
|
// on its very first call.
|
|
327
|
-
|
|
379
|
+
//
|
|
380
|
+
// flair#1182 — `unwrap` is async: it must be AWAITED before the result is
|
|
381
|
+
// spread, exactly as every sibling tool does (`await unwrap(...)` in
|
|
382
|
+
// memory_store / memory_update / memory_get). Without the await, `result` is
|
|
383
|
+
// the still-pending PROMISE, and `{ ...aPromise }` copies no own-enumerable
|
|
384
|
+
// keys — so the entire computed payload (resolved agentId, scope, soul,
|
|
385
|
+
// memories, predicted, the #1182.1 containers, the abstention verdict) was
|
|
386
|
+
// silently discarded and the caller saw ONLY the injected `flairVersion`.
|
|
387
|
+
const result = await unwrap(await h.post(body));
|
|
328
388
|
if (result && typeof result === "object" && !Array.isArray(result)) {
|
|
329
389
|
return { ...result, flairVersion: resolveVersion() };
|
|
330
390
|
}
|
|
@@ -514,13 +574,14 @@ export const TOOLS = {
|
|
|
514
574
|
memory_get: {
|
|
515
575
|
def: {
|
|
516
576
|
name: "memory_get",
|
|
517
|
-
description: "Retrieve a specific memory by ID.",
|
|
577
|
+
description: "Retrieve a specific memory by ID. The record's raw embedding vector is omitted by default (it is large and not useful to a caller); pass includeEmbedding=true to include it.",
|
|
518
578
|
annotations: { readOnlyHint: true },
|
|
519
579
|
inputSchema: {
|
|
520
580
|
type: "object",
|
|
521
581
|
properties: {
|
|
522
582
|
id: { type: "string", description: "Memory ID" },
|
|
523
583
|
includeTrust: { type: "boolean", description: "Attach a trust-evidence block (provenance, author, usage, freshness, supersession) to the record. Default false." },
|
|
584
|
+
includeEmbedding: { type: "boolean", description: "Include the raw embedding vector (hundreds of floats) in the returned record. Omitted by default because it is large and rarely useful to a caller. Default false." },
|
|
524
585
|
},
|
|
525
586
|
required: ["id"],
|
|
526
587
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpsdev-ai/flair",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.6",
|
|
4
4
|
"packageManager": "bun@1.3.10",
|
|
5
5
|
"description": "Identity, memory, and soul for AI agents. Cryptographic identity (Ed25519), semantic memory with local embeddings, and persistent personality — all in a single process.",
|
|
6
6
|
"type": "module",
|