Compare commits
2 Commits
8ee080b744
...
a194cf6b8b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a194cf6b8b | ||
|
|
59395f95d8 |
26
API.md
26
API.md
@@ -8,6 +8,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
|
|
||||||
> **Convention**: `PK` primary key · `?` nullable · `->tbl` foreign key · `UQ` unique · `s(N)` string · `txt` text · `i` int · `bi` bigint · `f` float · `d` decimal · `b` bit · `dt` datetime · `bin` binary · `=val` default
|
> **Convention**: `PK` primary key · `?` nullable · `->tbl` foreign key · `UQ` unique · `s(N)` string · `txt` text · `i` int · `bi` bigint · `f` float · `d` decimal · `b` bit · `dt` datetime · `bin` binary · `=val` default
|
||||||
|
|
||||||
|
- **account**: `id PK, company_id->company, type:s(100), name:s(255)`
|
||||||
- **article**: `id PK, sku?:s(100) UQ, unit_id->unit, unitamount:f, weight:f, track_stock:b=1, brand_id?->brand, articlelist_id?->articlelist, optionslist_id?->optionslist, is_parent:b=0, parentarticle_id?->article, parentattributename_id?->attributename, parentsort:i=0, created_at:dt, updated_at:dt, UQ(parentarticle_id, parentsort)`
|
- **article**: `id PK, sku?:s(100) UQ, unit_id->unit, unitamount:f, weight:f, track_stock:b=1, brand_id?->brand, articlelist_id?->articlelist, optionslist_id?->optionslist, is_parent:b=0, parentarticle_id?->article, parentattributename_id?->attributename, parentsort:i=0, created_at:dt, updated_at:dt, UQ(parentarticle_id, parentsort)`
|
||||||
- **articleattributevalue**: `id PK, article_id->article, attributevalue_id->attributevalue, sort:i=0, UQ(article_id, attributevalue_id)`
|
- **articleattributevalue**: `id PK, article_id->article, attributevalue_id->attributevalue, sort:i=0, UQ(article_id, attributevalue_id)`
|
||||||
- **articleean**: `id PK, article_id->article, ean:s(50) UQ`
|
- **articleean**: `id PK, article_id->article, ean:s(50) UQ`
|
||||||
@@ -18,6 +19,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- **articleproperty**: `id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0`
|
- **articleproperty**: `id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0`
|
||||||
- **articlesupplier**: `id PK, article_id->article, entity_id->entity, net?:f, tax_id?->tax, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)`
|
- **articlesupplier**: `id PK, article_id->article, entity_id->entity, net?:f, tax_id?->tax, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)`
|
||||||
- **articletext**: `id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)`
|
- **articletext**: `id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)`
|
||||||
|
- **articletombstone**: `id PK, company_id->company, article_id?:i, sku?:s(100), name?:s(255), taxrate?:d(18,4), net?:f, deleted_at:dt`
|
||||||
- **attributename**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
- **attributename**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
||||||
- **attributevalue**: `id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)`
|
- **attributevalue**: `id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)`
|
||||||
- **attributevaluepic**: `id PK, attributevalue_id->attributevalue, pic_id->pic, sort:i=0, UQ(attributevalue_id, pic_id), UQ(attributevalue_id, sort)`
|
- **attributevaluepic**: `id PK, attributevalue_id->attributevalue, pic_id->pic, sort:i=0, UQ(attributevalue_id, pic_id), UQ(attributevalue_id, sort)`
|
||||||
@@ -25,13 +27,16 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- **brandpic**: `id PK, brand_id->brand, pic_id->pic, sort:i=0, UQ(brand_id, pic_id), UQ(brand_id, sort)`
|
- **brandpic**: `id PK, brand_id->brand, pic_id->pic, sort:i=0, UQ(brand_id, pic_id), UQ(brand_id, sort)`
|
||||||
- **category**: `id PK, parent_id?->category, sort:i=0`
|
- **category**: `id PK, parent_id?->category, sort:i=0`
|
||||||
- **categoryarticle**: `id PK, category_id->category, article_id->article, UQ(category_id, article_id)`
|
- **categoryarticle**: `id PK, category_id->category, article_id->article, UQ(category_id, article_id)`
|
||||||
|
- **categoryattributevalue**: `id PK, category_id->category, attributevalue_id->attributevalue, sort:i=0, UQ(category_id, attributevalue_id)`
|
||||||
- **categorypic**: `id PK, category_id->category, pic_id->pic, sort:i=0, UQ(category_id, pic_id), UQ(category_id, sort)`
|
- **categorypic**: `id PK, category_id->category, pic_id->pic, sort:i=0, UQ(category_id, pic_id), UQ(category_id, sort)`
|
||||||
|
- **categoryproperty**: `id PK, category_id->category, property_id->propertyname, value:txt, sort:i=0`
|
||||||
- **categorytext**: `id PK, category_id->category, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(category_id, language_id)`
|
- **categorytext**: `id PK, category_id->category, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(category_id, language_id)`
|
||||||
- **company**: `id PK, name:s(255) UQ, root_category_id?->category, default_language_id?->language, taxrate?->tax, reducedtaxrate?->tax, taxfreerate?->tax, poscustomergroup_id->customergroup`
|
- **company**: `id PK, name:s(255) UQ, root_category_id?->category, default_language_id?->language, taxrate?->tax, reducedtaxrate?->tax, taxfreerate?->tax, poscustomergroup_id->customergroup`
|
||||||
- **companyhistory**: `id PK, company_id->company, companyuser_id?->companyuser, date:dt, text:txt`
|
- **companyhistory**: `id PK, company_id->company, companyuser_id?->companyuser, date:dt, text:txt`
|
||||||
- **companysetting**: `id PK, company_id->company, key:s(255), value:txt, frontend:b=0, writeonly:b=0, UQ(company_id, key)`
|
- **companysetting**: `id PK, company_id->company, key:s(255), value:txt, frontend:b=0, writeonly:b=0, UQ(company_id, key)`
|
||||||
- **companyuser**: `id PK, google_auth_id->google_auth, company_id->company, UQ(google_auth_id, company_id)`
|
- **companyuser**: `id PK, google_auth_id->google_auth, company_id->company, UQ(google_auth_id, company_id)`
|
||||||
- **customergroup**: `id PK, name:s(255), sort:i=0, company_id?->company`
|
- **customergroup**: `id PK, name:s(255), sort:i=0, company_id?->company`
|
||||||
|
- **deliverysummary**: `id PK, company_id->company, manifest_id->manifest UQ, delivery_number:s(100), external_number?:s(100), delivery_date:dt, created_at:dt, supplier_id?->entity, supplier_name?:s(255), positions:i=0, gross_total:f=0, net_total:f=0, total_quantity:f=0, stock_positions:i=0, booked_positions:i=0, unbooked_positions:i=0, stock_quantity:f=0, booked_quantity:f=0, unbooked_quantity:f=0, is_booked:b=0`
|
||||||
- **entity**: `id PK, customergroup_id->customergroup, first_name?:s(255), name:s(255), number?:s(100), created_at:dt, updated_at:dt, UQ(company_id, number)`
|
- **entity**: `id PK, customergroup_id->customergroup, first_name?:s(255), name:s(255), number?:s(100), created_at:dt, updated_at:dt, UQ(company_id, number)`
|
||||||
- **entityaddress**: `id PK, entity_id->entity, first_name?:s(255), name?:s(255), street?:s(255), streetnumber?:s(50), zip?:s(50), city?:s(255), county?:s(255), addresstype:s(50), sort:i=0`
|
- **entityaddress**: `id PK, entity_id->entity, first_name?:s(255), name?:s(255), street?:s(255), streetnumber?:s(50), zip?:s(50), city?:s(255), county?:s(255), addresstype:s(50), sort:i=0`
|
||||||
- **entitycontact**: `id PK, entity_id->entity, contacttype:s(50), contact:s(255), sort:i=0`
|
- **entitycontact**: `id PK, entity_id->entity, contacttype:s(50), contact:s(255), sort:i=0`
|
||||||
@@ -44,16 +49,29 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- **manifest**: `id PK, company_id->company, number:s(100), type:s(100), entity_id?->entity, external_number?:s(100), date:dt, created_at:dt`
|
- **manifest**: `id PK, company_id->company, number:s(100), type:s(100), entity_id?->entity, external_number?:s(100), date:dt, created_at:dt`
|
||||||
- **manifestarticle**: `id PK, manifest_id->manifest, sku?:s(100), name?:s(255), pu:f=1, amount:f, net:f, comment?:txt, rebate:f=0, taxrate:f=0`
|
- **manifestarticle**: `id PK, manifest_id->manifest, sku?:s(100), name?:s(255), pu:f=1, amount:f, net:f, comment?:txt, rebate:f=0, taxrate:f=0`
|
||||||
- **manifestattachment**: `id PK, manifest_id->manifest, file_id->file, sort:i=0, UQ(manifest_id, sort)`
|
- **manifestattachment**: `id PK, manifest_id->manifest, file_id->file, sort:i=0, UQ(manifest_id, sort)`
|
||||||
|
- **mcp_auth_code**: `code:s(128) PK, client_id:s(100), google_auth_id->google_auth, redirect_uri:s(2048), code_challenge:s(255), code_challenge_method:s(32), scope?:s(255), expires_at:dt, used:b=0, created_at:dt`
|
||||||
|
- **mcp_client**: `id PK, client_id:s(100) UQ, client_secret?:s(255), client_name:s(255), redirect_uris:txt, grant_types?:s(255), response_types?:s(255), scope?:s(255), created_at:dt`
|
||||||
|
- **mcp_token**: `id PK, refresh_token:s(128) UQ, client_id:s(100), google_auth_id->google_auth, scope?:s(255), expires_at:dt, revoked:b=0, created_at:dt`
|
||||||
- **meta**: `key:s(255) PK, value:txt`
|
- **meta**: `key:s(255) PK, value:txt`
|
||||||
|
- **modelconversation**: `id PK, companyuser_id->companyuser, provider:s(100), model:s(255), created_at:dt, updated_at:dt, state:s(20)='idle', started_by?:i`
|
||||||
|
- **modelmessage**: `id PK, conversation_id->modelconversation, created_at:dt, role:s(20), message:txt`
|
||||||
|
- **modelvfs**: `id PK, company_id->company, name:s(255), mime:s(100), content:bin, meta?:txt, created_at:dt, updated_at:dt, UQ(company_id, name)`
|
||||||
- **numbers**: `id PK, company_id->company, type:s(100), prefix:s(50)='', padding:i=0, next:i=1, UQ(company_id, type)`
|
- **numbers**: `id PK, company_id->company, type:s(100), prefix:s(50)='', padding:i=0, next:i=1, UQ(company_id, type)`
|
||||||
- **optionslist**: `id PK`
|
- **optionslist**: `id PK`
|
||||||
- **optionslistarticle**: `id PK, optionslist_id->optionslist, article_id->article, count:i=1, sort:i=0, mandated:b=0, UQ(optionslist_id, article_id), UQ(optionslist_id, sort)`
|
- **optionslistarticle**: `id PK, optionslist_id->optionslist, article_id->article, count:i=1, sort:i=0, mandated:b=0, UQ(optionslist_id, article_id), UQ(optionslist_id, sort)`
|
||||||
|
- **ordersummary**: `id PK, company_id->company, manifest_id->manifest UQ, order_number:s(100), order_date:dt, created_at:dt, entity_id?->entity, customer_name?:s(255), positions:i=0, gross_total:f=0, paid_total:f=0, ordered_quantity:f=0, shipped_quantity:f=0, is_paid:b=0, is_shipped:b=0`
|
||||||
|
- **package**: `id PK, shipping_id->shipping, entityaddress_id->entityaddress, number:s(100), type:s(100), state:s(100), details?:txt`
|
||||||
|
- **payment**: `id PK, account_id->account, manifest_id->manifest, type:s(100), amount:f`
|
||||||
- **pic**: `id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin`
|
- **pic**: `id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin`
|
||||||
- **posterminal**: `id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt`
|
- **posterminal**: `id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt`
|
||||||
- **posterminalcategory**: `id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)`
|
- **posterminalcategory**: `id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)`
|
||||||
- **price**: `id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f`
|
- **price**: `id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f`
|
||||||
- **printer**: `id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt`
|
- **printer**: `id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt`
|
||||||
- **propertyname**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
- **propertyname**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
||||||
|
- **quotesummary**: `id PK, company_id->company, manifest_id->manifest UQ, quote_number:s(100), quote_date:dt, created_at:dt, entity_id?->entity, customer_name?:s(255), positions:i=0, gross_total:f=0, total_quantity:f=0`
|
||||||
|
- **shipmentsummary**: `id PK, company_id->company, manifest_id->manifest UQ, shipment_number:s(100), shipment_date:dt, created_at:dt, order_id?:i, order_number?:s(100), entity_id?->entity, customer_name?:s(255), positions:i=0, total_quantity:f=0, package_count:i=0, carrier?:s(100), tracking_code?:s(255), state:s(50)='new'`
|
||||||
|
- **shipping**: `id PK, manifest_id->manifest, number:s(100), tracking_code?:s(255), carrier?:s(100), type:s(100), state:s(100)`
|
||||||
|
- **subagentschedule**: `id PK, company_id->company, desc?:txt, prompt:txt, skills?:txt, lastagentnote?:txt, max_itr:i=15, cron:s(100), created_at:dt, lastrun_at?:dt`
|
||||||
- **tax**: `id PK, rate:d(18,4) UQ`
|
- **tax**: `id PK, rate:d(18,4) UQ`
|
||||||
- **unit**: `id PK, company_id->company, si:s(50), basesi:s(50), basesifactor:f, UQ(company_id, si)`
|
- **unit**: `id PK, company_id->company, si:s(50), basesi:s(50), basesifactor:f, UQ(company_id, si)`
|
||||||
- **unittext**: `id PK, unit_id->unit, language_id->language, symbol:s(50), name:s(255), UQ(unit_id, language_id)`
|
- **unittext**: `id PK, unit_id->unit, language_id->language, symbol:s(50), name:s(255), UQ(unit_id, language_id)`
|
||||||
@@ -363,5 +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}>`
|
- `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>`
|
- `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}>>`
|
- `listByManifestId(googleAuthId: number, manifestId: number, tx?: object): Promise<Array<{id: number, accountId: number, manifestId: number, type: string, amount: number}>>`
|
||||||
- [runner.js](API.runner.js.md)
|
- [subagentschedule](API.subagentschedule.md)
|
||||||
- `runner(provider: import('../providers/provider.js').DatabaseProvider, tx?: object): ((sql: string, params?: object) => Promise<import('../providers/provider.js').QueryResult>) & { query: Function, dialect?: string }`
|
- `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}>`
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
# runner.js
|
|
||||||
|
|
||||||
This document is auto-generated from the JSDoc comments in `src/store` by running `npm run api-doc`.
|
|
||||||
|
|
||||||
## `runner.js.runner`
|
|
||||||
|
|
||||||
*Source: `src/store/runner.js`*
|
|
||||||
|
|
||||||
Resolves the object a store method should query through. Converted store modules call `runner(sql, params)` or `runner.query(sql, params)`. During the incremental migration they may still be constructed with a raw `mssql` pool, or called with a raw `mssql` Transaction as `tx`. This adapter exposes the unified runner contract over both so mixed call sites keep working until every module is converted.
|
|
||||||
|
|
||||||
**Parameters**
|
|
||||||
|
|
||||||
| Name | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `provider` | `import('../providers/provider.js').DatabaseProvider` | |
|
|
||||||
| `[tx]` | `object` | Optional provider runner or legacy mssql Transaction. |
|
|
||||||
|
|
||||||
**Returns**
|
|
||||||
|
|
||||||
`((sql: string, params?: object) => Promise<import('../providers/provider.js').QueryResult>) & { query: Function, dialect?: string }`
|
|
||||||
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.
|
||||||
@@ -75,6 +75,8 @@ const INTERNAL_FILES = new Set([
|
|||||||
'shape.js',
|
'shape.js',
|
||||||
'createStore.js',
|
'createStore.js',
|
||||||
'manifestLines.js',
|
'manifestLines.js',
|
||||||
|
'runner.js',
|
||||||
|
'cron.js',
|
||||||
'index.js',
|
'index.js',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -321,6 +323,7 @@ function render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SCHEMA_TABLES = [
|
const SCHEMA_TABLES = [
|
||||||
|
['account', 'id PK, company_id->company, type:s(100), name:s(255)'],
|
||||||
['article', 'id PK, sku?:s(100) UQ, unit_id->unit, unitamount:f, weight:f, track_stock:b=1, brand_id?->brand, articlelist_id?->articlelist, optionslist_id?->optionslist, is_parent:b=0, parentarticle_id?->article, parentattributename_id?->attributename, parentsort:i=0, created_at:dt, updated_at:dt, UQ(parentarticle_id, parentsort)'],
|
['article', 'id PK, sku?:s(100) UQ, unit_id->unit, unitamount:f, weight:f, track_stock:b=1, brand_id?->brand, articlelist_id?->articlelist, optionslist_id?->optionslist, is_parent:b=0, parentarticle_id?->article, parentattributename_id?->attributename, parentsort:i=0, created_at:dt, updated_at:dt, UQ(parentarticle_id, parentsort)'],
|
||||||
['articleattributevalue', 'id PK, article_id->article, attributevalue_id->attributevalue, sort:i=0, UQ(article_id, attributevalue_id)'],
|
['articleattributevalue', 'id PK, article_id->article, attributevalue_id->attributevalue, sort:i=0, UQ(article_id, attributevalue_id)'],
|
||||||
['articleean', 'id PK, article_id->article, ean:s(50) UQ'],
|
['articleean', 'id PK, article_id->article, ean:s(50) UQ'],
|
||||||
@@ -331,6 +334,7 @@ const SCHEMA_TABLES = [
|
|||||||
['articleproperty', 'id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0'],
|
['articleproperty', 'id PK, article_id->article, property_id->propertyname, value:txt, sort:i=0'],
|
||||||
['articlesupplier', 'id PK, article_id->article, entity_id->entity, net?:f, tax_id?->tax, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)'],
|
['articlesupplier', 'id PK, article_id->article, entity_id->entity, net?:f, tax_id?->tax, sku?:s(100), stock?:f, pu:f=1, sort:i=0, UQ(article_id, entity_id), UQ(article_id, sort)'],
|
||||||
['articletext', 'id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)'],
|
['articletext', 'id PK, article_id->article, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(article_id, language_id)'],
|
||||||
|
['articletombstone', 'id PK, company_id->company, article_id?:i, sku?:s(100), name?:s(255), taxrate?:d(18,4), net?:f, deleted_at:dt'],
|
||||||
['attributename', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
['attributename', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
||||||
['attributevalue', 'id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)'],
|
['attributevalue', 'id PK, attribute_id->attributename, value:s(255), sort:i=0, UQ(attribute_id, value)'],
|
||||||
['attributevaluepic', 'id PK, attributevalue_id->attributevalue, pic_id->pic, sort:i=0, UQ(attributevalue_id, pic_id), UQ(attributevalue_id, sort)'],
|
['attributevaluepic', 'id PK, attributevalue_id->attributevalue, pic_id->pic, sort:i=0, UQ(attributevalue_id, pic_id), UQ(attributevalue_id, sort)'],
|
||||||
@@ -338,13 +342,16 @@ const SCHEMA_TABLES = [
|
|||||||
['brandpic', 'id PK, brand_id->brand, pic_id->pic, sort:i=0, UQ(brand_id, pic_id), UQ(brand_id, sort)'],
|
['brandpic', 'id PK, brand_id->brand, pic_id->pic, sort:i=0, UQ(brand_id, pic_id), UQ(brand_id, sort)'],
|
||||||
['category', 'id PK, parent_id?->category, sort:i=0'],
|
['category', 'id PK, parent_id?->category, sort:i=0'],
|
||||||
['categoryarticle', 'id PK, category_id->category, article_id->article, UQ(category_id, article_id)'],
|
['categoryarticle', 'id PK, category_id->category, article_id->article, UQ(category_id, article_id)'],
|
||||||
|
['categoryattributevalue', 'id PK, category_id->category, attributevalue_id->attributevalue, sort:i=0, UQ(category_id, attributevalue_id)'],
|
||||||
['categorypic', 'id PK, category_id->category, pic_id->pic, sort:i=0, UQ(category_id, pic_id), UQ(category_id, sort)'],
|
['categorypic', 'id PK, category_id->category, pic_id->pic, sort:i=0, UQ(category_id, pic_id), UQ(category_id, sort)'],
|
||||||
|
['categoryproperty', 'id PK, category_id->category, property_id->propertyname, value:txt, sort:i=0'],
|
||||||
['categorytext', 'id PK, category_id->category, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(category_id, language_id)'],
|
['categorytext', 'id PK, category_id->category, language_id->language, name:s(255), slug:s(255), seo?:txt, desc?:txt, UQ(category_id, language_id)'],
|
||||||
['company', 'id PK, name:s(255) UQ, root_category_id?->category, default_language_id?->language, taxrate?->tax, reducedtaxrate?->tax, taxfreerate?->tax, poscustomergroup_id->customergroup'],
|
['company', 'id PK, name:s(255) UQ, root_category_id?->category, default_language_id?->language, taxrate?->tax, reducedtaxrate?->tax, taxfreerate?->tax, poscustomergroup_id->customergroup'],
|
||||||
['companyhistory', 'id PK, company_id->company, companyuser_id?->companyuser, date:dt, text:txt'],
|
['companyhistory', 'id PK, company_id->company, companyuser_id?->companyuser, date:dt, text:txt'],
|
||||||
['companysetting', 'id PK, company_id->company, key:s(255), value:txt, frontend:b=0, writeonly:b=0, UQ(company_id, key)'],
|
['companysetting', 'id PK, company_id->company, key:s(255), value:txt, frontend:b=0, writeonly:b=0, UQ(company_id, key)'],
|
||||||
['companyuser', 'id PK, google_auth_id->google_auth, company_id->company, UQ(google_auth_id, company_id)'],
|
['companyuser', 'id PK, google_auth_id->google_auth, company_id->company, UQ(google_auth_id, company_id)'],
|
||||||
['customergroup', 'id PK, name:s(255), sort:i=0, company_id?->company'],
|
['customergroup', 'id PK, name:s(255), sort:i=0, company_id?->company'],
|
||||||
|
['deliverysummary', 'id PK, company_id->company, manifest_id->manifest UQ, delivery_number:s(100), external_number?:s(100), delivery_date:dt, created_at:dt, supplier_id?->entity, supplier_name?:s(255), positions:i=0, gross_total:f=0, net_total:f=0, total_quantity:f=0, stock_positions:i=0, booked_positions:i=0, unbooked_positions:i=0, stock_quantity:f=0, booked_quantity:f=0, unbooked_quantity:f=0, is_booked:b=0'],
|
||||||
['entity', 'id PK, customergroup_id->customergroup, first_name?:s(255), name:s(255), number?:s(100), created_at:dt, updated_at:dt, UQ(company_id, number)'],
|
['entity', 'id PK, customergroup_id->customergroup, first_name?:s(255), name:s(255), number?:s(100), created_at:dt, updated_at:dt, UQ(company_id, number)'],
|
||||||
['entityaddress', 'id PK, entity_id->entity, first_name?:s(255), name?:s(255), street?:s(255), streetnumber?:s(50), zip?:s(50), city?:s(255), county?:s(255), addresstype:s(50), sort:i=0'],
|
['entityaddress', 'id PK, entity_id->entity, first_name?:s(255), name?:s(255), street?:s(255), streetnumber?:s(50), zip?:s(50), city?:s(255), county?:s(255), addresstype:s(50), sort:i=0'],
|
||||||
['entitycontact', 'id PK, entity_id->entity, contacttype:s(50), contact:s(255), sort:i=0'],
|
['entitycontact', 'id PK, entity_id->entity, contacttype:s(50), contact:s(255), sort:i=0'],
|
||||||
@@ -357,16 +364,29 @@ const SCHEMA_TABLES = [
|
|||||||
['manifest', 'id PK, company_id->company, number:s(100), type:s(100), entity_id?->entity, external_number?:s(100), date:dt, created_at:dt'],
|
['manifest', 'id PK, company_id->company, number:s(100), type:s(100), entity_id?->entity, external_number?:s(100), date:dt, created_at:dt'],
|
||||||
['manifestarticle', 'id PK, manifest_id->manifest, sku?:s(100), name?:s(255), pu:f=1, amount:f, net:f, comment?:txt, rebate:f=0, taxrate:f=0'],
|
['manifestarticle', 'id PK, manifest_id->manifest, sku?:s(100), name?:s(255), pu:f=1, amount:f, net:f, comment?:txt, rebate:f=0, taxrate:f=0'],
|
||||||
['manifestattachment', 'id PK, manifest_id->manifest, file_id->file, sort:i=0, UQ(manifest_id, sort)'],
|
['manifestattachment', 'id PK, manifest_id->manifest, file_id->file, sort:i=0, UQ(manifest_id, sort)'],
|
||||||
|
['mcp_auth_code', 'code:s(128) PK, client_id:s(100), google_auth_id->google_auth, redirect_uri:s(2048), code_challenge:s(255), code_challenge_method:s(32), scope?:s(255), expires_at:dt, used:b=0, created_at:dt'],
|
||||||
|
['mcp_client', 'id PK, client_id:s(100) UQ, client_secret?:s(255), client_name:s(255), redirect_uris:txt, grant_types?:s(255), response_types?:s(255), scope?:s(255), created_at:dt'],
|
||||||
|
['mcp_token', 'id PK, refresh_token:s(128) UQ, client_id:s(100), google_auth_id->google_auth, scope?:s(255), expires_at:dt, revoked:b=0, created_at:dt'],
|
||||||
['meta', 'key:s(255) PK, value:txt'],
|
['meta', 'key:s(255) PK, value:txt'],
|
||||||
|
['modelconversation', 'id PK, companyuser_id->companyuser, provider:s(100), model:s(255), created_at:dt, updated_at:dt, state:s(20)=\'idle\', started_by?:i'],
|
||||||
|
['modelmessage', 'id PK, conversation_id->modelconversation, created_at:dt, role:s(20), message:txt'],
|
||||||
|
['modelvfs', 'id PK, company_id->company, name:s(255), mime:s(100), content:bin, meta?:txt, created_at:dt, updated_at:dt, UQ(company_id, name)'],
|
||||||
['numbers', 'id PK, company_id->company, type:s(100), prefix:s(50)=\'\', padding:i=0, next:i=1, UQ(company_id, type)'],
|
['numbers', 'id PK, company_id->company, type:s(100), prefix:s(50)=\'\', padding:i=0, next:i=1, UQ(company_id, type)'],
|
||||||
['optionslist', 'id PK'],
|
['optionslist', 'id PK'],
|
||||||
['optionslistarticle', 'id PK, optionslist_id->optionslist, article_id->article, count:i=1, sort:i=0, mandated:b=0, UQ(optionslist_id, article_id), UQ(optionslist_id, sort)'],
|
['optionslistarticle', 'id PK, optionslist_id->optionslist, article_id->article, count:i=1, sort:i=0, mandated:b=0, UQ(optionslist_id, article_id), UQ(optionslist_id, sort)'],
|
||||||
|
['ordersummary', 'id PK, company_id->company, manifest_id->manifest UQ, order_number:s(100), order_date:dt, created_at:dt, entity_id?->entity, customer_name?:s(255), positions:i=0, gross_total:f=0, paid_total:f=0, ordered_quantity:f=0, shipped_quantity:f=0, is_paid:b=0, is_shipped:b=0'],
|
||||||
|
['package', 'id PK, shipping_id->shipping, entityaddress_id->entityaddress, number:s(100), type:s(100), state:s(100), details?:txt'],
|
||||||
|
['payment', 'id PK, account_id->account, manifest_id->manifest, type:s(100), amount:f'],
|
||||||
['pic', 'id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin'],
|
['pic', 'id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin'],
|
||||||
['posterminal', 'id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt'],
|
['posterminal', 'id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt'],
|
||||||
['posterminalcategory', 'id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)'],
|
['posterminalcategory', 'id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)'],
|
||||||
['price', 'id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f'],
|
['price', 'id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f'],
|
||||||
['printer', 'id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt'],
|
['printer', 'id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt'],
|
||||||
['propertyname', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
['propertyname', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
||||||
|
['quotesummary', 'id PK, company_id->company, manifest_id->manifest UQ, quote_number:s(100), quote_date:dt, created_at:dt, entity_id?->entity, customer_name?:s(255), positions:i=0, gross_total:f=0, total_quantity:f=0'],
|
||||||
|
['shipmentsummary', 'id PK, company_id->company, manifest_id->manifest UQ, shipment_number:s(100), shipment_date:dt, created_at:dt, order_id?:i, order_number?:s(100), entity_id?->entity, customer_name?:s(255), positions:i=0, total_quantity:f=0, package_count:i=0, carrier?:s(100), tracking_code?:s(255), state:s(50)=\'new\''],
|
||||||
|
['shipping', 'id PK, manifest_id->manifest, number:s(100), tracking_code?:s(255), carrier?:s(100), type:s(100), state:s(100)'],
|
||||||
|
['subagentschedule', 'id PK, company_id->company, desc?:txt, prompt:txt, skills?:txt, lastagentnote?:txt, max_itr:i=15, cron:s(100), created_at:dt, lastrun_at?:dt'],
|
||||||
['tax', 'id PK, rate:d(18,4) UQ'],
|
['tax', 'id PK, rate:d(18,4) UQ'],
|
||||||
['unit', 'id PK, company_id->company, si:s(50), basesi:s(50), basesifactor:f, UQ(company_id, si)'],
|
['unit', 'id PK, company_id->company, si:s(50), basesi:s(50), basesifactor:f, UQ(company_id, si)'],
|
||||||
['unittext', 'id PK, unit_id->unit, language_id->language, symbol:s(50), name:s(255), UQ(unit_id, language_id)'],
|
['unittext', 'id PK, unit_id->unit, language_id->language, symbol:s(50), name:s(255), UQ(unit_id, language_id)'],
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ const CLUSTERS = [
|
|||||||
{
|
{
|
||||||
id: 'ai',
|
id: 'ai',
|
||||||
label: 'AI & Models',
|
label: 'AI & Models',
|
||||||
tables: ['modelconversation', 'modelmessage', 'modelvfs'],
|
tables: ['modelconversation', 'modelmessage', 'modelvfs', 'subagentschedule'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'attributes',
|
id: 'attributes',
|
||||||
|
|||||||
280
schema-graph.dot
280
schema-graph.dot
File diff suppressed because one or more lines are too long
6165
schema-graph.svg
6165
schema-graph.svg
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 386 KiB After Width: | Height: | Size: 396 KiB |
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 modelvfsList from './store/modelvfs/list.js';
|
||||||
import modelvfsDelete from './store/modelvfs/delete.js';
|
import modelvfsDelete from './store/modelvfs/delete.js';
|
||||||
import modelvfsReset from './store/modelvfs/reset.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 accountCreate from './store/account/create.js';
|
||||||
import accountList from './store/account/list.js';
|
import accountList from './store/account/list.js';
|
||||||
import accountDelete from './store/account/delete.js';
|
import accountDelete from './store/account/delete.js';
|
||||||
@@ -584,6 +589,14 @@ export default class LibDashStore {
|
|||||||
add: modelmessageAdd(provider),
|
add: modelmessageAdd(provider),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.subagentschedule = {
|
||||||
|
create: subagentscheduleCreate(provider),
|
||||||
|
getById: subagentscheduleGetById(provider),
|
||||||
|
list: subagentscheduleList(provider),
|
||||||
|
update: subagentscheduleUpdate(provider),
|
||||||
|
delete: subagentscheduleDelete(provider),
|
||||||
|
};
|
||||||
|
|
||||||
this.labeltemplate = {
|
this.labeltemplate = {
|
||||||
create: labeltemplateCreate(provider),
|
create: labeltemplateCreate(provider),
|
||||||
getById: labeltemplateGetById(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
|
||||||
|
`;
|
||||||
@@ -1376,6 +1376,26 @@ BEGIN
|
|||||||
END
|
END
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const INIT_SUBAGENTSCHEDULE = `
|
||||||
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'subagentschedule')
|
||||||
|
BEGIN
|
||||||
|
CREATE TABLE subagentschedule (
|
||||||
|
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||||
|
company_id INT NOT NULL,
|
||||||
|
[desc] NVARCHAR(MAX) NULL,
|
||||||
|
prompt NVARCHAR(MAX) NOT NULL,
|
||||||
|
skills NVARCHAR(MAX) NULL,
|
||||||
|
lastagentnote NVARCHAR(MAX) NULL,
|
||||||
|
max_itr INT NOT NULL CONSTRAINT DF_subagentschedule_max_itr DEFAULT 15,
|
||||||
|
cron NVARCHAR(100) NOT NULL,
|
||||||
|
created_at DATETIME2 NOT NULL CONSTRAINT DF_subagentschedule_created_at DEFAULT SYSUTCDATETIME(),
|
||||||
|
lastrun_at DATETIME2 NULL,
|
||||||
|
CONSTRAINT FK_subagentschedule_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IX_subagentschedule_company ON subagentschedule (company_id);
|
||||||
|
END
|
||||||
|
`;
|
||||||
|
|
||||||
/** DDL scripts in dependency order for schema init. */
|
/** DDL scripts in dependency order for schema init. */
|
||||||
export const SCHEMA_SCRIPTS = [
|
export const SCHEMA_SCRIPTS = [
|
||||||
INIT_META,
|
INIT_META,
|
||||||
@@ -1450,4 +1470,5 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_MCP_CLIENT,
|
INIT_MCP_CLIENT,
|
||||||
INIT_MCP_AUTH_CODE,
|
INIT_MCP_AUTH_CODE,
|
||||||
INIT_MCP_TOKEN,
|
INIT_MCP_TOKEN,
|
||||||
|
INIT_SUBAGENTSCHEDULE,
|
||||||
];
|
];
|
||||||
|
|||||||
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;
|
||||||
@@ -1011,6 +1011,23 @@ CREATE TABLE IF NOT EXISTS mcp_token (
|
|||||||
);
|
);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const INIT_SUBAGENTSCHEDULE = `
|
||||||
|
CREATE TABLE IF NOT EXISTS subagentschedule (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
company_id INTEGER NOT NULL,
|
||||||
|
"desc" TEXT,
|
||||||
|
prompt TEXT NOT NULL,
|
||||||
|
skills TEXT,
|
||||||
|
lastagentnote TEXT,
|
||||||
|
max_itr INTEGER NOT NULL DEFAULT 15,
|
||||||
|
cron TEXT NOT NULL,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (${UTC_NOW}),
|
||||||
|
lastrun_at TEXT,
|
||||||
|
FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS IX_subagentschedule_company ON subagentschedule (company_id);
|
||||||
|
`;
|
||||||
|
|
||||||
/** DDL scripts in dependency order for SQLite schema initialization. */
|
/** DDL scripts in dependency order for SQLite schema initialization. */
|
||||||
export const SCHEMA_SCRIPTS = [
|
export const SCHEMA_SCRIPTS = [
|
||||||
INIT_META,
|
INIT_META,
|
||||||
@@ -1082,4 +1099,5 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_MCP_CLIENT,
|
INIT_MCP_CLIENT,
|
||||||
INIT_MCP_AUTH_CODE,
|
INIT_MCP_AUTH_CODE,
|
||||||
INIT_MCP_TOKEN,
|
INIT_MCP_TOKEN,
|
||||||
|
INIT_SUBAGENTSCHEDULE,
|
||||||
];
|
];
|
||||||
|
|||||||
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