@scotthuang/agent-knock-knock 0.13.18 → 0.14.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/CHANGELOG.md +41 -0
- package/CONTRIBUTING.md +212 -0
- package/README.md +106 -166
- package/connectors/deepseek-harness/LICENSE +21 -0
- package/connectors/deepseek-harness/README.md +406 -0
- package/connectors/pi/LICENSE +21 -0
- package/connectors/pi/README.md +446 -0
- package/dist/src/backend-public-progress.d.ts +38 -0
- package/dist/src/backend-public-progress.js +106 -0
- package/dist/src/backend-public-progress.js.map +1 -0
- package/dist/src/backend-recovery-semantic.d.ts +16 -0
- package/dist/src/backend-recovery-semantic.js +113 -0
- package/dist/src/backend-recovery-semantic.js.map +1 -0
- package/dist/src/backend-task-recovery.d.ts +103 -0
- package/dist/src/backend-task-recovery.js +143 -0
- package/dist/src/backend-task-recovery.js.map +1 -0
- package/dist/src/callback-transport.d.ts +8 -0
- package/dist/src/callback-transport.js +14 -0
- package/dist/src/callback-transport.js.map +1 -1
- package/dist/src/cli-core.js +20 -10
- package/dist/src/cli-core.js.map +1 -1
- package/dist/src/cli-runtime-context.d.ts +5 -0
- package/dist/src/cli-runtime-context.js.map +1 -1
- package/dist/src/codex-app-server-read-client.d.ts +3 -0
- package/dist/src/codex-app-server-read-client.js.map +1 -1
- package/dist/src/codex-native-cli-adapter.d.ts +6 -0
- package/dist/src/codex-native-cli-adapter.js +303 -0
- package/dist/src/codex-native-cli-adapter.js.map +1 -0
- package/dist/src/codex-native-client-interactions.d.ts +6 -0
- package/dist/src/codex-native-client-interactions.js +124 -0
- package/dist/src/codex-native-client-interactions.js.map +1 -0
- package/dist/src/codex-native-client-rpc.d.ts +21 -0
- package/dist/src/codex-native-client-rpc.js +137 -0
- package/dist/src/codex-native-client-rpc.js.map +1 -0
- package/dist/src/codex-native-client.d.ts +42 -0
- package/dist/src/codex-native-client.js +331 -0
- package/dist/src/codex-native-client.js.map +1 -0
- package/dist/src/codex-native-identity.d.ts +6 -0
- package/dist/src/codex-native-identity.js +42 -0
- package/dist/src/codex-native-identity.js.map +1 -0
- package/dist/src/codex-native-monitor.d.ts +4 -0
- package/dist/src/codex-native-monitor.js +92 -0
- package/dist/src/codex-native-monitor.js.map +1 -0
- package/dist/src/codex-native-outbox.d.ts +16 -0
- package/dist/src/codex-native-outbox.js +120 -0
- package/dist/src/codex-native-outbox.js.map +1 -0
- package/dist/src/codex-native-public-projection.d.ts +545 -0
- package/dist/src/codex-native-public-projection.js +182 -0
- package/dist/src/codex-native-public-projection.js.map +1 -0
- package/dist/src/codex-native-record-store.d.ts +27 -0
- package/dist/src/codex-native-record-store.js +111 -0
- package/dist/src/codex-native-record-store.js.map +1 -0
- package/dist/src/codex-native-response-service.d.ts +69 -0
- package/dist/src/codex-native-response-service.js +244 -0
- package/dist/src/codex-native-response-service.js.map +1 -0
- package/dist/src/codex-native-runtime.d.ts +46 -0
- package/dist/src/codex-native-runtime.js +112 -0
- package/dist/src/codex-native-runtime.js.map +1 -0
- package/dist/src/codex-native-semantic.d.ts +17 -0
- package/dist/src/codex-native-semantic.js +175 -0
- package/dist/src/codex-native-semantic.js.map +1 -0
- package/dist/src/codex-native-snapshot.d.ts +19 -0
- package/dist/src/codex-native-snapshot.js +160 -0
- package/dist/src/codex-native-snapshot.js.map +1 -0
- package/dist/src/codex-native-state-store.d.ts +61 -0
- package/dist/src/codex-native-state-store.js +132 -0
- package/dist/src/codex-native-state-store.js.map +1 -0
- package/dist/src/codex-native-task-service.d.ts +71 -0
- package/dist/src/codex-native-task-service.js +503 -0
- package/dist/src/codex-native-task-service.js.map +1 -0
- package/dist/src/codex-native-types.d.ts +92 -0
- package/dist/src/codex-native-types.js +15 -0
- package/dist/src/codex-native-types.js.map +1 -0
- package/dist/src/conversation-list.d.ts +12 -0
- package/dist/src/conversation-list.js +30 -0
- package/dist/src/conversation-list.js.map +1 -0
- package/dist/src/conversation-route-dispatch.d.ts +13 -0
- package/dist/src/conversation-route-dispatch.js +66 -0
- package/dist/src/conversation-route-dispatch.js.map +1 -0
- package/dist/src/conversation-route-legacy.d.ts +18 -0
- package/dist/src/conversation-route-legacy.js +54 -0
- package/dist/src/conversation-route-legacy.js.map +1 -0
- package/dist/src/conversation-route-store.d.ts +51 -0
- package/dist/src/conversation-route-store.js +126 -0
- package/dist/src/conversation-route-store.js.map +1 -0
- package/dist/src/conversation-routing-cli-adapter.d.ts +12 -0
- package/dist/src/conversation-routing-cli-adapter.js +211 -0
- package/dist/src/conversation-routing-cli-adapter.js.map +1 -0
- package/dist/src/conversation-routing-commands.d.ts +11 -0
- package/dist/src/conversation-routing-commands.js +85 -0
- package/dist/src/conversation-routing-commands.js.map +1 -0
- package/dist/src/conversation-routing-home.d.ts +26 -0
- package/dist/src/conversation-routing-home.js +105 -0
- package/dist/src/conversation-routing-home.js.map +1 -0
- package/dist/src/conversation-routing-identity.d.ts +40 -0
- package/dist/src/conversation-routing-identity.js +174 -0
- package/dist/src/conversation-routing-identity.js.map +1 -0
- package/dist/src/conversation-runtime-route-store.d.ts +11 -0
- package/dist/src/conversation-runtime-route-store.js +118 -0
- package/dist/src/conversation-runtime-route-store.js.map +1 -0
- package/dist/src/desktop-async-interactions.d.ts +15 -0
- package/dist/src/desktop-async-interactions.js +88 -0
- package/dist/src/desktop-async-interactions.js.map +1 -0
- package/dist/src/desktop-async-state.d.ts +5 -0
- package/dist/src/desktop-async-state.js +53 -0
- package/dist/src/desktop-async-state.js.map +1 -0
- package/dist/src/desktop-cli-adapter.d.ts +7 -0
- package/dist/src/desktop-cli-adapter.js +343 -0
- package/dist/src/desktop-cli-adapter.js.map +1 -0
- package/dist/src/desktop-cli-controls.d.ts +9 -0
- package/dist/src/desktop-cli-controls.js +45 -0
- package/dist/src/desktop-cli-controls.js.map +1 -0
- package/dist/src/desktop-command-presentation.d.ts +2 -0
- package/dist/src/desktop-command-presentation.js +31 -0
- package/dist/src/desktop-command-presentation.js.map +1 -0
- package/dist/src/desktop-control-semantic.d.ts +8 -0
- package/dist/src/desktop-control-semantic.js +68 -0
- package/dist/src/desktop-control-semantic.js.map +1 -0
- package/dist/src/desktop-identity.d.ts +5 -0
- package/dist/src/desktop-identity.js +40 -0
- package/dist/src/desktop-identity.js.map +1 -0
- package/dist/src/desktop-interaction-projection.d.ts +57 -0
- package/dist/src/desktop-interaction-projection.js +196 -0
- package/dist/src/desktop-interaction-projection.js.map +1 -0
- package/dist/src/desktop-interaction-state.d.ts +3 -0
- package/dist/src/desktop-interaction-state.js +48 -0
- package/dist/src/desktop-interaction-state.js.map +1 -0
- package/dist/src/desktop-ipc-async-answer.d.ts +9 -0
- package/dist/src/desktop-ipc-async-answer.js +71 -0
- package/dist/src/desktop-ipc-async-answer.js.map +1 -0
- package/dist/src/desktop-ipc-client.d.ts +47 -0
- package/dist/src/desktop-ipc-client.js +400 -0
- package/dist/src/desktop-ipc-client.js.map +1 -0
- package/dist/src/desktop-ipc-native-operations.d.ts +11 -0
- package/dist/src/desktop-ipc-native-operations.js +126 -0
- package/dist/src/desktop-ipc-native-operations.js.map +1 -0
- package/dist/src/desktop-ipc-transport.d.ts +13 -0
- package/dist/src/desktop-ipc-transport.js +123 -0
- package/dist/src/desktop-ipc-transport.js.map +1 -0
- package/dist/src/desktop-list.d.ts +25 -0
- package/dist/src/desktop-list.js +55 -0
- package/dist/src/desktop-list.js.map +1 -0
- package/dist/src/desktop-metadata-reader.d.ts +30 -0
- package/dist/src/desktop-metadata-reader.js +182 -0
- package/dist/src/desktop-metadata-reader.js.map +1 -0
- package/dist/src/desktop-monitor.d.ts +4 -0
- package/dist/src/desktop-monitor.js +101 -0
- package/dist/src/desktop-monitor.js.map +1 -0
- package/dist/src/desktop-public-projection.d.ts +6 -0
- package/dist/src/desktop-public-projection.js +134 -0
- package/dist/src/desktop-public-projection.js.map +1 -0
- package/dist/src/desktop-request-interactions.d.ts +14 -0
- package/dist/src/desktop-request-interactions.js +144 -0
- package/dist/src/desktop-request-interactions.js.map +1 -0
- package/dist/src/desktop-response-dispatch.d.ts +14 -0
- package/dist/src/desktop-response-dispatch.js +19 -0
- package/dist/src/desktop-response-dispatch.js.map +1 -0
- package/dist/src/desktop-response-evidence.d.ts +4 -0
- package/dist/src/desktop-response-evidence.js +19 -0
- package/dist/src/desktop-response-evidence.js.map +1 -0
- package/dist/src/desktop-response-service.d.ts +11 -0
- package/dist/src/desktop-response-service.js +188 -0
- package/dist/src/desktop-response-service.js.map +1 -0
- package/dist/src/desktop-response-store.d.ts +35 -0
- package/dist/src/desktop-response-store.js +58 -0
- package/dist/src/desktop-response-store.js.map +1 -0
- package/dist/src/desktop-response-types.d.ts +20 -0
- package/dist/src/desktop-response-types.js +2 -0
- package/dist/src/desktop-response-types.js.map +1 -0
- package/dist/src/desktop-response-value.d.ts +6 -0
- package/dist/src/desktop-response-value.js +31 -0
- package/dist/src/desktop-response-value.js.map +1 -0
- package/dist/src/desktop-runtime.d.ts +153 -0
- package/dist/src/desktop-runtime.js +88 -0
- package/dist/src/desktop-runtime.js.map +1 -0
- package/dist/src/desktop-semantic.d.ts +21 -0
- package/dist/src/desktop-semantic.js +140 -0
- package/dist/src/desktop-semantic.js.map +1 -0
- package/dist/src/desktop-session-catalog.d.ts +68 -0
- package/dist/src/desktop-session-catalog.js +225 -0
- package/dist/src/desktop-session-catalog.js.map +1 -0
- package/dist/src/desktop-session-controls.d.ts +145 -0
- package/dist/src/desktop-session-controls.js +176 -0
- package/dist/src/desktop-session-controls.js.map +1 -0
- package/dist/src/desktop-sidebar-metadata.d.ts +27 -0
- package/dist/src/desktop-sidebar-metadata.js +83 -0
- package/dist/src/desktop-sidebar-metadata.js.map +1 -0
- package/dist/src/desktop-sidebar-projects.d.ts +10 -0
- package/dist/src/desktop-sidebar-projects.js +31 -0
- package/dist/src/desktop-sidebar-projects.js.map +1 -0
- package/dist/src/desktop-sidebar-selection.d.ts +28 -0
- package/dist/src/desktop-sidebar-selection.js +85 -0
- package/dist/src/desktop-sidebar-selection.js.map +1 -0
- package/dist/src/desktop-snapshot-details.d.ts +4 -0
- package/dist/src/desktop-snapshot-details.js +116 -0
- package/dist/src/desktop-snapshot-details.js.map +1 -0
- package/dist/src/desktop-snapshot.d.ts +11 -0
- package/dist/src/desktop-snapshot.js +281 -0
- package/dist/src/desktop-snapshot.js.map +1 -0
- package/dist/src/desktop-state-store.d.ts +72 -0
- package/dist/src/desktop-state-store.js +269 -0
- package/dist/src/desktop-state-store.js.map +1 -0
- package/dist/src/desktop-task-interactions.d.ts +10 -0
- package/dist/src/desktop-task-interactions.js +93 -0
- package/dist/src/desktop-task-interactions.js.map +1 -0
- package/dist/src/desktop-task-recovery.d.ts +38 -0
- package/dist/src/desktop-task-recovery.js +172 -0
- package/dist/src/desktop-task-recovery.js.map +1 -0
- package/dist/src/desktop-task-service.d.ts +54 -0
- package/dist/src/desktop-task-service.js +442 -0
- package/dist/src/desktop-task-service.js.map +1 -0
- package/dist/src/desktop-types.d.ts +283 -0
- package/dist/src/desktop-types.js +13 -0
- package/dist/src/desktop-types.js.map +1 -0
- package/dist/src/host-monitor-reconciliation.js +36 -4
- package/dist/src/host-monitor-reconciliation.js.map +1 -1
- package/dist/src/host-profile-runtime.js +7 -3
- package/dist/src/host-profile-runtime.js.map +1 -1
- package/dist/src/local-codex-cli-adapter.d.ts +7 -0
- package/dist/src/local-codex-cli-adapter.js +13 -0
- package/dist/src/local-codex-cli-adapter.js.map +1 -0
- package/dist/src/monitor-deadline-policy.d.ts +8 -0
- package/dist/src/monitor-deadline-policy.js +16 -0
- package/dist/src/monitor-deadline-policy.js.map +1 -0
- package/dist/src/openclaw-callback-transport.js +2 -1
- package/dist/src/openclaw-callback-transport.js.map +1 -1
- package/dist/src/semantic-conversation-target.d.ts +4 -0
- package/dist/src/semantic-conversation-target.js +20 -0
- package/dist/src/semantic-conversation-target.js.map +1 -0
- package/dist/src/semantic-permission-control.js +47 -9
- package/dist/src/semantic-permission-control.js.map +1 -1
- package/dist/src/semantic-private-authority-offers.d.ts +1 -1
- package/dist/src/semantic-private-authority-offers.js +3 -1
- package/dist/src/semantic-private-authority-offers.js.map +1 -1
- package/dist/src/semantic-tool-command-helpers.d.ts +6 -0
- package/dist/src/semantic-tool-command-helpers.js +199 -78
- package/dist/src/semantic-tool-command-helpers.js.map +1 -1
- package/dist/src/semantic-tool-descriptions.d.ts +2 -1
- package/dist/src/semantic-tool-descriptions.js +84 -35
- package/dist/src/semantic-tool-descriptions.js.map +1 -1
- package/dist/src/semantic-tool-list-projection.js +66 -2
- package/dist/src/semantic-tool-list-projection.js.map +1 -1
- package/dist/src/semantic-tool-presentation.js +76 -7
- package/dist/src/semantic-tool-presentation.js.map +1 -1
- package/dist/src/semantic-tool-runtime.js +129 -29
- package/dist/src/semantic-tool-runtime.js.map +1 -1
- package/dist/src/semantic-tool-schemas.d.ts +410 -27
- package/dist/src/semantic-tool-schemas.js +176 -88
- package/dist/src/semantic-tool-schemas.js.map +1 -1
- package/dist/src/terminal-action-contracts.js +10 -6
- package/dist/src/terminal-action-contracts.js.map +1 -1
- package/dist/src/terminal-command-cli-adapter.js +4 -4
- package/dist/src/terminal-command-cli-adapter.js.map +1 -1
- package/dist/src/terminal-command-dispatch-preparation.js +2 -1
- package/dist/src/terminal-command-dispatch-preparation.js.map +1 -1
- package/dist/src/terminal-list-cli-adapter.d.ts +1 -0
- package/dist/src/terminal-list-cli-adapter.js +6 -3
- package/dist/src/terminal-list-cli-adapter.js.map +1 -1
- package/dist/src/terminal-monitor-decision-policy.d.ts +1 -1
- package/dist/src/terminal-monitor-launch-plan.js +3 -2
- package/dist/src/terminal-monitor-launch-plan.js.map +1 -1
- package/dist/src/terminal-monitor-supervision-cli-adapter.js +2 -2
- package/dist/src/terminal-monitor-supervision-cli-adapter.js.map +1 -1
- package/dist/src/terminal-submission-retry-reconciliation.js +2 -2
- package/dist/src/terminal-submission-retry-reconciliation.js.map +1 -1
- package/dist/src/terminal-user-send-intent.d.ts +2 -0
- package/dist/src/terminal-user-send-intent.js +11 -3
- package/dist/src/terminal-user-send-intent.js.map +1 -1
- package/dist/src/terminal-watch-cli-adapter.js +4 -4
- package/dist/src/terminal-watch-cli-adapter.js.map +1 -1
- package/docs/architecture/current-architecture.md +313 -0
- package/docs/architecture/interactive-terminal-response.md +276 -0
- package/docs/architecture/issue-126-final-report.md +248 -0
- package/docs/architecture/orchestration-refactor-history.md +2987 -0
- package/docs/architecture/orchestration-refactor.md +21 -0
- package/docs/backend-task-recovery.md +98 -0
- package/docs/bidirectional-agent-protocol.md +260 -0
- package/docs/codex-cli-native-compatibility.md +246 -0
- package/docs/codex-desktop-compatibility.md +414 -0
- package/docs/openclaw-operations.md +281 -0
- package/docs/openclaw-session-turn-delivery-requirement.md +45 -0
- package/docs/operator-guide.md +572 -0
- package/docs/storage-and-logging.md +91 -0
- package/docs/test-performance-issue-108.md +80 -0
- package/docs/test-performance-issue-120.md +226 -0
- package/docs/testing.md +628 -0
- package/openclaw.plugin.json +8 -4
- package/package.json +6 -13
- package/templates/openclaw-skills/agent-knock-knock/SKILL.md +66 -15
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { backendTaskRecoveryProjection } from "./backend-task-recovery.js";
|
|
2
|
+
import { desktopObservationStopped } from "./desktop-task-recovery.js";
|
|
3
|
+
import { desktopInteractionIsApproval, desktopInteractionProjection } from "./desktop-interaction-projection.js";
|
|
4
|
+
export function desktopSessionProjection(entry, snapshot, writesVerified = false, observationError) {
|
|
5
|
+
const live = snapshot !== undefined;
|
|
6
|
+
const activeTurn = activeDesktopTurn(snapshot);
|
|
7
|
+
const watch = Boolean(activeTurn);
|
|
8
|
+
const send = Boolean(snapshot?.canSend && writesVerified);
|
|
9
|
+
const interactions = writesVerified && activeTurn ? (snapshot?.pendingInteractions ?? snapshot?.asyncQuestions ?? [])
|
|
10
|
+
.filter(item => item.turnId === activeTurn) : [];
|
|
11
|
+
const settings = Boolean(writesVerified && snapshot?.canSend && snapshot.runtimeStatus === "idle");
|
|
12
|
+
const capabilities = { status: true, send, watch, interaction_notify: watch, ...interactionCapabilities(interactions),
|
|
13
|
+
set_permissions: settings, set_model: settings, cancel: writesVerified && watch };
|
|
14
|
+
return {
|
|
15
|
+
id: entry.conversationId, conversation_id: entry.conversationId, source: "codex_desktop", agent: "codex",
|
|
16
|
+
title: snapshot?.title ?? entry.title, cwd: snapshot?.cwd ?? entry.cwd,
|
|
17
|
+
native_thread_id: entry.threadId, host_id: entry.hostId, updated_at: new Date(entry.updatedAtMs).toISOString(),
|
|
18
|
+
catalog_membership: entry.catalogMembership, creator_originator: entry.originator,
|
|
19
|
+
...(entry.sidebar ? { sidebar_section: entry.sidebar.section, sidebar_project_id: entry.sidebar.projectId,
|
|
20
|
+
sidebar_project_name: entry.sidebar.projectName } : {}),
|
|
21
|
+
connection_state: live ? "live_owner_verified" : "unconfirmed",
|
|
22
|
+
activity_state: snapshot?.runtimeStatus ?? "unknown",
|
|
23
|
+
...sessionObservation(snapshot, writesVerified),
|
|
24
|
+
...sessionSendAvailability(snapshot, writesVerified, observationError),
|
|
25
|
+
...(observationError ? { observation_error: observationError } : {}), capabilities,
|
|
26
|
+
pending_async_count: interactions.filter(item => item.kind === "async_question").length,
|
|
27
|
+
pending_interaction_count: interactions.length,
|
|
28
|
+
interaction_state: interactions.map(item => desktopInteractionProjection(item, entry.conversationId)),
|
|
29
|
+
available_actions: sessionActions(entry.conversationId, { live, send, watch, cancel: writesVerified && watch }, activeTurn)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function sessionSendAvailability(snapshot, writesVerified, observationError) {
|
|
33
|
+
if (!snapshot)
|
|
34
|
+
return { can_send_reason: observationError ?? "live_owner_not_confirmed",
|
|
35
|
+
...(observationError === "no_live_owner" ? {
|
|
36
|
+
manual_action: "Open this conversation in Desktop, then refresh AKK List. It is listed but cannot currently receive tasks."
|
|
37
|
+
} : {}) };
|
|
38
|
+
return { can_send_reason: !writesVerified ? "desktop_write_contract_unverified"
|
|
39
|
+
: snapshot.canSend ? "ready" : snapshot.idleBlockedReason ?? "desktop_not_sendable" };
|
|
40
|
+
}
|
|
41
|
+
/** Do not export prompts, internal owner IDs, callback configuration or raw native state. */
|
|
42
|
+
export function desktopTaskProjection(task, writesVerified = true) {
|
|
43
|
+
const terminal = desktopObservationStopped(task) || ["completed", "failed", "interrupted", "timed_out", "cancelled"].includes(task.status);
|
|
44
|
+
const interactions = writesVerified && !terminal ? actionableTaskInteractions(task) : [];
|
|
45
|
+
const notifications = notificationProjection(task);
|
|
46
|
+
const canCancel = writesVerified && !terminal && Boolean(task.native_turn_id);
|
|
47
|
+
const { recovery_actions, ...recovery } = backendTaskRecoveryProjection(task);
|
|
48
|
+
return {
|
|
49
|
+
watch_id: task.watch_id, conversation_id: task.desktop_id, source: "codex_desktop",
|
|
50
|
+
status: task.closed_at ? "closed" : task.status, observation_status: task.status,
|
|
51
|
+
...recovery,
|
|
52
|
+
observation_mode: task.native_turn_id ? "exact_task" : "pending_acceptance",
|
|
53
|
+
anchor_state: task.native_turn_id ? "verified" : "pending", native_thread_id: task.target.threadId,
|
|
54
|
+
native_turn_id: task.native_turn_id ?? null, created_at: task.created_at, updated_at: task.updated_at,
|
|
55
|
+
observed_at: task.observed_at, observation_error: task.observation_error,
|
|
56
|
+
pending_manual_count: task.pending_manual_count, final_text: task.final_text,
|
|
57
|
+
...taskInteractionCounts(task, interactions),
|
|
58
|
+
interaction_state: interactions.map(item => desktopInteractionProjection(item, task.desktop_id, task.watch_id)),
|
|
59
|
+
callback_expected: callbackExpected(task, terminal),
|
|
60
|
+
callback_configured: Boolean(task.callback_route), callback_notifications: notifications,
|
|
61
|
+
...desktopSendReceiptProjection(task.send_intent),
|
|
62
|
+
capabilities: { callback: Boolean(task.callback_route), interaction_notify: Boolean(task.callback_route),
|
|
63
|
+
...interactionCapabilities(interactions), cancel: canCancel, ...desktopRecoveryCapabilities(task) },
|
|
64
|
+
available_actions: { ...recovery_actions, status: { tool: "agent_knock_knock_status", input: { watch_id: task.watch_id } },
|
|
65
|
+
...(canCancel ? { cancel: { tool: "agent_knock_knock_cancel", input: { watch_id: task.watch_id } } } : {}) },
|
|
66
|
+
...(task.pending_manual_count ? { manual_action: terminal
|
|
67
|
+
? "Handle any remaining question or approval in Desktop; this Watch has stopped."
|
|
68
|
+
: "Answer the question or approval in Desktop; AKK continues watching this task." } : {})
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Keep task delivery evidence distinct from current interaction availability. */
|
|
72
|
+
function desktopSendReceiptProjection(intent) {
|
|
73
|
+
if (!intent)
|
|
74
|
+
return {};
|
|
75
|
+
const accepted = intent.state === "accepted";
|
|
76
|
+
return { message_id: intent.message_id, delivery_receipt: accepted ? "native_task_verified"
|
|
77
|
+
: intent.state === "not_sent" ? "not_sent" : "acceptance_unproven",
|
|
78
|
+
delivered: accepted, agent_acceptance: accepted ? "proven" : "unproven",
|
|
79
|
+
send_state: intent.state, send_error: intent.error_code, resend_allowed: false };
|
|
80
|
+
}
|
|
81
|
+
function actionableTaskInteractions(task) {
|
|
82
|
+
const items = task.pending_interactions ?? task.pending_async_interactions ?? [];
|
|
83
|
+
if (!task.observation_error)
|
|
84
|
+
return items;
|
|
85
|
+
// The owner request list is independently fresh even when async turn history is partial.
|
|
86
|
+
return task.observation_error === "desktop_async_questions_incomplete" ? items.filter(item => item.kind !== "async_question") : [];
|
|
87
|
+
}
|
|
88
|
+
function activeDesktopTurn(snapshot) {
|
|
89
|
+
if (!snapshot || snapshot.runtimeStatus !== "active" || !snapshot.tailKnown)
|
|
90
|
+
return undefined;
|
|
91
|
+
const active = snapshot.turns.filter(turn => turn.status === "inProgress");
|
|
92
|
+
return active.length === 1 && snapshot.latestTurnId === active[0].turnId ? active[0].turnId : undefined;
|
|
93
|
+
}
|
|
94
|
+
function interactionCapabilities(interactions) {
|
|
95
|
+
return { interaction_respond: interactions.some(item => !desktopInteractionIsApproval(item)),
|
|
96
|
+
approve: interactions.some(desktopInteractionIsApproval) };
|
|
97
|
+
}
|
|
98
|
+
function sessionObservation(snapshot, writesVerified) {
|
|
99
|
+
if (!snapshot)
|
|
100
|
+
return {};
|
|
101
|
+
const actionable = writesVerified ? (snapshot.pendingInteractions ?? []).filter(item => item.kind !== "async_question").length : 0;
|
|
102
|
+
return { native_turn_id: snapshot.latestTurnId, pending_manual_count: Math.max(0, snapshot.pendingRequestCount - actionable),
|
|
103
|
+
observed_revision: snapshot.revision };
|
|
104
|
+
}
|
|
105
|
+
function sessionActions(id, capabilities, activeTurn) {
|
|
106
|
+
const input = { conversation_id: id };
|
|
107
|
+
return { status: { tool: "agent_knock_knock_status", input },
|
|
108
|
+
...(capabilities.send ? { send: { tool: "agent_knock_knock_send", input } } : {}),
|
|
109
|
+
...(capabilities.watch ? { watch: { tool: "agent_knock_knock_watch", input } } : {}),
|
|
110
|
+
...(capabilities.cancel ? { cancel: { tool: "agent_knock_knock_cancel", input: { ...input, expected_native_turn_id: activeTurn } } } : {}),
|
|
111
|
+
...(capabilities.live ? { native_inspect: { tool: "agent_knock_knock_native_inspect", input: { ...input, inspection: "status" } },
|
|
112
|
+
permission_options: { tool: "agent_knock_knock_permission_options", input },
|
|
113
|
+
model_options: { tool: "agent_knock_knock_model_options", input } } : {}) };
|
|
114
|
+
}
|
|
115
|
+
function notificationProjection(task) {
|
|
116
|
+
return task.notifications.map(note => ({ id: note.id, notification_id: note.id, status: note.status, attempts: note.attempts,
|
|
117
|
+
...(note.outcome && "error_code" in note.outcome ? { error_code: note.outcome.error_code } : {}) }));
|
|
118
|
+
}
|
|
119
|
+
function callbackExpected(task, terminal) {
|
|
120
|
+
return Boolean(task.callback_route && !desktopObservationStopped(task) &&
|
|
121
|
+
(!terminal || task.notifications.some(note => ["ready", "retry_wait", "leased"].includes(note.status))));
|
|
122
|
+
}
|
|
123
|
+
function taskInteractionCounts(task, items) {
|
|
124
|
+
return { pending_async_count: task.observation_error ? null : (task.pending_async_interactions ?? []).length,
|
|
125
|
+
async_interactions_state: task.observation_error ? "unknown" : "current",
|
|
126
|
+
pending_interaction_count: task.observation_error ? null : items.length };
|
|
127
|
+
}
|
|
128
|
+
function desktopRecoveryCapabilities(task) {
|
|
129
|
+
const stopped = desktopObservationStopped(task);
|
|
130
|
+
return { close: task.kind === "send" && !task.closed_at, unwatch: !stopped,
|
|
131
|
+
recover: !task.closed_at, renew: !task.closed_at && !["completed", "failed", "interrupted"].includes(task.status),
|
|
132
|
+
retry_callback: !stopped && task.notifications.some(notification => ["failed", "retry_wait"].includes(notification.status) && notification.outcome?.disposition === "retryable_failure") };
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=desktop-public-projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-public-projection.js","sourceRoot":"","sources":["../../src/desktop-public-projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type DesktopInteraction, type DesktopRequestInteraction, type DesktopRequestResponse, type DesktopSnapshot, type DesktopTurn } from "./desktop-types.js";
|
|
2
|
+
export declare const desktopObject: (value: unknown) => value is Record<string, unknown>;
|
|
3
|
+
export declare function desktopNativeRequestId(value: unknown): string | number;
|
|
4
|
+
export declare function desktopRequestInteractionId(value: Omit<DesktopRequestInteraction, "id">): string;
|
|
5
|
+
export declare function parseDesktopRequestInteraction(raw: unknown, threadId: string, turns: DesktopTurn[]): DesktopRequestInteraction | null;
|
|
6
|
+
export declare function desktopInteractions(snapshot: DesktopSnapshot, turnId?: string): DesktopInteraction[];
|
|
7
|
+
export declare function desktopRequestResponse(interaction: DesktopRequestInteraction, response: DesktopRequestResponse): Record<string, unknown>;
|
|
8
|
+
export declare function findDesktopRequestEffect(snapshot: DesktopSnapshot, input: {
|
|
9
|
+
interaction: DesktopRequestInteraction;
|
|
10
|
+
response: DesktopRequestResponse;
|
|
11
|
+
}): {
|
|
12
|
+
evidence: "exact_blocking_answer_observed" | "exact_approval_item_advanced";
|
|
13
|
+
itemId: string;
|
|
14
|
+
} | null;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { isDeepStrictEqual } from "node:util";
|
|
3
|
+
import { desktopAsyncQuestions } from "./desktop-async-interactions.js";
|
|
4
|
+
import { DesktopIpcError } from "./desktop-types.js";
|
|
5
|
+
export const desktopObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6
|
+
function invalid(message) { throw new DesktopIpcError("invalid_response", message); }
|
|
7
|
+
function text(value) {
|
|
8
|
+
if (typeof value !== "string" || !value || value.length > 16_384)
|
|
9
|
+
invalid("Invalid Desktop request string");
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
export function desktopNativeRequestId(value) {
|
|
13
|
+
if (typeof value === "string" && value.length > 0 && value.length <= 512)
|
|
14
|
+
return value;
|
|
15
|
+
if (typeof value === "number" && Number.isSafeInteger(value))
|
|
16
|
+
return value;
|
|
17
|
+
return invalid("Invalid Desktop native request identity");
|
|
18
|
+
}
|
|
19
|
+
export function desktopRequestInteractionId(value) {
|
|
20
|
+
const fields = [value.kind, value.threadId, value.turnId, value.itemId, value.method, value.requestId, value.questions,
|
|
21
|
+
value.command, value.reason, value.cwd, value.availableDecisions, value.approvalId, value.nativeApprovalKind, value.networkApprovalContext];
|
|
22
|
+
return `desktop-request-interaction:${createHash("sha256").update(JSON.stringify(fields)).digest("hex")}`;
|
|
23
|
+
}
|
|
24
|
+
function parseQuestions(value) {
|
|
25
|
+
if (!Array.isArray(value) || !value.length || value.length > 64)
|
|
26
|
+
invalid("Invalid Desktop blocking questions");
|
|
27
|
+
const ids = new Set();
|
|
28
|
+
return value.map(raw => {
|
|
29
|
+
if (!desktopObject(raw))
|
|
30
|
+
invalid("Invalid Desktop blocking question");
|
|
31
|
+
const id = text(raw.id);
|
|
32
|
+
if (ids.has(id))
|
|
33
|
+
invalid("Duplicate Desktop blocking question");
|
|
34
|
+
ids.add(id);
|
|
35
|
+
if (raw.options != null && (!Array.isArray(raw.options) || raw.options.length > 128))
|
|
36
|
+
invalid("Invalid Desktop blocking options");
|
|
37
|
+
const options = (raw.options ?? []).map(option => {
|
|
38
|
+
if (!desktopObject(option))
|
|
39
|
+
invalid("Invalid Desktop blocking option");
|
|
40
|
+
return text(option.label);
|
|
41
|
+
});
|
|
42
|
+
return { id, title: text(raw.question), options, isOther: raw.isOther === true, isSecret: raw.isSecret === true };
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function approvalDetails(params, result) {
|
|
46
|
+
for (const key of ["command", "reason", "cwd", "approvalId"]) {
|
|
47
|
+
const value = params[key];
|
|
48
|
+
if (value == null)
|
|
49
|
+
continue;
|
|
50
|
+
if (typeof value !== "string" || value.length > 16_384)
|
|
51
|
+
invalid("Invalid Desktop approval detail");
|
|
52
|
+
result[key] = value;
|
|
53
|
+
}
|
|
54
|
+
if (params.availableDecisions != null) {
|
|
55
|
+
if (!Array.isArray(params.availableDecisions))
|
|
56
|
+
invalid("Invalid Desktop approval decisions");
|
|
57
|
+
result.availableDecisions = params.availableDecisions.filter((value) => typeof value === "string");
|
|
58
|
+
}
|
|
59
|
+
if (result.kind !== "command_approval")
|
|
60
|
+
return;
|
|
61
|
+
result.nativeApprovalKind = params.kind == null ? "command" : text(params.kind);
|
|
62
|
+
if (params.networkApprovalContext != null) {
|
|
63
|
+
if (!desktopObject(params.networkApprovalContext))
|
|
64
|
+
invalid("Invalid Desktop network approval");
|
|
65
|
+
result.networkApprovalContext = { host: text(params.networkApprovalContext.host), protocol: text(params.networkApprovalContext.protocol) };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const requestKinds = new Map([
|
|
69
|
+
["item/commandExecution/requestApproval", "command_approval"], ["item/fileChange/requestApproval", "file_approval"],
|
|
70
|
+
["item/tool/requestUserInput", "blocking_question"]
|
|
71
|
+
]);
|
|
72
|
+
export function parseDesktopRequestInteraction(raw, threadId, turns) {
|
|
73
|
+
if (!desktopObject(raw) || typeof raw.method !== "string")
|
|
74
|
+
return null;
|
|
75
|
+
const kind = requestKinds.get(raw.method);
|
|
76
|
+
if (!kind)
|
|
77
|
+
return null;
|
|
78
|
+
if (!desktopObject(raw.params))
|
|
79
|
+
return null;
|
|
80
|
+
const params = raw.params;
|
|
81
|
+
if (params.threadId === undefined || typeof params.turnId !== "string" || typeof params.itemId !== "string")
|
|
82
|
+
return null;
|
|
83
|
+
if (params.threadId !== threadId)
|
|
84
|
+
invalid("Desktop request belongs to a different thread");
|
|
85
|
+
const result = { id: "", kind, method: raw.method, requestId: desktopNativeRequestId(raw.id),
|
|
86
|
+
threadId, turnId: text(params.turnId), itemId: text(params.itemId), questions: kind === "blocking_question" ? parseQuestions(params.questions) : [] };
|
|
87
|
+
approvalDetails(params, result);
|
|
88
|
+
result.id = desktopRequestInteractionId(result);
|
|
89
|
+
const item = turns.find(turn => turn.turnId === result.turnId)?.items.find(item => item.id === result.itemId);
|
|
90
|
+
if (kind === "file_approval" && item?.type === "fileChange" && item.changes)
|
|
91
|
+
result.changes = item.changes;
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
export function desktopInteractions(snapshot, turnId) {
|
|
95
|
+
const requests = (snapshot.pendingInteractions ?? []).filter((item) => item.kind !== "async_question");
|
|
96
|
+
return [...requests, ...desktopAsyncQuestions(snapshot, turnId)].filter(item => turnId === undefined || item.turnId === turnId);
|
|
97
|
+
}
|
|
98
|
+
export function desktopRequestResponse(interaction, response) {
|
|
99
|
+
if (interaction.kind !== "blocking_question" && "decision" in response && ["accept", "decline", "cancel"].includes(response.decision)) {
|
|
100
|
+
return { decision: response.decision };
|
|
101
|
+
}
|
|
102
|
+
if (interaction.kind !== "blocking_question" || !("answers" in response) || !desktopObject(response.answers)
|
|
103
|
+
|| Object.keys(response.answers).length !== interaction.questions.length)
|
|
104
|
+
throw new DesktopIpcError("invalid_argument", "Response does not match Desktop request");
|
|
105
|
+
const answers = Object.create(null);
|
|
106
|
+
for (const question of interaction.questions) {
|
|
107
|
+
answers[question.id] = { answers: blockingAnswer(question, response.answers[question.id]) };
|
|
108
|
+
}
|
|
109
|
+
return { answers };
|
|
110
|
+
}
|
|
111
|
+
function blockingAnswer(question, values) {
|
|
112
|
+
if (!Array.isArray(values) || !values.length || values.length > 100 || values.some(value => typeof value !== "string"
|
|
113
|
+
|| !value.trim() || value.length > 16_384 || (!question.isOther && question.options.length > 0 && !question.options.includes(value)))) {
|
|
114
|
+
throw new DesktopIpcError("invalid_argument", "Invalid Desktop blocking answer");
|
|
115
|
+
}
|
|
116
|
+
return values;
|
|
117
|
+
}
|
|
118
|
+
function blockingEffect(turn, interaction, answers) {
|
|
119
|
+
const matches = turn.items.filter(item => item.type === "userInputResponse" && item.completed === true
|
|
120
|
+
&& item.requestId === interaction.requestId && item.turnId === interaction.turnId && item.answers !== undefined
|
|
121
|
+
&& isDeepStrictEqual(Object.entries(item.answers).sort(), Object.entries(answers).sort()));
|
|
122
|
+
return matches.length === 1 ? matches[0].id : undefined;
|
|
123
|
+
}
|
|
124
|
+
export function findDesktopRequestEffect(snapshot, input) {
|
|
125
|
+
const { interaction, response } = input;
|
|
126
|
+
if (snapshot.threadId !== interaction.threadId)
|
|
127
|
+
return null;
|
|
128
|
+
const turn = snapshot.turns.find(turn => turn.turnId === interaction.turnId);
|
|
129
|
+
if (!turn?.itemsComplete)
|
|
130
|
+
return null;
|
|
131
|
+
if (snapshot.pendingRequests.some(request => request.requestId === interaction.requestId && request.method === interaction.method))
|
|
132
|
+
return null;
|
|
133
|
+
if (interaction.kind === "blocking_question" && "answers" in response) {
|
|
134
|
+
const itemId = blockingEffect(turn, interaction, response.answers);
|
|
135
|
+
return itemId ? { evidence: "exact_blocking_answer_observed", itemId } : null;
|
|
136
|
+
}
|
|
137
|
+
if (!("decision" in response))
|
|
138
|
+
return null;
|
|
139
|
+
const item = turn.items.find(item => item.id === interaction.itemId
|
|
140
|
+
&& item.type === (interaction.kind === "command_approval" ? "commandExecution" : "fileChange"));
|
|
141
|
+
const expected = response.decision === "accept" ? ["completed", "failed"] : ["declined"];
|
|
142
|
+
return item?.status && expected.includes(item.status) ? { evidence: "exact_approval_item_advanced", itemId: item.id } : null;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=desktop-request-interactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-request-interactions.js","sourceRoot":"","sources":["../../src/desktop-request-interactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DesktopResponseDependencies } from "./desktop-response-types.js";
|
|
2
|
+
import type { DesktopResponseRecord } from "./desktop-response-store.js";
|
|
3
|
+
import type { DesktopSnapshot, DesktopThreadIdentity } from "./desktop-types.js";
|
|
4
|
+
interface DispatchOptions {
|
|
5
|
+
threadId: string;
|
|
6
|
+
ownerClientId: string;
|
|
7
|
+
expectedRevision: number;
|
|
8
|
+
expectedTurnId: string;
|
|
9
|
+
interactionId: string;
|
|
10
|
+
beforeDispatch(snapshot: DesktopSnapshot): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/** These acknowledgements mean sent; the durable service separately verifies native effects. */
|
|
13
|
+
export declare function dispatchDesktopResponse(deps: DesktopResponseDependencies, target: DesktopThreadIdentity, record: DesktopResponseRecord, options: DispatchOptions): Promise<void>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DesktopTaskError } from "./desktop-task-service.js";
|
|
2
|
+
/** These acknowledgements mean sent; the durable service separately verifies native effects. */
|
|
3
|
+
export async function dispatchDesktopResponse(deps, target, record, options) {
|
|
4
|
+
if (record.interaction.kind === "async_question") {
|
|
5
|
+
const receipt = await deps.answerAsync(target, { ...options, answer: record.answer, clientUserMessageId: record.client_user_message_id });
|
|
6
|
+
if (receipt.turnId !== record.interaction.turnId || receipt.clientUserMessageId !== record.client_user_message_id) {
|
|
7
|
+
throw new Error("Desktop async response receipt changed exact task identity");
|
|
8
|
+
}
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (!deps.respondRequest)
|
|
12
|
+
throw new DesktopTaskError("unsupported_capability", "Desktop request responses are unavailable", "not_sent");
|
|
13
|
+
const receipt = await deps.respondRequest(target, { ...options, operationId: record.operation_id, response: record.response });
|
|
14
|
+
if (receipt.turnId !== record.interaction.turnId || receipt.interactionId !== record.interaction.id ||
|
|
15
|
+
receipt.requestId !== record.interaction.requestId || receipt.acknowledged !== true) {
|
|
16
|
+
throw new Error("Desktop native response receipt changed exact request identity");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=desktop-response-dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-response-dispatch.js","sourceRoot":"","sources":["../../src/desktop-response-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAc7D,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,IAAiC,EAAE,MAA6B,EAC5G,MAA6B,EAAE,OAAwB;IACvD,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAO,EAAE,mBAAmB,EAAE,MAAM,CAAC,sBAAuB,EAAE,CAAC,CAAC;QAC5I,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,OAAO,CAAC,mBAAmB,KAAK,MAAM,CAAC,sBAAsB,EAAE,CAAC;YAClH,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,cAAc;QAAE,MAAM,IAAI,gBAAgB,CAAC,wBAAwB,EAAE,2CAA2C,EAAE,UAAU,CAAC,CAAC;IACxI,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,YAAa,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAS,EAAE,CAAC,CAAC;IACjI,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,OAAO,CAAC,aAAa,KAAK,MAAM,CAAC,WAAW,CAAC,EAAE;QACjG,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC,WAAW,CAAC,SAAS,IAAI,OAAO,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QACtF,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DesktopResponseRecord } from "./desktop-response-store.js";
|
|
2
|
+
import type { DesktopSnapshot } from "./desktop-types.js";
|
|
3
|
+
/** A transport acknowledgement or disappearing prompt alone never confirms a response. */
|
|
4
|
+
export declare function desktopResponseEvidence(record: DesktopResponseRecord, snapshot: DesktopSnapshot): DesktopResponseRecord["evidence"];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { findDesktopAsyncAnswer } from "./desktop-async-interactions.js";
|
|
2
|
+
import { findDesktopRequestEffect } from "./desktop-request-interactions.js";
|
|
3
|
+
/** A transport acknowledgement or disappearing prompt alone never confirms a response. */
|
|
4
|
+
export function desktopResponseEvidence(record, snapshot) {
|
|
5
|
+
if (record.interaction.kind === "async_question") {
|
|
6
|
+
return findDesktopAsyncAnswer(snapshot, { turnId: record.interaction.turnId, interaction: record.interaction,
|
|
7
|
+
answer: record.answer, clientUserMessageId: record.client_user_message_id }) ? "exact_async_answer_observed" : undefined;
|
|
8
|
+
}
|
|
9
|
+
const effect = findDesktopRequestEffect(snapshot, { interaction: record.interaction, response: record.response });
|
|
10
|
+
if (!effect)
|
|
11
|
+
return undefined;
|
|
12
|
+
if (effect.evidence === "exact_blocking_answer_observed")
|
|
13
|
+
return effect.evidence;
|
|
14
|
+
const turn = snapshot.turns.find(candidate => candidate.turnId === record.interaction.turnId);
|
|
15
|
+
const item = turn?.items.find(candidate => candidate.id === effect.itemId);
|
|
16
|
+
// The item must actually advance after this answer intent, not merely have an old terminal status.
|
|
17
|
+
return item?.status !== undefined && item.status !== record.baseline_item_status ? effect.evidence : undefined;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=desktop-response-evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-response-evidence.js","sourceRoot":"","sources":["../../src/desktop-response-evidence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAI7E,0FAA0F;AAC1F,MAAM,UAAU,uBAAuB,CAAC,MAA6B,EAAE,QAAyB;IAC9F,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACjD,OAAO,sBAAsB,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW;YAC1G,MAAM,EAAE,MAAM,CAAC,MAAO,EAAE,mBAAmB,EAAE,MAAM,CAAC,sBAAuB,EAAE,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/H,CAAC;IACD,MAAM,MAAM,GAAG,wBAAwB,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAS,EAAE,CAAC,CAAC;IACnH,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,MAAM,CAAC,QAAQ,KAAK,gCAAgC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IACjF,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9F,MAAM,IAAI,GAAG,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3E,mGAAmG;IACnG,OAAO,IAAI,EAAE,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AACjH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type DesktopResponseRecord } from "./desktop-response-store.js";
|
|
2
|
+
import type { DesktopResponseDependencies, DesktopResponseInput } from "./desktop-response-types.js";
|
|
3
|
+
export type { DesktopResponseDependencies, DesktopResponseInput } from "./desktop-response-types.js";
|
|
4
|
+
/** One durable answer per native question, shared across direct and Watch response routes. */
|
|
5
|
+
export declare function createDesktopResponseService(deps: DesktopResponseDependencies): {
|
|
6
|
+
respond: (input: DesktopResponseInput) => Promise<DesktopResponseRecord>;
|
|
7
|
+
reconcile: (id: string) => Promise<DesktopResponseRecord>;
|
|
8
|
+
status: (id: string) => DesktopResponseRecord;
|
|
9
|
+
list: () => DesktopResponseRecord[];
|
|
10
|
+
respondWatch(watchId: string, input: Omit<DesktopResponseInput, "target" | "desktopId">): Promise<DesktopResponseRecord>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { backendObservationStopped } from "./backend-task-recovery.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { isDeepStrictEqual } from "node:util";
|
|
4
|
+
import { desktopNonblank } from "./desktop-async-state.js";
|
|
5
|
+
import { desktopInteractions } from "./desktop-request-interactions.js";
|
|
6
|
+
import { assertDesktopInteraction, persistDesktopInteraction } from "./desktop-interaction-state.js";
|
|
7
|
+
import { desktopResponseEvidence } from "./desktop-response-evidence.js";
|
|
8
|
+
import { dispatchDesktopResponse } from "./desktop-response-dispatch.js";
|
|
9
|
+
import { validateDesktopResponseValue } from "./desktop-response-value.js";
|
|
10
|
+
import { assertDesktopResponseIdentity, desktopResponseId } from "./desktop-response-store.js";
|
|
11
|
+
import { DesktopTaskError } from "./desktop-task-service.js";
|
|
12
|
+
function errorCode(error) {
|
|
13
|
+
const code = error?.code;
|
|
14
|
+
return typeof code === "string" && /^[a-zA-Z0-9_-]{1,100}$/.test(code) ? code : "desktop_response_observation_unavailable";
|
|
15
|
+
}
|
|
16
|
+
function currentInteraction(snapshot, input, expectedTurnId) {
|
|
17
|
+
const interactions = desktopInteractions(snapshot).filter(candidate => candidate.id === input.interactionId && candidate.threadId === input.target.threadId);
|
|
18
|
+
const interaction = interactions.length === 1 ? interactions[0] : undefined;
|
|
19
|
+
const active = snapshot.turns.filter(turn => turn.status === "inProgress");
|
|
20
|
+
if (snapshot.threadId !== input.target.threadId || !snapshot.ownerClientId || snapshot.runtimeStatus !== "active" ||
|
|
21
|
+
!snapshot.tailKnown || !interaction || active.length !== 1 || active[0].turnId !== interaction.turnId ||
|
|
22
|
+
snapshot.latestTurnId !== interaction.turnId || expectedTurnId && interaction.turnId !== expectedTurnId) {
|
|
23
|
+
throw new DesktopTaskError("stale_interaction", "The exact Desktop interaction is no longer active", "not_sent");
|
|
24
|
+
}
|
|
25
|
+
assertDesktopInteraction(interaction, input.target, expectedTurnId);
|
|
26
|
+
return interaction;
|
|
27
|
+
}
|
|
28
|
+
function assertInput(input) {
|
|
29
|
+
assertDesktopResponseIdentity(input.desktopId, input.target);
|
|
30
|
+
if (![input.controllerSession, input.interactionId, input.responseId].every(desktopNonblank)) {
|
|
31
|
+
throw new DesktopTaskError("invalid_argument", "Desktop response requires controller, interaction and response ID");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function assertDuplicate(record, input, expectedTurnId) {
|
|
35
|
+
if (record.controller_session !== input.controllerSession || record.desktop_id !== input.desktopId ||
|
|
36
|
+
record.interaction.id !== input.interactionId || record.answer !== input.answer || !isDeepStrictEqual(record.response, input.response) ||
|
|
37
|
+
expectedTurnId && record.interaction.turnId !== expectedTurnId) {
|
|
38
|
+
throw new DesktopTaskError("desktop_response_conflict", "This Desktop interaction already has a different response intent");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function itemStatus(snapshot, interaction) {
|
|
42
|
+
return snapshot.turns.find(turn => turn.turnId === interaction.turnId)?.items.find(item => item.id === interaction.itemId)?.status;
|
|
43
|
+
}
|
|
44
|
+
/** One durable answer per native question, shared across direct and Watch response routes. */
|
|
45
|
+
export function createDesktopResponseService(deps) {
|
|
46
|
+
const repo = deps.repository;
|
|
47
|
+
const now = deps.now ?? (() => new Date());
|
|
48
|
+
const uuid = deps.randomUUID ?? randomUUID;
|
|
49
|
+
function status(id) {
|
|
50
|
+
const record = repo.load(id);
|
|
51
|
+
if (!record)
|
|
52
|
+
throw new DesktopTaskError("desktop_response_not_found", "Desktop response was not found");
|
|
53
|
+
return record;
|
|
54
|
+
}
|
|
55
|
+
function update(id, operation) {
|
|
56
|
+
return repo.withLock(id, () => {
|
|
57
|
+
const record = status(id);
|
|
58
|
+
operation(record);
|
|
59
|
+
record.updated_at = now().toISOString();
|
|
60
|
+
return repo.save(record, record.revision);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async function reconcile(id) {
|
|
64
|
+
const previous = status(id);
|
|
65
|
+
if (["confirmed", "not_sent", "reserved"].includes(previous.state))
|
|
66
|
+
return previous;
|
|
67
|
+
let snapshot;
|
|
68
|
+
try {
|
|
69
|
+
snapshot = await deps.observe(previous.target);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
return update(id, record => { if (record.state !== "confirmed")
|
|
73
|
+
record.error_code = errorCode(error); });
|
|
74
|
+
}
|
|
75
|
+
if (snapshot.threadId !== previous.target.threadId)
|
|
76
|
+
throw new DesktopTaskError("desktop_identity_mismatch", "Desktop response observation changed thread");
|
|
77
|
+
const evidence = desktopResponseEvidence(previous, snapshot);
|
|
78
|
+
return update(id, record => {
|
|
79
|
+
if (!evidence || !["sent", "uncertain"].includes(record.state))
|
|
80
|
+
return;
|
|
81
|
+
record.state = "confirmed";
|
|
82
|
+
record.evidence = evidence;
|
|
83
|
+
delete record.error_code;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function reserve(input, interaction, snapshot) {
|
|
87
|
+
const id = desktopResponseId(input.target, input.interactionId);
|
|
88
|
+
const date = now().toISOString();
|
|
89
|
+
return repo.withLock(id, () => {
|
|
90
|
+
const existing = repo.load(id);
|
|
91
|
+
if (existing) {
|
|
92
|
+
assertDuplicate(existing, input);
|
|
93
|
+
if (existing.state !== "not_sent")
|
|
94
|
+
return { record: existing, claimed: false };
|
|
95
|
+
existing.not_sent_history = [...(existing.not_sent_history ?? []), { attempt: existing.attempts, observed_at: existing.updated_at,
|
|
96
|
+
...(existing.error_code ? { error_code: existing.error_code } : {}),
|
|
97
|
+
...(existing.baseline_item_status !== undefined ? { baseline_item_status: existing.baseline_item_status } : {}) }];
|
|
98
|
+
if (interaction.kind !== "async_question")
|
|
99
|
+
existing.baseline_item_status = itemStatus(snapshot, interaction);
|
|
100
|
+
existing.state = "reserved";
|
|
101
|
+
existing.attempts++;
|
|
102
|
+
existing.updated_at = date;
|
|
103
|
+
delete existing.error_code;
|
|
104
|
+
return { record: repo.save(existing, existing.revision), claimed: true };
|
|
105
|
+
}
|
|
106
|
+
const record = { schema: "agent-knock-knock/desktop-response", version: 1, revision: 1, id,
|
|
107
|
+
created_at: date, updated_at: date, target: structuredClone(input.target), desktop_id: input.desktopId,
|
|
108
|
+
controller_session: input.controllerSession, response_id: input.responseId, interaction: persistDesktopInteraction(interaction),
|
|
109
|
+
...(interaction.kind === "async_question" ? { answer: input.answer, client_user_message_id: uuid() }
|
|
110
|
+
: { response: structuredClone(input.response), operation_id: uuid(), baseline_item_status: itemStatus(snapshot, interaction) }),
|
|
111
|
+
state: "reserved", attempts: 1 };
|
|
112
|
+
return { record: repo.save(record, null), claimed: true };
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function withWatch(watchId, input, operation) {
|
|
116
|
+
if (!watchId)
|
|
117
|
+
return operation();
|
|
118
|
+
return deps.tasks.withLock(watchId, () => {
|
|
119
|
+
const task = deps.tasks.load(watchId);
|
|
120
|
+
if (!task || task.controller_session !== input.controllerSession)
|
|
121
|
+
throw new DesktopTaskError("desktop_controller_mismatch", "Watch response requires its owning controller", "not_sent");
|
|
122
|
+
if (backendObservationStopped(task))
|
|
123
|
+
throw new DesktopTaskError("desktop_watch_stopped", "Desktop Watch observation has stopped", "not_sent");
|
|
124
|
+
return operation();
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async function dispatch(input, snapshot, record, watchId) {
|
|
128
|
+
try {
|
|
129
|
+
const options = { threadId: input.target.threadId, ownerClientId: snapshot.ownerClientId,
|
|
130
|
+
expectedRevision: snapshot.revision, expectedTurnId: record.interaction.turnId, interactionId: record.interaction.id,
|
|
131
|
+
beforeDispatch: async (fresh) => {
|
|
132
|
+
const question = currentInteraction(fresh, input, record.interaction.turnId);
|
|
133
|
+
if (fresh.ownerClientId !== snapshot.ownerClientId || fresh.revision < snapshot.revision || question.id !== record.interaction.id) {
|
|
134
|
+
throw new DesktopTaskError("snapshot_changed", "Desktop interaction changed before response dispatch", "not_sent");
|
|
135
|
+
}
|
|
136
|
+
withWatch(watchId, input, () => update(record.id, current => {
|
|
137
|
+
if (current.state !== "reserved")
|
|
138
|
+
throw new DesktopTaskError("desktop_response_already_claimed", "Desktop response was already dispatched", "not_sent");
|
|
139
|
+
current.state = "uncertain";
|
|
140
|
+
}));
|
|
141
|
+
} };
|
|
142
|
+
await dispatchDesktopResponse(deps, input.target, record, options);
|
|
143
|
+
update(record.id, current => { if (current.state !== "confirmed")
|
|
144
|
+
current.state = "sent"; });
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
update(record.id, current => {
|
|
148
|
+
if (current.state === "confirmed")
|
|
149
|
+
return;
|
|
150
|
+
current.state = error?.dispatchState === "not_sent" ? "not_sent" : "uncertain";
|
|
151
|
+
current.error_code = errorCode(error);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function respond(input, expectedTurnId, watchId) {
|
|
156
|
+
assertInput(input);
|
|
157
|
+
withWatch(watchId, input, () => undefined);
|
|
158
|
+
const id = desktopResponseId(input.target, input.interactionId);
|
|
159
|
+
const previous = repo.load(id);
|
|
160
|
+
if (previous) {
|
|
161
|
+
assertDuplicate(previous, input, expectedTurnId);
|
|
162
|
+
if (previous.state !== "not_sent")
|
|
163
|
+
return reconcile(id);
|
|
164
|
+
}
|
|
165
|
+
const snapshot = await deps.observe(input.target);
|
|
166
|
+
const interaction = currentInteraction(snapshot, input, expectedTurnId);
|
|
167
|
+
validateDesktopResponseValue(interaction, input);
|
|
168
|
+
const reserved = withWatch(watchId, input, () => reserve(input, interaction, snapshot));
|
|
169
|
+
if (!reserved.claimed)
|
|
170
|
+
return reserved.record;
|
|
171
|
+
await dispatch(input, snapshot, reserved.record, watchId);
|
|
172
|
+
return reconcile(id);
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
respond: (input) => respond(input), reconcile, status, list: () => repo.list(),
|
|
176
|
+
async respondWatch(watchId, input) {
|
|
177
|
+
const task = deps.tasks.load(watchId);
|
|
178
|
+
if (!task || task.controller_session !== input.controllerSession)
|
|
179
|
+
throw new DesktopTaskError("desktop_controller_mismatch", "Watch response requires its owning controller");
|
|
180
|
+
if (backendObservationStopped(task))
|
|
181
|
+
throw new DesktopTaskError("desktop_watch_stopped", "Desktop Watch observation has stopped", "not_sent");
|
|
182
|
+
if (!task.native_turn_id)
|
|
183
|
+
throw new DesktopTaskError("stale_interaction", "Desktop Watch has no exact task anchor");
|
|
184
|
+
return respond({ ...input, target: task.target, desktopId: task.desktop_id }, task.native_turn_id, watchId);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=desktop-response-service.js.map
|