@oagi/oagi 0.1.3

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/dist/cli.cjs ADDED
@@ -0,0 +1,1927 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+ var __decorateClass = (decorators, target, key, kind) => {
26
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
27
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
28
+ if (decorator = decorators[i])
29
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
30
+ if (kind && result) __defProp(target, key, result);
31
+ return result;
32
+ };
33
+
34
+ // src/cli/main.ts
35
+ var import_commander = require("commander");
36
+
37
+ // src/types/models/action.ts
38
+ var z = __toESM(require("zod"), 1);
39
+ var ActionTypeSchema = z.enum([
40
+ "click",
41
+ "left_double",
42
+ "left_triple",
43
+ "right_single",
44
+ "drag",
45
+ "hotkey",
46
+ "type",
47
+ "scroll",
48
+ "finish",
49
+ "wait",
50
+ "call_user"
51
+ ]);
52
+ var ActionSchema = z.object({
53
+ /**
54
+ * Type of action to perform
55
+ */
56
+ type: ActionTypeSchema,
57
+ /**
58
+ * Action argument in the specified format
59
+ */
60
+ argument: z.string(),
61
+ /**
62
+ * Number of times to repeat the action
63
+ */
64
+ count: z.int().default(1)
65
+ });
66
+ var parseCoords = (args) => {
67
+ const match = /(\d+),\s*(\d+)/.exec(args);
68
+ if (!match) {
69
+ return null;
70
+ }
71
+ return [Number(match[1]), Number(match[2])];
72
+ };
73
+ var parseDragCoords = (args) => {
74
+ const match = /(\d+),\s*(\d+),\s*(\d+),\s*(\d+)/.exec(args);
75
+ if (!match) {
76
+ return null;
77
+ }
78
+ return [
79
+ Number(match[1]),
80
+ Number(match[2]),
81
+ Number(match[3]),
82
+ Number(match[4])
83
+ ];
84
+ };
85
+ var parseScroll = (args) => {
86
+ const match = /(\d+),\s*(\d+),\s*(\w+)/.exec(args);
87
+ if (!match) {
88
+ return null;
89
+ }
90
+ return [Number(match[1]), Number(match[2]), match[3].toLowerCase()];
91
+ };
92
+
93
+ // src/types/models/client.ts
94
+ var z2 = __toESM(require("zod"), 1);
95
+ var UsageSchema = z2.object({
96
+ prompt_tokens: z2.int(),
97
+ completion_tokens: z2.int(),
98
+ total_tokens: z2.int()
99
+ });
100
+ var ErrorDetailSchema = z2.object({
101
+ code: z2.string(),
102
+ message: z2.string()
103
+ });
104
+ var ErrorResponseSchema = z2.object({
105
+ error: ErrorDetailSchema.nullish()
106
+ });
107
+ var UploadFileResponseSchema = z2.object({
108
+ url: z2.string(),
109
+ uuid: z2.string(),
110
+ expires_at: z2.int(),
111
+ file_expires_at: z2.int(),
112
+ download_url: z2.string()
113
+ });
114
+ var GenerateResponseSchema = z2.object({
115
+ response: z2.string(),
116
+ prompt_tokens: z2.int(),
117
+ completion_tokens: z2.int(),
118
+ /**
119
+ * @deprecated This field is deprecated
120
+ */
121
+ cost: z2.float64().nullish(),
122
+ request_id: z2.string().nullish()
123
+ });
124
+
125
+ // src/types/models/image-config.ts
126
+ var z3 = __toESM(require("zod"), 1);
127
+ var ImageConfigSchema = z3.object({
128
+ format: z3.enum(["PNG", "JPEG"]).default("JPEG"),
129
+ quality: z3.int().min(1).max(100).default(85),
130
+ width: z3.int().positive().nullish().default(1260),
131
+ height: z3.int().positive().nullish().default(700),
132
+ optimize: z3.boolean().default(false),
133
+ resample: z3.enum(["NEAREST", "BILINEAR", "BICUBIC", "LANCZOS"]).default("LANCZOS")
134
+ }).transform((value) => {
135
+ if (value.format === "PNG") {
136
+ return { ...value, quality: 85 };
137
+ }
138
+ return value;
139
+ });
140
+
141
+ // src/types/step_observer.ts
142
+ var z4 = __toESM(require("zod"), 1);
143
+ var BaseEventSchema = z4.object({
144
+ timestamp: z4.date().default(() => /* @__PURE__ */ new Date())
145
+ });
146
+ var ImageEventSchema = BaseEventSchema.extend({
147
+ type: z4.literal("image"),
148
+ step_num: z4.number(),
149
+ image: z4.string()
150
+ });
151
+ var StepEventSchema = BaseEventSchema.extend({
152
+ type: z4.literal("step"),
153
+ step_num: z4.number(),
154
+ image: z4.custom(),
155
+ step: z4.custom(),
156
+ task_id: z4.string().optional()
157
+ });
158
+ var ActionEventSchema = BaseEventSchema.extend({
159
+ type: z4.literal("action"),
160
+ step_num: z4.number(),
161
+ actions: z4.array(z4.custom()),
162
+ error: z4.string().optional()
163
+ });
164
+ var LogEventSchema = BaseEventSchema.extend({
165
+ type: z4.literal("log"),
166
+ message: z4.string()
167
+ });
168
+ var SplitEventSchema = BaseEventSchema.extend({
169
+ type: z4.literal("split"),
170
+ label: z4.string().optional()
171
+ });
172
+ var PlanEventSchema = BaseEventSchema.extend({
173
+ type: z4.literal("plan"),
174
+ phase: z4.enum(["initial", "reflection", "summary"]),
175
+ image: z4.string().or(z4.custom()).optional(),
176
+ reasoning: z4.string(),
177
+ result: z4.string().optional(),
178
+ request_id: z4.string().optional()
179
+ });
180
+ var StepObserver = class {
181
+ chain(observer) {
182
+ return new ChainedStepObserver([this, observer ?? null]);
183
+ }
184
+ };
185
+ var ChainedStepObserver = class extends StepObserver {
186
+ observers;
187
+ constructor(observers) {
188
+ super();
189
+ this.observers = observers;
190
+ }
191
+ async onEvent(event) {
192
+ return await this.observers.reduce(async (prev, observer) => {
193
+ await prev;
194
+ if (observer) await observer.onEvent(event);
195
+ }, Promise.resolve());
196
+ }
197
+ };
198
+
199
+ // src/agent/observer/exporters.ts
200
+ var import_node_fs = __toESM(require("fs"), 1);
201
+ var import_node_path = __toESM(require("path"), 1);
202
+ var import_node_url = require("url");
203
+ var import_meta = {};
204
+ var ensureDir = (dirPath) => {
205
+ import_node_fs.default.mkdirSync(dirPath, { recursive: true });
206
+ };
207
+ var parseActionCoords = (action) => {
208
+ const arg = action.argument.replace(/^\(|\)$/g, "");
209
+ switch (action.type) {
210
+ case "click":
211
+ case "left_double":
212
+ case "left_triple":
213
+ case "right_single": {
214
+ const coords = parseCoords(arg);
215
+ if (coords) {
216
+ return { type: "click", x: coords[0], y: coords[1] };
217
+ }
218
+ return null;
219
+ }
220
+ case "drag": {
221
+ const coords = parseDragCoords(arg);
222
+ if (coords) {
223
+ return {
224
+ type: "drag",
225
+ x1: coords[0],
226
+ y1: coords[1],
227
+ x2: coords[2],
228
+ y2: coords[3]
229
+ };
230
+ }
231
+ return null;
232
+ }
233
+ case "scroll": {
234
+ const result = parseScroll(arg);
235
+ if (result) {
236
+ return {
237
+ type: "scroll",
238
+ x: result[0],
239
+ y: result[1],
240
+ direction: result[2]
241
+ };
242
+ }
243
+ return null;
244
+ }
245
+ default:
246
+ return null;
247
+ }
248
+ };
249
+ var exportToMarkdown = (events, filePath, imagesDir) => {
250
+ const outputDir = import_node_path.default.dirname(filePath);
251
+ ensureDir(outputDir);
252
+ if (imagesDir) {
253
+ ensureDir(imagesDir);
254
+ }
255
+ const lines = ["# Agent Execution Report\n"];
256
+ for (const event of events) {
257
+ const d = event.timestamp instanceof Date ? event.timestamp : new Date(event.timestamp);
258
+ const timestamp = d.toTimeString().slice(0, 8);
259
+ switch (event.type) {
260
+ case "step":
261
+ lines.push(`
262
+ ## Step ${event.step_num}
263
+ `);
264
+ lines.push(`**Time:** ${timestamp}
265
+ `);
266
+ if (event.task_id) {
267
+ lines.push(`**Task ID:** \`${event.task_id}\`
268
+ `);
269
+ }
270
+ if (typeof event.image !== "string") {
271
+ if (imagesDir) {
272
+ const imageFilename = `step_${event.step_num}.png`;
273
+ const imagePath = import_node_path.default.join(imagesDir, imageFilename);
274
+ import_node_fs.default.writeFileSync(imagePath, Buffer.from(event.image));
275
+ const relPath = import_node_path.default.join(import_node_path.default.basename(imagesDir), imageFilename);
276
+ lines.push(`
277
+ ![Step ${event.step_num}](${relPath})
278
+ `);
279
+ } else {
280
+ lines.push(
281
+ `
282
+ *[Screenshot captured - ${event.image.byteLength} bytes]*
283
+ `
284
+ );
285
+ }
286
+ } else {
287
+ lines.push(`
288
+ **Screenshot URL:** ${event.image}
289
+ `);
290
+ }
291
+ if (event.step.reason) {
292
+ lines.push(`
293
+ **Reasoning:**
294
+ > ${event.step.reason}
295
+ `);
296
+ }
297
+ if (event.step.actions?.length) {
298
+ lines.push("\n**Planned Actions:**\n");
299
+ for (const action of event.step.actions) {
300
+ const countStr = action.count && action.count > 1 ? ` (x${action.count})` : "";
301
+ lines.push(`- \`${action.type}\`: ${action.argument}${countStr}
302
+ `);
303
+ }
304
+ }
305
+ if (event.step.stop) {
306
+ lines.push("\n**Status:** Task Complete\n");
307
+ }
308
+ break;
309
+ case "action":
310
+ lines.push(`
311
+ ### Actions Executed (${timestamp})
312
+ `);
313
+ if (event.error) {
314
+ lines.push(`
315
+ **Error:** ${event.error}
316
+ `);
317
+ } else {
318
+ lines.push("\n**Result:** Success\n");
319
+ }
320
+ break;
321
+ case "log":
322
+ lines.push(`
323
+ > **Log (${timestamp}):** ${event.message}
324
+ `);
325
+ break;
326
+ case "split":
327
+ if (event.label) {
328
+ lines.push(`
329
+ ---
330
+
331
+ ### ${event.label}
332
+ `);
333
+ } else {
334
+ lines.push("\n---\n");
335
+ }
336
+ break;
337
+ case "image":
338
+ break;
339
+ case "plan": {
340
+ const phaseTitles = {
341
+ initial: "Initial Planning",
342
+ reflection: "Reflection",
343
+ summary: "Summary"
344
+ };
345
+ const phaseTitle = phaseTitles[event.phase] ?? event.phase;
346
+ lines.push(`
347
+ ### ${phaseTitle} (${timestamp})
348
+ `);
349
+ if (event.request_id) {
350
+ lines.push(`**Request ID:** \`${event.request_id}\`
351
+ `);
352
+ }
353
+ if (event.image) {
354
+ if (typeof event.image !== "string") {
355
+ if (imagesDir) {
356
+ const imageFilename = `plan_${event.phase}_${Date.now()}.png`;
357
+ const imagePath = import_node_path.default.join(imagesDir, imageFilename);
358
+ import_node_fs.default.writeFileSync(imagePath, Buffer.from(event.image));
359
+ const relPath = import_node_path.default.join(
360
+ import_node_path.default.basename(imagesDir),
361
+ imageFilename
362
+ );
363
+ lines.push(`
364
+ ![${phaseTitle}](${relPath})
365
+ `);
366
+ } else {
367
+ lines.push(
368
+ `
369
+ *[Screenshot captured - ${event.image.byteLength} bytes]*
370
+ `
371
+ );
372
+ }
373
+ } else {
374
+ lines.push(`
375
+ **Screenshot URL:** ${event.image}
376
+ `);
377
+ }
378
+ }
379
+ if (event.reasoning) {
380
+ lines.push(`
381
+ **Reasoning:**
382
+ > ${event.reasoning}
383
+ `);
384
+ }
385
+ if (event.result) {
386
+ lines.push(`
387
+ **Result:** ${event.result}
388
+ `);
389
+ }
390
+ break;
391
+ }
392
+ }
393
+ }
394
+ import_node_fs.default.writeFileSync(filePath, lines.join(""), "utf-8");
395
+ };
396
+ var convertEventsForHtml = (events) => {
397
+ const result = [];
398
+ for (const event of events) {
399
+ const d = event.timestamp instanceof Date ? event.timestamp : new Date(event.timestamp);
400
+ const timestamp = d.toTimeString().slice(0, 8);
401
+ switch (event.type) {
402
+ case "step": {
403
+ const action_coords = [];
404
+ const actions = [];
405
+ if (event.step.actions?.length) {
406
+ for (const action of event.step.actions) {
407
+ const coords = parseActionCoords(action);
408
+ if (coords) {
409
+ action_coords.push(coords);
410
+ }
411
+ actions.push({
412
+ type: action.type,
413
+ argument: action.argument,
414
+ count: action.count ?? 1
415
+ });
416
+ }
417
+ }
418
+ let image = null;
419
+ if (typeof event.image !== "string") {
420
+ image = Buffer.from(event.image).toString("base64");
421
+ } else {
422
+ image = event.image;
423
+ }
424
+ result.push({
425
+ event_type: "step",
426
+ timestamp,
427
+ step_num: event.step_num,
428
+ image,
429
+ action_coords,
430
+ reason: event.step.reason,
431
+ actions,
432
+ stop: event.step.stop,
433
+ task_id: event.task_id
434
+ });
435
+ break;
436
+ }
437
+ case "action":
438
+ result.push({
439
+ event_type: "action",
440
+ timestamp,
441
+ error: event.error ?? null
442
+ });
443
+ break;
444
+ case "log":
445
+ result.push({ event_type: "log", timestamp, message: event.message });
446
+ break;
447
+ case "split":
448
+ result.push({ event_type: "split", timestamp, label: event.label });
449
+ break;
450
+ case "image":
451
+ break;
452
+ case "plan": {
453
+ let image = null;
454
+ if (event.image) {
455
+ if (typeof event.image !== "string") {
456
+ image = Buffer.from(event.image).toString("base64");
457
+ } else {
458
+ image = event.image;
459
+ }
460
+ }
461
+ result.push({
462
+ event_type: "plan",
463
+ timestamp,
464
+ phase: event.phase,
465
+ image,
466
+ reasoning: event.reasoning,
467
+ result: event.result ?? null,
468
+ request_id: event.request_id ?? null
469
+ });
470
+ break;
471
+ }
472
+ }
473
+ }
474
+ return result;
475
+ };
476
+ var exportToHtml = (events, filePath) => {
477
+ const outputDir = import_node_path.default.dirname(filePath);
478
+ ensureDir(outputDir);
479
+ const moduleUrl = import_meta?.url ? import_meta.url : (0, import_node_url.pathToFileURL)(__filename).href;
480
+ const moduleDir = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(moduleUrl));
481
+ const templatePath = import_node_path.default.join(moduleDir, "report_template.html");
482
+ const template = import_node_fs.default.readFileSync(templatePath, "utf-8");
483
+ const eventsData = convertEventsForHtml(events);
484
+ const eventsJson = JSON.stringify(eventsData);
485
+ const htmlContent = template.replace("{EVENTS_DATA}", eventsJson);
486
+ import_node_fs.default.writeFileSync(filePath, htmlContent, "utf-8");
487
+ };
488
+ var exportToJson = (events, filePath) => {
489
+ const outputDir = import_node_path.default.dirname(filePath);
490
+ ensureDir(outputDir);
491
+ const jsonEvents = events.map((event) => {
492
+ const timestamp = event.timestamp instanceof Date ? event.timestamp.toISOString() : new Date(event.timestamp).toISOString();
493
+ if ("image" in event && event.image instanceof ArrayBuffer) {
494
+ return {
495
+ ...event,
496
+ timestamp,
497
+ image: Buffer.from(event.image).toString("base64"),
498
+ image_encoding: "base64"
499
+ };
500
+ }
501
+ return {
502
+ ...event,
503
+ timestamp
504
+ };
505
+ });
506
+ import_node_fs.default.writeFileSync(filePath, JSON.stringify(jsonEvents, null, 2), "utf-8");
507
+ };
508
+
509
+ // src/agent/observer/agent_observer.ts
510
+ var AsyncAgentObserver = class extends StepObserver {
511
+ /**
512
+ * Records agent execution events and exports to various formats.
513
+ *
514
+ * This class implements the AsyncObserver protocol and provides
515
+ * functionality for recording events during agent execution and
516
+ * exporting them to Markdown or HTML formats.
517
+ */
518
+ events = [];
519
+ async onEvent(event) {
520
+ this.events.push(event);
521
+ }
522
+ addLog(message) {
523
+ const event = {
524
+ type: "log",
525
+ timestamp: /* @__PURE__ */ new Date(),
526
+ message
527
+ };
528
+ this.events.push(event);
529
+ }
530
+ addSplit(label = "") {
531
+ const event = {
532
+ type: "split",
533
+ timestamp: /* @__PURE__ */ new Date(),
534
+ label
535
+ };
536
+ this.events.push(event);
537
+ }
538
+ clear() {
539
+ this.events = [];
540
+ }
541
+ getEventsByStep(step_num) {
542
+ return this.events.filter(
543
+ (event) => event.step_num !== void 0 && event.step_num === step_num
544
+ );
545
+ }
546
+ export(format, path2, images_dir) {
547
+ const normalized = typeof format === "string" ? format.toLowerCase() : format;
548
+ switch (normalized) {
549
+ case "markdown" /* MARKDOWN */:
550
+ exportToMarkdown(this.events, path2, images_dir ?? void 0);
551
+ return;
552
+ case "html" /* HTML */:
553
+ exportToHtml(this.events, path2);
554
+ return;
555
+ case "json" /* JSON */:
556
+ exportToJson(this.events, path2);
557
+ return;
558
+ default:
559
+ throw new Error(`Unknown export format: ${String(format)}`);
560
+ }
561
+ }
562
+ };
563
+
564
+ // src/consts.ts
565
+ var DEFAULT_BASE_URL = "https://api.agiopen.org";
566
+ var API_KEY_HELP_URL = "https://developer.agiopen.org/api-keys";
567
+ var API_V1_FILE_UPLOAD_ENDPOINT = "/v1/file/upload";
568
+ var API_V1_GENERATE_ENDPOINT = "/v1/generate";
569
+ var MODEL_ACTOR = "lux-actor-1";
570
+ var MODEL_THINKER = "lux-thinker-1";
571
+ var MODE_ACTOR = "actor";
572
+ var DEFAULT_MAX_STEPS = 20;
573
+ var DEFAULT_MAX_STEPS_THINKER = 100;
574
+ var MAX_STEPS_ACTOR = 30;
575
+ var MAX_STEPS_THINKER = 120;
576
+ var DEFAULT_STEP_DELAY = 0.3;
577
+ var DEFAULT_TEMPERATURE = 0.5;
578
+ var DEFAULT_TEMPERATURE_LOW = 0.1;
579
+ var HTTP_CLIENT_TIMEOUT = 60;
580
+ var DEFAULT_MAX_RETRIES = 2;
581
+
582
+ // src/actor.ts
583
+ var import_crypto = require("crypto");
584
+
585
+ // src/client.ts
586
+ var import_openai = __toESM(require("openai"), 1);
587
+
588
+ // src/errors.ts
589
+ var OAGIError = class extends Error {
590
+ };
591
+ var APIError = class extends OAGIError {
592
+ constructor(response, message) {
593
+ super(message ?? response.statusText);
594
+ this.response = response;
595
+ }
596
+ toString() {
597
+ return `API Error [${this.response.status}]: ${this.message}`;
598
+ }
599
+ };
600
+ var AuthenticationError = class extends APIError {
601
+ };
602
+ var RateLimitError = class extends APIError {
603
+ };
604
+ var ValidationError = class extends APIError {
605
+ };
606
+ var NotFoundError = class extends APIError {
607
+ };
608
+ var ServerError = class extends APIError {
609
+ };
610
+ var ConfigurationError = class extends OAGIError {
611
+ };
612
+ var NetworkError = class extends OAGIError {
613
+ constructor(message, originalError) {
614
+ super(message);
615
+ this.originalError = originalError;
616
+ }
617
+ };
618
+ var RequestTimeoutError = class extends NetworkError {
619
+ };
620
+ var ValueError = class extends OAGIError {
621
+ };
622
+
623
+ // src/logger.ts
624
+ var import_pino = __toESM(require("pino"), 1);
625
+ var levelEnv = process.env.OAGI_LOG?.toLowerCase() ?? "info";
626
+ var allowedLevels = ["debug", "info", "warn", "error", "fatal"];
627
+ var logger = (0, import_pino.default)({
628
+ level: allowedLevels.includes(levelEnv) ? levelEnv : "info",
629
+ base: null,
630
+ timestamp: () => `,"time":"${(/* @__PURE__ */ new Date()).toISOString()}"`,
631
+ messageKey: "msg",
632
+ transport: {
633
+ target: "pino-pretty",
634
+ options: {
635
+ colorize: false,
636
+ translateTime: "SYS:yyyy-mm-dd HH:MM:ss",
637
+ messageFormat: "{msg}",
638
+ ignore: "pid,hostname"
639
+ }
640
+ }
641
+ });
642
+ var getLogger = (name) => logger.child({ name: `oagi.${name}` });
643
+ var logger_default = getLogger;
644
+ var logTraceOnFailure = (_, __, descriptor) => {
645
+ const original = descriptor.value;
646
+ descriptor.value = async function(...args) {
647
+ try {
648
+ return await original.apply(this, args);
649
+ } catch (err) {
650
+ if (err instanceof APIError) {
651
+ const requestId = err.response.headers.get("x-request-id") ?? "";
652
+ const traceId = err.response.headers.get("x-trace-id") ?? "";
653
+ logger.error(`Request Id: ${requestId}`);
654
+ logger.error(`Trace Id: ${traceId}`);
655
+ }
656
+ throw err;
657
+ }
658
+ };
659
+ return descriptor;
660
+ };
661
+
662
+ // src/utils/output-parser.ts
663
+ var splitActions = (actionBlock) => {
664
+ const actions = [];
665
+ let currentAction = [];
666
+ let parenLevel = 0;
667
+ for (const char of actionBlock) {
668
+ currentAction.push(char);
669
+ switch (char) {
670
+ case "(":
671
+ parenLevel++;
672
+ break;
673
+ case ")":
674
+ parenLevel--;
675
+ break;
676
+ case "&":
677
+ if (parenLevel === 0) {
678
+ const action = currentAction.join("").trim();
679
+ action && actions.push(action);
680
+ currentAction = [];
681
+ }
682
+ break;
683
+ }
684
+ }
685
+ const lastAction = currentAction.join("").trim();
686
+ lastAction && actions.push(lastAction);
687
+ return actions;
688
+ };
689
+ var parseAction = (action) => {
690
+ const match = /(\w+)\((.*)\)/.exec(action);
691
+ if (!match) return null;
692
+ const { data: actionType, success } = ActionTypeSchema.safeParse(match[1]);
693
+ if (!success) return null;
694
+ let argument = match[2].trim();
695
+ const args = argument.split(",");
696
+ let count = 1;
697
+ switch (actionType) {
698
+ // hotkey(key, c) - press key c times
699
+ case "hotkey":
700
+ if (args.length >= 2 && args[1].trim()) {
701
+ argument = args[0].trim();
702
+ count = Number(args[1].trim());
703
+ }
704
+ break;
705
+ case "scroll":
706
+ if (args.length >= 4) {
707
+ const x = args[0].trim();
708
+ const y = args[1].trim();
709
+ const direction = args[2].trim();
710
+ argument = `${x},${y},${direction}`;
711
+ count = Number(args[3].trim());
712
+ }
713
+ break;
714
+ default:
715
+ }
716
+ if (!Number.isInteger(count) || count <= 0) {
717
+ count = 1;
718
+ }
719
+ return { type: actionType, argument, count };
720
+ };
721
+ var parseRawOutput = (rawOutput) => {
722
+ const reason = /<\|think_start\|>(.*?)<\|think_end\|>/s.exec(rawOutput)?.[1] ?? "";
723
+ const action = /<\|action_start\|>(.*?)<\|action_end\|>/s.exec(rawOutput)?.[1] ?? "";
724
+ const actions = splitActions(action).map(parseAction).filter((action2) => !!action2);
725
+ return {
726
+ reason,
727
+ actions,
728
+ stop: actions.some((action2) => action2.type === "finish")
729
+ };
730
+ };
731
+
732
+ // src/utils/prompt-builder.ts
733
+ var buildPrompt = (taskDescription) => `You are a Desktop Agent completing computer use tasks from a user instruction.
734
+
735
+ Every step, you will look at the screenshot and output the desired actions in a format as:
736
+
737
+ <|think_start|> brief description of your intent and reasoning <|think_end|>
738
+ <|action_start|> one of the allowed actions as below <|action_end|>
739
+
740
+ In the action field, you have the following action formats:
741
+ 1. click(x, y) # left-click at the position (x, y), where x and y are integers normalized between 0 and 1000
742
+ 2. left_double(x, y) # left-double-click at the position (x, y), where x and y are integers normalized between 0 and 1000
743
+ 3. left_triple(x, y) # left-triple-click at the position (x, y), where x and y are integers normalized between 0 and 1000
744
+ 4. right_single(x, y) # right-click at the position (x, y), where x and y are integers normalized between 0 and 1000
745
+ 5. drag(x1, y1, x2, y2) # drag the mouse from (x1, y1) to (x2, y2) to select or move contents, where x1, y1, x2, y2 are integers normalized between 0 and 1000
746
+ 6. hotkey(key, c) # press the key for c times
747
+ 7. type(text) # type a text string on the keyboard
748
+ 8. scroll(x, y, direction, c) # scroll the mouse at position (x, y) in the direction of up or down for c times, where x and y are integers normalized between 0 and 1000
749
+ 9. wait() # wait for a while
750
+ 10. finish() # indicate the task is finished
751
+
752
+ Directly output the text beginning with <|think_start|>, no additional text is needed for this scenario.
753
+
754
+ The user instruction is:
755
+ ${taskDescription}
756
+ `;
757
+
758
+ // src/client.ts
759
+ var logger2 = logger_default("client");
760
+ var _Client = class _Client {
761
+ constructor(baseUrl = process.env.OAGI_BASE_URL ?? DEFAULT_BASE_URL, apiKey = process.env.OAGI_API_KEY ?? null, maxRetries = DEFAULT_MAX_RETRIES) {
762
+ this.baseUrl = baseUrl;
763
+ this.apiKey = apiKey;
764
+ if (!apiKey) {
765
+ throw new ConfigurationError(
766
+ `OAGI API key must be provided either as 'api_key' parameter or OAGI_API_KEY environment variable. Get your API key at ${API_KEY_HELP_URL}`
767
+ );
768
+ }
769
+ this.client = new import_openai.default({
770
+ baseURL: new URL("./v1", baseUrl).href,
771
+ apiKey,
772
+ maxRetries
773
+ });
774
+ logger2.info(`Client initialized with base_url: ${baseUrl}`);
775
+ }
776
+ timeout = HTTP_CLIENT_TIMEOUT;
777
+ client;
778
+ fetch(input, init) {
779
+ if (typeof input === "string" || input instanceof URL) {
780
+ input = new URL(input, this.baseUrl);
781
+ } else {
782
+ input = new URL(input.url, this.baseUrl);
783
+ }
784
+ init ??= {};
785
+ const signal = AbortSignal.timeout(this.timeout * 1e3);
786
+ init.signal = init.signal ? AbortSignal.any([signal, init.signal]) : signal;
787
+ return fetch(input, init);
788
+ }
789
+ buildHeaders(apiVersion) {
790
+ const headers = {};
791
+ if (apiVersion) {
792
+ headers["x-api-version"] = apiVersion;
793
+ }
794
+ if (this.apiKey) {
795
+ headers["x-api-key"] = this.apiKey;
796
+ }
797
+ return headers;
798
+ }
799
+ async handleResponseError(response) {
800
+ const data = await response.json();
801
+ const cls = _Client.getErrorClass(response.status);
802
+ const err = new cls(response, data.error?.message);
803
+ logger2.error(err.toString());
804
+ throw err;
805
+ }
806
+ handleHttpErrors(err) {
807
+ if (err instanceof DOMException) {
808
+ if (err.name === "TimeoutError") {
809
+ const message = `Request timed out after ${this.timeout} seconds`;
810
+ logger2.error(message);
811
+ throw new RequestTimeoutError(message, err);
812
+ }
813
+ } else if (err instanceof TypeError) {
814
+ const message = `Network error: ${err}`;
815
+ logger2.error(message);
816
+ throw new NetworkError(message, err);
817
+ }
818
+ throw err;
819
+ }
820
+ static getErrorClass(statusCode) {
821
+ if (statusCode >= 500) return ServerError;
822
+ return {
823
+ 401: AuthenticationError,
824
+ 404: NotFoundError,
825
+ 422: ValidationError,
826
+ 429: RateLimitError
827
+ }[statusCode] ?? APIError;
828
+ }
829
+ /**
830
+ * Call OpenAI-compatible /v1/chat/completions endpoint.
831
+ *
832
+ * @param model Model to use for inference
833
+ * @param messages Full message history (OpenAI-compatible format)
834
+ * @param temperature Sampling temperature (0.0-2.0)
835
+ * @param taskId Optional task ID for multi-turn conversations
836
+ * @returns Tuple of (Step, raw_output, Usage)
837
+ * - Step: Parsed actions and reasoning
838
+ * - raw_output: Raw model output string (for message history)
839
+ * - Usage: Token usage statistics (or None if not available)
840
+ */
841
+ async chatCompletions(model, messages, temperature, taskId) {
842
+ logger2.info(`Making async chat completion request with model: ${model}`);
843
+ const response = await this.client.chat.completions.create({
844
+ model,
845
+ messages,
846
+ temperature,
847
+ // @ts-expect-error extra body
848
+ task_id: taskId
849
+ });
850
+ const rawOutput = response.choices[0].message.content ?? "";
851
+ const step = parseRawOutput(rawOutput);
852
+ taskId = response.task_id;
853
+ const task = taskId ? `task_id: ${taskId}, ` : "";
854
+ const usage = response.usage ? `, tokens: ${response.usage.prompt_tokens}+${response.usage.completion_tokens}` : "";
855
+ logger2.info(
856
+ `Chat completion successful - ${task}actions: ${step.actions.length}, stop: ${step.stop}${usage}`
857
+ );
858
+ return [step, rawOutput, response.usage];
859
+ }
860
+ /**
861
+ * Call the /v1/file/upload endpoint to get a S3 presigned URL
862
+ *
863
+ * @param apiVersion API version header
864
+ * @returns {Promise<UploadFileResponse>} The response from /v1/file/upload with uuid and presigned S3 URL
865
+ */
866
+ async getS3PresignedUrl(apiVersion) {
867
+ logger2.debug(`Making async API request to ${API_V1_FILE_UPLOAD_ENDPOINT}`);
868
+ try {
869
+ const headers = this.buildHeaders(apiVersion);
870
+ const response = await this.fetch(API_V1_FILE_UPLOAD_ENDPOINT, {
871
+ headers
872
+ });
873
+ if (!response.ok) {
874
+ await this.handleResponseError(response);
875
+ }
876
+ try {
877
+ const uploadFileResponse = UploadFileResponseSchema.parse(
878
+ await response.json()
879
+ );
880
+ logger2.debug("Calling /v1/file/upload successful");
881
+ return uploadFileResponse;
882
+ } catch (err) {
883
+ logger2.error(`Invalid upload response: ${response.status}`);
884
+ throw new APIError(
885
+ response,
886
+ `Invalid presigned S3 URL response: ${err}`
887
+ );
888
+ }
889
+ } catch (err) {
890
+ this.handleHttpErrors(err);
891
+ }
892
+ }
893
+ /**
894
+ * Upload image bytes to S3 using presigned URL
895
+ *
896
+ * @param url S3 presigned URL
897
+ * @param content Image bytes to upload
898
+ * @throws {APIError} If upload fails
899
+ */
900
+ async uploadToS3(url, content) {
901
+ logger2.debug("Uploading image to S3");
902
+ let response = null;
903
+ try {
904
+ response = await this.fetch(url, {
905
+ body: content,
906
+ method: "PUT"
907
+ });
908
+ if (!response.ok) {
909
+ await this.handleResponseError(response);
910
+ }
911
+ } catch (err) {
912
+ logger2.error(`S3 upload failed ${err}`);
913
+ if (err instanceof APIError) {
914
+ throw err;
915
+ }
916
+ throw new APIError(
917
+ response ?? new Response(null, { status: 500 }),
918
+ `${err}`
919
+ );
920
+ }
921
+ }
922
+ /**
923
+ * Get S3 presigned URL and upload image (convenience method)
924
+ *
925
+ * @param screenshot Screenshot image bytes
926
+ * @param apiVersion API version header
927
+ * @returns {UploadFileResponse} The response from /v1/file/upload with uuid and presigned S3 URL
928
+ */
929
+ async putS3PresignedUrl(screenshot, apiVersion) {
930
+ const uploadFileResponse = await this.getS3PresignedUrl(apiVersion);
931
+ await this.uploadToS3(uploadFileResponse.url, screenshot);
932
+ return uploadFileResponse;
933
+ }
934
+ async callWorker({
935
+ workerId,
936
+ overallTodo,
937
+ taskDescription,
938
+ todos,
939
+ history = [],
940
+ currentTodoIndex,
941
+ taskExecutionSummary,
942
+ currentScreenshot,
943
+ currentSubtaskInstruction,
944
+ windowSteps,
945
+ windowScreenshots,
946
+ resultScreenshot,
947
+ priorNotes,
948
+ latestTodoSummary,
949
+ apiVersion
950
+ }) {
951
+ const validWorkers = ["oagi_first", "oagi_follow", "oagi_task_summary"];
952
+ if (!validWorkers.includes(workerId)) {
953
+ throw new ValueError(
954
+ `Invalid worker_id '${workerId}'. Must be one of: ${validWorkers}`
955
+ );
956
+ }
957
+ logger2.info(`Calling /v1/generate with worker_id: ${workerId}`);
958
+ const payload = {
959
+ external_worker_id: workerId,
960
+ overall_todo: overallTodo,
961
+ task_description: taskDescription,
962
+ todos,
963
+ history,
964
+ // Add optional memory fields
965
+ current_todo_index: currentTodoIndex,
966
+ task_execution_summary: taskExecutionSummary,
967
+ // Add optional screenshot/worker-specific fields
968
+ current_screenshot: currentScreenshot,
969
+ current_subtask_instruction: currentSubtaskInstruction,
970
+ window_steps: windowSteps,
971
+ window_screenshots: windowScreenshots,
972
+ result_screenshot: resultScreenshot,
973
+ prior_notes: priorNotes,
974
+ latest_todo_summary: latestTodoSummary
975
+ };
976
+ const headers = this.buildHeaders(apiVersion);
977
+ try {
978
+ const response = await this.fetch(API_V1_GENERATE_ENDPOINT, {
979
+ body: JSON.stringify(payload),
980
+ headers,
981
+ method: "POST"
982
+ });
983
+ if (!response.ok) {
984
+ await this.handleResponseError(response);
985
+ }
986
+ const result = GenerateResponseSchema.parse(await response.json());
987
+ result.request_id = response.headers.get("X-Request-ID");
988
+ logger2.info(
989
+ `Generate request successful - tokens: ${result.prompt_tokens}+${result.completion_tokens}, request_id: ${result.request_id}`
990
+ );
991
+ return result;
992
+ } catch (err) {
993
+ this.handleHttpErrors(err);
994
+ }
995
+ }
996
+ };
997
+ __decorateClass([
998
+ logTraceOnFailure
999
+ ], _Client.prototype, "callWorker", 1);
1000
+ var Client = _Client;
1001
+
1002
+ // src/actor.ts
1003
+ var logger3 = logger_default("task");
1004
+ var Actor = class {
1005
+ constructor(apiKey, baseUrl, model = MODEL_ACTOR, temperature) {
1006
+ this.model = model;
1007
+ this.temperature = temperature;
1008
+ this.client = new Client(baseUrl, apiKey);
1009
+ }
1010
+ /**
1011
+ * Client-side generated UUID
1012
+ */
1013
+ taskId = (0, import_crypto.randomUUID)();
1014
+ taskDescription = null;
1015
+ /**
1016
+ * OpenAI-compatible message history
1017
+ */
1018
+ messageHistory = [];
1019
+ maxSteps = DEFAULT_MAX_STEPS;
1020
+ /**
1021
+ * Current step counter
1022
+ */
1023
+ currentStep = 0;
1024
+ client;
1025
+ validateAndIncrementStep() {
1026
+ if (!this.taskDescription) {
1027
+ throw new ValueError(
1028
+ "Task description must be set. Call initTask() first."
1029
+ );
1030
+ }
1031
+ if (this.currentStep >= this.maxSteps) {
1032
+ throw new ValueError(
1033
+ `Max steps limit (${this.maxSteps}) reached. Call initTask() to start a new task.`
1034
+ );
1035
+ }
1036
+ this.currentStep++;
1037
+ }
1038
+ /**
1039
+ * Get screenshot URL, uploading to S3 if needed (async version).
1040
+ * @param screenshot Screenshot as URL string, or raw bytes
1041
+ * @returns Screenshot URL (either direct or from S3 upload)
1042
+ */
1043
+ async ensureScreenshotUrl(screenshot) {
1044
+ if (typeof screenshot === "string") return screenshot;
1045
+ const uploadResponse = await this.client.putS3PresignedUrl(screenshot);
1046
+ return uploadResponse.download_url;
1047
+ }
1048
+ /**
1049
+ * Add user message with screenshot to message history.
1050
+ *
1051
+ * @param screenshot URL of the screenshot
1052
+ * @param prompt Optional prompt text (for first message only)
1053
+ */
1054
+ addUserMessageToHistory(screenshot, prompt) {
1055
+ const content = [];
1056
+ if (prompt) {
1057
+ content.push({
1058
+ type: "text",
1059
+ text: prompt
1060
+ });
1061
+ }
1062
+ content.push({
1063
+ type: "image_url",
1064
+ image_url: {
1065
+ url: screenshot
1066
+ }
1067
+ });
1068
+ this.messageHistory.push({ role: "user", content });
1069
+ }
1070
+ /**
1071
+ * Build prompt for first message only.
1072
+ */
1073
+ buildStepPrompt() {
1074
+ if (this.messageHistory.length === 0) {
1075
+ return buildPrompt(this.taskDescription);
1076
+ }
1077
+ }
1078
+ /**
1079
+ * Initialize a new task with the given description.
1080
+ *
1081
+ * @param taskDescription Task description
1082
+ * @param maxSteps Maximum number of steps allowed
1083
+ */
1084
+ initTask(taskDescription, maxSteps = DEFAULT_MAX_STEPS) {
1085
+ this.taskId = (0, import_crypto.randomUUID)();
1086
+ this.taskDescription = taskDescription;
1087
+ this.messageHistory = [];
1088
+ const limit = this.model == MODEL_THINKER ? MAX_STEPS_THINKER : MAX_STEPS_ACTOR;
1089
+ if (maxSteps > limit) {
1090
+ logger3.warn(
1091
+ `max_steps (${maxSteps}) exceeds limit for model '${this.model}'. Capping to ${limit}.`
1092
+ );
1093
+ maxSteps = limit;
1094
+ }
1095
+ this.maxSteps = maxSteps;
1096
+ this.currentStep = 0;
1097
+ logger3.info(
1098
+ `Task initialized: '${taskDescription}' (max_steps: ${maxSteps})`
1099
+ );
1100
+ }
1101
+ /**
1102
+ * Send screenshot to the server and get the next actions.
1103
+ *
1104
+ * @param screenshot Screenshot as URL string, or raw bytes
1105
+ * @param instruction Optional additional instruction for this step (currently unused)
1106
+ * @param temperature Sampling temperature for this step (overrides task default if provided)
1107
+ */
1108
+ async step(screenshot, _instruction, temperature) {
1109
+ this.validateAndIncrementStep();
1110
+ logger3.debug(`Executing step for task: '${this.taskDescription}'`);
1111
+ try {
1112
+ const screenshotUrl = await this.ensureScreenshotUrl(screenshot);
1113
+ this.addUserMessageToHistory(screenshotUrl, this.buildStepPrompt());
1114
+ const [step, rawOutput] = await this.client.chatCompletions(
1115
+ this.model,
1116
+ this.messageHistory,
1117
+ temperature ?? this.temperature,
1118
+ this.taskId
1119
+ );
1120
+ if (rawOutput) {
1121
+ this.messageHistory.push({
1122
+ role: "assistant",
1123
+ content: [
1124
+ {
1125
+ type: "text",
1126
+ text: rawOutput
1127
+ }
1128
+ ]
1129
+ });
1130
+ }
1131
+ if (step.stop) {
1132
+ logger3.info("Task completed.");
1133
+ } else {
1134
+ logger3.debug(`Step completed with${step.actions.length} actions`);
1135
+ }
1136
+ return step;
1137
+ } catch (err) {
1138
+ logger3.error(`Error during step execution: ${err}`);
1139
+ throw err;
1140
+ }
1141
+ }
1142
+ };
1143
+
1144
+ // src/agent/default.ts
1145
+ var logger4 = logger_default("agent.default");
1146
+ var resetHandler = (handler) => {
1147
+ if (typeof handler.reset === "function") {
1148
+ handler.reset();
1149
+ }
1150
+ };
1151
+ var sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
1152
+ var DefaultAgent = class {
1153
+ /** Default asynchronous agent implementation using OAGI client. */
1154
+ api_key;
1155
+ base_url;
1156
+ model;
1157
+ max_steps;
1158
+ temperature;
1159
+ step_observer;
1160
+ step_delay;
1161
+ constructor(api_key, base_url, model = MODEL_ACTOR, max_steps = DEFAULT_MAX_STEPS, temperature = DEFAULT_TEMPERATURE, step_observer, step_delay = DEFAULT_STEP_DELAY) {
1162
+ this.api_key = api_key;
1163
+ this.base_url = base_url;
1164
+ this.model = model;
1165
+ this.max_steps = max_steps;
1166
+ this.temperature = temperature;
1167
+ this.step_observer = step_observer;
1168
+ this.step_delay = step_delay;
1169
+ }
1170
+ async execute(instruction, action_handler, image_provider) {
1171
+ const actor = new Actor(this.api_key, this.base_url, this.model);
1172
+ logger4.info(`Starting async task execution: ${instruction}`);
1173
+ await actor.initTask(instruction, this.max_steps);
1174
+ resetHandler(action_handler);
1175
+ for (let i = 0; i < this.max_steps; i++) {
1176
+ const step_num = i + 1;
1177
+ logger4.debug(`Executing step ${step_num}/${this.max_steps}`);
1178
+ const image = await image_provider.provide();
1179
+ const step = await actor.step(image, void 0, this.temperature);
1180
+ if (step.reason) {
1181
+ logger4.info(`Step ${step_num}: ${step.reason}`);
1182
+ }
1183
+ if (this.step_observer) {
1184
+ const event = {
1185
+ type: "step",
1186
+ timestamp: /* @__PURE__ */ new Date(),
1187
+ step_num,
1188
+ image,
1189
+ step,
1190
+ task_id: actor.taskId
1191
+ };
1192
+ await this.step_observer.onEvent(event);
1193
+ }
1194
+ if (step.actions?.length) {
1195
+ logger4.info(`Actions (${step.actions.length}):`);
1196
+ for (const action of step.actions) {
1197
+ const count_suffix = action.count && action.count > 1 ? ` x${action.count}` : "";
1198
+ logger4.info(` [${action.type}] ${action.argument}${count_suffix}`);
1199
+ }
1200
+ let error = null;
1201
+ try {
1202
+ await action_handler.handle(step.actions);
1203
+ } catch (e) {
1204
+ error = String(e);
1205
+ throw e;
1206
+ } finally {
1207
+ if (this.step_observer) {
1208
+ const event = {
1209
+ type: "action",
1210
+ timestamp: /* @__PURE__ */ new Date(),
1211
+ step_num,
1212
+ actions: step.actions,
1213
+ error: error ?? void 0
1214
+ };
1215
+ await this.step_observer.onEvent(event);
1216
+ }
1217
+ }
1218
+ }
1219
+ if (this.step_delay > 0) {
1220
+ await sleep(this.step_delay);
1221
+ }
1222
+ if (step.stop) {
1223
+ logger4.info(`Task completed successfully after ${step_num} steps`);
1224
+ return true;
1225
+ }
1226
+ }
1227
+ logger4.warn(
1228
+ `Task reached max steps (${this.max_steps}) without completion`
1229
+ );
1230
+ return false;
1231
+ }
1232
+ };
1233
+
1234
+ // src/agent/registry.ts
1235
+ var agentRegistry = {};
1236
+ var asyncAgentRegister = (mode) => {
1237
+ return (func) => {
1238
+ if (mode in agentRegistry) {
1239
+ throw new Error(
1240
+ `Agent mode '${mode}' is already registered. Cannot register the same mode twice.`
1241
+ );
1242
+ }
1243
+ agentRegistry[mode] = func;
1244
+ return func;
1245
+ };
1246
+ };
1247
+ var getAgentFactory = (mode) => {
1248
+ if (!(mode in agentRegistry)) {
1249
+ const availableModes = Object.keys(agentRegistry);
1250
+ throw new Error(
1251
+ `Unknown agent mode: '${mode}'. Available modes: ${availableModes}`
1252
+ );
1253
+ }
1254
+ return agentRegistry[mode];
1255
+ };
1256
+ var listAgentModes = () => {
1257
+ return Object.keys(agentRegistry);
1258
+ };
1259
+ var createAgent = (mode, options = {}) => {
1260
+ const factory = getAgentFactory(mode);
1261
+ const agent = factory(options);
1262
+ if (!agent || typeof agent.execute !== "function") {
1263
+ throw new TypeError(
1264
+ `Factory for mode '${mode}' returned an object that doesn't implement Agent. Expected an object with an 'execute' method.`
1265
+ );
1266
+ }
1267
+ return agent;
1268
+ };
1269
+
1270
+ // src/agent/factories.ts
1271
+ asyncAgentRegister("actor")((options = {}) => {
1272
+ const {
1273
+ apiKey,
1274
+ baseUrl,
1275
+ model = MODEL_ACTOR,
1276
+ maxSteps = DEFAULT_MAX_STEPS,
1277
+ temperature = DEFAULT_TEMPERATURE_LOW,
1278
+ stepObserver,
1279
+ stepDelay = DEFAULT_STEP_DELAY
1280
+ } = options;
1281
+ return new DefaultAgent(
1282
+ apiKey,
1283
+ baseUrl,
1284
+ model,
1285
+ maxSteps,
1286
+ temperature,
1287
+ stepObserver ?? void 0,
1288
+ stepDelay
1289
+ );
1290
+ });
1291
+ asyncAgentRegister("thinker")((options = {}) => {
1292
+ const {
1293
+ apiKey,
1294
+ baseUrl,
1295
+ model = MODEL_THINKER,
1296
+ maxSteps = DEFAULT_MAX_STEPS_THINKER,
1297
+ temperature = DEFAULT_TEMPERATURE_LOW,
1298
+ stepObserver,
1299
+ stepDelay = DEFAULT_STEP_DELAY
1300
+ } = options;
1301
+ return new DefaultAgent(
1302
+ apiKey,
1303
+ baseUrl,
1304
+ model,
1305
+ maxSteps,
1306
+ temperature,
1307
+ stepObserver ?? void 0,
1308
+ stepDelay
1309
+ );
1310
+ });
1311
+
1312
+ // src/handler.ts
1313
+ var import_robotjs = __toESM(require("robotjs"), 1);
1314
+ var import_sharp = __toESM(require("sharp"), 1);
1315
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
1316
+ var toSharpKernel = (resample) => {
1317
+ switch (resample) {
1318
+ case "NEAREST":
1319
+ return "nearest";
1320
+ case "BICUBIC":
1321
+ return "cubic";
1322
+ case "BILINEAR":
1323
+ return "mitchell";
1324
+ case "LANCZOS":
1325
+ default:
1326
+ return "lanczos3";
1327
+ }
1328
+ };
1329
+ var normalizeKey = (raw, opts) => {
1330
+ const key = raw.trim().toLowerCase();
1331
+ if (key === "caps_lock" || key === "caps") return "capslock";
1332
+ if (key === "page_up" || key === "pageup") return "pageup";
1333
+ if (key === "page_down" || key === "pagedown") return "pagedown";
1334
+ if (key === "cmd") return "command";
1335
+ if (opts.macosCtrlToCmd && process.platform === "darwin" && key === "ctrl") {
1336
+ return "command";
1337
+ }
1338
+ if (key === "ctrl") return "control";
1339
+ return key;
1340
+ };
1341
+ var parseHotkey = (arg, opts) => {
1342
+ const s = arg.trim().replace(/^\(/, "").replace(/\)$/, "");
1343
+ return s.split("+").map((k) => normalizeKey(k, opts)).filter(Boolean);
1344
+ };
1345
+ var stripOuterParens = (s) => s.trim().replace(/^\(/, "").replace(/\)$/, "");
1346
+ var applySessionCaps = (text, enabled) => {
1347
+ if (!enabled) return text;
1348
+ return text.split("").map((c) => /[a-z]/i.test(c) ? c.toUpperCase() : c).join("");
1349
+ };
1350
+ var defaultDesktopAutomationConfig = () => ({
1351
+ dragDurationMs: 500,
1352
+ scrollAmount: process.platform === "darwin" ? 2 : 100,
1353
+ waitDurationMs: 1e3,
1354
+ hotkeyDelayMs: 100,
1355
+ macosCtrlToCmd: true,
1356
+ capslockMode: "session"
1357
+ });
1358
+ var ScreenshotMaker = class _ScreenshotMaker {
1359
+ #cfg;
1360
+ constructor(cfg) {
1361
+ const defaultConfig = ImageConfigSchema.parse({});
1362
+ this.#cfg = { ...defaultConfig, ...cfg };
1363
+ }
1364
+ static toArrayBuffer(buffer) {
1365
+ const arraybuffer = new ArrayBuffer(buffer.length);
1366
+ const view = new Uint8Array(arraybuffer);
1367
+ for (let i = 0; i < buffer.length; ++i) {
1368
+ view[i] = buffer[i];
1369
+ }
1370
+ return arraybuffer;
1371
+ }
1372
+ async provide() {
1373
+ const { width, height } = import_robotjs.default.getScreenSize();
1374
+ const screenshot = import_robotjs.default.screen.capture(0, 0, width, height);
1375
+ const channels = 3;
1376
+ const data = new Uint8Array(
1377
+ screenshot.width * screenshot.height * channels
1378
+ );
1379
+ for (let w = 0; w < screenshot.width; ++w) {
1380
+ for (let h = 0; h < screenshot.height; ++h) {
1381
+ let offset = (h * screenshot.width + w) * channels;
1382
+ let offset2 = screenshot.byteWidth * h + w * screenshot.bytesPerPixel;
1383
+ data[offset] = screenshot.image.readUInt8(offset2 + 2);
1384
+ data[offset + 1] = screenshot.image.readUInt8(offset2 + 1);
1385
+ data[offset + 2] = screenshot.image.readUInt8(offset2 + 0);
1386
+ }
1387
+ }
1388
+ let p = (0, import_sharp.default)(Buffer.from(data), {
1389
+ raw: {
1390
+ width: screenshot.width,
1391
+ height: screenshot.height,
1392
+ channels
1393
+ }
1394
+ });
1395
+ if (this.#cfg.width || this.#cfg.height) {
1396
+ p = p.resize(this.#cfg.width ?? width, this.#cfg.height ?? height, {
1397
+ fit: "fill",
1398
+ kernel: toSharpKernel(this.#cfg.resample)
1399
+ });
1400
+ }
1401
+ const encoded = this.#cfg.format === "PNG" ? await p.png({ compressionLevel: this.#cfg.optimize ? 9 : 6 }).toBuffer() : await p.jpeg({ quality: this.#cfg.quality }).toBuffer();
1402
+ return _ScreenshotMaker.toArrayBuffer(encoded);
1403
+ }
1404
+ };
1405
+ var DefaultActionHandler = class {
1406
+ #cfg;
1407
+ #sessionCapsEnabled = false;
1408
+ constructor(cfg) {
1409
+ this.#cfg = { ...defaultDesktopAutomationConfig(), ...cfg };
1410
+ }
1411
+ reset() {
1412
+ this.#sessionCapsEnabled = false;
1413
+ }
1414
+ async handle(actions) {
1415
+ for (const action of actions) {
1416
+ const count = action.count ?? 1;
1417
+ for (let i = 0; i < count; i++) {
1418
+ await this.#handleOne(action);
1419
+ }
1420
+ }
1421
+ }
1422
+ #denormalize(x, y) {
1423
+ const { width, height } = import_robotjs.default.getScreenSize();
1424
+ let px = Math.floor(x * width / 1e3);
1425
+ let py = Math.floor(y * height / 1e3);
1426
+ if (px < 1) px = 1;
1427
+ if (px > width - 1) px = width - 1;
1428
+ if (py < 1) py = 1;
1429
+ if (py > height - 1) py = height - 1;
1430
+ return { x: px, y: py };
1431
+ }
1432
+ async #handleOne(action) {
1433
+ const arg = stripOuterParens(action.argument);
1434
+ switch (action.type) {
1435
+ case "click": {
1436
+ const coords = parseCoords(arg);
1437
+ if (!coords) throw new Error(`Invalid coords: ${arg}`);
1438
+ const p = this.#denormalize(coords[0], coords[1]);
1439
+ import_robotjs.default.moveMouse(p.x, p.y);
1440
+ import_robotjs.default.mouseClick("left", false);
1441
+ return;
1442
+ }
1443
+ case "left_double": {
1444
+ const coords = parseCoords(arg);
1445
+ if (!coords) throw new Error(`Invalid coords: ${arg}`);
1446
+ const p = this.#denormalize(coords[0], coords[1]);
1447
+ import_robotjs.default.moveMouse(p.x, p.y);
1448
+ import_robotjs.default.mouseClick("left", true);
1449
+ return;
1450
+ }
1451
+ case "left_triple": {
1452
+ const coords = parseCoords(arg);
1453
+ if (!coords) throw new Error(`Invalid coords: ${arg}`);
1454
+ const p = this.#denormalize(coords[0], coords[1]);
1455
+ import_robotjs.default.moveMouse(p.x, p.y);
1456
+ import_robotjs.default.mouseClick("left", true);
1457
+ import_robotjs.default.mouseClick("left", false);
1458
+ return;
1459
+ }
1460
+ case "right_single": {
1461
+ const coords = parseCoords(arg);
1462
+ if (!coords) throw new Error(`Invalid coords: ${arg}`);
1463
+ const p = this.#denormalize(coords[0], coords[1]);
1464
+ import_robotjs.default.moveMouse(p.x, p.y);
1465
+ import_robotjs.default.mouseClick("right", false);
1466
+ return;
1467
+ }
1468
+ case "drag": {
1469
+ const coords = parseDragCoords(arg);
1470
+ if (!coords) throw new Error(`Invalid drag coords: ${arg}`);
1471
+ const p1 = this.#denormalize(coords[0], coords[1]);
1472
+ const p2 = this.#denormalize(coords[2], coords[3]);
1473
+ import_robotjs.default.moveMouse(p1.x, p1.y);
1474
+ import_robotjs.default.mouseToggle("down", "left");
1475
+ import_robotjs.default.dragMouse(p2.x, p2.y);
1476
+ await sleep2(this.#cfg.dragDurationMs);
1477
+ import_robotjs.default.mouseToggle("up", "left");
1478
+ return;
1479
+ }
1480
+ case "hotkey": {
1481
+ const keys = parseHotkey(arg, {
1482
+ macosCtrlToCmd: this.#cfg.macosCtrlToCmd
1483
+ });
1484
+ if (keys.length === 1 && keys[0] === "capslock") {
1485
+ if (this.#cfg.capslockMode === "system") {
1486
+ import_robotjs.default.keyTap("capslock");
1487
+ } else {
1488
+ this.#sessionCapsEnabled = !this.#sessionCapsEnabled;
1489
+ }
1490
+ return;
1491
+ }
1492
+ const last = keys.at(-1);
1493
+ if (!last) return;
1494
+ const modifiers = keys.slice(0, -1);
1495
+ import_robotjs.default.keyTap(last, modifiers.length ? modifiers : []);
1496
+ await sleep2(this.#cfg.hotkeyDelayMs);
1497
+ return;
1498
+ }
1499
+ case "type": {
1500
+ const raw = arg.replace(/^['"]/, "").replace(/['"]$/, "");
1501
+ const text = applySessionCaps(raw, this.#sessionCapsEnabled);
1502
+ import_robotjs.default.typeString(text);
1503
+ return;
1504
+ }
1505
+ case "scroll": {
1506
+ const parsed = parseScroll(arg);
1507
+ if (!parsed) throw new Error(`Invalid scroll: ${arg}`);
1508
+ const p = this.#denormalize(parsed[0], parsed[1]);
1509
+ const direction = parsed[2];
1510
+ import_robotjs.default.moveMouse(p.x, p.y);
1511
+ const amount = direction === "up" ? this.#cfg.scrollAmount : -this.#cfg.scrollAmount;
1512
+ import_robotjs.default.scrollMouse(0, amount);
1513
+ return;
1514
+ }
1515
+ case "wait": {
1516
+ await sleep2(this.#cfg.waitDurationMs);
1517
+ return;
1518
+ }
1519
+ case "finish": {
1520
+ this.reset();
1521
+ return;
1522
+ }
1523
+ case "call_user": {
1524
+ return;
1525
+ }
1526
+ default: {
1527
+ const exhaustive = action.type;
1528
+ throw new Error(`Unknown action type: ${String(exhaustive)}`);
1529
+ }
1530
+ }
1531
+ }
1532
+ };
1533
+
1534
+ // src/cli/display.ts
1535
+ var import_cli_table3 = __toESM(require("cli-table3"), 1);
1536
+ var displayStepTable = (steps, success, durationSeconds) => {
1537
+ const table = new import_cli_table3.default({
1538
+ head: ["Step", "Reasoning", "Actions", "Status"],
1539
+ colWidths: [6, 60, 40, 10],
1540
+ wordWrap: true
1541
+ });
1542
+ for (const step of steps) {
1543
+ const reason = step.reasoning ?? "N/A";
1544
+ const actionsDisplay = [];
1545
+ for (const action of step.actions.slice(0, 3)) {
1546
+ const arg = action.argument ? String(action.argument).slice(0, 20) : "";
1547
+ const countStr = action.count && action.count > 1 ? ` x${action.count}` : "";
1548
+ actionsDisplay.push(`${action.type}(${arg})${countStr}`);
1549
+ }
1550
+ let actionsStr = actionsDisplay.join(", ");
1551
+ if (step.actions.length > 3) {
1552
+ actionsStr += ` (+${step.actions.length - 3} more)`;
1553
+ }
1554
+ const statusDisplay = step.status === "completed" ? "ok" : step.status;
1555
+ table.push([String(step.step_num), reason, actionsStr, statusDisplay]);
1556
+ }
1557
+ process.stdout.write(String(table) + "\n");
1558
+ const statusText = success ? "Success" : "Failed/Interrupted";
1559
+ process.stdout.write(
1560
+ `
1561
+ Total Steps: ${steps.length} | Status: ${statusText}
1562
+ `
1563
+ );
1564
+ if (typeof durationSeconds === "number") {
1565
+ process.stdout.write(`Duration: ${durationSeconds.toFixed(2)}s
1566
+ `);
1567
+ }
1568
+ };
1569
+
1570
+ // src/cli/tracking.ts
1571
+ var StepTracker = class extends StepObserver {
1572
+ /** Tracks agent step execution by implementing AsyncObserver protocol. */
1573
+ steps = [];
1574
+ async onEvent(event) {
1575
+ switch (event.type) {
1576
+ case "step": {
1577
+ const e = event;
1578
+ this.steps.push({
1579
+ step_num: e.step_num,
1580
+ timestamp: e.timestamp,
1581
+ reasoning: e.step.reason ?? null,
1582
+ actions: e.step.actions,
1583
+ action_count: e.step.actions.length,
1584
+ status: "running"
1585
+ });
1586
+ return;
1587
+ }
1588
+ case "action": {
1589
+ const e = event;
1590
+ for (const step of this.steps) {
1591
+ if (step.step_num === e.step_num) {
1592
+ step.status = e.error ? "error" : "completed";
1593
+ break;
1594
+ }
1595
+ }
1596
+ return;
1597
+ }
1598
+ default:
1599
+ return;
1600
+ }
1601
+ }
1602
+ };
1603
+
1604
+ // src/cli/agent.ts
1605
+ var import_node_mac_permissions = __toESM(require("@hurdlegroup/node-mac-permissions"), 1);
1606
+ var logger5 = logger_default("cli.agent");
1607
+ var checkPermissions = async () => {
1608
+ if (process.platform !== "darwin") {
1609
+ process.stdout.write(
1610
+ "Warning: Permission check is only applicable on macOS.\n"
1611
+ );
1612
+ process.stdout.write(
1613
+ "On other platforms, no special permissions are required.\n"
1614
+ );
1615
+ return;
1616
+ }
1617
+ const screenPermission = import_node_mac_permissions.default.getAuthStatus("screen");
1618
+ const accessibilityPermission = import_node_mac_permissions.default.getAuthStatus("accessibility");
1619
+ console.log("Checking permissions...");
1620
+ console.log(` ${screenPermission ? "[OK]" : "[MISSING]"} Screen Recording`);
1621
+ console.log(
1622
+ ` ${accessibilityPermission ? "[OK]" : "[MISSING]"} Accessibility`
1623
+ );
1624
+ if (!screenPermission) {
1625
+ import_node_mac_permissions.default.askForScreenCaptureAccess(true);
1626
+ }
1627
+ if (!accessibilityPermission) {
1628
+ import_node_mac_permissions.default.askForAccessibilityAccess();
1629
+ }
1630
+ if (screenPermission && accessibilityPermission) {
1631
+ console.log("All permissions granted. You can run the agent.");
1632
+ } else {
1633
+ console.log("After granting, run this command again to continue.");
1634
+ console.log(
1635
+ "Note: You may need to restart your terminal after granting permissions."
1636
+ );
1637
+ process.exitCode = 1;
1638
+ return;
1639
+ }
1640
+ };
1641
+ var runAgent = async (instruction, opts) => {
1642
+ const apiKey = opts.oagiApiKey ?? process.env.OAGI_API_KEY;
1643
+ if (!apiKey) {
1644
+ process.stderr.write(
1645
+ `Error: OAGI API key not provided.
1646
+ Set OAGI_API_KEY environment variable or use --oagi-api-key flag.
1647
+ Get your API key at ${API_KEY_HELP_URL}
1648
+ `
1649
+ );
1650
+ process.exitCode = 1;
1651
+ return;
1652
+ }
1653
+ const baseUrl = opts.oagiBaseUrl ?? process.env.OAGI_BASE_URL ?? DEFAULT_BASE_URL;
1654
+ const mode = opts.mode ?? MODE_ACTOR;
1655
+ const stepDelay = opts.stepDelay ?? DEFAULT_STEP_DELAY;
1656
+ const exportFormat = opts.export;
1657
+ const exportFile = opts.exportFile;
1658
+ const stepTracker = new StepTracker();
1659
+ const agentObserver = exportFormat ? new AsyncAgentObserver() : null;
1660
+ const createOpts = {
1661
+ apiKey,
1662
+ baseUrl,
1663
+ stepObserver: stepTracker.chain(agentObserver),
1664
+ stepDelay
1665
+ };
1666
+ if (opts.model) {
1667
+ createOpts.model = opts.model;
1668
+ if (opts.model === MODEL_THINKER && !opts.maxSteps) {
1669
+ createOpts.maxSteps = DEFAULT_MAX_STEPS_THINKER;
1670
+ }
1671
+ }
1672
+ if (typeof opts.maxSteps === "number") {
1673
+ createOpts.maxSteps = opts.maxSteps;
1674
+ }
1675
+ if (typeof opts.temperature === "number") {
1676
+ createOpts.temperature = opts.temperature;
1677
+ }
1678
+ const agent = createAgent(mode, createOpts);
1679
+ let actionHandler;
1680
+ let imageProvider;
1681
+ try {
1682
+ actionHandler = new DefaultActionHandler();
1683
+ imageProvider = new ScreenshotMaker();
1684
+ } catch (e) {
1685
+ process.stderr.write(
1686
+ `Error: desktop automation dependencies failed to load: ${String(e)}
1687
+ If you're using pnpm and robotjs is installed, you may need to run: pnpm approve-builds
1688
+ `
1689
+ );
1690
+ process.exitCode = 1;
1691
+ return;
1692
+ }
1693
+ if (instruction) {
1694
+ process.stdout.write(`Starting agent with instruction: ${instruction}
1695
+ `);
1696
+ } else {
1697
+ process.stdout.write(
1698
+ `Starting agent with mode: ${mode} (using pre-configured instruction)
1699
+ `
1700
+ );
1701
+ }
1702
+ process.stdout.write(`Mode: ${mode}
1703
+ `);
1704
+ process.stdout.write("-".repeat(60) + "\n");
1705
+ const start = Date.now();
1706
+ let success = false;
1707
+ let interrupted = false;
1708
+ const onSigint = () => {
1709
+ interrupted = true;
1710
+ process.stdout.write("\nAgent execution interrupted by user (Ctrl+C)\n");
1711
+ };
1712
+ process.once("SIGINT", onSigint);
1713
+ try {
1714
+ if (interrupted) throw new Error("Interrupted");
1715
+ success = await agent.execute(instruction, actionHandler, imageProvider);
1716
+ } catch (err) {
1717
+ if (interrupted) {
1718
+ process.exitCode = 130;
1719
+ } else {
1720
+ logger5.error(`Error during agent execution: ${String(err)}`);
1721
+ process.exitCode = 1;
1722
+ }
1723
+ } finally {
1724
+ process.off("SIGINT", onSigint);
1725
+ const durationSeconds = (Date.now() - start) / 1e3;
1726
+ if (stepTracker.steps.length) {
1727
+ process.stdout.write("\n" + "=".repeat(60) + "\n");
1728
+ displayStepTable(stepTracker.steps, success, durationSeconds);
1729
+ } else {
1730
+ process.stdout.write("\nNo steps were executed.\n");
1731
+ }
1732
+ if (exportFormat && agentObserver) {
1733
+ const extMap = {
1734
+ markdown: "md",
1735
+ html: "html",
1736
+ json: "json"
1737
+ };
1738
+ const outputPath = exportFile ?? `execution_report.${extMap[exportFormat]}`;
1739
+ try {
1740
+ agentObserver.export(exportFormat, outputPath);
1741
+ process.stdout.write(
1742
+ `
1743
+ Execution history exported to: ${outputPath}
1744
+ `
1745
+ );
1746
+ } catch (e) {
1747
+ process.stderr.write(
1748
+ `
1749
+ Error exporting execution history: ${String(e)}
1750
+ `
1751
+ );
1752
+ }
1753
+ }
1754
+ if (interrupted) {
1755
+ process.exitCode = 130;
1756
+ } else if (!success && !process.exitCode) {
1757
+ process.exitCode = 1;
1758
+ }
1759
+ }
1760
+ };
1761
+ var addAgentCommand = (program) => {
1762
+ const agent = program.command("agent").description("Agent execution commands");
1763
+ agent.command("run").description("Run an agent with the given instruction").argument("[instruction]", "Task instruction for the agent to execute").option("--model <model>", "Model to use (default: determined by mode)").option(
1764
+ "--max-steps <number>",
1765
+ "Maximum number of steps (default: determined by mode)",
1766
+ (v) => Number(v)
1767
+ ).option(
1768
+ "--temperature <number>",
1769
+ "Sampling temperature (default: determined by mode)",
1770
+ (v) => Number(v)
1771
+ ).option(
1772
+ "--mode <mode>",
1773
+ `Agent mode to use (default: ${MODE_ACTOR})`,
1774
+ MODE_ACTOR
1775
+ ).option(
1776
+ "--oagi-api-key <key>",
1777
+ "OAGI API key (default: OAGI_API_KEY env var)"
1778
+ ).option(
1779
+ "--oagi-base-url <url>",
1780
+ `OAGI base URL (default: ${DEFAULT_BASE_URL}, or OAGI_BASE_URL env var)`
1781
+ ).option(
1782
+ "--export <format>",
1783
+ "Export execution history to file (markdown, html, or json)"
1784
+ ).option(
1785
+ "--export-file <path>",
1786
+ "Output file path for export (default: execution_report.[md|html|json])"
1787
+ ).option(
1788
+ "--step-delay <number>",
1789
+ `Delay in seconds after each step before next screenshot (default: ${DEFAULT_STEP_DELAY})`,
1790
+ (v) => Number(v)
1791
+ ).action(async (instruction, options) => {
1792
+ await runAgent(instruction ?? "", {
1793
+ model: options.model,
1794
+ maxSteps: options.maxSteps,
1795
+ temperature: options.temperature,
1796
+ mode: options.mode,
1797
+ oagiApiKey: options.oagiApiKey,
1798
+ oagiBaseUrl: options.oagiBaseUrl,
1799
+ export: options.export,
1800
+ exportFile: options.exportFile,
1801
+ stepDelay: options.stepDelay
1802
+ });
1803
+ });
1804
+ agent.command("modes").description("List available agent modes").action(() => {
1805
+ const modes = listAgentModes();
1806
+ process.stdout.write("Available agent modes:\n");
1807
+ for (const m of modes) process.stdout.write(` - ${m}
1808
+ `);
1809
+ });
1810
+ agent.command("permission").description(
1811
+ "Check macOS permissions for screen recording and accessibility"
1812
+ ).action(async () => {
1813
+ await checkPermissions();
1814
+ });
1815
+ };
1816
+
1817
+ // src/cli/utils.ts
1818
+ var setupLogging = (verbose) => {
1819
+ if (verbose) {
1820
+ process.env.OAGI_LOG = "debug";
1821
+ }
1822
+ };
1823
+ var maskApiKey = (value) => {
1824
+ if (!value) return "";
1825
+ return value.length > 8 ? `${value.slice(0, 8)}...` : "***";
1826
+ };
1827
+
1828
+ // src/cli/config.ts
1829
+ var displayConfig = () => {
1830
+ const configVars = {
1831
+ OAGI_API_KEY: process.env.OAGI_API_KEY ?? "",
1832
+ OAGI_BASE_URL: process.env.OAGI_BASE_URL ?? DEFAULT_BASE_URL,
1833
+ OAGI_DEFAULT_MODEL: process.env.OAGI_DEFAULT_MODEL ?? MODEL_ACTOR,
1834
+ OAGI_LOG: process.env.OAGI_LOG ?? "info",
1835
+ OAGI_MAX_STEPS: process.env.OAGI_MAX_STEPS ?? "30"
1836
+ };
1837
+ process.stdout.write("Current Configuration:\n");
1838
+ process.stdout.write("-".repeat(50) + "\n");
1839
+ for (const [key, value] of Object.entries(configVars)) {
1840
+ if (key === "OAGI_API_KEY" && value) {
1841
+ process.stdout.write(`${key}: ${maskApiKey(value)}
1842
+ `);
1843
+ } else {
1844
+ const displayValue = value ? value : "(not set)";
1845
+ process.stdout.write(`${key}: ${displayValue}
1846
+ `);
1847
+ }
1848
+ }
1849
+ };
1850
+ var addConfigCommand = (program) => {
1851
+ const config = program.command("config").description("Configuration management");
1852
+ config.command("show").description("Display current configuration").action(() => {
1853
+ displayConfig();
1854
+ });
1855
+ };
1856
+
1857
+ // src/cli/version.ts
1858
+ var import_module = require("module");
1859
+ var import_meta2 = {};
1860
+ var getSdkVersion = () => {
1861
+ try {
1862
+ const require2 = (0, import_module.createRequire)(import_meta2.url);
1863
+ for (const p of ["../package.json", "../../package.json"]) {
1864
+ try {
1865
+ const pkg = require2(p);
1866
+ if (pkg.version && pkg.version !== "0.0.0") return pkg.version;
1867
+ } catch {
1868
+ }
1869
+ }
1870
+ } catch {
1871
+ }
1872
+ return "unknown";
1873
+ };
1874
+ var displayVersion = () => {
1875
+ const sdkVersion = getSdkVersion();
1876
+ process.stdout.write(`OAGI SDK version: ${sdkVersion}
1877
+ `);
1878
+ process.stdout.write(`Node version: ${process.version}
1879
+ `);
1880
+ process.stdout.write(`Platform: ${process.platform}
1881
+ `);
1882
+ };
1883
+ var addVersionCommand = (program) => {
1884
+ program.command("version").description("Show SDK version and environment info").action(() => {
1885
+ displayVersion();
1886
+ });
1887
+ };
1888
+
1889
+ // src/cli/main.ts
1890
+ var createProgram = () => {
1891
+ const program = new import_commander.Command();
1892
+ program.name("oagi").description("OAGI SDK Command Line Interface").option("-v, --verbose", "Enable verbose (debug) logging");
1893
+ addAgentCommand(program);
1894
+ addVersionCommand(program);
1895
+ addConfigCommand(program);
1896
+ return program;
1897
+ };
1898
+ var main = async (argv = process.argv) => {
1899
+ const program = createProgram();
1900
+ try {
1901
+ program.hook("preAction", (thisCommand) => {
1902
+ const opts = thisCommand.opts();
1903
+ setupLogging(Boolean(opts?.verbose));
1904
+ });
1905
+ await program.parseAsync(argv);
1906
+ } catch (err) {
1907
+ if (err instanceof Error && err.name === "CommanderError") {
1908
+ process.exitCode = 1;
1909
+ return;
1910
+ }
1911
+ if (err instanceof Error && err.message === "Interrupted") {
1912
+ process.exitCode = 130;
1913
+ return;
1914
+ }
1915
+ process.stderr.write(`Unexpected error: ${String(err)}
1916
+ `);
1917
+ process.exitCode = 1;
1918
+ }
1919
+ };
1920
+
1921
+ // src/cli.ts
1922
+ main().catch((err) => {
1923
+ process.stderr.write(`Unexpected error: ${String(err)}
1924
+ `);
1925
+ process.exitCode = 1;
1926
+ });
1927
+ //# sourceMappingURL=cli.cjs.map