dsh-workbuddy-xdpool 1.2.0 → 1.4.0
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/CHANGELOG.md +91 -0
- package/README.en.md +112 -45
- package/README.md +104 -53
- package/assets/automation-panel.png +0 -0
- package/assets/settings-card.png +0 -0
- package/lib/bin.js +190 -9
- package/lib/client.js +23 -7
- package/lib/index.d.ts +81 -0
- package/lib/index.js +639 -30
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -275,6 +275,10 @@ window.__ModuleLoader__.load({
|
|
|
275
275
|
.dsm-workbuddy-xdpool-auto-job-name{flex:0 0 72px;color:var(--dsw-alias-label-primary,#e8e8ea)}
|
|
276
276
|
.dsm-workbuddy-xdpool-auto-job-when{flex:1 1 auto;font-variant-numeric:tabular-nums}
|
|
277
277
|
.dsm-workbuddy-xdpool-auto-job-last{flex:0 0 auto;text-align:right;font-variant-numeric:tabular-nums}
|
|
278
|
+
/* The job detail wraps to its own full-width line: it is a list of reward
|
|
279
|
+
titles, which needs the whole row rather than a cramped right-hand slot. */
|
|
280
|
+
.dsm-workbuddy-xdpool-auto-job-detail{flex:1 1 100%;color:var(--dsw-alias-label-secondary,#b8bcc4);line-height:1.5;word-break:break-word}
|
|
281
|
+
.dsm-workbuddy-xdpool-auto-job-note{flex:0 0 auto;color:var(--dsw-alias-label-secondary,#b8bcc4)}
|
|
278
282
|
.dsm-workbuddy-xdpool-auto-run{flex:0 0 auto;padding:2px 8px;font-size:10px;line-height:16px}
|
|
279
283
|
/* Reserved credits: one inline number field per account. */
|
|
280
284
|
.dsm-workbuddy-xdpool-reserve{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px dashed var(--dsw-alias-border-l2,#36373b);font-size:11px;color:var(--dsw-alias-label-dimmed,#8a97b5)}
|
|
@@ -362,10 +366,11 @@ window.__ModuleLoader__.load({
|
|
|
362
366
|
const AUTOMATION_POLL_MS = 2e3;
|
|
363
367
|
const AUTOMATION_POLL_ATTEMPTS = 90;
|
|
364
368
|
const AUTOMATION_JOBS = [
|
|
369
|
+
"checkin",
|
|
365
370
|
"report",
|
|
366
371
|
"tasks",
|
|
367
|
-
"
|
|
368
|
-
"
|
|
372
|
+
"streak",
|
|
373
|
+
"travel"
|
|
369
374
|
];
|
|
370
375
|
/** Read one job's configured hours off the status document. */
|
|
371
376
|
function automationHours(status, kind) {
|
|
@@ -376,6 +381,7 @@ window.__ModuleLoader__.load({
|
|
|
376
381
|
case "tasks": return automation.taskHours;
|
|
377
382
|
case "checkin": return automation.checkinHours;
|
|
378
383
|
case "streak": return automation.streakHours;
|
|
384
|
+
case "travel": return automation.travelHours;
|
|
379
385
|
}
|
|
380
386
|
}
|
|
381
387
|
/** Read one job's last-run record off the status document. */
|
|
@@ -1132,6 +1138,14 @@ window.__ModuleLoader__.load({
|
|
|
1132
1138
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1133
1139
|
className: "dsm-workbuddy-xdpool-auto-job-last",
|
|
1134
1140
|
children: job?.lastRunDate === void 0 ? t?.("row.autoNever") ?? "not run yet" : `${job.lastRunDate} · ${job.ok}${job.failed > 0 ? `/${job.failed}` : ""}`
|
|
1141
|
+
}),
|
|
1142
|
+
job?.progress === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1143
|
+
className: "dsm-workbuddy-xdpool-auto-job-note",
|
|
1144
|
+
children: job.progress
|
|
1145
|
+
}),
|
|
1146
|
+
job?.detail === void 0 || job.detail.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1147
|
+
className: "dsm-workbuddy-xdpool-auto-job-detail",
|
|
1148
|
+
children: job.detail.join(" · ")
|
|
1135
1149
|
})
|
|
1136
1150
|
]
|
|
1137
1151
|
}, kind);
|
|
@@ -1767,13 +1781,14 @@ window.__ModuleLoader__.load({
|
|
|
1767
1781
|
"row.autoOn": "On",
|
|
1768
1782
|
"row.autoOff": "Off",
|
|
1769
1783
|
"row.autoBusy": "Saving…",
|
|
1770
|
-
"row.autoHintOn": "
|
|
1784
|
+
"row.autoHintOn": "Checks in, reports activity, claims task and streak rewards, and runs the buddy trip — every day.",
|
|
1771
1785
|
"row.autoHintOff": "Off: no background requests are made for you.",
|
|
1772
1786
|
"row.autoJob_report": "Activity report",
|
|
1773
1787
|
"row.autoJob_tasks": "Task rewards",
|
|
1774
1788
|
"row.autoJob_checkin": "Daily check-in",
|
|
1775
1789
|
"row.autoJob_streak": "Streak bonus",
|
|
1776
|
-
"row.
|
|
1790
|
+
"row.autoJob_travel": "Buddy trip",
|
|
1791
|
+
"row.autoHourNone": "skipped today",
|
|
1777
1792
|
"row.autoNever": "not run yet",
|
|
1778
1793
|
"row.autoRun": "Run now",
|
|
1779
1794
|
"row.autoRunning": "Running…",
|
|
@@ -1895,14 +1910,15 @@ window.__ModuleLoader__.load({
|
|
|
1895
1910
|
"row.autoOn": "已开启",
|
|
1896
1911
|
"row.autoOff": "已关闭",
|
|
1897
1912
|
"row.autoBusy": "保存中…",
|
|
1898
|
-
"row.autoHintOn": "
|
|
1913
|
+
"row.autoHintOn": "每天自动签到、上报活跃、领取任务奖励与连登奖励,并照看猫猫旅行。",
|
|
1899
1914
|
"row.autoHintOff": "已关闭:不会替你发起任何后台请求。",
|
|
1900
1915
|
"row.autoJob_report": "活跃上报",
|
|
1901
1916
|
"row.autoJob_tasks": "任务奖励",
|
|
1902
1917
|
"row.autoJob_checkin": "每日签到",
|
|
1903
1918
|
"row.autoJob_streak": "连登奖励",
|
|
1904
|
-
"row.
|
|
1905
|
-
"row.
|
|
1919
|
+
"row.autoJob_travel": "猫猫旅行",
|
|
1920
|
+
"row.autoHourNone": "当天不跑",
|
|
1921
|
+
"row.autoNever": "还没跑过",
|
|
1906
1922
|
"row.autoRun": "立即运行",
|
|
1907
1923
|
"row.autoRunning": "运行中…",
|
|
1908
1924
|
"row.autoRan": "完成:{count} 个账号正常,{failed} 个失败",
|
package/lib/index.d.ts
CHANGED
|
@@ -164,6 +164,32 @@ export declare function expertActualUseEvent(expert: MarketExpert, conversationI
|
|
|
164
164
|
*/
|
|
165
165
|
export declare function expertChatEvents(expert: MarketExpert, conversationId: string, requestId: string): Record<string, unknown>[];
|
|
166
166
|
//#endregion
|
|
167
|
+
//#region src/context-budget.d.ts
|
|
168
|
+
/**
|
|
169
|
+
* Context-window budgeting for the WorkBuddy shim.
|
|
170
|
+
*
|
|
171
|
+
* The upstream answers `context_length_exceeded` (business code 11115) when a
|
|
172
|
+
* request overruns the model's window. Rather than bouncing that back to the
|
|
173
|
+
* user as a dead turn, the shim compacts the conversation on the fly:
|
|
174
|
+
*
|
|
175
|
+
* 1. estimate the prompt cost locally (cheap, no round trip);
|
|
176
|
+
* 2. drop the oldest turns while keeping `system` + the newest exchange;
|
|
177
|
+
* 3. if that still overruns, ask the model itself to summarise the middle of
|
|
178
|
+
* the conversation and splice that summary back in as a system message.
|
|
179
|
+
*
|
|
180
|
+
* Everything here is pure and synchronous-free except `summarizeMessages`,
|
|
181
|
+
* which the caller drives through an injected chat function so this module
|
|
182
|
+
* stays testable without a network.
|
|
183
|
+
*
|
|
184
|
+
* @module dsh-workbuddy-xdpool/context-budget
|
|
185
|
+
*/
|
|
186
|
+
/** One OpenAI chat message, narrowed to the fields we must preserve. */
|
|
187
|
+
interface ChatMessage {
|
|
188
|
+
role: string;
|
|
189
|
+
content: unknown;
|
|
190
|
+
[key: string]: unknown;
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
167
193
|
//#region src/upstream.d.ts
|
|
168
194
|
/** Upstream failure classes the shim maps onto distinct HTTP answers. */
|
|
169
195
|
type UpstreamErrorKind = 'hard_credit' | 'soft_rate' | 'session_dead' | 'not_found' | 'server' | 'client';
|
|
@@ -388,6 +414,24 @@ export declare class WorkBuddyUpstreamClient {
|
|
|
388
414
|
* business code 11128), and flatten `tool_choice` into its string form.
|
|
389
415
|
*/
|
|
390
416
|
prepareChatBody(raw: string): string;
|
|
417
|
+
/**
|
|
418
|
+
* Parse a raw OpenAI chat body without normalising it.
|
|
419
|
+
*
|
|
420
|
+
* The compactor needs the message array as objects, while `chatStream` only
|
|
421
|
+
* accepts the serialised string form.
|
|
422
|
+
*/
|
|
423
|
+
parseChatBody(raw: string): Record<string, unknown> | undefined;
|
|
424
|
+
/** Re-serialise `base` with a rewritten `messages` array, still normalised. */
|
|
425
|
+
buildChatBody(base: Record<string, unknown>, messages: readonly ChatMessage[]): string;
|
|
426
|
+
/**
|
|
427
|
+
* Run one NON-streaming completion and return the assistant text.
|
|
428
|
+
*
|
|
429
|
+
* Used only for internal compaction (summarising dropped turns). The chat
|
|
430
|
+
* endpoint itself always streams, so this reassembles the SSE frames into a
|
|
431
|
+
* single string. Throws on any failure: the compactor then falls back to
|
|
432
|
+
* plain truncation rather than failing the user's turn.
|
|
433
|
+
*/
|
|
434
|
+
completeChat(credential: WorkBuddyCredential, prepared: string, signal?: AbortSignal): Promise<string>;
|
|
391
435
|
/** Forward one chat completion. Never throws for upstream failures. */
|
|
392
436
|
chatStream(credential: WorkBuddyCredential, prepared: string, signal?: AbortSignal): Promise<ChatStreamResult>;
|
|
393
437
|
/** POST the token-refresh endpoint; the caller merges the outcome. */
|
|
@@ -1151,6 +1195,16 @@ interface SchedulerLogger {
|
|
|
1151
1195
|
interface AutomationJobState {
|
|
1152
1196
|
/** `YYYY-MM-DD` of the last completed run, or undefined if it never ran. */
|
|
1153
1197
|
lastRunDate?: string;
|
|
1198
|
+
/**
|
|
1199
|
+
* The scheduled SLOT of the last run, as `YYYY-MM-DDTHH`.
|
|
1200
|
+
*
|
|
1201
|
+
* The tick de-duplicates on this rather than on the date: keying on the date
|
|
1202
|
+
* alone caps every job at one run a day, which is wrong for a job with two
|
|
1203
|
+
* time points — blocking the cat loop's second pass would leave the cat out
|
|
1204
|
+
* until tomorrow. Per slot a job runs once in each configured hour, while a
|
|
1205
|
+
* repeat tick inside the same hour is still refused.
|
|
1206
|
+
*/
|
|
1207
|
+
lastRunSlot?: string;
|
|
1154
1208
|
/** Epoch ms of the last completed run. */
|
|
1155
1209
|
lastRunAtMs?: number;
|
|
1156
1210
|
/** Accounts that completed without throwing. */
|
|
@@ -1164,6 +1218,23 @@ interface AutomationJobState {
|
|
|
1164
1218
|
/** Tasks claimed by the task job on the last run. */
|
|
1165
1219
|
claimed: number;
|
|
1166
1220
|
/** Human-readable summary of the last run. */
|
|
1221
|
+
/**
|
|
1222
|
+
* What this run actually did, in the words of the task board.
|
|
1223
|
+
*
|
|
1224
|
+
* `message` is a count ("3 accounts, 5 tasks claimed"); this is the list a
|
|
1225
|
+
* person can check off — the reward titles the pass collected. A row showing
|
|
1226
|
+
* only a bare number cannot answer "did it do the thing I care about", which
|
|
1227
|
+
* is the question the panel exists to answer.
|
|
1228
|
+
*/
|
|
1229
|
+
detail?: readonly string[];
|
|
1230
|
+
/**
|
|
1231
|
+
* A pending milestone worth naming, when there is one.
|
|
1232
|
+
*
|
|
1233
|
+
* Streak tiers are why this exists: every tier reads `locked` until enough
|
|
1234
|
+
* consecutive days accumulate, and "locked" on its own reads as "broken"
|
|
1235
|
+
* rather than "come back in four days".
|
|
1236
|
+
*/
|
|
1237
|
+
progress?: string;
|
|
1167
1238
|
message?: string;
|
|
1168
1239
|
}
|
|
1169
1240
|
/**
|
|
@@ -1794,6 +1865,15 @@ interface PoolWebAutomationJob {
|
|
|
1794
1865
|
claimed: number;
|
|
1795
1866
|
/** One-line summary of the last run. */
|
|
1796
1867
|
message?: string;
|
|
1868
|
+
/**
|
|
1869
|
+
* What the last run actually did, in the words of the task board.
|
|
1870
|
+
*
|
|
1871
|
+
* `message` is a count; this is the list a person can check off, which is
|
|
1872
|
+
* what turns a row from "it ran" into "it did the things I care about".
|
|
1873
|
+
*/
|
|
1874
|
+
detail?: readonly string[];
|
|
1875
|
+
/** A pending milestone worth naming, e.g. the next streak tier countdown. */
|
|
1876
|
+
progress?: string;
|
|
1797
1877
|
}
|
|
1798
1878
|
/**
|
|
1799
1879
|
* Automation block on the status document.
|
|
@@ -1812,6 +1892,7 @@ interface PoolWebAutomation {
|
|
|
1812
1892
|
reportHours: readonly number[];
|
|
1813
1893
|
taskHours: readonly number[];
|
|
1814
1894
|
streakHours: readonly number[];
|
|
1895
|
+
travelHours: readonly number[];
|
|
1815
1896
|
jobs: {
|
|
1816
1897
|
checkin: PoolWebAutomationJob;
|
|
1817
1898
|
report: PoolWebAutomationJob;
|