@tetherto/mdk-ui-agent 0.0.0 → 0.12.1
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/LICENSE +202 -0
- package/README.md +310 -0
- package/dist/branding.d.ts +36 -0
- package/dist/branding.d.ts.map +1 -0
- package/dist/branding.js +37 -0
- package/dist/branding.js.map +1 -0
- package/dist/components/approval-card.d.ts +46 -0
- package/dist/components/approval-card.d.ts.map +1 -0
- package/dist/components/approval-card.js +84 -0
- package/dist/components/approval-card.js.map +1 -0
- package/dist/components/assistant-message.d.ts +25 -0
- package/dist/components/assistant-message.d.ts.map +1 -0
- package/dist/components/assistant-message.js +49 -0
- package/dist/components/assistant-message.js.map +1 -0
- package/dist/components/co-pilot-panel.d.ts +17 -0
- package/dist/components/co-pilot-panel.d.ts.map +1 -0
- package/dist/components/co-pilot-panel.js +33 -0
- package/dist/components/co-pilot-panel.js.map +1 -0
- package/dist/components/code-block.d.ts +17 -0
- package/dist/components/code-block.d.ts.map +1 -0
- package/dist/components/code-block.js +40 -0
- package/dist/components/code-block.js.map +1 -0
- package/dist/components/collapsible-answer.d.ts +26 -0
- package/dist/components/collapsible-answer.d.ts.map +1 -0
- package/dist/components/collapsible-answer.js +30 -0
- package/dist/components/collapsible-answer.js.map +1 -0
- package/dist/components/composer.d.ts +31 -0
- package/dist/components/composer.d.ts.map +1 -0
- package/dist/components/composer.js +82 -0
- package/dist/components/composer.js.map +1 -0
- package/dist/components/conversation-list.d.ts +21 -0
- package/dist/components/conversation-list.d.ts.map +1 -0
- package/dist/components/conversation-list.js +42 -0
- package/dist/components/conversation-list.js.map +1 -0
- package/dist/components/icons.d.ts +88 -0
- package/dist/components/icons.d.ts.map +1 -0
- package/dist/components/icons.js +112 -0
- package/dist/components/icons.js.map +1 -0
- package/dist/components/launcher-fab.d.ts +8 -0
- package/dist/components/launcher-fab.d.ts.map +1 -0
- package/dist/components/launcher-fab.js +6 -0
- package/dist/components/launcher-fab.js.map +1 -0
- package/dist/components/leaked-tool-call-notice.d.ts +18 -0
- package/dist/components/leaked-tool-call-notice.d.ts.map +1 -0
- package/dist/components/leaked-tool-call-notice.js +14 -0
- package/dist/components/leaked-tool-call-notice.js.map +1 -0
- package/dist/components/markdown-link.d.ts +17 -0
- package/dist/components/markdown-link.d.ts.map +1 -0
- package/dist/components/markdown-link.js +18 -0
- package/dist/components/markdown-link.js.map +1 -0
- package/dist/components/markdown-text.d.ts +26 -0
- package/dist/components/markdown-text.d.ts.map +1 -0
- package/dist/components/markdown-text.js +32 -0
- package/dist/components/markdown-text.js.map +1 -0
- package/dist/components/message-list.d.ts +24 -0
- package/dist/components/message-list.d.ts.map +1 -0
- package/dist/components/message-list.js +92 -0
- package/dist/components/message-list.js.map +1 -0
- package/dist/components/no-tools-note.d.ts +26 -0
- package/dist/components/no-tools-note.d.ts.map +1 -0
- package/dist/components/no-tools-note.js +27 -0
- package/dist/components/no-tools-note.js.map +1 -0
- package/dist/components/panel-header.d.ts +26 -0
- package/dist/components/panel-header.d.ts.map +1 -0
- package/dist/components/panel-header.js +13 -0
- package/dist/components/panel-header.js.map +1 -0
- package/dist/components/rehype-highlight-subset.d.ts +17 -0
- package/dist/components/rehype-highlight-subset.d.ts.map +1 -0
- package/dist/components/rehype-highlight-subset.js +77 -0
- package/dist/components/rehype-highlight-subset.js.map +1 -0
- package/dist/components/system-message.d.ts +15 -0
- package/dist/components/system-message.d.ts.map +1 -0
- package/dist/components/system-message.js +12 -0
- package/dist/components/system-message.js.map +1 -0
- package/dist/components/tool-chip.d.ts +19 -0
- package/dist/components/tool-chip.d.ts.map +1 -0
- package/dist/components/tool-chip.js +32 -0
- package/dist/components/tool-chip.js.map +1 -0
- package/dist/components/user-message.d.ts +9 -0
- package/dist/components/user-message.d.ts.map +1 -0
- package/dist/components/user-message.js +7 -0
- package/dist/components/user-message.js.map +1 -0
- package/dist/core/conversation-store.d.ts +107 -0
- package/dist/core/conversation-store.d.ts.map +1 -0
- package/dist/core/conversation-store.js +254 -0
- package/dist/core/conversation-store.js.map +1 -0
- package/dist/core/error-text.d.ts +19 -0
- package/dist/core/error-text.d.ts.map +1 -0
- package/dist/core/error-text.js +35 -0
- package/dist/core/error-text.js.map +1 -0
- package/dist/core/events.d.ts +98 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +50 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/format.d.ts +23 -0
- package/dist/core/format.d.ts.map +1 -0
- package/dist/core/format.js +49 -0
- package/dist/core/format.js.map +1 -0
- package/dist/core/index.d.ts +27 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +20 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/markdown.d.ts +26 -0
- package/dist/core/markdown.d.ts.map +1 -0
- package/dist/core/markdown.js +49 -0
- package/dist/core/markdown.js.map +1 -0
- package/dist/core/prose.d.ts +27 -0
- package/dist/core/prose.d.ts.map +1 -0
- package/dist/core/prose.js +79 -0
- package/dist/core/prose.js.map +1 -0
- package/dist/core/small-talk.d.ts +15 -0
- package/dist/core/small-talk.d.ts.map +1 -0
- package/dist/core/small-talk.js +42 -0
- package/dist/core/small-talk.js.map +1 -0
- package/dist/core/sse.d.ts +108 -0
- package/dist/core/sse.d.ts.map +1 -0
- package/dist/core/sse.js +236 -0
- package/dist/core/sse.js.map +1 -0
- package/dist/core/tool-label.d.ts +16 -0
- package/dist/core/tool-label.d.ts.map +1 -0
- package/dist/core/tool-label.js +31 -0
- package/dist/core/tool-label.js.map +1 -0
- package/dist/core/transport.d.ts +71 -0
- package/dist/core/transport.d.ts.map +1 -0
- package/dist/core/transport.js +147 -0
- package/dist/core/transport.js.map +1 -0
- package/dist/core/turn.d.ts +87 -0
- package/dist/core/turn.d.ts.map +1 -0
- package/dist/core/turn.js +232 -0
- package/dist/core/turn.js.map +1 -0
- package/dist/core/uuid.d.ts +21 -0
- package/dist/core/uuid.d.ts.map +1 -0
- package/dist/core/uuid.js +54 -0
- package/dist/core/uuid.js.map +1 -0
- package/dist/entries/chat-page.d.ts +28 -0
- package/dist/entries/chat-page.d.ts.map +1 -0
- package/dist/entries/chat-page.js +25 -0
- package/dist/entries/chat-page.js.map +1 -0
- package/dist/entries/co-pilot.d.ts +41 -0
- package/dist/entries/co-pilot.d.ts.map +1 -0
- package/dist/entries/co-pilot.js +39 -0
- package/dist/entries/co-pilot.js.map +1 -0
- package/dist/entries/lazy-panel.d.ts +15 -0
- package/dist/entries/lazy-panel.d.ts.map +1 -0
- package/dist/entries/lazy-panel.js +19 -0
- package/dist/entries/lazy-panel.js.map +1 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use-agent-chat.d.ts +46 -0
- package/dist/hooks/use-agent-chat.d.ts.map +1 -0
- package/dist/hooks/use-agent-chat.js +288 -0
- package/dist/hooks/use-agent-chat.js.map +1 -0
- package/dist/hooks/use-agent-config.d.ts +29 -0
- package/dist/hooks/use-agent-config.d.ts.map +1 -0
- package/dist/hooks/use-agent-config.js +45 -0
- package/dist/hooks/use-agent-config.js.map +1 -0
- package/dist/hooks/use-conversations.d.ts +19 -0
- package/dist/hooks/use-conversations.d.ts.map +1 -0
- package/dist/hooks/use-conversations.js +19 -0
- package/dist/hooks/use-conversations.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/package.json +105 -1
- package/src/branding.ts +40 -0
- package/src/components/approval-card.tsx +141 -0
- package/src/components/assistant-message.tsx +140 -0
- package/src/components/co-pilot-panel.tsx +109 -0
- package/src/components/code-block.tsx +63 -0
- package/src/components/collapsible-answer.tsx +55 -0
- package/src/components/composer.tsx +147 -0
- package/src/components/conversation-list.tsx +141 -0
- package/src/components/icons.tsx +189 -0
- package/src/components/launcher-fab.tsx +16 -0
- package/src/components/leaked-tool-call-notice.tsx +29 -0
- package/src/components/markdown-link.tsx +30 -0
- package/src/components/markdown-text.tsx +58 -0
- package/src/components/message-list.tsx +164 -0
- package/src/components/no-tools-note.tsx +33 -0
- package/src/components/panel-header.tsx +86 -0
- package/src/components/rehype-highlight-subset.ts +84 -0
- package/src/components/system-message.tsx +19 -0
- package/src/components/tool-chip.tsx +58 -0
- package/src/components/user-message.tsx +18 -0
- package/src/core/conversation-store.ts +342 -0
- package/src/core/error-text.ts +36 -0
- package/src/core/events.ts +127 -0
- package/src/core/format.ts +59 -0
- package/src/core/index.ts +115 -0
- package/src/core/markdown.ts +52 -0
- package/src/core/prose.ts +78 -0
- package/src/core/small-talk.ts +45 -0
- package/src/core/sse.ts +269 -0
- package/src/core/tool-label.ts +33 -0
- package/src/core/transport.ts +208 -0
- package/src/core/turn.ts +299 -0
- package/src/core/uuid.ts +59 -0
- package/src/entries/chat-page.tsx +56 -0
- package/src/entries/co-pilot.tsx +84 -0
- package/src/entries/lazy-panel.tsx +19 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/use-agent-chat.ts +387 -0
- package/src/hooks/use-agent-config.ts +70 -0
- package/src/hooks/use-conversations.ts +39 -0
- package/src/index.ts +30 -0
- package/src/styles/_approval.scss +68 -0
- package/src/styles/_composer.scss +45 -0
- package/src/styles/_conversations.scss +160 -0
- package/src/styles/_messages.scss +444 -0
- package/src/styles/_mixins.scss +27 -0
- package/src/styles/_panel.scss +147 -0
- package/src/styles/_tokens.scss +30 -0
- package/src/styles.scss +16 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"small-talk.js","sourceRoot":"","sources":["../../src/core/small-talk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,yFAAyF;AACzF,MAAM,cAAc,GAAG;IACrB,oFAAoF;IACpF,iDAAiD;IACjD,gHAAgH;IAChH,yCAAyC;IACzC,kFAAkF;CACnF,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,GACb,wQAAwQ,CAAA;AAE5Q,qFAAqF;AACrF,MAAM,SAAS,GAAG,CAAC,CAAA;AAEnB,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,UAAU,GAAG,IAAI;SACpB,WAAW,EAAE;SACb,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,iDAAiD;SACvE,IAAI,EAAE,CAAA;IAET,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACzC,IAAI,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9C,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,SAAS;QAAE,OAAO,KAAK,CAAA;IAE5D,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA;AACnE,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE reading for the agent message route.
|
|
3
|
+
*
|
|
4
|
+
* `EventSource` is unusable here: the message is a POST body and `EventSource`
|
|
5
|
+
* is GET-only. So this is `fetch` + a body-stream reader, which is also what the
|
|
6
|
+
* producer's own docs prescribe.
|
|
7
|
+
*
|
|
8
|
+
* The gateway writes `event: <type>\ndata: <json>\n\n` and nothing else — no
|
|
9
|
+
* `id:`, no `retry:`, and no heartbeat comment frames. The `event:` line is
|
|
10
|
+
* redundant (`data.type` carries the same value) so only `data:` is parsed. The
|
|
11
|
+
* rest of the parser is nonetheless written against the spec rather than against
|
|
12
|
+
* that one producer: CRLF line endings and multi-line `data:` are both legal, and
|
|
13
|
+
* a proxy that rewrites line endings would otherwise silently end every turn as a
|
|
14
|
+
* truncation.
|
|
15
|
+
*/
|
|
16
|
+
import type { WireEvent } from './events';
|
|
17
|
+
/** Synthesized locally, never sent by the gateway. See `readAgentStream`. */
|
|
18
|
+
export declare const ERR_STREAM_TRUNCATED = "ERR_AGENT_STREAM_TRUNCATED";
|
|
19
|
+
/** Synthesized locally: the socket stayed open but nothing arrived. See `readAgentStream`. */
|
|
20
|
+
export declare const ERR_STREAM_IDLE = "ERR_AGENT_STREAM_IDLE";
|
|
21
|
+
/**
|
|
22
|
+
* How long a turn may say nothing between events before the connection is
|
|
23
|
+
* assumed lost.
|
|
24
|
+
*
|
|
25
|
+
* The gateway sends no heartbeats, so silence is the only symptom of a wedged
|
|
26
|
+
* agent, a half-closed proxy or a laptop resumed from sleep. Once events are
|
|
27
|
+
* flowing, 30s of nothing is already far outside what a working turn does: the
|
|
28
|
+
* producer emits a frame per token.
|
|
29
|
+
*/
|
|
30
|
+
export declare const STREAM_IDLE_TIMEOUT_MS = 30000;
|
|
31
|
+
/**
|
|
32
|
+
* The same limit before the first event, which is a different wait entirely.
|
|
33
|
+
*
|
|
34
|
+
* Nothing is emitted until the producer's first model call returns a routing
|
|
35
|
+
* decision, and a local model may think for a long time before it answers a
|
|
36
|
+
* single character: measured against a 4B thinking model on this hardware, the
|
|
37
|
+
* first event arrived at 61s. Held to the producer's own per-call budget
|
|
38
|
+
* (`REQUEST_TIMEOUT_MS`, 120s in backend/core/agent/src/constants.js) so a turn
|
|
39
|
+
* the server is still legitimately working on is never abandoned here first —
|
|
40
|
+
* whatever the model does, the server gives up before this does and says why.
|
|
41
|
+
*/
|
|
42
|
+
export declare const FIRST_EVENT_IDLE_TIMEOUT_MS = 120000;
|
|
43
|
+
/**
|
|
44
|
+
* The same limit while an approval is outstanding, where silence is legitimate:
|
|
45
|
+
* the producer is waiting on a human, and only auto-rejects after its own
|
|
46
|
+
* `agent.approvalTimeoutMs`. Five minutes is that default plus room to spare, so
|
|
47
|
+
* the stream is never given up on before the server itself would have resumed it.
|
|
48
|
+
*/
|
|
49
|
+
export declare const APPROVAL_IDLE_TIMEOUT_MS = 300000;
|
|
50
|
+
/** Thrown out of `readFrames` when the deadline expires; converted to an event above. */
|
|
51
|
+
export declare class StreamIdleError extends Error {
|
|
52
|
+
constructor();
|
|
53
|
+
}
|
|
54
|
+
export type ReadFramesOptions = {
|
|
55
|
+
/**
|
|
56
|
+
* Milliseconds of silence tolerated before the next read is given up on, read
|
|
57
|
+
* fresh before every read so the caller can widen it mid-stream. `0` disables
|
|
58
|
+
* the deadline.
|
|
59
|
+
*/
|
|
60
|
+
idleTimeoutMs?: () => number;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Pulls the `data:` payload out of one frame.
|
|
64
|
+
*
|
|
65
|
+
* A frame may carry several `data:` lines, which the spec joins with newlines;
|
|
66
|
+
* anything else (`event:`, `id:`, a `:` comment) is ignored. Returns null for a
|
|
67
|
+
* frame with no data at all.
|
|
68
|
+
*/
|
|
69
|
+
export declare function parseFrame(frame: string): unknown;
|
|
70
|
+
/**
|
|
71
|
+
* Yields each decoded `data:` payload, in order, as frames arrive.
|
|
72
|
+
*
|
|
73
|
+
* The abort signal is handled here rather than left to `fetch`. Aborting a fetch
|
|
74
|
+
* whose headers have already arrived is only specified to error the body stream
|
|
75
|
+
* — cancelling the reader is what actually unblocks a `read()` that is parked
|
|
76
|
+
* waiting for the next token, which is where an abort almost always lands.
|
|
77
|
+
*/
|
|
78
|
+
export declare function readFrames(stream: ReadableStream<Uint8Array>, signal?: AbortSignal, options?: ReadFramesOptions): AsyncGenerator<unknown>;
|
|
79
|
+
export type ReadAgentStreamOptions = {
|
|
80
|
+
/** Silence tolerated between events. Defaults to {@link STREAM_IDLE_TIMEOUT_MS}; `0` disables it. */
|
|
81
|
+
idleTimeoutMs?: number;
|
|
82
|
+
/** Silence tolerated while an approval is outstanding. Defaults to {@link APPROVAL_IDLE_TIMEOUT_MS}. */
|
|
83
|
+
approvalIdleTimeoutMs?: number;
|
|
84
|
+
/** Silence tolerated before the first event. Defaults to {@link FIRST_EVENT_IDLE_TIMEOUT_MS}. */
|
|
85
|
+
firstEventIdleTimeoutMs?: number;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Turns a live response into the guaranteed-well-formed event sequence the rest
|
|
89
|
+
* of the package is written against. Four contract obligations live here:
|
|
90
|
+
*
|
|
91
|
+
* 1. Unknown or malformed events are dropped, not thrown on (invariant 5).
|
|
92
|
+
* 2. Nothing is emitted after the terminal event (invariant 1), so a
|
|
93
|
+
* misbehaving producer cannot reopen a finished turn.
|
|
94
|
+
* 3. Every stream ends with exactly one terminal event. The gateway's stream
|
|
95
|
+
* route calls `rep.hijack()`, so a failure after the headers are sent just
|
|
96
|
+
* closes the socket — no `error` frame, no `done`. Left alone that reads as a
|
|
97
|
+
* turn that never finishes, so an EOF with no terminal event is converted
|
|
98
|
+
* into one here. An abort is excluded: the operator stopping the turn is not
|
|
99
|
+
* a failure, and nothing should be reported back to them as one.
|
|
100
|
+
* 4. A socket that stays open but stops delivering ends the same way. Without
|
|
101
|
+
* that, a consumer awaiting the next event parks forever and the panel stays
|
|
102
|
+
* busy until the page is reloaded. The deadline is per phase, because how much
|
|
103
|
+
* silence is normal is not constant across a turn: wide before the first event
|
|
104
|
+
* (the model is still thinking), wide again while an approval is outstanding
|
|
105
|
+
* (the producer is waiting on a human), narrow in between.
|
|
106
|
+
*/
|
|
107
|
+
export declare function readAgentStream(stream: ReadableStream<Uint8Array>, signal?: AbortSignal, options?: ReadAgentStreamOptions): AsyncGenerator<WireEvent>;
|
|
108
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/core/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAQzC,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,+BAA+B,CAAA;AAChE,8FAA8F;AAC9F,eAAO,MAAM,eAAe,0BAA0B,CAAA;AAEtD;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,QAAS,CAAA;AAE5C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,SAAU,CAAA;AAElD;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,SAAU,CAAA;AAE/C,yFAAyF;AACzF,qBAAa,eAAgB,SAAQ,KAAK;IACxC,cAGC;CACF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,MAAM,CAAA;CAC7B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAejD;AAiCD;;;;;;;GAOG;AACH,wBAAuB,UAAU,CAC/B,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,iBAAsB,GAC9B,cAAc,CAAC,OAAO,CAAC,CA8CzB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,qGAAqG;IACrG,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,wGAAwG;IACxG,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,iGAAiG;IACjG,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACjC,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAuB,eAAe,CACpC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,sBAA2B,GACnC,cAAc,CAAC,SAAS,CAAC,CA0C3B"}
|
package/dist/core/sse.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE reading for the agent message route.
|
|
3
|
+
*
|
|
4
|
+
* `EventSource` is unusable here: the message is a POST body and `EventSource`
|
|
5
|
+
* is GET-only. So this is `fetch` + a body-stream reader, which is also what the
|
|
6
|
+
* producer's own docs prescribe.
|
|
7
|
+
*
|
|
8
|
+
* The gateway writes `event: <type>\ndata: <json>\n\n` and nothing else — no
|
|
9
|
+
* `id:`, no `retry:`, and no heartbeat comment frames. The `event:` line is
|
|
10
|
+
* redundant (`data.type` carries the same value) so only `data:` is parsed. The
|
|
11
|
+
* rest of the parser is nonetheless written against the spec rather than against
|
|
12
|
+
* that one producer: CRLF line endings and multi-line `data:` are both legal, and
|
|
13
|
+
* a proxy that rewrites line endings would otherwise silently end every turn as a
|
|
14
|
+
* truncation.
|
|
15
|
+
*/
|
|
16
|
+
import { EVENT, isTerminal, isWireEvent } from './events';
|
|
17
|
+
/** A blank line ends a frame; either line ending is legal (spec §7). */
|
|
18
|
+
const FRAME_SEPARATOR = /\r?\n\r?\n/;
|
|
19
|
+
const LINE_SEPARATOR = /\r?\n/;
|
|
20
|
+
const DATA_PREFIX = 'data:';
|
|
21
|
+
/** Synthesized locally, never sent by the gateway. See `readAgentStream`. */
|
|
22
|
+
export const ERR_STREAM_TRUNCATED = 'ERR_AGENT_STREAM_TRUNCATED';
|
|
23
|
+
/** Synthesized locally: the socket stayed open but nothing arrived. See `readAgentStream`. */
|
|
24
|
+
export const ERR_STREAM_IDLE = 'ERR_AGENT_STREAM_IDLE';
|
|
25
|
+
/**
|
|
26
|
+
* How long a turn may say nothing between events before the connection is
|
|
27
|
+
* assumed lost.
|
|
28
|
+
*
|
|
29
|
+
* The gateway sends no heartbeats, so silence is the only symptom of a wedged
|
|
30
|
+
* agent, a half-closed proxy or a laptop resumed from sleep. Once events are
|
|
31
|
+
* flowing, 30s of nothing is already far outside what a working turn does: the
|
|
32
|
+
* producer emits a frame per token.
|
|
33
|
+
*/
|
|
34
|
+
export const STREAM_IDLE_TIMEOUT_MS = 30_000;
|
|
35
|
+
/**
|
|
36
|
+
* The same limit before the first event, which is a different wait entirely.
|
|
37
|
+
*
|
|
38
|
+
* Nothing is emitted until the producer's first model call returns a routing
|
|
39
|
+
* decision, and a local model may think for a long time before it answers a
|
|
40
|
+
* single character: measured against a 4B thinking model on this hardware, the
|
|
41
|
+
* first event arrived at 61s. Held to the producer's own per-call budget
|
|
42
|
+
* (`REQUEST_TIMEOUT_MS`, 120s in backend/core/agent/src/constants.js) so a turn
|
|
43
|
+
* the server is still legitimately working on is never abandoned here first —
|
|
44
|
+
* whatever the model does, the server gives up before this does and says why.
|
|
45
|
+
*/
|
|
46
|
+
export const FIRST_EVENT_IDLE_TIMEOUT_MS = 120_000;
|
|
47
|
+
/**
|
|
48
|
+
* The same limit while an approval is outstanding, where silence is legitimate:
|
|
49
|
+
* the producer is waiting on a human, and only auto-rejects after its own
|
|
50
|
+
* `agent.approvalTimeoutMs`. Five minutes is that default plus room to spare, so
|
|
51
|
+
* the stream is never given up on before the server itself would have resumed it.
|
|
52
|
+
*/
|
|
53
|
+
export const APPROVAL_IDLE_TIMEOUT_MS = 300_000;
|
|
54
|
+
/** Thrown out of `readFrames` when the deadline expires; converted to an event above. */
|
|
55
|
+
export class StreamIdleError extends Error {
|
|
56
|
+
constructor() {
|
|
57
|
+
super(ERR_STREAM_IDLE);
|
|
58
|
+
this.name = 'StreamIdleError';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Pulls the `data:` payload out of one frame.
|
|
63
|
+
*
|
|
64
|
+
* A frame may carry several `data:` lines, which the spec joins with newlines;
|
|
65
|
+
* anything else (`event:`, `id:`, a `:` comment) is ignored. Returns null for a
|
|
66
|
+
* frame with no data at all.
|
|
67
|
+
*/
|
|
68
|
+
export function parseFrame(frame) {
|
|
69
|
+
const data = frame
|
|
70
|
+
.split(LINE_SEPARATOR)
|
|
71
|
+
.filter((line) => line.startsWith(DATA_PREFIX))
|
|
72
|
+
.map((line) => line.slice(DATA_PREFIX.length).trim());
|
|
73
|
+
if (data.length === 0)
|
|
74
|
+
return null;
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(data.join('\n'));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// A frame we cannot parse is indistinguishable from an event type we do not
|
|
80
|
+
// know about, and invariant 5 says ignore those rather than throw.
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const IDLE = Symbol('idle');
|
|
85
|
+
/**
|
|
86
|
+
* One `read()`, given up on after `timeoutMs` of silence.
|
|
87
|
+
*
|
|
88
|
+
* The abandoned read is left attached to a rejection handler on purpose: the
|
|
89
|
+
* caller's `finally` cancels the reader straight after, and an unobserved
|
|
90
|
+
* rejection from a read parked on a socket we just cancelled would surface as a
|
|
91
|
+
* global unhandled rejection.
|
|
92
|
+
*/
|
|
93
|
+
async function readWithDeadline(reader, timeoutMs) {
|
|
94
|
+
const read = reader.read();
|
|
95
|
+
if (timeoutMs <= 0)
|
|
96
|
+
return read;
|
|
97
|
+
read.catch(() => { });
|
|
98
|
+
let timer;
|
|
99
|
+
try {
|
|
100
|
+
return await Promise.race([
|
|
101
|
+
read,
|
|
102
|
+
new Promise((resolve) => {
|
|
103
|
+
timer = setTimeout(() => resolve(IDLE), timeoutMs);
|
|
104
|
+
}),
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
clearTimeout(timer);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Yields each decoded `data:` payload, in order, as frames arrive.
|
|
113
|
+
*
|
|
114
|
+
* The abort signal is handled here rather than left to `fetch`. Aborting a fetch
|
|
115
|
+
* whose headers have already arrived is only specified to error the body stream
|
|
116
|
+
* — cancelling the reader is what actually unblocks a `read()` that is parked
|
|
117
|
+
* waiting for the next token, which is where an abort almost always lands.
|
|
118
|
+
*/
|
|
119
|
+
export async function* readFrames(stream, signal, options = {}) {
|
|
120
|
+
const reader = stream.getReader();
|
|
121
|
+
const decoder = new TextDecoder();
|
|
122
|
+
let buffer = '';
|
|
123
|
+
const cancel = () => {
|
|
124
|
+
reader.cancel().catch(() => {
|
|
125
|
+
// Already closed or errored; there is nothing left to release.
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
if (signal?.aborted)
|
|
129
|
+
cancel();
|
|
130
|
+
signal?.addEventListener('abort', cancel, { once: true });
|
|
131
|
+
const drain = function* () {
|
|
132
|
+
for (;;) {
|
|
133
|
+
const match = FRAME_SEPARATOR.exec(buffer);
|
|
134
|
+
if (!match)
|
|
135
|
+
return;
|
|
136
|
+
const frame = buffer.slice(0, match.index);
|
|
137
|
+
buffer = buffer.slice(match.index + match[0].length);
|
|
138
|
+
const payload = parseFrame(frame);
|
|
139
|
+
if (payload !== null)
|
|
140
|
+
yield payload;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
try {
|
|
144
|
+
for (;;) {
|
|
145
|
+
const outcome = await readWithDeadline(reader, options.idleTimeoutMs?.() ?? 0);
|
|
146
|
+
if (outcome === IDLE)
|
|
147
|
+
throw new StreamIdleError();
|
|
148
|
+
const { value, done } = outcome;
|
|
149
|
+
if (done)
|
|
150
|
+
break;
|
|
151
|
+
buffer += decoder.decode(value, { stream: true });
|
|
152
|
+
yield* drain();
|
|
153
|
+
}
|
|
154
|
+
// Flush whatever the decoder was holding from an incomplete multibyte
|
|
155
|
+
// sequence, then the final frame if it arrived without its blank line.
|
|
156
|
+
buffer += decoder.decode();
|
|
157
|
+
yield* drain();
|
|
158
|
+
const tail = parseFrame(buffer);
|
|
159
|
+
if (tail !== null)
|
|
160
|
+
yield tail;
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
signal?.removeEventListener('abort', cancel);
|
|
164
|
+
cancel();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Turns a live response into the guaranteed-well-formed event sequence the rest
|
|
169
|
+
* of the package is written against. Four contract obligations live here:
|
|
170
|
+
*
|
|
171
|
+
* 1. Unknown or malformed events are dropped, not thrown on (invariant 5).
|
|
172
|
+
* 2. Nothing is emitted after the terminal event (invariant 1), so a
|
|
173
|
+
* misbehaving producer cannot reopen a finished turn.
|
|
174
|
+
* 3. Every stream ends with exactly one terminal event. The gateway's stream
|
|
175
|
+
* route calls `rep.hijack()`, so a failure after the headers are sent just
|
|
176
|
+
* closes the socket — no `error` frame, no `done`. Left alone that reads as a
|
|
177
|
+
* turn that never finishes, so an EOF with no terminal event is converted
|
|
178
|
+
* into one here. An abort is excluded: the operator stopping the turn is not
|
|
179
|
+
* a failure, and nothing should be reported back to them as one.
|
|
180
|
+
* 4. A socket that stays open but stops delivering ends the same way. Without
|
|
181
|
+
* that, a consumer awaiting the next event parks forever and the panel stays
|
|
182
|
+
* busy until the page is reloaded. The deadline is per phase, because how much
|
|
183
|
+
* silence is normal is not constant across a turn: wide before the first event
|
|
184
|
+
* (the model is still thinking), wide again while an approval is outstanding
|
|
185
|
+
* (the producer is waiting on a human), narrow in between.
|
|
186
|
+
*/
|
|
187
|
+
export async function* readAgentStream(stream, signal, options = {}) {
|
|
188
|
+
const streamingTimeout = options.idleTimeoutMs ?? STREAM_IDLE_TIMEOUT_MS;
|
|
189
|
+
const approvalTimeout = options.approvalIdleTimeoutMs ?? APPROVAL_IDLE_TIMEOUT_MS;
|
|
190
|
+
const firstEventTimeout = options.firstEventIdleTimeoutMs ?? FIRST_EVENT_IDLE_TIMEOUT_MS;
|
|
191
|
+
let terminalSeen = false;
|
|
192
|
+
let awaitingApproval = false;
|
|
193
|
+
let seenAnyEvent = false;
|
|
194
|
+
let idle = false;
|
|
195
|
+
const idleTimeoutMs = () => {
|
|
196
|
+
if (streamingTimeout <= 0)
|
|
197
|
+
return 0;
|
|
198
|
+
if (awaitingApproval)
|
|
199
|
+
return approvalTimeout;
|
|
200
|
+
if (!seenAnyEvent)
|
|
201
|
+
return firstEventTimeout;
|
|
202
|
+
return streamingTimeout;
|
|
203
|
+
};
|
|
204
|
+
try {
|
|
205
|
+
for await (const payload of readFrames(stream, signal, { idleTimeoutMs })) {
|
|
206
|
+
if (!isWireEvent(payload))
|
|
207
|
+
continue;
|
|
208
|
+
if (terminalSeen)
|
|
209
|
+
continue;
|
|
210
|
+
seenAnyEvent = true;
|
|
211
|
+
// An approval pauses the producer; its result is what releases it.
|
|
212
|
+
if (payload.type === EVENT.PENDING_APPROVAL)
|
|
213
|
+
awaitingApproval = true;
|
|
214
|
+
if (payload.type === EVENT.TOOL_RESULT)
|
|
215
|
+
awaitingApproval = false;
|
|
216
|
+
if (isTerminal(payload))
|
|
217
|
+
terminalSeen = true;
|
|
218
|
+
yield payload;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
if (!(error instanceof StreamIdleError))
|
|
223
|
+
throw error;
|
|
224
|
+
idle = true;
|
|
225
|
+
}
|
|
226
|
+
if (!terminalSeen && !signal?.aborted) {
|
|
227
|
+
yield {
|
|
228
|
+
type: EVENT.ERROR,
|
|
229
|
+
error: idle ? ERR_STREAM_IDLE : ERR_STREAM_TRUNCATED,
|
|
230
|
+
turnId: '',
|
|
231
|
+
seq: Number.MAX_SAFE_INTEGER,
|
|
232
|
+
ts: 0,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/core/sse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human labels for tool chips.
|
|
3
|
+
*
|
|
4
|
+
* Tools are supplied by whichever MCP server the operator points the agent at,
|
|
5
|
+
* so no name can be hardcoded here — `summarize_site` and `get_device` happen to
|
|
6
|
+
* come from the reference site tools, but another deployment ships another set
|
|
7
|
+
* entirely. Callers pass a `toolLabels` map for the names they know; everything
|
|
8
|
+
* else falls back to a readable form of the identifier.
|
|
9
|
+
*/
|
|
10
|
+
export type ToolLabels = Record<string, string>;
|
|
11
|
+
/** `summarize_site` -> `Summarize site`. */
|
|
12
|
+
export declare function humanizeToolName(name: string): string;
|
|
13
|
+
export declare function toolLabel(name: string, labels?: ToolLabels): string;
|
|
14
|
+
/** `420` -> `0.4s`, so a chip reads `Site status · 0.4s`. */
|
|
15
|
+
export declare function formatDuration(durationMs: number | undefined): string | null;
|
|
16
|
+
//# sourceMappingURL=tool-label.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-label.d.ts","sourceRoot":"","sources":["../../src/core/tool-label.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAE/C,4CAA4C;AAC5C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAEnE;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAK5E"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human labels for tool chips.
|
|
3
|
+
*
|
|
4
|
+
* Tools are supplied by whichever MCP server the operator points the agent at,
|
|
5
|
+
* so no name can be hardcoded here — `summarize_site` and `get_device` happen to
|
|
6
|
+
* come from the reference site tools, but another deployment ships another set
|
|
7
|
+
* entirely. Callers pass a `toolLabels` map for the names they know; everything
|
|
8
|
+
* else falls back to a readable form of the identifier.
|
|
9
|
+
*/
|
|
10
|
+
/** `summarize_site` -> `Summarize site`. */
|
|
11
|
+
export function humanizeToolName(name) {
|
|
12
|
+
const words = name
|
|
13
|
+
.replaceAll(/[_-]+/g, ' ')
|
|
14
|
+
.replaceAll(/([a-z\d])([A-Z])/g, '$1 $2')
|
|
15
|
+
.trim();
|
|
16
|
+
if (words.length === 0)
|
|
17
|
+
return name;
|
|
18
|
+
return words.charAt(0).toUpperCase() + words.slice(1).toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
export function toolLabel(name, labels) {
|
|
21
|
+
return labels?.[name] ?? humanizeToolName(name);
|
|
22
|
+
}
|
|
23
|
+
/** `420` -> `0.4s`, so a chip reads `Site status · 0.4s`. */
|
|
24
|
+
export function formatDuration(durationMs) {
|
|
25
|
+
if (durationMs === undefined || !Number.isFinite(durationMs))
|
|
26
|
+
return null;
|
|
27
|
+
const seconds = durationMs / 1000;
|
|
28
|
+
// Tenths stay readable up to a minute; past that the decimal is noise.
|
|
29
|
+
return seconds < 60 ? `${seconds.toFixed(1)}s` : `${Math.round(seconds)}s`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=tool-label.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-label.js","sourceRoot":"","sources":["../../src/core/tool-label.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,4CAA4C;AAC5C,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,KAAK,GAAG,IAAI;SACf,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC;SACzB,UAAU,CAAC,mBAAmB,EAAE,OAAO,CAAC;SACxC,IAAI,EAAE,CAAA;IACT,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;AACrE,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAmB;IACzD,OAAO,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAA;AACjD,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,cAAc,CAAC,UAA8B;IAC3D,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAA;IACzE,MAAM,OAAO,GAAG,UAAU,GAAG,IAAI,CAAA;IACjC,uEAAuE;IACvE,OAAO,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAA;AAC5E,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four agent routes, as declared in `backend/apps/agent/mdk-plugin.json`.
|
|
3
|
+
*
|
|
4
|
+
* POST /agent/sessions -> { sessionId }
|
|
5
|
+
* POST /agent/sessions/:id/messages -> text/event-stream
|
|
6
|
+
* POST /agent/sessions/:id/approvals/:approvalId -> { approvalId, approved }
|
|
7
|
+
* DELETE /agent/sessions/:id -> { sessionId, deleted }
|
|
8
|
+
*
|
|
9
|
+
* Note the approval route is session-scoped. `backend/core/agent/docs/CONTRACT.md`
|
|
10
|
+
* documents it as `/agent/turns/{turnId}/approvals/{approvalId}`; that is stale —
|
|
11
|
+
* `turnId` appears in no URL.
|
|
12
|
+
*
|
|
13
|
+
* The gateway sends no CORS headers, and the stream route calls `rep.hijack()` so
|
|
14
|
+
* no CORS hook could decorate it even if one existed. Callers must be same-origin
|
|
15
|
+
* (served from `staticRootPath`) or proxied (`/agent` in the dev server).
|
|
16
|
+
*/
|
|
17
|
+
import type { WireEvent } from './events';
|
|
18
|
+
import type { ReadAgentStreamOptions } from './sse';
|
|
19
|
+
export declare const AGENT_ROUTE_PREFIX = "/agent";
|
|
20
|
+
/** The `ERR_*` codes these routes can return. */
|
|
21
|
+
export declare const AGENT_ERROR: {
|
|
22
|
+
readonly SESSION_NOT_FOUND: 'ERR_AGENT_SESSION_NOT_FOUND';
|
|
23
|
+
readonly TURN_ACTIVE: 'ERR_AGENT_TURN_ACTIVE';
|
|
24
|
+
readonly TEXT_REQUIRED: 'ERR_AGENT_MESSAGE_TEXT_REQUIRED';
|
|
25
|
+
readonly UNAVAILABLE: 'ERR_AGENT_UNAVAILABLE';
|
|
26
|
+
readonly APPROVAL_NOT_FOUND: 'ERR_AGENT_APPROVAL_NOT_FOUND';
|
|
27
|
+
};
|
|
28
|
+
export type AgentErrorCode = (typeof AGENT_ERROR)[keyof typeof AGENT_ERROR];
|
|
29
|
+
export type TokenSource = () => string | null | undefined | Promise<string | null | undefined>;
|
|
30
|
+
export type AgentTransportOptions = {
|
|
31
|
+
/** Gateway origin. Empty string means relative URLs — i.e. same-origin or proxied. */
|
|
32
|
+
baseUrl?: string;
|
|
33
|
+
getToken?: TokenSource;
|
|
34
|
+
/** Injected in tests; defaults to the global `fetch`. */
|
|
35
|
+
fetchImpl?: typeof fetch;
|
|
36
|
+
};
|
|
37
|
+
/** A gateway error carrying the `ERR_*` code the UI branches on. */
|
|
38
|
+
export declare class AgentApiError extends Error {
|
|
39
|
+
readonly status: number;
|
|
40
|
+
readonly code: string;
|
|
41
|
+
constructor(status: number, code: string, message?: string);
|
|
42
|
+
is(code: AgentErrorCode): boolean;
|
|
43
|
+
}
|
|
44
|
+
/** Identity comes from the token, so the request body is ignored by the gateway. */
|
|
45
|
+
export declare function createSession(options?: AgentTransportOptions): Promise<string>;
|
|
46
|
+
export declare function deleteSession(sessionId: string, options?: AgentTransportOptions): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Answers a paused approval. The decision travels on its own request while the
|
|
49
|
+
* message stream stays open — the stream resumes on its own once this lands.
|
|
50
|
+
*
|
|
51
|
+
* The gateway tests `approved === true`, so anything else is a rejection. It is
|
|
52
|
+
* passed through as a real boolean rather than coerced, to keep that explicit.
|
|
53
|
+
*
|
|
54
|
+
* A decision that arrives after the approval timed out, or a second decision for
|
|
55
|
+
* the same approval, is a 404 `ERR_AGENT_APPROVAL_NOT_FOUND` — the two are
|
|
56
|
+
* deliberately indistinguishable. Callers should treat it as "already settled",
|
|
57
|
+
* not as a failure.
|
|
58
|
+
*/
|
|
59
|
+
export declare function decideApproval(sessionId: string, approvalId: string, approved: boolean, options?: AgentTransportOptions): Promise<void>;
|
|
60
|
+
export type StreamTurnOptions = AgentTransportOptions & ReadAgentStreamOptions & {
|
|
61
|
+
signal?: AbortSignal;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Sends one message and yields its events until the turn ends.
|
|
65
|
+
*
|
|
66
|
+
* Only one turn may be in flight per session; a second send while this is
|
|
67
|
+
* running — including while it is paused on an approval, since a paused turn
|
|
68
|
+
* still holds the session busy — throws `ERR_AGENT_TURN_ACTIVE`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function streamTurn(sessionId: string, text: string, options?: StreamTurnOptions): AsyncGenerator<WireEvent>;
|
|
71
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/core/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAA;AAGnD,eAAO,MAAM,kBAAkB,WAAW,CAAA;AAE1C,iDAAiD;AACjD,eAAO,MAAM,WAAW;aACtB,iBAAiB,EAAE,6BAA6B;aAChD,WAAW,EAAE,uBAAuB;aACpC,aAAa,EAAE,iCAAiC;aAChD,WAAW,EAAE,uBAAuB;aACpC,kBAAkB,EAAE,8BAA8B;CAC1C,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAE3E,MAAM,MAAM,WAAW,GAAG,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAE9F,MAAM,MAAM,qBAAqB,GAAG;IAClC,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB,CAAA;AAED,oEAAoE;AACpE,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,YAAY,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAKzD;IAED,EAAE,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAEhC;CACF;AAyDD,oFAAoF;AACpF,wBAAsB,aAAa,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxF;AAED,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG,sBAAsB,GAAG;IAC/E,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED;;;;;;GAMG;AACH,wBAAuB,UAAU,CAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,iBAAsB,GAC9B,cAAc,CAAC,SAAS,CAAC,CA0B3B"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four agent routes, as declared in `backend/apps/agent/mdk-plugin.json`.
|
|
3
|
+
*
|
|
4
|
+
* POST /agent/sessions -> { sessionId }
|
|
5
|
+
* POST /agent/sessions/:id/messages -> text/event-stream
|
|
6
|
+
* POST /agent/sessions/:id/approvals/:approvalId -> { approvalId, approved }
|
|
7
|
+
* DELETE /agent/sessions/:id -> { sessionId, deleted }
|
|
8
|
+
*
|
|
9
|
+
* Note the approval route is session-scoped. `backend/core/agent/docs/CONTRACT.md`
|
|
10
|
+
* documents it as `/agent/turns/{turnId}/approvals/{approvalId}`; that is stale —
|
|
11
|
+
* `turnId` appears in no URL.
|
|
12
|
+
*
|
|
13
|
+
* The gateway sends no CORS headers, and the stream route calls `rep.hijack()` so
|
|
14
|
+
* no CORS hook could decorate it even if one existed. Callers must be same-origin
|
|
15
|
+
* (served from `staticRootPath`) or proxied (`/agent` in the dev server).
|
|
16
|
+
*/
|
|
17
|
+
import { readAgentStream } from './sse';
|
|
18
|
+
export const AGENT_ROUTE_PREFIX = '/agent';
|
|
19
|
+
/** The `ERR_*` codes these routes can return. */
|
|
20
|
+
export const AGENT_ERROR = {
|
|
21
|
+
SESSION_NOT_FOUND: 'ERR_AGENT_SESSION_NOT_FOUND',
|
|
22
|
+
TURN_ACTIVE: 'ERR_AGENT_TURN_ACTIVE',
|
|
23
|
+
TEXT_REQUIRED: 'ERR_AGENT_MESSAGE_TEXT_REQUIRED',
|
|
24
|
+
UNAVAILABLE: 'ERR_AGENT_UNAVAILABLE',
|
|
25
|
+
APPROVAL_NOT_FOUND: 'ERR_AGENT_APPROVAL_NOT_FOUND',
|
|
26
|
+
};
|
|
27
|
+
/** A gateway error carrying the `ERR_*` code the UI branches on. */
|
|
28
|
+
export class AgentApiError extends Error {
|
|
29
|
+
status;
|
|
30
|
+
code;
|
|
31
|
+
constructor(status, code, message) {
|
|
32
|
+
super(message ?? code);
|
|
33
|
+
this.name = 'AgentApiError';
|
|
34
|
+
this.status = status;
|
|
35
|
+
this.code = code;
|
|
36
|
+
}
|
|
37
|
+
is(code) {
|
|
38
|
+
return this.code === code;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Trimmed with a scan rather than /\/+$/: the regex backtracks quadratically on a long run
|
|
42
|
+
// of trailing slashes, which CodeQL flags as a polynomial ReDoS (js/polynomial-redos).
|
|
43
|
+
function stripTrailingSlashes(value) {
|
|
44
|
+
let end = value.length;
|
|
45
|
+
while (end > 0 && value[end - 1] === '/')
|
|
46
|
+
end--;
|
|
47
|
+
return value.slice(0, end);
|
|
48
|
+
}
|
|
49
|
+
function joinUrl(baseUrl, path) {
|
|
50
|
+
if (!baseUrl)
|
|
51
|
+
return path;
|
|
52
|
+
return `${stripTrailingSlashes(baseUrl)}${path}`;
|
|
53
|
+
}
|
|
54
|
+
async function buildHeaders(options, extra) {
|
|
55
|
+
const headers = new Headers(extra);
|
|
56
|
+
const token = await options.getToken?.();
|
|
57
|
+
if (token)
|
|
58
|
+
headers.set('authorization', `Bearer ${token}`);
|
|
59
|
+
return headers;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Both error body shapes, reduced to a code.
|
|
63
|
+
*
|
|
64
|
+
* Normal routes answer `{ statusCode, error, message }`; the streaming route
|
|
65
|
+
* answers `{ statusCode, message }` with no `error` key at all. Either way the
|
|
66
|
+
* `ERR_*` code is in `message`. `ERR_AGENT_UNAVAILABLE` additionally has its
|
|
67
|
+
* reason concatenated in (`"ERR_AGENT_UNAVAILABLE: config.agent missing"`), so
|
|
68
|
+
* the code is only the part before the colon.
|
|
69
|
+
*/
|
|
70
|
+
async function toApiError(response) {
|
|
71
|
+
let message = response.statusText;
|
|
72
|
+
try {
|
|
73
|
+
const body = (await response.json());
|
|
74
|
+
if (typeof body?.message === 'string')
|
|
75
|
+
message = body.message;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Non-JSON body (or none). The status alone still identifies the failure.
|
|
79
|
+
}
|
|
80
|
+
const code = message.split(':')[0]?.trim() || `HTTP_${response.status}`;
|
|
81
|
+
return new AgentApiError(response.status, code, message);
|
|
82
|
+
}
|
|
83
|
+
async function requestJson(path, init, options) {
|
|
84
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
85
|
+
const response = await fetchImpl(joinUrl(options.baseUrl, path), init);
|
|
86
|
+
if (!response.ok)
|
|
87
|
+
throw await toApiError(response);
|
|
88
|
+
return (await response.json());
|
|
89
|
+
}
|
|
90
|
+
/** Identity comes from the token, so the request body is ignored by the gateway. */
|
|
91
|
+
export async function createSession(options = {}) {
|
|
92
|
+
const headers = await buildHeaders(options, { 'content-type': 'application/json' });
|
|
93
|
+
const body = await requestJson(`${AGENT_ROUTE_PREFIX}/sessions`, { method: 'POST', headers, body: '{}' }, options);
|
|
94
|
+
return body.sessionId;
|
|
95
|
+
}
|
|
96
|
+
export async function deleteSession(sessionId, options = {}) {
|
|
97
|
+
const headers = await buildHeaders(options);
|
|
98
|
+
await requestJson(`${AGENT_ROUTE_PREFIX}/sessions/${encodeURIComponent(sessionId)}`, { method: 'DELETE', headers }, options);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Answers a paused approval. The decision travels on its own request while the
|
|
102
|
+
* message stream stays open — the stream resumes on its own once this lands.
|
|
103
|
+
*
|
|
104
|
+
* The gateway tests `approved === true`, so anything else is a rejection. It is
|
|
105
|
+
* passed through as a real boolean rather than coerced, to keep that explicit.
|
|
106
|
+
*
|
|
107
|
+
* A decision that arrives after the approval timed out, or a second decision for
|
|
108
|
+
* the same approval, is a 404 `ERR_AGENT_APPROVAL_NOT_FOUND` — the two are
|
|
109
|
+
* deliberately indistinguishable. Callers should treat it as "already settled",
|
|
110
|
+
* not as a failure.
|
|
111
|
+
*/
|
|
112
|
+
export async function decideApproval(sessionId, approvalId, approved, options = {}) {
|
|
113
|
+
const headers = await buildHeaders(options, { 'content-type': 'application/json' });
|
|
114
|
+
await requestJson(`${AGENT_ROUTE_PREFIX}/sessions/${encodeURIComponent(sessionId)}`
|
|
115
|
+
+ `/approvals/${encodeURIComponent(approvalId)}`, { method: 'POST', headers, body: JSON.stringify({ approved }) }, options);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Sends one message and yields its events until the turn ends.
|
|
119
|
+
*
|
|
120
|
+
* Only one turn may be in flight per session; a second send while this is
|
|
121
|
+
* running — including while it is paused on an approval, since a paused turn
|
|
122
|
+
* still holds the session busy — throws `ERR_AGENT_TURN_ACTIVE`.
|
|
123
|
+
*/
|
|
124
|
+
export async function* streamTurn(sessionId, text, options = {}) {
|
|
125
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
126
|
+
const headers = await buildHeaders(options, {
|
|
127
|
+
'content-type': 'application/json',
|
|
128
|
+
'accept': 'text/event-stream',
|
|
129
|
+
});
|
|
130
|
+
const response = await fetchImpl(joinUrl(options.baseUrl, `${AGENT_ROUTE_PREFIX}/sessions/${encodeURIComponent(sessionId)}/messages`), { method: 'POST', headers, body: JSON.stringify({ text }), signal: options.signal });
|
|
131
|
+
// 404 / 409 / 400 are all raised before the SSE headers go out, so they arrive
|
|
132
|
+
// as an ordinary JSON body rather than as an event on the stream.
|
|
133
|
+
if (!response.ok)
|
|
134
|
+
throw await toApiError(response);
|
|
135
|
+
if (!response.body)
|
|
136
|
+
throw new AgentApiError(response.status, 'ERR_AGENT_STREAM_EMPTY');
|
|
137
|
+
yield* readAgentStream(response.body, options.signal, {
|
|
138
|
+
...(options.idleTimeoutMs === undefined ? {} : { idleTimeoutMs: options.idleTimeoutMs }),
|
|
139
|
+
...(options.approvalIdleTimeoutMs === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: { approvalIdleTimeoutMs: options.approvalIdleTimeoutMs }),
|
|
142
|
+
...(options.firstEventIdleTimeoutMs === undefined
|
|
143
|
+
? {}
|
|
144
|
+
: { firstEventIdleTimeoutMs: options.firstEventIdleTimeoutMs }),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/core/transport.ts"],"names":[],"mappings":"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"}
|