@tea-agent/loop-agent 0.34.2 → 0.34.4

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.
Files changed (29) hide show
  1. package/AGENTS.md +7 -2
  2. package/CHANGELOG.md +65 -22
  3. package/dist/application/task-lifecycle/advance.js +5 -1
  4. package/dist/task/source-prepare/index.js +1 -0
  5. package/dist/task/source-prepare/placeholder-paths.js +77 -0
  6. package/dist/task/source-prepare/semantic-intake.js +192 -27
  7. package/dist/worker/console/app-data.js +2 -0
  8. package/dist/worker/console/chat/chat-event-store.js +85 -3
  9. package/dist/worker/console/chat/pi-runtime.js +230 -62
  10. package/dist/worker/console/chat/resource-preferences-store.js +152 -0
  11. package/dist/worker/console/chat/routes.js +401 -18
  12. package/dist/worker/console/chat/turn-execution-registry.js +82 -0
  13. package/dist/worker/console/dag-execution-receipt.js +14 -1
  14. package/dist/worker/console/prd-intake-bridge.js +51 -10
  15. package/dist/worker/console/server.js +4 -0
  16. package/dist/worker/console/static/assets/index-B6Qdbk8V.js +29 -0
  17. package/dist/worker/console/static/assets/index-Bt0NUxcQ.css +1 -0
  18. package/dist/worker/console/static/index.html +2 -2
  19. package/dist/worker/console/static-src/operator-chat/refs.js +24 -0
  20. package/dist/worker/console/static-src/operator-chat/resource-auto-invocation.js +91 -0
  21. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +690 -0
  22. package/dist/worker/console/static-src/operator-chat/turn-submission.js +158 -0
  23. package/dist/worker/console/static-src/operator-chat/useChatStream.js +535 -86
  24. package/dist/workflows/dag/init-hybrid.js +2 -0
  25. package/docs/operations/local-development-environment.md +4 -2
  26. package/docs/templates/branch-merge-report.md +9 -0
  27. package/package.json +3 -2
  28. package/dist/worker/console/static/assets/index-BQkhJpV8.css +0 -1
  29. package/dist/worker/console/static/assets/index-BpuHmlSP.js +0 -29
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Pure Turn submission / response protocol helpers for Operator Chat.
3
+ * Extracted so double-submit, TURN_ACTIVE adoption, transport ambiguity, and
4
+ * generation fences can be unit-tested without mounting the full React tree.
5
+ */
6
+ export function createPendingSubmission(input) {
7
+ let resolveOutcome;
8
+ const outcomePromise = new Promise((resolve) => {
9
+ resolveOutcome = resolve;
10
+ });
11
+ return {
12
+ ...input,
13
+ outcomePromise,
14
+ resolveOutcome,
15
+ };
16
+ }
17
+ /** Transport / network failure while creating a Turn — never a definitive rejection. */
18
+ export function classifyCreateTurnNetworkFailure(message = "network error while creating turn") {
19
+ return { kind: "ambiguous", message };
20
+ }
21
+ /**
22
+ * After the same-clientRequestId POST retry still lacks definitive acceptance,
23
+ * stay ambiguous so the client keeps busy ownership and continues /state reconcile.
24
+ * Must never promote transport uncertainty to rejected (would forge idle).
25
+ */
26
+ export function keepAmbiguousAfterRetry(message = "无法确认 Turn 是否已创建,正在与服务端对账(不会重复提交新的请求 ID)") {
27
+ return { kind: "ambiguous", message };
28
+ }
29
+ /** Classify a POST /turns HTTP response into a submission outcome. */
30
+ export function classifyCreateTurnResponse(input) {
31
+ const { body, clientRequestId } = input;
32
+ const errorCode = body.error?.code;
33
+ const errorMessage = body.error?.message ??
34
+ (input.httpOk ? "turn was not accepted" : `HTTP ${input.status}`);
35
+ if (errorCode === "TURN_ACTIVE" && body.activeTurn?.turnId) {
36
+ return {
37
+ kind: "adopt-active",
38
+ activeTurn: body.activeTurn,
39
+ message: "上一轮仍在运行,已重新连接;当前消息已保留。",
40
+ };
41
+ }
42
+ if (body.accepted === true || (input.httpOk && body.turnId)) {
43
+ const turnId = body.turn?.turnId ?? body.turnId;
44
+ if (!turnId) {
45
+ return { kind: "ambiguous", message: errorMessage };
46
+ }
47
+ return {
48
+ kind: "accepted",
49
+ turnId,
50
+ idempotent: body.idempotent === true,
51
+ turn: body.turn ?? {
52
+ turnId,
53
+ clientRequestId,
54
+ state: body.state,
55
+ },
56
+ };
57
+ }
58
+ if (body.accepted === false || errorCode) {
59
+ return {
60
+ kind: "rejected",
61
+ code: errorCode,
62
+ message: errorMessage,
63
+ };
64
+ }
65
+ // Transport-level uncertainty: no definitive acceptance flag.
66
+ return { kind: "ambiguous", message: errorMessage };
67
+ }
68
+ /** Resolve an ambiguous POST via GET /state using clientRequestId. */
69
+ export function resolveAmbiguousFromState(input) {
70
+ const clientRequestId = input.clientRequestId;
71
+ const active = input.state?.activeTurn;
72
+ const latest = input.state?.latestTurn;
73
+ if (active?.clientRequestId === clientRequestId && active.turnId) {
74
+ return {
75
+ kind: "accepted",
76
+ turnId: active.turnId,
77
+ idempotent: true,
78
+ turn: active,
79
+ };
80
+ }
81
+ if (latest?.clientRequestId === clientRequestId && latest.turnId) {
82
+ return {
83
+ kind: "accepted",
84
+ turnId: latest.turnId,
85
+ idempotent: true,
86
+ turn: latest,
87
+ };
88
+ }
89
+ if (active?.turnId) {
90
+ return {
91
+ kind: "adopt-active",
92
+ activeTurn: active,
93
+ message: "上一轮仍在运行,已重新连接;当前消息已保留。",
94
+ };
95
+ }
96
+ return null;
97
+ }
98
+ export function reconcilePendingSubmissionFromState(input) {
99
+ const clientRequestId = input.clientRequestId;
100
+ const active = input.state?.activeTurn;
101
+ const latest = input.state?.latestTurn;
102
+ const activeState = active?.state ?? input.state?.activeTurnState ?? undefined;
103
+ const latestState = latest?.state ?? input.state?.latestTurnState ?? undefined;
104
+ if (active?.clientRequestId === clientRequestId && active.turnId) {
105
+ if (isTerminalTurnState(activeState)) {
106
+ return {
107
+ action: "release-terminal",
108
+ turnId: active.turnId,
109
+ state: String(activeState),
110
+ };
111
+ }
112
+ return { action: "bind-active", turnId: active.turnId };
113
+ }
114
+ if (latest?.clientRequestId === clientRequestId && latest.turnId) {
115
+ if (isTerminalTurnState(latestState)) {
116
+ return {
117
+ action: "release-terminal",
118
+ turnId: latest.turnId,
119
+ state: String(latestState),
120
+ };
121
+ }
122
+ // Non-terminal match on latest without a conflicting foreign active:
123
+ // bind and keep busy ownership (same clientRequestId, no re-POST).
124
+ if (!active?.turnId || active.clientRequestId === clientRequestId) {
125
+ return { action: "bind-active", turnId: latest.turnId };
126
+ }
127
+ }
128
+ // Explicit non-acceptance: no same-id Turn and runtime not busy.
129
+ // Do not forge idle while durable/runtime still reports busy.
130
+ if (!isRuntimeBusyUnion(input.state)) {
131
+ const foreignActive = Boolean(active?.turnId) && active?.clientRequestId !== clientRequestId;
132
+ if (!foreignActive) {
133
+ return { action: "release-not-accepted" };
134
+ }
135
+ }
136
+ return { action: "hold" };
137
+ }
138
+ /** Busy truth = durable active Turn ∪ runtime busy facts. */
139
+ export function isRuntimeBusyUnion(state) {
140
+ if (state?.activeTurnId || state?.activeTurn?.turnId)
141
+ return true;
142
+ const runtime = state?.runtime;
143
+ if (!runtime)
144
+ return false;
145
+ return (runtime.isStreaming === true ||
146
+ runtime.isPromptRunning === true ||
147
+ runtime.isCompacting === true ||
148
+ runtime.isBashRunning === true);
149
+ }
150
+ export function isTerminalTurnState(state) {
151
+ return state === "settled" || state === "aborted" || state === "failed";
152
+ }
153
+ /** Whether a late response may mutate the current session UI. */
154
+ export function isSubmissionCurrent(input) {
155
+ return (input.pending.sessionId === input.sessionId &&
156
+ input.pending.sessionGeneration === input.sessionGeneration &&
157
+ input.pending.submitGeneration === input.submitGeneration);
158
+ }