ticlawk 0.1.16-dev.9 → 0.1.17-dev.1
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 +17 -3
- package/bin/ticlawk.mjs +255 -21
- package/package.json +1 -1
- package/src/adapters/ticlawk/api.mjs +350 -50
- package/src/adapters/ticlawk/credentials.mjs +41 -1
- package/src/adapters/ticlawk/index.mjs +248 -130
- package/src/adapters/ticlawk/wake-client.mjs +1 -1
- package/src/cli/agent-commands.mjs +715 -18
- package/src/core/agent-cli-handlers.mjs +556 -18
- package/src/core/agent-home.mjs +81 -1
- package/src/core/argv.mjs +11 -1
- package/src/core/events/worker-events.mjs +32 -36
- package/src/core/http.mjs +152 -0
- package/src/core/runtime-contract.mjs +0 -1
- package/src/core/runtime-env.mjs +7 -0
- package/src/core/runtime-support.mjs +130 -78
- package/src/runtimes/_shared/agent-handbook.mjs +45 -0
- package/src/runtimes/_shared/brand.mjs +2 -0
- package/src/runtimes/_shared/goal-step-prompt.mjs +98 -0
- package/src/runtimes/_shared/goal-task-protocol.mjs +50 -0
- package/src/runtimes/_shared/handbook/BASICS.md +27 -0
- package/src/runtimes/_shared/handbook/COLLABORATION.md +37 -0
- package/src/runtimes/_shared/handbook/COMMUNICATION.md +55 -0
- package/src/runtimes/_shared/handbook/DM_SCOPE.md +13 -0
- package/src/runtimes/_shared/handbook/GOAL_AUTHORITY.md +47 -0
- package/src/runtimes/_shared/handbook/GOAL_TASK_CORE.md +43 -0
- package/src/runtimes/_shared/handbook/GROUP_ADMIN_SCOPE.md +21 -0
- package/src/runtimes/_shared/handbook/GROUP_MEMBER_SCOPE.md +15 -0
- package/src/runtimes/_shared/handbook/SURFACES.md +41 -0
- package/src/runtimes/_shared/handbook/TASK_WORKER.md +14 -0
- package/src/runtimes/_shared/standing-prompt.mjs +124 -279
- package/src/runtimes/_shared/wake-prompt.mjs +268 -0
- package/src/runtimes/claude-code/index.mjs +19 -46
- package/src/runtimes/claude-code/session.mjs +2 -7
- package/src/runtimes/codex/index.mjs +115 -63
- package/src/runtimes/codex/session.mjs +2 -12
- package/src/runtimes/openclaw/index.mjs +11 -24
- package/src/runtimes/opencode/index.mjs +38 -60
- package/src/runtimes/opencode/session.mjs +12 -12
- package/src/runtimes/pi/index.mjs +38 -60
- package/src/runtimes/pi/session.mjs +9 -6
- package/ticlawk.mjs +0 -30
|
@@ -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 {
|
|
@@ -18,15 +19,18 @@ import {
|
|
|
18
19
|
requirePiPath,
|
|
19
20
|
runPiPrompt,
|
|
20
21
|
} from './session.mjs';
|
|
21
|
-
import {
|
|
22
|
+
import { emitWorkerEventBestEffort } from '../../core/events/worker-events.mjs';
|
|
22
23
|
import {
|
|
23
24
|
shouldStreamRuntime,
|
|
24
|
-
createDeltaAggregator,
|
|
25
25
|
reportSubprocessFailure,
|
|
26
26
|
terminalRuntimeFailure,
|
|
27
27
|
updateBindingRuntimeMeta,
|
|
28
|
+
resolveRuntimeSessionScope,
|
|
29
|
+
buildRuntimeSessionMetaPatch,
|
|
28
30
|
} from '../../core/runtime-support.mjs';
|
|
29
31
|
|
|
32
|
+
const standingPromptSeen = new Set();
|
|
33
|
+
|
|
30
34
|
export const piRuntime = {
|
|
31
35
|
name: 'pi',
|
|
32
36
|
|
|
@@ -39,6 +43,7 @@ export const piRuntime = {
|
|
|
39
43
|
piPath,
|
|
40
44
|
agentEnv,
|
|
41
45
|
standingPrompt: opts.standingPrompt || null,
|
|
46
|
+
forceStandingPrompt: Boolean(opts.forceStandingPrompt),
|
|
42
47
|
timeoutMs: opts.timeoutMs,
|
|
43
48
|
});
|
|
44
49
|
},
|
|
@@ -52,6 +57,7 @@ export const piRuntime = {
|
|
|
52
57
|
piPath,
|
|
53
58
|
agentEnv,
|
|
54
59
|
standingPrompt: opts.standingPrompt || null,
|
|
60
|
+
forceStandingPrompt: Boolean(opts.forceStandingPrompt),
|
|
55
61
|
timeoutMs: opts.timeoutMs,
|
|
56
62
|
onEvent: opts.onEvent,
|
|
57
63
|
});
|
|
@@ -128,46 +134,39 @@ export const piRuntime = {
|
|
|
128
134
|
message = captionText || 'Please analyze the attached image(s).';
|
|
129
135
|
}
|
|
130
136
|
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
await emitWorkerEvent({
|
|
135
|
-
adapter,
|
|
136
|
-
binding,
|
|
137
|
-
agent: this.name,
|
|
138
|
-
sessionId: sessionId || meta.sessionId || binding.id,
|
|
139
|
-
cwd: cwd || agentHome,
|
|
140
|
-
replyToMessageId: inbound.messageId || null,
|
|
141
|
-
event: {
|
|
142
|
-
hook_event_name: 'worker.message.delta',
|
|
143
|
-
worker_event_name: 'worker.message.delta',
|
|
144
|
-
delta: text,
|
|
145
|
-
},
|
|
146
|
-
logger: ctx.logger,
|
|
147
|
-
});
|
|
148
|
-
},
|
|
149
|
-
});
|
|
137
|
+
const sessionScope = resolveRuntimeSessionScope(meta, inbound);
|
|
138
|
+
const shouldRotate = sessionScope.shouldRotate;
|
|
139
|
+
const targetSessionId = shouldRotate ? null : sessionScope.sessionId;
|
|
150
140
|
|
|
151
141
|
try {
|
|
152
142
|
const runtimePiPath = requirePiPath(meta.piPath || meta.runtimePath);
|
|
153
143
|
const runtimePiVersion = getPiRuntimeHealth(runtimePiPath).version || meta.piVersion || null;
|
|
154
144
|
const agentEnv = buildAgentRuntimeEnv({
|
|
155
145
|
agentId: binding.id,
|
|
156
|
-
sessionId:
|
|
146
|
+
sessionId: targetSessionId,
|
|
157
147
|
hostId: binding.runtime_host_id,
|
|
148
|
+
conversationId: inbound.conversationId,
|
|
149
|
+
messageId: inbound.messageId,
|
|
150
|
+
target: inbound.envelopeTarget,
|
|
158
151
|
});
|
|
159
|
-
const standingPrompt = buildStandingPrompt({ agentId: binding.id });
|
|
152
|
+
const standingPrompt = buildStandingPrompt({ agentId: binding.id, inbound });
|
|
153
|
+
const protocolOverlayKey = getGoalTaskProtocolOverlayKey({ agentId: binding.id, inbound });
|
|
154
|
+
const standingPromptSeenKey = targetSessionId
|
|
155
|
+
? `${binding.id}|${targetSessionId}|${protocolOverlayKey}`
|
|
156
|
+
: null;
|
|
157
|
+
const forceStandingPrompt = Boolean(standingPromptSeenKey && !standingPromptSeen.has(standingPromptSeenKey));
|
|
160
158
|
const result = shouldStreamRuntime(this.name, this)
|
|
161
|
-
? await this.runTurnStream({ sessionId:
|
|
159
|
+
? await this.runTurnStream({ sessionId: targetSessionId, cwd: agentHome, piPath: runtimePiPath, agentEnv }, message, {
|
|
162
160
|
standingPrompt,
|
|
161
|
+
forceStandingPrompt,
|
|
163
162
|
images,
|
|
164
163
|
onEvent: async (event) => {
|
|
165
164
|
if (event?.type === 'turn.started') {
|
|
166
|
-
|
|
165
|
+
emitWorkerEventBestEffort({
|
|
167
166
|
adapter,
|
|
168
167
|
binding,
|
|
169
168
|
agent: this.name,
|
|
170
|
-
sessionId: event.sessionId ||
|
|
169
|
+
sessionId: event.sessionId || targetSessionId || binding.id,
|
|
171
170
|
cwd: agentHome,
|
|
172
171
|
replyToMessageId: inbound.messageId || null,
|
|
173
172
|
event: {
|
|
@@ -176,31 +175,29 @@ export const piRuntime = {
|
|
|
176
175
|
},
|
|
177
176
|
logger: ctx.logger,
|
|
178
177
|
});
|
|
179
|
-
} else if (event?.type === 'message.delta' && event.text) {
|
|
180
|
-
deltaAggregator.push(event.text, {
|
|
181
|
-
sessionId: event.sessionId || meta.sessionId || binding.id,
|
|
182
|
-
cwd: agentHome,
|
|
183
|
-
});
|
|
184
178
|
}
|
|
185
179
|
},
|
|
186
180
|
})
|
|
187
|
-
: await this.runTurn({ sessionId:
|
|
181
|
+
: await this.runTurn({ sessionId: targetSessionId, cwd: agentHome, piPath: runtimePiPath, agentEnv }, message, { images, standingPrompt, forceStandingPrompt });
|
|
188
182
|
|
|
189
|
-
|
|
183
|
+
const observedSessionId = result?.sessionId || targetSessionId;
|
|
184
|
+
if (observedSessionId) {
|
|
185
|
+
standingPromptSeen.add(`${binding.id}|${observedSessionId}|${protocolOverlayKey}`);
|
|
186
|
+
}
|
|
190
187
|
const nextBinding = await updateBindingRuntimeMeta(ctx, binding, {
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
...buildRuntimeSessionMetaPatch(meta, sessionScope, {
|
|
189
|
+
sessionId: result?.sessionId,
|
|
190
|
+
path: result?.path,
|
|
191
|
+
}),
|
|
193
192
|
runtimePath: runtimePiPath,
|
|
194
193
|
piPath: runtimePiPath,
|
|
195
194
|
piVersion: runtimePiVersion,
|
|
196
|
-
rotatePending: false,
|
|
197
|
-
lastRotatedAt: shouldRotate ? new Date().toISOString() : meta.lastRotatedAt,
|
|
198
195
|
}, { status: 'connected' });
|
|
199
|
-
|
|
196
|
+
emitWorkerEventBestEffort({
|
|
200
197
|
adapter,
|
|
201
198
|
binding: nextBinding,
|
|
202
199
|
agent: this.name,
|
|
203
|
-
sessionId: result?.sessionId ||
|
|
200
|
+
sessionId: result?.sessionId || targetSessionId || binding.id,
|
|
204
201
|
cwd: result?.cwd || agentHome,
|
|
205
202
|
replyToMessageId: inbound.messageId || null,
|
|
206
203
|
event: {
|
|
@@ -211,12 +208,11 @@ export const piRuntime = {
|
|
|
211
208
|
});
|
|
212
209
|
return true;
|
|
213
210
|
} catch (err) {
|
|
214
|
-
|
|
215
|
-
await emitWorkerEvent({
|
|
211
|
+
emitWorkerEventBestEffort({
|
|
216
212
|
adapter,
|
|
217
213
|
binding,
|
|
218
214
|
agent: this.name,
|
|
219
|
-
sessionId:
|
|
215
|
+
sessionId: targetSessionId || binding.id,
|
|
220
216
|
cwd: agentHome,
|
|
221
217
|
replyToMessageId: inbound.messageId || null,
|
|
222
218
|
event: {
|
|
@@ -242,24 +238,6 @@ export const piRuntime = {
|
|
|
242
238
|
}
|
|
243
239
|
},
|
|
244
240
|
|
|
245
|
-
async reconcileAfterRestart(binding, ctx) {
|
|
246
|
-
const meta = binding.runtimeMeta || {};
|
|
247
|
-
await emitWorkerEvent({
|
|
248
|
-
adapter: ctx.adapter,
|
|
249
|
-
binding,
|
|
250
|
-
agent: this.name,
|
|
251
|
-
sessionId: meta.sessionId || binding.id,
|
|
252
|
-
cwd: ensureAgentHome(binding.id) || '',
|
|
253
|
-
event: {
|
|
254
|
-
hook_event_name: 'Stop',
|
|
255
|
-
worker_event_name: 'worker.turn.complete',
|
|
256
|
-
reason: 'connector.restart.reconcile',
|
|
257
|
-
},
|
|
258
|
-
logger: ctx.logger,
|
|
259
|
-
});
|
|
260
|
-
return 1;
|
|
261
|
-
},
|
|
262
|
-
|
|
263
241
|
sessionsDir: PI_SESSIONS_DIR,
|
|
264
242
|
maxAgeMs: PI_MAX_AGE_MS,
|
|
265
243
|
};
|
|
@@ -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) => {
|
|
@@ -220,12 +223,13 @@ export function runPiPrompt({
|
|
|
220
223
|
let activeSessionFile = null;
|
|
221
224
|
let finalText = '';
|
|
222
225
|
let settled = false;
|
|
223
|
-
let eventChain = Promise.resolve();
|
|
224
226
|
const pending = new Map();
|
|
225
227
|
|
|
226
228
|
const emit = (event) => {
|
|
227
229
|
if (typeof onEvent !== 'function') return;
|
|
228
|
-
|
|
230
|
+
void Promise.resolve()
|
|
231
|
+
.then(() => onEvent(event))
|
|
232
|
+
.catch(() => {});
|
|
229
233
|
};
|
|
230
234
|
|
|
231
235
|
const settle = (fn, value) => {
|
|
@@ -237,7 +241,7 @@ export function runPiPrompt({
|
|
|
237
241
|
}
|
|
238
242
|
pending.clear();
|
|
239
243
|
try { child.kill('SIGTERM'); } catch {}
|
|
240
|
-
|
|
244
|
+
fn(value);
|
|
241
245
|
};
|
|
242
246
|
|
|
243
247
|
const sendRaw = (payload) => {
|
|
@@ -305,7 +309,6 @@ export function runPiPrompt({
|
|
|
305
309
|
const delta = extractDeltaFromEvent(event);
|
|
306
310
|
if (delta) {
|
|
307
311
|
finalText += delta;
|
|
308
|
-
emit({ type: 'message.delta', sessionId: activeSessionId, text: delta });
|
|
309
312
|
}
|
|
310
313
|
return;
|
|
311
314
|
}
|
package/ticlawk.mjs
CHANGED
|
@@ -211,35 +211,6 @@ async function recoverAllRuntimes(runtimeList, adapter) {
|
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
async function reconcileBindingsAfterRestart(runtimes, adapter) {
|
|
215
|
-
const hostId = getHostId();
|
|
216
|
-
for (const binding of listBindings({ adapter: adapter.id })) {
|
|
217
|
-
if (!belongsToRuntimeHost(binding, hostId)) {
|
|
218
|
-
logger.debugError('core', 'binding.reconcile-host-mismatch', {
|
|
219
|
-
bindingId: binding.id,
|
|
220
|
-
adapter: binding.adapter,
|
|
221
|
-
hostId,
|
|
222
|
-
runtime_host_id: getBindingRuntimeHostId(binding),
|
|
223
|
-
});
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
const runtime = binding.runtime ? runtimes[binding.runtime] : null;
|
|
227
|
-
if (typeof runtime?.reconcileAfterRestart !== 'function') continue;
|
|
228
|
-
try {
|
|
229
|
-
await runtime.reconcileAfterRestart(binding, {
|
|
230
|
-
adapter,
|
|
231
|
-
logger,
|
|
232
|
-
});
|
|
233
|
-
} catch (err) {
|
|
234
|
-
logger.debugError('startup', 'reconcileAfterRestart.failed', {
|
|
235
|
-
runtime: binding.runtime,
|
|
236
|
-
bindingId: binding.id,
|
|
237
|
-
error: err?.message || String(err),
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
214
|
export async function startTiclawk() {
|
|
244
215
|
if (started) return;
|
|
245
216
|
started = true;
|
|
@@ -278,7 +249,6 @@ export async function startTiclawk() {
|
|
|
278
249
|
});
|
|
279
250
|
startReminderTicker();
|
|
280
251
|
await recoverAllRuntimes(runtimeList, adapter);
|
|
281
|
-
await reconcileBindingsAfterRestart(runtimes, adapter);
|
|
282
252
|
await adapter.start();
|
|
283
253
|
}
|
|
284
254
|
|