@lapis-notes/ai 0.1.0
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 +6 -0
- package/LICENSE.md +8 -0
- package/README.md +20 -0
- package/dist/ai-plugin.d.ts +88 -0
- package/dist/ai-plugin.js +742 -0
- package/dist/bootstrap/build.d.ts +15 -0
- package/dist/bootstrap/build.js +28 -0
- package/dist/bootstrap/folder-instructions.d.ts +4 -0
- package/dist/bootstrap/folder-instructions.js +49 -0
- package/dist/bootstrap/format.d.ts +2 -0
- package/dist/bootstrap/format.js +46 -0
- package/dist/bootstrap/instructions.d.ts +1 -0
- package/dist/bootstrap/instructions.js +8 -0
- package/dist/bootstrap/types.d.ts +36 -0
- package/dist/bootstrap/types.js +3 -0
- package/dist/catalog/ai-catalog-panel.svelte +742 -0
- package/dist/catalog/ai-catalog-panel.svelte.d.ts +13 -0
- package/dist/catalog/ai-catalog-view-type.d.ts +1 -0
- package/dist/catalog/ai-catalog-view-type.js +1 -0
- package/dist/catalog/ai-catalog-view.d.ts +22 -0
- package/dist/catalog/ai-catalog-view.js +48 -0
- package/dist/catalog/filter.d.ts +3 -0
- package/dist/catalog/filter.js +24 -0
- package/dist/catalog/inventory.d.ts +21 -0
- package/dist/catalog/inventory.js +255 -0
- package/dist/catalog/tree.d.ts +12 -0
- package/dist/catalog/tree.js +60 -0
- package/dist/catalog/types.d.ts +44 -0
- package/dist/catalog/types.js +1 -0
- package/dist/chat/ai-approval-card.svelte +54 -0
- package/dist/chat/ai-approval-card.svelte.d.ts +9 -0
- package/dist/chat/ai-chat-panel.svelte +1288 -0
- package/dist/chat/ai-chat-panel.svelte.d.ts +50 -0
- package/dist/chat/ai-inventory-result.css +55 -0
- package/dist/chat/ai-inventory-result.svelte +63 -0
- package/dist/chat/ai-inventory-result.svelte.d.ts +5 -0
- package/dist/chat/ai-question-card.svelte +132 -0
- package/dist/chat/ai-question-card.svelte.d.ts +9 -0
- package/dist/chat/ai-view-bootstrap.d.ts +13 -0
- package/dist/chat/ai-view-bootstrap.js +86 -0
- package/dist/chat/ai-view-panel.svelte +89 -0
- package/dist/chat/ai-view-panel.svelte.d.ts +13 -0
- package/dist/chat/ai-view-type.d.ts +1 -0
- package/dist/chat/ai-view-type.js +1 -0
- package/dist/chat/ai-view.d.ts +60 -0
- package/dist/chat/ai-view.js +121 -0
- package/dist/chat/chat-controller.svelte.d.ts +82 -0
- package/dist/chat/chat-controller.svelte.js +1926 -0
- package/dist/chat/chat-items.d.ts +88 -0
- package/dist/chat/chat-items.js +9 -0
- package/dist/chat/chat-mentions.d.ts +15 -0
- package/dist/chat/chat-mentions.js +77 -0
- package/dist/chat/chat-result-views.d.ts +5 -0
- package/dist/chat/chat-result-views.js +15 -0
- package/dist/chat/chat-session.d.ts +28 -0
- package/dist/chat/chat-session.js +50 -0
- package/dist/chat/chat-status.d.ts +1 -0
- package/dist/chat/chat-status.js +3 -0
- package/dist/chat/chat-time.d.ts +18 -0
- package/dist/chat/chat-time.js +90 -0
- package/dist/chat/chat-tool-display.d.ts +17 -0
- package/dist/chat/chat-tool-display.js +213 -0
- package/dist/chat/chat-tool-identity.d.ts +4 -0
- package/dist/chat/chat-tool-identity.js +42 -0
- package/dist/chat/chat-trace.d.ts +6 -0
- package/dist/chat/chat-trace.js +256 -0
- package/dist/chat/live-runtime-unavailable.d.ts +1 -0
- package/dist/chat/live-runtime-unavailable.js +1 -0
- package/dist/commands/agent.d.ts +8 -0
- package/dist/commands/agent.js +38 -0
- package/dist/commands/catalog.d.ts +18 -0
- package/dist/commands/catalog.js +115 -0
- package/dist/commands/discovery.d.ts +36 -0
- package/dist/commands/discovery.js +151 -0
- package/dist/commands/groups.d.ts +16 -0
- package/dist/commands/groups.js +121 -0
- package/dist/commands/inspect.d.ts +18 -0
- package/dist/commands/inspect.js +29 -0
- package/dist/commands/markdown.d.ts +21 -0
- package/dist/commands/markdown.js +117 -0
- package/dist/commands/parser.d.ts +4 -0
- package/dist/commands/parser.js +24 -0
- package/dist/commands/reserved.d.ts +4 -0
- package/dist/commands/reserved.js +107 -0
- package/dist/commands/router.d.ts +17 -0
- package/dist/commands/router.js +170 -0
- package/dist/commands/seed.d.ts +4 -0
- package/dist/commands/seed.js +8 -0
- package/dist/commands/types.d.ts +54 -0
- package/dist/commands/types.js +1 -0
- package/dist/commands/user-agents-node.d.ts +3 -0
- package/dist/commands/user-agents-node.js +52 -0
- package/dist/commands/user-agents.d.ts +22 -0
- package/dist/commands/user-agents.js +40 -0
- package/dist/conversations/approval-grants.d.ts +20 -0
- package/dist/conversations/approval-grants.js +75 -0
- package/dist/conversations/binding-state.d.ts +6 -0
- package/dist/conversations/binding-state.js +35 -0
- package/dist/conversations/context-handoff.d.ts +25 -0
- package/dist/conversations/context-handoff.js +207 -0
- package/dist/conversations/conversation-index-coordinator.d.ts +18 -0
- package/dist/conversations/conversation-index-coordinator.js +81 -0
- package/dist/conversations/conversation-index.d.ts +16 -0
- package/dist/conversations/conversation-index.js +125 -0
- package/dist/conversations/conversation-locator.d.ts +2 -0
- package/dist/conversations/conversation-locator.js +20 -0
- package/dist/conversations/conversation-palette.d.ts +18 -0
- package/dist/conversations/conversation-palette.js +29 -0
- package/dist/conversations/conversation-repository.d.ts +39 -0
- package/dist/conversations/conversation-repository.js +213 -0
- package/dist/conversations/handoff-summary.d.ts +48 -0
- package/dist/conversations/handoff-summary.js +269 -0
- package/dist/conversations/hashes.d.ts +5 -0
- package/dist/conversations/hashes.js +40 -0
- package/dist/conversations/history-creation-scope.d.ts +12 -0
- package/dist/conversations/history-creation-scope.js +44 -0
- package/dist/conversations/jsonl.d.ts +10 -0
- package/dist/conversations/jsonl.js +41 -0
- package/dist/conversations/memory-transcript-store.d.ts +15 -0
- package/dist/conversations/memory-transcript-store.js +119 -0
- package/dist/conversations/paths.d.ts +14 -0
- package/dist/conversations/paths.js +92 -0
- package/dist/conversations/redaction.d.ts +13 -0
- package/dist/conversations/redaction.js +94 -0
- package/dist/conversations/reveal-scope.d.ts +3 -0
- package/dist/conversations/reveal-scope.js +8 -0
- package/dist/conversations/scope-resolver.d.ts +11 -0
- package/dist/conversations/scope-resolver.js +18 -0
- package/dist/conversations/scope-tree.d.ts +10 -0
- package/dist/conversations/scope-tree.js +71 -0
- package/dist/conversations/transcript-projection.d.ts +9 -0
- package/dist/conversations/transcript-projection.js +409 -0
- package/dist/conversations/transcript-store.d.ts +24 -0
- package/dist/conversations/transcript-store.js +27 -0
- package/dist/conversations/types.d.ts +224 -0
- package/dist/conversations/types.js +12 -0
- package/dist/conversations/validation.d.ts +4 -0
- package/dist/conversations/validation.js +383 -0
- package/dist/conversations/vault-transcript-store.d.ts +22 -0
- package/dist/conversations/vault-transcript-store.js +219 -0
- package/dist/core/event-queue.d.ts +6 -0
- package/dist/core/event-queue.js +39 -0
- package/dist/core/types.d.ts +241 -0
- package/dist/core/types.js +50 -0
- package/dist/history/ai-history-panel.svelte +937 -0
- package/dist/history/ai-history-panel.svelte.d.ts +17 -0
- package/dist/history/ai-history-view-type.d.ts +1 -0
- package/dist/history/ai-history-view-type.js +1 -0
- package/dist/history/ai-history-view.d.ts +26 -0
- package/dist/history/ai-history-view.js +51 -0
- package/dist/history/conversation-history-tree.d.ts +15 -0
- package/dist/history/conversation-history-tree.js +71 -0
- package/dist/host/agent-workspace.d.ts +6 -0
- package/dist/host/agent-workspace.js +16 -0
- package/dist/host/create-host-runtimes.d.ts +2 -0
- package/dist/host/create-host-runtimes.js +14 -0
- package/dist/host/desktop-process-host.d.ts +6 -0
- package/dist/host/desktop-process-host.js +74 -0
- package/dist/host/host-runtime-availability.d.ts +1 -0
- package/dist/host/host-runtime-availability.js +3 -0
- package/dist/host/process-host.d.ts +31 -0
- package/dist/host/process-host.js +6 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.js +49 -0
- package/dist/jsonl/ai-jsonl-preview.d.ts +27 -0
- package/dist/jsonl/ai-jsonl-preview.js +68 -0
- package/dist/jsonl/ai-jsonl-view-type.d.ts +1 -0
- package/dist/jsonl/ai-jsonl-view-type.js +1 -0
- package/dist/jsonl/ai-jsonl-view.d.ts +16 -0
- package/dist/jsonl/ai-jsonl-view.js +57 -0
- package/dist/jsonl/ai-jsonl-view.svelte +260 -0
- package/dist/jsonl/ai-jsonl-view.svelte.d.ts +9 -0
- package/dist/memory/candidate-extractor.d.ts +25 -0
- package/dist/memory/candidate-extractor.js +191 -0
- package/dist/memory/forget-confirmation.d.ts +3 -0
- package/dist/memory/forget-confirmation.js +45 -0
- package/dist/memory/hashes.d.ts +5 -0
- package/dist/memory/hashes.js +37 -0
- package/dist/memory/memory-ingestion-coordinator.d.ts +19 -0
- package/dist/memory/memory-ingestion-coordinator.js +108 -0
- package/dist/memory/memory-record-store.d.ts +62 -0
- package/dist/memory/memory-record-store.js +369 -0
- package/dist/memory/memory-scheduler.d.ts +21 -0
- package/dist/memory/memory-scheduler.js +143 -0
- package/dist/memory/memory-tools.d.ts +61 -0
- package/dist/memory/memory-tools.js +99 -0
- package/dist/memory/native-memory-service.d.ts +72 -0
- package/dist/memory/native-memory-service.js +1256 -0
- package/dist/memory/paths.d.ts +13 -0
- package/dist/memory/paths.js +60 -0
- package/dist/memory/runtime-consolidation-provider.d.ts +18 -0
- package/dist/memory/runtime-consolidation-provider.js +154 -0
- package/dist/memory/types.d.ts +139 -0
- package/dist/memory/types.js +1 -0
- package/dist/providers/acp-model-provider.d.ts +11 -0
- package/dist/providers/acp-model-provider.js +99 -0
- package/dist/providers/codex-model-catalog.d.ts +7 -0
- package/dist/providers/codex-model-catalog.js +179 -0
- package/dist/providers/codex-model-provider.d.ts +12 -0
- package/dist/providers/codex-model-provider.js +42 -0
- package/dist/providers/model-provider.d.ts +26 -0
- package/dist/providers/model-provider.js +26 -0
- package/dist/public-components.d.ts +3 -0
- package/dist/public-components.js +3 -0
- package/dist/registry/runtime-registry.d.ts +11 -0
- package/dist/registry/runtime-registry.js +71 -0
- package/dist/registry/select-runtime.d.ts +9 -0
- package/dist/registry/select-runtime.js +31 -0
- package/dist/runtime-adapters.d.ts +16 -0
- package/dist/runtime-adapters.js +9 -0
- package/dist/runtimes/acp/acp-event-mapper.d.ts +56 -0
- package/dist/runtimes/acp/acp-event-mapper.js +237 -0
- package/dist/runtimes/acp/acp-runtime.d.ts +46 -0
- package/dist/runtimes/acp/acp-runtime.js +165 -0
- package/dist/runtimes/acp/desktop-acp-backend.d.ts +16 -0
- package/dist/runtimes/acp/desktop-acp-backend.js +243 -0
- package/dist/runtimes/codex/app-server-protocol.d.ts +28 -0
- package/dist/runtimes/codex/app-server-protocol.js +274 -0
- package/dist/runtimes/codex/codex-runtime.d.ts +24 -0
- package/dist/runtimes/codex/codex-runtime.js +318 -0
- package/dist/runtimes/fake/fake-runtime.d.ts +51 -0
- package/dist/runtimes/fake/fake-runtime.js +257 -0
- package/dist/sessions/plugin-data.d.ts +8 -0
- package/dist/sessions/plugin-data.js +29 -0
- package/dist/sessions/session-store.d.ts +47 -0
- package/dist/sessions/session-store.js +117 -0
- package/dist/settings/acp-agents.d.ts +8 -0
- package/dist/settings/acp-agents.js +11 -0
- package/dist/settings/ai-settings-tab.d.ts +8 -0
- package/dist/settings/ai-settings-tab.js +249 -0
- package/dist/settings/ai-settings.d.ts +43 -0
- package/dist/settings/ai-settings.js +147 -0
- package/dist/settings/app-tool-setting-rows.d.ts +16 -0
- package/dist/settings/app-tool-setting-rows.js +30 -0
- package/dist/settings/register-ai-settings.d.ts +3 -0
- package/dist/settings/register-ai-settings.js +393 -0
- package/dist/skills/activation.d.ts +2 -0
- package/dist/skills/activation.js +20 -0
- package/dist/skills/bundled/lapis-notes.d.ts +3 -0
- package/dist/skills/bundled/lapis-notes.js +52 -0
- package/dist/skills/bundled/research.d.ts +6 -0
- package/dist/skills/bundled/research.js +29 -0
- package/dist/skills/discovery.d.ts +21 -0
- package/dist/skills/discovery.js +227 -0
- package/dist/skills/manifest.d.ts +3 -0
- package/dist/skills/manifest.js +39 -0
- package/dist/skills/parser.d.ts +12 -0
- package/dist/skills/parser.js +124 -0
- package/dist/skills/registry.d.ts +21 -0
- package/dist/skills/registry.js +89 -0
- package/dist/skills/seed.d.ts +5 -0
- package/dist/skills/seed.js +18 -0
- package/dist/skills/skill-tools.d.ts +8 -0
- package/dist/skills/skill-tools.js +113 -0
- package/dist/skills/types.d.ts +67 -0
- package/dist/skills/types.js +1 -0
- package/dist/styles.css +514 -0
- package/dist/tools/app-tool-host.d.ts +47 -0
- package/dist/tools/app-tool-host.js +419 -0
- package/dist/tools/desktop-app-tool-bridge.d.ts +23 -0
- package/dist/tools/desktop-app-tool-bridge.js +223 -0
- package/dist/tools/mcp-server-registry.d.ts +7 -0
- package/dist/tools/mcp-server-registry.js +30 -0
- package/manifest.json +34 -0
- package/package.json +83 -0
- package/styles.css +1 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { AsyncEventQueue } from "../../core/event-queue";
|
|
2
|
+
import { ACP_APPROVAL_CAPABILITIES, projectAgentTurnPrompt, } from "../../core/types";
|
|
3
|
+
import { mapAcpPermissionRequest, mapAcpRuntimeEvent, mapApprovalOptionToAcpDecision, } from "./acp-event-mapper";
|
|
4
|
+
import { projectSkillActivationPrompt } from "../../skills/activation";
|
|
5
|
+
export class AcpAgentSession {
|
|
6
|
+
id;
|
|
7
|
+
#backend;
|
|
8
|
+
#events = new AsyncEventQueue();
|
|
9
|
+
#pending = new Map();
|
|
10
|
+
#consume = null;
|
|
11
|
+
#activations;
|
|
12
|
+
constructor(backend, activations) {
|
|
13
|
+
this.id = backend.id;
|
|
14
|
+
this.#backend = backend;
|
|
15
|
+
this.#activations = activations;
|
|
16
|
+
this.#consume = this.#pump();
|
|
17
|
+
}
|
|
18
|
+
events() {
|
|
19
|
+
return this.#events;
|
|
20
|
+
}
|
|
21
|
+
async send(input, options) {
|
|
22
|
+
const projected = projectSkillActivationPrompt(projectAgentTurnPrompt(input, options?.contextBlocks), this.#activations);
|
|
23
|
+
this.#activations = undefined;
|
|
24
|
+
await this.#backend.prompt(projected);
|
|
25
|
+
}
|
|
26
|
+
configure(input) {
|
|
27
|
+
if (!this.#backend.configure) {
|
|
28
|
+
return Promise.resolve({
|
|
29
|
+
...(input.model
|
|
30
|
+
? {
|
|
31
|
+
model: {
|
|
32
|
+
status: "unsupported",
|
|
33
|
+
reason: "ACP backend configuration is unavailable.",
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
: {}),
|
|
37
|
+
...(input.thinking
|
|
38
|
+
? {
|
|
39
|
+
thinking: {
|
|
40
|
+
status: "unsupported",
|
|
41
|
+
reason: "ACP backend configuration is unavailable.",
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
: {}),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return this.#backend.configure(input);
|
|
48
|
+
}
|
|
49
|
+
async respondToApproval(requestId, optionId) {
|
|
50
|
+
const pending = this.#pending.get(requestId);
|
|
51
|
+
if (!pending)
|
|
52
|
+
throw new Error(`Unknown approval request: ${requestId}`);
|
|
53
|
+
this.#pending.delete(requestId);
|
|
54
|
+
pending.resolve(optionId);
|
|
55
|
+
}
|
|
56
|
+
async cancel() {
|
|
57
|
+
await this.#backend.cancel();
|
|
58
|
+
}
|
|
59
|
+
async detach() {
|
|
60
|
+
for (const [id, pending] of this.#pending) {
|
|
61
|
+
this.#pending.delete(id);
|
|
62
|
+
pending.reject(new Error("Session detached."));
|
|
63
|
+
}
|
|
64
|
+
if (this.#backend.detach)
|
|
65
|
+
await this.#backend.detach();
|
|
66
|
+
else
|
|
67
|
+
await this.#backend.close();
|
|
68
|
+
await this.#consume;
|
|
69
|
+
this.#events.close();
|
|
70
|
+
}
|
|
71
|
+
async close() {
|
|
72
|
+
for (const [id, pending] of this.#pending) {
|
|
73
|
+
this.#pending.delete(id);
|
|
74
|
+
pending.reject(new Error("Session closed."));
|
|
75
|
+
}
|
|
76
|
+
await this.#backend.close();
|
|
77
|
+
await this.#consume;
|
|
78
|
+
this.#events.close();
|
|
79
|
+
}
|
|
80
|
+
async handlePermissionRequest(request) {
|
|
81
|
+
const mapped = mapAcpPermissionRequest(request);
|
|
82
|
+
this.#events.push({
|
|
83
|
+
type: "permission.request",
|
|
84
|
+
request: mapped,
|
|
85
|
+
...(request.__source ? { source: { ...request.__source } } : {}),
|
|
86
|
+
});
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
this.#pending.set(mapped.id, {
|
|
89
|
+
resolve: (optionId) => resolve(mapApprovalOptionToAcpDecision(optionId)),
|
|
90
|
+
reject,
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async #pump() {
|
|
95
|
+
try {
|
|
96
|
+
for await (const event of this.#backend.events()) {
|
|
97
|
+
const mapped = mapAcpRuntimeEvent(event);
|
|
98
|
+
if (mapped)
|
|
99
|
+
this.#events.push(mapped);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.#events.push({
|
|
104
|
+
type: "error",
|
|
105
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export class AcpAgentRuntime {
|
|
111
|
+
id = "acp";
|
|
112
|
+
#backend;
|
|
113
|
+
constructor(backend) {
|
|
114
|
+
this.#backend = backend;
|
|
115
|
+
}
|
|
116
|
+
capabilities() {
|
|
117
|
+
return {
|
|
118
|
+
sessions: true,
|
|
119
|
+
resume: typeof this.#backend.resume === "function",
|
|
120
|
+
cancel: true,
|
|
121
|
+
steer: false,
|
|
122
|
+
modelSelection: true,
|
|
123
|
+
nativeTools: true,
|
|
124
|
+
mcpTools: true,
|
|
125
|
+
approvals: ACP_APPROVAL_CAPABILITIES,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async supports(request) {
|
|
129
|
+
if (request.requirePolicyAmendments)
|
|
130
|
+
return false;
|
|
131
|
+
return this.#backend.available();
|
|
132
|
+
}
|
|
133
|
+
async start(request) {
|
|
134
|
+
let session;
|
|
135
|
+
const backend = await this.#backend.start({
|
|
136
|
+
request,
|
|
137
|
+
onPermissionRequest: (permission) => {
|
|
138
|
+
if (!session) {
|
|
139
|
+
throw new Error("ACP session is not ready for approvals.");
|
|
140
|
+
}
|
|
141
|
+
return session.handlePermissionRequest(permission);
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
session = new AcpAgentSession(backend, request.skillActivations);
|
|
145
|
+
return session;
|
|
146
|
+
}
|
|
147
|
+
async resume(sessionId, request) {
|
|
148
|
+
if (!this.#backend.resume) {
|
|
149
|
+
throw new Error("ACP backend does not support resume.");
|
|
150
|
+
}
|
|
151
|
+
let session;
|
|
152
|
+
const backend = await this.#backend.resume({
|
|
153
|
+
sessionId,
|
|
154
|
+
request,
|
|
155
|
+
onPermissionRequest: (permission) => {
|
|
156
|
+
if (!session) {
|
|
157
|
+
throw new Error("ACP session is not ready for approvals.");
|
|
158
|
+
}
|
|
159
|
+
return session.handlePermissionRequest(permission);
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
session = new AcpAgentSession(backend, request?.skillActivations);
|
|
163
|
+
return session;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentRequest } from "../../core/types";
|
|
2
|
+
import type { AcpBackendSession, AcpRuntimeBackend } from "./acp-runtime";
|
|
3
|
+
import type { AcpPermissionDecision, AcpPermissionRequestLike } from "./acp-event-mapper";
|
|
4
|
+
export declare class DesktopAcpRuntimeBackend implements AcpRuntimeBackend {
|
|
5
|
+
#private;
|
|
6
|
+
available(): Promise<boolean>;
|
|
7
|
+
start(input: {
|
|
8
|
+
request: AgentRequest;
|
|
9
|
+
onPermissionRequest(request: AcpPermissionRequestLike): Promise<AcpPermissionDecision>;
|
|
10
|
+
}): Promise<AcpBackendSession>;
|
|
11
|
+
resume(input: {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
request?: Omit<AgentRequest, "prompt">;
|
|
14
|
+
onPermissionRequest(request: AcpPermissionRequestLike): Promise<AcpPermissionDecision>;
|
|
15
|
+
}): Promise<AcpBackendSession>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { getNativeDesktopBridge, getNativeDesktopCapability, hasNativeDesktopCapability, } from "@lapis-notes/api/desktop-native";
|
|
2
|
+
import { AsyncEventQueue } from "../../core/event-queue";
|
|
3
|
+
const RUN_STATUS_POLL_MS = 1_000;
|
|
4
|
+
const MAX_RUN_STATUS_FAILURES = 3;
|
|
5
|
+
function isTerminalRuntimeEvent(event) {
|
|
6
|
+
const type = event.event.event?.type;
|
|
7
|
+
return (event.event.type === "closed" ||
|
|
8
|
+
type === "done" ||
|
|
9
|
+
type === "completed" ||
|
|
10
|
+
type === "error");
|
|
11
|
+
}
|
|
12
|
+
export class DesktopAcpRuntimeBackend {
|
|
13
|
+
async available() {
|
|
14
|
+
return hasNativeDesktopCapability("agent-runtime");
|
|
15
|
+
}
|
|
16
|
+
async start(input) {
|
|
17
|
+
return this.#open(input.request, input.onPermissionRequest);
|
|
18
|
+
}
|
|
19
|
+
async resume(input) {
|
|
20
|
+
return this.#open({ ...input.request, prompt: "" }, input.onPermissionRequest, input.sessionId);
|
|
21
|
+
}
|
|
22
|
+
async #open(request, onPermissionRequest, resumeSessionId) {
|
|
23
|
+
const bridge = getRequiredBridge();
|
|
24
|
+
const capability = getNativeDesktopCapability("agent-runtime");
|
|
25
|
+
const protocolVersion = Number(capability?.details?.protocolVersion ?? 2);
|
|
26
|
+
const supportsSessionConfiguration = protocolVersion >= 5 ||
|
|
27
|
+
capability?.details?.sessionConfiguration === "configure";
|
|
28
|
+
const deferredStart = capability?.details?.deferredStart === true;
|
|
29
|
+
const reconcilesRunStatus = capability?.details?.runStatus === true;
|
|
30
|
+
const events = new AsyncEventQueue();
|
|
31
|
+
let sessionId = deferredStart
|
|
32
|
+
? (resumeSessionId ?? crypto.randomUUID())
|
|
33
|
+
: "";
|
|
34
|
+
let activeRunId = null;
|
|
35
|
+
let lastSequence = 0;
|
|
36
|
+
let statusFailures = 0;
|
|
37
|
+
let disposed = false;
|
|
38
|
+
let statusTimer;
|
|
39
|
+
const clearStatusTimer = () => {
|
|
40
|
+
if (statusTimer)
|
|
41
|
+
clearTimeout(statusTimer);
|
|
42
|
+
statusTimer = undefined;
|
|
43
|
+
};
|
|
44
|
+
const settleActiveRun = (runId) => {
|
|
45
|
+
if (activeRunId !== runId)
|
|
46
|
+
return;
|
|
47
|
+
activeRunId = null;
|
|
48
|
+
statusFailures = 0;
|
|
49
|
+
clearStatusTimer();
|
|
50
|
+
};
|
|
51
|
+
const deliverRuntimeEvent = (event, deliverySource = "live") => {
|
|
52
|
+
if (event.sessionId !== sessionId)
|
|
53
|
+
return;
|
|
54
|
+
if (activeRunId && event.runId !== activeRunId)
|
|
55
|
+
return;
|
|
56
|
+
if (reconcilesRunStatus &&
|
|
57
|
+
deliverySource === "live" &&
|
|
58
|
+
activeRunId === event.runId &&
|
|
59
|
+
isTerminalRuntimeEvent(event)) {
|
|
60
|
+
clearStatusTimer();
|
|
61
|
+
void reconcileRunStatus(event.runId);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (event.sequence <= lastSequence)
|
|
65
|
+
return;
|
|
66
|
+
lastSequence = event.sequence;
|
|
67
|
+
const source = {
|
|
68
|
+
sessionId: event.sessionId,
|
|
69
|
+
runId: event.runId,
|
|
70
|
+
sequence: event.sequence,
|
|
71
|
+
};
|
|
72
|
+
if (event.event.type === "event" && event.event.event) {
|
|
73
|
+
events.push({
|
|
74
|
+
...event.event.event,
|
|
75
|
+
__source: source,
|
|
76
|
+
});
|
|
77
|
+
if (isTerminalRuntimeEvent(event))
|
|
78
|
+
settleActiveRun(event.runId);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (event.event.type === "permission" && event.event.request) {
|
|
82
|
+
const request = {
|
|
83
|
+
...event.event.request,
|
|
84
|
+
__source: source,
|
|
85
|
+
};
|
|
86
|
+
void onPermissionRequest(request).then((decision) => bridge.invoke("desktop_agent_acp_respond", {
|
|
87
|
+
sessionId,
|
|
88
|
+
requestId: String(request.requestId ?? request.id),
|
|
89
|
+
decision: decision.outcome,
|
|
90
|
+
}));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (event.event.event?.type === "error") {
|
|
94
|
+
events.push({
|
|
95
|
+
type: "error",
|
|
96
|
+
message: String(event.event.event.message ?? "") ||
|
|
97
|
+
"Agent-runtime connection closed",
|
|
98
|
+
__source: source,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (isTerminalRuntimeEvent(event))
|
|
102
|
+
settleActiveRun(event.runId);
|
|
103
|
+
events.close();
|
|
104
|
+
};
|
|
105
|
+
const failRunStatus = (runId, message) => {
|
|
106
|
+
if (activeRunId !== runId)
|
|
107
|
+
return;
|
|
108
|
+
events.push({ type: "error", message });
|
|
109
|
+
settleActiveRun(runId);
|
|
110
|
+
events.close();
|
|
111
|
+
};
|
|
112
|
+
const scheduleRunStatus = (runId) => {
|
|
113
|
+
if (!reconcilesRunStatus || disposed || activeRunId !== runId)
|
|
114
|
+
return;
|
|
115
|
+
clearStatusTimer();
|
|
116
|
+
statusTimer = setTimeout(() => void reconcileRunStatus(runId), RUN_STATUS_POLL_MS);
|
|
117
|
+
};
|
|
118
|
+
const reconcileRunStatus = async (runId) => {
|
|
119
|
+
if (disposed || activeRunId !== runId)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
const snapshot = await bridge.invoke("desktop_agent_acp_status", { sessionId });
|
|
123
|
+
if (disposed || activeRunId !== runId)
|
|
124
|
+
return;
|
|
125
|
+
if (snapshot.runId !== runId || snapshot.state === "idle") {
|
|
126
|
+
statusFailures += 1;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
statusFailures = 0;
|
|
130
|
+
}
|
|
131
|
+
if (snapshot.runId === runId && snapshot.state === "terminal") {
|
|
132
|
+
const retained = snapshot.events?.length
|
|
133
|
+
? [...snapshot.events].sort((left, right) => left.sequence - right.sequence)
|
|
134
|
+
: snapshot.terminalEvent
|
|
135
|
+
? [snapshot.terminalEvent]
|
|
136
|
+
: [];
|
|
137
|
+
for (const event of retained)
|
|
138
|
+
deliverRuntimeEvent(event, "status");
|
|
139
|
+
if (activeRunId === runId) {
|
|
140
|
+
failRunStatus(runId, "The desktop agent finished without a recoverable terminal event.");
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
statusFailures += 1;
|
|
147
|
+
}
|
|
148
|
+
if (statusFailures >= MAX_RUN_STATUS_FAILURES) {
|
|
149
|
+
failRunStatus(runId, "The desktop agent status channel became unavailable.");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
scheduleRunStatus(runId);
|
|
153
|
+
};
|
|
154
|
+
const onRuntimeEvent = (event) => {
|
|
155
|
+
deliverRuntimeEvent(event);
|
|
156
|
+
};
|
|
157
|
+
let unsubscribe = deferredStart
|
|
158
|
+
? bridge.onAgentRuntimeEvent?.(onRuntimeEvent)
|
|
159
|
+
: undefined;
|
|
160
|
+
try {
|
|
161
|
+
const started = await bridge.invoke("desktop_agent_acp_start", {
|
|
162
|
+
...(deferredStart ? { sessionId } : {}),
|
|
163
|
+
workspace: request.workspace,
|
|
164
|
+
agent: request.agent,
|
|
165
|
+
model: request.model,
|
|
166
|
+
thinking: request.thinking,
|
|
167
|
+
metadata: request.metadata,
|
|
168
|
+
restricted: request.restricted,
|
|
169
|
+
...(protocolVersion >= 3
|
|
170
|
+
? {
|
|
171
|
+
mcpServers: request.mcpServers,
|
|
172
|
+
appToolBridgeId: request.appToolSession?.bridgeId,
|
|
173
|
+
}
|
|
174
|
+
: { tools: request.mcpServers }),
|
|
175
|
+
resumeSessionId,
|
|
176
|
+
});
|
|
177
|
+
if (deferredStart && started.sessionId !== sessionId) {
|
|
178
|
+
throw new Error("The desktop agent host returned a different reserved session id.");
|
|
179
|
+
}
|
|
180
|
+
sessionId = started.sessionId;
|
|
181
|
+
unsubscribe ??= bridge.onAgentRuntimeEvent?.(onRuntimeEvent);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
unsubscribe?.();
|
|
185
|
+
events.close();
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
const detach = () => {
|
|
189
|
+
disposed = true;
|
|
190
|
+
activeRunId = null;
|
|
191
|
+
clearStatusTimer();
|
|
192
|
+
unsubscribe?.();
|
|
193
|
+
events.close();
|
|
194
|
+
};
|
|
195
|
+
return {
|
|
196
|
+
id: sessionId,
|
|
197
|
+
events: () => events,
|
|
198
|
+
async prompt(text) {
|
|
199
|
+
lastSequence = 0;
|
|
200
|
+
const prompted = await bridge.invoke("desktop_agent_acp_prompt", { sessionId, text });
|
|
201
|
+
activeRunId = prompted.runId;
|
|
202
|
+
statusFailures = 0;
|
|
203
|
+
scheduleRunStatus(prompted.runId);
|
|
204
|
+
},
|
|
205
|
+
async configure(input) {
|
|
206
|
+
if (!supportsSessionConfiguration) {
|
|
207
|
+
return {
|
|
208
|
+
...(input.model
|
|
209
|
+
? { model: { status: "unsupported" } }
|
|
210
|
+
: {}),
|
|
211
|
+
...(input.thinking
|
|
212
|
+
? { thinking: { status: "unsupported" } }
|
|
213
|
+
: {}),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return bridge.invoke("desktop_agent_acp_configure", {
|
|
217
|
+
sessionId,
|
|
218
|
+
model: input.model,
|
|
219
|
+
thinking: input.thinking,
|
|
220
|
+
});
|
|
221
|
+
},
|
|
222
|
+
async cancel() {
|
|
223
|
+
activeRunId = null;
|
|
224
|
+
clearStatusTimer();
|
|
225
|
+
await bridge.invoke("desktop_agent_acp_cancel", { sessionId });
|
|
226
|
+
},
|
|
227
|
+
async detach() {
|
|
228
|
+
detach();
|
|
229
|
+
},
|
|
230
|
+
async close() {
|
|
231
|
+
detach();
|
|
232
|
+
await bridge.invoke("desktop_agent_acp_close", { sessionId });
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function getRequiredBridge() {
|
|
238
|
+
const bridge = getNativeDesktopBridge();
|
|
239
|
+
if (!bridge) {
|
|
240
|
+
throw new Error("The desktop agent-runtime bridge is not registered.");
|
|
241
|
+
}
|
|
242
|
+
return bridge;
|
|
243
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type AgentEvent, type ApprovalRequest, type UserInputAnswers, type UserInputRequest } from "../../core/types";
|
|
2
|
+
export type AppServerMessage = {
|
|
3
|
+
id?: string | number;
|
|
4
|
+
method?: string;
|
|
5
|
+
params?: unknown;
|
|
6
|
+
result?: unknown;
|
|
7
|
+
error?: {
|
|
8
|
+
message?: string;
|
|
9
|
+
} | unknown;
|
|
10
|
+
};
|
|
11
|
+
export declare function mapCodexNotification(message: AppServerMessage): AgentEvent | null;
|
|
12
|
+
export declare function approvalRequestFromServerRequest(message: AppServerMessage): ApprovalRequest | null;
|
|
13
|
+
export declare function userInputRequestFromServerRequest(message: AppServerMessage): UserInputRequest | null;
|
|
14
|
+
export declare function userInputReplyForServerRequest(message: AppServerMessage, answers: UserInputAnswers): {
|
|
15
|
+
result?: Record<string, unknown>;
|
|
16
|
+
error?: {
|
|
17
|
+
code: number;
|
|
18
|
+
message: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function approvalResponseForOption(optionId: string): Record<string, unknown>;
|
|
22
|
+
export declare function approvalReplyForServerRequest(message: AppServerMessage, optionId: string): {
|
|
23
|
+
result?: Record<string, unknown>;
|
|
24
|
+
error?: {
|
|
25
|
+
code: number;
|
|
26
|
+
message: string;
|
|
27
|
+
};
|
|
28
|
+
};
|