crewly 1.20.182 → 1.20.183
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/config/roles/orchestrator/prompt.md +4 -0
- package/config/skills/agent/core/report-status/execute.sh +4 -2
- package/dist/backend/backend/src/constants.d.ts +35 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +35 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js +22 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +25 -24
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +15 -0
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts +2 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.js +6 -3
- package/dist/backend/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +6 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.d.ts +3 -1
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.js +7 -4
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.js.map +1 -1
- package/dist/backend/backend/src/services/orc/orc-status-router.service.d.ts +110 -0
- package/dist/backend/backend/src/services/orc/orc-status-router.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-status-router.service.js +229 -0
- package/dist/backend/backend/src/services/orc/orc-status-router.service.js.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.d.ts +108 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.js +145 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.js.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.d.ts +86 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.js +130 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.js.map +1 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts +33 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.js +49 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.js.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts +2 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js +10 -4
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +16 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +31 -8
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.js +2 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +61 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +35 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +35 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts +2 -1
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/message-queue.service.js +6 -3
- package/dist/cli/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.js +6 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts +3 -1
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js +7 -4
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js.map +1 -1
- package/dist/cli/backend/src/services/orc/orc-status-routing.d.ts +108 -0
- package/dist/cli/backend/src/services/orc/orc-status-routing.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-status-routing.js +145 -0
- package/dist/cli/backend/src/services/orc/orc-status-routing.js.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.d.ts +86 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.js +130 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.js.map +1 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts +198 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.js +288 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.js.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +16 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +31 -8
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +61 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hourly count of orchestrator turns, by why it was woken
|
|
3
|
+
* (specs/2026-10-01-orc-status-wakes.md).
|
|
4
|
+
*
|
|
5
|
+
* Every orchestrator turn re-reads its whole context (~70k tokens on
|
|
6
|
+
* 2026-09-29), so the number of turns IS the cost. Once an hour the counter
|
|
7
|
+
* logs one line:
|
|
8
|
+
*
|
|
9
|
+
* orc wakes: 14 (owner 3, delegated-done 2, escalations 1, digest 2, other 6)
|
|
10
|
+
*
|
|
11
|
+
* - `N` and `owner` are counted when the queue processor starts an
|
|
12
|
+
* orchestrator turn (`owner` = any non-system source: Slack, web chat, …).
|
|
13
|
+
* - `delegated-done`, `escalations`, `digest` are counted when the status
|
|
14
|
+
* router decides to wake the orchestrator (several queued system events
|
|
15
|
+
* can coalesce into one turn, so these may add up to more than the turns
|
|
16
|
+
* they caused).
|
|
17
|
+
* - `other` = turns that are neither owner messages nor status-router wakes
|
|
18
|
+
* (cron, wiki, triggers, enforcer reminders, …).
|
|
19
|
+
*
|
|
20
|
+
* @module services/orc/orc-wake-counter
|
|
21
|
+
*/
|
|
22
|
+
import { MESSAGE_SOURCES, ORC_WAKE_CONSTANTS } from '../../constants.js';
|
|
23
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
24
|
+
/** A fresh, zeroed count. */
|
|
25
|
+
function zero() {
|
|
26
|
+
return { turns: 0, owner: 0, delegatedDone: 0, escalations: 0, digest: 0, statusOther: 0 };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The log line for one period.
|
|
30
|
+
*
|
|
31
|
+
* @param c - Counts
|
|
32
|
+
* @returns `orc wakes: N (owner X, delegated-done Y, escalations Z, digest W, other V)`
|
|
33
|
+
*/
|
|
34
|
+
export function formatOrcWakeLine(c) {
|
|
35
|
+
const routed = c.delegatedDone + c.escalations + c.digest;
|
|
36
|
+
const other = Math.max(0, c.turns - c.owner - routed);
|
|
37
|
+
return `orc wakes: ${c.turns} (owner ${c.owner}, delegated-done ${c.delegatedDone}, escalations ${c.escalations}, digest ${c.digest}, other ${other})`;
|
|
38
|
+
}
|
|
39
|
+
/** Counts orchestrator wakes and logs them once per period. */
|
|
40
|
+
export class OrcWakeCounter {
|
|
41
|
+
now;
|
|
42
|
+
static instance = null;
|
|
43
|
+
counts = zero();
|
|
44
|
+
periodStart;
|
|
45
|
+
timer = null;
|
|
46
|
+
logger;
|
|
47
|
+
/**
|
|
48
|
+
* @param now - Clock (tests)
|
|
49
|
+
*/
|
|
50
|
+
constructor(now = Date.now) {
|
|
51
|
+
this.now = now;
|
|
52
|
+
this.periodStart = now();
|
|
53
|
+
this.logger = LoggerService.getInstance().createComponentLogger('OrcWakes');
|
|
54
|
+
}
|
|
55
|
+
/** The process-wide counter. */
|
|
56
|
+
static getInstance() {
|
|
57
|
+
if (!OrcWakeCounter.instance)
|
|
58
|
+
OrcWakeCounter.instance = new OrcWakeCounter();
|
|
59
|
+
return OrcWakeCounter.instance;
|
|
60
|
+
}
|
|
61
|
+
/** Drop the singleton (tests). */
|
|
62
|
+
static resetInstance() {
|
|
63
|
+
OrcWakeCounter.instance?.stop();
|
|
64
|
+
OrcWakeCounter.instance = null;
|
|
65
|
+
}
|
|
66
|
+
/** Log every {@link ORC_WAKE_CONSTANTS.COUNTER_LOG_INTERVAL_MS}. Idempotent. */
|
|
67
|
+
start() {
|
|
68
|
+
if (this.timer)
|
|
69
|
+
return;
|
|
70
|
+
this.timer = setInterval(() => this.flush(), ORC_WAKE_CONSTANTS.COUNTER_LOG_INTERVAL_MS);
|
|
71
|
+
this.timer.unref?.();
|
|
72
|
+
}
|
|
73
|
+
/** Stop the periodic log. */
|
|
74
|
+
stop() {
|
|
75
|
+
if (this.timer)
|
|
76
|
+
clearInterval(this.timer);
|
|
77
|
+
this.timer = null;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* An orchestrator turn started (queue processor).
|
|
81
|
+
*
|
|
82
|
+
* @param source - Message source of the turn
|
|
83
|
+
*/
|
|
84
|
+
noteTurn(source) {
|
|
85
|
+
this.counts.turns += 1;
|
|
86
|
+
if (source !== MESSAGE_SOURCES.SYSTEM_EVENT)
|
|
87
|
+
this.counts.owner += 1;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The status router decided to wake the orchestrator.
|
|
91
|
+
*
|
|
92
|
+
* @param category - Why
|
|
93
|
+
*/
|
|
94
|
+
noteRouted(category) {
|
|
95
|
+
switch (category) {
|
|
96
|
+
case 'owner':
|
|
97
|
+
case 'delegated-done':
|
|
98
|
+
this.counts.delegatedDone += 1;
|
|
99
|
+
break;
|
|
100
|
+
case 'escalation':
|
|
101
|
+
this.counts.escalations += 1;
|
|
102
|
+
break;
|
|
103
|
+
case 'digest':
|
|
104
|
+
this.counts.digest += 1;
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
this.counts.statusOther += 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** The current period's numbers (copy). */
|
|
111
|
+
snapshot() {
|
|
112
|
+
return { ...this.counts };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Log the period's line and start a new period.
|
|
116
|
+
*
|
|
117
|
+
* @returns The logged line
|
|
118
|
+
*/
|
|
119
|
+
flush() {
|
|
120
|
+
const line = formatOrcWakeLine(this.counts);
|
|
121
|
+
this.logger.info(line, {
|
|
122
|
+
since: new Date(this.periodStart).toISOString(),
|
|
123
|
+
...this.counts,
|
|
124
|
+
});
|
|
125
|
+
this.counts = zero();
|
|
126
|
+
this.periodStart = this.now();
|
|
127
|
+
return line;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=orc-wake-counter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orc-wake-counter.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/orc-wake-counter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an agent's answer goes, decided by the WORK it is answering
|
|
3
|
+
* (specs/2026-10-01-decision-cards.md §6).
|
|
4
|
+
*
|
|
5
|
+
* Incident: Atlas posted the output of a scheduled task ("steveswiki 第一次季度
|
|
6
|
+
* 回看…") into an unrelated #pro-think-tank thread. The 1.20.170 `reply` sent
|
|
7
|
+
* every answer to "the thread the agent was last asked in", and a cron run
|
|
8
|
+
* has no asker — so the last owner thread, however old, won.
|
|
9
|
+
*
|
|
10
|
+
* Now each work item carries its own origin and the answer follows it:
|
|
11
|
+
*
|
|
12
|
+
* | Work | Destination |
|
|
13
|
+
* |---|---|
|
|
14
|
+
* | owner asked (newest, < 2 h) | that conversation / thread (turn origin) |
|
|
15
|
+
* | ticket work | the ticket's Slack thread (created on first post) |
|
|
16
|
+
* | trigger / cron / auto work | the trigger's `destination`, else a NEW top-level post in the team channel |
|
|
17
|
+
* | no current work | a NEW top-level post in the team channel |
|
|
18
|
+
*
|
|
19
|
+
* Pure functions only; the effects live in `work-item-destination.wiring.ts`.
|
|
20
|
+
*
|
|
21
|
+
* @module services/orc/work-item-destination
|
|
22
|
+
*/
|
|
23
|
+
import type { WorkItem } from '../../types/v2/work-item.types.js';
|
|
24
|
+
import type { TurnOrigin } from './orc-reply-route.service.js';
|
|
25
|
+
/** The origin a work item carries in `metadata.origin`. */
|
|
26
|
+
export type WorkItemOrigin =
|
|
27
|
+
/** Asked by the owner in a conversation / Slack thread */
|
|
28
|
+
{
|
|
29
|
+
kind: 'owner';
|
|
30
|
+
conversationId?: string;
|
|
31
|
+
slackChannelId?: string;
|
|
32
|
+
threadTs?: string;
|
|
33
|
+
chatThreadId?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Work on a project ticket */
|
|
36
|
+
| {
|
|
37
|
+
kind: 'ticket';
|
|
38
|
+
projectPath: string;
|
|
39
|
+
ticketId: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
teamId?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Fired by a trigger or a cron task */
|
|
44
|
+
| {
|
|
45
|
+
kind: 'trigger';
|
|
46
|
+
triggerId?: string;
|
|
47
|
+
cronTaskId?: string;
|
|
48
|
+
destination?: string;
|
|
49
|
+
teamId?: string;
|
|
50
|
+
topic: string;
|
|
51
|
+
};
|
|
52
|
+
/** Where the answer goes. */
|
|
53
|
+
export type WorkDestination =
|
|
54
|
+
/** The owner's turn origin — the existing `reply` path */
|
|
55
|
+
{
|
|
56
|
+
kind: 'owner-origin';
|
|
57
|
+
origin: TurnOrigin;
|
|
58
|
+
reason: string;
|
|
59
|
+
}
|
|
60
|
+
/** The ticket's Slack thread (created with a `*ID · title*` root when missing) */
|
|
61
|
+
| {
|
|
62
|
+
kind: 'ticket-thread';
|
|
63
|
+
projectPath: string;
|
|
64
|
+
ticketId: string;
|
|
65
|
+
title?: string;
|
|
66
|
+
teamId?: string;
|
|
67
|
+
reason: string;
|
|
68
|
+
}
|
|
69
|
+
/** An explicit Slack place (a trigger's destination): channel name/id, optional thread */
|
|
70
|
+
| {
|
|
71
|
+
kind: 'slack';
|
|
72
|
+
target: string;
|
|
73
|
+
threadTs?: string;
|
|
74
|
+
topic?: string;
|
|
75
|
+
reason: string;
|
|
76
|
+
}
|
|
77
|
+
/** A new top-level post in the agent's (or the work's) team channel */
|
|
78
|
+
| {
|
|
79
|
+
kind: 'new-top-level';
|
|
80
|
+
teamId?: string;
|
|
81
|
+
topic?: string;
|
|
82
|
+
reason: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Build the origin stamped on a trigger- or cron-created work item.
|
|
86
|
+
*
|
|
87
|
+
* @param input - Trigger/cron ids, its destination, team and a topic
|
|
88
|
+
* @returns The origin (topic shortened to one line)
|
|
89
|
+
*/
|
|
90
|
+
export declare function buildTriggerOrigin(input: {
|
|
91
|
+
triggerId?: string;
|
|
92
|
+
cronTaskId?: string;
|
|
93
|
+
destination?: string;
|
|
94
|
+
teamId?: string;
|
|
95
|
+
topic: string;
|
|
96
|
+
}): WorkItemOrigin;
|
|
97
|
+
/**
|
|
98
|
+
* One-line topic, capped at {@link WORK_ITEM_DESTINATION_CONSTANTS.TOPIC_MAX_CHARS}.
|
|
99
|
+
*
|
|
100
|
+
* @param text - Any text
|
|
101
|
+
* @returns Single line, possibly shortened with an ellipsis
|
|
102
|
+
*/
|
|
103
|
+
export declare function shortTopic(text: string | undefined): string;
|
|
104
|
+
/**
|
|
105
|
+
* The agent's current work item: the newest (by start) item targeted at it
|
|
106
|
+
* that is running or accepted.
|
|
107
|
+
*
|
|
108
|
+
* @param items - Pool items
|
|
109
|
+
* @param session - Agent session
|
|
110
|
+
* @returns The item, or null
|
|
111
|
+
*/
|
|
112
|
+
export declare function currentWorkItemOf(items: readonly WorkItem[], session: string): WorkItem | null;
|
|
113
|
+
/**
|
|
114
|
+
* The origin of a work item: its stamped `metadata.origin`, else what its
|
|
115
|
+
* other fields say (a linked project ticket, a trigger, a cron task).
|
|
116
|
+
*
|
|
117
|
+
* @param wi - Work item
|
|
118
|
+
* @returns The origin, or null when nothing tells where it came from
|
|
119
|
+
*/
|
|
120
|
+
export declare function originOfWorkItem(wi: WorkItem): WorkItemOrigin | null;
|
|
121
|
+
/**
|
|
122
|
+
* The origin an owner turn gives the work started from it.
|
|
123
|
+
*
|
|
124
|
+
* @param turn - The owner's turn origin (OrcReplyRouteService)
|
|
125
|
+
* @returns An owner origin
|
|
126
|
+
*/
|
|
127
|
+
export declare function ownerOriginFromTurn(turn: TurnOrigin): WorkItemOrigin;
|
|
128
|
+
/** Inputs of {@link inheritedOrigin}. */
|
|
129
|
+
export interface InheritOriginInput {
|
|
130
|
+
/** The item being created */
|
|
131
|
+
workItem: WorkItem;
|
|
132
|
+
/** The item it continues (verify / retry / subtask parent), when it has one */
|
|
133
|
+
parent: WorkItem | null;
|
|
134
|
+
/** Where the creating agent's current work came from (its plan), when an agent creates it */
|
|
135
|
+
creatorDestination: WorkDestination | null;
|
|
136
|
+
/** The creating agent's current work item */
|
|
137
|
+
creatorWorkItem: WorkItem | null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The origin a new work item inherits (owner request → delegate → verify /
|
|
141
|
+
* retry / subtask). Incident 2026-10-01: Atlas delegated the owner's
|
|
142
|
+
* #morning-brief question to Sage; Sage's [DONE] made a verify item for
|
|
143
|
+
* Atlas with no origin, and the answer's file landed in an unrelated thread.
|
|
144
|
+
*
|
|
145
|
+
* Order: an origin already stamped wins (null = keep it); then the parent's;
|
|
146
|
+
* then the creator's current owner request; then the creator's current
|
|
147
|
+
* work item's.
|
|
148
|
+
*
|
|
149
|
+
* @param input - New item, its parent, the creator's current work
|
|
150
|
+
* @returns The origin to stamp, or null (nothing to inherit / already stamped)
|
|
151
|
+
*/
|
|
152
|
+
export declare function inheritedOrigin(input: InheritOriginInput): WorkItemOrigin | null;
|
|
153
|
+
/**
|
|
154
|
+
* Shape check for a stamped origin.
|
|
155
|
+
*
|
|
156
|
+
* @param value - Anything
|
|
157
|
+
* @returns True for a {@link WorkItemOrigin}
|
|
158
|
+
*/
|
|
159
|
+
export declare function isWorkItemOrigin(value: unknown): value is WorkItemOrigin;
|
|
160
|
+
/**
|
|
161
|
+
* Split a trigger destination into a post target and an optional thread.
|
|
162
|
+
*
|
|
163
|
+
* @param destination - `#name`, `C…` or `C…:<ts>`
|
|
164
|
+
* @returns Target + thread, or null when unreadable
|
|
165
|
+
*/
|
|
166
|
+
export declare function parseDestination(destination: string): {
|
|
167
|
+
target: string;
|
|
168
|
+
threadTs?: string;
|
|
169
|
+
} | null;
|
|
170
|
+
/** Inputs of {@link planWorkDestination}. */
|
|
171
|
+
export interface WorkDestinationInput {
|
|
172
|
+
/** The agent's current work item (see {@link currentWorkItemOf}) */
|
|
173
|
+
workItem: WorkItem | null;
|
|
174
|
+
/** The agent's last owner turn origin (OrcReplyRouteService) */
|
|
175
|
+
ownerOrigin?: TurnOrigin;
|
|
176
|
+
/** Clock (epoch ms) */
|
|
177
|
+
now: number;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Decide where the answer to the agent's current work goes.
|
|
181
|
+
*
|
|
182
|
+
* The current work is the newer of the running work item and the last owner
|
|
183
|
+
* message — the owner message only counts while it is fresh
|
|
184
|
+
* ({@link WORK_ITEM_DESTINATION_CONSTANTS.OWNER_ORIGIN_FRESH_MS}).
|
|
185
|
+
*
|
|
186
|
+
* @param input - Current work item, owner origin, clock
|
|
187
|
+
* @returns The destination
|
|
188
|
+
*/
|
|
189
|
+
export declare function planWorkDestination(input: WorkDestinationInput): WorkDestination;
|
|
190
|
+
/**
|
|
191
|
+
* The text of a new top-level post: the topic line in bold, then the body.
|
|
192
|
+
*
|
|
193
|
+
* @param topic - Topic (may be empty)
|
|
194
|
+
* @param text - Body
|
|
195
|
+
* @returns Post text
|
|
196
|
+
*/
|
|
197
|
+
export declare function withTopicLine(topic: string | undefined, text: string): string;
|
|
198
|
+
//# sourceMappingURL=work-item-destination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-item-destination.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/work-item-destination.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an agent's answer goes, decided by the WORK it is answering
|
|
3
|
+
* (specs/2026-10-01-decision-cards.md §6).
|
|
4
|
+
*
|
|
5
|
+
* Incident: Atlas posted the output of a scheduled task ("steveswiki 第一次季度
|
|
6
|
+
* 回看…") into an unrelated #pro-think-tank thread. The 1.20.170 `reply` sent
|
|
7
|
+
* every answer to "the thread the agent was last asked in", and a cron run
|
|
8
|
+
* has no asker — so the last owner thread, however old, won.
|
|
9
|
+
*
|
|
10
|
+
* Now each work item carries its own origin and the answer follows it:
|
|
11
|
+
*
|
|
12
|
+
* | Work | Destination |
|
|
13
|
+
* |---|---|
|
|
14
|
+
* | owner asked (newest, < 2 h) | that conversation / thread (turn origin) |
|
|
15
|
+
* | ticket work | the ticket's Slack thread (created on first post) |
|
|
16
|
+
* | trigger / cron / auto work | the trigger's `destination`, else a NEW top-level post in the team channel |
|
|
17
|
+
* | no current work | a NEW top-level post in the team channel |
|
|
18
|
+
*
|
|
19
|
+
* Pure functions only; the effects live in `work-item-destination.wiring.ts`.
|
|
20
|
+
*
|
|
21
|
+
* @module services/orc/work-item-destination
|
|
22
|
+
*/
|
|
23
|
+
import { WORK_ITEM_DESTINATION_CONSTANTS } from '../../constants.js';
|
|
24
|
+
import { parseSlackThreadKey } from '../slack/slack-thread-key.js';
|
|
25
|
+
/** Statuses in which a work item is the agent's current work. */
|
|
26
|
+
const CURRENT_STATUSES = new Set(['running', 'accepted']);
|
|
27
|
+
/**
|
|
28
|
+
* Build the origin stamped on a trigger- or cron-created work item.
|
|
29
|
+
*
|
|
30
|
+
* @param input - Trigger/cron ids, its destination, team and a topic
|
|
31
|
+
* @returns The origin (topic shortened to one line)
|
|
32
|
+
*/
|
|
33
|
+
export function buildTriggerOrigin(input) {
|
|
34
|
+
return {
|
|
35
|
+
kind: 'trigger',
|
|
36
|
+
...(input.triggerId ? { triggerId: input.triggerId } : {}),
|
|
37
|
+
...(input.cronTaskId ? { cronTaskId: input.cronTaskId } : {}),
|
|
38
|
+
...(input.destination?.trim() ? { destination: input.destination.trim() } : {}),
|
|
39
|
+
...(input.teamId ? { teamId: input.teamId } : {}),
|
|
40
|
+
topic: shortTopic(input.topic),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One-line topic, capped at {@link WORK_ITEM_DESTINATION_CONSTANTS.TOPIC_MAX_CHARS}.
|
|
45
|
+
*
|
|
46
|
+
* @param text - Any text
|
|
47
|
+
* @returns Single line, possibly shortened with an ellipsis
|
|
48
|
+
*/
|
|
49
|
+
export function shortTopic(text) {
|
|
50
|
+
const flat = String(text ?? '').replace(/\s+/g, ' ').trim();
|
|
51
|
+
const max = WORK_ITEM_DESTINATION_CONSTANTS.TOPIC_MAX_CHARS;
|
|
52
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The agent's current work item: the newest (by start) item targeted at it
|
|
56
|
+
* that is running or accepted.
|
|
57
|
+
*
|
|
58
|
+
* @param items - Pool items
|
|
59
|
+
* @param session - Agent session
|
|
60
|
+
* @returns The item, or null
|
|
61
|
+
*/
|
|
62
|
+
export function currentWorkItemOf(items, session) {
|
|
63
|
+
let best = null;
|
|
64
|
+
let bestAt = -Infinity;
|
|
65
|
+
for (const wi of items) {
|
|
66
|
+
if (wi.target !== session || !CURRENT_STATUSES.has(wi.status))
|
|
67
|
+
continue;
|
|
68
|
+
const at = startOf(wi);
|
|
69
|
+
if (at > bestAt) {
|
|
70
|
+
best = wi;
|
|
71
|
+
bestAt = at;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return best;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* When a work item started (else when it was created).
|
|
78
|
+
*
|
|
79
|
+
* @param wi - Work item
|
|
80
|
+
* @returns Epoch ms (0 when unreadable)
|
|
81
|
+
*/
|
|
82
|
+
function startOf(wi) {
|
|
83
|
+
return Date.parse(wi.startedAt ?? '') || Date.parse(wi.createdAt) || 0;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The origin of a work item: its stamped `metadata.origin`, else what its
|
|
87
|
+
* other fields say (a linked project ticket, a trigger, a cron task).
|
|
88
|
+
*
|
|
89
|
+
* @param wi - Work item
|
|
90
|
+
* @returns The origin, or null when nothing tells where it came from
|
|
91
|
+
*/
|
|
92
|
+
export function originOfWorkItem(wi) {
|
|
93
|
+
const meta = (wi.metadata ?? {});
|
|
94
|
+
const stamped = meta[WORK_ITEM_DESTINATION_CONSTANTS.METADATA_KEY];
|
|
95
|
+
if (isWorkItemOrigin(stamped))
|
|
96
|
+
return stamped;
|
|
97
|
+
const link = meta.projectTicket;
|
|
98
|
+
if (link && typeof link.projectPath === 'string' && typeof link.id === 'string') {
|
|
99
|
+
return {
|
|
100
|
+
kind: 'ticket',
|
|
101
|
+
projectPath: link.projectPath,
|
|
102
|
+
ticketId: link.id,
|
|
103
|
+
...(typeof meta.teamId === 'string' ? { teamId: meta.teamId } : {}),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (wi.triggerId)
|
|
107
|
+
return buildTriggerOrigin({ triggerId: wi.triggerId, topic: wi.title });
|
|
108
|
+
if (meta.source === 'cron') {
|
|
109
|
+
return buildTriggerOrigin({
|
|
110
|
+
...(typeof meta.cronTaskId === 'string' ? { cronTaskId: meta.cronTaskId } : {}),
|
|
111
|
+
...(typeof meta.targetTeamId === 'string' ? { teamId: meta.targetTeamId } : {}),
|
|
112
|
+
topic: wi.description ?? wi.title,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The origin an owner turn gives the work started from it.
|
|
119
|
+
*
|
|
120
|
+
* @param turn - The owner's turn origin (OrcReplyRouteService)
|
|
121
|
+
* @returns An owner origin
|
|
122
|
+
*/
|
|
123
|
+
export function ownerOriginFromTurn(turn) {
|
|
124
|
+
const key = parseSlackThreadKey(turn.slackThreadKey);
|
|
125
|
+
const slackChannelId = key?.slackChannelId ?? turn.slackChannelId;
|
|
126
|
+
const threadTs = key?.threadTs ?? turn.slackThreadTs;
|
|
127
|
+
return {
|
|
128
|
+
kind: 'owner',
|
|
129
|
+
conversationId: turn.conversationId,
|
|
130
|
+
...(slackChannelId ? { slackChannelId } : {}),
|
|
131
|
+
...(threadTs ? { threadTs } : {}),
|
|
132
|
+
...(turn.chatThreadId ? { chatThreadId: turn.chatThreadId } : {}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The origin a new work item inherits (owner request → delegate → verify /
|
|
137
|
+
* retry / subtask). Incident 2026-10-01: Atlas delegated the owner's
|
|
138
|
+
* #morning-brief question to Sage; Sage's [DONE] made a verify item for
|
|
139
|
+
* Atlas with no origin, and the answer's file landed in an unrelated thread.
|
|
140
|
+
*
|
|
141
|
+
* Order: an origin already stamped wins (null = keep it); then the parent's;
|
|
142
|
+
* then the creator's current owner request; then the creator's current
|
|
143
|
+
* work item's.
|
|
144
|
+
*
|
|
145
|
+
* @param input - New item, its parent, the creator's current work
|
|
146
|
+
* @returns The origin to stamp, or null (nothing to inherit / already stamped)
|
|
147
|
+
*/
|
|
148
|
+
export function inheritedOrigin(input) {
|
|
149
|
+
const meta = (input.workItem.metadata ?? {});
|
|
150
|
+
if (isWorkItemOrigin(meta[WORK_ITEM_DESTINATION_CONSTANTS.METADATA_KEY]))
|
|
151
|
+
return null;
|
|
152
|
+
if (input.parent) {
|
|
153
|
+
const fromParent = originOfWorkItem(input.parent);
|
|
154
|
+
if (fromParent)
|
|
155
|
+
return fromParent;
|
|
156
|
+
}
|
|
157
|
+
const dest = input.creatorDestination;
|
|
158
|
+
if (dest?.kind === 'owner-origin')
|
|
159
|
+
return ownerOriginFromTurn(dest.origin);
|
|
160
|
+
if (input.creatorWorkItem)
|
|
161
|
+
return originOfWorkItem(input.creatorWorkItem);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Shape check for a stamped origin.
|
|
166
|
+
*
|
|
167
|
+
* @param value - Anything
|
|
168
|
+
* @returns True for a {@link WorkItemOrigin}
|
|
169
|
+
*/
|
|
170
|
+
export function isWorkItemOrigin(value) {
|
|
171
|
+
if (!value || typeof value !== 'object')
|
|
172
|
+
return false;
|
|
173
|
+
const v = value;
|
|
174
|
+
if (v.kind === 'owner')
|
|
175
|
+
return true;
|
|
176
|
+
if (v.kind === 'ticket')
|
|
177
|
+
return typeof v.projectPath === 'string' && typeof v.ticketId === 'string';
|
|
178
|
+
if (v.kind === 'trigger')
|
|
179
|
+
return typeof v.topic === 'string';
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Split a trigger destination into a post target and an optional thread.
|
|
184
|
+
*
|
|
185
|
+
* @param destination - `#name`, `C…` or `C…:<ts>`
|
|
186
|
+
* @returns Target + thread, or null when unreadable
|
|
187
|
+
*/
|
|
188
|
+
export function parseDestination(destination) {
|
|
189
|
+
const d = destination.trim();
|
|
190
|
+
const thread = /^([CG][A-Z0-9]{6,}):(\d{6,}\.\d+)$/.exec(d);
|
|
191
|
+
if (thread)
|
|
192
|
+
return { target: thread[1], threadTs: thread[2] };
|
|
193
|
+
if (/^[CG][A-Z0-9]{6,}$/.test(d))
|
|
194
|
+
return { target: d };
|
|
195
|
+
if (/^#[a-z0-9][a-z0-9._-]*$/.test(d))
|
|
196
|
+
return { target: d };
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Decide where the answer to the agent's current work goes.
|
|
201
|
+
*
|
|
202
|
+
* The current work is the newer of the running work item and the last owner
|
|
203
|
+
* message — the owner message only counts while it is fresh
|
|
204
|
+
* ({@link WORK_ITEM_DESTINATION_CONSTANTS.OWNER_ORIGIN_FRESH_MS}).
|
|
205
|
+
*
|
|
206
|
+
* @param input - Current work item, owner origin, clock
|
|
207
|
+
* @returns The destination
|
|
208
|
+
*/
|
|
209
|
+
export function planWorkDestination(input) {
|
|
210
|
+
const { workItem, ownerOrigin, now } = input;
|
|
211
|
+
const ownerFresh = !!ownerOrigin && now - ownerOrigin.receivedAt < WORK_ITEM_DESTINATION_CONSTANTS.OWNER_ORIGIN_FRESH_MS;
|
|
212
|
+
if (ownerOrigin && ownerFresh && (!workItem || ownerOrigin.receivedAt >= startOf(workItem))) {
|
|
213
|
+
return { kind: 'owner-origin', origin: ownerOrigin, reason: workItem ? 'the owner asked after the work item started' : 'the owner asked (no work item running)' };
|
|
214
|
+
}
|
|
215
|
+
if (!workItem) {
|
|
216
|
+
return { kind: 'new-top-level', reason: ownerOrigin ? 'no current work; the last owner message is stale' : 'no current work' };
|
|
217
|
+
}
|
|
218
|
+
const origin = originOfWorkItem(workItem);
|
|
219
|
+
if (!origin) {
|
|
220
|
+
return { kind: 'new-top-level', topic: shortTopic(workItem.title), reason: `work item ${workItem.id} has no recorded origin` };
|
|
221
|
+
}
|
|
222
|
+
switch (origin.kind) {
|
|
223
|
+
case 'owner': {
|
|
224
|
+
if (origin.conversationId) {
|
|
225
|
+
const threadKey = origin.slackChannelId && origin.threadTs ? `${origin.slackChannelId}:${origin.threadTs}` : undefined;
|
|
226
|
+
return {
|
|
227
|
+
kind: 'owner-origin',
|
|
228
|
+
origin: {
|
|
229
|
+
conversationId: origin.conversationId,
|
|
230
|
+
...(origin.slackChannelId ? { slackChannelId: origin.slackChannelId } : {}),
|
|
231
|
+
...(origin.threadTs ? { slackThreadTs: origin.threadTs } : {}),
|
|
232
|
+
...(threadKey ? { slackThreadKey: threadKey } : {}),
|
|
233
|
+
...(origin.chatThreadId ? { chatThreadId: origin.chatThreadId } : {}),
|
|
234
|
+
receivedAt: startOf(workItem),
|
|
235
|
+
},
|
|
236
|
+
reason: `work item ${workItem.id} was asked by the owner`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (origin.slackChannelId) {
|
|
240
|
+
return { kind: 'slack', target: origin.slackChannelId, ...(origin.threadTs ? { threadTs: origin.threadTs } : {}), reason: `work item ${workItem.id} was asked by the owner in Slack` };
|
|
241
|
+
}
|
|
242
|
+
return { kind: 'new-top-level', topic: shortTopic(workItem.title), reason: `work item ${workItem.id} owner origin has no place` };
|
|
243
|
+
}
|
|
244
|
+
case 'ticket':
|
|
245
|
+
return {
|
|
246
|
+
kind: 'ticket-thread',
|
|
247
|
+
projectPath: origin.projectPath,
|
|
248
|
+
ticketId: origin.ticketId,
|
|
249
|
+
...(origin.title ? { title: origin.title } : {}),
|
|
250
|
+
...(origin.teamId ? { teamId: origin.teamId } : {}),
|
|
251
|
+
reason: `work item ${workItem.id} is ticket ${origin.ticketId}`,
|
|
252
|
+
};
|
|
253
|
+
case 'trigger': {
|
|
254
|
+
const parsed = origin.destination ? parseDestination(origin.destination) : null;
|
|
255
|
+
if (parsed) {
|
|
256
|
+
return {
|
|
257
|
+
kind: 'slack',
|
|
258
|
+
target: parsed.target,
|
|
259
|
+
...(parsed.threadTs ? { threadTs: parsed.threadTs } : { topic: origin.topic }),
|
|
260
|
+
reason: `scheduled work item ${workItem.id}: its trigger's destination`,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
kind: 'new-top-level',
|
|
265
|
+
...(origin.teamId ? { teamId: origin.teamId } : {}),
|
|
266
|
+
topic: origin.topic,
|
|
267
|
+
reason: `scheduled work item ${workItem.id}: new top-level post`,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* The text of a new top-level post: the topic line in bold, then the body.
|
|
274
|
+
*
|
|
275
|
+
* @param topic - Topic (may be empty)
|
|
276
|
+
* @param text - Body
|
|
277
|
+
* @returns Post text
|
|
278
|
+
*/
|
|
279
|
+
export function withTopicLine(topic, text) {
|
|
280
|
+
const t = shortTopic(topic);
|
|
281
|
+
if (!t)
|
|
282
|
+
return text;
|
|
283
|
+
// An agent that already opened with the topic needs no second copy.
|
|
284
|
+
if (text.trimStart().startsWith(`*${t}*`))
|
|
285
|
+
return text;
|
|
286
|
+
return `*${t}*\n${text}`;
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=work-item-destination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-item-destination.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/work-item-destination.ts"],"names":[],"mappings":"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"}
|
|
@@ -857,6 +857,16 @@ export declare class SlackTeamChannelService {
|
|
|
857
857
|
title?: string;
|
|
858
858
|
comment?: string;
|
|
859
859
|
threadId?: string;
|
|
860
|
+
/**
|
|
861
|
+
* Where the agent's current work answers (the `reply` resolver,
|
|
862
|
+
* work-item-destination.wiring). Used when no thread is named; null/absent
|
|
863
|
+
* = no known place → top level, never "the latest thread in the channel".
|
|
864
|
+
*/
|
|
865
|
+
destination?: {
|
|
866
|
+
slackChannelId: string;
|
|
867
|
+
threadTs?: string;
|
|
868
|
+
topic?: string;
|
|
869
|
+
} | null;
|
|
860
870
|
}): Promise<{
|
|
861
871
|
ok: true;
|
|
862
872
|
slackChannelId: string;
|
|
@@ -867,6 +877,12 @@ export declare class SlackTeamChannelService {
|
|
|
867
877
|
ok: false;
|
|
868
878
|
reason: string;
|
|
869
879
|
}>;
|
|
880
|
+
/**
|
|
881
|
+
* @param mapping - Channel mapping
|
|
882
|
+
* @param dto - The outbound message (thread reference / metadata)
|
|
883
|
+
* @param allowLatestRoot - Fall back to the channel's latest Slack thread (text mirror only; never for files)
|
|
884
|
+
* @returns Slack thread ts, or undefined for top level
|
|
885
|
+
*/
|
|
870
886
|
private resolveOutboundThreadTs;
|
|
871
887
|
/**
|
|
872
888
|
* Give every member of a mapped team a real Slack identity: ask Cloud for
|