@agentrix/agentrix-run 0.5.0 → 0.7.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/dist/index.cjs CHANGED
@@ -5,13 +5,15 @@ var shared = require('@agentrix/shared');
5
5
 
6
6
  const DEFAULT_RESPONSE_MODE = "stream";
7
7
  const DEFAULT_WAIT_TIMEOUT_SECONDS = 1800;
8
+ const DEFAULT_AGENTRIX_BASE_URL = "https://agentrix.xmz.ai";
8
9
  function usage() {
9
10
  return [
10
- "Usage: agentrix-run --agent <agent> --prompt <prompt> [options]",
11
+ "Usage: agentrix-run (--agent <agent> | --resume <task-id>) --prompt <prompt> [options]",
11
12
  "",
12
13
  "Options:",
13
14
  " --title <text>",
14
15
  " --allow-filesystem-agent",
16
+ " --resume <task-id>",
15
17
  " --repo <json>",
16
18
  " --output-schema <json>",
17
19
  " --ref <ref>",
@@ -26,7 +28,7 @@ function usage() {
26
28
  " --capability-profile <name>",
27
29
  " --runner-id <cloud-id|machine-id>",
28
30
  " --result-file <path>",
29
- " --base-url <url>",
31
+ ` --base-url <url> (default: ${DEFAULT_AGENTRIX_BASE_URL})`,
30
32
  " --api-key <api-key>",
31
33
  " --metadata <key=value>",
32
34
  " --help"
@@ -180,6 +182,10 @@ function parseArgs(argv) {
180
182
  case "--allow-filesystem-agent":
181
183
  options.allowFilesystemAgent = true;
182
184
  break;
185
+ case "--resume":
186
+ options.resumeTaskId = requireValue(argv, index, arg);
187
+ index += 1;
188
+ break;
183
189
  case "--title":
184
190
  options.title = requireValue(argv, index, arg);
185
191
  index += 1;
@@ -267,12 +273,15 @@ function parseArgs(argv) {
267
273
  throw new Error(`Unknown argument: ${arg}`);
268
274
  }
269
275
  }
270
- if (!options.agent.trim()) {
276
+ if (!options.resumeTaskId && !options.agent.trim()) {
271
277
  throw new Error("--agent is required");
272
278
  }
273
279
  if (!options.prompt.trim()) {
274
280
  throw new Error("--prompt is required");
275
281
  }
282
+ if (options.resumeTaskId !== void 0 && !options.resumeTaskId.trim()) {
283
+ throw new Error("--resume must be a non-empty task ID");
284
+ }
276
285
  return options;
277
286
  }
278
287
  function normalizeRef(value) {
@@ -451,10 +460,7 @@ function buildRequest(options, detected) {
451
460
  return shared.CreateCiRunRequestSchema.parse(request);
452
461
  }
453
462
  function resolveBaseUrl(options) {
454
- const value = options.baseUrl || process.env.AGENTRIX_BASE_URL;
455
- if (!value) {
456
- throw new Error("Missing --base-url and AGENTRIX_BASE_URL");
457
- }
463
+ const value = options.baseUrl || process.env.AGENTRIX_BASE_URL || DEFAULT_AGENTRIX_BASE_URL;
458
464
  return value.replace(/\/+$/, "");
459
465
  }
460
466
  function resolveApiKey(options) {
@@ -485,6 +491,36 @@ async function createRun(baseUrl, apiKey, request) {
485
491
  const response = await requestJson("POST", `${baseUrl}/v1/ci/runs`, apiKey, request);
486
492
  return shared.CreateCiRunResponseSchema.parse(response);
487
493
  }
494
+ function createPromptMessage(text) {
495
+ return {
496
+ type: "user",
497
+ message: {
498
+ role: "user",
499
+ content: text.trim()
500
+ },
501
+ parent_tool_use_id: null,
502
+ session_id: ""
503
+ };
504
+ }
505
+ function buildResumeMessageRequest(options) {
506
+ return {
507
+ message: createPromptMessage(options.prompt),
508
+ target: "agent",
509
+ senderType: "human",
510
+ senderId: "agentrix-run",
511
+ senderName: "agentrix-run",
512
+ responseMode: options.responseMode
513
+ };
514
+ }
515
+ async function sendResumeMessage(baseUrl, apiKey, taskId, request) {
516
+ const response = await requestJson(
517
+ "POST",
518
+ `${baseUrl}/v1/tasks/${encodeURIComponent(taskId)}/send-message`,
519
+ apiKey,
520
+ request
521
+ );
522
+ return shared.SendTaskMessageResponseSchema.parse(response);
523
+ }
488
524
  function exitCodeForStatus(status) {
489
525
  return status === "completed" ? 0 : 1;
490
526
  }
@@ -569,12 +605,12 @@ function parseSseBlock(block) {
569
605
  data: JSON.parse(dataText)
570
606
  };
571
607
  }
572
- async function createRunStream(baseUrl, apiKey, request, deadline) {
608
+ async function streamRunRequest(baseUrl, apiKey, path, request, deadline) {
573
609
  const timeoutMs = Math.max(deadline - Date.now(), 1);
574
610
  const controller = new AbortController();
575
611
  const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
576
612
  try {
577
- const response = await fetch(`${baseUrl}/v1/ci/runs`, {
613
+ const response = await fetch(`${baseUrl}${path}`, {
578
614
  method: "POST",
579
615
  headers: {
580
616
  Authorization: `Bearer ${apiKey}`,
@@ -642,11 +678,44 @@ async function createRunStream(baseUrl, apiKey, request, deadline) {
642
678
  clearTimeout(timeoutHandle);
643
679
  }
644
680
  }
681
+ async function createRunStream(baseUrl, apiKey, request, deadline) {
682
+ return streamRunRequest(baseUrl, apiKey, "/v1/ci/runs", request, deadline);
683
+ }
684
+ async function resumeRunStream(baseUrl, apiKey, taskId, request, deadline) {
685
+ return streamRunRequest(
686
+ baseUrl,
687
+ apiKey,
688
+ `/v1/tasks/${encodeURIComponent(taskId)}/send-message`,
689
+ request,
690
+ deadline
691
+ );
692
+ }
645
693
  async function main(argv = process.argv.slice(2)) {
646
694
  const options = parseArgs(argv);
647
695
  const detected = detectCiContext();
648
696
  const baseUrl = resolveBaseUrl(options);
649
697
  const apiKey = resolveApiKey(options);
698
+ if (options.resumeTaskId) {
699
+ const taskId = options.resumeTaskId.trim();
700
+ const request2 = buildResumeMessageRequest(options);
701
+ if (options.responseMode === "async") {
702
+ const response = await sendResumeMessage(baseUrl, apiKey, taskId, request2);
703
+ if (!response.run) {
704
+ throw new Error("Server did not return CI run metadata for resumed task");
705
+ }
706
+ writeAsyncResultFile(options.resultFile, response.run);
707
+ printStandardFields({
708
+ runId: response.run.runId,
709
+ status: response.run.status,
710
+ detailUrl: response.run.detailUrl
711
+ });
712
+ return 0;
713
+ }
714
+ const deadline2 = ensureWaitDeadline(options);
715
+ const finalStatus2 = await resumeRunStream(baseUrl, apiKey, taskId, request2, deadline2);
716
+ writeResultFile(options.resultFile, finalStatus2);
717
+ return exitCodeForStatus(finalStatus2.status);
718
+ }
650
719
  const request = buildRequest(options, detected);
651
720
  if (options.responseMode === "async") {
652
721
  const run = await createRun(baseUrl, apiKey, request);
package/dist/index.mjs CHANGED
@@ -1,15 +1,17 @@
1
1
  import { writeFileSync, readFileSync } from 'node:fs';
2
- import { CreateCiRunRequestSchema, CiRunStatusResponseSchema, CreateCiRunResponseSchema } from '@agentrix/shared';
2
+ import { CreateCiRunRequestSchema, CiRunStatusResponseSchema, SendTaskMessageResponseSchema, CreateCiRunResponseSchema } from '@agentrix/shared';
3
3
 
4
4
  const DEFAULT_RESPONSE_MODE = "stream";
5
5
  const DEFAULT_WAIT_TIMEOUT_SECONDS = 1800;
6
+ const DEFAULT_AGENTRIX_BASE_URL = "https://agentrix.xmz.ai";
6
7
  function usage() {
7
8
  return [
8
- "Usage: agentrix-run --agent <agent> --prompt <prompt> [options]",
9
+ "Usage: agentrix-run (--agent <agent> | --resume <task-id>) --prompt <prompt> [options]",
9
10
  "",
10
11
  "Options:",
11
12
  " --title <text>",
12
13
  " --allow-filesystem-agent",
14
+ " --resume <task-id>",
13
15
  " --repo <json>",
14
16
  " --output-schema <json>",
15
17
  " --ref <ref>",
@@ -24,7 +26,7 @@ function usage() {
24
26
  " --capability-profile <name>",
25
27
  " --runner-id <cloud-id|machine-id>",
26
28
  " --result-file <path>",
27
- " --base-url <url>",
29
+ ` --base-url <url> (default: ${DEFAULT_AGENTRIX_BASE_URL})`,
28
30
  " --api-key <api-key>",
29
31
  " --metadata <key=value>",
30
32
  " --help"
@@ -178,6 +180,10 @@ function parseArgs(argv) {
178
180
  case "--allow-filesystem-agent":
179
181
  options.allowFilesystemAgent = true;
180
182
  break;
183
+ case "--resume":
184
+ options.resumeTaskId = requireValue(argv, index, arg);
185
+ index += 1;
186
+ break;
181
187
  case "--title":
182
188
  options.title = requireValue(argv, index, arg);
183
189
  index += 1;
@@ -265,12 +271,15 @@ function parseArgs(argv) {
265
271
  throw new Error(`Unknown argument: ${arg}`);
266
272
  }
267
273
  }
268
- if (!options.agent.trim()) {
274
+ if (!options.resumeTaskId && !options.agent.trim()) {
269
275
  throw new Error("--agent is required");
270
276
  }
271
277
  if (!options.prompt.trim()) {
272
278
  throw new Error("--prompt is required");
273
279
  }
280
+ if (options.resumeTaskId !== void 0 && !options.resumeTaskId.trim()) {
281
+ throw new Error("--resume must be a non-empty task ID");
282
+ }
274
283
  return options;
275
284
  }
276
285
  function normalizeRef(value) {
@@ -449,10 +458,7 @@ function buildRequest(options, detected) {
449
458
  return CreateCiRunRequestSchema.parse(request);
450
459
  }
451
460
  function resolveBaseUrl(options) {
452
- const value = options.baseUrl || process.env.AGENTRIX_BASE_URL;
453
- if (!value) {
454
- throw new Error("Missing --base-url and AGENTRIX_BASE_URL");
455
- }
461
+ const value = options.baseUrl || process.env.AGENTRIX_BASE_URL || DEFAULT_AGENTRIX_BASE_URL;
456
462
  return value.replace(/\/+$/, "");
457
463
  }
458
464
  function resolveApiKey(options) {
@@ -483,6 +489,36 @@ async function createRun(baseUrl, apiKey, request) {
483
489
  const response = await requestJson("POST", `${baseUrl}/v1/ci/runs`, apiKey, request);
484
490
  return CreateCiRunResponseSchema.parse(response);
485
491
  }
492
+ function createPromptMessage(text) {
493
+ return {
494
+ type: "user",
495
+ message: {
496
+ role: "user",
497
+ content: text.trim()
498
+ },
499
+ parent_tool_use_id: null,
500
+ session_id: ""
501
+ };
502
+ }
503
+ function buildResumeMessageRequest(options) {
504
+ return {
505
+ message: createPromptMessage(options.prompt),
506
+ target: "agent",
507
+ senderType: "human",
508
+ senderId: "agentrix-run",
509
+ senderName: "agentrix-run",
510
+ responseMode: options.responseMode
511
+ };
512
+ }
513
+ async function sendResumeMessage(baseUrl, apiKey, taskId, request) {
514
+ const response = await requestJson(
515
+ "POST",
516
+ `${baseUrl}/v1/tasks/${encodeURIComponent(taskId)}/send-message`,
517
+ apiKey,
518
+ request
519
+ );
520
+ return SendTaskMessageResponseSchema.parse(response);
521
+ }
486
522
  function exitCodeForStatus(status) {
487
523
  return status === "completed" ? 0 : 1;
488
524
  }
@@ -567,12 +603,12 @@ function parseSseBlock(block) {
567
603
  data: JSON.parse(dataText)
568
604
  };
569
605
  }
570
- async function createRunStream(baseUrl, apiKey, request, deadline) {
606
+ async function streamRunRequest(baseUrl, apiKey, path, request, deadline) {
571
607
  const timeoutMs = Math.max(deadline - Date.now(), 1);
572
608
  const controller = new AbortController();
573
609
  const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
574
610
  try {
575
- const response = await fetch(`${baseUrl}/v1/ci/runs`, {
611
+ const response = await fetch(`${baseUrl}${path}`, {
576
612
  method: "POST",
577
613
  headers: {
578
614
  Authorization: `Bearer ${apiKey}`,
@@ -640,11 +676,44 @@ async function createRunStream(baseUrl, apiKey, request, deadline) {
640
676
  clearTimeout(timeoutHandle);
641
677
  }
642
678
  }
679
+ async function createRunStream(baseUrl, apiKey, request, deadline) {
680
+ return streamRunRequest(baseUrl, apiKey, "/v1/ci/runs", request, deadline);
681
+ }
682
+ async function resumeRunStream(baseUrl, apiKey, taskId, request, deadline) {
683
+ return streamRunRequest(
684
+ baseUrl,
685
+ apiKey,
686
+ `/v1/tasks/${encodeURIComponent(taskId)}/send-message`,
687
+ request,
688
+ deadline
689
+ );
690
+ }
643
691
  async function main(argv = process.argv.slice(2)) {
644
692
  const options = parseArgs(argv);
645
693
  const detected = detectCiContext();
646
694
  const baseUrl = resolveBaseUrl(options);
647
695
  const apiKey = resolveApiKey(options);
696
+ if (options.resumeTaskId) {
697
+ const taskId = options.resumeTaskId.trim();
698
+ const request2 = buildResumeMessageRequest(options);
699
+ if (options.responseMode === "async") {
700
+ const response = await sendResumeMessage(baseUrl, apiKey, taskId, request2);
701
+ if (!response.run) {
702
+ throw new Error("Server did not return CI run metadata for resumed task");
703
+ }
704
+ writeAsyncResultFile(options.resultFile, response.run);
705
+ printStandardFields({
706
+ runId: response.run.runId,
707
+ status: response.run.status,
708
+ detailUrl: response.run.detailUrl
709
+ });
710
+ return 0;
711
+ }
712
+ const deadline2 = ensureWaitDeadline(options);
713
+ const finalStatus2 = await resumeRunStream(baseUrl, apiKey, taskId, request2, deadline2);
714
+ writeResultFile(options.resultFile, finalStatus2);
715
+ return exitCodeForStatus(finalStatus2.status);
716
+ }
648
717
  const request = buildRequest(options, detected);
649
718
  if (options.responseMode === "async") {
650
719
  const run = await createRun(baseUrl, apiKey, request);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentrix/agentrix-run",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Native CI submit-and-observe wrapper for Agentrix",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  "prepublishOnly": "yarn build"
33
33
  },
34
34
  "dependencies": {
35
- "@agentrix/shared": "^2.32.0"
35
+ "@agentrix/shared": "^2.40.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": ">=20",