@frockbot/plugin-memory 0.3.8 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frockbot/plugin-memory",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -22,10 +22,10 @@
22
22
  "typecheck": "tsc --noEmit -p tsconfig.json"
23
23
  },
24
24
  "dependencies": {
25
- "@frockbot/kernel-agent-loop": "0.3.8",
26
- "@frockbot/kernel-contracts": "0.3.8",
27
- "@frockbot/secret-shapes": "0.3.8",
28
- "@frockbot/workspace-store": "0.3.8",
25
+ "@frockbot/kernel-agent-loop": "0.3.9",
26
+ "@frockbot/kernel-contracts": "0.3.9",
27
+ "@frockbot/secret-shapes": "0.3.9",
28
+ "@frockbot/workspace-store": "0.3.9",
29
29
  "cordis": "4.0.0-rc.8"
30
30
  },
31
31
  "devDependencies": {
package/src/facts.ts CHANGED
@@ -65,8 +65,11 @@ export interface MemoryFactV1 {
65
65
  export interface SourcedMemoryFactV1 extends MemoryFactV1 {
66
66
  /** The Bot whose shard holds it. */
67
67
  botId: string;
68
- /** The display name of that Bot, or its id when no name is known. */
69
- via: string;
68
+ /**
69
+ * The display name of that Bot, absent when no name is known. Never its id:
70
+ * a rendered id is a handle the model reads as a name and says out loud.
71
+ */
72
+ via?: string;
70
73
  /** `profile.md` or a monthly log. */
71
74
  kind: "profile" | "log";
72
75
  /** The generation the line was read from; ordering's tiebreak. */
package/src/render.ts CHANGED
@@ -225,7 +225,9 @@ function injected(
225
225
  // prefix inside the text. The marker on the recorded text is what the
226
226
  // tier was; the file it sits in is not.
227
227
  tier: parseMemoryMarkerV1(fact.text).marker === "note" ? "note" : tier,
228
- via: withVia ? fact.via : "",
228
+ // `via` is a name or nothing: a Bot with no name known to this store is
229
+ // uncredited rather than credited by its id.
230
+ via: withVia ? (fact.via ?? "") : "",
229
231
  learnedAt: fact.date,
230
232
  text: fact.text,
231
233
  }));
package/src/store.test.ts CHANGED
@@ -5,6 +5,7 @@ import type {
5
5
  WorkspaceFilesV1,
6
6
  WorkspaceWriterV1,
7
7
  } from "@frockbot/kernel-contracts";
8
+ import { renderInjectedFactLineV1 } from "./facts.ts";
8
9
  import {
9
10
  botMemoryRootV1,
10
11
  projectMemoryRootV1,
@@ -128,6 +129,33 @@ describe("the Memory writer", () => {
128
129
  ]);
129
130
  });
130
131
 
132
+ // A Bot id is a handle, not a name. Rendered as `[via remy-9d15e086]` the
133
+ // model reads it as a name and tells the User a sibling's id.
134
+ test("credits nobody rather than a Bot id when no name is known", async () => {
135
+ const files = createTestMemoryFilesV1({ userId: "user-1" });
136
+ const nameless = new MemoryStore({
137
+ files,
138
+ owner: { userId: "user-1", botId: "bot-9" },
139
+ clock: () => AT,
140
+ });
141
+ const root = userMemoryRootV1(OWNER);
142
+ await nameless.write({
143
+ root,
144
+ tier: "profile",
145
+ fact: "Tim stops drinking coffee at 2pm.",
146
+ writer: writerFor("bot-9"),
147
+ });
148
+
149
+ const tier = await nameless.read(root);
150
+
151
+ expect(tier.profile).toHaveLength(1);
152
+ expect(tier.profile[0]?.via).toBeUndefined();
153
+ expect(tier.profile[0]?.botId).toBe("bot-9");
154
+ expect(renderInjectedFactLineV1(tier.profile[0]!, 200)).not.toContain(
155
+ "bot-9",
156
+ );
157
+ });
158
+
131
159
  test("dedupes a fact that is already recorded, without writing", async () => {
132
160
  const { store } = storeFor("bot-1");
133
161
  const root = botMemoryRootV1(OWNER);
package/src/store.ts CHANGED
@@ -202,8 +202,16 @@ export class MemoryStore {
202
202
  return this.#files;
203
203
  }
204
204
 
205
- private via(botId: string): string {
206
- return this.#names[botId] ?? botId;
205
+ /**
206
+ * The name to credit a shared fact to, or nothing.
207
+ *
208
+ * A Bot id is an internal handle, not a name: rendered into the prompt as
209
+ * `[via remy-9d15e086]` the model reads it as something to say out loud and
210
+ * tells the User a sibling's id. With no name to give, the fact is simply
211
+ * uncredited — the fact itself is what the User asked for.
212
+ */
213
+ private via(botId: string): string | undefined {
214
+ return this.#names[botId];
207
215
  }
208
216
 
209
217
  /**