aglio-worker 0.14.0 → 0.22.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.
Files changed (2) hide show
  1. package/agent.js +65 -21
  2. package/package.json +1 -1
package/agent.js CHANGED
@@ -27378,6 +27378,20 @@ var autoClaimScheduleSchema = external_exports.object({
27378
27378
  start: autoClaimTimeSchema.default("00:00"),
27379
27379
  end: autoClaimTimeSchema.default("00:00")
27380
27380
  }).default({ enabled: false, timezone: "UTC", days: [0, 1, 2, 3, 4, 5, 6], start: "00:00", end: "00:00" });
27381
+ var routingLabelsSchema = external_exports.array(external_exports.string()).max(16).superRefine((labels, ctx) => {
27382
+ try {
27383
+ validateRoutingLabels(labels);
27384
+ } catch (error62) {
27385
+ ctx.addIssue({
27386
+ code: "custom",
27387
+ message: error62 instanceof Error ? error62.message : "Invalid worker labels."
27388
+ });
27389
+ }
27390
+ });
27391
+ var cardRoutingOverrideSchema = external_exports.object({
27392
+ requiredWorkerLabels: routingLabelsSchema.nullable().optional(),
27393
+ planningRequiredWorkerLabels: routingLabelsSchema.nullable().optional()
27394
+ });
27381
27395
  var projectSettingsSchema = external_exports.object({
27382
27396
  /** Demo projects are sandbox rows: the worker never claims them and no model runs. */
27383
27397
  demoMode: external_exports.boolean().default(false),
@@ -27402,23 +27416,20 @@ var projectSettingsSchema = external_exports.object({
27402
27416
  runRetryBackoffSeconds: external_exports.number().int().min(10).max(600).default(60),
27403
27417
  runRetryMaxBackoffSeconds: external_exports.number().int().min(60).max(3600).default(600),
27404
27418
  notificationSound: external_exports.boolean().default(true),
27419
+ /** Null inherits the workspace default. True or false overrides it for this project. */
27420
+ requireVerificationEvidence: external_exports.boolean().nullable().default(null),
27405
27421
  /** Slack incoming webhook for question, failure and PR-ready alerts. Null disables Slack. */
27406
27422
  slackWebhookUrl: external_exports.string().trim().max(500).refine(isSlackWebhookUrl, "Slack webhook must be an https URL").nullable().default(null),
27407
27423
  /** Rendered column strip: built-in columns and custom list ids. */
27408
27424
  boardColumnOrder: external_exports.array(external_exports.string()).optional(),
27409
27425
  /** Last repository connectivity check from Project settings or the worker gate. */
27410
27426
  repoConnection: repoConnectionReportSchema.nullish(),
27411
- /** Worker labels every job in this project needs. Empty means any worker. */
27412
- requiredWorkerLabels: external_exports.array(external_exports.string()).max(16).default([]).superRefine((labels, ctx) => {
27413
- try {
27414
- validateRoutingLabels(labels);
27415
- } catch (error62) {
27416
- ctx.addIssue({
27417
- code: "custom",
27418
- message: error62 instanceof Error ? error62.message : "Invalid worker labels."
27419
- });
27420
- }
27421
- })
27427
+ /** Build, consult and review job labels. Empty means any worker. */
27428
+ requiredWorkerLabels: routingLabelsSchema.default([]),
27429
+ /** Planning job labels. Empty means any online worker, so planning never waits on a build machine. */
27430
+ planningRequiredWorkerLabels: routingLabelsSchema.default([]),
27431
+ /** Undefined inherits the workspace switch. True or false overrides it. */
27432
+ postBuildReply: external_exports.boolean().optional()
27422
27433
  });
27423
27434
  var repoConfigSchema = external_exports.object({
27424
27435
  id: external_exports.string(),
@@ -27671,6 +27682,18 @@ function artifactFileName(id, label) {
27671
27682
  return `${id}-${sanitizeFileName(label)}`;
27672
27683
  }
27673
27684
 
27685
+ // ../../packages/shared/src/feedback.ts
27686
+ var FEEDBACK_TYPES = ["bug", "feature"];
27687
+ var FEEDBACK_MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;
27688
+ var FEEDBACK_RATE_WINDOW_MS = 60 * 60 * 1e3;
27689
+ var feedbackTypeSchema = external_exports.enum(FEEDBACK_TYPES);
27690
+ var feedbackInputSchema = external_exports.object({
27691
+ type: feedbackTypeSchema,
27692
+ title: external_exports.string().trim().min(5, "Title must be at least 5 characters").max(140, "Title must be 140 characters or fewer"),
27693
+ description: external_exports.string().trim().min(10, "Description must be at least 10 characters").max(5e3, "Description must be 5000 characters or fewer"),
27694
+ pageUrl: external_exports.string().trim().max(500, "Page URL must be 500 characters or fewer").refine((value) => value === "" || URL.canParse(value), "Page URL must be a valid URL").optional().default("")
27695
+ });
27696
+
27674
27697
  // ../../packages/shared/src/providers.ts
27675
27698
  var apiKey = (env, drivers, label = "API key") => ({
27676
27699
  type: "api_key",
@@ -28161,7 +28184,9 @@ var WORKSPACE_SETTINGS_DEFAULTS = {
28161
28184
  artifactRetentionDays: 0,
28162
28185
  defaultGitProvider: "github",
28163
28186
  /** The shared workspace consultant is opt-out. Disabled hides every entry point. */
28164
- consultantEnabled: true
28187
+ consultantEnabled: true,
28188
+ /** Post the agent's exact final build message as a card comment. */
28189
+ postBuildReply: true
28165
28190
  };
28166
28191
  var workspaceSettingsSchema = external_exports.object({
28167
28192
  allowMemberInvites: external_exports.boolean().catch(WORKSPACE_SETTINGS_DEFAULTS.allowMemberInvites),
@@ -28169,7 +28194,8 @@ var workspaceSettingsSchema = external_exports.object({
28169
28194
  requireVerificationEvidence: external_exports.boolean().catch(WORKSPACE_SETTINGS_DEFAULTS.requireVerificationEvidence),
28170
28195
  artifactRetentionDays: external_exports.number().int().min(0).max(3650).catch(WORKSPACE_SETTINGS_DEFAULTS.artifactRetentionDays),
28171
28196
  defaultGitProvider: external_exports.string().optional().transform((value) => normalizeGitProvider(value)).catch(WORKSPACE_SETTINGS_DEFAULTS.defaultGitProvider),
28172
- consultantEnabled: external_exports.boolean().catch(WORKSPACE_SETTINGS_DEFAULTS.consultantEnabled)
28197
+ consultantEnabled: external_exports.boolean().catch(WORKSPACE_SETTINGS_DEFAULTS.consultantEnabled),
28198
+ postBuildReply: external_exports.boolean().catch(WORKSPACE_SETTINGS_DEFAULTS.postBuildReply)
28173
28199
  }).passthrough();
28174
28200
 
28175
28201
  // ../../packages/shared/src/theme.ts
@@ -28252,7 +28278,7 @@ var CARD_OPEN_SIZES = ["default", "large", "fullscreen"];
28252
28278
  var cardOpenSizeSchema = external_exports.enum(CARD_OPEN_SIZES);
28253
28279
 
28254
28280
  // src/remote-docker.ts
28255
- import { existsSync } from "node:fs";
28281
+ import { existsSync, readFileSync as readFileSync2 } from "node:fs";
28256
28282
  import { PassThrough } from "node:stream";
28257
28283
  import { join as join2, posix, relative, resolve } from "node:path";
28258
28284
  import Dockerode from "dockerode";
@@ -28477,6 +28503,17 @@ var CONTAINER_WORKSPACE = "/workspace";
28477
28503
  function isRunningInContainer() {
28478
28504
  return existsSync("/.dockerenv") || existsSync("/run/.containerenv");
28479
28505
  }
28506
+ function parseAgentContainerId(mountInfo) {
28507
+ const match = mountInfo.match(/containers\/([0-9a-f]{64})\/(?:hostname|hosts|resolv\.conf)/);
28508
+ return match?.[1] ?? null;
28509
+ }
28510
+ function readAgentContainerId() {
28511
+ try {
28512
+ return parseAgentContainerId(readFileSync2("/proc/self/mountinfo", "utf8"));
28513
+ } catch {
28514
+ return null;
28515
+ }
28516
+ }
28480
28517
  function resolveRunnerNetworkMode(input2) {
28481
28518
  const override = input2.override?.trim();
28482
28519
  if (override) return override;
@@ -30470,6 +30507,7 @@ async function runRemoteCardJob(deps) {
30470
30507
  });
30471
30508
  const exit = await runAgent(command, env);
30472
30509
  if (deps.cancelled()) return { state: "cancelled", error: "Cancelled from the board" };
30510
+ await status({ finalMessage: exit.finalMessage });
30473
30511
  if (exit.error) return { state: "failed", error: exit.error };
30474
30512
  if (exit.sessionId) await status({ sessionId: exit.sessionId, usage: exit.usage });
30475
30513
  if (context.card && (context.run.kind === "build" || context.run.kind === "consult")) {
@@ -30780,6 +30818,7 @@ async function runRemoteCardJob(deps) {
30780
30818
  let messageSeq = 0;
30781
30819
  let lastFlushAt = 0;
30782
30820
  let chatMessageId = null;
30821
+ let finalMessage = "";
30783
30822
  let toolCalls = 0;
30784
30823
  let consumeQueue = Promise.resolve();
30785
30824
  const isPlanning = context.run.kind === "planning";
@@ -30865,10 +30904,12 @@ async function runRemoteCardJob(deps) {
30865
30904
  }
30866
30905
  if (parsed.messageEnd) {
30867
30906
  await flushAssistant(true);
30907
+ finalMessage = text || messageText;
30868
30908
  messageText = "";
30869
30909
  messageSeq += 1;
30870
30910
  chatMessageId = null;
30871
30911
  } else if (!parsed.assistantDelta) {
30912
+ finalMessage = text;
30872
30913
  messageSeq += 1;
30873
30914
  chatMessageId = null;
30874
30915
  }
@@ -30923,18 +30964,20 @@ async function runRemoteCardJob(deps) {
30923
30964
  });
30924
30965
  await consumeQueue;
30925
30966
  await flushAssistant(true);
30967
+ if (!finalMessage && messageText) finalMessage = messageText;
30926
30968
  clearTimeout(timeout);
30927
30969
  deps.signal.removeEventListener("abort", forwardAbort);
30928
- if (deps.cancelled()) return { error: null, sessionId, usage: usagePatch };
30929
- if (error62) return { error: error62, sessionId, usage: usagePatch };
30970
+ if (deps.cancelled()) return { error: null, sessionId, finalMessage, usage: usagePatch };
30971
+ if (error62) return { error: error62, sessionId, finalMessage, usage: usagePatch };
30930
30972
  if (code !== 0 && !final && !timedOut) {
30931
30973
  return {
30932
30974
  error: stderr.trim().slice(-2e3) || `Agent exited with code ${code}`,
30933
30975
  sessionId,
30976
+ finalMessage,
30934
30977
  usage: usagePatch
30935
30978
  };
30936
30979
  }
30937
- return { error: null, sessionId, usage: usagePatch };
30980
+ return { error: null, sessionId, finalMessage, usage: usagePatch };
30938
30981
  }
30939
30982
  }
30940
30983
 
@@ -43699,7 +43742,7 @@ function createServerForRun(run) {
43699
43742
  server.registerTool(
43700
43743
  "verification_record",
43701
43744
  {
43702
- description: "Record mandatory verification evidence before opening a PR. Non-N/A kinds require an artifactId. N/A requires a reason.",
43745
+ description: "Record verification evidence before opening a PR. Non-N/A kinds require an artifactId unless this project or its workspace made evidence optional. N/A requires a reason.",
43703
43746
  inputSchema: {
43704
43747
  kind: external_exports.enum(VERIFICATION_KINDS),
43705
43748
  summary: external_exports.string().min(1).max(400),
@@ -43776,7 +43819,7 @@ function createServerForRun(run) {
43776
43819
  server.registerTool(
43777
43820
  "pr_open",
43778
43821
  {
43779
- description: "Push the branch and open a pull request for one repo. Requires verification evidence unless the workspace relaxed the rule. Moves the card to review.",
43822
+ description: "Push the branch and open a pull request for one repo. Requires verification evidence unless this project or its workspace made evidence optional. Moves the card to review.",
43780
43823
  inputSchema: {
43781
43824
  repoId: external_exports.string().min(1),
43782
43825
  branch: external_exports.string().min(1),
@@ -43902,10 +43945,11 @@ async function main() {
43902
43945
  const mcpPort = Number(process.env.AGLIO_WORKER_MCP_PORT ?? 4310);
43903
43946
  const claimTimeoutRaw = Number(process.env.AGLIO_WORKER_CLAIM_TIMEOUT_SECONDS);
43904
43947
  const claimTimeoutSeconds = Number.isFinite(claimTimeoutRaw) && claimTimeoutRaw > 0 ? claimTimeoutRaw : void 0;
43905
- const agentContainerId = process.env.HOSTNAME?.trim() || hostname3();
43948
+ const containerized = isRunningInContainer();
43949
+ const agentContainerId = (containerized ? readAgentContainerId() : null) || process.env.HOSTNAME?.trim() || hostname3();
43906
43950
  const runnerNetwork = mode === "docker" ? resolveRunnerNetworkMode({
43907
43951
  override: process.env.AGLIO_WORKER_RUNNER_NETWORK,
43908
- containerized: isRunningInContainer(),
43952
+ containerized,
43909
43953
  hostname: agentContainerId
43910
43954
  }) : "host";
43911
43955
  const containerMcpUrl = runnerMcpUrl({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aglio-worker",
3
- "version": "0.14.0",
3
+ "version": "0.22.0",
4
4
  "description": "Host machine agent for Aglio: claims jobs over the API and starts aglio-runner containers.",
5
5
  "type": "module",
6
6
  "bin": {