u
This commit is contained in:
6
API.md
6
API.md
@@ -381,3 +381,9 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
||||
- `create(googleAuthId: number, input: {accountId: number, manifestId: number, type: string, amount: number}, tx?: object): Promise<{id: number, accountId: number, manifestId: number, type: string, amount: number}>`
|
||||
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
||||
- `listByManifestId(googleAuthId: number, manifestId: number, tx?: object): Promise<Array<{id: number, accountId: number, manifestId: number, type: string, amount: number}>>`
|
||||
- [subagentschedule](API.subagentschedule.md)
|
||||
- `create(googleAuthId: number, input: {prompt: string, cron: string, desc?: string, skills?: string|Array<string>, lastagentnote?: string, max_itr?: number}, tx?: object): Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>`
|
||||
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
||||
- `getById(googleAuthId: number, id: number, tx?: object): Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}|null>`
|
||||
- `list(googleAuthId: number, tx?: object): Promise<Array<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>>`
|
||||
- `update(googleAuthId: number, id: number, input: {prompt?: string, cron?: string, desc?: string|null, skills?: string|Array<string>|null, lastagentnote?: string|null, max_itr?: number, lastrun_at?: string|null}, tx?: object): Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>`
|
||||
|
||||
130
API.subagentschedule.md
Normal file
130
API.subagentschedule.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# subagentschedule
|
||||
|
||||
This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.
|
||||
|
||||
## `subagentschedule.create`
|
||||
|
||||
*Source: `src/store/subagentschedule/create.js`*
|
||||
|
||||
Creates a new subagent schedule for the user's selected company.
|
||||
|
||||
**Parameters**
|
||||
|
||||
| Name | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||
| `input` | `object` | Schedule input. |
|
||||
| `input.prompt` | `string` | The task prompt for the subagent. |
|
||||
| `input.cron` | `string` | Standard 5-field cron timetable string. |
|
||||
| `[input.desc]` | `string` | Optional schedule description. |
|
||||
| `[input.skills]` | `string|Array<string>` | Optional skill names or JSON string. |
|
||||
| `[input.lastagentnote]` | `string` | Optional initial agent note. |
|
||||
| `[input.max_itr=15]` | `number` | Optional max iterations per run. |
|
||||
| `[tx]` | `object` | Optional transaction to run within. |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>`
|
||||
|
||||
**Throws**
|
||||
|
||||
`Error` — If prompt is missing, cron is invalid, or max_itr is invalid.
|
||||
|
||||
**Example**
|
||||
|
||||
```js
|
||||
const schedule = await store.subagentschedule.create(googleAuthId, {
|
||||
desc: 'Nightly inventory audit',
|
||||
prompt: 'Check stock discrepancies across all warehouses and summarize.',
|
||||
cron: '0 2 * * *',
|
||||
skills: ['stock', 'reporting'],
|
||||
max_itr: 20,
|
||||
});
|
||||
```
|
||||
|
||||
## `subagentschedule.delete`
|
||||
|
||||
*Source: `src/store/subagentschedule/delete.js`*
|
||||
|
||||
Deletes a subagent schedule by id for the user's selected company.
|
||||
|
||||
**Parameters**
|
||||
|
||||
| Name | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||
| `id` | `number` | The schedule ID to delete. |
|
||||
| `[tx]` | `object` | Optional transaction to run within. |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<void>`
|
||||
|
||||
**Throws**
|
||||
|
||||
`Error` — If schedule not found.
|
||||
|
||||
## `subagentschedule.getById`
|
||||
|
||||
*Source: `src/store/subagentschedule/getById.js`*
|
||||
|
||||
Retrieves a single subagent schedule by id for the user's selected company.
|
||||
|
||||
**Parameters**
|
||||
|
||||
| Name | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||
| `id` | `number` | The schedule ID. |
|
||||
| `[tx]` | `object` | Optional transaction to run within. |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}|null>`
|
||||
|
||||
## `subagentschedule.list`
|
||||
|
||||
*Source: `src/store/subagentschedule/list.js`*
|
||||
|
||||
Lists all subagent schedules for the user's selected company.
|
||||
|
||||
**Parameters**
|
||||
|
||||
| Name | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||
| `[tx]` | `object` | Optional transaction to run within. |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<Array<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>>`
|
||||
|
||||
## `subagentschedule.update`
|
||||
|
||||
*Source: `src/store/subagentschedule/update.js`*
|
||||
|
||||
Updates an existing subagent schedule for the user's selected company.
|
||||
|
||||
**Parameters**
|
||||
|
||||
| Name | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||
| `id` | `number` | The schedule ID to update. |
|
||||
| `input` | `object` | Update payload. |
|
||||
| `[input.prompt]` | `string` | Optional updated task prompt. |
|
||||
| `[input.cron]` | `string` | Optional updated cron expression. |
|
||||
| `[input.desc]` | `string|null` | Optional updated description. |
|
||||
| `[input.skills]` | `string|Array<string>|null` | Optional updated skills. |
|
||||
| `[input.lastagentnote]` | `string|null` | Optional updated agent note. |
|
||||
| `[input.max_itr]` | `number` | Optional updated max iterations. |
|
||||
| `[input.lastrun_at]` | `string|null` | Optional updated last run timestamp. |
|
||||
| `[tx]` | `object` | Optional transaction to run within. |
|
||||
|
||||
**Returns**
|
||||
|
||||
`Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>`
|
||||
|
||||
**Throws**
|
||||
|
||||
`Error` — If schedule not found, prompt is empty, cron is invalid, or max_itr is invalid.
|
||||
@@ -76,6 +76,7 @@ const INTERNAL_FILES = new Set([
|
||||
'createStore.js',
|
||||
'manifestLines.js',
|
||||
'runner.js',
|
||||
'cron.js',
|
||||
'index.js',
|
||||
]);
|
||||
|
||||
|
||||
13
src/index.js
13
src/index.js
@@ -183,6 +183,11 @@ import modelvfsRead from './store/modelvfs/read.js';
|
||||
import modelvfsList from './store/modelvfs/list.js';
|
||||
import modelvfsDelete from './store/modelvfs/delete.js';
|
||||
import modelvfsReset from './store/modelvfs/reset.js';
|
||||
import subagentscheduleCreate from './store/subagentschedule/create.js';
|
||||
import subagentscheduleGetById from './store/subagentschedule/getById.js';
|
||||
import subagentscheduleList from './store/subagentschedule/list.js';
|
||||
import subagentscheduleUpdate from './store/subagentschedule/update.js';
|
||||
import subagentscheduleDelete from './store/subagentschedule/delete.js';
|
||||
import accountCreate from './store/account/create.js';
|
||||
import accountList from './store/account/list.js';
|
||||
import accountDelete from './store/account/delete.js';
|
||||
@@ -584,6 +589,14 @@ export default class LibDashStore {
|
||||
add: modelmessageAdd(provider),
|
||||
};
|
||||
|
||||
this.subagentschedule = {
|
||||
create: subagentscheduleCreate(provider),
|
||||
getById: subagentscheduleGetById(provider),
|
||||
list: subagentscheduleList(provider),
|
||||
update: subagentscheduleUpdate(provider),
|
||||
delete: subagentscheduleDelete(provider),
|
||||
};
|
||||
|
||||
this.labeltemplate = {
|
||||
create: labeltemplateCreate(provider),
|
||||
getById: labeltemplateGetById(provider),
|
||||
|
||||
88
src/providers/mssql/queries/subagentschedule.js
Normal file
88
src/providers/mssql/queries/subagentschedule.js
Normal file
@@ -0,0 +1,88 @@
|
||||
export const SUBAGENTSCHEDULE_COLUMNS = `
|
||||
id,
|
||||
company_id,
|
||||
[desc],
|
||||
prompt,
|
||||
skills,
|
||||
lastagentnote,
|
||||
max_itr,
|
||||
cron,
|
||||
created_at,
|
||||
lastrun_at
|
||||
`;
|
||||
|
||||
export const LIST_BY_COMPANY = `
|
||||
SELECT
|
||||
${SUBAGENTSCHEDULE_COLUMNS}
|
||||
FROM subagentschedule
|
||||
WHERE company_id = @companyId
|
||||
ORDER BY id ASC
|
||||
`;
|
||||
|
||||
export const GET_BY_COMPANY_AND_ID = `
|
||||
SELECT
|
||||
${SUBAGENTSCHEDULE_COLUMNS}
|
||||
FROM subagentschedule
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
export const CREATE = `
|
||||
INSERT INTO subagentschedule (
|
||||
company_id,
|
||||
[desc],
|
||||
prompt,
|
||||
skills,
|
||||
lastagentnote,
|
||||
max_itr,
|
||||
cron
|
||||
)
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.company_id,
|
||||
INSERTED.[desc],
|
||||
INSERTED.prompt,
|
||||
INSERTED.skills,
|
||||
INSERTED.lastagentnote,
|
||||
INSERTED.max_itr,
|
||||
INSERTED.cron,
|
||||
INSERTED.created_at,
|
||||
INSERTED.lastrun_at
|
||||
VALUES (
|
||||
@companyId,
|
||||
@desc,
|
||||
@prompt,
|
||||
@skills,
|
||||
@lastagentnote,
|
||||
@maxItr,
|
||||
@cron
|
||||
)
|
||||
`;
|
||||
|
||||
export const UPDATE = `
|
||||
UPDATE subagentschedule
|
||||
SET
|
||||
[desc] = @desc,
|
||||
prompt = @prompt,
|
||||
skills = @skills,
|
||||
lastagentnote = @lastagentnote,
|
||||
max_itr = @maxItr,
|
||||
cron = @cron,
|
||||
lastrun_at = @lastrunAt
|
||||
OUTPUT
|
||||
INSERTED.id,
|
||||
INSERTED.company_id,
|
||||
INSERTED.[desc],
|
||||
INSERTED.prompt,
|
||||
INSERTED.skills,
|
||||
INSERTED.lastagentnote,
|
||||
INSERTED.max_itr,
|
||||
INSERTED.cron,
|
||||
INSERTED.created_at,
|
||||
INSERTED.lastrun_at
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
|
||||
export const DELETE_BY_COMPANY_AND_ID = `
|
||||
DELETE FROM subagentschedule
|
||||
WHERE id = @id AND company_id = @companyId
|
||||
`;
|
||||
12
src/providers/sqlite3/queries/subagentschedule.js
Normal file
12
src/providers/sqlite3/queries/subagentschedule.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import * as source from '../../mssql/queries/subagentschedule.js';
|
||||
import { translateQueries } from './translate.js';
|
||||
|
||||
const queries = translateQueries(source, 'subagentschedule');
|
||||
export const {
|
||||
CREATE,
|
||||
DELETE_BY_COMPANY_AND_ID,
|
||||
GET_BY_COMPANY_AND_ID,
|
||||
LIST_BY_COMPANY,
|
||||
SUBAGENTSCHEDULE_COLUMNS,
|
||||
UPDATE,
|
||||
} = queries;
|
||||
118
src/store/subagentschedule/create.js
Normal file
118
src/store/subagentschedule/create.js
Normal file
@@ -0,0 +1,118 @@
|
||||
import { CREATE as MSSQL_CREATE } from '../../providers/mssql/queries/subagentschedule.js';
|
||||
import { CREATE as SQLITE_CREATE } from '../../providers/sqlite3/queries/subagentschedule.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
import { isValidCron } from './cron.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
company_id: row.company_id ?? row.companyId,
|
||||
desc: row.desc ?? null,
|
||||
prompt: row.prompt,
|
||||
skills: row.skills ?? null,
|
||||
lastagentnote: row.lastagentnote ?? null,
|
||||
max_itr: row.max_itr,
|
||||
cron: row.cron,
|
||||
created_at: row.created_at,
|
||||
lastrun_at: row.lastrun_at ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
function optionalString(value) {
|
||||
if (value == null || value === '') return null;
|
||||
const s = String(value).trim();
|
||||
return s || null;
|
||||
}
|
||||
|
||||
export default function create(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const createSql = isSqlite ? SQLITE_CREATE : MSSQL_CREATE;
|
||||
|
||||
/**
|
||||
* Creates a new subagent schedule for the user's selected company.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {object} input - Schedule input.
|
||||
* @param {string} input.prompt - The task prompt for the subagent.
|
||||
* @param {string} input.cron - Standard 5-field cron timetable string.
|
||||
* @param {string} [input.desc] - Optional schedule description.
|
||||
* @param {string|Array<string>} [input.skills] - Optional skill names or JSON string.
|
||||
* @param {string} [input.lastagentnote] - Optional initial agent note.
|
||||
* @param {number} [input.max_itr=15] - Optional max iterations per run.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>}
|
||||
* @throws {Error} If prompt is missing, cron is invalid, or max_itr is invalid.
|
||||
*
|
||||
* @example
|
||||
* const schedule = await store.subagentschedule.create(googleAuthId, {
|
||||
* desc: 'Nightly inventory audit',
|
||||
* prompt: 'Check stock discrepancies across all warehouses and summarize.',
|
||||
* cron: '0 2 * * *',
|
||||
* skills: ['stock', 'reporting'],
|
||||
* max_itr: 20,
|
||||
* });
|
||||
*/
|
||||
return async (googleAuthId, input = {}, tx) => {
|
||||
const prompt = typeof input.prompt === 'string' ? input.prompt.trim() : '';
|
||||
if (!prompt) {
|
||||
throw new Error('Prompt required');
|
||||
}
|
||||
|
||||
const cron = typeof input.cron === 'string' ? input.cron.trim() : '';
|
||||
if (!cron) {
|
||||
throw new Error('Cron expression required');
|
||||
}
|
||||
if (!isValidCron(cron)) {
|
||||
throw new Error('Invalid cron expression');
|
||||
}
|
||||
|
||||
let maxItr = 15;
|
||||
if (input.max_itr !== undefined && input.max_itr !== null) {
|
||||
const parsed = Number(input.max_itr);
|
||||
if (!Number.isInteger(parsed) || parsed <= 0) {
|
||||
throw new Error('Invalid max iterations: must be a positive integer');
|
||||
}
|
||||
maxItr = parsed;
|
||||
}
|
||||
|
||||
let skills = null;
|
||||
if (Array.isArray(input.skills)) {
|
||||
skills = JSON.stringify(input.skills);
|
||||
} else if (input.skills != null) {
|
||||
skills = optionalString(input.skills);
|
||||
}
|
||||
|
||||
const desc = optionalString(input.desc);
|
||||
const lastagentnote = optionalString(input.lastagentnote);
|
||||
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, runner);
|
||||
|
||||
const result = await runner.query(createSql, {
|
||||
companyId,
|
||||
desc,
|
||||
prompt,
|
||||
skills,
|
||||
lastagentnote,
|
||||
maxItr,
|
||||
cron,
|
||||
});
|
||||
|
||||
const row = result.rows[0] ?? {
|
||||
id: result.insertId,
|
||||
company_id: companyId,
|
||||
desc,
|
||||
prompt,
|
||||
skills,
|
||||
lastagentnote,
|
||||
max_itr: maxItr,
|
||||
cron,
|
||||
created_at: new Date().toISOString(),
|
||||
lastrun_at: null,
|
||||
};
|
||||
|
||||
return shape(row);
|
||||
};
|
||||
}
|
||||
99
src/store/subagentschedule/cron.js
Normal file
99
src/store/subagentschedule/cron.js
Normal file
@@ -0,0 +1,99 @@
|
||||
const CRON_NICKNAMES = new Set([
|
||||
'@yearly',
|
||||
'@annually',
|
||||
'@monthly',
|
||||
'@weekly',
|
||||
'@daily',
|
||||
'@midnight',
|
||||
'@hourly',
|
||||
]);
|
||||
|
||||
const MONTH_NAMES = {
|
||||
jan: 1, feb: 2, mar: 3, apr: 4, may: 5, jun: 6,
|
||||
jul: 7, aug: 8, sep: 9, oct: 10, nov: 11, dec: 12,
|
||||
};
|
||||
|
||||
const DAY_NAMES = {
|
||||
sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6,
|
||||
};
|
||||
|
||||
const FIELD_RANGES = [
|
||||
{ name: 'minute', min: 0, max: 59 },
|
||||
{ name: 'hour', min: 0, max: 23 },
|
||||
{ name: 'day of month', min: 1, max: 31 },
|
||||
{ name: 'month', min: 1, max: 12, names: MONTH_NAMES },
|
||||
{ name: 'day of week', min: 0, max: 7, names: DAY_NAMES },
|
||||
];
|
||||
|
||||
function parseCronValue(val, min, max, names) {
|
||||
if (names && typeof val === 'string') {
|
||||
const lower = val.toLowerCase();
|
||||
if (lower in names) return names[lower];
|
||||
}
|
||||
if (!/^\d+$/.test(val)) return null;
|
||||
const num = parseInt(val, 10);
|
||||
if (num < min || num > max) return null;
|
||||
return num;
|
||||
}
|
||||
|
||||
function validateField(part, min, max, names) {
|
||||
if (!part) return false;
|
||||
const items = part.split(',');
|
||||
if (items.length === 0) return false;
|
||||
|
||||
for (const item of items) {
|
||||
if (!item) return false;
|
||||
const slashParts = item.split('/');
|
||||
if (slashParts.length > 2) return false;
|
||||
if (slashParts.length === 2) {
|
||||
const step = slashParts[1];
|
||||
if (!/^\d+$/.test(step)) return false;
|
||||
const stepNum = parseInt(step, 10);
|
||||
if (stepNum <= 0 || stepNum > max) return false;
|
||||
}
|
||||
|
||||
const base = slashParts[0];
|
||||
if (base === '*' || base === '?') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const dashParts = base.split('-');
|
||||
if (dashParts.length > 2) return false;
|
||||
if (dashParts.length === 2) {
|
||||
const start = parseCronValue(dashParts[0], min, max, names);
|
||||
const end = parseCronValue(dashParts[1], min, max, names);
|
||||
if (start === null || end === null || start > end) return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const val = parseCronValue(base, min, max, names);
|
||||
if (val === null) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a standard 5-part cron timetable string or standard nickname.
|
||||
*
|
||||
* @param {string} cron - The cron expression to validate.
|
||||
* @returns {boolean} True if the cron expression is syntactically valid.
|
||||
*/
|
||||
export function isValidCron(cron) {
|
||||
if (typeof cron !== 'string') return false;
|
||||
const trimmed = cron.trim();
|
||||
if (!trimmed) return false;
|
||||
if (CRON_NICKNAMES.has(trimmed.toLowerCase())) return true;
|
||||
|
||||
const parts = trimmed.split(/\s+/);
|
||||
if (parts.length !== 5) return false;
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const part = parts[i];
|
||||
const { min, max, names } = FIELD_RANGES[i];
|
||||
if (!validateField(part, min, max, names)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
34
src/store/subagentschedule/delete.js
Normal file
34
src/store/subagentschedule/delete.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { DELETE_BY_COMPANY_AND_ID as MSSQL_DELETE } from '../../providers/mssql/queries/subagentschedule.js';
|
||||
import { DELETE_BY_COMPANY_AND_ID as SQLITE_DELETE } from '../../providers/sqlite3/queries/subagentschedule.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
export default function remove(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const deleteSql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
|
||||
|
||||
/**
|
||||
* Deletes a subagent schedule by id for the user's selected company.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {number} id - The schedule ID to delete.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<void>}
|
||||
* @throws {Error} If schedule not found.
|
||||
*/
|
||||
return async (googleAuthId, id, tx) => {
|
||||
const numericId = Number(id);
|
||||
if (!Number.isInteger(numericId) || numericId <= 0) {
|
||||
throw new Error('Subagent schedule not found');
|
||||
}
|
||||
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, runner);
|
||||
|
||||
const result = await runner.query(deleteSql, { id: numericId, companyId });
|
||||
if (result.rowCount === 0) {
|
||||
throw new Error('Subagent schedule not found');
|
||||
}
|
||||
};
|
||||
}
|
||||
47
src/store/subagentschedule/getById.js
Normal file
47
src/store/subagentschedule/getById.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { GET_BY_COMPANY_AND_ID as MSSQL_GET_BY_ID } from '../../providers/mssql/queries/subagentschedule.js';
|
||||
import { GET_BY_COMPANY_AND_ID as SQLITE_GET_BY_ID } from '../../providers/sqlite3/queries/subagentschedule.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
company_id: row.company_id ?? row.companyId,
|
||||
desc: row.desc ?? null,
|
||||
prompt: row.prompt,
|
||||
skills: row.skills ?? null,
|
||||
lastagentnote: row.lastagentnote ?? null,
|
||||
max_itr: row.max_itr,
|
||||
cron: row.cron,
|
||||
created_at: row.created_at,
|
||||
lastrun_at: row.lastrun_at ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
export default function getById(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const getSql = isSqlite ? SQLITE_GET_BY_ID : MSSQL_GET_BY_ID;
|
||||
|
||||
/**
|
||||
* Retrieves a single subagent schedule by id for the user's selected company.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {number} id - The schedule ID.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}|null>}
|
||||
*/
|
||||
return async (googleAuthId, id, tx) => {
|
||||
const numericId = Number(id);
|
||||
if (!Number.isInteger(numericId) || numericId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, runner);
|
||||
|
||||
const result = await runner.query(getSql, { id: numericId, companyId });
|
||||
const row = result.rows[0];
|
||||
return row ? shape(row) : null;
|
||||
};
|
||||
}
|
||||
40
src/store/subagentschedule/list.js
Normal file
40
src/store/subagentschedule/list.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { LIST_BY_COMPANY as MSSQL_LIST } from '../../providers/mssql/queries/subagentschedule.js';
|
||||
import { LIST_BY_COMPANY as SQLITE_LIST } from '../../providers/sqlite3/queries/subagentschedule.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
company_id: row.company_id ?? row.companyId,
|
||||
desc: row.desc ?? null,
|
||||
prompt: row.prompt,
|
||||
skills: row.skills ?? null,
|
||||
lastagentnote: row.lastagentnote ?? null,
|
||||
max_itr: row.max_itr,
|
||||
cron: row.cron,
|
||||
created_at: row.created_at,
|
||||
lastrun_at: row.lastrun_at ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
export default function list(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const listSql = isSqlite ? SQLITE_LIST : MSSQL_LIST;
|
||||
|
||||
/**
|
||||
* Lists all subagent schedules for the user's selected company.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<Array<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>>}
|
||||
*/
|
||||
return async (googleAuthId, tx) => {
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, runner);
|
||||
|
||||
const result = await runner.query(listSql, { companyId });
|
||||
return result.rows.map(shape);
|
||||
};
|
||||
}
|
||||
142
src/store/subagentschedule/update.js
Normal file
142
src/store/subagentschedule/update.js
Normal file
@@ -0,0 +1,142 @@
|
||||
import {
|
||||
GET_BY_COMPANY_AND_ID as MSSQL_GET_BY_ID,
|
||||
UPDATE as MSSQL_UPDATE,
|
||||
} from '../../providers/mssql/queries/subagentschedule.js';
|
||||
import {
|
||||
GET_BY_COMPANY_AND_ID as SQLITE_GET_BY_ID,
|
||||
UPDATE as SQLITE_UPDATE,
|
||||
} from '../../providers/sqlite3/queries/subagentschedule.js';
|
||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||
import makeRunner from '../runner.js';
|
||||
import { isValidCron } from './cron.js';
|
||||
|
||||
function shape(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
company_id: row.company_id ?? row.companyId,
|
||||
desc: row.desc ?? null,
|
||||
prompt: row.prompt,
|
||||
skills: row.skills ?? null,
|
||||
lastagentnote: row.lastagentnote ?? null,
|
||||
max_itr: row.max_itr,
|
||||
cron: row.cron,
|
||||
created_at: row.created_at,
|
||||
lastrun_at: row.lastrun_at ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
function optionalString(value) {
|
||||
if (value == null || value === '') return null;
|
||||
const s = String(value).trim();
|
||||
return s || null;
|
||||
}
|
||||
|
||||
export default function update(provider) {
|
||||
const access = resolveSelectedCompanyAccess(provider);
|
||||
const isSqlite = provider?.dialect === 'sqlite3';
|
||||
const getSql = isSqlite ? SQLITE_GET_BY_ID : MSSQL_GET_BY_ID;
|
||||
const updateSql = isSqlite ? SQLITE_UPDATE : MSSQL_UPDATE;
|
||||
|
||||
/**
|
||||
* Updates an existing subagent schedule for the user's selected company.
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {number} id - The schedule ID to update.
|
||||
* @param {object} input - Update payload.
|
||||
* @param {string} [input.prompt] - Optional updated task prompt.
|
||||
* @param {string} [input.cron] - Optional updated cron expression.
|
||||
* @param {string|null} [input.desc] - Optional updated description.
|
||||
* @param {string|Array<string>|null} [input.skills] - Optional updated skills.
|
||||
* @param {string|null} [input.lastagentnote] - Optional updated agent note.
|
||||
* @param {number} [input.max_itr] - Optional updated max iterations.
|
||||
* @param {string|null} [input.lastrun_at] - Optional updated last run timestamp.
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<{id: number, company_id: number, desc: string|null, prompt: string, skills: string|null, lastagentnote: string|null, max_itr: number, cron: string, created_at: string, lastrun_at: string|null}>}
|
||||
* @throws {Error} If schedule not found, prompt is empty, cron is invalid, or max_itr is invalid.
|
||||
*/
|
||||
return async (googleAuthId, id, input = {}, tx) => {
|
||||
const numericId = Number(id);
|
||||
if (!Number.isInteger(numericId) || numericId <= 0) {
|
||||
throw new Error('Subagent schedule not found');
|
||||
}
|
||||
|
||||
const runner = makeRunner(provider, tx);
|
||||
const { companyId } = await access(googleAuthId, runner);
|
||||
|
||||
const existing = await runner.query(getSql, { id: numericId, companyId });
|
||||
const current = existing.rows[0];
|
||||
if (!current) {
|
||||
throw new Error('Subagent schedule not found');
|
||||
}
|
||||
|
||||
let prompt = current.prompt;
|
||||
if (input.prompt !== undefined) {
|
||||
const cleaned = typeof input.prompt === 'string' ? input.prompt.trim() : '';
|
||||
if (!cleaned) {
|
||||
throw new Error('Prompt required');
|
||||
}
|
||||
prompt = cleaned;
|
||||
}
|
||||
|
||||
let cron = current.cron;
|
||||
if (input.cron !== undefined) {
|
||||
const cleaned = typeof input.cron === 'string' ? input.cron.trim() : '';
|
||||
if (!cleaned) {
|
||||
throw new Error('Cron expression required');
|
||||
}
|
||||
if (!isValidCron(cleaned)) {
|
||||
throw new Error('Invalid cron expression');
|
||||
}
|
||||
cron = cleaned;
|
||||
}
|
||||
|
||||
let maxItr = current.max_itr;
|
||||
if (input.max_itr !== undefined && input.max_itr !== null) {
|
||||
const parsed = Number(input.max_itr);
|
||||
if (!Number.isInteger(parsed) || parsed <= 0) {
|
||||
throw new Error('Invalid max iterations: must be a positive integer');
|
||||
}
|
||||
maxItr = parsed;
|
||||
}
|
||||
|
||||
let skills = current.skills;
|
||||
if (input.skills !== undefined) {
|
||||
if (Array.isArray(input.skills)) {
|
||||
skills = JSON.stringify(input.skills);
|
||||
} else {
|
||||
skills = optionalString(input.skills);
|
||||
}
|
||||
}
|
||||
|
||||
const desc = input.desc !== undefined ? optionalString(input.desc) : (current.desc ?? null);
|
||||
const lastagentnote = input.lastagentnote !== undefined ? optionalString(input.lastagentnote) : (current.lastagentnote ?? null);
|
||||
const lastrunAt = input.lastrun_at !== undefined ? optionalString(input.lastrun_at) : (current.lastrun_at ?? null);
|
||||
|
||||
const result = await runner.query(updateSql, {
|
||||
id: numericId,
|
||||
companyId,
|
||||
desc,
|
||||
prompt,
|
||||
skills,
|
||||
lastagentnote,
|
||||
maxItr,
|
||||
cron,
|
||||
lastrunAt,
|
||||
});
|
||||
|
||||
const row = result.rows[0] ?? {
|
||||
id: numericId,
|
||||
company_id: companyId,
|
||||
desc,
|
||||
prompt,
|
||||
skills,
|
||||
lastagentnote,
|
||||
max_itr: maxItr,
|
||||
cron,
|
||||
created_at: current.created_at,
|
||||
lastrun_at: lastrunAt,
|
||||
};
|
||||
|
||||
return shape(row);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user