Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .agentworkforce/agents/relay-feature-guardian/agent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
import { resolveManifestPath } from './agent.ts';

const persona = JSON.parse(readFileSync(new URL('./persona.json', import.meta.url), 'utf8')) as {
inputs: { SLACK_CHANNEL: { default: string } };
};

describe('relay-feature-guardian runtime paths', () => {
it('reads the manifest from the cloned relay repository', () => {
expect(resolveManifestPath('/home/daytona/workspace')).toBe(
'/home/daytona/workspace/github/repos/AgentWorkforce/relay/.agentworkforce/features/manifest.yaml'
);
});

it('defaults delivery to the relay feature-check channel', () => {
expect(persona.inputs.SLACK_CHANNEL.default).toBe('C0AEKNLDNKW');
});
});
23 changes: 19 additions & 4 deletions .agentworkforce/agents/relay-feature-guardian/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* relay-feature-guardian handler.
*
* Hourly cron tick:
* 1. Read the feature list from .agentworkforce/features/manifest.yaml
* 1. Read the feature list from the cloned relay repository
* 2. Load feature progress from memory
* 3. Pick the next unchecked feature (ordered by criticality then tier)
* 4. Generate a concise quiz question via ctx.llm
Expand Down Expand Up @@ -55,9 +55,20 @@ interface Feature {
}

const MANIFEST_RELPATH = '.agentworkforce/features/manifest.yaml';
const RELAY_REPO_RELPATH = 'github/repos/AgentWorkforce/relay';

/**
* GitHub-scoped repositories are cloned beneath the proactive workspace root.
* WorkforceCtx currently exposes that workspace root (`sandbox.cwd`), but not
* an integration-specific repository directory, so derive the clone path from
* the documented `/github/repos/{owner}/{repo}` layout.
*/
export function resolveManifestPath(workspaceDir: string): string {
return `${workspaceDir}/${RELAY_REPO_RELPATH}/${MANIFEST_RELPATH}`;
}

async function loadFeatures(ctx: WorkforceCtx): Promise<Feature[]> {
const absPath = `${ctx.sandbox.cwd}/${MANIFEST_RELPATH}`;
const absPath = resolveManifestPath(ctx.sandbox.cwd);
const raw = await ctx.sandbox.readFile(absPath);
const manifest = parse(raw) as Manifest;
const features: Feature[] = [];
Expand Down Expand Up @@ -191,17 +202,21 @@ export default defineAgent({
try {
features = await loadFeatures(ctx);
} catch (err) {
const absPath = `${ctx.sandbox.cwd}/${MANIFEST_RELPATH}`;
const absPath = resolveManifestPath(ctx.sandbox.cwd);
ctx.log('error', 'relay-feature-guardian.manifest-load-failed', { path: absPath, err: String(err) });
const isNotFound = String(err).includes('ENOENT');
const errMsg = isNotFound
? `⚠️ *relay-feature-guardian* can't find the feature manifest at \`${MANIFEST_RELPATH}\`.\n\nThe \`feature/verify-features-workflow\` branch hasn't been merged to main yet — the sandbox runs on main, so the manifest doesn't exist. Merge PR #1283 to fix this.`
? `⚠️ *relay-feature-guardian* can't find the feature manifest in the cloned relay repository at \`${RELAY_REPO_RELPATH}/${MANIFEST_RELPATH}\`.`
: `⚠️ *relay-feature-guardian* failed to load the feature manifest: \`${String(err)}\``;
await slackClient()
.post(channel, errMsg)
.catch(() => undefined);
return;
}
ctx.log('info', 'relay-feature-guardian.manifest-loaded', {
path: resolveManifestPath(ctx.sandbox.cwd),
features: features.length,
});
if (features.length === 0) {
ctx.log('error', 'relay-feature-guardian.no-features', { reason: 'manifest parsed but empty' });
await slackClient()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
"timeoutSeconds": 300
},
"integrations": {
"github": {
"scope": {
"repo": "AgentWorkforce/relay"
}
},
"slack": {
"scope": {
"paths": "/slack/channels/**"
Expand All @@ -20,7 +25,7 @@
"SLACK_CHANNEL": {
"description": "Slack channel to post feature checks to (e.g. relay-health or general).",
"env": "SLACK_CHANNEL",
"default": "C0BHWJSF309",
"default": "C0AEKNLDNKW",
"picker": {
"provider": "slack",
"resource": "channels"
Expand Down
1 change: 1 addition & 0 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export default defineConfig({
environment: 'node',
setupFiles: [path.resolve(__dirname, './vitest.setup.ts')],
include: [
'.agentworkforce/agents/**/*.test.ts',
'tests/fixtures/**/*.test.ts',
'tests/integration/broker/evals/**/*.unit.test.ts',
'packages/**/src/**/*.test.ts',
Expand Down
Loading