aglio-worker 0.14.0 → 0.22.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 (2) hide show
  1. package/agent.js +69 -22
  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;
@@ -29850,10 +29887,13 @@ function parsePiLine(raw) {
29850
29887
  cost: message.usage.cost?.total
29851
29888
  } : void 0;
29852
29889
  const error62 = message.stopReason === "error" ? message.errorMessage ?? "Agent provider error" : void 0;
29890
+ const text = Array.isArray(message.content) ? message.content.map(
29891
+ (block) => block && typeof block === "object" && block.type === "text" ? String(block.text ?? "") : ""
29892
+ ).filter(Boolean).join("\n\n") : typeof message.content === "string" ? message.content : void 0;
29853
29893
  return {
29854
29894
  type,
29855
29895
  error: error62,
29856
- assistantText: typeof message.content === "string" ? message.content : void 0,
29896
+ assistantText: text || void 0,
29857
29897
  messageEnd: true,
29858
29898
  final: message.stopReason === "stop",
29859
29899
  at: timestampOf(message.timestamp) ?? timestampOf(raw.timestamp),
@@ -30470,6 +30510,7 @@ async function runRemoteCardJob(deps) {
30470
30510
  });
30471
30511
  const exit = await runAgent(command, env);
30472
30512
  if (deps.cancelled()) return { state: "cancelled", error: "Cancelled from the board" };
30513
+ await status({ finalMessage: exit.finalMessage });
30473
30514
  if (exit.error) return { state: "failed", error: exit.error };
30474
30515
  if (exit.sessionId) await status({ sessionId: exit.sessionId, usage: exit.usage });
30475
30516
  if (context.card && (context.run.kind === "build" || context.run.kind === "consult")) {
@@ -30780,6 +30821,7 @@ async function runRemoteCardJob(deps) {
30780
30821
  let messageSeq = 0;
30781
30822
  let lastFlushAt = 0;
30782
30823
  let chatMessageId = null;
30824
+ let finalMessage = "";
30783
30825
  let toolCalls = 0;
30784
30826
  let consumeQueue = Promise.resolve();
30785
30827
  const isPlanning = context.run.kind === "planning";
@@ -30865,10 +30907,12 @@ async function runRemoteCardJob(deps) {
30865
30907
  }
30866
30908
  if (parsed.messageEnd) {
30867
30909
  await flushAssistant(true);
30910
+ finalMessage = text || messageText;
30868
30911
  messageText = "";
30869
30912
  messageSeq += 1;
30870
30913
  chatMessageId = null;
30871
30914
  } else if (!parsed.assistantDelta) {
30915
+ finalMessage = text;
30872
30916
  messageSeq += 1;
30873
30917
  chatMessageId = null;
30874
30918
  }
@@ -30923,18 +30967,20 @@ async function runRemoteCardJob(deps) {
30923
30967
  });
30924
30968
  await consumeQueue;
30925
30969
  await flushAssistant(true);
30970
+ if (!finalMessage && messageText) finalMessage = messageText;
30926
30971
  clearTimeout(timeout);
30927
30972
  deps.signal.removeEventListener("abort", forwardAbort);
30928
- if (deps.cancelled()) return { error: null, sessionId, usage: usagePatch };
30929
- if (error62) return { error: error62, sessionId, usage: usagePatch };
30973
+ if (deps.cancelled()) return { error: null, sessionId, finalMessage, usage: usagePatch };
30974
+ if (error62) return { error: error62, sessionId, finalMessage, usage: usagePatch };
30930
30975
  if (code !== 0 && !final && !timedOut) {
30931
30976
  return {
30932
30977
  error: stderr.trim().slice(-2e3) || `Agent exited with code ${code}`,
30933
30978
  sessionId,
30979
+ finalMessage,
30934
30980
  usage: usagePatch
30935
30981
  };
30936
30982
  }
30937
- return { error: null, sessionId, usage: usagePatch };
30983
+ return { error: null, sessionId, finalMessage, usage: usagePatch };
30938
30984
  }
30939
30985
  }
30940
30986
 
@@ -43699,7 +43745,7 @@ function createServerForRun(run) {
43699
43745
  server.registerTool(
43700
43746
  "verification_record",
43701
43747
  {
43702
- description: "Record mandatory verification evidence before opening a PR. Non-N/A kinds require an artifactId. N/A requires a reason.",
43748
+ 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
43749
  inputSchema: {
43704
43750
  kind: external_exports.enum(VERIFICATION_KINDS),
43705
43751
  summary: external_exports.string().min(1).max(400),
@@ -43776,7 +43822,7 @@ function createServerForRun(run) {
43776
43822
  server.registerTool(
43777
43823
  "pr_open",
43778
43824
  {
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.",
43825
+ 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
43826
  inputSchema: {
43781
43827
  repoId: external_exports.string().min(1),
43782
43828
  branch: external_exports.string().min(1),
@@ -43902,10 +43948,11 @@ async function main() {
43902
43948
  const mcpPort = Number(process.env.AGLIO_WORKER_MCP_PORT ?? 4310);
43903
43949
  const claimTimeoutRaw = Number(process.env.AGLIO_WORKER_CLAIM_TIMEOUT_SECONDS);
43904
43950
  const claimTimeoutSeconds = Number.isFinite(claimTimeoutRaw) && claimTimeoutRaw > 0 ? claimTimeoutRaw : void 0;
43905
- const agentContainerId = process.env.HOSTNAME?.trim() || hostname3();
43951
+ const containerized = isRunningInContainer();
43952
+ const agentContainerId = (containerized ? readAgentContainerId() : null) || process.env.HOSTNAME?.trim() || hostname3();
43906
43953
  const runnerNetwork = mode === "docker" ? resolveRunnerNetworkMode({
43907
43954
  override: process.env.AGLIO_WORKER_RUNNER_NETWORK,
43908
- containerized: isRunningInContainer(),
43955
+ containerized,
43909
43956
  hostname: agentContainerId
43910
43957
  }) : "host";
43911
43958
  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.1",
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": {