@deepseek-ai/dsh-schedule 0.2.0-rc.2 → 0.2.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +14 -14
- package/README.md +6 -5
- package/README.zh.md +6 -5
- package/lib/index.js +37 -645
- package/lib/typert.host.js +16 -9
- package/lib/typert.remote-client.js +8 -5
- package/lib/types/domain.d.ts +3 -3
- package/lib/types/domain.js +1 -1
- package/lib/types/index.d.ts +24 -5
- package/lib/types/index.js +40 -30
- package/lib/types/types.d.ts +6 -1
- package/package.json +35 -40
- package/lib/invariant.js +0 -370
- package/lib/types/invariant.d.ts +0 -16
- package/lib/types/invariant.js +0 -58
- package/lib/types/tools.d.ts +0 -15
- package/lib/types/tools.js +0 -505
package/lib/index.js
CHANGED
|
@@ -2,10 +2,10 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { Service } from "@deepseek-ai/cordis";
|
|
4
4
|
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
5
|
+
import { delegationDepthOf } from "@deepseek-ai/dsh-subagent";
|
|
5
6
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
6
7
|
import { Temporal } from "@js-temporal/polyfill";
|
|
7
8
|
import { SessionId, SessionLogOffset } from "@deepseek-ai/dsh-session";
|
|
8
|
-
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
9
9
|
import { z as z$1 } from "zod";
|
|
10
10
|
import { MessageId } from "@deepseek-ai/dsh-llm/brand";
|
|
11
11
|
import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
|
|
@@ -42,7 +42,7 @@ var ScheduleLogError = class extends Error {
|
|
|
42
42
|
this.name = "ScheduleLogError";
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
|
-
/** Error from a model-supplied Schedule rule that cannot become a record. */
|
|
45
|
+
/** Error from a model-supplied Schedule rule or target Session that cannot become a record. */
|
|
46
46
|
var ScheduleInputError = class extends Error {
|
|
47
47
|
/** Stable public Schedule input code. */
|
|
48
48
|
code;
|
|
@@ -1647,627 +1647,6 @@ var ScheduleRuntime = class {
|
|
|
1647
1647
|
}
|
|
1648
1648
|
};
|
|
1649
1649
|
//#endregion
|
|
1650
|
-
//#region lib/types/tools.js
|
|
1651
|
-
/**
|
|
1652
|
-
* Agent-scoped consumers of the shared Host Schedule management service.
|
|
1653
|
-
* @module @deepseek-ai/dsh-schedule
|
|
1654
|
-
*/
|
|
1655
|
-
const SHARED_VIEW_PROPERTIES = {
|
|
1656
|
-
id: {
|
|
1657
|
-
type: "string",
|
|
1658
|
-
required: true
|
|
1659
|
-
},
|
|
1660
|
-
title: {
|
|
1661
|
-
type: "string",
|
|
1662
|
-
required: true
|
|
1663
|
-
},
|
|
1664
|
-
prompt: {
|
|
1665
|
-
type: "string",
|
|
1666
|
-
required: true
|
|
1667
|
-
},
|
|
1668
|
-
scheduledAt: {
|
|
1669
|
-
type: "string",
|
|
1670
|
-
required: true
|
|
1671
|
-
},
|
|
1672
|
-
state: {
|
|
1673
|
-
type: "string",
|
|
1674
|
-
required: true,
|
|
1675
|
-
enum: ["scheduled", "overdue"]
|
|
1676
|
-
},
|
|
1677
|
-
deliveryMode: {
|
|
1678
|
-
type: "string",
|
|
1679
|
-
required: true,
|
|
1680
|
-
const: "host"
|
|
1681
|
-
}
|
|
1682
|
-
};
|
|
1683
|
-
const VIEW_SCHEMA = { oneOf: [
|
|
1684
|
-
{
|
|
1685
|
-
type: "object",
|
|
1686
|
-
additionalProperties: false,
|
|
1687
|
-
properties: {
|
|
1688
|
-
...SHARED_VIEW_PROPERTIES,
|
|
1689
|
-
kind: {
|
|
1690
|
-
type: "string",
|
|
1691
|
-
required: true,
|
|
1692
|
-
const: "after"
|
|
1693
|
-
},
|
|
1694
|
-
afterSeconds: {
|
|
1695
|
-
type: "integer",
|
|
1696
|
-
required: true
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
},
|
|
1700
|
-
{
|
|
1701
|
-
type: "object",
|
|
1702
|
-
additionalProperties: false,
|
|
1703
|
-
properties: {
|
|
1704
|
-
...SHARED_VIEW_PROPERTIES,
|
|
1705
|
-
kind: {
|
|
1706
|
-
type: "string",
|
|
1707
|
-
required: true,
|
|
1708
|
-
const: "at"
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
},
|
|
1712
|
-
{
|
|
1713
|
-
type: "object",
|
|
1714
|
-
additionalProperties: false,
|
|
1715
|
-
properties: {
|
|
1716
|
-
...SHARED_VIEW_PROPERTIES,
|
|
1717
|
-
kind: {
|
|
1718
|
-
type: "string",
|
|
1719
|
-
required: true,
|
|
1720
|
-
const: "every"
|
|
1721
|
-
},
|
|
1722
|
-
everySeconds: {
|
|
1723
|
-
type: "integer",
|
|
1724
|
-
required: true
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
},
|
|
1728
|
-
{
|
|
1729
|
-
type: "object",
|
|
1730
|
-
additionalProperties: false,
|
|
1731
|
-
properties: {
|
|
1732
|
-
...SHARED_VIEW_PROPERTIES,
|
|
1733
|
-
kind: {
|
|
1734
|
-
type: "string",
|
|
1735
|
-
required: true,
|
|
1736
|
-
const: "daily"
|
|
1737
|
-
},
|
|
1738
|
-
time: {
|
|
1739
|
-
type: "string",
|
|
1740
|
-
required: true
|
|
1741
|
-
},
|
|
1742
|
-
timeZone: {
|
|
1743
|
-
type: "string",
|
|
1744
|
-
required: true
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
},
|
|
1748
|
-
{
|
|
1749
|
-
type: "object",
|
|
1750
|
-
additionalProperties: false,
|
|
1751
|
-
properties: {
|
|
1752
|
-
...SHARED_VIEW_PROPERTIES,
|
|
1753
|
-
kind: {
|
|
1754
|
-
type: "string",
|
|
1755
|
-
required: true,
|
|
1756
|
-
const: "weekly"
|
|
1757
|
-
},
|
|
1758
|
-
time: {
|
|
1759
|
-
type: "string",
|
|
1760
|
-
required: true
|
|
1761
|
-
},
|
|
1762
|
-
timeZone: {
|
|
1763
|
-
type: "string",
|
|
1764
|
-
required: true
|
|
1765
|
-
},
|
|
1766
|
-
weekdays: {
|
|
1767
|
-
type: "array",
|
|
1768
|
-
required: true,
|
|
1769
|
-
items: { type: "integer" }
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
},
|
|
1773
|
-
{
|
|
1774
|
-
type: "object",
|
|
1775
|
-
additionalProperties: false,
|
|
1776
|
-
properties: {
|
|
1777
|
-
...SHARED_VIEW_PROPERTIES,
|
|
1778
|
-
kind: {
|
|
1779
|
-
type: "string",
|
|
1780
|
-
required: true,
|
|
1781
|
-
const: "cron"
|
|
1782
|
-
},
|
|
1783
|
-
expression: {
|
|
1784
|
-
type: "string",
|
|
1785
|
-
required: true
|
|
1786
|
-
},
|
|
1787
|
-
timeZone: {
|
|
1788
|
-
type: "string",
|
|
1789
|
-
required: true
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
}
|
|
1793
|
-
] };
|
|
1794
|
-
/** Build one exact two-field error schema while preserving its literal code. */
|
|
1795
|
-
function basicErrorSchema(code) {
|
|
1796
|
-
return {
|
|
1797
|
-
type: "object",
|
|
1798
|
-
additionalProperties: false,
|
|
1799
|
-
properties: {
|
|
1800
|
-
code: {
|
|
1801
|
-
type: "string",
|
|
1802
|
-
required: true,
|
|
1803
|
-
const: code
|
|
1804
|
-
},
|
|
1805
|
-
message: {
|
|
1806
|
-
type: "string",
|
|
1807
|
-
required: true
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
};
|
|
1811
|
-
}
|
|
1812
|
-
const ERROR_SCHEMAS = [
|
|
1813
|
-
basicErrorSchema("invalid_prompt"),
|
|
1814
|
-
basicErrorSchema("invalid_selector"),
|
|
1815
|
-
basicErrorSchema("invalid_rule"),
|
|
1816
|
-
basicErrorSchema("invalid_time_zone"),
|
|
1817
|
-
basicErrorSchema("not_future"),
|
|
1818
|
-
basicErrorSchema("time_out_of_range"),
|
|
1819
|
-
basicErrorSchema("frequency_too_high"),
|
|
1820
|
-
basicErrorSchema("internal_error")
|
|
1821
|
-
];
|
|
1822
|
-
const CREATE_OUTPUT_SCHEMA = { oneOf: [VIEW_SCHEMA, ...ERROR_SCHEMAS] };
|
|
1823
|
-
const LIST_OUTPUT_SCHEMA = { oneOf: [{
|
|
1824
|
-
type: "array",
|
|
1825
|
-
items: VIEW_SCHEMA
|
|
1826
|
-
}, ...ERROR_SCHEMAS] };
|
|
1827
|
-
const DELETE_OUTPUT_SCHEMA = { oneOf: [
|
|
1828
|
-
{
|
|
1829
|
-
type: "object",
|
|
1830
|
-
additionalProperties: false,
|
|
1831
|
-
properties: {
|
|
1832
|
-
id: {
|
|
1833
|
-
type: "string",
|
|
1834
|
-
required: true
|
|
1835
|
-
},
|
|
1836
|
-
deleted: {
|
|
1837
|
-
type: "boolean",
|
|
1838
|
-
required: true,
|
|
1839
|
-
const: true
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
},
|
|
1843
|
-
{
|
|
1844
|
-
type: "object",
|
|
1845
|
-
additionalProperties: false,
|
|
1846
|
-
properties: {
|
|
1847
|
-
id: {
|
|
1848
|
-
type: "string",
|
|
1849
|
-
required: true
|
|
1850
|
-
},
|
|
1851
|
-
deleted: {
|
|
1852
|
-
type: "boolean",
|
|
1853
|
-
required: true,
|
|
1854
|
-
const: false
|
|
1855
|
-
},
|
|
1856
|
-
code: {
|
|
1857
|
-
type: "string",
|
|
1858
|
-
required: true,
|
|
1859
|
-
const: "schedule_not_found"
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
},
|
|
1863
|
-
...ERROR_SCHEMAS
|
|
1864
|
-
] };
|
|
1865
|
-
const UPDATE_OUTPUT_SCHEMA = { oneOf: [
|
|
1866
|
-
VIEW_SCHEMA,
|
|
1867
|
-
{
|
|
1868
|
-
type: "object",
|
|
1869
|
-
additionalProperties: false,
|
|
1870
|
-
properties: {
|
|
1871
|
-
id: {
|
|
1872
|
-
type: "string",
|
|
1873
|
-
required: true
|
|
1874
|
-
},
|
|
1875
|
-
updated: {
|
|
1876
|
-
type: "boolean",
|
|
1877
|
-
required: true,
|
|
1878
|
-
const: false
|
|
1879
|
-
},
|
|
1880
|
-
code: {
|
|
1881
|
-
type: "string",
|
|
1882
|
-
required: true,
|
|
1883
|
-
enum: [
|
|
1884
|
-
"schedule_not_found",
|
|
1885
|
-
"schedule_ended",
|
|
1886
|
-
"schedule_conflict"
|
|
1887
|
-
]
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
},
|
|
1891
|
-
...ERROR_SCHEMAS
|
|
1892
|
-
] };
|
|
1893
|
-
const CREATE_DESCRIPTION = "Create a reminder in the current session that delivers prompt when it becomes due. Supply exactly one timing parameter: after_seconds, at, every_seconds, daily, weekly, or cron. Local times that do not exist in the zone are skipped; repeated local times fire once, at the earlier instant. After downtime, a recurring reminder delivers only its latest missed occurrence. Delivery can repeat after a crash.";
|
|
1894
|
-
const LIST_DESCRIPTION = "List the active reminders in the current session.";
|
|
1895
|
-
const DELETE_DESCRIPTION = "Delete a reminder in the current session, active or inactive. Deletion does not retract a reminder message that is already queued.";
|
|
1896
|
-
const UPDATE_DESCRIPTION = "Change a reminder in place, keeping its id. Supply a new title, prompt, or at most one timing parameter; omitted fields keep their stored values. To change a relative delay, create a new reminder.";
|
|
1897
|
-
/** Deterministic model content for every canonical Schedule value. */
|
|
1898
|
-
function renderValue(_args, value) {
|
|
1899
|
-
return [{
|
|
1900
|
-
type: "text",
|
|
1901
|
-
text: JSON.stringify(value)
|
|
1902
|
-
}];
|
|
1903
|
-
}
|
|
1904
|
-
/** Pure generic pending card. */
|
|
1905
|
-
function present(title, kind, rawInput) {
|
|
1906
|
-
return {
|
|
1907
|
-
card: "generic",
|
|
1908
|
-
title,
|
|
1909
|
-
kind,
|
|
1910
|
-
...rawInput === void 0 ? {} : { rawInput }
|
|
1911
|
-
};
|
|
1912
|
-
}
|
|
1913
|
-
/** Stable error for failures not safe to expose. */
|
|
1914
|
-
function internalError() {
|
|
1915
|
-
return {
|
|
1916
|
-
code: "internal_error",
|
|
1917
|
-
message: "The schedule operation failed."
|
|
1918
|
-
};
|
|
1919
|
-
}
|
|
1920
|
-
/** Translate invalid input while withholding internal storage failures. */
|
|
1921
|
-
function operationError(error) {
|
|
1922
|
-
return error instanceof ScheduleInputError ? {
|
|
1923
|
-
code: error.code,
|
|
1924
|
-
message: error.message
|
|
1925
|
-
} : internalError();
|
|
1926
|
-
}
|
|
1927
|
-
/** One supplied fixed-rate interval: a safe integer at or above the Host floor, or undefined. */
|
|
1928
|
-
function invalidInterval(everySeconds) {
|
|
1929
|
-
if (everySeconds === void 0) return void 0;
|
|
1930
|
-
if (!Number.isSafeInteger(everySeconds)) return {
|
|
1931
|
-
code: "invalid_rule",
|
|
1932
|
-
message: "every_seconds must be a safe integer."
|
|
1933
|
-
};
|
|
1934
|
-
if (everySeconds < 60) return {
|
|
1935
|
-
code: "frequency_too_high",
|
|
1936
|
-
message: `every_seconds must be at least 60.`
|
|
1937
|
-
};
|
|
1938
|
-
}
|
|
1939
|
-
/** Validate selector constraints that the open parameter root cannot express. */
|
|
1940
|
-
function validateCreateArgs(args) {
|
|
1941
|
-
if (Object.keys(args).some((key) => key !== "prompt" && key !== "title" && key !== "after_seconds" && key !== "at" && key !== "every_seconds" && key !== "daily" && key !== "weekly" && key !== "cron") || Number(args.after_seconds !== void 0) + Number(args.at !== void 0) + Number(args.every_seconds !== void 0) + Number(args.daily !== void 0) + Number(args.weekly !== void 0) + Number(args.cron !== void 0) !== 1) return {
|
|
1942
|
-
code: "invalid_selector",
|
|
1943
|
-
message: "schedule_create accepts exactly one of after_seconds, at, every_seconds, daily, weekly, or cron."
|
|
1944
|
-
};
|
|
1945
|
-
if (args.prompt.trim().length === 0) return {
|
|
1946
|
-
code: "invalid_prompt",
|
|
1947
|
-
message: "prompt must be non-empty after trimming."
|
|
1948
|
-
};
|
|
1949
|
-
if (args.title.trim().length === 0) return {
|
|
1950
|
-
code: "invalid_prompt",
|
|
1951
|
-
message: REQUIRED_TITLE_MESSAGE
|
|
1952
|
-
};
|
|
1953
|
-
if (args.title.trim().length > 120) return {
|
|
1954
|
-
code: "invalid_prompt",
|
|
1955
|
-
message: `title must be at most 120 characters.`
|
|
1956
|
-
};
|
|
1957
|
-
if (args.after_seconds !== void 0 && (!Number.isSafeInteger(args.after_seconds) || args.after_seconds <= 0)) return {
|
|
1958
|
-
code: "invalid_rule",
|
|
1959
|
-
message: "after_seconds must be a positive safe integer."
|
|
1960
|
-
};
|
|
1961
|
-
return invalidInterval(args.every_seconds);
|
|
1962
|
-
}
|
|
1963
|
-
/** Validate the in-place update's selector count, id, and any supplied name, instruction, or interval. */
|
|
1964
|
-
function validateUpdateArgs(args) {
|
|
1965
|
-
const selectors = [
|
|
1966
|
-
args.at !== void 0,
|
|
1967
|
-
args.every_seconds !== void 0,
|
|
1968
|
-
args.daily !== void 0,
|
|
1969
|
-
args.weekly !== void 0,
|
|
1970
|
-
args.cron !== void 0
|
|
1971
|
-
].filter(Boolean).length;
|
|
1972
|
-
if (Object.keys(args).some((key) => key !== "id" && key !== "title" && key !== "prompt" && key !== "at" && key !== "every_seconds" && key !== "daily" && key !== "weekly" && key !== "cron") || selectors > 1) return {
|
|
1973
|
-
code: "invalid_selector",
|
|
1974
|
-
message: "schedule_update accepts at most one of at, every_seconds, daily, weekly, or cron."
|
|
1975
|
-
};
|
|
1976
|
-
if (args.id.length === 0 || args.id.trim() !== args.id) return {
|
|
1977
|
-
code: "invalid_rule",
|
|
1978
|
-
message: "schedule_update id must be non-empty without surrounding whitespace."
|
|
1979
|
-
};
|
|
1980
|
-
if (selectors === 0 && args.title === void 0 && args.prompt === void 0) return {
|
|
1981
|
-
code: "invalid_selector",
|
|
1982
|
-
message: "schedule_update needs a new title, prompt, or one of at, every_seconds, daily, weekly, or cron."
|
|
1983
|
-
};
|
|
1984
|
-
if (args.title !== void 0 && args.title.trim().length === 0) return {
|
|
1985
|
-
code: "invalid_prompt",
|
|
1986
|
-
message: REQUIRED_TITLE_MESSAGE
|
|
1987
|
-
};
|
|
1988
|
-
if (args.title !== void 0 && args.title.trim().length > 120) return {
|
|
1989
|
-
code: "invalid_prompt",
|
|
1990
|
-
message: `title must be at most 120 characters.`
|
|
1991
|
-
};
|
|
1992
|
-
if (args.prompt !== void 0 && args.prompt.trim().length === 0) return {
|
|
1993
|
-
code: "invalid_prompt",
|
|
1994
|
-
message: "prompt must be non-empty after trimming."
|
|
1995
|
-
};
|
|
1996
|
-
return invalidInterval(args.every_seconds);
|
|
1997
|
-
}
|
|
1998
|
-
/** The one timing replacement the update carries, or undefined when the request keeps the committed target. */
|
|
1999
|
-
function timingChangeFrom(args) {
|
|
2000
|
-
if (args.at !== void 0) return {
|
|
2001
|
-
kind: "at",
|
|
2002
|
-
at: args.at
|
|
2003
|
-
};
|
|
2004
|
-
if (args.every_seconds !== void 0) return {
|
|
2005
|
-
kind: "every",
|
|
2006
|
-
every_seconds: args.every_seconds
|
|
2007
|
-
};
|
|
2008
|
-
if (args.daily !== void 0) return {
|
|
2009
|
-
kind: "daily",
|
|
2010
|
-
daily: args.daily
|
|
2011
|
-
};
|
|
2012
|
-
if (args.weekly !== void 0) return {
|
|
2013
|
-
kind: "weekly",
|
|
2014
|
-
weekly: args.weekly
|
|
2015
|
-
};
|
|
2016
|
-
if (args.cron !== void 0) return {
|
|
2017
|
-
kind: "cron",
|
|
2018
|
-
cron: args.cron
|
|
2019
|
-
};
|
|
2020
|
-
}
|
|
2021
|
-
/**
|
|
2022
|
-
* Selector parameters shared by `schedule_create` and `schedule_update`, in the order the
|
|
2023
|
-
* generated tool catalog states them.
|
|
2024
|
-
*/
|
|
2025
|
-
const SELECTOR_PARAMETERS = {
|
|
2026
|
-
every_seconds: {
|
|
2027
|
-
type: "number",
|
|
2028
|
-
description: `Fixed-rate interval in whole seconds, at least 60, aligned to the creation time; changing it with schedule_update re-aligns it to the save time.`
|
|
2029
|
-
},
|
|
2030
|
-
daily: {
|
|
2031
|
-
type: "object",
|
|
2032
|
-
additionalProperties: false,
|
|
2033
|
-
description: "Every day at a local time.",
|
|
2034
|
-
properties: {
|
|
2035
|
-
time: {
|
|
2036
|
-
type: "string",
|
|
2037
|
-
required: true,
|
|
2038
|
-
description: "HH:mm:ss with optional 1-3 fractional digits, for example 23:00:00."
|
|
2039
|
-
},
|
|
2040
|
-
time_zone: {
|
|
2041
|
-
type: "string",
|
|
2042
|
-
required: true,
|
|
2043
|
-
description: "UTC or IANA Area/Location, for example Asia/Shanghai."
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
},
|
|
2047
|
-
weekly: {
|
|
2048
|
-
type: "object",
|
|
2049
|
-
additionalProperties: false,
|
|
2050
|
-
description: "On the given weekdays at a local time.",
|
|
2051
|
-
properties: {
|
|
2052
|
-
time: {
|
|
2053
|
-
type: "string",
|
|
2054
|
-
required: true,
|
|
2055
|
-
description: "HH:mm:ss with optional 1-3 fractional digits, for example 09:00:00."
|
|
2056
|
-
},
|
|
2057
|
-
time_zone: {
|
|
2058
|
-
type: "string",
|
|
2059
|
-
required: true,
|
|
2060
|
-
description: "UTC or IANA Area/Location, for example Asia/Shanghai."
|
|
2061
|
-
},
|
|
2062
|
-
weekdays: {
|
|
2063
|
-
type: "array",
|
|
2064
|
-
required: true,
|
|
2065
|
-
description: "ISO weekdays, Monday 1 through Sunday 7, without repetitions.",
|
|
2066
|
-
items: { type: "integer" }
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
},
|
|
2070
|
-
cron: {
|
|
2071
|
-
type: "object",
|
|
2072
|
-
additionalProperties: false,
|
|
2073
|
-
description: "Five-field Vixie cron expression in a time zone.",
|
|
2074
|
-
properties: {
|
|
2075
|
-
expression: {
|
|
2076
|
-
type: "string",
|
|
2077
|
-
required: true,
|
|
2078
|
-
description: "minute hour day-of-month month day-of-week, for example \"*/15 9-17 * * 1-5\". When both day fields are restricted, a date matches if either one matches."
|
|
2079
|
-
},
|
|
2080
|
-
time_zone: {
|
|
2081
|
-
type: "string",
|
|
2082
|
-
required: true,
|
|
2083
|
-
description: "UTC or IANA Area/Location, for example Asia/Shanghai."
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
},
|
|
2087
|
-
at: {
|
|
2088
|
-
description: "Absolute target: an RFC 3339 date-time with offset, or a local date, time, and IANA time_zone.",
|
|
2089
|
-
oneOf: [{ type: "string" }, {
|
|
2090
|
-
type: "object",
|
|
2091
|
-
additionalProperties: false,
|
|
2092
|
-
properties: {
|
|
2093
|
-
date: {
|
|
2094
|
-
type: "string",
|
|
2095
|
-
required: true
|
|
2096
|
-
},
|
|
2097
|
-
time: {
|
|
2098
|
-
type: "string",
|
|
2099
|
-
required: true
|
|
2100
|
-
},
|
|
2101
|
-
time_zone: {
|
|
2102
|
-
type: "string",
|
|
2103
|
-
required: true
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
}]
|
|
2107
|
-
}
|
|
2108
|
-
};
|
|
2109
|
-
/**
|
|
2110
|
-
* Register all four Schedule tools in one exact agent scope.
|
|
2111
|
-
* @param rootCtx - Host context owning the shared Schedule service.
|
|
2112
|
-
* @param toolCtx - Exact agent-scoped context receiving the definitions.
|
|
2113
|
-
* @param agent - Exact live owner whose session the tools mutate.
|
|
2114
|
-
* @returns Idempotent aggregate disposer for the four registrations.
|
|
2115
|
-
*/
|
|
2116
|
-
function registerScheduleTools(rootCtx, toolCtx, agent) {
|
|
2117
|
-
const disposers = [];
|
|
2118
|
-
try {
|
|
2119
|
-
disposers.push(toolCtx.tools.register(defineTool({
|
|
2120
|
-
name: "schedule_create",
|
|
2121
|
-
description: CREATE_DESCRIPTION,
|
|
2122
|
-
parameters: {
|
|
2123
|
-
prompt: {
|
|
2124
|
-
type: "string",
|
|
2125
|
-
required: true,
|
|
2126
|
-
description: "Reminder content to present when the target becomes due."
|
|
2127
|
-
},
|
|
2128
|
-
title: {
|
|
2129
|
-
type: "string",
|
|
2130
|
-
required: true,
|
|
2131
|
-
description: `Task name of at most 120 characters, shown on the task card and in task lists.`
|
|
2132
|
-
},
|
|
2133
|
-
after_seconds: {
|
|
2134
|
-
type: "number",
|
|
2135
|
-
description: "Delay in whole seconds."
|
|
2136
|
-
},
|
|
2137
|
-
...SELECTOR_PARAMETERS
|
|
2138
|
-
},
|
|
2139
|
-
output: {
|
|
2140
|
-
schema: CREATE_OUTPUT_SCHEMA,
|
|
2141
|
-
render: renderValue
|
|
2142
|
-
},
|
|
2143
|
-
async execute(args, exec) {
|
|
2144
|
-
if (exec.agent !== agent) return internalError();
|
|
2145
|
-
const invalid = validateCreateArgs(args);
|
|
2146
|
-
if (invalid !== void 0) return invalid;
|
|
2147
|
-
if (exec.signal.aborted) return internalError();
|
|
2148
|
-
try {
|
|
2149
|
-
return scheduleView(await rootCtx.schedule.create(agent.session.id, args, exec.signal), Date.now());
|
|
2150
|
-
} catch (error) {
|
|
2151
|
-
return operationError(error);
|
|
2152
|
-
}
|
|
2153
|
-
},
|
|
2154
|
-
presentCall: (args) => present("Create reminder", "other", args.prompt)
|
|
2155
|
-
})));
|
|
2156
|
-
disposers.push(toolCtx.tools.register(defineTool({
|
|
2157
|
-
name: "schedule_list",
|
|
2158
|
-
description: LIST_DESCRIPTION,
|
|
2159
|
-
parameters: {},
|
|
2160
|
-
output: {
|
|
2161
|
-
schema: LIST_OUTPUT_SCHEMA,
|
|
2162
|
-
render: renderValue
|
|
2163
|
-
},
|
|
2164
|
-
async execute(_args, exec) {
|
|
2165
|
-
if (exec.agent !== agent) return internalError();
|
|
2166
|
-
if (exec.signal.aborted) return internalError();
|
|
2167
|
-
try {
|
|
2168
|
-
return (await rootCtx.schedule.list({ sessionId: agent.session.id })).map((record) => scheduleView(record, Date.now()));
|
|
2169
|
-
} catch (error) {
|
|
2170
|
-
return operationError(error);
|
|
2171
|
-
}
|
|
2172
|
-
},
|
|
2173
|
-
presentCall: () => present("List reminders", "read")
|
|
2174
|
-
})));
|
|
2175
|
-
disposers.push(toolCtx.tools.register(defineTool({
|
|
2176
|
-
name: "schedule_delete",
|
|
2177
|
-
description: DELETE_DESCRIPTION,
|
|
2178
|
-
parameters: { id: {
|
|
2179
|
-
type: "string",
|
|
2180
|
-
required: true,
|
|
2181
|
-
description: "Schedule id returned by schedule_list."
|
|
2182
|
-
} },
|
|
2183
|
-
output: {
|
|
2184
|
-
schema: DELETE_OUTPUT_SCHEMA,
|
|
2185
|
-
render: renderValue
|
|
2186
|
-
},
|
|
2187
|
-
async execute(args, exec) {
|
|
2188
|
-
if (args.id.length === 0 || args.id.trim() !== args.id) return {
|
|
2189
|
-
code: "invalid_rule",
|
|
2190
|
-
message: "schedule_delete id must be non-empty without surrounding whitespace."
|
|
2191
|
-
};
|
|
2192
|
-
const id = ScheduleId(args.id);
|
|
2193
|
-
if (exec.agent !== agent) return internalError();
|
|
2194
|
-
if (exec.signal.aborted) return internalError();
|
|
2195
|
-
try {
|
|
2196
|
-
return await rootCtx.schedule.delete({
|
|
2197
|
-
sessionId: agent.session.id,
|
|
2198
|
-
id
|
|
2199
|
-
}, exec.signal);
|
|
2200
|
-
} catch (error) {
|
|
2201
|
-
return operationError(error);
|
|
2202
|
-
}
|
|
2203
|
-
},
|
|
2204
|
-
presentCall: (args) => present("Delete reminder", "other", args.id)
|
|
2205
|
-
})));
|
|
2206
|
-
disposers.push(toolCtx.tools.register(defineTool({
|
|
2207
|
-
name: "schedule_update",
|
|
2208
|
-
description: UPDATE_DESCRIPTION,
|
|
2209
|
-
parameters: {
|
|
2210
|
-
id: {
|
|
2211
|
-
type: "string",
|
|
2212
|
-
required: true,
|
|
2213
|
-
description: "Schedule id returned by schedule_list."
|
|
2214
|
-
},
|
|
2215
|
-
title: {
|
|
2216
|
-
type: "string",
|
|
2217
|
-
description: `New task name of at most 120 characters.`
|
|
2218
|
-
},
|
|
2219
|
-
prompt: {
|
|
2220
|
-
type: "string",
|
|
2221
|
-
description: "New reminder content."
|
|
2222
|
-
},
|
|
2223
|
-
...SELECTOR_PARAMETERS
|
|
2224
|
-
},
|
|
2225
|
-
output: {
|
|
2226
|
-
schema: UPDATE_OUTPUT_SCHEMA,
|
|
2227
|
-
render: renderValue
|
|
2228
|
-
},
|
|
2229
|
-
async execute(args, exec) {
|
|
2230
|
-
if (exec.agent !== agent) return internalError();
|
|
2231
|
-
const invalid = validateUpdateArgs(args);
|
|
2232
|
-
if (invalid !== void 0) return invalid;
|
|
2233
|
-
if (exec.signal.aborted) return internalError();
|
|
2234
|
-
const id = ScheduleId(args.id);
|
|
2235
|
-
try {
|
|
2236
|
-
const sessionId = agent.session.id;
|
|
2237
|
-
const expected = (await rootCtx.schedule.list({ sessionId })).find((record) => record.id === id);
|
|
2238
|
-
if (expected === void 0) return {
|
|
2239
|
-
id,
|
|
2240
|
-
updated: false,
|
|
2241
|
-
code: (await rootCtx.schedule.catalog()).some((entry) => entry.sessionId === sessionId && entry.id === id) ? "schedule_ended" : "schedule_not_found"
|
|
2242
|
-
};
|
|
2243
|
-
const change = timingChangeFrom(args);
|
|
2244
|
-
const result = await rootCtx.schedule.update({
|
|
2245
|
-
sessionId,
|
|
2246
|
-
id,
|
|
2247
|
-
expected,
|
|
2248
|
-
...change === void 0 ? {} : { change },
|
|
2249
|
-
...args.title === void 0 ? {} : { title: args.title },
|
|
2250
|
-
...args.prompt === void 0 ? {} : { prompt: args.prompt }
|
|
2251
|
-
}, exec.signal);
|
|
2252
|
-
return "record" in result ? scheduleView(result.record, Date.now()) : result;
|
|
2253
|
-
} catch (error) {
|
|
2254
|
-
return operationError(error);
|
|
2255
|
-
}
|
|
2256
|
-
},
|
|
2257
|
-
presentCall: (args) => present("Update reminder", "other", args.id)
|
|
2258
|
-
})));
|
|
2259
|
-
} catch (error) {
|
|
2260
|
-
for (const dispose of disposers.reverse()) dispose();
|
|
2261
|
-
throw error;
|
|
2262
|
-
}
|
|
2263
|
-
let active = true;
|
|
2264
|
-
return () => {
|
|
2265
|
-
if (!active) return;
|
|
2266
|
-
active = false;
|
|
2267
|
-
for (const dispose of disposers.reverse()) dispose();
|
|
2268
|
-
};
|
|
2269
|
-
}
|
|
2270
|
-
//#endregion
|
|
2271
1650
|
//#region lib/types/storage.js
|
|
2272
1651
|
/** Durable Host-wide Schedule tasks, independently of Session activation. */
|
|
2273
1652
|
const recordSchema = z$1.unknown().transform((value, context) => {
|
|
@@ -2590,7 +1969,6 @@ let ScheduleService = (() => {
|
|
|
2590
1969
|
static inject = [
|
|
2591
1970
|
"agents",
|
|
2592
1971
|
"sessions",
|
|
2593
|
-
"tools",
|
|
2594
1972
|
"storageDomain",
|
|
2595
1973
|
"sessionController",
|
|
2596
1974
|
"sessionPersistence"
|
|
@@ -2650,22 +2028,6 @@ let ScheduleService = (() => {
|
|
|
2650
2028
|
this.runtime.requestDrive();
|
|
2651
2029
|
return cleanup;
|
|
2652
2030
|
});
|
|
2653
|
-
const registered = /* @__PURE__ */ new WeakSet();
|
|
2654
|
-
const attached = /* @__PURE__ */ new Map();
|
|
2655
|
-
const attach = (agent) => {
|
|
2656
|
-
if (this.stopping || registered.has(agent) || !ctx.agents.roots().includes(agent)) return;
|
|
2657
|
-
registered.add(agent);
|
|
2658
|
-
attached.set(agent, ctx.effect(() => agent.ctx.effect(() => registerScheduleTools(ctx, agent.ctx, agent))));
|
|
2659
|
-
};
|
|
2660
|
-
ctx.on("agent/created", ({ agent }) => {
|
|
2661
|
-
attach(agent);
|
|
2662
|
-
});
|
|
2663
|
-
ctx.on("agent/disposed", ({ agent }) => {
|
|
2664
|
-
const detach = attached.get(agent);
|
|
2665
|
-
if (detach === void 0) return;
|
|
2666
|
-
attached.delete(agent);
|
|
2667
|
-
detach();
|
|
2668
|
-
});
|
|
2669
2031
|
ctx.on("session/created", (session) => {
|
|
2670
2032
|
let activeLegacy = 0;
|
|
2671
2033
|
try {
|
|
@@ -2699,7 +2061,6 @@ let ScheduleService = (() => {
|
|
|
2699
2061
|
activity();
|
|
2700
2062
|
};
|
|
2701
2063
|
}, "schedule.archiveAdmission()");
|
|
2702
|
-
for (const agent of ctx.agents.roots()) attach(agent);
|
|
2703
2064
|
}
|
|
2704
2065
|
async [Service.init]() {
|
|
2705
2066
|
await this.initialized;
|
|
@@ -2709,6 +2070,8 @@ let ScheduleService = (() => {
|
|
|
2709
2070
|
*
|
|
2710
2071
|
* The request must supply a title; a missing, blank-after-trim, or over-long
|
|
2711
2072
|
* title rejects with `invalid_prompt` instead of deriving one from the prompt.
|
|
2073
|
+
* A Session a delegated child owns rejects with `subagent_session`, because delivery
|
|
2074
|
+
* can never reach it: the child is one whose delegation depth is above zero.
|
|
2712
2075
|
* The record is built from the clock reading taken before the request joins the
|
|
2713
2076
|
* serialized queue, so a create that waits behind a longer operation keeps its
|
|
2714
2077
|
* request-time anchor and may already be due when the queue reaches it.
|
|
@@ -2731,6 +2094,8 @@ let ScheduleService = (() => {
|
|
|
2731
2094
|
else if (request.cron !== void 0) record = createCronScheduleRecord(id, request.prompt, request.cron, now, title);
|
|
2732
2095
|
else throw new ScheduleInputError("invalid_selector", "Exactly one reminder selector is required.");
|
|
2733
2096
|
return this.serialize(async () => {
|
|
2097
|
+
const refusal = this.reminderTargetRefusal(sessionId);
|
|
2098
|
+
if (refusal !== void 0) throw new ScheduleInputError("subagent_session", refusal.message);
|
|
2734
2099
|
const domain = await this.getDomain();
|
|
2735
2100
|
signal?.throwIfAborted();
|
|
2736
2101
|
await domain.table("tasks").put(id, {
|
|
@@ -2789,7 +2154,9 @@ let ScheduleService = (() => {
|
|
|
2789
2154
|
* Delete one task belonging to the selected Session, leaving queued messages intact.
|
|
2790
2155
|
*
|
|
2791
2156
|
* The row is removed: the task no longer schedules, leaves `list` and `catalog`, and its
|
|
2792
|
-
* saved delivery records go with it.
|
|
2157
|
+
* saved delivery records go with it. A task bound to a Session a delegated child owns
|
|
2158
|
+
* stays deletable even though creation and timing edits refuse that binding, so a task
|
|
2159
|
+
* stored before that rule existed remains removable.
|
|
2793
2160
|
* @param request - Session and exact task identity.
|
|
2794
2161
|
* @param signal - Optional cancellation checked before persistence begins, including after FIFO waits.
|
|
2795
2162
|
* @returns Whether that Session owned a deleted task. Cancellation does not roll back an in-flight write.
|
|
@@ -2818,14 +2185,19 @@ let ScheduleService = (() => {
|
|
|
2818
2185
|
* binding without activating the Session or changing saved deliveries.
|
|
2819
2186
|
*
|
|
2820
2187
|
* Each supplied field replaces its stored value; an omitted field keeps it. A name or
|
|
2821
|
-
* instruction change alone does not reset the committed target.
|
|
2188
|
+
* instruction change alone does not reset the committed target. A Session a delegated
|
|
2189
|
+
* child owns returns the non-mutating `subagent_session` result, so an edit cannot
|
|
2190
|
+
* re-arm a task bound to a Session delivery can never reach, and the Web editor can
|
|
2191
|
+
* explain the refusal through the ordinary result it already renders.
|
|
2822
2192
|
* @param request - Task binding, complete observed record, and any combination of timing, name, and instruction.
|
|
2823
2193
|
* @param signal - Cancellation checked after domain readiness and FIFO waits, before persistence begins.
|
|
2824
|
-
* @returns The committed record, unchanged record for a no-op, or a non-mutating input/lookup/conflict result.
|
|
2194
|
+
* @returns The committed record, unchanged record for a no-op, or a non-mutating input/lookup/conflict/refusal result.
|
|
2825
2195
|
* Storage and lifecycle failures reject; cancellation after a write starts does not roll it back.
|
|
2826
2196
|
*/
|
|
2827
2197
|
async update(request, signal) {
|
|
2828
2198
|
return this.serialize(async () => {
|
|
2199
|
+
const refusal = this.reminderTargetRefusal(request.sessionId);
|
|
2200
|
+
if (refusal !== void 0) return refusal;
|
|
2829
2201
|
const tasks = (await this.getDomain()).table("tasks");
|
|
2830
2202
|
signal?.throwIfAborted();
|
|
2831
2203
|
const current = tasks.get(request.id);
|
|
@@ -2868,6 +2240,26 @@ let ScheduleService = (() => {
|
|
|
2868
2240
|
return this.ready;
|
|
2869
2241
|
}
|
|
2870
2242
|
/**
|
|
2243
|
+
* Refuse a Session no delivery can reach because a delegated child owns it.
|
|
2244
|
+
*
|
|
2245
|
+
* Delivery resolves the bound Session through `ctx.sessionController.resolveAgent`,
|
|
2246
|
+
* which rejects the live Agent of a delegated child; a stored task for such a Session
|
|
2247
|
+
* would stay permanently overdue and retry on every drive. Both operations that can
|
|
2248
|
+
* arm a delivery read that same fact here instead of restating it: a delegated child
|
|
2249
|
+
* is one whose {@link delegationDepthOf} is above zero, the accounting the delegation
|
|
2250
|
+
* cap itself enforces, which survives a cold resume through the persisted header.
|
|
2251
|
+
* @param sessionId - Session the task would be bound to.
|
|
2252
|
+
* @returns The stable refusal for a delegated child's Session, or undefined when the Session is eligible.
|
|
2253
|
+
*/
|
|
2254
|
+
reminderTargetRefusal(sessionId) {
|
|
2255
|
+
const agent = this.ctx.agents.get(sessionId);
|
|
2256
|
+
if (agent === void 0 || delegationDepthOf(agent) === 0) return void 0;
|
|
2257
|
+
return {
|
|
2258
|
+
code: "subagent_session",
|
|
2259
|
+
message: "This Session belongs to subagent routing, which never receives reminder delivery."
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
/**
|
|
2871
2263
|
* Remove every active task stored for one Session, inside the queue the tools
|
|
2872
2264
|
* use.
|
|
2873
2265
|
*
|
|
@@ -2907,4 +2299,4 @@ let ScheduleService = (() => {
|
|
|
2907
2299
|
};
|
|
2908
2300
|
})();
|
|
2909
2301
|
//#endregion
|
|
2910
|
-
export { MAX_TITLE_LENGTH, MIN_EVERY_INTERVAL_SECONDS, SCHEDULE_CHANGE_VERSION, ScheduleId, ScheduleInputError, ScheduleLogError, ScheduleService, ScheduleService as default, canonicalizeCronExpression, createAfterScheduleRecord, createAtScheduleRecord, createCronScheduleRecord, createDailyScheduleRecord, createEveryScheduleRecord, createWeeklyScheduleRecord, decodeScheduleChange, decodeScheduleRecord, foldScheduleEvents, isRecurringScheduleRecord, normalizeWeekdays, parseCronInput, parseWeeklyInput,
|
|
2302
|
+
export { MAX_TITLE_LENGTH, MIN_EVERY_INTERVAL_SECONDS, REQUIRED_TITLE_MESSAGE, SCHEDULE_CHANGE_VERSION, ScheduleId, ScheduleInputError, ScheduleLogError, ScheduleService, ScheduleService as default, canonicalizeCronExpression, createAfterScheduleRecord, createAtScheduleRecord, createCronScheduleRecord, createDailyScheduleRecord, createEveryScheduleRecord, createWeeklyScheduleRecord, decodeScheduleChange, decodeScheduleRecord, foldScheduleEvents, isRecurringScheduleRecord, normalizeWeekdays, parseCronInput, parseWeeklyInput, renderRecurringReminderBatchFraming, renderReminderFraming, resolveCronOccurrence, resolveDailyOccurrence, resolveEveryOccurrence, resolveRecurringOccurrence, resolveWeeklyOccurrence, scheduleDomain, scheduleTitle, scheduleView, weeklyTime };
|