@openagents-org/agent-launcher 0.2.115 → 0.2.116
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 +1 -1
- package/src/adapters/claude.js +56 -1
- package/src/workspace-client.js +26 -0
package/package.json
CHANGED
package/src/adapters/claude.js
CHANGED
|
@@ -128,6 +128,48 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
128
128
|
} catch {}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Build a short transcript of the channel's last chat exchanges, used to
|
|
133
|
+
* re-seed context when --resume fails and we have to start a fresh
|
|
134
|
+
* Claude Code session. Returns null when there's nothing useful to add.
|
|
135
|
+
*
|
|
136
|
+
* Excludes the user's current message (the for-loop will append it
|
|
137
|
+
* normally) and any status/thinking events, which are mostly tool-call
|
|
138
|
+
* noise and inflate the prompt without adding signal.
|
|
139
|
+
*/
|
|
140
|
+
async _buildChannelRecap(channelName, currentMessage) {
|
|
141
|
+
const messages = await this.client.getRecentMessages(
|
|
142
|
+
this.workspaceId, channelName, this.token, 30
|
|
143
|
+
);
|
|
144
|
+
if (!messages || messages.length === 0) return null;
|
|
145
|
+
|
|
146
|
+
const lines = [];
|
|
147
|
+
for (const m of messages) {
|
|
148
|
+
const mt = m.messageType || 'chat';
|
|
149
|
+
if (mt === 'status' || mt === 'thinking' || mt === 'loading') continue;
|
|
150
|
+
const text = (m.content || '').trim();
|
|
151
|
+
if (!text) continue;
|
|
152
|
+
// Don't echo the user's current message back at them.
|
|
153
|
+
if (text === currentMessage) continue;
|
|
154
|
+
const who = m.senderType === 'human'
|
|
155
|
+
? (m.senderName || 'user')
|
|
156
|
+
: (m.senderName || 'agent');
|
|
157
|
+
// Cap each line so a single huge paste doesn't blow up the prompt.
|
|
158
|
+
const truncated = text.length > 800 ? text.slice(0, 800) + '…' : text;
|
|
159
|
+
lines.push(`[${who}] ${truncated}`);
|
|
160
|
+
}
|
|
161
|
+
if (lines.length === 0) return null;
|
|
162
|
+
|
|
163
|
+
// Keep only the tail; older context has diminishing value and we
|
|
164
|
+
// don't want to balloon the system prompt.
|
|
165
|
+
const tail = lines.slice(-15).join('\n');
|
|
166
|
+
return (
|
|
167
|
+
'You previously worked in this channel but your prior session is no ' +
|
|
168
|
+
'longer available, so here is the recent conversation for context:\n\n' +
|
|
169
|
+
tail
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
131
173
|
async _stopAllProcesses(completionMessage = 'Execution stopped.') {
|
|
132
174
|
const entries = Object.entries(this._channelProcesses);
|
|
133
175
|
if (!entries.length) return;
|
|
@@ -449,10 +491,23 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
449
491
|
|
|
450
492
|
// Run up to 2 attempts: first with session resume, then fresh if stale session detected
|
|
451
493
|
let _shouldRetry = false;
|
|
494
|
+
let effectiveContent = content;
|
|
452
495
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
453
496
|
if (mcpConfigFile) { try { fs.unlinkSync(mcpConfigFile); } catch {} mcpConfigFile = null; }
|
|
497
|
+
|
|
498
|
+
// On the retry pass after a stale --resume, the spawned `claude`
|
|
499
|
+
// starts a brand-new session with no memory of prior turns. Replay
|
|
500
|
+
// the channel's recent chat history so the agent at least has a
|
|
501
|
+
// recap instead of saying "I don't see any previous messages."
|
|
502
|
+
if (attempt > 0) {
|
|
503
|
+
try {
|
|
504
|
+
const recap = await this._buildChannelRecap(msgChannel, content);
|
|
505
|
+
if (recap) effectiveContent = `${recap}\n\n---\n\n${content}`;
|
|
506
|
+
} catch {}
|
|
507
|
+
}
|
|
508
|
+
|
|
454
509
|
try {
|
|
455
|
-
const built = this._buildClaudeCmd(
|
|
510
|
+
const built = this._buildClaudeCmd(effectiveContent, msgChannel, { skipResume: attempt > 0 });
|
|
456
511
|
cmd = built.cmd;
|
|
457
512
|
mcpConfigFile = built.mcpConfigFile;
|
|
458
513
|
} catch (e) {
|
package/src/workspace-client.js
CHANGED
|
@@ -191,6 +191,32 @@ class WorkspaceClient {
|
|
|
191
191
|
return events.map((e) => this._eventToMessage(e));
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Fetch the most recent N messages in a channel, returned oldest-to-newest.
|
|
196
|
+
* Used by adapters to rebuild context for a fresh Claude Code session
|
|
197
|
+
* when --resume of the previous session fails (the channel's chat history
|
|
198
|
+
* is the only thing that survives a session-storage rotation).
|
|
199
|
+
*/
|
|
200
|
+
async getRecentMessages(workspaceId, channelName, token, limit = 30) {
|
|
201
|
+
try {
|
|
202
|
+
const params = new URLSearchParams({
|
|
203
|
+
network: workspaceId,
|
|
204
|
+
channel: channelName,
|
|
205
|
+
type: 'workspace.message',
|
|
206
|
+
sort: 'desc',
|
|
207
|
+
limit: String(limit),
|
|
208
|
+
});
|
|
209
|
+
const data = await this._get(`/v1/events?${params}`, this._wsHeaders(token));
|
|
210
|
+
const result = data.data || data;
|
|
211
|
+
const events = (result && result.events) || [];
|
|
212
|
+
// Server returned newest-first; reverse so the caller can present them
|
|
213
|
+
// in chronological order without further fiddling.
|
|
214
|
+
return events.slice().reverse().map((e) => this._eventToMessage(e));
|
|
215
|
+
} catch {
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
194
220
|
/**
|
|
195
221
|
* Fetch the latest workspace.message.posted event id (head cursor).
|
|
196
222
|
* Used by adapters to skip past existing events on join in O(1) instead
|