@drisp/cli 0.5.10 → 0.5.13
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/dist/athena-gateway.js +434 -337
- package/dist/{chunk-RN5AVH3D.js → chunk-BUNMENOT.js} +582 -457
- package/dist/cli.js +9 -2
- package/dist/dashboard-daemon.js +1 -1
- package/dist/hook-forwarder.js +5 -5
- package/package.json +1 -1
|
@@ -216,7 +216,6 @@ function cleanupStaleSockets(sockDir) {
|
|
|
216
216
|
|
|
217
217
|
// src/harnesses/claude/runtime/interactionRules.ts
|
|
218
218
|
var DEFAULT_TIMEOUT_MS = 4e3;
|
|
219
|
-
var PERMISSION_TIMEOUT_MS = 3e5;
|
|
220
219
|
var DEFAULT_HINTS = {
|
|
221
220
|
expectsDecision: false,
|
|
222
221
|
defaultTimeoutMs: DEFAULT_TIMEOUT_MS,
|
|
@@ -225,12 +224,12 @@ var DEFAULT_HINTS = {
|
|
|
225
224
|
var RULES = {
|
|
226
225
|
"permission.request": {
|
|
227
226
|
expectsDecision: true,
|
|
228
|
-
defaultTimeoutMs:
|
|
227
|
+
defaultTimeoutMs: null,
|
|
229
228
|
canBlock: true
|
|
230
229
|
},
|
|
231
230
|
"tool.pre": {
|
|
232
231
|
expectsDecision: true,
|
|
233
|
-
defaultTimeoutMs:
|
|
232
|
+
defaultTimeoutMs: null,
|
|
234
233
|
canBlock: true
|
|
235
234
|
},
|
|
236
235
|
"tool.post": {
|
|
@@ -390,7 +389,7 @@ var RULES = {
|
|
|
390
389
|
},
|
|
391
390
|
"elicitation.request": {
|
|
392
391
|
expectsDecision: true,
|
|
393
|
-
defaultTimeoutMs:
|
|
392
|
+
defaultTimeoutMs: null,
|
|
394
393
|
canBlock: true
|
|
395
394
|
},
|
|
396
395
|
"elicitation.result": {
|
|
@@ -5369,13 +5368,12 @@ function describeAction(a) {
|
|
|
5369
5368
|
}
|
|
5370
5369
|
|
|
5371
5370
|
// src/harnesses/codex/runtime/interactionRules.ts
|
|
5372
|
-
var APPROVAL_TIMEOUT_MS = 3e5;
|
|
5373
5371
|
var DEFAULT_TIMEOUT_MS2 = 4e3;
|
|
5374
5372
|
function getCodexInteractionHints(expectsDecision) {
|
|
5375
5373
|
if (expectsDecision) {
|
|
5376
5374
|
return {
|
|
5377
5375
|
expectsDecision: true,
|
|
5378
|
-
defaultTimeoutMs:
|
|
5376
|
+
defaultTimeoutMs: null,
|
|
5379
5377
|
canBlock: true
|
|
5380
5378
|
};
|
|
5381
5379
|
}
|
|
@@ -7167,15 +7165,10 @@ function loadPlugin(pluginDir) {
|
|
|
7167
7165
|
}
|
|
7168
7166
|
const mcpConfigPath = path12.join(pluginDir, ".mcp.json");
|
|
7169
7167
|
const hasMcpConfig = fs14.existsSync(mcpConfigPath);
|
|
7170
|
-
const entries = fs14.readdirSync(skillsDir, { withFileTypes: true });
|
|
7171
7168
|
const commands2 = [];
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
if (!fs14.existsSync(skillPath)) continue;
|
|
7176
|
-
const content = fs14.readFileSync(skillPath, "utf-8");
|
|
7177
|
-
const parsed = parseFrontmatter(content);
|
|
7178
|
-
if (!parsed.frontmatter["user-invocable"]) continue;
|
|
7169
|
+
const loadSkillFile = (skillPath) => {
|
|
7170
|
+
const parsed = parseFrontmatter(fs14.readFileSync(skillPath, "utf-8"));
|
|
7171
|
+
if (!parsed.frontmatter["user-invocable"]) return;
|
|
7179
7172
|
commands2.push(
|
|
7180
7173
|
skillToCommand(
|
|
7181
7174
|
parsed.frontmatter,
|
|
@@ -7183,6 +7176,20 @@ function loadPlugin(pluginDir) {
|
|
|
7183
7176
|
hasMcpConfig ? mcpConfigPath : void 0
|
|
7184
7177
|
)
|
|
7185
7178
|
);
|
|
7179
|
+
};
|
|
7180
|
+
for (const entry of fs14.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
7181
|
+
if (!entry.isDirectory()) continue;
|
|
7182
|
+
const entryDir = path12.join(skillsDir, entry.name);
|
|
7183
|
+
const directSkill = path12.join(entryDir, "SKILL.md");
|
|
7184
|
+
if (fs14.existsSync(directSkill)) {
|
|
7185
|
+
loadSkillFile(directSkill);
|
|
7186
|
+
continue;
|
|
7187
|
+
}
|
|
7188
|
+
for (const nested of fs14.readdirSync(entryDir, { withFileTypes: true })) {
|
|
7189
|
+
if (!nested.isDirectory()) continue;
|
|
7190
|
+
const nestedSkill = path12.join(entryDir, nested.name, "SKILL.md");
|
|
7191
|
+
if (fs14.existsSync(nestedSkill)) loadSkillFile(nestedSkill);
|
|
7192
|
+
}
|
|
7186
7193
|
}
|
|
7187
7194
|
return commands2;
|
|
7188
7195
|
}
|
|
@@ -7851,7 +7858,8 @@ function createTranscriptReader() {
|
|
|
7851
7858
|
}
|
|
7852
7859
|
|
|
7853
7860
|
// src/core/feed/internals/runLifecycle.ts
|
|
7854
|
-
function createRunLifecycle() {
|
|
7861
|
+
function createRunLifecycle(boundary) {
|
|
7862
|
+
const { makeEvent, resetPerRunState } = boundary;
|
|
7855
7863
|
let currentSession = null;
|
|
7856
7864
|
let currentRun = null;
|
|
7857
7865
|
let seq = 0;
|
|
@@ -7860,17 +7868,79 @@ function createRunLifecycle() {
|
|
|
7860
7868
|
const sessId = currentSession?.session_id ?? "unknown";
|
|
7861
7869
|
return `${sessId}:R${runSeq}`;
|
|
7862
7870
|
}
|
|
7871
|
+
function allocateSeq() {
|
|
7872
|
+
return ++seq;
|
|
7873
|
+
}
|
|
7874
|
+
function getCurrentRun() {
|
|
7875
|
+
return currentRun;
|
|
7876
|
+
}
|
|
7877
|
+
function closeRun(ts, status) {
|
|
7878
|
+
if (!currentRun) return null;
|
|
7879
|
+
currentRun.status = status;
|
|
7880
|
+
currentRun.ended_at = ts;
|
|
7881
|
+
const closed = currentRun;
|
|
7882
|
+
currentRun = null;
|
|
7883
|
+
return closed;
|
|
7884
|
+
}
|
|
7885
|
+
function openNewRun(ts, sessionId, triggerType, promptPreview) {
|
|
7886
|
+
runSeq++;
|
|
7887
|
+
currentRun = {
|
|
7888
|
+
run_id: getRunId(),
|
|
7889
|
+
session_id: sessionId,
|
|
7890
|
+
started_at: ts,
|
|
7891
|
+
trigger: { type: triggerType, prompt_preview: promptPreview },
|
|
7892
|
+
status: "running",
|
|
7893
|
+
actors: { root_agent_id: "agent:root", subagent_ids: [] },
|
|
7894
|
+
counters: {
|
|
7895
|
+
tool_uses: 0,
|
|
7896
|
+
tool_failures: 0,
|
|
7897
|
+
permission_requests: 0,
|
|
7898
|
+
blocks: 0
|
|
7899
|
+
}
|
|
7900
|
+
};
|
|
7901
|
+
return currentRun;
|
|
7902
|
+
}
|
|
7903
|
+
function closeRunIntoEvent(runtimeEvent, status) {
|
|
7904
|
+
const closed = closeRun(runtimeEvent.timestamp, status);
|
|
7905
|
+
if (!closed) return null;
|
|
7906
|
+
return makeEvent(
|
|
7907
|
+
"run.end",
|
|
7908
|
+
"info",
|
|
7909
|
+
"system",
|
|
7910
|
+
{ status, counters: { ...closed.counters } },
|
|
7911
|
+
runtimeEvent
|
|
7912
|
+
);
|
|
7913
|
+
}
|
|
7914
|
+
function beginRun(runtimeEvent, triggerType = "other", promptPreview) {
|
|
7915
|
+
if (currentRun && triggerType === "other") return [];
|
|
7916
|
+
const results = [];
|
|
7917
|
+
const closeEvt = closeRunIntoEvent(runtimeEvent, "completed");
|
|
7918
|
+
if (closeEvt) results.push(closeEvt);
|
|
7919
|
+
resetPerRunState();
|
|
7920
|
+
openNewRun(
|
|
7921
|
+
runtimeEvent.timestamp,
|
|
7922
|
+
runtimeEvent.sessionId,
|
|
7923
|
+
triggerType,
|
|
7924
|
+
promptPreview
|
|
7925
|
+
);
|
|
7926
|
+
results.push(
|
|
7927
|
+
makeEvent(
|
|
7928
|
+
"run.start",
|
|
7929
|
+
"info",
|
|
7930
|
+
"system",
|
|
7931
|
+
{ trigger: { type: triggerType, prompt_preview: promptPreview } },
|
|
7932
|
+
runtimeEvent
|
|
7933
|
+
)
|
|
7934
|
+
);
|
|
7935
|
+
return results;
|
|
7936
|
+
}
|
|
7863
7937
|
return {
|
|
7864
|
-
allocateSeq
|
|
7865
|
-
return ++seq;
|
|
7866
|
-
},
|
|
7938
|
+
allocateSeq,
|
|
7867
7939
|
getRunId,
|
|
7868
7940
|
getSession() {
|
|
7869
7941
|
return currentSession;
|
|
7870
7942
|
},
|
|
7871
|
-
getCurrentRun
|
|
7872
|
-
return currentRun;
|
|
7873
|
-
},
|
|
7943
|
+
getCurrentRun,
|
|
7874
7944
|
setSession(session) {
|
|
7875
7945
|
currentSession = session;
|
|
7876
7946
|
},
|
|
@@ -7883,32 +7953,10 @@ function createRunLifecycle() {
|
|
|
7883
7953
|
incrementCounter(name) {
|
|
7884
7954
|
if (currentRun) currentRun.counters[name]++;
|
|
7885
7955
|
},
|
|
7886
|
-
closeRun
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
const closed = currentRun;
|
|
7891
|
-
currentRun = null;
|
|
7892
|
-
return closed;
|
|
7893
|
-
},
|
|
7894
|
-
openNewRun(ts, sessionId, triggerType, promptPreview) {
|
|
7895
|
-
runSeq++;
|
|
7896
|
-
currentRun = {
|
|
7897
|
-
run_id: getRunId(),
|
|
7898
|
-
session_id: sessionId,
|
|
7899
|
-
started_at: ts,
|
|
7900
|
-
trigger: { type: triggerType, prompt_preview: promptPreview },
|
|
7901
|
-
status: "running",
|
|
7902
|
-
actors: { root_agent_id: "agent:root", subagent_ids: [] },
|
|
7903
|
-
counters: {
|
|
7904
|
-
tool_uses: 0,
|
|
7905
|
-
tool_failures: 0,
|
|
7906
|
-
permission_requests: 0,
|
|
7907
|
-
blocks: 0
|
|
7908
|
-
}
|
|
7909
|
-
};
|
|
7910
|
-
return currentRun;
|
|
7911
|
-
},
|
|
7956
|
+
closeRun,
|
|
7957
|
+
openNewRun,
|
|
7958
|
+
closeRunIntoEvent,
|
|
7959
|
+
beginRun,
|
|
7912
7960
|
restoreFrom(bootstrap) {
|
|
7913
7961
|
for (const e of bootstrap.feedEvents) {
|
|
7914
7962
|
if (e.seq > seq) seq = e.seq;
|
|
@@ -8028,6 +8076,34 @@ function createToolCorrelation() {
|
|
|
8028
8076
|
};
|
|
8029
8077
|
}
|
|
8030
8078
|
|
|
8079
|
+
// src/core/feed/internals/projection.ts
|
|
8080
|
+
function readString(...values) {
|
|
8081
|
+
for (const value of values) {
|
|
8082
|
+
if (typeof value === "string") return value;
|
|
8083
|
+
}
|
|
8084
|
+
return void 0;
|
|
8085
|
+
}
|
|
8086
|
+
function readBoolean(...values) {
|
|
8087
|
+
for (const value of values) {
|
|
8088
|
+
if (typeof value === "boolean") return value;
|
|
8089
|
+
}
|
|
8090
|
+
return void 0;
|
|
8091
|
+
}
|
|
8092
|
+
function readObject(...values) {
|
|
8093
|
+
for (const value of values) {
|
|
8094
|
+
if (typeof value === "object" && value !== null) {
|
|
8095
|
+
return value;
|
|
8096
|
+
}
|
|
8097
|
+
}
|
|
8098
|
+
return {};
|
|
8099
|
+
}
|
|
8100
|
+
function readSuggestionArray(...values) {
|
|
8101
|
+
for (const value of values) {
|
|
8102
|
+
if (Array.isArray(value)) return value;
|
|
8103
|
+
}
|
|
8104
|
+
return void 0;
|
|
8105
|
+
}
|
|
8106
|
+
|
|
8031
8107
|
// src/core/feed/internals/agentMessageStream.ts
|
|
8032
8108
|
function normalizeAgentMessage(message) {
|
|
8033
8109
|
return message.replace(/\r\n/g, "\n").trimEnd();
|
|
@@ -8035,6 +8111,9 @@ function normalizeAgentMessage(message) {
|
|
|
8035
8111
|
function agentMessageKey(actorId, scope) {
|
|
8036
8112
|
return `${actorId}\0${scope}`;
|
|
8037
8113
|
}
|
|
8114
|
+
function isStopEvent(kind) {
|
|
8115
|
+
return kind === "stop.request" || kind === "subagent.stop";
|
|
8116
|
+
}
|
|
8038
8117
|
function createAgentMessageStream(eventBuilder, transcriptReader) {
|
|
8039
8118
|
const pendingMessages = /* @__PURE__ */ new Map();
|
|
8040
8119
|
const lastAgentMessageByActorScope = /* @__PURE__ */ new Map();
|
|
@@ -8061,6 +8140,25 @@ function createAgentMessageStream(eventBuilder, transcriptReader) {
|
|
|
8061
8140
|
lastAgentMessageByActorScope.set(key, normalized);
|
|
8062
8141
|
return event;
|
|
8063
8142
|
}
|
|
8143
|
+
function emitTranscriptMessages(transcriptPath, runtimeEvent, actorId, scope) {
|
|
8144
|
+
const msgs = transcriptReader.readNewAssistantMessages(transcriptPath);
|
|
8145
|
+
const out = [];
|
|
8146
|
+
for (const msg of msgs) {
|
|
8147
|
+
const ev = emit({
|
|
8148
|
+
runtimeEvent,
|
|
8149
|
+
actorId,
|
|
8150
|
+
scope,
|
|
8151
|
+
message: msg.text,
|
|
8152
|
+
source: "transcript",
|
|
8153
|
+
model: msg.model
|
|
8154
|
+
});
|
|
8155
|
+
if (ev) out.push(ev);
|
|
8156
|
+
}
|
|
8157
|
+
return out;
|
|
8158
|
+
}
|
|
8159
|
+
function drainTranscript(transcriptPath) {
|
|
8160
|
+
transcriptReader.readNewAssistantMessages(transcriptPath);
|
|
8161
|
+
}
|
|
8064
8162
|
return {
|
|
8065
8163
|
emit,
|
|
8066
8164
|
appendPendingDelta(itemId, delta, defaultActorId, defaultScope) {
|
|
@@ -8116,25 +8214,37 @@ function createAgentMessageStream(eventBuilder, transcriptReader) {
|
|
|
8116
8214
|
}
|
|
8117
8215
|
return out;
|
|
8118
8216
|
},
|
|
8119
|
-
emitTranscriptMessages
|
|
8120
|
-
|
|
8121
|
-
const
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
model: msg.model
|
|
8130
|
-
});
|
|
8131
|
-
if (ev) out.push(ev);
|
|
8132
|
-
}
|
|
8133
|
-
return out;
|
|
8217
|
+
emitTranscriptMessages,
|
|
8218
|
+
replayBeforeEvent(runtimeEvent, actorId, scope) {
|
|
8219
|
+
const transcriptPath = runtimeEvent.context.transcriptPath;
|
|
8220
|
+
if (!transcriptPath || isStopEvent(runtimeEvent.kind)) return [];
|
|
8221
|
+
return emitTranscriptMessages(
|
|
8222
|
+
transcriptPath,
|
|
8223
|
+
runtimeEvent,
|
|
8224
|
+
actorId,
|
|
8225
|
+
scope
|
|
8226
|
+
);
|
|
8134
8227
|
},
|
|
8135
|
-
|
|
8136
|
-
|
|
8228
|
+
emitStopFallback(runtimeEvent, opts) {
|
|
8229
|
+
const transcriptPath = runtimeEvent.context.transcriptPath;
|
|
8230
|
+
if (transcriptPath) drainTranscript(transcriptPath);
|
|
8231
|
+
if (opts.priorResults.some((r) => r.kind === "agent.message")) return [];
|
|
8232
|
+
const message = readString(
|
|
8233
|
+
runtimeEvent.data["last_assistant_message"]
|
|
8234
|
+
);
|
|
8235
|
+
if (!message) return [];
|
|
8236
|
+
const parent = opts.priorResults.find((r) => r.kind === opts.parentKind);
|
|
8237
|
+
const ev = emit({
|
|
8238
|
+
runtimeEvent,
|
|
8239
|
+
actorId: opts.actorId,
|
|
8240
|
+
scope: opts.scope,
|
|
8241
|
+
message,
|
|
8242
|
+
source: "hook",
|
|
8243
|
+
cause: parent ? { parent_event_id: parent.event_id } : void 0
|
|
8244
|
+
});
|
|
8245
|
+
return ev ? [ev] : [];
|
|
8137
8246
|
},
|
|
8247
|
+
drainTranscript,
|
|
8138
8248
|
appendReasoningSummary(itemId, index, chunk) {
|
|
8139
8249
|
const key = `${itemId ?? ""}:${index ?? 0}`;
|
|
8140
8250
|
const next = `${reasoningSummaryByKey.get(key) ?? ""}${chunk}`;
|
|
@@ -8233,6 +8343,129 @@ function createTaskLifecycleTracker() {
|
|
|
8233
8343
|
};
|
|
8234
8344
|
}
|
|
8235
8345
|
|
|
8346
|
+
// src/core/feed/internals/taskStateTracker.ts
|
|
8347
|
+
function extractTodoItems(toolInput) {
|
|
8348
|
+
const input = toolInput;
|
|
8349
|
+
return Array.isArray(input?.todos) ? input.todos : [];
|
|
8350
|
+
}
|
|
8351
|
+
function mapPlanStepStatus(status) {
|
|
8352
|
+
switch (status) {
|
|
8353
|
+
case "inProgress":
|
|
8354
|
+
return "in_progress";
|
|
8355
|
+
case "completed":
|
|
8356
|
+
return "completed";
|
|
8357
|
+
case void 0:
|
|
8358
|
+
default:
|
|
8359
|
+
return "pending";
|
|
8360
|
+
}
|
|
8361
|
+
}
|
|
8362
|
+
function createTaskStateTracker() {
|
|
8363
|
+
const rootPlan = createRootPlanTracker();
|
|
8364
|
+
const taskLifecycle = createTaskLifecycleTracker();
|
|
8365
|
+
function applyToolPre(input) {
|
|
8366
|
+
const { toolName, toolInput, actorId } = input;
|
|
8367
|
+
if (toolName === "TodoWrite" && actorId === "agent:root") {
|
|
8368
|
+
rootPlan.set(extractTodoItems(toolInput));
|
|
8369
|
+
}
|
|
8370
|
+
if (toolName === "TaskUpdate") {
|
|
8371
|
+
const taskId = readString(toolInput["taskId"], toolInput["task_id"]);
|
|
8372
|
+
const status = coerceTaskStatus(toolInput["status"]);
|
|
8373
|
+
if (taskId && status) {
|
|
8374
|
+
taskLifecycle.updateStatus({ taskId, status });
|
|
8375
|
+
}
|
|
8376
|
+
}
|
|
8377
|
+
}
|
|
8378
|
+
function applyToolPost(input) {
|
|
8379
|
+
const { toolName, toolInput, toolResponse } = input;
|
|
8380
|
+
if (toolName === "TaskCreate") {
|
|
8381
|
+
const response = readObject(toolResponse);
|
|
8382
|
+
const task = readObject(response["task"]);
|
|
8383
|
+
const taskId = readString(task["id"], task["task_id"]);
|
|
8384
|
+
const subject = readString(task["subject"], toolInput["subject"]);
|
|
8385
|
+
if (taskId && subject) {
|
|
8386
|
+
taskLifecycle.upsertCreated({
|
|
8387
|
+
taskId,
|
|
8388
|
+
subject,
|
|
8389
|
+
description: readString(toolInput["description"]),
|
|
8390
|
+
activeForm: readString(toolInput["activeForm"])
|
|
8391
|
+
});
|
|
8392
|
+
}
|
|
8393
|
+
}
|
|
8394
|
+
if (toolName === "TaskUpdate") {
|
|
8395
|
+
const response = readObject(toolResponse);
|
|
8396
|
+
const taskId = readString(
|
|
8397
|
+
response["taskId"],
|
|
8398
|
+
response["task_id"],
|
|
8399
|
+
toolInput["taskId"],
|
|
8400
|
+
toolInput["task_id"]
|
|
8401
|
+
);
|
|
8402
|
+
const status = coerceTaskStatus(
|
|
8403
|
+
readObject(response["statusChange"])["to"] ?? toolInput["status"]
|
|
8404
|
+
);
|
|
8405
|
+
if (taskId && status) {
|
|
8406
|
+
taskLifecycle.updateStatus({ taskId, status });
|
|
8407
|
+
}
|
|
8408
|
+
}
|
|
8409
|
+
}
|
|
8410
|
+
function applyTaskCreatedEvent(data) {
|
|
8411
|
+
const taskId = readString(data["task_id"]);
|
|
8412
|
+
const subject = readString(data["task_subject"]);
|
|
8413
|
+
const description = readString(data["task_description"]);
|
|
8414
|
+
if (taskId && subject) {
|
|
8415
|
+
taskLifecycle.upsertCreated({ taskId, subject, description });
|
|
8416
|
+
}
|
|
8417
|
+
}
|
|
8418
|
+
function applyTaskCompletedEvent(data) {
|
|
8419
|
+
const taskId = readString(data["task_id"]);
|
|
8420
|
+
const subject = readString(data["task_subject"]);
|
|
8421
|
+
if (taskId) {
|
|
8422
|
+
taskLifecycle.markCompleted({ taskId, subject });
|
|
8423
|
+
}
|
|
8424
|
+
}
|
|
8425
|
+
return {
|
|
8426
|
+
current() {
|
|
8427
|
+
return [...rootPlan.current(), ...taskLifecycle.current()];
|
|
8428
|
+
},
|
|
8429
|
+
applyToolPre,
|
|
8430
|
+
applyToolPost,
|
|
8431
|
+
applyPlanDelta(planSteps) {
|
|
8432
|
+
if (!Array.isArray(planSteps) || planSteps.length === 0) return false;
|
|
8433
|
+
const next = planSteps.map((step) => ({
|
|
8434
|
+
content: typeof step.step === "string" ? step.step : "",
|
|
8435
|
+
status: mapPlanStepStatus(step.status)
|
|
8436
|
+
}));
|
|
8437
|
+
if (!rootPlan.differs(next)) return false;
|
|
8438
|
+
rootPlan.set(next);
|
|
8439
|
+
return true;
|
|
8440
|
+
},
|
|
8441
|
+
applyTaskCreatedEvent,
|
|
8442
|
+
applyTaskCompletedEvent,
|
|
8443
|
+
restore(feedEvents) {
|
|
8444
|
+
for (const e of feedEvents) {
|
|
8445
|
+
if (e.kind === "tool.pre") {
|
|
8446
|
+
const data = e.data;
|
|
8447
|
+
applyToolPre({
|
|
8448
|
+
toolName: data.tool_name ?? "",
|
|
8449
|
+
toolInput: readObject(data.tool_input),
|
|
8450
|
+
actorId: e.actor_id
|
|
8451
|
+
});
|
|
8452
|
+
} else if (e.kind === "tool.post") {
|
|
8453
|
+
const data = e.data;
|
|
8454
|
+
applyToolPost({
|
|
8455
|
+
toolName: data.tool_name ?? "",
|
|
8456
|
+
toolInput: readObject(data.tool_input),
|
|
8457
|
+
toolResponse: data.tool_response
|
|
8458
|
+
});
|
|
8459
|
+
} else if (e.kind === "task.created") {
|
|
8460
|
+
applyTaskCreatedEvent(e.data);
|
|
8461
|
+
} else if (e.kind === "task.completed") {
|
|
8462
|
+
applyTaskCompletedEvent(e.data);
|
|
8463
|
+
}
|
|
8464
|
+
}
|
|
8465
|
+
}
|
|
8466
|
+
};
|
|
8467
|
+
}
|
|
8468
|
+
|
|
8236
8469
|
// src/core/feed/internals/subagentTracker.ts
|
|
8237
8470
|
function createSubagentTracker() {
|
|
8238
8471
|
const stack = [];
|
|
@@ -8275,44 +8508,57 @@ function createSubagentTracker() {
|
|
|
8275
8508
|
};
|
|
8276
8509
|
}
|
|
8277
8510
|
|
|
8278
|
-
// src/core/feed/internals/projection.ts
|
|
8279
|
-
function readString(...values) {
|
|
8280
|
-
for (const value of values) {
|
|
8281
|
-
if (typeof value === "string") return value;
|
|
8282
|
-
}
|
|
8283
|
-
return void 0;
|
|
8284
|
-
}
|
|
8285
|
-
function readBoolean(...values) {
|
|
8286
|
-
for (const value of values) {
|
|
8287
|
-
if (typeof value === "boolean") return value;
|
|
8288
|
-
}
|
|
8289
|
-
return void 0;
|
|
8290
|
-
}
|
|
8291
|
-
function readObject(...values) {
|
|
8292
|
-
for (const value of values) {
|
|
8293
|
-
if (typeof value === "object" && value !== null) {
|
|
8294
|
-
return value;
|
|
8295
|
-
}
|
|
8296
|
-
}
|
|
8297
|
-
return {};
|
|
8298
|
-
}
|
|
8299
|
-
function readSuggestionArray(...values) {
|
|
8300
|
-
for (const value of values) {
|
|
8301
|
-
if (Array.isArray(value)) return value;
|
|
8302
|
-
}
|
|
8303
|
-
return void 0;
|
|
8304
|
-
}
|
|
8305
|
-
|
|
8306
8511
|
// src/core/feed/todo.ts
|
|
8307
8512
|
function isSubagentTool(toolName) {
|
|
8308
8513
|
return toolName === "Task" || toolName === "Agent";
|
|
8309
8514
|
}
|
|
8310
8515
|
|
|
8311
|
-
// src/core/feed/internals/
|
|
8312
|
-
function
|
|
8313
|
-
const
|
|
8314
|
-
|
|
8516
|
+
// src/core/feed/internals/subagentLifecycle.ts
|
|
8517
|
+
function createSubagentLifecycle(args) {
|
|
8518
|
+
const { actors, runLifecycle } = args;
|
|
8519
|
+
const tracker = createSubagentTracker();
|
|
8520
|
+
const actorIdFor = (agentId) => `subagent:${agentId}`;
|
|
8521
|
+
return {
|
|
8522
|
+
observeToolInput(toolName, toolInput) {
|
|
8523
|
+
if (!isSubagentTool(toolName)) return;
|
|
8524
|
+
if (typeof toolInput["description"] === "string") {
|
|
8525
|
+
tracker.recordPendingDescription(toolInput["description"]);
|
|
8526
|
+
} else {
|
|
8527
|
+
tracker.clearPendingDescription();
|
|
8528
|
+
}
|
|
8529
|
+
},
|
|
8530
|
+
startSubagent({ agentId, agentType, fallbackDescription }) {
|
|
8531
|
+
const description = tracker.consumePendingDescription() ?? fallbackDescription;
|
|
8532
|
+
if (agentId) {
|
|
8533
|
+
actors.ensureSubagent(agentId, agentType ?? "unknown");
|
|
8534
|
+
const currentRun = runLifecycle.getCurrentRun();
|
|
8535
|
+
if (currentRun) currentRun.actors.subagent_ids.push(agentId);
|
|
8536
|
+
tracker.pushActor(actorIdFor(agentId));
|
|
8537
|
+
if (description) tracker.setDescription(agentId, description);
|
|
8538
|
+
}
|
|
8539
|
+
return { actorId: "agent:root", description: description ?? void 0 };
|
|
8540
|
+
},
|
|
8541
|
+
stopSubagent(agentId) {
|
|
8542
|
+
if (agentId) tracker.popActor(actorIdFor(agentId));
|
|
8543
|
+
return {
|
|
8544
|
+
actorId: actorIdFor(agentId ?? "unknown"),
|
|
8545
|
+
description: tracker.description(agentId ?? "")
|
|
8546
|
+
};
|
|
8547
|
+
},
|
|
8548
|
+
currentActor() {
|
|
8549
|
+
return tracker.peek() ?? "agent:root";
|
|
8550
|
+
},
|
|
8551
|
+
currentScope() {
|
|
8552
|
+
return tracker.currentScope();
|
|
8553
|
+
},
|
|
8554
|
+
actorIdFor,
|
|
8555
|
+
clear() {
|
|
8556
|
+
tracker.clear();
|
|
8557
|
+
}
|
|
8558
|
+
};
|
|
8315
8559
|
}
|
|
8560
|
+
|
|
8561
|
+
// src/core/feed/internals/toolProjection.ts
|
|
8316
8562
|
function resolveToolUseId(event, record) {
|
|
8317
8563
|
return event.toolUseId ?? record["tool_use_id"];
|
|
8318
8564
|
}
|
|
@@ -8328,8 +8574,7 @@ function createToolProjection(args) {
|
|
|
8328
8574
|
makeEvent,
|
|
8329
8575
|
runLifecycle,
|
|
8330
8576
|
toolCorrelation,
|
|
8331
|
-
|
|
8332
|
-
taskLifecycle,
|
|
8577
|
+
taskState,
|
|
8333
8578
|
subagents,
|
|
8334
8579
|
resolveToolActor
|
|
8335
8580
|
} = args;
|
|
@@ -8426,23 +8671,12 @@ function createToolProjection(args) {
|
|
|
8426
8671
|
webSearchStarted(event, data, toolUseId, preEvent.event_id)
|
|
8427
8672
|
);
|
|
8428
8673
|
}
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
if (taskId && status) {
|
|
8436
|
-
taskLifecycle.updateStatus({ taskId, status });
|
|
8437
|
-
}
|
|
8438
|
-
}
|
|
8439
|
-
if (isSubagentTool(toolName)) {
|
|
8440
|
-
if (typeof toolInput["description"] === "string") {
|
|
8441
|
-
subagents.recordPendingDescription(toolInput["description"]);
|
|
8442
|
-
} else {
|
|
8443
|
-
subagents.clearPendingDescription();
|
|
8444
|
-
}
|
|
8445
|
-
}
|
|
8674
|
+
taskState.applyToolPre({
|
|
8675
|
+
toolName,
|
|
8676
|
+
toolInput,
|
|
8677
|
+
actorId: preEvent.actor_id
|
|
8678
|
+
});
|
|
8679
|
+
subagents.observeToolInput(toolName, toolInput);
|
|
8446
8680
|
return results;
|
|
8447
8681
|
}
|
|
8448
8682
|
if (event.kind === "tool.post") {
|
|
@@ -8462,35 +8696,11 @@ function createToolProjection(args) {
|
|
|
8462
8696
|
toolUseCause(toolUseId, parentId)
|
|
8463
8697
|
);
|
|
8464
8698
|
results.push(postEvent);
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
if (taskId && subject) {
|
|
8471
|
-
taskLifecycle.upsertCreated({
|
|
8472
|
-
taskId,
|
|
8473
|
-
subject,
|
|
8474
|
-
description: readString(toolInput["description"]),
|
|
8475
|
-
activeForm: readString(toolInput["activeForm"])
|
|
8476
|
-
});
|
|
8477
|
-
}
|
|
8478
|
-
}
|
|
8479
|
-
if (toolName === "TaskUpdate") {
|
|
8480
|
-
const response = readObject(data["tool_response"]);
|
|
8481
|
-
const taskId = readString(
|
|
8482
|
-
response["taskId"],
|
|
8483
|
-
response["task_id"],
|
|
8484
|
-
toolInput["taskId"],
|
|
8485
|
-
toolInput["task_id"]
|
|
8486
|
-
);
|
|
8487
|
-
const status = coerceTaskStatus(
|
|
8488
|
-
readObject(response["statusChange"])["to"] ?? toolInput["status"]
|
|
8489
|
-
);
|
|
8490
|
-
if (taskId && status) {
|
|
8491
|
-
taskLifecycle.updateStatus({ taskId, status });
|
|
8492
|
-
}
|
|
8493
|
-
}
|
|
8699
|
+
taskState.applyToolPost({
|
|
8700
|
+
toolName,
|
|
8701
|
+
toolInput,
|
|
8702
|
+
toolResponse: data.tool_response
|
|
8703
|
+
});
|
|
8494
8704
|
if (toolName === "WebSearch") {
|
|
8495
8705
|
results.push(
|
|
8496
8706
|
webSearchCompleted(event, data, toolUseId, postEvent.event_id)
|
|
@@ -8931,29 +9141,27 @@ function createDecisionProjection(args) {
|
|
|
8931
9141
|
|
|
8932
9142
|
// src/core/feed/internals/subagentProjection.ts
|
|
8933
9143
|
function createSubagentProjection(args) {
|
|
8934
|
-
const { ensureRunArray, makeEvent,
|
|
9144
|
+
const { ensureRunArray, makeEvent, subagents } = args;
|
|
8935
9145
|
return {
|
|
8936
9146
|
mapSubagentEvent(event, data) {
|
|
8937
9147
|
const results = ensureRunArray(event);
|
|
8938
9148
|
const agentId = event.agentId ?? readString(data["agent_id"]);
|
|
8939
9149
|
const agentType = event.agentType ?? readString(data["agent_type"]);
|
|
8940
9150
|
if (event.kind === "subagent.start") {
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
}
|
|
8947
|
-
const description = subagents.consumePendingDescription() ?? readString(data["prompt"]);
|
|
9151
|
+
const { actorId: actorId2, description: description2 } = subagents.startSubagent({
|
|
9152
|
+
agentId,
|
|
9153
|
+
agentType,
|
|
9154
|
+
fallbackDescription: readString(data["prompt"])
|
|
9155
|
+
});
|
|
8948
9156
|
results.push(
|
|
8949
9157
|
makeEvent(
|
|
8950
9158
|
"subagent.start",
|
|
8951
9159
|
"info",
|
|
8952
|
-
|
|
9160
|
+
actorId2,
|
|
8953
9161
|
{
|
|
8954
9162
|
agent_id: agentId ?? "",
|
|
8955
9163
|
agent_type: agentType ?? "",
|
|
8956
|
-
description:
|
|
9164
|
+
description: description2 ?? void 0,
|
|
8957
9165
|
tool: readString(data["tool"]),
|
|
8958
9166
|
sender_thread_id: readString(data["sender_thread_id"]),
|
|
8959
9167
|
receiver_thread_id: readString(data["receiver_thread_id"]),
|
|
@@ -8963,23 +9171,21 @@ function createSubagentProjection(args) {
|
|
|
8963
9171
|
event
|
|
8964
9172
|
)
|
|
8965
9173
|
);
|
|
8966
|
-
if (agentId && description)
|
|
8967
|
-
subagents.setDescription(agentId, description);
|
|
8968
9174
|
return results;
|
|
8969
9175
|
}
|
|
8970
|
-
|
|
9176
|
+
const { actorId, description } = subagents.stopSubagent(agentId);
|
|
8971
9177
|
results.push(
|
|
8972
9178
|
makeEvent(
|
|
8973
9179
|
"subagent.stop",
|
|
8974
9180
|
"info",
|
|
8975
|
-
|
|
9181
|
+
actorId,
|
|
8976
9182
|
{
|
|
8977
9183
|
agent_id: agentId ?? "",
|
|
8978
9184
|
agent_type: agentType ?? "",
|
|
8979
9185
|
stop_hook_active: readBoolean(data["stop_hook_active"]) ?? false,
|
|
8980
9186
|
agent_transcript_path: readString(data["agent_transcript_path"]),
|
|
8981
9187
|
last_assistant_message: readString(data["last_assistant_message"]),
|
|
8982
|
-
description
|
|
9188
|
+
description,
|
|
8983
9189
|
tool: readString(data["tool"]),
|
|
8984
9190
|
status: readString(data["status"]),
|
|
8985
9191
|
sender_thread_id: readString(data["sender_thread_id"]),
|
|
@@ -9160,17 +9366,6 @@ function createFileConfigProjection(args) {
|
|
|
9160
9366
|
}
|
|
9161
9367
|
|
|
9162
9368
|
// src/core/feed/internals/runSessionProjection.ts
|
|
9163
|
-
function mapPlanStepStatus(status) {
|
|
9164
|
-
switch (status) {
|
|
9165
|
-
case "inProgress":
|
|
9166
|
-
return "in_progress";
|
|
9167
|
-
case "completed":
|
|
9168
|
-
return "completed";
|
|
9169
|
-
case void 0:
|
|
9170
|
-
default:
|
|
9171
|
-
return "pending";
|
|
9172
|
-
}
|
|
9173
|
-
}
|
|
9174
9369
|
function createRunSessionProjection(args) {
|
|
9175
9370
|
const {
|
|
9176
9371
|
ensureRunArray,
|
|
@@ -9178,7 +9373,7 @@ function createRunSessionProjection(args) {
|
|
|
9178
9373
|
closeRunIntoEvent,
|
|
9179
9374
|
runLifecycle,
|
|
9180
9375
|
agentMessageStream,
|
|
9181
|
-
|
|
9376
|
+
taskState,
|
|
9182
9377
|
resolveToolActor,
|
|
9183
9378
|
currentScope
|
|
9184
9379
|
} = args;
|
|
@@ -9329,28 +9524,19 @@ function createRunSessionProjection(args) {
|
|
|
9329
9524
|
}
|
|
9330
9525
|
if (event.kind === "plan.delta") {
|
|
9331
9526
|
const planSteps = data["plan"];
|
|
9332
|
-
if (
|
|
9333
|
-
|
|
9334
|
-
(
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9527
|
+
if (taskState.applyPlanDelta(planSteps)) {
|
|
9528
|
+
results.push(
|
|
9529
|
+
makeEvent(
|
|
9530
|
+
"todo.update",
|
|
9531
|
+
"info",
|
|
9532
|
+
"system",
|
|
9533
|
+
{
|
|
9534
|
+
todo_id: "plan",
|
|
9535
|
+
patch: { status: "doing" }
|
|
9536
|
+
},
|
|
9537
|
+
event
|
|
9538
|
+
)
|
|
9338
9539
|
);
|
|
9339
|
-
if (rootPlan.differs(next)) {
|
|
9340
|
-
rootPlan.set(next);
|
|
9341
|
-
results.push(
|
|
9342
|
-
makeEvent(
|
|
9343
|
-
"todo.update",
|
|
9344
|
-
"info",
|
|
9345
|
-
"system",
|
|
9346
|
-
{
|
|
9347
|
-
todo_id: "plan",
|
|
9348
|
-
patch: { status: "doing" }
|
|
9349
|
-
},
|
|
9350
|
-
event
|
|
9351
|
-
)
|
|
9352
|
-
);
|
|
9353
|
-
}
|
|
9354
9540
|
}
|
|
9355
9541
|
results.push(
|
|
9356
9542
|
makeEvent(
|
|
@@ -9422,7 +9608,7 @@ function createRunSessionProjection(args) {
|
|
|
9422
9608
|
|
|
9423
9609
|
// src/core/feed/internals/statusProjection.ts
|
|
9424
9610
|
function createStatusProjection(args) {
|
|
9425
|
-
const { ensureRunArray, makeEvent,
|
|
9611
|
+
const { ensureRunArray, makeEvent, taskState } = args;
|
|
9426
9612
|
return {
|
|
9427
9613
|
mapStatusEvent(event, data) {
|
|
9428
9614
|
const results = ensureRunArray(event);
|
|
@@ -9445,13 +9631,7 @@ function createStatusProjection(args) {
|
|
|
9445
9631
|
const taskId = readString(data["task_id"]) ?? "";
|
|
9446
9632
|
const subject = readString(data["task_subject"]) ?? "";
|
|
9447
9633
|
const description = readString(data["task_description"]);
|
|
9448
|
-
|
|
9449
|
-
taskLifecycle.upsertCreated({
|
|
9450
|
-
taskId,
|
|
9451
|
-
subject,
|
|
9452
|
-
description
|
|
9453
|
-
});
|
|
9454
|
-
}
|
|
9634
|
+
taskState.applyTaskCreatedEvent(data);
|
|
9455
9635
|
results.push(
|
|
9456
9636
|
makeEvent(
|
|
9457
9637
|
"task.created",
|
|
@@ -9472,7 +9652,7 @@ function createStatusProjection(args) {
|
|
|
9472
9652
|
if (event.kind === "task.completed") {
|
|
9473
9653
|
const taskId = readString(data["task_id"]) ?? "";
|
|
9474
9654
|
const subject = readString(data["task_subject"]);
|
|
9475
|
-
|
|
9655
|
+
taskState.applyTaskCompletedEvent(data);
|
|
9476
9656
|
results.push(
|
|
9477
9657
|
makeEvent(
|
|
9478
9658
|
"task.completed",
|
|
@@ -9542,14 +9722,21 @@ var STATUS_EVENT_KINDS = /* @__PURE__ */ new Set([
|
|
|
9542
9722
|
"task.created"
|
|
9543
9723
|
]);
|
|
9544
9724
|
function createFeedMapper(bootstrap) {
|
|
9545
|
-
const runLifecycle = createRunLifecycle(
|
|
9725
|
+
const runLifecycle = createRunLifecycle({
|
|
9726
|
+
makeEvent,
|
|
9727
|
+
resetPerRunState: () => {
|
|
9728
|
+
toolCorrelation.resetForNewRun();
|
|
9729
|
+
decisionCorrelation.resetForNewRun();
|
|
9730
|
+
agentMessageStream.resetForNewRun();
|
|
9731
|
+
subagents.clear();
|
|
9732
|
+
}
|
|
9733
|
+
});
|
|
9546
9734
|
const decisionCorrelation = createDecisionCorrelation();
|
|
9547
9735
|
const toolCorrelation = createToolCorrelation();
|
|
9548
9736
|
const transcriptReader = createTranscriptReader();
|
|
9549
9737
|
const actors = new ActorRegistry();
|
|
9550
|
-
const
|
|
9551
|
-
const
|
|
9552
|
-
const subagents = createSubagentTracker();
|
|
9738
|
+
const taskState = createTaskStateTracker();
|
|
9739
|
+
const subagents = createSubagentLifecycle({ actors, runLifecycle });
|
|
9553
9740
|
function makeEvent(kind, level, actorId, data, runtimeEvent, cause) {
|
|
9554
9741
|
const s = runLifecycle.allocateSeq();
|
|
9555
9742
|
const runId = runLifecycle.getRunId();
|
|
@@ -9584,117 +9771,21 @@ function createFeedMapper(bootstrap) {
|
|
|
9584
9771
|
makeEvent,
|
|
9585
9772
|
transcriptReader
|
|
9586
9773
|
);
|
|
9587
|
-
function replayTaskLifecycleToolEvent(e) {
|
|
9588
|
-
if (e.kind !== "tool.pre" && e.kind !== "tool.post") return;
|
|
9589
|
-
const data = e.data;
|
|
9590
|
-
const toolInput = readObject(data.tool_input);
|
|
9591
|
-
if (data.tool_name === "TaskCreate" && e.kind === "tool.post") {
|
|
9592
|
-
const response = readObject(data.tool_response);
|
|
9593
|
-
const task = readObject(response["task"]);
|
|
9594
|
-
const taskId = readString(task["id"], task["task_id"]);
|
|
9595
|
-
const subject = readString(task["subject"], toolInput["subject"]);
|
|
9596
|
-
if (taskId && subject) {
|
|
9597
|
-
taskLifecycle.upsertCreated({
|
|
9598
|
-
taskId,
|
|
9599
|
-
subject,
|
|
9600
|
-
description: readString(toolInput["description"]),
|
|
9601
|
-
activeForm: readString(toolInput["activeForm"])
|
|
9602
|
-
});
|
|
9603
|
-
}
|
|
9604
|
-
}
|
|
9605
|
-
if (data.tool_name === "TaskUpdate") {
|
|
9606
|
-
const response = readObject(data.tool_response);
|
|
9607
|
-
const status = coerceTaskStatus(
|
|
9608
|
-
readObject(response["statusChange"])["to"] ?? toolInput["status"]
|
|
9609
|
-
);
|
|
9610
|
-
const taskId = readString(
|
|
9611
|
-
response["taskId"],
|
|
9612
|
-
response["task_id"],
|
|
9613
|
-
toolInput["taskId"],
|
|
9614
|
-
toolInput["task_id"]
|
|
9615
|
-
);
|
|
9616
|
-
if (taskId && status) {
|
|
9617
|
-
taskLifecycle.updateStatus({ taskId, status });
|
|
9618
|
-
}
|
|
9619
|
-
}
|
|
9620
|
-
}
|
|
9621
9774
|
if (bootstrap) {
|
|
9622
9775
|
runLifecycle.restoreFrom(bootstrap);
|
|
9623
|
-
|
|
9624
|
-
if (e.kind === "tool.pre" && e.actor_id === "agent:root" && e.data.tool_name === "TodoWrite") {
|
|
9625
|
-
rootPlan.set(
|
|
9626
|
-
extractTodoItems(e.data.tool_input)
|
|
9627
|
-
);
|
|
9628
|
-
}
|
|
9629
|
-
replayTaskLifecycleToolEvent(e);
|
|
9630
|
-
if (e.kind === "task.created") {
|
|
9631
|
-
const data = e.data;
|
|
9632
|
-
if (data.task_id && data.task_subject) {
|
|
9633
|
-
taskLifecycle.upsertCreated({
|
|
9634
|
-
taskId: data.task_id,
|
|
9635
|
-
subject: data.task_subject,
|
|
9636
|
-
description: data.task_description
|
|
9637
|
-
});
|
|
9638
|
-
}
|
|
9639
|
-
}
|
|
9640
|
-
if (e.kind === "task.completed") {
|
|
9641
|
-
const data = e.data;
|
|
9642
|
-
if (data.task_id) {
|
|
9643
|
-
taskLifecycle.markCompleted({
|
|
9644
|
-
taskId: data.task_id,
|
|
9645
|
-
subject: data.task_subject
|
|
9646
|
-
});
|
|
9647
|
-
}
|
|
9648
|
-
}
|
|
9649
|
-
}
|
|
9650
|
-
}
|
|
9651
|
-
function closeRunIntoEvent(runtimeEvent, status) {
|
|
9652
|
-
const closed = runLifecycle.closeRun(runtimeEvent.timestamp, status);
|
|
9653
|
-
if (!closed) return null;
|
|
9654
|
-
return makeEvent(
|
|
9655
|
-
"run.end",
|
|
9656
|
-
"info",
|
|
9657
|
-
"system",
|
|
9658
|
-
{ status, counters: { ...closed.counters } },
|
|
9659
|
-
runtimeEvent
|
|
9660
|
-
);
|
|
9661
|
-
}
|
|
9662
|
-
function ensureRunArray(runtimeEvent, triggerType = "other", promptPreview) {
|
|
9663
|
-
if (runLifecycle.getCurrentRun() && triggerType === "other") return [];
|
|
9664
|
-
const results = [];
|
|
9665
|
-
const closeEvt = closeRunIntoEvent(runtimeEvent, "completed");
|
|
9666
|
-
if (closeEvt) results.push(closeEvt);
|
|
9667
|
-
toolCorrelation.resetForNewRun();
|
|
9668
|
-
decisionCorrelation.resetForNewRun();
|
|
9669
|
-
agentMessageStream.resetForNewRun();
|
|
9670
|
-
subagents.clear();
|
|
9671
|
-
runLifecycle.openNewRun(
|
|
9672
|
-
runtimeEvent.timestamp,
|
|
9673
|
-
runtimeEvent.sessionId,
|
|
9674
|
-
triggerType,
|
|
9675
|
-
promptPreview
|
|
9676
|
-
);
|
|
9677
|
-
results.push(
|
|
9678
|
-
makeEvent(
|
|
9679
|
-
"run.start",
|
|
9680
|
-
"info",
|
|
9681
|
-
"system",
|
|
9682
|
-
{ trigger: { type: triggerType, prompt_preview: promptPreview } },
|
|
9683
|
-
runtimeEvent
|
|
9684
|
-
)
|
|
9685
|
-
);
|
|
9686
|
-
return results;
|
|
9776
|
+
taskState.restore(bootstrap.feedEvents);
|
|
9687
9777
|
}
|
|
9778
|
+
const ensureRunArray = runLifecycle.beginRun;
|
|
9779
|
+
const closeRunIntoEvent = runLifecycle.closeRunIntoEvent;
|
|
9688
9780
|
function resolveToolActor() {
|
|
9689
|
-
return subagents.
|
|
9781
|
+
return subagents.currentActor();
|
|
9690
9782
|
}
|
|
9691
9783
|
const toolProjection = createToolProjection({
|
|
9692
9784
|
ensureRunArray,
|
|
9693
9785
|
makeEvent,
|
|
9694
9786
|
runLifecycle,
|
|
9695
9787
|
toolCorrelation,
|
|
9696
|
-
|
|
9697
|
-
taskLifecycle,
|
|
9788
|
+
taskState,
|
|
9698
9789
|
subagents,
|
|
9699
9790
|
resolveToolActor
|
|
9700
9791
|
});
|
|
@@ -9712,8 +9803,6 @@ function createFeedMapper(bootstrap) {
|
|
|
9712
9803
|
const subagentProjection = createSubagentProjection({
|
|
9713
9804
|
ensureRunArray,
|
|
9714
9805
|
makeEvent,
|
|
9715
|
-
runLifecycle,
|
|
9716
|
-
actors,
|
|
9717
9806
|
subagents
|
|
9718
9807
|
});
|
|
9719
9808
|
const fileConfigProjection = createFileConfigProjection({
|
|
@@ -9723,7 +9812,7 @@ function createFeedMapper(bootstrap) {
|
|
|
9723
9812
|
const statusProjection = createStatusProjection({
|
|
9724
9813
|
ensureRunArray,
|
|
9725
9814
|
makeEvent,
|
|
9726
|
-
|
|
9815
|
+
taskState
|
|
9727
9816
|
});
|
|
9728
9817
|
const currentScope = () => subagents.currentScope();
|
|
9729
9818
|
const runSessionProjection = createRunSessionProjection({
|
|
@@ -9732,7 +9821,7 @@ function createFeedMapper(bootstrap) {
|
|
|
9732
9821
|
closeRunIntoEvent,
|
|
9733
9822
|
runLifecycle,
|
|
9734
9823
|
agentMessageStream,
|
|
9735
|
-
|
|
9824
|
+
taskState,
|
|
9736
9825
|
resolveToolActor,
|
|
9737
9826
|
currentScope
|
|
9738
9827
|
});
|
|
@@ -9740,33 +9829,13 @@ function createFeedMapper(bootstrap) {
|
|
|
9740
9829
|
const d = event.data;
|
|
9741
9830
|
const eventKind2 = event.kind;
|
|
9742
9831
|
const results = [];
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
actorId,
|
|
9751
|
-
scope,
|
|
9752
|
-
message: msg,
|
|
9753
|
-
source: "hook",
|
|
9754
|
-
cause: parentEvt ? { parent_event_id: parentEvt.event_id } : void 0
|
|
9755
|
-
});
|
|
9756
|
-
if (ev) results.push(ev);
|
|
9757
|
-
}
|
|
9758
|
-
const transcriptPath = event.context.transcriptPath;
|
|
9759
|
-
const isStopEvent = eventKind2 === "stop.request" || eventKind2 === "subagent.stop";
|
|
9760
|
-
if (transcriptPath && !isStopEvent) {
|
|
9761
|
-
results.push(
|
|
9762
|
-
...agentMessageStream.emitTranscriptMessages(
|
|
9763
|
-
transcriptPath,
|
|
9764
|
-
event,
|
|
9765
|
-
resolveToolActor(),
|
|
9766
|
-
currentScope()
|
|
9767
|
-
)
|
|
9768
|
-
);
|
|
9769
|
-
}
|
|
9832
|
+
results.push(
|
|
9833
|
+
...agentMessageStream.replayBeforeEvent(
|
|
9834
|
+
event,
|
|
9835
|
+
resolveToolActor(),
|
|
9836
|
+
currentScope()
|
|
9837
|
+
)
|
|
9838
|
+
);
|
|
9770
9839
|
if (RUN_SESSION_EVENT_KINDS.has(eventKind2)) {
|
|
9771
9840
|
results.push(...runSessionProjection.mapRunSessionEvent(event, d));
|
|
9772
9841
|
} else if (TOOL_EVENT_KINDS.has(eventKind2)) {
|
|
@@ -9801,13 +9870,25 @@ function createFeedMapper(bootstrap) {
|
|
|
9801
9870
|
results.push(unknownEvt);
|
|
9802
9871
|
}
|
|
9803
9872
|
if (eventKind2 === "stop.request") {
|
|
9804
|
-
|
|
9805
|
-
|
|
9873
|
+
results.push(
|
|
9874
|
+
...agentMessageStream.emitStopFallback(event, {
|
|
9875
|
+
actorId: "agent:root",
|
|
9876
|
+
scope: "root",
|
|
9877
|
+
parentKind: "stop.request",
|
|
9878
|
+
priorResults: results
|
|
9879
|
+
})
|
|
9880
|
+
);
|
|
9806
9881
|
}
|
|
9807
9882
|
if (eventKind2 === "subagent.stop") {
|
|
9808
9883
|
const agentId = readString(d["agent_id"]) ?? "unknown";
|
|
9809
|
-
|
|
9810
|
-
|
|
9884
|
+
results.push(
|
|
9885
|
+
...agentMessageStream.emitStopFallback(event, {
|
|
9886
|
+
actorId: subagents.actorIdFor(agentId),
|
|
9887
|
+
scope: "subagent",
|
|
9888
|
+
parentKind: "subagent.stop",
|
|
9889
|
+
priorResults: results
|
|
9890
|
+
})
|
|
9891
|
+
);
|
|
9811
9892
|
}
|
|
9812
9893
|
return results;
|
|
9813
9894
|
}
|
|
@@ -9820,7 +9901,7 @@ function createFeedMapper(bootstrap) {
|
|
|
9820
9901
|
getSession: () => runLifecycle.getSession(),
|
|
9821
9902
|
getCurrentRun: () => runLifecycle.getCurrentRun(),
|
|
9822
9903
|
getActors: () => actors.all(),
|
|
9823
|
-
getTasks: () =>
|
|
9904
|
+
getTasks: () => taskState.current(),
|
|
9824
9905
|
allocateSeq: () => runLifecycle.allocateSeq()
|
|
9825
9906
|
};
|
|
9826
9907
|
}
|
|
@@ -12422,8 +12503,32 @@ var VERBOSE_ONLY_KINDS = /* @__PURE__ */ new Set([
|
|
|
12422
12503
|
"worktree.remove",
|
|
12423
12504
|
"turn.diff",
|
|
12424
12505
|
"usage.update",
|
|
12425
|
-
"reasoning.summary"
|
|
12506
|
+
"reasoning.summary",
|
|
12507
|
+
// Codex protocol bookkeeping that churns the feed without conveying
|
|
12508
|
+
// meaningful agent progress. `usage.update` (above) still feeds header
|
|
12509
|
+
// token/context metrics via the raw event stream — only the rendered row
|
|
12510
|
+
// is suppressed in the default (non-verbose) feed.
|
|
12511
|
+
"thread.status",
|
|
12512
|
+
"server.request.resolved"
|
|
12513
|
+
]);
|
|
12514
|
+
var VERBOSE_ONLY_NOTIFICATION_TYPES = /* @__PURE__ */ new Set([
|
|
12515
|
+
"account.rate_limits_updated",
|
|
12516
|
+
"account.updated",
|
|
12517
|
+
"item.agentMessage.started",
|
|
12518
|
+
"raw_response_item.completed",
|
|
12519
|
+
"command_exec.output_delta",
|
|
12520
|
+
"fuzzy_file_search.updated",
|
|
12521
|
+
"fuzzy_file_search.completed",
|
|
12522
|
+
"app.list_updated",
|
|
12523
|
+
"thread_name",
|
|
12524
|
+
"thread.archived",
|
|
12525
|
+
"thread.unarchived",
|
|
12526
|
+
"thread.realtime.transcript_delta",
|
|
12527
|
+
"thread.realtime.output_audio_delta"
|
|
12426
12528
|
]);
|
|
12529
|
+
function isVerboseOnlyNotification(event) {
|
|
12530
|
+
return event.kind === "notification" && typeof event.data.notification_type === "string" && VERBOSE_ONLY_NOTIFICATION_TYPES.has(event.data.notification_type);
|
|
12531
|
+
}
|
|
12427
12532
|
function toRunStatus(event) {
|
|
12428
12533
|
switch (event.data.status) {
|
|
12429
12534
|
case "completed":
|
|
@@ -13212,6 +13317,9 @@ function shouldSkipEvent(event, verbose) {
|
|
|
13212
13317
|
if (!verbose && event.kind === "stop.request" && !event.data.stop_hook_active) {
|
|
13213
13318
|
return true;
|
|
13214
13319
|
}
|
|
13320
|
+
if (!verbose && isVerboseOnlyNotification(event)) {
|
|
13321
|
+
return true;
|
|
13322
|
+
}
|
|
13215
13323
|
return false;
|
|
13216
13324
|
}
|
|
13217
13325
|
function mergedToolUseId(event, postByToolUseId) {
|
|
@@ -13871,7 +13979,7 @@ async function connect(opts) {
|
|
|
13871
13979
|
const entry = pending.get(requestId);
|
|
13872
13980
|
if (!entry) return;
|
|
13873
13981
|
pending.delete(requestId);
|
|
13874
|
-
clearTimeout(entry.timer);
|
|
13982
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
13875
13983
|
entry.resolve(parsed);
|
|
13876
13984
|
return;
|
|
13877
13985
|
}
|
|
@@ -13895,7 +14003,7 @@ async function connect(opts) {
|
|
|
13895
14003
|
)
|
|
13896
14004
|
);
|
|
13897
14005
|
for (const [, p] of pending) {
|
|
13898
|
-
clearTimeout(p.timer);
|
|
14006
|
+
if (p.timer) clearTimeout(p.timer);
|
|
13899
14007
|
p.reject(
|
|
13900
14008
|
new GatewayProtocolError("connection closed", "connection_closed")
|
|
13901
14009
|
);
|
|
@@ -13955,14 +14063,14 @@ async function connect(opts) {
|
|
|
13955
14063
|
kind,
|
|
13956
14064
|
payload
|
|
13957
14065
|
};
|
|
13958
|
-
const effectiveTimeoutMs = reqOpts?.timeoutMs
|
|
14066
|
+
const effectiveTimeoutMs = reqOpts?.timeoutMs === void 0 ? timeoutMs : reqOpts.timeoutMs;
|
|
13959
14067
|
const responsePromise = new Promise(
|
|
13960
14068
|
(resolve, reject) => {
|
|
13961
|
-
const timer = setTimeout(() => {
|
|
14069
|
+
const timer = effectiveTimeoutMs === null ? void 0 : setTimeout(() => {
|
|
13962
14070
|
pending.delete(requestId);
|
|
13963
14071
|
reject(new GatewayProtocolError(`request ${kind} timed out`));
|
|
13964
14072
|
}, effectiveTimeoutMs);
|
|
13965
|
-
pending.set(requestId, { resolve, reject, timer });
|
|
14073
|
+
pending.set(requestId, { resolve, reject, ...timer ? { timer } : {} });
|
|
13966
14074
|
}
|
|
13967
14075
|
);
|
|
13968
14076
|
connection.send(envelope);
|
|
@@ -14218,7 +14326,6 @@ function writeGatewayClientConfig(config, env = process.env) {
|
|
|
14218
14326
|
}
|
|
14219
14327
|
|
|
14220
14328
|
// src/app/channels/sessionBridge.ts
|
|
14221
|
-
var RELAY_REQUEST_TIMEOUT_MS = 6 * 6e4;
|
|
14222
14329
|
var RECONNECT_BACKOFF_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
|
|
14223
14330
|
var SessionBridge = class {
|
|
14224
14331
|
opts;
|
|
@@ -14370,9 +14477,9 @@ var SessionBridge = class {
|
|
|
14370
14477
|
toolName: req.toolName,
|
|
14371
14478
|
description: req.description,
|
|
14372
14479
|
inputPreview: req.inputPreview,
|
|
14373
|
-
|
|
14480
|
+
ttlMs: req.ttlMs ?? null
|
|
14374
14481
|
};
|
|
14375
|
-
const overallTimeoutMs = req.ttlMs
|
|
14482
|
+
const overallTimeoutMs = req.ttlMs ?? null;
|
|
14376
14483
|
return this.requestWithReconnect("relay.permission.request", payload, overallTimeoutMs);
|
|
14377
14484
|
}
|
|
14378
14485
|
async relayQuestion(req) {
|
|
@@ -14381,9 +14488,9 @@ var SessionBridge = class {
|
|
|
14381
14488
|
channelRequestId,
|
|
14382
14489
|
title: req.title,
|
|
14383
14490
|
questions: req.questions,
|
|
14384
|
-
|
|
14491
|
+
ttlMs: req.ttlMs ?? null
|
|
14385
14492
|
};
|
|
14386
|
-
const overallTimeoutMs = req.ttlMs
|
|
14493
|
+
const overallTimeoutMs = req.ttlMs ?? null;
|
|
14387
14494
|
return this.requestWithReconnect("relay.question.request", payload, overallTimeoutMs);
|
|
14388
14495
|
}
|
|
14389
14496
|
/**
|
|
@@ -14391,8 +14498,9 @@ var SessionBridge = class {
|
|
|
14391
14498
|
* survives a transient WS disconnect: on `connection closed`, wait for
|
|
14392
14499
|
* the bridge's reconnect to settle, then re-issue the same payload. The
|
|
14393
14500
|
* server attaches the replay to the existing pending entry by
|
|
14394
|
-
* `channelRequestId`, so adapters are not re-prompted.
|
|
14395
|
-
*
|
|
14501
|
+
* `channelRequestId`, so adapters are not re-prompted. If the caller
|
|
14502
|
+
* provided an explicit TTL, reconnect retries are bounded by that deadline;
|
|
14503
|
+
* otherwise human-in-the-loop relays wait until answered or cancelled.
|
|
14396
14504
|
*/
|
|
14397
14505
|
async requestWithReconnect(kind, payload, overallTimeoutMs) {
|
|
14398
14506
|
const deadline = overallTimeoutMs === null ? null : Date.now() + overallTimeoutMs;
|
|
@@ -14404,9 +14512,7 @@ var SessionBridge = class {
|
|
|
14404
14512
|
}
|
|
14405
14513
|
try {
|
|
14406
14514
|
return await client.request(kind, payload, {
|
|
14407
|
-
|
|
14408
|
-
// inner request never self-cancels in any human time scale.
|
|
14409
|
-
timeoutMs: remaining ?? 2147483647
|
|
14515
|
+
timeoutMs: remaining
|
|
14410
14516
|
});
|
|
14411
14517
|
} catch (err) {
|
|
14412
14518
|
if (err instanceof GatewayProtocolError && err.code === "connection_closed" && !this.stopped && (deadline === null || Date.now() < deadline)) {
|
|
@@ -15030,7 +15136,8 @@ async function runExec(options) {
|
|
|
15030
15136
|
const runtimeFactory = options.runtimeFactory ?? createRuntime;
|
|
15031
15137
|
const sessionStoreFactory = options.sessionStoreFactory ?? createSessionStore;
|
|
15032
15138
|
const athenaSessionId = options.athenaSessionId ?? crypto2.randomUUID();
|
|
15033
|
-
const
|
|
15139
|
+
const ownedFeedPublisher = options.dashboardFeedPublisher ? null : createPairedFeedPublisher();
|
|
15140
|
+
const dashboardFeedPublisher = options.dashboardFeedPublisher ?? ownedFeedPublisher;
|
|
15034
15141
|
const dashboardOrigin = options.dashboardOrigin ?? "local";
|
|
15035
15142
|
const output = createExecOutputWriter({
|
|
15036
15143
|
json,
|
|
@@ -15399,6 +15506,7 @@ async function runExec(options) {
|
|
|
15399
15506
|
}
|
|
15400
15507
|
await bridge?.stop();
|
|
15401
15508
|
store.close();
|
|
15509
|
+
ownedFeedPublisher?.close();
|
|
15402
15510
|
}
|
|
15403
15511
|
const resolvedFinalMessage = resolveFinalMessage({
|
|
15404
15512
|
streamMessage: streamFinalMessage,
|
|
@@ -16406,8 +16514,26 @@ function parseRemoteRunSpec(value) {
|
|
|
16406
16514
|
callbackToken: typeof callbackToken === "string" && callbackToken.length > 0 ? callbackToken : void 0
|
|
16407
16515
|
};
|
|
16408
16516
|
}
|
|
16409
|
-
function
|
|
16410
|
-
|
|
16517
|
+
function validateDashboardAssignment(frame) {
|
|
16518
|
+
const spec = parseRemoteRunSpec(frame.runSpec);
|
|
16519
|
+
if (!spec) {
|
|
16520
|
+
return {
|
|
16521
|
+
kind: "rejected",
|
|
16522
|
+
rejection: {
|
|
16523
|
+
reason: "malformed_assignment",
|
|
16524
|
+
message: "remote assignment missing prompt"
|
|
16525
|
+
}
|
|
16526
|
+
};
|
|
16527
|
+
}
|
|
16528
|
+
return {
|
|
16529
|
+
kind: "valid",
|
|
16530
|
+
assignment: {
|
|
16531
|
+
runId: frame.runId,
|
|
16532
|
+
runnerId: frame.runnerId ?? "legacy",
|
|
16533
|
+
spec,
|
|
16534
|
+
frame
|
|
16535
|
+
}
|
|
16536
|
+
};
|
|
16411
16537
|
}
|
|
16412
16538
|
function workflowNameFromRef(ref) {
|
|
16413
16539
|
if (!ref) return void 0;
|
|
@@ -16488,7 +16614,7 @@ function mergeRunSpecEnvIntoWorkflow(workflow, env) {
|
|
|
16488
16614
|
};
|
|
16489
16615
|
}
|
|
16490
16616
|
async function executeRemoteAssignment({
|
|
16491
|
-
|
|
16617
|
+
assignment,
|
|
16492
16618
|
client,
|
|
16493
16619
|
projectDir,
|
|
16494
16620
|
log = () => {
|
|
@@ -16511,11 +16637,11 @@ async function executeRemoteAssignment({
|
|
|
16511
16637
|
const deferredFailedCompletion = {
|
|
16512
16638
|
current: null
|
|
16513
16639
|
};
|
|
16514
|
-
const spec =
|
|
16640
|
+
const { spec, runId, frame } = assignment;
|
|
16515
16641
|
const runEventPublisher = await createRemoteRunEventPublisher({
|
|
16516
|
-
runId
|
|
16517
|
-
callbackWsUrl: spec
|
|
16518
|
-
callbackToken: spec
|
|
16642
|
+
runId,
|
|
16643
|
+
callbackWsUrl: spec.callbackWsUrl,
|
|
16644
|
+
callbackToken: spec.callbackToken,
|
|
16519
16645
|
client,
|
|
16520
16646
|
log,
|
|
16521
16647
|
now,
|
|
@@ -16530,10 +16656,6 @@ async function executeRemoteAssignment({
|
|
|
16530
16656
|
};
|
|
16531
16657
|
send("progress", { message: "assignment received" });
|
|
16532
16658
|
try {
|
|
16533
|
-
if (!spec) {
|
|
16534
|
-
send("error", { message: "remote assignment missing prompt" });
|
|
16535
|
-
return;
|
|
16536
|
-
}
|
|
16537
16659
|
let artifactUploadSpec;
|
|
16538
16660
|
try {
|
|
16539
16661
|
artifactUploadSpec = parseArtifactUploadSpec(frame.runSpec);
|
|
@@ -16614,7 +16736,7 @@ async function executeRemoteAssignment({
|
|
|
16614
16736
|
prompt: spec.prompt,
|
|
16615
16737
|
projectDir,
|
|
16616
16738
|
harness: runtimeConfig.harness,
|
|
16617
|
-
athenaSessionId: spec.athenaSessionId ?? spec.sessionId ?? `athena-${
|
|
16739
|
+
athenaSessionId: spec.athenaSessionId ?? spec.sessionId ?? `athena-${runId}`,
|
|
16618
16740
|
adapterResumeSessionId: spec.adapterResumeSessionId,
|
|
16619
16741
|
isolationConfig: runtimeConfig.isolationConfig,
|
|
16620
16742
|
pluginMcpConfig: runtimeConfig.pluginMcpConfig,
|
|
@@ -16631,8 +16753,8 @@ async function executeRemoteAssignment({
|
|
|
16631
16753
|
...decisionInbox ? { dashboardDecisionInbox: decisionInbox } : {},
|
|
16632
16754
|
...dashboardFeedPublisher ? { dashboardFeedPublisher } : {},
|
|
16633
16755
|
...artifactUploadSpec ? {
|
|
16634
|
-
beforeTerminalCompletion: async ({ result: result2, runId }) => {
|
|
16635
|
-
const artifactRunId =
|
|
16756
|
+
beforeTerminalCompletion: async ({ result: result2, runId: runId2 }) => {
|
|
16757
|
+
const artifactRunId = runId2 ?? assignment.runId;
|
|
16636
16758
|
const { feedEvent } = await captureAndUploadArtifacts({
|
|
16637
16759
|
spec: artifactUploadSpec,
|
|
16638
16760
|
projectDir,
|
|
@@ -17042,54 +17164,55 @@ function createDashboardPairedExecution(options) {
|
|
|
17042
17164
|
});
|
|
17043
17165
|
log("warn", `run ${runId} rejected: ${rejection.message}`);
|
|
17044
17166
|
}
|
|
17045
|
-
function
|
|
17167
|
+
function submitDashboardDecision(submission) {
|
|
17046
17168
|
decisionInbox.enqueue({
|
|
17047
|
-
athenaSessionId:
|
|
17048
|
-
requestId:
|
|
17049
|
-
decision:
|
|
17169
|
+
athenaSessionId: submission.athenaSessionId,
|
|
17170
|
+
requestId: submission.requestId,
|
|
17171
|
+
decision: submission.decision,
|
|
17050
17172
|
receivedAt: now()
|
|
17051
17173
|
});
|
|
17052
17174
|
client.sendDecisionAck({
|
|
17053
|
-
athenaSessionId:
|
|
17054
|
-
requestId:
|
|
17175
|
+
athenaSessionId: submission.athenaSessionId,
|
|
17176
|
+
requestId: submission.requestId
|
|
17055
17177
|
});
|
|
17056
17178
|
}
|
|
17057
|
-
function
|
|
17058
|
-
const entry = active.get(
|
|
17059
|
-
if (!entry) return;
|
|
17179
|
+
function cancelRun(runId) {
|
|
17180
|
+
const entry = active.get(runId);
|
|
17181
|
+
if (!entry) return false;
|
|
17060
17182
|
entry.record.status = "cancelled";
|
|
17061
17183
|
entry.controller.abort();
|
|
17184
|
+
return true;
|
|
17062
17185
|
}
|
|
17063
|
-
function handleAssignment(
|
|
17064
|
-
|
|
17186
|
+
function handleAssignment(assignment, input = {}) {
|
|
17187
|
+
const { runId, runnerId } = assignment;
|
|
17188
|
+
if (active.has(runId)) {
|
|
17065
17189
|
const rejection = {
|
|
17066
17190
|
reason: "duplicate",
|
|
17067
|
-
message: `duplicate active assignment ${
|
|
17191
|
+
message: `duplicate active assignment ${runId}`
|
|
17068
17192
|
};
|
|
17069
|
-
rejectAssignment(
|
|
17193
|
+
rejectAssignment(runId, rejection);
|
|
17070
17194
|
return { kind: "rejected", rejection };
|
|
17071
17195
|
}
|
|
17072
|
-
const
|
|
17073
|
-
const bucket = activeByRunner.get(runnerKey) ?? /* @__PURE__ */ new Set();
|
|
17196
|
+
const bucket = activeByRunner.get(runnerId) ?? /* @__PURE__ */ new Set();
|
|
17074
17197
|
if (bucket.size >= maxConcurrentRuns) {
|
|
17075
17198
|
const rejection = {
|
|
17076
17199
|
reason: "local_capacity",
|
|
17077
|
-
message: `runtime daemon at concurrency cap (${maxConcurrentRuns}) for runner ${
|
|
17200
|
+
message: `runtime daemon at concurrency cap (${maxConcurrentRuns}) for runner ${runnerId}`
|
|
17078
17201
|
};
|
|
17079
|
-
rejectAssignment(
|
|
17202
|
+
rejectAssignment(runId, rejection);
|
|
17080
17203
|
return { kind: "rejected", rejection };
|
|
17081
17204
|
}
|
|
17082
17205
|
const controller = new AbortController();
|
|
17083
17206
|
const record = {
|
|
17084
|
-
runId
|
|
17207
|
+
runId,
|
|
17085
17208
|
startedAt: now(),
|
|
17086
17209
|
status: "running"
|
|
17087
17210
|
};
|
|
17088
17211
|
recordRun(record);
|
|
17089
|
-
bucket.add(
|
|
17090
|
-
activeByRunner.set(
|
|
17212
|
+
bucket.add(runId);
|
|
17213
|
+
activeByRunner.set(runnerId, bucket);
|
|
17091
17214
|
const promise = executor({
|
|
17092
|
-
|
|
17215
|
+
assignment,
|
|
17093
17216
|
client,
|
|
17094
17217
|
projectDir: input.projectDir ?? projectDir,
|
|
17095
17218
|
log,
|
|
@@ -17105,40 +17228,33 @@ function createDashboardPairedExecution(options) {
|
|
|
17105
17228
|
record.error = err instanceof Error ? err.message : String(err);
|
|
17106
17229
|
log(
|
|
17107
17230
|
"error",
|
|
17108
|
-
`run ${
|
|
17231
|
+
`run ${runId} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
17109
17232
|
);
|
|
17110
17233
|
}).finally(() => {
|
|
17111
17234
|
record.endedAt = now();
|
|
17112
17235
|
completedRuns += 1;
|
|
17113
|
-
active.delete(
|
|
17114
|
-
const remaining = activeByRunner.get(
|
|
17236
|
+
active.delete(runId);
|
|
17237
|
+
const remaining = activeByRunner.get(runnerId);
|
|
17115
17238
|
if (remaining) {
|
|
17116
|
-
remaining.delete(
|
|
17117
|
-
if (remaining.size === 0) activeByRunner.delete(
|
|
17239
|
+
remaining.delete(runId);
|
|
17240
|
+
if (remaining.size === 0) activeByRunner.delete(runnerId);
|
|
17118
17241
|
}
|
|
17119
17242
|
});
|
|
17120
|
-
active.set(
|
|
17243
|
+
active.set(runId, { controller, promise, record, runnerKey: runnerId });
|
|
17121
17244
|
return { kind: "accepted" };
|
|
17122
17245
|
}
|
|
17123
17246
|
return {
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
}
|
|
17133
|
-
if (frame.type === "job_assignment") {
|
|
17134
|
-
handleAssignment(frame);
|
|
17135
|
-
return true;
|
|
17136
|
-
}
|
|
17137
|
-
return false;
|
|
17138
|
-
},
|
|
17139
|
-
admitAssignment(frame, input) {
|
|
17140
|
-
return handleAssignment(frame, input);
|
|
17247
|
+
// `job_assignment` is intentionally not handled here: the runtime daemon
|
|
17248
|
+
// routes assignments through `DashboardAssignmentIntake`, which gates
|
|
17249
|
+
// admission on attachment readiness and then calls `admitAssignment`
|
|
17250
|
+
// directly. Run-control frames (`dashboard_decision`, `cancel`) are
|
|
17251
|
+
// translated by `routeDashboardRunFrame` into `submitDashboardDecision`
|
|
17252
|
+
// and `cancelRun` calls.
|
|
17253
|
+
admitAssignment(assignment, input) {
|
|
17254
|
+
return handleAssignment(assignment, input);
|
|
17141
17255
|
},
|
|
17256
|
+
cancelRun,
|
|
17257
|
+
submitDashboardDecision,
|
|
17142
17258
|
rejectAssignment,
|
|
17143
17259
|
snapshot() {
|
|
17144
17260
|
return {
|
|
@@ -17169,22 +17285,12 @@ function createDashboardPairedExecution(options) {
|
|
|
17169
17285
|
import fs23 from "fs";
|
|
17170
17286
|
import os13 from "os";
|
|
17171
17287
|
import path21 from "path";
|
|
17172
|
-
function resolveRemoteWorkspace(
|
|
17173
|
-
const spec =
|
|
17174
|
-
if (!spec) {
|
|
17175
|
-
return {
|
|
17176
|
-
kind: "rejected",
|
|
17177
|
-
rejection: {
|
|
17178
|
-
reason: "workspace_unresolved",
|
|
17179
|
-
message: "remote assignment missing prompt"
|
|
17180
|
-
}
|
|
17181
|
-
};
|
|
17182
|
-
}
|
|
17288
|
+
function resolveRemoteWorkspace(assignment, options = {}) {
|
|
17289
|
+
const { spec, runId, runnerId } = assignment;
|
|
17183
17290
|
if (spec.projectDir) {
|
|
17184
17291
|
return validateProjectDir(spec.projectDir, options.env);
|
|
17185
17292
|
}
|
|
17186
17293
|
const sessionId = spec.athenaSessionId ?? spec.sessionId;
|
|
17187
|
-
const runnerId = frame.runnerId ?? "legacy";
|
|
17188
17294
|
const deploymentSlug = deploymentSlugFromUrl(options.dashboardUrl);
|
|
17189
17295
|
const stateDir = daemonStatePaths(options.env).dir;
|
|
17190
17296
|
const projectDir = sessionId ? path21.join(
|
|
@@ -17200,7 +17306,7 @@ function resolveRemoteWorkspace(frame, options = {}) {
|
|
|
17200
17306
|
deploymentSlug,
|
|
17201
17307
|
sanitizePathSegment(runnerId),
|
|
17202
17308
|
"runs",
|
|
17203
|
-
sanitizePathSegment(
|
|
17309
|
+
sanitizePathSegment(runId)
|
|
17204
17310
|
);
|
|
17205
17311
|
try {
|
|
17206
17312
|
fs23.mkdirSync(projectDir, { recursive: true, mode: 448 });
|
|
@@ -17283,23 +17389,21 @@ function sanitizePathSegment(value) {
|
|
|
17283
17389
|
function createDashboardAssignmentIntake(options) {
|
|
17284
17390
|
const log = options.log ?? (() => {
|
|
17285
17391
|
});
|
|
17286
|
-
const resolveWorkspace = options.resolveWorkspace ?? ((
|
|
17392
|
+
const resolveWorkspace = options.resolveWorkspace ?? ((assignment, context2) => resolveRemoteWorkspace(assignment, { dashboardUrl: context2.dashboardUrl }));
|
|
17287
17393
|
const pending = [];
|
|
17288
|
-
let
|
|
17289
|
-
function handle(frame) {
|
|
17290
|
-
|
|
17291
|
-
|
|
17292
|
-
|
|
17293
|
-
message: "remote assignment missing prompt"
|
|
17294
|
-
};
|
|
17295
|
-
options.execution.rejectAssignment(frame.runId, rejection);
|
|
17394
|
+
let context = null;
|
|
17395
|
+
function handle(frame, readyContext) {
|
|
17396
|
+
const validation = validateDashboardAssignment(frame);
|
|
17397
|
+
if (validation.kind === "rejected") {
|
|
17398
|
+
options.execution.rejectAssignment(frame.runId, validation.rejection);
|
|
17296
17399
|
options.client.sendAssignmentRejected({
|
|
17297
17400
|
runId: frame.runId,
|
|
17298
|
-
...rejection
|
|
17401
|
+
...validation.rejection
|
|
17299
17402
|
});
|
|
17300
17403
|
return;
|
|
17301
17404
|
}
|
|
17302
|
-
const
|
|
17405
|
+
const assignment = validation.assignment;
|
|
17406
|
+
const workspace = resolveWorkspace(assignment, readyContext);
|
|
17303
17407
|
if (workspace.kind === "rejected") {
|
|
17304
17408
|
options.execution.rejectAssignment(frame.runId, workspace.rejection);
|
|
17305
17409
|
options.client.sendAssignmentRejected({
|
|
@@ -17308,7 +17412,7 @@ function createDashboardAssignmentIntake(options) {
|
|
|
17308
17412
|
});
|
|
17309
17413
|
return;
|
|
17310
17414
|
}
|
|
17311
|
-
const outcome = options.execution.admitAssignment(
|
|
17415
|
+
const outcome = options.execution.admitAssignment(assignment, {
|
|
17312
17416
|
projectDir: workspace.projectDir
|
|
17313
17417
|
});
|
|
17314
17418
|
if (outcome.kind === "accepted") {
|
|
@@ -17321,15 +17425,15 @@ function createDashboardAssignmentIntake(options) {
|
|
|
17321
17425
|
});
|
|
17322
17426
|
}
|
|
17323
17427
|
function drain() {
|
|
17324
|
-
if (!
|
|
17428
|
+
if (!context) return;
|
|
17325
17429
|
while (pending.length > 0) {
|
|
17326
17430
|
const frame = pending.shift();
|
|
17327
|
-
if (frame) handle(frame);
|
|
17431
|
+
if (frame) handle(frame, context);
|
|
17328
17432
|
}
|
|
17329
17433
|
}
|
|
17330
17434
|
return {
|
|
17331
17435
|
receive(frame) {
|
|
17332
|
-
if (!
|
|
17436
|
+
if (!context) {
|
|
17333
17437
|
pending.push(frame);
|
|
17334
17438
|
log(
|
|
17335
17439
|
"debug",
|
|
@@ -17337,18 +17441,35 @@ function createDashboardAssignmentIntake(options) {
|
|
|
17337
17441
|
);
|
|
17338
17442
|
return;
|
|
17339
17443
|
}
|
|
17340
|
-
handle(frame);
|
|
17444
|
+
handle(frame, context);
|
|
17341
17445
|
},
|
|
17342
|
-
markReady() {
|
|
17343
|
-
|
|
17446
|
+
markReady(nextContext) {
|
|
17447
|
+
context = nextContext;
|
|
17344
17448
|
drain();
|
|
17345
17449
|
},
|
|
17346
17450
|
markNotReady() {
|
|
17347
|
-
|
|
17451
|
+
context = null;
|
|
17348
17452
|
}
|
|
17349
17453
|
};
|
|
17350
17454
|
}
|
|
17351
17455
|
|
|
17456
|
+
// src/app/dashboard/dashboardFrameRouter.ts
|
|
17457
|
+
function routeDashboardRunFrame(execution, frame) {
|
|
17458
|
+
if (frame.type === "dashboard_decision") {
|
|
17459
|
+
execution.submitDashboardDecision({
|
|
17460
|
+
athenaSessionId: frame.athenaSessionId,
|
|
17461
|
+
requestId: frame.requestId,
|
|
17462
|
+
decision: frame.decision
|
|
17463
|
+
});
|
|
17464
|
+
return true;
|
|
17465
|
+
}
|
|
17466
|
+
if (frame.type === "cancel") {
|
|
17467
|
+
execution.cancelRun(frame.runId);
|
|
17468
|
+
return true;
|
|
17469
|
+
}
|
|
17470
|
+
return false;
|
|
17471
|
+
}
|
|
17472
|
+
|
|
17352
17473
|
// src/app/dashboard/runtimeDaemon.ts
|
|
17353
17474
|
var DEFAULT_RECONNECT_DELAYS_MS2 = [1e3, 2e3, 5e3, 1e4, 3e4];
|
|
17354
17475
|
var DEFAULT_MAX_CONCURRENT_RUNS2 = 1;
|
|
@@ -17452,7 +17573,7 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
17452
17573
|
},
|
|
17453
17574
|
execution: pairedExecution,
|
|
17454
17575
|
log,
|
|
17455
|
-
resolveWorkspace: (
|
|
17576
|
+
resolveWorkspace: (assignment, context) => resolveRemoteWorkspace(assignment, { dashboardUrl: context.dashboardUrl })
|
|
17456
17577
|
});
|
|
17457
17578
|
function nextReconnectDelay() {
|
|
17458
17579
|
if (reconnectDelays.length === 0) return 0;
|
|
@@ -17571,7 +17692,7 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
17571
17692
|
assignmentIntake.receive(frame);
|
|
17572
17693
|
return;
|
|
17573
17694
|
}
|
|
17574
|
-
pairedExecution
|
|
17695
|
+
routeDashboardRunFrame(pairedExecution, frame);
|
|
17575
17696
|
});
|
|
17576
17697
|
next.onClose((reason) => {
|
|
17577
17698
|
if (stopped || client !== next) return;
|
|
@@ -17594,15 +17715,19 @@ async function runDashboardRuntimeDaemon(options = {}) {
|
|
|
17594
17715
|
accessToken: token.accessToken
|
|
17595
17716
|
});
|
|
17596
17717
|
} catch (err) {
|
|
17597
|
-
client = null;
|
|
17598
|
-
assignmentIntake.markNotReady();
|
|
17599
17718
|
attachmentReconciler.markStale(token.instanceId);
|
|
17600
|
-
|
|
17601
|
-
|
|
17719
|
+
log(
|
|
17720
|
+
"warn",
|
|
17721
|
+
`runtime daemon: attachment reconciliation failed; continuing with push-only mirror: ${err instanceof Error ? err.message : String(err)}`
|
|
17722
|
+
);
|
|
17602
17723
|
}
|
|
17724
|
+
if (stopped || client !== next) return;
|
|
17603
17725
|
currentInstanceId = token.instanceId;
|
|
17604
17726
|
currentDashboardUrl = config.dashboardUrl;
|
|
17605
|
-
assignmentIntake.markReady(
|
|
17727
|
+
assignmentIntake.markReady({
|
|
17728
|
+
dashboardUrl: config.dashboardUrl,
|
|
17729
|
+
instanceId: token.instanceId
|
|
17730
|
+
});
|
|
17606
17731
|
reconnectAttempt = 0;
|
|
17607
17732
|
scheduleRefresh(token.expiresInSec);
|
|
17608
17733
|
pairedFeedPublisher.attachTransport(next);
|
|
@@ -18062,4 +18187,4 @@ export {
|
|
|
18062
18187
|
startUdsServer,
|
|
18063
18188
|
sendUdsRequest
|
|
18064
18189
|
};
|
|
18065
|
-
//# sourceMappingURL=chunk-
|
|
18190
|
+
//# sourceMappingURL=chunk-BUNMENOT.js.map
|