refactor: centralize task runtime contracts (#199)
This commit is contained in:
@@ -10,10 +10,16 @@ import { z } from 'zod';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { CronExpressionParser } from 'cron-parser';
|
||||
import { EJCLAW_ENV, normalizePairedRoomRole } from 'ejclaw-runners-shared';
|
||||
import {
|
||||
DEFAULT_SCHEDULE_TASK_CONTEXT_MODE,
|
||||
DEFAULT_TASK_CONTEXT_MODE,
|
||||
DEFAULT_WATCH_CI_CONTEXT_MODE,
|
||||
EJCLAW_ENV,
|
||||
TASK_CONTEXT_MODES,
|
||||
normalizePairedRoomRole,
|
||||
} from 'ejclaw-runners-shared';
|
||||
import {
|
||||
buildCiWatchPrompt,
|
||||
DEFAULT_WATCH_CI_CONTEXT_MODE,
|
||||
normalizeWatchCiIntervalSeconds,
|
||||
} from './watch-ci.js';
|
||||
import { resolveHostEvidenceResponsesDir } from './host-evidence.js';
|
||||
@@ -142,10 +148,10 @@ SCHEDULE VALUE FORMAT (all times are LOCAL timezone):
|
||||
'cron: "*/5 * * * *" | interval: milliseconds like "300000" | once: local timestamp like "2026-02-01T15:30:00" (no Z suffix!)',
|
||||
),
|
||||
context_mode: z
|
||||
.enum(['group', 'isolated'])
|
||||
.default('group')
|
||||
.enum(TASK_CONTEXT_MODES)
|
||||
.default(DEFAULT_SCHEDULE_TASK_CONTEXT_MODE)
|
||||
.describe(
|
||||
'group=runs with chat history and memory, isolated=fresh session (include context in prompt)',
|
||||
'group=runs with chat history and memory, isolated=fresh session (include context in prompt). Default: group.',
|
||||
),
|
||||
target_group_jid: z
|
||||
.string()
|
||||
@@ -226,7 +232,7 @@ SCHEDULE VALUE FORMAT (all times are LOCAL timezone):
|
||||
schedule_value: args.schedule_value,
|
||||
agent_type: currentAgentType(),
|
||||
room_role: currentRoomRole(),
|
||||
context_mode: args.context_mode || 'group',
|
||||
context_mode: args.context_mode || DEFAULT_SCHEDULE_TASK_CONTEXT_MODE,
|
||||
targetJid,
|
||||
createdBy: groupFolder,
|
||||
timestamp: new Date().toISOString(),
|
||||
@@ -300,7 +306,7 @@ server.tool(
|
||||
'How often to poll in seconds. Defaults to 60 for generic watchers and 15 for GitHub host-driven watchers. Generic watchers require 30+, GitHub host-driven watchers allow 10+.',
|
||||
),
|
||||
context_mode: z
|
||||
.enum(['group', 'isolated'])
|
||||
.enum(TASK_CONTEXT_MODES)
|
||||
.default(DEFAULT_WATCH_CI_CONTEXT_MODE)
|
||||
.describe(
|
||||
'group=runs with chat history and memory, isolated=fresh session (include all context in check_instructions). Default: isolated.',
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import {
|
||||
DEFAULT_WATCH_CI_CONTEXT_MODE,
|
||||
WATCH_CI_PROMPT_PREFIX,
|
||||
} from 'ejclaw-runners-shared';
|
||||
|
||||
export const DEFAULT_WATCH_CI_INTERVAL_SECONDS = 60;
|
||||
export const MIN_WATCH_CI_INTERVAL_SECONDS = 30;
|
||||
export const DEFAULT_GITHUB_WATCH_CI_INTERVAL_SECONDS = 15;
|
||||
export const MIN_GITHUB_WATCH_CI_INTERVAL_SECONDS = 10;
|
||||
export const MAX_WATCH_CI_INTERVAL_SECONDS = 3600;
|
||||
export const DEFAULT_WATCH_CI_CONTEXT_MODE = 'isolated';
|
||||
|
||||
export interface NormalizeWatchCiIntervalOptions {
|
||||
ciProvider?: 'github';
|
||||
@@ -48,7 +52,7 @@ export function buildCiWatchPrompt({
|
||||
checkInstructions,
|
||||
}: BuildCiWatchPromptArgs): string {
|
||||
return `
|
||||
[BACKGROUND CI WATCH]
|
||||
${WATCH_CI_PROMPT_PREFIX}
|
||||
|
||||
You are running as an EJClaw background CI watcher.
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
DEFAULT_WATCH_CI_CONTEXT_MODE,
|
||||
WATCH_CI_PROMPT_PREFIX,
|
||||
} from 'ejclaw-runners-shared';
|
||||
|
||||
import {
|
||||
buildCiWatchPrompt,
|
||||
DEFAULT_WATCH_CI_CONTEXT_MODE,
|
||||
DEFAULT_GITHUB_WATCH_CI_INTERVAL_SECONDS,
|
||||
normalizeWatchCiIntervalSeconds,
|
||||
} from '../src/watch-ci.js';
|
||||
@@ -16,6 +19,7 @@ describe('watch-ci helpers', () => {
|
||||
});
|
||||
|
||||
expect(prompt).toContain('PR #42 checks');
|
||||
expect(prompt.startsWith(WATCH_CI_PROMPT_PREFIX)).toBe(true);
|
||||
expect(prompt).not.toContain('Task ID:');
|
||||
expect(prompt).toContain('cancel_task');
|
||||
expect(prompt).toContain('send_message');
|
||||
|
||||
@@ -27,6 +27,16 @@ export {
|
||||
type GitHubEvidenceAction,
|
||||
type HostEvidenceAction,
|
||||
} from './evidence-actions.js';
|
||||
export {
|
||||
DEFAULT_SCHEDULE_TASK_CONTEXT_MODE,
|
||||
DEFAULT_TASK_CONTEXT_MODE,
|
||||
DEFAULT_WATCH_CI_CONTEXT_MODE,
|
||||
TASK_CONTEXT_MODES,
|
||||
WATCH_CI_PROMPT_PREFIX,
|
||||
isTaskContextMode,
|
||||
normalizeTaskContextMode,
|
||||
type TaskContextMode,
|
||||
} from './task-runtime.js';
|
||||
export {
|
||||
extractMarkdownImageAttachments,
|
||||
extractMediaAttachments,
|
||||
|
||||
18
runners/shared/src/task-runtime.ts
Normal file
18
runners/shared/src/task-runtime.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export const TASK_CONTEXT_MODES = ['group', 'isolated'] as const;
|
||||
export type TaskContextMode = (typeof TASK_CONTEXT_MODES)[number];
|
||||
|
||||
export const DEFAULT_TASK_CONTEXT_MODE: TaskContextMode = 'isolated';
|
||||
export const DEFAULT_SCHEDULE_TASK_CONTEXT_MODE: TaskContextMode = 'group';
|
||||
export const DEFAULT_WATCH_CI_CONTEXT_MODE: TaskContextMode = 'isolated';
|
||||
export const WATCH_CI_PROMPT_PREFIX = '[BACKGROUND CI WATCH]';
|
||||
|
||||
export function isTaskContextMode(value: unknown): value is TaskContextMode {
|
||||
return value === 'group' || value === 'isolated';
|
||||
}
|
||||
|
||||
export function normalizeTaskContextMode(
|
||||
value: unknown,
|
||||
fallback: TaskContextMode = DEFAULT_TASK_CONTEXT_MODE,
|
||||
): TaskContextMode {
|
||||
return isTaskContextMode(value) ? value : fallback;
|
||||
}
|
||||
32
runners/shared/test/task-runtime.test.ts
Normal file
32
runners/shared/test/task-runtime.test.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
DEFAULT_SCHEDULE_TASK_CONTEXT_MODE,
|
||||
DEFAULT_TASK_CONTEXT_MODE,
|
||||
DEFAULT_WATCH_CI_CONTEXT_MODE,
|
||||
TASK_CONTEXT_MODES,
|
||||
WATCH_CI_PROMPT_PREFIX,
|
||||
isTaskContextMode,
|
||||
normalizeTaskContextMode,
|
||||
} from '../src/task-runtime.js';
|
||||
|
||||
describe('task runtime constants', () => {
|
||||
it('defines the task context modes and default', () => {
|
||||
expect(TASK_CONTEXT_MODES).toEqual(['group', 'isolated']);
|
||||
expect(DEFAULT_TASK_CONTEXT_MODE).toBe('isolated');
|
||||
expect(DEFAULT_SCHEDULE_TASK_CONTEXT_MODE).toBe('group');
|
||||
expect(DEFAULT_WATCH_CI_CONTEXT_MODE).toBe('isolated');
|
||||
});
|
||||
|
||||
it('normalizes task context modes consistently', () => {
|
||||
expect(isTaskContextMode('group')).toBe(true);
|
||||
expect(isTaskContextMode('isolated')).toBe(true);
|
||||
expect(isTaskContextMode('invalid')).toBe(false);
|
||||
expect(normalizeTaskContextMode('group')).toBe('group');
|
||||
expect(normalizeTaskContextMode('invalid')).toBe('isolated');
|
||||
});
|
||||
|
||||
it('defines the watch CI prompt sentinel', () => {
|
||||
expect(WATCH_CI_PROMPT_PREFIX).toBe('[BACKGROUND CI WATCH]');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user