@tea-agent/loop-agent 0.36.4-beta.0 → 0.37.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -6
- package/CHANGELOG.md +72 -163
- package/README.md +1 -1
- package/bin/loop-agent.js +1 -37
- package/dist/application/task-lifecycle/advance.js +0 -1
- package/dist/application/task-lifecycle/observe.js +0 -15
- package/dist/application/task-lifecycle/plan-transitions.js +0 -15
- package/dist/cli/command-definitions.js +0 -7
- package/dist/cli/program.js +3 -8
- package/dist/commands/init-upgrade.js +19 -351
- package/dist/commands/init.js +67 -14
- package/dist/commands/run-dag-progress.js +0 -14
- package/dist/commands/task-advance.js +3 -33
- package/dist/executors/dag-pi-executor.js +30 -47
- package/dist/executors/pi-sdk-executor.js +0 -34
- package/dist/executors/shell-executor.js +95 -6
- package/dist/infrastructure/harness/atomic-write.js +1 -2
- package/dist/shared/operator/capabilities.js +13 -200
- package/dist/shared/package-metadata.js +0 -42
- package/dist/task/frontend-project-capability.js +12 -162
- package/dist/task/source-prepare/completeness.js +0 -17
- package/dist/task/source-prepare/parse-intent.js +1 -15
- package/dist/task/source-prepare/semantic-intake.js +23 -144
- package/dist/worker/console/chat/artifact-card.js +1 -8
- package/dist/worker/console/chat/chat-event-store.js +0 -61
- package/dist/worker/console/chat/human-gate-card.js +1 -9
- package/dist/worker/console/chat/operation-card.js +2 -71
- package/dist/worker/console/chat/pi-runtime.js +62 -86
- package/dist/worker/console/chat/routes.js +8 -36
- package/dist/worker/console/chat/session-store.js +0 -3
- package/dist/worker/console/chat/shortcuts.js +7 -9
- package/dist/worker/console/chat/turn-process.js +23 -97
- package/dist/worker/console/chat/workspace-landing.js +1 -2
- package/dist/worker/console/operation-runner.js +6 -155
- package/dist/worker/console/operator-actions.js +13 -373
- package/dist/worker/console/operator-user-error.js +0 -4
- package/dist/worker/console/recovery-cta.js +3 -50
- package/dist/worker/console/static/assets/index-HX1pbOyl.css +1 -0
- package/dist/worker/console/static/assets/index-M0BLEBfh.js +56 -0
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +9 -13
- package/dist/worker/console/static-src/app/useOperatorActions.js +2 -4
- package/dist/worker/console/static-src/app/useRecoveryActions.js +56 -65
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +1 -73
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +30 -89
- package/dist/worker/console/static-src/operator-chat/refs.js +0 -3
- package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +11 -30
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -12
- package/dist/worker/console/static-src/operator-chat/useComposer.js +8 -45
- package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -7
- package/dist/worker/loop-agent/loop-agent-client.js +3 -17
- package/dist/worker/observability/read-model.js +0 -20
- package/dist/worker/observe/spec-evidence.js +8 -3
- package/dist/worker/observe/static/operator-chrome.d.ts +0 -1
- package/dist/worker/observe/static/operator-chrome.js +1 -6
- package/dist/worker/observe/static/views/dag-inspector.js +71 -6
- package/dist/worker/observe/static/views/dag.js +0 -12
- package/dist/worker/preflight.js +1 -2
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +707 -37
- package/dist/workflows/dag/backend-test-case-manifest.js +4 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +109 -7
- package/dist/workflows/dag/backend-test-module-stem.js +5 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +345 -24
- package/dist/workflows/dag/backend-test-scenario-param.js +890 -164
- package/dist/workflows/dag/backend-test-writer-completeness.js +47 -16
- package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
- package/dist/workflows/dag/dynamic-runtime/shared.js +1 -9
- package/dist/workflows/dag/failure-routing.js +4 -9
- package/dist/workflows/dag/frontend-implementation-contract.js +39 -233
- package/dist/workflows/dag/frontend-prewrite-gate.js +62 -394
- package/dist/workflows/dag/frontend-repair.js +18 -219
- package/dist/workflows/dag/frontend-verification-trace.js +32 -47
- package/dist/workflows/dag/init-hybrid.js +86 -238
- package/dist/workflows/dag/lifecycle.js +0 -4
- package/dist/workflows/dag/node-execution.js +6 -105
- package/dist/workflows/dag/recovery-recommendation.js +0 -58
- package/dist/workflows/dag/report.js +0 -6
- package/dist/workflows/dag/retry-policy.js +0 -11
- package/dist/workflows/dag/runner.js +12 -314
- package/dist/workflows/dag/scheduler.js +3 -257
- package/dist/workflows/dag/types.js +9 -132
- package/dist/workflows/dag/validate.js +2 -7
- package/docs/README.md +3 -3
- package/docs/architecture/evolution.md +67 -102
- package/docs/templates/backend-test-dag.json +50 -32
- package/docs/templates/frontend-design-contract.md +14 -34
- package/docs/templates/frontend-task-constraints.md +13 -33
- package/docs/templates/frontend-task-requirement.md +20 -54
- package/docs/templates/init-managed-agents.md +2 -5
- package/harness.json +2 -2
- package/package.json +3 -4
- package/skills/loop-agent/SKILL.md +0 -1
- package/skills/loop-agent/references/command-reference.md +0 -3
- package/dist/build-stamp.json +0 -6
- package/dist/commands/dag-request-interrupt.js +0 -20
- package/dist/worker/console/chat/assistant-content.js +0 -121
- package/dist/worker/console/chat/semantic-activity.js +0 -471
- package/dist/worker/console/operation-run-facts.js +0 -190
- package/dist/worker/console/operation-wait.js +0 -355
- package/dist/worker/console/recovery-error-copy.js +0 -198
- package/dist/worker/console/static/assets/index-D83DYAFG.css +0 -1
- package/dist/worker/console/static/assets/index-IXm7oYjL.js +0 -59
- package/dist/worker/console/static-src/operator-chat/activity-journey.js +0 -125
- package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
- package/dist/worker/console/static-src/operator-chat/activity-references.js +0 -20
- package/dist/worker/console/static-src/operator-chat/slash-palette-layout.js +0 -24
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +0 -141
- package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
- package/dist/worker/observability/interrupt-eligibility.js +0 -264
- package/dist/workflows/dag/contract-output-registry.js +0 -14
- package/dist/workflows/dag/contract-validator-registrations.js +0 -8
- package/dist/workflows/dag/frontend-recovery-plan.js +0 -73
- package/dist/workflows/dag/frontend-recovery-root-manifest.js +0 -123
- package/dist/workflows/dag/frontend-recovery-run.js +0 -539
- package/dist/workflows/dag/frontend-writer-recovery.js +0 -106
- package/dist/workflows/dag/frontend-writer-rollback.js +0 -821
- package/dist/workflows/dag/interrupt-request.js +0 -559
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { clipPreview, } from "./operation-store.js";
|
|
2
2
|
import { stateEvent } from "./operation-sse.js";
|
|
3
|
-
import { extractTrustedRunFacts } from "./operation-run-facts.js";
|
|
4
3
|
/**
|
|
5
4
|
* Execute a queued operation via LoopAgentClient (or inject).
|
|
6
5
|
* Timeout without proven exit → needs-reconcile (never Cancel).
|
|
@@ -75,30 +74,6 @@ export async function runOperation(operationId, deps) {
|
|
|
75
74
|
message: chunk,
|
|
76
75
|
});
|
|
77
76
|
},
|
|
78
|
-
onHeartbeat: (info) => {
|
|
79
|
-
// P1 (2026-08-13): project sibling CLI heartbeats into canonical
|
|
80
|
-
// operation events so operationWait/operationEventSummary can consume
|
|
81
|
-
// them. The projection is best-effort: a failed append must never
|
|
82
|
-
// terminate the sibling CLI execution (AC-002). The injected test
|
|
83
|
-
// runCommand path has no LoopAgentClient callback guard, so the
|
|
84
|
-
// runner protects itself here.
|
|
85
|
-
try {
|
|
86
|
-
deps.events.append(operationId, {
|
|
87
|
-
at: info.at,
|
|
88
|
-
kind: "heartbeat",
|
|
89
|
-
message: `heartbeat elapsedMs=${info.elapsedMs}`,
|
|
90
|
-
data: {
|
|
91
|
-
elapsedMs: info.elapsedMs,
|
|
92
|
-
action: op.action,
|
|
93
|
-
...(op.taskId ? { taskId: op.taskId } : {}),
|
|
94
|
-
...(op.dagRunId ? { dagRunId: op.dagRunId } : {}),
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
catch {
|
|
99
|
-
// Heartbeat is derived telemetry; ignore projection failures.
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
77
|
});
|
|
103
78
|
await spawnUpdate;
|
|
104
79
|
finished = await finalizeFromWorkerResult(operationId, result, deps);
|
|
@@ -122,38 +97,6 @@ export async function runOperation(operationId, deps) {
|
|
|
122
97
|
}
|
|
123
98
|
return finished;
|
|
124
99
|
}
|
|
125
|
-
function taskAdvanceBusinessBlock(operation, envelope) {
|
|
126
|
-
if (!operation || !envelope)
|
|
127
|
-
return undefined;
|
|
128
|
-
if (operation.action !== "taskAdvance" && operation.action !== "dagRunTask") {
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
const result = envelope.result && typeof envelope.result === "object"
|
|
132
|
-
? envelope.result
|
|
133
|
-
: undefined;
|
|
134
|
-
const lifecycleState = typeof result?.lifecycleState === "string"
|
|
135
|
-
? result.lifecycleState
|
|
136
|
-
: undefined;
|
|
137
|
-
const blockers = Array.isArray(result?.blockers)
|
|
138
|
-
? result.blockers
|
|
139
|
-
: [];
|
|
140
|
-
const expectedGateStop = lifecycleState === "awaiting-write-set-approval" && blockers.length === 0;
|
|
141
|
-
if (expectedGateStop)
|
|
142
|
-
return undefined;
|
|
143
|
-
if (lifecycleState !== "intake-incomplete" &&
|
|
144
|
-
blockers.length === 0 &&
|
|
145
|
-
envelope.outcome !== "blocked") {
|
|
146
|
-
return undefined;
|
|
147
|
-
}
|
|
148
|
-
const firstBlocker = blockers[0];
|
|
149
|
-
const code = typeof firstBlocker?.code === "string"
|
|
150
|
-
? firstBlocker.code
|
|
151
|
-
: "TASK_ADVANCE_BLOCKED";
|
|
152
|
-
const message = typeof firstBlocker?.message === "string"
|
|
153
|
-
? firstBlocker.message
|
|
154
|
-
: `task advance stopped before runnable DAG completion (lifecycleState=${lifecycleState ?? "unknown"})`;
|
|
155
|
-
return { code, message };
|
|
156
|
-
}
|
|
157
100
|
async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
158
101
|
const previewStdout = clipPreview(result.stdout ?? "");
|
|
159
102
|
const previewStderr = clipPreview(result.stderr ?? "");
|
|
@@ -163,8 +106,6 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
163
106
|
resultPath: result.artifacts.resultPath,
|
|
164
107
|
dir: result.artifacts.dir,
|
|
165
108
|
};
|
|
166
|
-
// Trusted structured run facts only (AC-003): never scanned from free text.
|
|
167
|
-
const runFacts = extractTrustedRunFacts(result);
|
|
168
109
|
if (result.timedOut) {
|
|
169
110
|
// Supervisory timeout without classified CLI timeout → needs-reconcile
|
|
170
111
|
// Only mark timed-out when we have a machine timeout result after exit.
|
|
@@ -180,35 +121,12 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
180
121
|
? "CLI timed out with process exit"
|
|
181
122
|
: "timeout reached without proven process exit; needs reconcile (not cancelled)",
|
|
182
123
|
result: coerceEnvelope(result),
|
|
183
|
-
...(runFacts
|
|
184
|
-
? {
|
|
185
|
-
dagRunId: runFacts.runId,
|
|
186
|
-
...(runFacts.runSummary ? { runSummary: runFacts.runSummary } : {}),
|
|
187
|
-
}
|
|
188
|
-
: {}),
|
|
189
124
|
});
|
|
190
125
|
stateEvent(deps.events, updated, state, updated.errorMessage);
|
|
191
|
-
if (runFacts) {
|
|
192
|
-
appendSafeResultEvent(deps, operationId, state, {
|
|
193
|
-
ok: false,
|
|
194
|
-
exitCode: result.exitCode,
|
|
195
|
-
}, runFacts);
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
deps.events.append(operationId, {
|
|
199
|
-
at: new Date().toISOString(),
|
|
200
|
-
kind: "result",
|
|
201
|
-
state,
|
|
202
|
-
data: { ok: false, exitCode: result.exitCode },
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
126
|
return updated;
|
|
206
127
|
}
|
|
207
128
|
const envelope = coerceEnvelope(result);
|
|
208
|
-
const
|
|
209
|
-
const businessBlock = taskAdvanceBusinessBlock(operation, envelope);
|
|
210
|
-
const processOk = envelope?.ok === true || (result.ok && result.exitCode === 0);
|
|
211
|
-
const ok = processOk && !businessBlock;
|
|
129
|
+
const ok = envelope?.ok === true || (result.ok && result.exitCode === 0);
|
|
212
130
|
const state = ok ? "succeeded" : "failed";
|
|
213
131
|
const updated = await deps.store.update(operationId, {
|
|
214
132
|
state,
|
|
@@ -220,43 +138,21 @@ async function finalizeFromWorkerResult(operationId, result, deps) {
|
|
|
220
138
|
stdout: previewStdout,
|
|
221
139
|
stderr: previewStderr,
|
|
222
140
|
}),
|
|
223
|
-
errorCode: ok
|
|
224
|
-
? undefined
|
|
225
|
-
: (businessBlock?.code ?? envelope?.error?.code ?? "INTERNAL_ERROR"),
|
|
141
|
+
errorCode: ok ? undefined : (envelope?.error?.code ?? "INTERNAL_ERROR"),
|
|
226
142
|
errorMessage: ok
|
|
227
143
|
? undefined
|
|
228
|
-
: (
|
|
229
|
-
envelope?.error?.message ??
|
|
144
|
+
: (envelope?.error?.message ??
|
|
230
145
|
(previewStderr.trim() ||
|
|
231
146
|
`command failed with exit ${result.exitCode}`)),
|
|
232
|
-
// Atomic final patch: state/result + trusted dagRunId + safe runSummary
|
|
233
|
-
// in a single per-op write-locked update (AC-004). The runSummary is a
|
|
234
|
-
// projection and never launders the envelope/exit-decided state.
|
|
235
|
-
...(runFacts
|
|
236
|
-
? {
|
|
237
|
-
dagRunId: runFacts.runId,
|
|
238
|
-
...(runFacts.runSummary ? { runSummary: runFacts.runSummary } : {}),
|
|
239
|
-
}
|
|
240
|
-
: {}),
|
|
241
147
|
});
|
|
242
|
-
stateEvent(deps.events, updated, state
|
|
243
|
-
appendSafeResultEvent(deps, operationId, state, { ok, exitCode: result.exitCode }, runFacts);
|
|
244
|
-
if (ok && operation?.action === "dagRequestInterrupt") {
|
|
245
|
-
await projectInterruptRequestOntoTarget(operation, result.json, deps);
|
|
246
|
-
}
|
|
247
|
-
return updated;
|
|
248
|
-
}
|
|
249
|
-
/** Result event carries the same safe summary persisted on the record. */
|
|
250
|
-
function appendSafeResultEvent(deps, operationId, state, base, runFacts) {
|
|
148
|
+
stateEvent(deps.events, updated, state);
|
|
251
149
|
deps.events.append(operationId, {
|
|
252
150
|
at: new Date().toISOString(),
|
|
253
151
|
kind: "result",
|
|
254
152
|
state,
|
|
255
|
-
data: {
|
|
256
|
-
...base,
|
|
257
|
-
...(runFacts?.runSummary ? { runSummary: runFacts.runSummary } : {}),
|
|
258
|
-
},
|
|
153
|
+
data: { ok, exitCode: result.exitCode },
|
|
259
154
|
});
|
|
155
|
+
return updated;
|
|
260
156
|
}
|
|
261
157
|
function coerceEnvelope(result) {
|
|
262
158
|
const json = result.json;
|
|
@@ -306,48 +202,3 @@ export function scheduleOperation(operationId, deps) {
|
|
|
306
202
|
});
|
|
307
203
|
});
|
|
308
204
|
}
|
|
309
|
-
async function projectInterruptRequestOntoTarget(operation, json, deps) {
|
|
310
|
-
const params = operation.actionParams ?? {};
|
|
311
|
-
const targetOperationId = typeof params.targetOperationId === "string"
|
|
312
|
-
? params.targetOperationId.trim()
|
|
313
|
-
: "";
|
|
314
|
-
const runId = typeof params.runId === "string" ? params.runId.trim() : "";
|
|
315
|
-
if (!targetOperationId)
|
|
316
|
-
return;
|
|
317
|
-
const rec = json && typeof json === "object" ? json : {};
|
|
318
|
-
const request = rec.request && typeof rec.request === "object"
|
|
319
|
-
? rec.request
|
|
320
|
-
: rec;
|
|
321
|
-
const status = (typeof rec.interruptStatus === "string" && rec.interruptStatus) ||
|
|
322
|
-
(typeof request.status === "string" && request.status) ||
|
|
323
|
-
"requested";
|
|
324
|
-
if (status !== "requested" &&
|
|
325
|
-
status !== "acknowledged" &&
|
|
326
|
-
status !== "settled" &&
|
|
327
|
-
status !== "needs-reconcile") {
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
const target = await deps.store.get(targetOperationId);
|
|
331
|
-
if (!target)
|
|
332
|
-
return;
|
|
333
|
-
await deps.store.update(targetOperationId, {
|
|
334
|
-
...(runId && !target.dagRunId ? { dagRunId: runId } : {}),
|
|
335
|
-
interrupt: {
|
|
336
|
-
status,
|
|
337
|
-
...(typeof request.requestId === "string"
|
|
338
|
-
? { requestId: request.requestId }
|
|
339
|
-
: {}),
|
|
340
|
-
...(typeof request.reasonCode === "string"
|
|
341
|
-
? { reasonCode: request.reasonCode }
|
|
342
|
-
: {}),
|
|
343
|
-
...(typeof request.requestedAt === "string"
|
|
344
|
-
? { requestedAt: request.requestedAt }
|
|
345
|
-
: {}),
|
|
346
|
-
},
|
|
347
|
-
});
|
|
348
|
-
deps.events.append(targetOperationId, {
|
|
349
|
-
kind: "state",
|
|
350
|
-
message: `interrupt ${status}`,
|
|
351
|
-
data: { interruptStatus: status, ...(runId ? { runId } : {}) },
|
|
352
|
-
});
|
|
353
|
-
}
|