ticlawk 0.1.16-dev.2 → 0.1.16-dev.21
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 +14 -2
- package/bin/ticlawk.mjs +207 -25
- package/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +230 -22
- package/src/adapters/ticlawk/credentials.mjs +41 -1
- package/src/adapters/ticlawk/index.mjs +196 -195
- package/src/adapters/ticlawk/wake-client.mjs +1 -1
- package/src/cli/agent-commands.mjs +601 -35
- package/src/core/agent-cli-handlers.mjs +448 -20
- package/src/core/agent-home.mjs +50 -10
- package/src/core/argv.mjs +11 -1
- package/src/core/http.mjs +126 -0
- package/src/core/runtime-env.mjs +7 -0
- package/src/core/runtime-support.mjs +101 -30
- package/src/migrate/write-initial-memory.mjs +5 -5
- package/src/runtimes/_shared/brand.mjs +1 -0
- package/src/runtimes/_shared/goal-task-protocol.mjs +228 -0
- package/src/runtimes/_shared/standing-prompt.mjs +120 -278
- package/src/runtimes/_shared/wake-prompt.mjs +173 -0
- package/src/runtimes/claude-code/index.mjs +30 -108
- package/src/runtimes/codex/index.mjs +114 -23
- package/src/runtimes/openclaw/index.mjs +16 -26
- package/src/runtimes/opencode/index.mjs +42 -36
- package/src/runtimes/opencode/session.mjs +5 -4
- package/src/runtimes/pi/index.mjs +39 -31
- package/src/runtimes/pi/session.mjs +5 -2
- package/src/adapters/ticlawk/cards.mjs +0 -149
- package/src/core/media/outbound.mjs +0 -163
|
@@ -12,7 +12,6 @@ import { buildAgentRuntimeEnv } from '../../core/runtime-env.mjs';
|
|
|
12
12
|
import { buildStandingPrompt } from '../_shared/standing-prompt.mjs';
|
|
13
13
|
import { ensureAgentHome } from '../../core/agent-home.mjs';
|
|
14
14
|
import {
|
|
15
|
-
createCCSession,
|
|
16
15
|
getClaudeCodeRuntimeHealth,
|
|
17
16
|
runCCPrompt,
|
|
18
17
|
streamCCPrompt,
|
|
@@ -24,29 +23,22 @@ import {
|
|
|
24
23
|
} from './session.mjs';
|
|
25
24
|
import { discoverSessions } from './transcripts.mjs';
|
|
26
25
|
import { buildImageMessageFromInbound } from '../../core/media/inbound.mjs';
|
|
27
|
-
import { normalizeOutboundMedia } from '../../core/media/outbound.mjs';
|
|
28
26
|
import { emitWorkerEvent } from '../../core/events/worker-events.mjs';
|
|
29
27
|
import {
|
|
30
28
|
shouldStreamRuntime,
|
|
31
|
-
sendAdapterMessage,
|
|
32
|
-
recordActivity,
|
|
33
29
|
reportSubprocessFailure,
|
|
34
30
|
terminalRuntimeFailure,
|
|
35
31
|
updateBindingRuntimeMeta,
|
|
32
|
+
resolveRuntimeSessionScope,
|
|
33
|
+
buildRuntimeSessionMetaPatch,
|
|
36
34
|
} from '../../core/runtime-support.mjs';
|
|
37
35
|
|
|
38
36
|
export const claudeCodeRuntime = {
|
|
39
37
|
name: 'claude_code',
|
|
40
38
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
async createSession({ projectDir, text, claudePath }) {
|
|
45
|
-
return createCCSession({ projectDir, message: text, claudePath });
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
// Run a Claude turn and wait for the final result on stdout. This is
|
|
49
|
-
// the worker-first path used by the adapter for direct reply delivery.
|
|
39
|
+
// Run a Claude turn and wait for the final result on stdout. Used by
|
|
40
|
+
// deliverTurn when streaming is disabled; both fresh sessions
|
|
41
|
+
// (sessionId=null) and resumed sessions go through here.
|
|
50
42
|
runTurn({ sessionId, projectDir, claudePath, agentEnv }, text, opts = {}) {
|
|
51
43
|
return runCCPrompt({
|
|
52
44
|
sessionId,
|
|
@@ -130,109 +122,41 @@ export const claudeCodeRuntime = {
|
|
|
130
122
|
if (!binding) return false;
|
|
131
123
|
const adapter = ctx.adapter;
|
|
132
124
|
const meta = binding.runtimeMeta || {};
|
|
133
|
-
//
|
|
125
|
+
// cwd is the per-agent home dir under ~/.ticlawk/agents/<id>/.
|
|
134
126
|
const projectDir = ensureAgentHome(binding.id, {
|
|
135
127
|
displayName: binding.display_name || binding.name || null,
|
|
136
128
|
});
|
|
137
|
-
const sessionId = meta.sessionId || binding.id;
|
|
138
129
|
const runtimeClaudePath = meta.claudePath || meta.runtimePath || null;
|
|
139
130
|
|
|
140
131
|
const message = inbound.action === 'image'
|
|
141
132
|
? await buildImageMessageFromInbound(inbound, 'claude-code')
|
|
142
133
|
: inbound.text;
|
|
143
134
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
hook_event_name: 'worker.turn.start',
|
|
155
|
-
worker_event_name: 'worker.turn.start',
|
|
156
|
-
},
|
|
157
|
-
logger: ctx.logger,
|
|
158
|
-
});
|
|
159
|
-
try {
|
|
160
|
-
const claudePath = requireClaudePath(runtimeClaudePath);
|
|
161
|
-
const claudeVersion = getClaudeCodeRuntimeHealth(claudePath).version || meta.claudeVersion || null;
|
|
162
|
-
const created = await this.createSession({ projectDir, text: message, claudePath });
|
|
163
|
-
const nextBinding = await updateBindingRuntimeMeta(ctx, binding, {
|
|
164
|
-
sessionId: created.sessionId,
|
|
165
|
-
path: null,
|
|
166
|
-
runtimePath: claudePath,
|
|
167
|
-
claudePath,
|
|
168
|
-
claudeVersion,
|
|
169
|
-
rotatePending: false,
|
|
170
|
-
lastRotatedAt: new Date().toISOString(),
|
|
171
|
-
}, { status: 'connected' });
|
|
172
|
-
if (created.resultText && created.resultText.trim()) {
|
|
173
|
-
await sendAdapterMessage(adapter, nextBinding, {
|
|
174
|
-
type: 'assistant',
|
|
175
|
-
text: created.resultText,
|
|
176
|
-
media: [],
|
|
177
|
-
replyToMessageId: inbound.messageId || null,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
await emitWorkerEvent({
|
|
181
|
-
adapter,
|
|
182
|
-
binding: nextBinding,
|
|
183
|
-
agent: this.name,
|
|
184
|
-
sessionId: created.sessionId,
|
|
185
|
-
cwd: projectDir,
|
|
186
|
-
replyToMessageId: inbound.messageId || null,
|
|
187
|
-
event: {
|
|
188
|
-
hook_event_name: 'Stop',
|
|
189
|
-
worker_event_name: 'worker.turn.complete',
|
|
190
|
-
},
|
|
191
|
-
logger: ctx.logger,
|
|
192
|
-
});
|
|
193
|
-
return true;
|
|
194
|
-
} catch (err) {
|
|
195
|
-
await emitWorkerEvent({
|
|
196
|
-
adapter,
|
|
197
|
-
binding,
|
|
198
|
-
agent: this.name,
|
|
199
|
-
sessionId: sessionId || binding.id,
|
|
200
|
-
cwd: projectDir,
|
|
201
|
-
replyToMessageId: inbound.messageId || null,
|
|
202
|
-
event: {
|
|
203
|
-
hook_event_name: 'worker.turn.error',
|
|
204
|
-
worker_event_name: 'worker.turn.error',
|
|
205
|
-
error: err?.message || 'Claude Code failed',
|
|
206
|
-
},
|
|
207
|
-
logger: ctx.logger,
|
|
208
|
-
});
|
|
209
|
-
await reportSubprocessFailure({
|
|
210
|
-
adapter,
|
|
211
|
-
binding,
|
|
212
|
-
inbound,
|
|
213
|
-
runtimeName: 'Claude Code',
|
|
214
|
-
info: err?.info || {
|
|
215
|
-
ok: false,
|
|
216
|
-
kind: 'exit-error',
|
|
217
|
-
errorMessage: err?.message || 'Claude Code failed',
|
|
218
|
-
durationMs: 0,
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
return terminalRuntimeFailure(err?.message || 'Claude Code failed');
|
|
222
|
-
}
|
|
223
|
-
}
|
|
135
|
+
// shouldRotate=true means this conversation has no runtime session
|
|
136
|
+
// yet, or the agent was reset and all scoped sessions are invalid.
|
|
137
|
+
// We pass sessionId=null so `claude` creates a fresh session; the new
|
|
138
|
+
// session_id is captured from stream events and persisted below.
|
|
139
|
+
// Unifying rotate + non-rotate into one path means the standing prompt
|
|
140
|
+
// is always attached, so the agent uses the CLI to reply on every
|
|
141
|
+
// turn — including the first.
|
|
142
|
+
const sessionScope = resolveRuntimeSessionScope(meta, inbound);
|
|
143
|
+
const targetSessionId = sessionScope.shouldRotate ? null : sessionScope.sessionId;
|
|
144
|
+
const errEventSessionId = targetSessionId || binding.id;
|
|
224
145
|
|
|
225
146
|
try {
|
|
226
147
|
const claudePath = requireClaudePath(runtimeClaudePath);
|
|
227
148
|
const claudeVersion = getClaudeCodeRuntimeHealth(claudePath).version || meta.claudeVersion || null;
|
|
228
149
|
const agentEnv = buildAgentRuntimeEnv({
|
|
229
150
|
agentId: binding.id,
|
|
230
|
-
sessionId,
|
|
151
|
+
sessionId: targetSessionId,
|
|
231
152
|
hostId: binding.runtime_host_id,
|
|
153
|
+
conversationId: inbound.conversationId,
|
|
154
|
+
messageId: inbound.messageId,
|
|
155
|
+
target: inbound.envelopeTarget,
|
|
232
156
|
});
|
|
233
|
-
const appendSystemPrompt = buildStandingPrompt({ agentId: binding.id });
|
|
157
|
+
const appendSystemPrompt = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
234
158
|
const result = shouldStreamRuntime(this.name, this)
|
|
235
|
-
? await this.runTurnStream({ sessionId, projectDir, claudePath, agentEnv }, message, {
|
|
159
|
+
? await this.runTurnStream({ sessionId: targetSessionId, projectDir, claudePath, agentEnv }, message, {
|
|
236
160
|
appendSystemPrompt,
|
|
237
161
|
onEvent: async (event) => {
|
|
238
162
|
if (event?.type === 'turn.started') {
|
|
@@ -240,7 +164,7 @@ export const claudeCodeRuntime = {
|
|
|
240
164
|
adapter,
|
|
241
165
|
binding,
|
|
242
166
|
agent: this.name,
|
|
243
|
-
sessionId: event.sessionId ||
|
|
167
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
244
168
|
cwd: projectDir,
|
|
245
169
|
replyToMessageId: inbound.messageId || null,
|
|
246
170
|
event: {
|
|
@@ -254,7 +178,7 @@ export const claudeCodeRuntime = {
|
|
|
254
178
|
adapter,
|
|
255
179
|
binding,
|
|
256
180
|
agent: this.name,
|
|
257
|
-
sessionId: event.sessionId ||
|
|
181
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
258
182
|
cwd: projectDir,
|
|
259
183
|
replyToMessageId: inbound.messageId || null,
|
|
260
184
|
event: {
|
|
@@ -267,22 +191,20 @@ export const claudeCodeRuntime = {
|
|
|
267
191
|
}
|
|
268
192
|
},
|
|
269
193
|
})
|
|
270
|
-
: await this.runTurn({ sessionId, projectDir, claudePath, agentEnv }, message, { appendSystemPrompt });
|
|
194
|
+
: await this.runTurn({ sessionId: targetSessionId, projectDir, claudePath, agentEnv }, message, { appendSystemPrompt });
|
|
271
195
|
const nextBinding = await updateBindingRuntimeMeta(ctx, binding, {
|
|
272
|
-
|
|
196
|
+
...buildRuntimeSessionMetaPatch(meta, sessionScope, {
|
|
197
|
+
sessionId: result?.sessionId,
|
|
198
|
+
}),
|
|
273
199
|
runtimePath: claudePath,
|
|
274
200
|
claudePath,
|
|
275
201
|
claudeVersion,
|
|
276
202
|
}, { status: 'connected' });
|
|
277
|
-
await recordActivity(adapter, nextBinding, inbound, {
|
|
278
|
-
...result,
|
|
279
|
-
media: normalizeOutboundMedia(result),
|
|
280
|
-
});
|
|
281
203
|
await emitWorkerEvent({
|
|
282
204
|
adapter,
|
|
283
205
|
binding: nextBinding,
|
|
284
206
|
agent: this.name,
|
|
285
|
-
sessionId: result?.sessionId ||
|
|
207
|
+
sessionId: result?.sessionId || targetSessionId || binding.id,
|
|
286
208
|
cwd: projectDir,
|
|
287
209
|
replyToMessageId: inbound.messageId || null,
|
|
288
210
|
event: {
|
|
@@ -297,7 +219,7 @@ export const claudeCodeRuntime = {
|
|
|
297
219
|
adapter,
|
|
298
220
|
binding,
|
|
299
221
|
agent: this.name,
|
|
300
|
-
sessionId,
|
|
222
|
+
sessionId: errEventSessionId,
|
|
301
223
|
cwd: projectDir,
|
|
302
224
|
replyToMessageId: inbound.messageId || null,
|
|
303
225
|
event: {
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* and discover local sessions.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { createHash } from 'node:crypto';
|
|
9
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { basename, join } from 'node:path';
|
|
9
12
|
import {
|
|
10
13
|
createCodexSession,
|
|
11
14
|
runCodexPrompt,
|
|
@@ -18,21 +21,98 @@ import {
|
|
|
18
21
|
requireCodexPath,
|
|
19
22
|
} from './session.mjs';
|
|
20
23
|
import { buildCodexInputFromInbound } from '../../core/media/inbound.mjs';
|
|
21
|
-
import { normalizeOutboundMedia } from '../../core/media/outbound.mjs';
|
|
22
24
|
import { emitWorkerEvent } from '../../core/events/worker-events.mjs';
|
|
23
25
|
import {
|
|
24
26
|
shouldStreamRuntime,
|
|
25
27
|
createDeltaAggregator,
|
|
26
|
-
sendAdapterMessage,
|
|
27
|
-
recordActivity,
|
|
28
28
|
reportSubprocessFailure,
|
|
29
29
|
terminalRuntimeFailure,
|
|
30
30
|
updateBindingRuntimeMeta,
|
|
31
31
|
isRuntimeGatewayFailure,
|
|
32
|
+
resolveRuntimeSessionScope,
|
|
33
|
+
buildRuntimeSessionMetaPatch,
|
|
32
34
|
} from '../../core/runtime-support.mjs';
|
|
33
35
|
import { buildAgentRuntimeEnv } from '../../core/runtime-env.mjs';
|
|
34
36
|
import { buildStandingPrompt } from '../_shared/standing-prompt.mjs';
|
|
35
37
|
import { ensureAgentHome } from '../../core/agent-home.mjs';
|
|
38
|
+
import { debugError, debugLog } from '../../core/logger.mjs';
|
|
39
|
+
|
|
40
|
+
function parseBooleanish(value) {
|
|
41
|
+
if (value === undefined || value === null || value === '') return false;
|
|
42
|
+
return ['1', 'true', 'on', 'yes'].includes(String(value).trim().toLowerCase());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function sha256(text) {
|
|
46
|
+
return createHash('sha256').update(String(text || ''), 'utf8').digest('hex');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function fileSafeId(value) {
|
|
50
|
+
return String(value || 'unknown')
|
|
51
|
+
.replace(/[^a-zA-Z0-9_-]+/g, '-')
|
|
52
|
+
.replace(/^-+|-+$/g, '')
|
|
53
|
+
.slice(0, 80) || 'unknown';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function writePromptSnapshot({
|
|
57
|
+
binding,
|
|
58
|
+
inbound,
|
|
59
|
+
agentHome,
|
|
60
|
+
targetSessionId,
|
|
61
|
+
shouldRotate,
|
|
62
|
+
developerInstructions,
|
|
63
|
+
message,
|
|
64
|
+
input,
|
|
65
|
+
}) {
|
|
66
|
+
if (!parseBooleanish(process.env.TICLAWK_LOG_RUNTIME_PROMPTS)) return;
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const rootDir = process.env.TICLAWK_RUNTIME_PROMPT_LOG_DIR
|
|
70
|
+
|| join(homedir(), '.ticlawk', 'prompt-logs');
|
|
71
|
+
const dir = join(rootDir, fileSafeId(binding?.id));
|
|
72
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
73
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
74
|
+
const messageId = fileSafeId(inbound?.messageId);
|
|
75
|
+
const filePath = join(dir, `${stamp}-${messageId}.json`);
|
|
76
|
+
const payload = {
|
|
77
|
+
createdAt: new Date().toISOString(),
|
|
78
|
+
runtime: 'codex',
|
|
79
|
+
agentId: binding?.id || null,
|
|
80
|
+
conversationId: inbound?.conversationId || null,
|
|
81
|
+
messageId: inbound?.messageId || null,
|
|
82
|
+
target: inbound?.envelopeTarget || null,
|
|
83
|
+
action: inbound?.action || null,
|
|
84
|
+
sessionId: targetSessionId || null,
|
|
85
|
+
shouldRotate: Boolean(shouldRotate),
|
|
86
|
+
agentHome,
|
|
87
|
+
hashes: {
|
|
88
|
+
developerInstructionsSha256: sha256(developerInstructions),
|
|
89
|
+
messageSha256: sha256(message),
|
|
90
|
+
},
|
|
91
|
+
developerInstructions,
|
|
92
|
+
message,
|
|
93
|
+
input: input || null,
|
|
94
|
+
};
|
|
95
|
+
writeFileSync(filePath, `${JSON.stringify(payload, null, 2)}\n`, { mode: 0o600 });
|
|
96
|
+
debugLog('codex', 'prompt.snapshot', {
|
|
97
|
+
agentId: binding?.id,
|
|
98
|
+
conversationId: inbound?.conversationId,
|
|
99
|
+
messageId: inbound?.messageId,
|
|
100
|
+
target: inbound?.envelopeTarget,
|
|
101
|
+
path: filePath,
|
|
102
|
+
developerInstructionChars: String(developerInstructions || '').length,
|
|
103
|
+
messageChars: String(message || '').length,
|
|
104
|
+
developerInstructionsSha256: payload.hashes.developerInstructionsSha256,
|
|
105
|
+
messageSha256: payload.hashes.messageSha256,
|
|
106
|
+
});
|
|
107
|
+
} catch (err) {
|
|
108
|
+
debugError('codex', 'prompt.snapshot.failed', {
|
|
109
|
+
agentId: binding?.id,
|
|
110
|
+
conversationId: inbound?.conversationId,
|
|
111
|
+
messageId: inbound?.messageId,
|
|
112
|
+
error: err?.message || String(err),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
36
116
|
|
|
37
117
|
export const codexRuntime = {
|
|
38
118
|
name: 'codex',
|
|
@@ -130,7 +210,7 @@ export const codexRuntime = {
|
|
|
130
210
|
if (!binding) return false;
|
|
131
211
|
const adapter = ctx.adapter;
|
|
132
212
|
const meta = binding.runtimeMeta || {};
|
|
133
|
-
//
|
|
213
|
+
// cwd is the per-agent home dir under ~/.ticlawk/agents/<id>/.
|
|
134
214
|
// ensureAgentHome creates it + seeds MEMORY.md if missing.
|
|
135
215
|
const agentHome = ensureAgentHome(binding.id, {
|
|
136
216
|
displayName: binding.display_name || binding.name || null,
|
|
@@ -143,14 +223,16 @@ export const codexRuntime = {
|
|
|
143
223
|
? (codexInput.find((item) => item?.type === 'text')?.text || inbound.text || '(image attached)')
|
|
144
224
|
: inbound.text;
|
|
145
225
|
|
|
146
|
-
const
|
|
226
|
+
const sessionScope = resolveRuntimeSessionScope(meta, inbound);
|
|
227
|
+
const shouldRotate = sessionScope.shouldRotate;
|
|
228
|
+
const targetSessionId = shouldRotate ? null : sessionScope.sessionId;
|
|
147
229
|
const deltaAggregator = createDeltaAggregator({
|
|
148
230
|
flushDelta: async ({ text, sessionId, turnId, cwd }) => {
|
|
149
231
|
await emitWorkerEvent({
|
|
150
232
|
adapter,
|
|
151
233
|
binding,
|
|
152
234
|
agent: this.name,
|
|
153
|
-
sessionId: sessionId ||
|
|
235
|
+
sessionId: sessionId || targetSessionId || binding.id,
|
|
154
236
|
turnId: turnId || null,
|
|
155
237
|
cwd: cwd || agentHome,
|
|
156
238
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -168,12 +250,25 @@ export const codexRuntime = {
|
|
|
168
250
|
const runtimeCodexVersion = getCodexRuntimeHealth(runtimeCodexPath).version || meta.codexVersion || null;
|
|
169
251
|
const agentEnv = buildAgentRuntimeEnv({
|
|
170
252
|
agentId: binding.id,
|
|
171
|
-
sessionId:
|
|
253
|
+
sessionId: targetSessionId,
|
|
172
254
|
hostId: binding.runtime_host_id,
|
|
255
|
+
conversationId: inbound.conversationId,
|
|
256
|
+
messageId: inbound.messageId,
|
|
257
|
+
target: inbound.envelopeTarget,
|
|
258
|
+
});
|
|
259
|
+
const developerInstructions = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
260
|
+
writePromptSnapshot({
|
|
261
|
+
binding,
|
|
262
|
+
inbound,
|
|
263
|
+
agentHome,
|
|
264
|
+
targetSessionId,
|
|
265
|
+
shouldRotate,
|
|
266
|
+
developerInstructions,
|
|
267
|
+
message,
|
|
268
|
+
input: codexInput,
|
|
173
269
|
});
|
|
174
|
-
const developerInstructions = buildStandingPrompt({ agentId: binding.id });
|
|
175
270
|
const result = (shouldRotate || inbound.action === 'image' || shouldStreamRuntime(this.name, this))
|
|
176
|
-
? await this.runTurnStream({ sessionId:
|
|
271
|
+
? await this.runTurnStream({ sessionId: targetSessionId, cwd: agentHome, codexPath: runtimeCodexPath, agentEnv }, message, {
|
|
177
272
|
input: codexInput,
|
|
178
273
|
developerInstructions,
|
|
179
274
|
onEvent: async (event) => {
|
|
@@ -182,7 +277,7 @@ export const codexRuntime = {
|
|
|
182
277
|
adapter,
|
|
183
278
|
binding,
|
|
184
279
|
agent: this.name,
|
|
185
|
-
sessionId: event.sessionId ||
|
|
280
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
186
281
|
turnId: event.turnId || null,
|
|
187
282
|
cwd: agentHome,
|
|
188
283
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -194,36 +289,32 @@ export const codexRuntime = {
|
|
|
194
289
|
});
|
|
195
290
|
} else if (event?.type === 'message.delta' && event.text) {
|
|
196
291
|
deltaAggregator.push(event.text, {
|
|
197
|
-
sessionId: event.sessionId ||
|
|
292
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
198
293
|
turnId: event.turnId || null,
|
|
199
294
|
cwd: agentHome,
|
|
200
295
|
});
|
|
201
296
|
}
|
|
202
297
|
},
|
|
203
298
|
})
|
|
204
|
-
: await this.runTurn({ sessionId:
|
|
299
|
+
: await this.runTurn({ sessionId: targetSessionId, cwd: agentHome, codexPath: runtimeCodexPath, agentEnv }, message, {
|
|
205
300
|
input: codexInput,
|
|
206
301
|
});
|
|
207
302
|
|
|
208
303
|
await deltaAggregator.flush();
|
|
209
304
|
const nextBinding = await updateBindingRuntimeMeta(ctx, binding, {
|
|
210
|
-
|
|
211
|
-
|
|
305
|
+
...buildRuntimeSessionMetaPatch(meta, sessionScope, {
|
|
306
|
+
sessionId: result?.sessionId,
|
|
307
|
+
path: result?.path,
|
|
308
|
+
}),
|
|
212
309
|
runtimePath: runtimeCodexPath,
|
|
213
310
|
codexPath: runtimeCodexPath,
|
|
214
311
|
codexVersion: runtimeCodexVersion,
|
|
215
|
-
rotatePending: false,
|
|
216
|
-
lastRotatedAt: shouldRotate ? new Date().toISOString() : meta.lastRotatedAt,
|
|
217
312
|
}, { status: 'connected' });
|
|
218
|
-
await recordActivity(adapter, nextBinding, inbound, {
|
|
219
|
-
...result,
|
|
220
|
-
media: normalizeOutboundMedia(result),
|
|
221
|
-
});
|
|
222
313
|
await emitWorkerEvent({
|
|
223
314
|
adapter,
|
|
224
315
|
binding: nextBinding,
|
|
225
316
|
agent: this.name,
|
|
226
|
-
sessionId: result?.sessionId ||
|
|
317
|
+
sessionId: result?.sessionId || targetSessionId || binding.id,
|
|
227
318
|
turnId: result?.turnId || null,
|
|
228
319
|
cwd: result?.cwd || agentHome,
|
|
229
320
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -254,7 +345,7 @@ export const codexRuntime = {
|
|
|
254
345
|
adapter,
|
|
255
346
|
binding: failureBinding,
|
|
256
347
|
agent: this.name,
|
|
257
|
-
sessionId:
|
|
348
|
+
sessionId: targetSessionId || binding.id,
|
|
258
349
|
turnId: failureInfo?.turnId || null,
|
|
259
350
|
cwd: agentHome,
|
|
260
351
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { reportSubprocessFailure, terminalRuntimeFailure } from '../../core/runtime-support.mjs';
|
|
2
|
+
import { getGoalTaskProtocolOverlayKey } from '../_shared/goal-task-protocol.mjs';
|
|
3
3
|
import { buildStandingPrompt } from '../_shared/standing-prompt.mjs';
|
|
4
4
|
import { GATEWAY_HOST, GATEWAY_PORT } from './identity.mjs';
|
|
5
5
|
|
|
@@ -25,10 +25,11 @@ async function probeOpenClawGatewayHealth() {
|
|
|
25
25
|
import { buildOpenClawSessionKey, normalizeOpenClawAgentId } from './target.mjs';
|
|
26
26
|
import { askGateway, isGatewayReady, registerOpenClawChannel } from './gateway.mjs';
|
|
27
27
|
|
|
28
|
-
// Tracks which (agentId, sessionKey
|
|
29
|
-
// prompt this process lifetime. OpenClaw's
|
|
30
|
-
// out of process, so we err on the side of
|
|
31
|
-
//
|
|
28
|
+
// Tracks which (agentId, sessionKey, protocol overlay) combinations
|
|
29
|
+
// already saw the standing prompt this process lifetime. OpenClaw's
|
|
30
|
+
// gateway holds session state out of process, so we err on the side of
|
|
31
|
+
// "inject on first observed overlay after daemon restart"; the gateway
|
|
32
|
+
// dedupes redundant context.
|
|
32
33
|
const standingPromptSeen = new Set();
|
|
33
34
|
import { addInFlight, recoverInFlightEntries, removeInFlight } from './inflight.mjs';
|
|
34
35
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
@@ -160,13 +161,13 @@ export const openClawRuntime = {
|
|
|
160
161
|
const sessionId = String(meta.sessionKey || buildOpenClawSessionKey(agentId)).trim();
|
|
161
162
|
|
|
162
163
|
// Inject the standing prompt on the first observed turn after a
|
|
163
|
-
// daemon start for this (agent, session)
|
|
164
|
-
// separate "system prompt" parameter on the gateway, so we
|
|
165
|
-
//
|
|
166
|
-
const standingKey = `${agentId}|${sessionId}`;
|
|
164
|
+
// daemon start for this (agent, session, protocol overlay). OpenClaw
|
|
165
|
+
// has no separate "system prompt" parameter on the gateway, so we
|
|
166
|
+
// prepend through the prompt body.
|
|
167
|
+
const standingKey = `${agentId}|${sessionId}|${getGoalTaskProtocolOverlayKey({ agentId: binding.id, inbound })}`;
|
|
167
168
|
let prompt = rawPrompt;
|
|
168
169
|
if (!standingPromptSeen.has(standingKey)) {
|
|
169
|
-
const standing = buildStandingPrompt({ agentId: binding.id });
|
|
170
|
+
const standing = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
170
171
|
prompt = `${standing}\n\n---\n\n${rawPrompt}`;
|
|
171
172
|
standingPromptSeen.add(standingKey);
|
|
172
173
|
}
|
|
@@ -192,10 +193,6 @@ export const openClawRuntime = {
|
|
|
192
193
|
});
|
|
193
194
|
},
|
|
194
195
|
});
|
|
195
|
-
await recordActivity(adapter, binding, inbound, {
|
|
196
|
-
...result,
|
|
197
|
-
media: normalizeOutboundMedia(result),
|
|
198
|
-
});
|
|
199
196
|
return true;
|
|
200
197
|
} catch (err) {
|
|
201
198
|
if (typeof adapter.emitEvent === 'function') {
|
|
@@ -233,18 +230,11 @@ export const openClawRuntime = {
|
|
|
233
230
|
}
|
|
234
231
|
},
|
|
235
232
|
|
|
236
|
-
async recoverInFlight(
|
|
233
|
+
async recoverInFlight() {
|
|
234
|
+
// Just drain the persisted in-flight set — the user-facing notice
|
|
235
|
+
// that used to surface here went through the dead chat-projection
|
|
236
|
+
// path. OpenClaw is non-primary; this no-ops cleanly for now.
|
|
237
237
|
const entries = recoverInFlightEntries();
|
|
238
|
-
for (const entry of entries) {
|
|
239
|
-
const binding = ctx.getBinding(entry.bindingId);
|
|
240
|
-
if (!binding) continue;
|
|
241
|
-
await sendAdapterMessage(ctx.adapter, binding, {
|
|
242
|
-
type: 'assistant',
|
|
243
|
-
text: '⚠️ Lost while ticlawk restarted.\n\nThis OpenClaw message was in flight when ticlawk restarted. Please retry your message.',
|
|
244
|
-
media: [],
|
|
245
|
-
replyToMessageId: entry.messageId || null,
|
|
246
|
-
}).catch(() => {});
|
|
247
|
-
}
|
|
248
238
|
return entries.length;
|
|
249
239
|
},
|
|
250
240
|
|