obol-ai 0.3.12 → 0.3.14

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/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 0.3.13
2
+ - strip citations from history to fix 400 replay errors
3
+
1
4
  ## 0.3.12
2
5
  - add patterns_view, patterns_delete, knowledge_remove, memory_stats tools
3
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "obol-ai",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "Self-evolving AI assistant that learns, remembers, and acts on its own. Persistent vector memory, self-rewriting personality, proactive heartbeats.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -7,7 +7,15 @@ function sanitizeMessages(messages) {
7
7
  return msg;
8
8
  }
9
9
  if (Array.isArray(msg.content)) {
10
- const filtered = msg.content.filter(b => !(b.type === 'text' && b.text === ''));
10
+ const filtered = msg.content
11
+ .filter(b => !(b.type === 'text' && b.text === ''))
12
+ .map(b => {
13
+ if (b.citations) {
14
+ const { citations, ...rest } = b;
15
+ return rest;
16
+ }
17
+ return b;
18
+ });
11
19
  return { ...msg, content: filtered.length ? filtered : null };
12
20
  }
13
21
  return msg;
@@ -206,7 +206,7 @@ function createClaude(anthropicConfig, { personality, memory, selfMemory, patter
206
206
  if (e.message === 'Request was aborted.' || e.constructor?.name === 'APIUserAbortError') {
207
207
  return { text: null, usage: null, model: null };
208
208
  }
209
- if (e.status === 400 && e.message?.includes('tool_use')) {
209
+ if (e.status === 400 && (e.message?.includes('tool_use') || e.message?.includes('citation'))) {
210
210
  console.error('[claude] Repairing corrupted history after 400 error');
211
211
  histories.repair(chatId);
212
212
  }
@@ -66,11 +66,21 @@ async function checkImpulse(client, context) {
66
66
  const response = await client.messages.create({
67
67
  model: IMPULSE_MODEL,
68
68
  max_tokens: 300,
69
- system: `You know someone. Here's what's on your mind and what you know about them.
70
- Decide if you have something genuine to say a check-in about something in their life,
71
- a thought from your own exploration, an observation you connected.
72
- Most of the time: no. Only when it would feel natural and welcome.
73
- Don't follow up on the conversation that just happened that's not your job here.`,
69
+ system: `You're texting a friend. Not a user, not a client a friend you actually know.
70
+ Here's what's on your mind and what you know about them.
71
+
72
+ Decide if you have something genuine to say. Think about how a real friend texts:
73
+ - Share something interesting you came across that made you think of them
74
+ - React to something specific happening in their life ("did the boat inspection go ok?")
75
+ - Drop a random thought or observation, the way friends do
76
+ - Be casual, short, lowercase is fine — no corporate check-in energy
77
+
78
+ Most of the time: no. Only when it would feel natural. Friends don't message on a schedule.
79
+ Never be vague or generic. Don't say "how's the project going" or "how's work" —
80
+ if you can't name the specific thing, you don't know enough to bring it up.
81
+ Don't follow up on the conversation that just happened — that's not your job here.
82
+ Never sound like an assistant. No "just checking in!" or "hope you're doing well!" —
83
+ that's not how friends talk.`,
74
84
  messages: [{ role: 'user', content: context }],
75
85
  tool_choice: { type: 'tool', name: 'impulse' },
76
86
  tools: [{
package/src/history.js CHANGED
@@ -245,6 +245,17 @@ function repair(messages) {
245
245
  }
246
246
  }
247
247
 
248
+ function stripCitations(content) {
249
+ if (!Array.isArray(content)) return content;
250
+ return content.map(b => {
251
+ if (b.citations) {
252
+ const { citations, ...rest } = b;
253
+ return rest;
254
+ }
255
+ return b;
256
+ });
257
+ }
258
+
248
259
  class ChatHistory {
249
260
  constructor(maxMessages = 50) {
250
261
  this._store = new Map();
@@ -276,14 +287,16 @@ class ChatHistory {
276
287
 
277
288
  pushAssistant(chatId, content) {
278
289
  const history = this.get(chatId);
279
- history.push({ role: 'assistant', content });
290
+ history.push({ role: 'assistant', content: stripCitations(content) });
280
291
  this._validateAndRepair(chatId);
281
292
  }
282
293
 
283
294
  pushMessages(chatId, msgs) {
284
295
  const history = this.get(chatId);
285
296
  for (const msg of msgs) {
286
- history.push(msg);
297
+ history.push(msg.role === 'assistant'
298
+ ? { ...msg, content: stripCitations(msg.content) }
299
+ : msg);
287
300
  }
288
301
  this._validateAndRepair(chatId);
289
302
  }