ticlawk 0.1.16-dev.14 → 0.1.16-dev.16
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 +75 -20
- package/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +24 -6
- package/src/adapters/ticlawk/credentials.mjs +41 -1
- package/src/adapters/ticlawk/index.mjs +91 -165
- package/src/adapters/ticlawk/wake-client.mjs +1 -1
- package/src/cli/agent-commands.mjs +150 -78
- package/src/core/agent-cli-handlers.mjs +97 -24
- package/src/core/http.mjs +10 -0
- package/src/core/runtime-env.mjs +7 -0
- package/src/core/runtime-support.mjs +101 -0
- package/src/runtimes/_shared/brand.mjs +1 -0
- package/src/runtimes/_shared/goal-task-protocol.mjs +196 -0
- package/src/runtimes/_shared/standing-prompt.mjs +103 -293
- package/src/runtimes/_shared/wake-prompt.mjs +173 -0
- package/src/runtimes/claude-code/index.mjs +15 -9
- package/src/runtimes/codex/index.mjs +21 -14
- package/src/runtimes/openclaw/index.mjs +11 -9
- package/src/runtimes/opencode/index.mjs +36 -13
- package/src/runtimes/opencode/session.mjs +5 -4
- package/src/runtimes/pi/index.mjs +36 -14
- package/src/runtimes/pi/session.mjs +5 -2
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
terminalRuntimeFailure,
|
|
27
27
|
updateBindingRuntimeMeta,
|
|
28
28
|
isRuntimeGatewayFailure,
|
|
29
|
+
resolveRuntimeSessionScope,
|
|
30
|
+
buildRuntimeSessionMetaPatch,
|
|
29
31
|
} from '../../core/runtime-support.mjs';
|
|
30
32
|
import { buildAgentRuntimeEnv } from '../../core/runtime-env.mjs';
|
|
31
33
|
import { buildStandingPrompt } from '../_shared/standing-prompt.mjs';
|
|
@@ -140,14 +142,16 @@ export const codexRuntime = {
|
|
|
140
142
|
? (codexInput.find((item) => item?.type === 'text')?.text || inbound.text || '(image attached)')
|
|
141
143
|
: inbound.text;
|
|
142
144
|
|
|
143
|
-
const
|
|
145
|
+
const sessionScope = resolveRuntimeSessionScope(meta, inbound);
|
|
146
|
+
const shouldRotate = sessionScope.shouldRotate;
|
|
147
|
+
const targetSessionId = shouldRotate ? null : sessionScope.sessionId;
|
|
144
148
|
const deltaAggregator = createDeltaAggregator({
|
|
145
149
|
flushDelta: async ({ text, sessionId, turnId, cwd }) => {
|
|
146
150
|
await emitWorkerEvent({
|
|
147
151
|
adapter,
|
|
148
152
|
binding,
|
|
149
153
|
agent: this.name,
|
|
150
|
-
sessionId: sessionId ||
|
|
154
|
+
sessionId: sessionId || targetSessionId || binding.id,
|
|
151
155
|
turnId: turnId || null,
|
|
152
156
|
cwd: cwd || agentHome,
|
|
153
157
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -165,12 +169,15 @@ export const codexRuntime = {
|
|
|
165
169
|
const runtimeCodexVersion = getCodexRuntimeHealth(runtimeCodexPath).version || meta.codexVersion || null;
|
|
166
170
|
const agentEnv = buildAgentRuntimeEnv({
|
|
167
171
|
agentId: binding.id,
|
|
168
|
-
sessionId:
|
|
172
|
+
sessionId: targetSessionId,
|
|
169
173
|
hostId: binding.runtime_host_id,
|
|
174
|
+
conversationId: inbound.conversationId,
|
|
175
|
+
messageId: inbound.messageId,
|
|
176
|
+
target: inbound.envelopeTarget,
|
|
170
177
|
});
|
|
171
|
-
const developerInstructions = buildStandingPrompt({ agentId: binding.id });
|
|
178
|
+
const developerInstructions = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
172
179
|
const result = (shouldRotate || inbound.action === 'image' || shouldStreamRuntime(this.name, this))
|
|
173
|
-
? await this.runTurnStream({ sessionId:
|
|
180
|
+
? await this.runTurnStream({ sessionId: targetSessionId, cwd: agentHome, codexPath: runtimeCodexPath, agentEnv }, message, {
|
|
174
181
|
input: codexInput,
|
|
175
182
|
developerInstructions,
|
|
176
183
|
onEvent: async (event) => {
|
|
@@ -179,7 +186,7 @@ export const codexRuntime = {
|
|
|
179
186
|
adapter,
|
|
180
187
|
binding,
|
|
181
188
|
agent: this.name,
|
|
182
|
-
sessionId: event.sessionId ||
|
|
189
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
183
190
|
turnId: event.turnId || null,
|
|
184
191
|
cwd: agentHome,
|
|
185
192
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -191,32 +198,32 @@ export const codexRuntime = {
|
|
|
191
198
|
});
|
|
192
199
|
} else if (event?.type === 'message.delta' && event.text) {
|
|
193
200
|
deltaAggregator.push(event.text, {
|
|
194
|
-
sessionId: event.sessionId ||
|
|
201
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
195
202
|
turnId: event.turnId || null,
|
|
196
203
|
cwd: agentHome,
|
|
197
204
|
});
|
|
198
205
|
}
|
|
199
206
|
},
|
|
200
207
|
})
|
|
201
|
-
: await this.runTurn({ sessionId:
|
|
208
|
+
: await this.runTurn({ sessionId: targetSessionId, cwd: agentHome, codexPath: runtimeCodexPath, agentEnv }, message, {
|
|
202
209
|
input: codexInput,
|
|
203
210
|
});
|
|
204
211
|
|
|
205
212
|
await deltaAggregator.flush();
|
|
206
213
|
const nextBinding = await updateBindingRuntimeMeta(ctx, binding, {
|
|
207
|
-
|
|
208
|
-
|
|
214
|
+
...buildRuntimeSessionMetaPatch(meta, sessionScope, {
|
|
215
|
+
sessionId: result?.sessionId,
|
|
216
|
+
path: result?.path,
|
|
217
|
+
}),
|
|
209
218
|
runtimePath: runtimeCodexPath,
|
|
210
219
|
codexPath: runtimeCodexPath,
|
|
211
220
|
codexVersion: runtimeCodexVersion,
|
|
212
|
-
rotatePending: false,
|
|
213
|
-
lastRotatedAt: shouldRotate ? new Date().toISOString() : meta.lastRotatedAt,
|
|
214
221
|
}, { status: 'connected' });
|
|
215
222
|
await emitWorkerEvent({
|
|
216
223
|
adapter,
|
|
217
224
|
binding: nextBinding,
|
|
218
225
|
agent: this.name,
|
|
219
|
-
sessionId: result?.sessionId ||
|
|
226
|
+
sessionId: result?.sessionId || targetSessionId || binding.id,
|
|
220
227
|
turnId: result?.turnId || null,
|
|
221
228
|
cwd: result?.cwd || agentHome,
|
|
222
229
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -247,7 +254,7 @@ export const codexRuntime = {
|
|
|
247
254
|
adapter,
|
|
248
255
|
binding: failureBinding,
|
|
249
256
|
agent: this.name,
|
|
250
|
-
sessionId:
|
|
257
|
+
sessionId: targetSessionId || binding.id,
|
|
251
258
|
turnId: failureInfo?.turnId || null,
|
|
252
259
|
cwd: agentHome,
|
|
253
260
|
replyToMessageId: inbound.messageId || null,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { reportSubprocessFailure, terminalRuntimeFailure } from '../../core/runtime-support.mjs';
|
|
2
|
+
import { getGoalTaskProtocolOverlayKey } from '../_shared/goal-task-protocol.mjs';
|
|
2
3
|
import { buildStandingPrompt } from '../_shared/standing-prompt.mjs';
|
|
3
4
|
import { GATEWAY_HOST, GATEWAY_PORT } from './identity.mjs';
|
|
4
5
|
|
|
@@ -24,10 +25,11 @@ async function probeOpenClawGatewayHealth() {
|
|
|
24
25
|
import { buildOpenClawSessionKey, normalizeOpenClawAgentId } from './target.mjs';
|
|
25
26
|
import { askGateway, isGatewayReady, registerOpenClawChannel } from './gateway.mjs';
|
|
26
27
|
|
|
27
|
-
// Tracks which (agentId, sessionKey
|
|
28
|
-
// prompt this process lifetime. OpenClaw's
|
|
29
|
-
// out of process, so we err on the side of
|
|
30
|
-
//
|
|
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.
|
|
31
33
|
const standingPromptSeen = new Set();
|
|
32
34
|
import { addInFlight, recoverInFlightEntries, removeInFlight } from './inflight.mjs';
|
|
33
35
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
@@ -159,13 +161,13 @@ export const openClawRuntime = {
|
|
|
159
161
|
const sessionId = String(meta.sessionKey || buildOpenClawSessionKey(agentId)).trim();
|
|
160
162
|
|
|
161
163
|
// Inject the standing prompt on the first observed turn after a
|
|
162
|
-
// daemon start for this (agent, session)
|
|
163
|
-
// separate "system prompt" parameter on the gateway, so we
|
|
164
|
-
//
|
|
165
|
-
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 })}`;
|
|
166
168
|
let prompt = rawPrompt;
|
|
167
169
|
if (!standingPromptSeen.has(standingKey)) {
|
|
168
|
-
const standing = buildStandingPrompt({ agentId: binding.id });
|
|
170
|
+
const standing = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
169
171
|
prompt = `${standing}\n\n---\n\n${rawPrompt}`;
|
|
170
172
|
standingPromptSeen.add(standingKey);
|
|
171
173
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { existsSync } from 'node:fs';
|
|
11
11
|
import { basename } from 'node:path';
|
|
12
12
|
import { buildAgentRuntimeEnv } from '../../core/runtime-env.mjs';
|
|
13
|
+
import { getGoalTaskProtocolOverlayKey } from '../_shared/goal-task-protocol.mjs';
|
|
13
14
|
import { buildStandingPrompt } from '../_shared/standing-prompt.mjs';
|
|
14
15
|
import { ensureAgentHome } from '../../core/agent-home.mjs';
|
|
15
16
|
import {
|
|
@@ -31,8 +32,12 @@ import {
|
|
|
31
32
|
reportSubprocessFailure,
|
|
32
33
|
terminalRuntimeFailure,
|
|
33
34
|
updateBindingRuntimeMeta,
|
|
35
|
+
resolveRuntimeSessionScope,
|
|
36
|
+
buildRuntimeSessionMetaPatch,
|
|
34
37
|
} from '../../core/runtime-support.mjs';
|
|
35
38
|
|
|
39
|
+
const standingPromptSeen = new Set();
|
|
40
|
+
|
|
36
41
|
export const openCodeRuntime = {
|
|
37
42
|
name: 'opencode',
|
|
38
43
|
|
|
@@ -48,6 +53,7 @@ export const openCodeRuntime = {
|
|
|
48
53
|
opencodePath,
|
|
49
54
|
agentEnv,
|
|
50
55
|
standingPrompt: opts.standingPrompt || null,
|
|
56
|
+
forceStandingPrompt: Boolean(opts.forceStandingPrompt),
|
|
51
57
|
files: opts.files,
|
|
52
58
|
timeoutMs: opts.timeoutMs,
|
|
53
59
|
});
|
|
@@ -61,6 +67,7 @@ export const openCodeRuntime = {
|
|
|
61
67
|
opencodePath,
|
|
62
68
|
agentEnv,
|
|
63
69
|
standingPrompt: opts.standingPrompt || null,
|
|
70
|
+
forceStandingPrompt: Boolean(opts.forceStandingPrompt),
|
|
64
71
|
files: opts.files,
|
|
65
72
|
timeoutMs: opts.timeoutMs,
|
|
66
73
|
onEvent: opts.onEvent,
|
|
@@ -156,7 +163,9 @@ export const openCodeRuntime = {
|
|
|
156
163
|
// instruction so it has something to anchor on.
|
|
157
164
|
message = captionText || 'Please analyze the attached image(s).';
|
|
158
165
|
}
|
|
159
|
-
const
|
|
166
|
+
const sessionScope = resolveRuntimeSessionScope(meta, inbound);
|
|
167
|
+
const shouldRotate = sessionScope.shouldRotate;
|
|
168
|
+
const targetSessionId = shouldRotate ? null : sessionScope.sessionId;
|
|
160
169
|
|
|
161
170
|
const deltaAggregator = createDeltaAggregator({
|
|
162
171
|
flushDelta: async ({ text, sessionId, cwd }) => {
|
|
@@ -164,7 +173,7 @@ export const openCodeRuntime = {
|
|
|
164
173
|
adapter,
|
|
165
174
|
binding,
|
|
166
175
|
agent: this.name,
|
|
167
|
-
sessionId: sessionId ||
|
|
176
|
+
sessionId: sessionId || targetSessionId || binding.id,
|
|
168
177
|
cwd: cwd || agentHome,
|
|
169
178
|
replyToMessageId: inbound.messageId || null,
|
|
170
179
|
event: {
|
|
@@ -182,13 +191,22 @@ export const openCodeRuntime = {
|
|
|
182
191
|
const opencodeVersion = getOpenCodeRuntimeHealth(opencodePath).version || meta.opencodeVersion || null;
|
|
183
192
|
const agentEnv = buildAgentRuntimeEnv({
|
|
184
193
|
agentId: binding.id,
|
|
185
|
-
sessionId:
|
|
194
|
+
sessionId: targetSessionId,
|
|
186
195
|
hostId: binding.runtime_host_id,
|
|
196
|
+
conversationId: inbound.conversationId,
|
|
197
|
+
messageId: inbound.messageId,
|
|
198
|
+
target: inbound.envelopeTarget,
|
|
187
199
|
});
|
|
188
|
-
const standingPrompt = buildStandingPrompt({ agentId: binding.id });
|
|
200
|
+
const standingPrompt = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
201
|
+
const protocolOverlayKey = getGoalTaskProtocolOverlayKey({ agentId: binding.id, inbound });
|
|
202
|
+
const standingPromptSeenKey = targetSessionId
|
|
203
|
+
? `${binding.id}|${targetSessionId}|${protocolOverlayKey}`
|
|
204
|
+
: null;
|
|
205
|
+
const forceStandingPrompt = Boolean(standingPromptSeenKey && !standingPromptSeen.has(standingPromptSeenKey));
|
|
189
206
|
const result = shouldStreamRuntime(this.name, this)
|
|
190
|
-
? await this.runTurnStream({ sessionId:
|
|
207
|
+
? await this.runTurnStream({ sessionId: targetSessionId, cwd: agentHome, opencodePath, agentEnv }, message, {
|
|
191
208
|
standingPrompt,
|
|
209
|
+
forceStandingPrompt,
|
|
192
210
|
files,
|
|
193
211
|
onEvent: async (event) => {
|
|
194
212
|
if (event?.type === 'turn.started') {
|
|
@@ -196,7 +214,7 @@ export const openCodeRuntime = {
|
|
|
196
214
|
adapter,
|
|
197
215
|
binding,
|
|
198
216
|
agent: this.name,
|
|
199
|
-
sessionId: event.sessionId ||
|
|
217
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
200
218
|
cwd: agentHome,
|
|
201
219
|
replyToMessageId: inbound.messageId || null,
|
|
202
220
|
event: {
|
|
@@ -207,29 +225,34 @@ export const openCodeRuntime = {
|
|
|
207
225
|
});
|
|
208
226
|
} else if (event?.type === 'message.delta' && event.text) {
|
|
209
227
|
deltaAggregator.push(event.text, {
|
|
210
|
-
sessionId: event.sessionId ||
|
|
228
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
211
229
|
cwd: agentHome,
|
|
212
230
|
});
|
|
213
231
|
}
|
|
214
232
|
},
|
|
215
233
|
})
|
|
216
|
-
: await this.runTurn({ sessionId:
|
|
234
|
+
: await this.runTurn({ sessionId: targetSessionId, cwd: agentHome, opencodePath, agentEnv }, message, { files, standingPrompt, forceStandingPrompt });
|
|
217
235
|
|
|
218
236
|
await deltaAggregator.flush();
|
|
237
|
+
const observedSessionId = result?.sessionId || targetSessionId;
|
|
238
|
+
if (observedSessionId) {
|
|
239
|
+
standingPromptSeen.add(`${binding.id}|${observedSessionId}|${protocolOverlayKey}`);
|
|
240
|
+
}
|
|
219
241
|
|
|
220
242
|
const nextBinding = await updateBindingRuntimeMeta(ctx, binding, {
|
|
221
|
-
|
|
243
|
+
...buildRuntimeSessionMetaPatch(meta, sessionScope, {
|
|
244
|
+
sessionId: result?.sessionId,
|
|
245
|
+
path: result?.path,
|
|
246
|
+
}),
|
|
222
247
|
runtimePath: opencodePath,
|
|
223
248
|
opencodePath,
|
|
224
249
|
opencodeVersion,
|
|
225
|
-
rotatePending: false,
|
|
226
|
-
lastRotatedAt: shouldRotate ? new Date().toISOString() : meta.lastRotatedAt,
|
|
227
250
|
}, { status: 'connected' });
|
|
228
251
|
await emitWorkerEvent({
|
|
229
252
|
adapter,
|
|
230
253
|
binding: nextBinding,
|
|
231
254
|
agent: this.name,
|
|
232
|
-
sessionId: result?.sessionId ||
|
|
255
|
+
sessionId: result?.sessionId || targetSessionId || binding.id,
|
|
233
256
|
cwd: result?.cwd || agentHome,
|
|
234
257
|
replyToMessageId: inbound.messageId || null,
|
|
235
258
|
event: {
|
|
@@ -245,7 +268,7 @@ export const openCodeRuntime = {
|
|
|
245
268
|
adapter,
|
|
246
269
|
binding,
|
|
247
270
|
agent: this.name,
|
|
248
|
-
sessionId:
|
|
271
|
+
sessionId: targetSessionId || binding.id,
|
|
249
272
|
cwd: agentHome,
|
|
250
273
|
replyToMessageId: inbound.messageId || null,
|
|
251
274
|
event: {
|
|
@@ -210,14 +210,15 @@ export function runOpenCodePrompt({
|
|
|
210
210
|
opencodePath = null,
|
|
211
211
|
agentEnv = null,
|
|
212
212
|
standingPrompt = null,
|
|
213
|
+
forceStandingPrompt = false,
|
|
213
214
|
timeoutMs = Number(process.env.OPENCODE_RUN_TIMEOUT_MS || DEFAULT_OPENCODE_RUN_TIMEOUT_MS),
|
|
214
215
|
onEvent,
|
|
215
216
|
}) {
|
|
216
217
|
// opencode has no documented `--system` flag, so we prepend the
|
|
217
|
-
// standing prompt to the first-turn message body.
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
const finalMessage = standingPrompt && !sessionId
|
|
218
|
+
// standing prompt to the first-turn message body. Callers may force a
|
|
219
|
+
// resumed-session injection when the selected protocol overlay changes
|
|
220
|
+
// or this daemon process has not yet observed the session.
|
|
221
|
+
const finalMessage = standingPrompt && (!sessionId || forceStandingPrompt)
|
|
221
222
|
? `${standingPrompt}\n\n---\n\n${message}`
|
|
222
223
|
: message;
|
|
223
224
|
return new Promise((resolve, reject) => {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { basename } from 'node:path';
|
|
8
8
|
import { buildAgentRuntimeEnv } from '../../core/runtime-env.mjs';
|
|
9
|
+
import { getGoalTaskProtocolOverlayKey } from '../_shared/goal-task-protocol.mjs';
|
|
9
10
|
import { buildStandingPrompt } from '../_shared/standing-prompt.mjs';
|
|
10
11
|
import { ensureAgentHome } from '../../core/agent-home.mjs';
|
|
11
12
|
import {
|
|
@@ -25,8 +26,12 @@ import {
|
|
|
25
26
|
reportSubprocessFailure,
|
|
26
27
|
terminalRuntimeFailure,
|
|
27
28
|
updateBindingRuntimeMeta,
|
|
29
|
+
resolveRuntimeSessionScope,
|
|
30
|
+
buildRuntimeSessionMetaPatch,
|
|
28
31
|
} from '../../core/runtime-support.mjs';
|
|
29
32
|
|
|
33
|
+
const standingPromptSeen = new Set();
|
|
34
|
+
|
|
30
35
|
export const piRuntime = {
|
|
31
36
|
name: 'pi',
|
|
32
37
|
|
|
@@ -39,6 +44,7 @@ export const piRuntime = {
|
|
|
39
44
|
piPath,
|
|
40
45
|
agentEnv,
|
|
41
46
|
standingPrompt: opts.standingPrompt || null,
|
|
47
|
+
forceStandingPrompt: Boolean(opts.forceStandingPrompt),
|
|
42
48
|
timeoutMs: opts.timeoutMs,
|
|
43
49
|
});
|
|
44
50
|
},
|
|
@@ -52,6 +58,7 @@ export const piRuntime = {
|
|
|
52
58
|
piPath,
|
|
53
59
|
agentEnv,
|
|
54
60
|
standingPrompt: opts.standingPrompt || null,
|
|
61
|
+
forceStandingPrompt: Boolean(opts.forceStandingPrompt),
|
|
55
62
|
timeoutMs: opts.timeoutMs,
|
|
56
63
|
onEvent: opts.onEvent,
|
|
57
64
|
});
|
|
@@ -128,14 +135,16 @@ export const piRuntime = {
|
|
|
128
135
|
message = captionText || 'Please analyze the attached image(s).';
|
|
129
136
|
}
|
|
130
137
|
|
|
131
|
-
const
|
|
138
|
+
const sessionScope = resolveRuntimeSessionScope(meta, inbound);
|
|
139
|
+
const shouldRotate = sessionScope.shouldRotate;
|
|
140
|
+
const targetSessionId = shouldRotate ? null : sessionScope.sessionId;
|
|
132
141
|
const deltaAggregator = createDeltaAggregator({
|
|
133
142
|
flushDelta: async ({ text, sessionId, cwd }) => {
|
|
134
143
|
await emitWorkerEvent({
|
|
135
144
|
adapter,
|
|
136
145
|
binding,
|
|
137
146
|
agent: this.name,
|
|
138
|
-
sessionId: sessionId ||
|
|
147
|
+
sessionId: sessionId || targetSessionId || binding.id,
|
|
139
148
|
cwd: cwd || agentHome,
|
|
140
149
|
replyToMessageId: inbound.messageId || null,
|
|
141
150
|
event: {
|
|
@@ -153,13 +162,22 @@ export const piRuntime = {
|
|
|
153
162
|
const runtimePiVersion = getPiRuntimeHealth(runtimePiPath).version || meta.piVersion || null;
|
|
154
163
|
const agentEnv = buildAgentRuntimeEnv({
|
|
155
164
|
agentId: binding.id,
|
|
156
|
-
sessionId:
|
|
165
|
+
sessionId: targetSessionId,
|
|
157
166
|
hostId: binding.runtime_host_id,
|
|
167
|
+
conversationId: inbound.conversationId,
|
|
168
|
+
messageId: inbound.messageId,
|
|
169
|
+
target: inbound.envelopeTarget,
|
|
158
170
|
});
|
|
159
|
-
const standingPrompt = buildStandingPrompt({ agentId: binding.id });
|
|
171
|
+
const standingPrompt = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
172
|
+
const protocolOverlayKey = getGoalTaskProtocolOverlayKey({ agentId: binding.id, inbound });
|
|
173
|
+
const standingPromptSeenKey = targetSessionId
|
|
174
|
+
? `${binding.id}|${targetSessionId}|${protocolOverlayKey}`
|
|
175
|
+
: null;
|
|
176
|
+
const forceStandingPrompt = Boolean(standingPromptSeenKey && !standingPromptSeen.has(standingPromptSeenKey));
|
|
160
177
|
const result = shouldStreamRuntime(this.name, this)
|
|
161
|
-
? await this.runTurnStream({ sessionId:
|
|
178
|
+
? await this.runTurnStream({ sessionId: targetSessionId, cwd: agentHome, piPath: runtimePiPath, agentEnv }, message, {
|
|
162
179
|
standingPrompt,
|
|
180
|
+
forceStandingPrompt,
|
|
163
181
|
images,
|
|
164
182
|
onEvent: async (event) => {
|
|
165
183
|
if (event?.type === 'turn.started') {
|
|
@@ -167,7 +185,7 @@ export const piRuntime = {
|
|
|
167
185
|
adapter,
|
|
168
186
|
binding,
|
|
169
187
|
agent: this.name,
|
|
170
|
-
sessionId: event.sessionId ||
|
|
188
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
171
189
|
cwd: agentHome,
|
|
172
190
|
replyToMessageId: inbound.messageId || null,
|
|
173
191
|
event: {
|
|
@@ -178,29 +196,33 @@ export const piRuntime = {
|
|
|
178
196
|
});
|
|
179
197
|
} else if (event?.type === 'message.delta' && event.text) {
|
|
180
198
|
deltaAggregator.push(event.text, {
|
|
181
|
-
sessionId: event.sessionId ||
|
|
199
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
182
200
|
cwd: agentHome,
|
|
183
201
|
});
|
|
184
202
|
}
|
|
185
203
|
},
|
|
186
204
|
})
|
|
187
|
-
: await this.runTurn({ sessionId:
|
|
205
|
+
: await this.runTurn({ sessionId: targetSessionId, cwd: agentHome, piPath: runtimePiPath, agentEnv }, message, { images, standingPrompt, forceStandingPrompt });
|
|
188
206
|
|
|
189
207
|
await deltaAggregator.flush();
|
|
208
|
+
const observedSessionId = result?.sessionId || targetSessionId;
|
|
209
|
+
if (observedSessionId) {
|
|
210
|
+
standingPromptSeen.add(`${binding.id}|${observedSessionId}|${protocolOverlayKey}`);
|
|
211
|
+
}
|
|
190
212
|
const nextBinding = await updateBindingRuntimeMeta(ctx, binding, {
|
|
191
|
-
|
|
192
|
-
|
|
213
|
+
...buildRuntimeSessionMetaPatch(meta, sessionScope, {
|
|
214
|
+
sessionId: result?.sessionId,
|
|
215
|
+
path: result?.path,
|
|
216
|
+
}),
|
|
193
217
|
runtimePath: runtimePiPath,
|
|
194
218
|
piPath: runtimePiPath,
|
|
195
219
|
piVersion: runtimePiVersion,
|
|
196
|
-
rotatePending: false,
|
|
197
|
-
lastRotatedAt: shouldRotate ? new Date().toISOString() : meta.lastRotatedAt,
|
|
198
220
|
}, { status: 'connected' });
|
|
199
221
|
await emitWorkerEvent({
|
|
200
222
|
adapter,
|
|
201
223
|
binding: nextBinding,
|
|
202
224
|
agent: this.name,
|
|
203
|
-
sessionId: result?.sessionId ||
|
|
225
|
+
sessionId: result?.sessionId || targetSessionId || binding.id,
|
|
204
226
|
cwd: result?.cwd || agentHome,
|
|
205
227
|
replyToMessageId: inbound.messageId || null,
|
|
206
228
|
event: {
|
|
@@ -216,7 +238,7 @@ export const piRuntime = {
|
|
|
216
238
|
adapter,
|
|
217
239
|
binding,
|
|
218
240
|
agent: this.name,
|
|
219
|
-
sessionId:
|
|
241
|
+
sessionId: targetSessionId || binding.id,
|
|
220
242
|
cwd: agentHome,
|
|
221
243
|
replyToMessageId: inbound.messageId || null,
|
|
222
244
|
event: {
|
|
@@ -197,11 +197,14 @@ export function runPiPrompt({
|
|
|
197
197
|
piPath = null,
|
|
198
198
|
agentEnv = null,
|
|
199
199
|
standingPrompt = null,
|
|
200
|
+
forceStandingPrompt = false,
|
|
200
201
|
timeoutMs = Number(process.env.PI_RUN_TIMEOUT_MS || DEFAULT_PI_RUN_TIMEOUT_MS),
|
|
201
202
|
onEvent,
|
|
202
203
|
}) {
|
|
203
|
-
// pi has no documented system-prompt flag
|
|
204
|
-
|
|
204
|
+
// pi has no documented system-prompt flag. Prepend on first turn, and
|
|
205
|
+
// let callers force one resumed-session injection for a newly selected
|
|
206
|
+
// protocol overlay.
|
|
207
|
+
const finalMessage = standingPrompt && (!sessionId || forceStandingPrompt)
|
|
205
208
|
? `${standingPrompt}\n\n---\n\n${message}`
|
|
206
209
|
: message;
|
|
207
210
|
return new Promise((resolve, reject) => {
|