@agent-api/app-engine 0.0.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.
Files changed (62) hide show
  1. package/README.md +46 -0
  2. package/dist/agent/runner.d.ts +117 -0
  3. package/dist/agent/runner.js +486 -0
  4. package/dist/agent.d.ts +2 -0
  5. package/dist/agent.js +2 -0
  6. package/dist/chat-options.d.ts +37 -0
  7. package/dist/chat-options.js +42 -0
  8. package/dist/config.d.ts +66 -0
  9. package/dist/config.js +201 -0
  10. package/dist/conversation/index.d.ts +17 -0
  11. package/dist/conversation/index.js +54 -0
  12. package/dist/engine/agent-engine.d.ts +38 -0
  13. package/dist/engine/agent-engine.js +146 -0
  14. package/dist/engine/index.d.ts +50 -0
  15. package/dist/engine/index.js +26 -0
  16. package/dist/engine/services.d.ts +20 -0
  17. package/dist/engine/services.js +1 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +1 -0
  20. package/dist/profile.d.ts +57 -0
  21. package/dist/profile.js +211 -0
  22. package/dist/runtime/index.d.ts +23 -0
  23. package/dist/runtime/index.js +177 -0
  24. package/dist/update.d.ts +16 -0
  25. package/dist/update.js +74 -0
  26. package/dist/workbench/auth-controller.d.ts +43 -0
  27. package/dist/workbench/auth-controller.js +84 -0
  28. package/dist/workbench/auth-gate-controller.d.ts +62 -0
  29. package/dist/workbench/auth-gate-controller.js +231 -0
  30. package/dist/workbench/command-controller.d.ts +29 -0
  31. package/dist/workbench/command-controller.js +426 -0
  32. package/dist/workbench/conversation-controller.d.ts +32 -0
  33. package/dist/workbench/conversation-controller.js +53 -0
  34. package/dist/workbench/engine.d.ts +66 -0
  35. package/dist/workbench/engine.js +291 -0
  36. package/dist/workbench/input-controller.d.ts +44 -0
  37. package/dist/workbench/input-controller.js +71 -0
  38. package/dist/workbench/isolator-installer.d.ts +29 -0
  39. package/dist/workbench/isolator-installer.js +208 -0
  40. package/dist/workbench/lifecycle-controller.d.ts +30 -0
  41. package/dist/workbench/lifecycle-controller.js +75 -0
  42. package/dist/workbench/local-controller.d.ts +21 -0
  43. package/dist/workbench/local-controller.js +94 -0
  44. package/dist/workbench/render-model.d.ts +46 -0
  45. package/dist/workbench/render-model.js +61 -0
  46. package/dist/workbench/runtime-controller.d.ts +12 -0
  47. package/dist/workbench/runtime-controller.js +57 -0
  48. package/dist/workbench/session.d.ts +29 -0
  49. package/dist/workbench/session.js +42 -0
  50. package/dist/workbench/settings-controller.d.ts +80 -0
  51. package/dist/workbench/settings-controller.js +309 -0
  52. package/dist/workbench/shell-isolation.d.ts +20 -0
  53. package/dist/workbench/shell-isolation.js +13 -0
  54. package/dist/workbench/state.d.ts +187 -0
  55. package/dist/workbench/state.js +392 -0
  56. package/dist/workbench/turn-controller.d.ts +25 -0
  57. package/dist/workbench/turn-controller.js +164 -0
  58. package/dist/workbench/view-model.d.ts +34 -0
  59. package/dist/workbench/view-model.js +121 -0
  60. package/dist/workdir/index.d.ts +22 -0
  61. package/dist/workdir/index.js +46 -0
  62. package/package.json +50 -0
@@ -0,0 +1,426 @@
1
+ import { UnknownPresetError } from "./settings-controller.js";
2
+ export function createWorkbenchCommandController(options) {
3
+ const dispatch = options.engine.dispatch;
4
+ return {
5
+ async run(command) {
6
+ const commandResult = options.engine.handleCommand(command);
7
+ if (commandResult.handled) {
8
+ await runEffects(commandResult.effects);
9
+ return;
10
+ }
11
+ switch (command.kind) {
12
+ case "abort":
13
+ if (!options.engine.snapshot().busy) {
14
+ dispatch({ type: "message.add", role: "system", text: "No agent turn is running." });
15
+ return;
16
+ }
17
+ await options.turnController.abort("Abort requested.");
18
+ return;
19
+ case "config":
20
+ await runConfigCommand(command);
21
+ return;
22
+ case "preset":
23
+ await runPresetCommand(command.value);
24
+ return;
25
+ case "summary":
26
+ await showSummary();
27
+ return;
28
+ case "search":
29
+ await searchWorkdir(command.query);
30
+ return;
31
+ case "new_conversation":
32
+ await startNewConversation(command.name);
33
+ return;
34
+ case "switch_conversation":
35
+ switchConversation(command.name);
36
+ return;
37
+ case "list_conversations":
38
+ await showConversations();
39
+ return;
40
+ case "preview":
41
+ showEditPreview();
42
+ return;
43
+ case "apply":
44
+ await applyPendingEdit(false);
45
+ return;
46
+ case "apply_all":
47
+ await applyPendingEdit(true);
48
+ return;
49
+ case "reject":
50
+ rejectPendingEdit();
51
+ return;
52
+ }
53
+ },
54
+ runEffects,
55
+ };
56
+ async function runEffects(effects) {
57
+ for (const effect of effects) {
58
+ switch (effect.type) {
59
+ case "exit":
60
+ options.onExit();
61
+ break;
62
+ case "login":
63
+ options.onLogin();
64
+ break;
65
+ case "logout":
66
+ dispatch({ type: "activity.add", text: `Logged out: ${options.profileName}` });
67
+ options.onLogout();
68
+ break;
69
+ case "delete_profile":
70
+ dispatch({ type: "activity.add", level: "warning", text: `Deleting profile: ${options.profileName}` });
71
+ await options.onDeleteProfile();
72
+ break;
73
+ case "switch_profile":
74
+ options.onSwitchProfile(effect.name);
75
+ break;
76
+ case "show_auth_status":
77
+ await showAuthStatus();
78
+ break;
79
+ case "export_transcript":
80
+ await exportTranscript(effect);
81
+ break;
82
+ case "clear_preset_tool_catalog_cache":
83
+ options.settingsController.clearPresetToolCatalogCache();
84
+ break;
85
+ }
86
+ }
87
+ }
88
+ async function runConfigCommand(command) {
89
+ const state = options.engine.snapshot();
90
+ if (!command.field) {
91
+ dispatch({
92
+ type: "message.add",
93
+ role: "system",
94
+ text: options.settingsController.configText({
95
+ profileName: options.profileName,
96
+ runPreset: state.runPreset,
97
+ runModel: state.runModel,
98
+ accessMode: state.accessMode,
99
+ contextEnabled: state.contextEnabled,
100
+ defaultPreset: state.defaultPreset,
101
+ renderMode: state.renderMode,
102
+ shellIsolation: state.shellIsolation,
103
+ }),
104
+ });
105
+ return;
106
+ }
107
+ if (command.field === "preset") {
108
+ if (!command.value) {
109
+ dispatch({
110
+ type: "message.add",
111
+ role: "system",
112
+ text: options.settingsController.defaultPresetHelp(state.defaultPreset),
113
+ });
114
+ return;
115
+ }
116
+ try {
117
+ const settings = await options.settingsController.saveDefaultPreset({
118
+ value: command.value,
119
+ profileName: options.profileName,
120
+ options: options.options,
121
+ });
122
+ dispatch({ type: "settings.set", settings: { defaultPreset: settings.defaultPreset, runPreset: settings.runPreset } });
123
+ dispatch({
124
+ type: "message.add",
125
+ role: "system",
126
+ text: settings.message,
127
+ });
128
+ dispatch({ type: "activity.add", level: "success", text: settings.activity });
129
+ }
130
+ catch (error) {
131
+ if (error instanceof UnknownPresetError) {
132
+ dispatch({
133
+ type: "message.add",
134
+ role: "system",
135
+ text: await presetListText(`Unknown preset: ${error.preset}`),
136
+ });
137
+ dispatch({ type: "activity.add", level: "warning", text: `Unknown preset: ${error.preset}` });
138
+ return;
139
+ }
140
+ dispatch({ type: "message.add", role: "system", text: `Could not save default preset: ${userFacingError(error)}` });
141
+ dispatch({ type: "activity.add", level: "error", text: "Default preset save failed" });
142
+ }
143
+ }
144
+ if (command.field === "isolation") {
145
+ if (!command.value) {
146
+ dispatch({
147
+ type: "message.add",
148
+ role: "system",
149
+ text: options.settingsController.shellIsolationHelp(state.shellIsolation),
150
+ });
151
+ return;
152
+ }
153
+ try {
154
+ const settings = await options.settingsController.saveShellIsolationMode(command.value);
155
+ dispatch({ type: "settings.set", settings: { shellIsolation: settings.shellIsolation } });
156
+ dispatch({ type: "message.add", role: "system", text: settings.message });
157
+ dispatch({ type: "activity.add", level: "success", text: settings.activity });
158
+ }
159
+ catch (error) {
160
+ dispatch({ type: "message.add", role: "system", text: `Could not save shell isolation mode: ${userFacingError(error)}` });
161
+ dispatch({ type: "activity.add", level: "error", text: "Shell isolation save failed" });
162
+ }
163
+ return;
164
+ }
165
+ if (command.field === "isolator") {
166
+ if (!command.value) {
167
+ dispatch({
168
+ type: "message.add",
169
+ role: "system",
170
+ text: options.settingsController.isolatorPathHelp(state.shellIsolation),
171
+ });
172
+ return;
173
+ }
174
+ try {
175
+ const [subcommand = "", ...rest] = command.value.split(/\s+/);
176
+ const value = rest.join(" ").trim();
177
+ const settings = subcommand === "source"
178
+ ? await options.settingsController.saveIsolatorSource(value)
179
+ : subcommand === "path"
180
+ ? await options.settingsController.saveIsolatorPath(value)
181
+ : await options.settingsController.saveIsolatorPath(command.value);
182
+ dispatch({ type: "settings.set", settings: { shellIsolation: settings.shellIsolation } });
183
+ dispatch({ type: "message.add", role: "system", text: settings.message });
184
+ dispatch({ type: "activity.add", level: "success", text: settings.activity });
185
+ }
186
+ catch (error) {
187
+ dispatch({ type: "message.add", role: "system", text: `Could not save isolator path: ${userFacingError(error)}` });
188
+ dispatch({ type: "activity.add", level: "error", text: "Isolator path save failed" });
189
+ }
190
+ }
191
+ }
192
+ async function runPresetCommand(value) {
193
+ const state = options.engine.snapshot();
194
+ if (!value) {
195
+ dispatch({
196
+ type: "message.add",
197
+ role: "system",
198
+ text: await presetListText(`Preset: ${state.runPreset || "none"}. Use /preset <name> or /preset none.`),
199
+ });
200
+ return;
201
+ }
202
+ const normalized = normalizeOptionalSetting(value, ["none", "off", "clear"]);
203
+ if (normalized && !(await validatePresetName(normalized))) {
204
+ return;
205
+ }
206
+ dispatch({ type: "settings.set", settings: { runPreset: normalized } });
207
+ dispatch({ type: "activity.add", text: `Preset: ${normalized || "none"}` });
208
+ }
209
+ async function validatePresetName(preset) {
210
+ try {
211
+ if (await options.settingsController.validatePreset(options.profileName, preset))
212
+ return true;
213
+ dispatch({
214
+ type: "message.add",
215
+ role: "system",
216
+ text: await presetListText(`Unknown preset: ${preset}`),
217
+ });
218
+ dispatch({ type: "activity.add", level: "warning", text: `Unknown preset: ${preset}` });
219
+ return false;
220
+ }
221
+ catch (error) {
222
+ dispatch({ type: "message.add", role: "system", text: `Could not validate preset "${preset}": ${userFacingError(error)}` });
223
+ dispatch({ type: "activity.add", level: "error", text: "Preset catalog unavailable" });
224
+ return false;
225
+ }
226
+ }
227
+ async function presetListText(prefix) {
228
+ return options.settingsController.presetListText({
229
+ profileName: options.profileName,
230
+ currentPreset: options.engine.snapshot().runPreset,
231
+ prefix,
232
+ });
233
+ }
234
+ async function showAuthStatus() {
235
+ dispatch({ type: "activity.add", text: "Checking auth status" });
236
+ try {
237
+ dispatch({ type: "message.add", role: "system", text: await options.authController.statusText(options.profileName) });
238
+ dispatch({ type: "activity.add", level: "success", text: "Auth status ready" });
239
+ }
240
+ catch (error) {
241
+ dispatch({ type: "message.add", role: "system", text: userFacingError(error) });
242
+ dispatch({ type: "activity.add", level: "error", text: "Auth status failed" });
243
+ }
244
+ }
245
+ async function exportTranscript(effect) {
246
+ try {
247
+ const file = await options.conversationController.exportTranscript(effect);
248
+ dispatch({ type: "message.add", role: "system", text: `Transcript exported:\n${file}` });
249
+ dispatch({ type: "activity.add", level: "success", text: "Transcript exported" });
250
+ }
251
+ catch (error) {
252
+ dispatch({ type: "message.add", role: "system", text: `Transcript export failed: ${userFacingError(error)}` });
253
+ dispatch({ type: "activity.add", level: "error", text: "Transcript export failed" });
254
+ }
255
+ }
256
+ async function showSummary() {
257
+ if (!options.localController.isLoaded()) {
258
+ dispatch({ type: "message.add", role: "system", text: unavailableWorkdirText() });
259
+ return;
260
+ }
261
+ dispatch({ type: "activity.add", text: "Summarizing workdir" });
262
+ try {
263
+ dispatch({
264
+ type: "message.add",
265
+ role: "system",
266
+ text: await options.localController.summaryText(),
267
+ });
268
+ dispatch({ type: "activity.add", level: "success", text: "Workdir summary ready" });
269
+ }
270
+ catch (error) {
271
+ dispatch({
272
+ type: "activity.add",
273
+ level: "error",
274
+ text: userFacingError(error),
275
+ });
276
+ }
277
+ }
278
+ async function startNewConversation(name) {
279
+ const conversation = await options.conversationController.startNewConversation(name, options.options.profile);
280
+ dispatch({ type: "messages.clear" });
281
+ dispatch({ type: "conversation.set", name: conversation.name });
282
+ dispatch({
283
+ type: "message.add",
284
+ role: "system",
285
+ text: conversation.message,
286
+ });
287
+ }
288
+ function switchConversation(name) {
289
+ const conversation = options.conversationController.switchConversation(name);
290
+ dispatch({ type: "messages.clear" });
291
+ dispatch({ type: "conversation.set", name: conversation.name });
292
+ dispatch({
293
+ type: "message.add",
294
+ role: "system",
295
+ text: conversation.message,
296
+ });
297
+ }
298
+ async function showConversations() {
299
+ try {
300
+ dispatch({
301
+ type: "message.add",
302
+ role: "system",
303
+ text: await options.conversationController.listConversations(options.options.profile),
304
+ });
305
+ }
306
+ catch (error) {
307
+ dispatch({ type: "message.add", role: "system", text: userFacingError(error) });
308
+ }
309
+ }
310
+ async function searchWorkdir(query) {
311
+ if (!query) {
312
+ dispatch({ type: "message.add", role: "system", text: "Usage: /search <query>" });
313
+ return;
314
+ }
315
+ if (!options.localController.isLoaded()) {
316
+ dispatch({ type: "message.add", role: "system", text: unavailableWorkdirText() });
317
+ return;
318
+ }
319
+ dispatch({ type: "activity.add", text: `Searching workdir: ${query}` });
320
+ try {
321
+ const result = await options.localController.searchText(query);
322
+ dispatch({
323
+ type: "message.add",
324
+ role: "system",
325
+ text: result.text,
326
+ });
327
+ dispatch({
328
+ type: "activity.add",
329
+ level: "success",
330
+ text: `Search complete: ${result.count} matches`,
331
+ });
332
+ }
333
+ catch (error) {
334
+ dispatch({
335
+ type: "activity.add",
336
+ level: "error",
337
+ text: userFacingError(error),
338
+ });
339
+ }
340
+ }
341
+ function showEditPreview() {
342
+ const state = options.engine.snapshot();
343
+ if (state.pendingLocalTool) {
344
+ dispatch({ type: "message.add", role: "system", text: options.localController.approvalPreview(state.pendingLocalTool) });
345
+ return;
346
+ }
347
+ dispatch({ type: "message.add", role: "system", text: "No pending local action." });
348
+ }
349
+ async function applyPendingEdit(allowFutureLocalActions) {
350
+ const state = options.engine.snapshot();
351
+ if (!options.localController.isLoaded()) {
352
+ dispatch({ type: "message.add", role: "system", text: unavailableWorkdirText() });
353
+ return;
354
+ }
355
+ if (state.pendingLocalTool) {
356
+ dispatch({
357
+ type: "activity.add",
358
+ level: "warning",
359
+ text: `Applying local action: ${state.pendingLocalTool.name}${state.pendingLocalTool.action ? `.${state.pendingLocalTool.action}` : ""}`,
360
+ });
361
+ try {
362
+ const result = await options.localController.applyApproval(state.pendingLocalTool);
363
+ const nextAccessMode = allowFutureLocalActions ? "full" : state.accessMode;
364
+ if (allowFutureLocalActions) {
365
+ dispatch({ type: "access.set", mode: "full" });
366
+ }
367
+ dispatch({
368
+ type: "message.add",
369
+ role: "system",
370
+ text: [
371
+ allowFutureLocalActions
372
+ ? "Applied local action. Future local actions in this workbench conversation are now allowed."
373
+ : "Applied local action once. Future local actions still require approval.",
374
+ "Continuing agent turn with the local result.",
375
+ "Result:",
376
+ JSON.stringify(result, null, 2),
377
+ ].join("\n"),
378
+ });
379
+ dispatch({ type: "activity.add", level: "success", text: "Local action applied" });
380
+ const approval = state.pendingLocalTool;
381
+ dispatch({ type: "local_tool.pending.clear" });
382
+ await options.turnController.continueAfterLocalApproval({
383
+ approval,
384
+ result,
385
+ accessMode: nextAccessMode,
386
+ });
387
+ }
388
+ catch (error) {
389
+ dispatch({ type: "message.add", role: "system", text: userFacingError(error) });
390
+ dispatch({ type: "activity.add", level: "error", text: userFacingError(error) });
391
+ }
392
+ return;
393
+ }
394
+ dispatch({ type: "message.add", role: "system", text: "No pending local action." });
395
+ }
396
+ function rejectPendingEdit() {
397
+ const state = options.engine.snapshot();
398
+ if (state.pendingLocalTool) {
399
+ dispatch({
400
+ type: "activity.add",
401
+ text: `Rejected local action: ${state.pendingLocalTool.name}${state.pendingLocalTool.action ? `.${state.pendingLocalTool.action}` : ""}`,
402
+ });
403
+ dispatch({ type: "local_tool.pending.clear" });
404
+ return;
405
+ }
406
+ dispatch({ type: "message.add", role: "system", text: "No pending local action." });
407
+ }
408
+ function unavailableWorkdirText() {
409
+ const state = options.engine.snapshot();
410
+ if (!state.contextEnabled || state.accessMode === "off") {
411
+ return "Local workdir tools are off. Use /workdir on, /access approval, or /access full to load and expose the current workdir.";
412
+ }
413
+ return "Workdir is still loading.";
414
+ }
415
+ }
416
+ export function normalizeOptionalSetting(value, clearValues) {
417
+ const trimmed = value.trim();
418
+ if (!trimmed)
419
+ return undefined;
420
+ return clearValues.includes(trimmed.toLowerCase()) ? undefined : trimmed;
421
+ }
422
+ function userFacingError(error) {
423
+ if (error instanceof Error)
424
+ return error.message;
425
+ return String(error);
426
+ }
@@ -0,0 +1,32 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { deleteConversation, listConversations } from "../agent.js";
3
+ export interface WorkbenchConversationController {
4
+ startNewConversation(name: string | undefined, profileName?: string): Promise<{
5
+ name: string;
6
+ message: string;
7
+ }>;
8
+ switchConversation(name: string): {
9
+ name: string;
10
+ message: string;
11
+ };
12
+ listConversations(profileName?: string): Promise<string>;
13
+ exportTranscript(input: {
14
+ path?: string;
15
+ transcript: string;
16
+ conversation: string;
17
+ }): Promise<string>;
18
+ }
19
+ export interface WorkbenchConversationControllerOptions {
20
+ deleteConversationImpl?: typeof deleteConversation;
21
+ listConversationsImpl?: typeof listConversations;
22
+ mkdirImpl?: typeof mkdir;
23
+ writeFileImpl?: typeof writeFile;
24
+ now?: () => Date;
25
+ dataDir?: string;
26
+ }
27
+ export declare function createWorkbenchConversationController(options?: WorkbenchConversationControllerOptions): WorkbenchConversationController;
28
+ export declare function defaultTranscriptExportPath(conversation: string, options?: {
29
+ dataDir?: string;
30
+ now?: () => Date;
31
+ }): string;
32
+ export declare function createConversationName(now?: Date): string;
@@ -0,0 +1,53 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { conversationSummary, deleteConversation, listConversations, } from "../agent.js";
4
+ import { runtime } from "../runtime/index.js";
5
+ export function createWorkbenchConversationController(options = {}) {
6
+ const deleteConversationImpl = options.deleteConversationImpl ?? deleteConversation;
7
+ const listConversationsImpl = options.listConversationsImpl ?? listConversations;
8
+ const mkdirImpl = options.mkdirImpl ?? mkdir;
9
+ const writeFileImpl = options.writeFileImpl ?? writeFile;
10
+ const now = options.now ?? (() => new Date());
11
+ return {
12
+ async startNewConversation(name, profileName) {
13
+ const conversation = name || createConversationName(now());
14
+ await deleteConversationImpl(conversation, profileName);
15
+ return {
16
+ name: conversation,
17
+ message: `Started fresh conversation "${conversation}".`,
18
+ };
19
+ },
20
+ switchConversation(name) {
21
+ return {
22
+ name,
23
+ message: `Switched to conversation "${name}". Future turns will continue this handle when history exists.`,
24
+ };
25
+ },
26
+ async listConversations(profileName) {
27
+ const conversations = await listConversationsImpl(profileName);
28
+ return conversations.length === 0
29
+ ? "No saved conversations yet."
30
+ : conversations.map(conversationSummary).join("\n");
31
+ },
32
+ async exportTranscript(input) {
33
+ const file = input.path?.trim()
34
+ ? path.resolve(process.cwd(), input.path.trim())
35
+ : defaultTranscriptExportPath(input.conversation, {
36
+ dataDir: options.dataDir,
37
+ now,
38
+ });
39
+ await mkdirImpl(path.dirname(file), { recursive: true });
40
+ await writeFileImpl(file, input.transcript, "utf8");
41
+ return file;
42
+ },
43
+ };
44
+ }
45
+ export function defaultTranscriptExportPath(conversation, options = {}) {
46
+ const safeConversation = conversation.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "conversation";
47
+ const stamp = (options.now?.() ?? new Date()).toISOString().replace(/[:.]/g, "-");
48
+ return path.join(options.dataDir ?? runtime.dirs.data, "transcripts", `${safeConversation}-${stamp}.txt`);
49
+ }
50
+ export function createConversationName(now = new Date()) {
51
+ const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\..+$/, "").replace("T", "-");
52
+ return `thread-${stamp}`;
53
+ }
@@ -0,0 +1,66 @@
1
+ import { type RenderMode, type WorkbenchAction, type WorkbenchCommand, type WorkbenchState } from "./state.js";
2
+ import type { AgentTurnEvent, WorkdirAccessMode } from "../agent.js";
3
+ export interface WorkbenchEngineOptions {
4
+ contextEnabled: boolean;
5
+ accessMode?: WorkdirAccessMode;
6
+ conversation?: string;
7
+ preset?: string;
8
+ model?: string;
9
+ renderMode?: RenderMode;
10
+ defaultPreset?: string | null;
11
+ }
12
+ export interface WorkbenchEngine {
13
+ snapshot(): WorkbenchState;
14
+ subscribe(listener: () => void): () => void;
15
+ dispatch(action: WorkbenchAction): void;
16
+ submit(input: string): WorkbenchSubmission;
17
+ handleCommand(command: WorkbenchCommand): WorkbenchCommandResult;
18
+ handleAgentEvent(event: AgentTurnEvent): WorkbenchEventResult;
19
+ }
20
+ export type WorkbenchSubmission = {
21
+ kind: "command";
22
+ command: WorkbenchCommand;
23
+ } | {
24
+ kind: "prompt";
25
+ prompt: string;
26
+ } | {
27
+ kind: "handled";
28
+ };
29
+ export type WorkbenchEffect = {
30
+ type: "exit";
31
+ } | {
32
+ type: "login";
33
+ } | {
34
+ type: "logout";
35
+ } | {
36
+ type: "delete_profile";
37
+ } | {
38
+ type: "switch_profile";
39
+ name?: string;
40
+ } | {
41
+ type: "show_auth_status";
42
+ } | {
43
+ type: "export_transcript";
44
+ path?: string;
45
+ transcript: string;
46
+ conversation: string;
47
+ } | {
48
+ type: "clear_preset_tool_catalog_cache";
49
+ };
50
+ export type WorkbenchRuntimeEffect = {
51
+ type: "append_text_delta";
52
+ delta: string;
53
+ } | {
54
+ type: "set_active_response_id";
55
+ responseID: string;
56
+ } | {
57
+ type: "flush_text_delta_buffer";
58
+ };
59
+ export interface WorkbenchCommandResult {
60
+ handled: boolean;
61
+ effects: WorkbenchEffect[];
62
+ }
63
+ export interface WorkbenchEventResult {
64
+ effects: WorkbenchRuntimeEffect[];
65
+ }
66
+ export declare function createWorkbenchEngine(options: WorkbenchEngineOptions): WorkbenchEngine;