ticlawk 0.1.17-dev.2 → 0.1.17-dev.20
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 +26 -59
- package/bin/ticlawk.mjs +31 -301
- package/package.json +4 -2
- package/scripts/publish-dev.sh +77 -0
- package/src/adapters/ticlawk/api.mjs +50 -378
- package/src/adapters/ticlawk/credentials.mjs +1 -43
- package/src/adapters/ticlawk/index.mjs +61 -565
- package/src/adapters/ticlawk/wake-client.mjs +1 -1
- package/src/cli/agent-commands.mjs +18 -715
- package/src/core/adapter-registry.mjs +1 -19
- package/src/core/agent-cli-handlers.mjs +18 -556
- package/src/core/agent-home.mjs +1 -81
- package/src/core/events/worker-events.mjs +36 -32
- package/src/core/http.mjs +0 -152
- package/src/core/profiles.mjs +0 -1
- package/src/core/runtime-contract.mjs +1 -0
- package/src/core/runtime-env.mjs +0 -8
- package/src/core/runtime-support.mjs +78 -130
- package/src/runtimes/_shared/incoming-message-prompt.mjs +232 -0
- package/src/runtimes/_shared/runtime-base-instructions.mjs +34 -0
- package/src/runtimes/claude-code/index.mjs +48 -21
- package/src/runtimes/claude-code/session.mjs +7 -2
- package/src/runtimes/codex/index.mjs +64 -116
- package/src/runtimes/codex/session.mjs +12 -2
- package/src/runtimes/openclaw/index.mjs +30 -17
- package/src/runtimes/opencode/index.mjs +64 -42
- package/src/runtimes/opencode/session.mjs +14 -14
- package/src/runtimes/pi/index.mjs +64 -42
- package/src/runtimes/pi/session.mjs +8 -11
- package/ticlawk.mjs +32 -5
- package/src/runtimes/_shared/agent-handbook.mjs +0 -45
- package/src/runtimes/_shared/brand.mjs +0 -2
- package/src/runtimes/_shared/goal-step-prompt.mjs +0 -98
- package/src/runtimes/_shared/goal-task-protocol.mjs +0 -50
- package/src/runtimes/_shared/handbook/BASICS.md +0 -27
- package/src/runtimes/_shared/handbook/COLLABORATION.md +0 -37
- package/src/runtimes/_shared/handbook/COMMUNICATION.md +0 -55
- package/src/runtimes/_shared/handbook/DM_SCOPE.md +0 -13
- package/src/runtimes/_shared/handbook/GOAL_AUTHORITY.md +0 -47
- package/src/runtimes/_shared/handbook/GOAL_TASK_CORE.md +0 -43
- package/src/runtimes/_shared/handbook/GROUP_ADMIN_SCOPE.md +0 -21
- package/src/runtimes/_shared/handbook/GROUP_MEMBER_SCOPE.md +0 -15
- package/src/runtimes/_shared/handbook/SURFACES.md +0 -41
- package/src/runtimes/_shared/handbook/TASK_WORKER.md +0 -14
- package/src/runtimes/_shared/standing-prompt.mjs +0 -171
- package/src/runtimes/_shared/wake-prompt.mjs +0 -268
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
cd "$ROOT_DIR"
|
|
6
|
+
|
|
7
|
+
EXPECTED_VERSION=""
|
|
8
|
+
DRY_RUN=false
|
|
9
|
+
|
|
10
|
+
while [[ $# -gt 0 ]]; do
|
|
11
|
+
case "$1" in
|
|
12
|
+
--expected-version)
|
|
13
|
+
EXPECTED_VERSION="${2:-}"
|
|
14
|
+
if [[ -z "$EXPECTED_VERSION" ]]; then
|
|
15
|
+
echo "--expected-version requires a value" >&2
|
|
16
|
+
exit 2
|
|
17
|
+
fi
|
|
18
|
+
shift 2
|
|
19
|
+
;;
|
|
20
|
+
--dry-run)
|
|
21
|
+
DRY_RUN=true
|
|
22
|
+
shift
|
|
23
|
+
;;
|
|
24
|
+
*)
|
|
25
|
+
echo "unknown argument: $1" >&2
|
|
26
|
+
echo "usage: npm run publish:dev -- [--expected-version X.Y.Z-dev.N] [--dry-run]" >&2
|
|
27
|
+
exit 2
|
|
28
|
+
;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
VERSION="$(node -p "JSON.parse(require('fs').readFileSync('package.json', 'utf8')).version")"
|
|
33
|
+
|
|
34
|
+
if [[ -n "$EXPECTED_VERSION" && "$EXPECTED_VERSION" != "$VERSION" ]]; then
|
|
35
|
+
echo "expected version ($EXPECTED_VERSION) does not match cli/package.json ($VERSION)" >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
if [[ "$VERSION" != *-* ]]; then
|
|
40
|
+
echo "refusing to publish stable version $VERSION with the dev script" >&2
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
NPM_ARGS=(--registry https://registry.npmjs.org/)
|
|
45
|
+
TMP_NPMRC=""
|
|
46
|
+
if [[ -n "${NPM_TOKEN:-}" ]]; then
|
|
47
|
+
TMP_NPMRC="$(mktemp)"
|
|
48
|
+
chmod 0600 "$TMP_NPMRC"
|
|
49
|
+
printf '//registry.npmjs.org/:_authToken=%s\n' "$NPM_TOKEN" > "$TMP_NPMRC"
|
|
50
|
+
NPM_ARGS+=(--userconfig "$TMP_NPMRC")
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
cleanup() {
|
|
54
|
+
if [[ -n "$TMP_NPMRC" ]]; then
|
|
55
|
+
rm -f "$TMP_NPMRC"
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
trap cleanup EXIT
|
|
59
|
+
|
|
60
|
+
if npm "${NPM_ARGS[@]}" view "ticlawk@$VERSION" version >/dev/null 2>&1; then
|
|
61
|
+
echo "ticlawk@$VERSION is already published" >&2
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if ! npm "${NPM_ARGS[@]}" whoami >/dev/null; then
|
|
66
|
+
echo "npm auth failed; run npm login or set a valid NPM_TOKEN with publish access to ticlawk" >&2
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
npm run verify:public-package
|
|
71
|
+
|
|
72
|
+
PUBLISH_ARGS=(publish --access public --tag dev)
|
|
73
|
+
if [[ "$DRY_RUN" == "true" ]]; then
|
|
74
|
+
PUBLISH_ARGS+=(--dry-run)
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
npm "${NPM_ARGS[@]}" "${PUBLISH_ARGS[@]}"
|
|
@@ -30,9 +30,8 @@ export function getConnectorWsUrl() {
|
|
|
30
30
|
return DEFAULT_CONNECTOR_WS_URL;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
// delivery lifecycle.
|
|
33
|
+
// Agent event writes must preserve per-agent order while still allowing
|
|
34
|
+
// different agents to proceed concurrently.
|
|
36
35
|
const agentEventQueues = new Map(); // agentId -> Promise
|
|
37
36
|
|
|
38
37
|
export class TiclawkUpdateRequiredError extends Error {
|
|
@@ -152,13 +151,13 @@ export async function updateChannel(id, updates) {
|
|
|
152
151
|
|
|
153
152
|
// ── Deliveries (replaces legacy message_jobs poll/ack) ──
|
|
154
153
|
|
|
155
|
-
export async function claimPendingDeliveries(hostId, limit = 5,
|
|
154
|
+
export async function claimPendingDeliveries(hostId, limit = 5, excludedAgentIds = []) {
|
|
156
155
|
const { data } = await apiFetch('/api/agent/deliveries/claim-pending', {
|
|
157
156
|
method: 'POST',
|
|
158
157
|
body: JSON.stringify(withTiclawkVersion({
|
|
159
158
|
runtime_host_id: hostId,
|
|
160
159
|
limit,
|
|
161
|
-
|
|
160
|
+
excluded_agent_ids: excludedAgentIds,
|
|
162
161
|
})),
|
|
163
162
|
});
|
|
164
163
|
return data || [];
|
|
@@ -189,7 +188,6 @@ export async function sendAgentMessage({
|
|
|
189
188
|
runtimeHostId,
|
|
190
189
|
visibility,
|
|
191
190
|
mediaAssetIds,
|
|
192
|
-
metadata,
|
|
193
191
|
}) {
|
|
194
192
|
const { data } = await apiFetch('/api/agent/messages/send', {
|
|
195
193
|
method: 'POST',
|
|
@@ -202,7 +200,6 @@ export async function sendAgentMessage({
|
|
|
202
200
|
runtime_host_id: runtimeHostId ?? null,
|
|
203
201
|
visibility: visibility || null,
|
|
204
202
|
media_asset_ids: Array.isArray(mediaAssetIds) && mediaAssetIds.length > 0 ? mediaAssetIds : undefined,
|
|
205
|
-
metadata: metadata ?? undefined,
|
|
206
203
|
}),
|
|
207
204
|
});
|
|
208
205
|
return data || null;
|
|
@@ -225,7 +222,7 @@ export async function readAgentMessages({
|
|
|
225
222
|
return data || [];
|
|
226
223
|
}
|
|
227
224
|
|
|
228
|
-
export async function createAgentTask({ actingAgentId, conversationId, text, title
|
|
225
|
+
export async function createAgentTask({ actingAgentId, conversationId, text, title }) {
|
|
229
226
|
return apiFetch('/api/agent/tasks/create', {
|
|
230
227
|
method: 'POST',
|
|
231
228
|
body: JSON.stringify({
|
|
@@ -233,7 +230,6 @@ export async function createAgentTask({ actingAgentId, conversationId, text, tit
|
|
|
233
230
|
conversation_id: conversationId,
|
|
234
231
|
text,
|
|
235
232
|
title: title ?? null,
|
|
236
|
-
assign_agent_id: assignAgentId ?? null,
|
|
237
233
|
}),
|
|
238
234
|
});
|
|
239
235
|
}
|
|
@@ -286,71 +282,6 @@ export async function updateAgentTask({ actingAgentId, taskId, status }) {
|
|
|
286
282
|
});
|
|
287
283
|
}
|
|
288
284
|
|
|
289
|
-
export async function reportGoalTransition({
|
|
290
|
-
actingAgentId, conversationId, transitionId, outcome, detail, currentTaskId,
|
|
291
|
-
}) {
|
|
292
|
-
return apiFetch('/api/agent/goal/report', {
|
|
293
|
-
method: 'POST',
|
|
294
|
-
body: JSON.stringify({
|
|
295
|
-
acting_as_agent_id: actingAgentId,
|
|
296
|
-
conversation_id: conversationId,
|
|
297
|
-
transition_id: transitionId,
|
|
298
|
-
outcome,
|
|
299
|
-
detail: detail ?? null,
|
|
300
|
-
current_task_id: currentTaskId ?? null,
|
|
301
|
-
}),
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
export async function noteGoalChanged({ actingAgentId, conversationId }) {
|
|
306
|
-
return apiFetch('/api/agent/goal/changed', {
|
|
307
|
-
method: 'POST',
|
|
308
|
-
body: JSON.stringify({
|
|
309
|
-
acting_as_agent_id: actingAgentId,
|
|
310
|
-
conversation_id: conversationId,
|
|
311
|
-
}),
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export async function requestGoalApproval({
|
|
316
|
-
actingAgentId, conversationId, title, detail, ttlSeconds,
|
|
317
|
-
}) {
|
|
318
|
-
return apiFetch('/api/agent/approval/request', {
|
|
319
|
-
method: 'POST',
|
|
320
|
-
body: JSON.stringify({
|
|
321
|
-
acting_as_agent_id: actingAgentId,
|
|
322
|
-
conversation_id: conversationId,
|
|
323
|
-
title,
|
|
324
|
-
detail: detail ?? null,
|
|
325
|
-
ttl_seconds: ttlSeconds ?? null,
|
|
326
|
-
}),
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
export async function listGoalApprovals({ actingAgentId, conversationId }) {
|
|
331
|
-
const params = new URLSearchParams();
|
|
332
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
333
|
-
params.set('conversation_id', conversationId);
|
|
334
|
-
const { data } = await apiFetch(`/api/agent/approval/list?${params}`);
|
|
335
|
-
return data || [];
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export async function resolveGoalApproval({
|
|
339
|
-
actingAgentId, requestId, decision, originalText, confidence, sourceMessageId,
|
|
340
|
-
}) {
|
|
341
|
-
return apiFetch('/api/agent/approval/resolve', {
|
|
342
|
-
method: 'POST',
|
|
343
|
-
body: JSON.stringify({
|
|
344
|
-
acting_as_agent_id: actingAgentId,
|
|
345
|
-
request_id: requestId,
|
|
346
|
-
decision,
|
|
347
|
-
original_text: originalText ?? null,
|
|
348
|
-
confidence: confidence ?? null,
|
|
349
|
-
source_message_id: sourceMessageId ?? null,
|
|
350
|
-
}),
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
285
|
export async function listAgentTasks({ actingAgentId, conversationId }) {
|
|
355
286
|
const params = new URLSearchParams();
|
|
356
287
|
params.set('acting_as_agent_id', actingAgentId);
|
|
@@ -553,294 +484,63 @@ export async function removeAgentGroupMember({
|
|
|
553
484
|
);
|
|
554
485
|
}
|
|
555
486
|
|
|
556
|
-
// ── Workstreams (managed groups) ──
|
|
557
|
-
|
|
558
|
-
export async function createWorkstream({
|
|
559
|
-
actingAgentId, name, description, charter, memberAgentIds,
|
|
560
|
-
}) {
|
|
561
|
-
return apiFetch('/api/agent/workstreams', {
|
|
562
|
-
method: 'POST',
|
|
563
|
-
body: JSON.stringify({
|
|
564
|
-
acting_as_agent_id: actingAgentId,
|
|
565
|
-
name,
|
|
566
|
-
description: description ?? null,
|
|
567
|
-
charter: charter ?? null,
|
|
568
|
-
member_agent_ids: memberAgentIds || [],
|
|
569
|
-
}),
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
export async function deleteWorkstream({ actingAgentId, conversationId }) {
|
|
574
|
-
return apiFetch(
|
|
575
|
-
`/api/agent/workstreams/${encodeURIComponent(conversationId)}`,
|
|
576
|
-
{
|
|
577
|
-
method: 'DELETE',
|
|
578
|
-
body: JSON.stringify({ acting_as_agent_id: actingAgentId }),
|
|
579
|
-
},
|
|
580
|
-
);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
export async function listWorkstreams({ actingAgentId }) {
|
|
584
|
-
const params = new URLSearchParams();
|
|
585
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
586
|
-
const { data } = await apiFetch(`/api/agent/workstreams?${params}`);
|
|
587
|
-
return data || [];
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// ── Agents ──
|
|
591
|
-
|
|
592
|
-
export async function listAgentSlots({ actingAgentId }) {
|
|
593
|
-
const params = new URLSearchParams();
|
|
594
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
595
|
-
const { data } = await apiFetch(`/api/agent/agents?${params}`);
|
|
596
|
-
return data || [];
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
export async function createAgentSlot({
|
|
600
|
-
actingAgentId, name, runtime, description, displayName, model,
|
|
601
|
-
}) {
|
|
602
|
-
return apiFetch('/api/agent/agents', {
|
|
603
|
-
method: 'POST',
|
|
604
|
-
body: JSON.stringify({
|
|
605
|
-
acting_as_agent_id: actingAgentId,
|
|
606
|
-
name,
|
|
607
|
-
runtime,
|
|
608
|
-
description: description ?? null,
|
|
609
|
-
display_name: displayName ?? null,
|
|
610
|
-
model: model ?? null,
|
|
611
|
-
}),
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
export async function archiveAgentSlot({ actingAgentId, agentId }) {
|
|
616
|
-
return apiFetch(
|
|
617
|
-
`/api/agent/agents/${encodeURIComponent(agentId)}`,
|
|
618
|
-
{
|
|
619
|
-
method: 'DELETE',
|
|
620
|
-
body: JSON.stringify({ acting_as_agent_id: actingAgentId }),
|
|
621
|
-
},
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// ── Services ──
|
|
626
|
-
|
|
627
|
-
export async function createService({
|
|
628
|
-
actingAgentId, name, description, contractSchema, endpointConfig,
|
|
629
|
-
}) {
|
|
630
|
-
return apiFetch('/api/agent/services', {
|
|
631
|
-
method: 'POST',
|
|
632
|
-
body: JSON.stringify({
|
|
633
|
-
acting_as_agent_id: actingAgentId,
|
|
634
|
-
name,
|
|
635
|
-
description: description ?? null,
|
|
636
|
-
contract_schema: contractSchema ?? null,
|
|
637
|
-
endpoint_config: endpointConfig,
|
|
638
|
-
}),
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
export async function updateService({ actingAgentId, serviceId, ...patch }) {
|
|
643
|
-
return apiFetch(
|
|
644
|
-
`/api/agent/services/${encodeURIComponent(serviceId)}`,
|
|
645
|
-
{
|
|
646
|
-
method: 'PATCH',
|
|
647
|
-
body: JSON.stringify({ acting_as_agent_id: actingAgentId, ...patch }),
|
|
648
|
-
},
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
export async function deleteService({ actingAgentId, serviceId }) {
|
|
653
|
-
return apiFetch(
|
|
654
|
-
`/api/agent/services/${encodeURIComponent(serviceId)}`,
|
|
655
|
-
{
|
|
656
|
-
method: 'DELETE',
|
|
657
|
-
body: JSON.stringify({ acting_as_agent_id: actingAgentId }),
|
|
658
|
-
},
|
|
659
|
-
);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
export async function listServices({ actingAgentId }) {
|
|
663
|
-
const params = new URLSearchParams();
|
|
664
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
665
|
-
const { data } = await apiFetch(`/api/agent/services?${params}`);
|
|
666
|
-
return data || [];
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
export async function getServiceInfo({ actingAgentId, name }) {
|
|
670
|
-
const params = new URLSearchParams();
|
|
671
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
672
|
-
return apiFetch(
|
|
673
|
-
`/api/agent/services/${encodeURIComponent(name)}/info?${params}`,
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
export async function callService({ actingAgentId, name, input }) {
|
|
678
|
-
return apiFetch(
|
|
679
|
-
`/api/agent/services/${encodeURIComponent(name)}/call`,
|
|
680
|
-
{
|
|
681
|
-
method: 'POST',
|
|
682
|
-
body: JSON.stringify({ acting_as_agent_id: actingAgentId, input }),
|
|
683
|
-
},
|
|
684
|
-
);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// ── Briefings ──
|
|
688
|
-
|
|
689
|
-
export async function getBriefing({actingAgentId, briefingId}) {
|
|
690
|
-
const params = new URLSearchParams();
|
|
691
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
692
|
-
return apiFetch(`/api/agent/briefings/${encodeURIComponent(briefingId)}?${params}`);
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
export async function publishBriefing({actingAgentId, bodyText, attachmentAssetId, currentConversationId, responseMode}) {
|
|
696
|
-
const body = { acting_as_agent_id: actingAgentId };
|
|
697
|
-
if (bodyText != null) body.body_text = bodyText;
|
|
698
|
-
if (attachmentAssetId != null) body.attachment_asset_id = attachmentAssetId;
|
|
699
|
-
if (currentConversationId != null) body.current_conversation_id = currentConversationId;
|
|
700
|
-
if (responseMode != null) body.response_mode = responseMode;
|
|
701
|
-
return apiFetch('/api/agent/briefings', {
|
|
702
|
-
method: 'POST',
|
|
703
|
-
body: JSON.stringify(body),
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
// ── Credentials (slot creation + daemon sync) ──
|
|
708
|
-
|
|
709
|
-
export async function fetchCredentials() {
|
|
710
|
-
return apiFetch('/api/agent/credentials', { method: 'GET' });
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
export async function requestCredential({
|
|
714
|
-
actingAgentId, name, description, workstreamId,
|
|
715
|
-
}) {
|
|
716
|
-
return apiFetch('/api/agent/credentials', {
|
|
717
|
-
method: 'POST',
|
|
718
|
-
body: JSON.stringify({
|
|
719
|
-
acting_as_agent_id: actingAgentId,
|
|
720
|
-
name,
|
|
721
|
-
description: description ?? null,
|
|
722
|
-
workstream_id: workstreamId ?? null,
|
|
723
|
-
}),
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
// ── Workstream dashboard ──
|
|
728
|
-
|
|
729
|
-
export async function setWorkstreamDashboard({
|
|
730
|
-
actingAgentId, conversationId, dataJson, htmlTemplate,
|
|
731
|
-
}) {
|
|
732
|
-
const body = { acting_as_agent_id: actingAgentId };
|
|
733
|
-
// Distinguish "omit" from "set to null" — only include keys the caller
|
|
734
|
-
// explicitly passed (including null clears the field).
|
|
735
|
-
if (dataJson !== undefined) body.data_json = dataJson;
|
|
736
|
-
if (htmlTemplate !== undefined) body.html_template = htmlTemplate;
|
|
737
|
-
return apiFetch(
|
|
738
|
-
`/api/agent/workstreams/${encodeURIComponent(conversationId)}/dashboard`,
|
|
739
|
-
{ method: 'POST', body: JSON.stringify(body) },
|
|
740
|
-
);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
export async function getWorkstreamDashboard({ actingAgentId, conversationId }) {
|
|
744
|
-
const params = new URLSearchParams();
|
|
745
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
746
|
-
return apiFetch(
|
|
747
|
-
`/api/agent/workstreams/${encodeURIComponent(conversationId)}/dashboard?${params}`,
|
|
748
|
-
);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// ── Workstream charter ──
|
|
752
|
-
|
|
753
|
-
export async function getWorkstreamCharter({ actingAgentId, conversationId }) {
|
|
754
|
-
const params = new URLSearchParams();
|
|
755
|
-
params.set('acting_as_agent_id', actingAgentId);
|
|
756
|
-
return apiFetch(
|
|
757
|
-
`/api/agent/workstreams/${encodeURIComponent(conversationId)}/charter?${params}`,
|
|
758
|
-
);
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
export async function setWorkstreamCharter({ actingAgentId, conversationId, charter }) {
|
|
762
|
-
return apiFetch(
|
|
763
|
-
`/api/agent/workstreams/${encodeURIComponent(conversationId)}/charter`,
|
|
764
|
-
{
|
|
765
|
-
method: 'POST',
|
|
766
|
-
body: JSON.stringify({
|
|
767
|
-
acting_as_agent_id: actingAgentId,
|
|
768
|
-
charter: charter ?? null,
|
|
769
|
-
}),
|
|
770
|
-
},
|
|
771
|
-
);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
487
|
// ── Channel event pipe ──
|
|
775
488
|
|
|
776
489
|
export async function postEvent({ agent, agent_id, runtime_host_id, session_id, cwd, runtime_version, event, required = false }) {
|
|
777
490
|
const agentId = agent_id || null;
|
|
778
491
|
const queueKey = agentId || `${agent}:${session_id || ''}`;
|
|
492
|
+
const previous = agentEventQueues.get(queueKey) || Promise.resolve(null);
|
|
779
493
|
const eventName = event?.worker_event_name || event?.hook_event_name || event?.event_name || 'unknown';
|
|
780
494
|
const turnId = event?.turn_id || event?.reply_to_message_id || null;
|
|
781
495
|
const seq = event?.event_seq ?? null;
|
|
782
496
|
const deltaChars = typeof event?.delta === 'string' ? event.delta.length : null;
|
|
783
497
|
|
|
784
|
-
if (eventName === 'worker.message.delta') {
|
|
785
|
-
debugLog('events', 'delta.drop', {
|
|
786
|
-
agent,
|
|
787
|
-
agentId,
|
|
788
|
-
sessionId: shortId(session_id),
|
|
789
|
-
turnId: shortId(turnId),
|
|
790
|
-
deltaChars,
|
|
791
|
-
});
|
|
792
|
-
return null;
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
const postOnce = async () => {
|
|
796
|
-
const startedAt = Date.now();
|
|
797
|
-
try {
|
|
798
|
-
const result = await apiFetch('/api/events', {
|
|
799
|
-
method: 'POST',
|
|
800
|
-
body: JSON.stringify({ agent, agent_id: agentId, runtime_host_id, session_id, cwd, runtime_version, event }),
|
|
801
|
-
timeout: 5000,
|
|
802
|
-
});
|
|
803
|
-
if (required && result?.matched === false) {
|
|
804
|
-
throw new Error(`event was not matched (${eventName})`);
|
|
805
|
-
}
|
|
806
|
-
debugLog('events', 'post.ok', {
|
|
807
|
-
agent,
|
|
808
|
-
agentId,
|
|
809
|
-
sessionId: shortId(session_id),
|
|
810
|
-
runtimeVersion: runtime_version ?? null,
|
|
811
|
-
turnId: shortId(turnId),
|
|
812
|
-
eventName,
|
|
813
|
-
seq,
|
|
814
|
-
durationMs: Date.now() - startedAt,
|
|
815
|
-
});
|
|
816
|
-
return result;
|
|
817
|
-
} catch (err) {
|
|
818
|
-
debugError('events', 'post.failed', {
|
|
819
|
-
agent,
|
|
820
|
-
agentId,
|
|
821
|
-
sessionId: shortId(session_id),
|
|
822
|
-
runtimeVersion: runtime_version ?? null,
|
|
823
|
-
turnId: shortId(turnId),
|
|
824
|
-
eventName,
|
|
825
|
-
seq,
|
|
826
|
-
durationMs: Date.now() - startedAt,
|
|
827
|
-
error: err?.message || 'unknown error',
|
|
828
|
-
});
|
|
829
|
-
if (required) {
|
|
830
|
-
throw err;
|
|
831
|
-
}
|
|
832
|
-
return null;
|
|
833
|
-
}
|
|
834
|
-
};
|
|
835
|
-
|
|
836
|
-
if (eventName === 'worker.turn.complete' || eventName === 'worker.turn.error') {
|
|
837
|
-
return postOnce();
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
const previous = agentEventQueues.get(queueKey) || Promise.resolve(null);
|
|
841
498
|
const queued = previous
|
|
842
499
|
.catch(() => null)
|
|
843
|
-
.then(
|
|
500
|
+
.then(async () => {
|
|
501
|
+
const startedAt = Date.now();
|
|
502
|
+
try {
|
|
503
|
+
const result = await apiFetch('/api/events', {
|
|
504
|
+
method: 'POST',
|
|
505
|
+
body: JSON.stringify({ agent, agent_id: agentId, runtime_host_id, session_id, cwd, runtime_version, event }),
|
|
506
|
+
timeout: 5000,
|
|
507
|
+
});
|
|
508
|
+
if (required && result?.matched === false) {
|
|
509
|
+
throw new Error(`event was not matched (${eventName})`);
|
|
510
|
+
}
|
|
511
|
+
debugLog('events', 'post.ok', {
|
|
512
|
+
agent,
|
|
513
|
+
agentId,
|
|
514
|
+
sessionId: shortId(session_id),
|
|
515
|
+
runtimeVersion: runtime_version ?? null,
|
|
516
|
+
turnId: shortId(turnId),
|
|
517
|
+
eventName,
|
|
518
|
+
seq,
|
|
519
|
+
deltaChars,
|
|
520
|
+
durationMs: Date.now() - startedAt,
|
|
521
|
+
});
|
|
522
|
+
return result;
|
|
523
|
+
} catch (err) {
|
|
524
|
+
debugError('events', 'post.failed', {
|
|
525
|
+
agent,
|
|
526
|
+
agentId,
|
|
527
|
+
sessionId: shortId(session_id),
|
|
528
|
+
runtimeVersion: runtime_version ?? null,
|
|
529
|
+
turnId: shortId(turnId),
|
|
530
|
+
eventName,
|
|
531
|
+
seq,
|
|
532
|
+
deltaChars,
|
|
533
|
+
durationMs: Date.now() - startedAt,
|
|
534
|
+
error: err?.message || 'unknown error',
|
|
535
|
+
});
|
|
536
|
+
if (required) {
|
|
537
|
+
throw err;
|
|
538
|
+
}
|
|
539
|
+
// Best-effort by default. Callers that need a hard failure set
|
|
540
|
+
// `required: true` (used for the final reply path).
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
});
|
|
844
544
|
|
|
845
545
|
agentEventQueues.set(queueKey, queued);
|
|
846
546
|
queued.finally(() => {
|
|
@@ -852,34 +552,6 @@ export async function postEvent({ agent, agent_id, runtime_host_id, session_id,
|
|
|
852
552
|
return queued;
|
|
853
553
|
}
|
|
854
554
|
|
|
855
|
-
// ── Pair (no auth needed) ──
|
|
856
|
-
|
|
857
|
-
export async function pair(payload) {
|
|
858
|
-
const url = `${getApiUrl()}/dispatch`;
|
|
859
|
-
const res = await fetch(url, {
|
|
860
|
-
method: 'POST',
|
|
861
|
-
headers: { 'Content-Type': 'application/json' },
|
|
862
|
-
body: JSON.stringify({ action: 'pair', ...payload }),
|
|
863
|
-
signal: AbortSignal.timeout(15000),
|
|
864
|
-
});
|
|
865
|
-
const body = await res.json().catch(() => ({}));
|
|
866
|
-
return {
|
|
867
|
-
statusCode: res.status,
|
|
868
|
-
...body,
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
export async function pairPreview(payload) {
|
|
873
|
-
const url = `${getApiUrl()}/dispatch`;
|
|
874
|
-
const res = await fetch(url, {
|
|
875
|
-
method: 'POST',
|
|
876
|
-
headers: { 'Content-Type': 'application/json' },
|
|
877
|
-
body: JSON.stringify({ action: 'pair-preview', ...payload }),
|
|
878
|
-
signal: AbortSignal.timeout(15000),
|
|
879
|
-
});
|
|
880
|
-
return res.json();
|
|
881
|
-
}
|
|
882
|
-
|
|
883
555
|
async function pairingRequest(payload, timeout = 15000) {
|
|
884
556
|
const url = `${getApiUrl()}/api/agent-pairings`;
|
|
885
557
|
const res = await fetch(url, {
|
|
@@ -6,56 +6,14 @@
|
|
|
6
6
|
* using the connector-specific env name.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { AF_CONFIG_PATH,
|
|
10
|
-
|
|
11
|
-
export const TICLAWK_CREDENTIAL_NAMES = 'TICLAWK_CREDENTIAL_NAMES';
|
|
12
|
-
|
|
13
|
-
function isRuntimeCredentialName(value) {
|
|
14
|
-
return /^[A-Z][A-Z0-9_]*$/.test(String(value || '').trim());
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function parseCredentialNames(value) {
|
|
18
|
-
return String(value || '')
|
|
19
|
-
.split(',')
|
|
20
|
-
.map((name) => name.trim())
|
|
21
|
-
.filter(isRuntimeCredentialName);
|
|
22
|
-
}
|
|
9
|
+
import { AF_CONFIG_PATH, persistConfig, TICLAWK_CONNECTOR_API_KEY } from '../../core/config.mjs';
|
|
23
10
|
|
|
24
11
|
export function persistApiCredential(apiKey) {
|
|
25
12
|
if (!apiKey || !apiKey.startsWith('tk_')) return;
|
|
26
13
|
|
|
27
14
|
persistConfig({
|
|
28
15
|
[TICLAWK_CONNECTOR_API_KEY]: apiKey,
|
|
29
|
-
TICLAWK_SETUP_CODE: '',
|
|
30
16
|
});
|
|
31
17
|
process.env[TICLAWK_CONNECTOR_API_KEY] = apiKey;
|
|
32
|
-
delete process.env.TICLAWK_SETUP_CODE;
|
|
33
18
|
console.log(`[connect] saved ${TICLAWK_CONNECTOR_API_KEY} to ${AF_CONFIG_PATH}`);
|
|
34
19
|
}
|
|
35
|
-
|
|
36
|
-
export function persistRuntimeCredentials(credentials = []) {
|
|
37
|
-
const current = loadPersistentConfig();
|
|
38
|
-
const previousNames = new Set(parseCredentialNames(current[TICLAWK_CREDENTIAL_NAMES]));
|
|
39
|
-
const nextNames = [];
|
|
40
|
-
const updates = {};
|
|
41
|
-
|
|
42
|
-
for (const credential of Array.isArray(credentials) ? credentials : []) {
|
|
43
|
-
const name = String(credential?.name || '').trim();
|
|
44
|
-
const value = typeof credential?.value === 'string' ? credential.value : '';
|
|
45
|
-
if (!isRuntimeCredentialName(name) || !value) continue;
|
|
46
|
-
updates[name] = value;
|
|
47
|
-
nextNames.push(name);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const nextNameSet = new Set(nextNames);
|
|
51
|
-
for (const name of previousNames) {
|
|
52
|
-
if (!nextNameSet.has(name)) updates[name] = '';
|
|
53
|
-
}
|
|
54
|
-
updates[TICLAWK_CREDENTIAL_NAMES] = nextNames.join(',');
|
|
55
|
-
|
|
56
|
-
persistConfig(updates);
|
|
57
|
-
return {
|
|
58
|
-
saved: nextNames.length,
|
|
59
|
-
removed: [...previousNames].filter((name) => !nextNameSet.has(name)).length,
|
|
60
|
-
};
|
|
61
|
-
}
|