@mitralab.io/platform-sdk 1.1.3 → 1.1.5-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/CHANGELOG.md +136 -96
- package/README.md +28 -5
- package/dist/index.cjs +68 -22
- package/dist/index.d.cts +25 -15
- package/dist/index.d.ts +25 -15
- package/dist/index.js +68 -22
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,96 +1,136 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project are documented in this file.
|
|
4
|
-
|
|
5
|
-
## 1.1.
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
`
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- Depend on `@mitralab.io/sdk-core@0.2.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
## 1.
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
## 1.0.
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
## 1.1.5-beta.0
|
|
6
|
+
|
|
7
|
+
- The eight `agentCredentials` methods take a trailing `{ scope: "ACCOUNT" }`, sent as the
|
|
8
|
+
`scope=ACCOUNT` query parameter, and `session({ create: true })` and `agentTasks.create()`
|
|
9
|
+
accept `scope: "ACCOUNT"` in the create body, so the credential and the chat resolve against
|
|
10
|
+
the person's own account instead of the app. Without `scope` nothing changes on the wire. The
|
|
11
|
+
Copilot honors `ACCOUNT` only for apps listed by flag and answers
|
|
12
|
+
`ACCOUNT_CREDENTIAL_NOT_ALLOWED` otherwise.
|
|
13
|
+
- Depend on `@mitralab.io/sdk-core@0.2.5-beta.0`, which carries the `scope` option through the
|
|
14
|
+
credential calls and into the create request and exports `AgentCredentialScope` and
|
|
15
|
+
`AgentCredentialOptions`.
|
|
16
|
+
|
|
17
|
+
## 1.1.4-beta.0
|
|
18
|
+
|
|
19
|
+
- On the direct channel the message and the interrupt are written on the box socket, as the
|
|
20
|
+
client frames the box already reads, instead of `POST /copilot/api/v1/tasks/{id}/inputs`. The
|
|
21
|
+
box asks the Copilot for admission itself and answers on the same socket, so the Copilot's host
|
|
22
|
+
socket buffer no longer bounds the message: the only limit is the box channel's own. REST stays
|
|
23
|
+
for a chat with no box socket, for a socket not open at the moment of the send, a redial in
|
|
24
|
+
progress included, and for every approval answer. A frame written on a socket that closes
|
|
25
|
+
before the box acknowledges it is not resent over REST, since the box may have admitted the
|
|
26
|
+
turn already; the redial's replay recovers it.
|
|
27
|
+
|
|
28
|
+
## 1.1.3
|
|
29
|
+
|
|
30
|
+
- A chat created through `session({ create: true })` over the `auto` or `websocket` transport is
|
|
31
|
+
born on the T3 box: the create request carries `runtime: "T3"`. A chat created with
|
|
32
|
+
`transport: "http"` stays on the runner, and an explicit `runtime` is forwarded as given.
|
|
33
|
+
- The box channel is asked for once. The Copilot now holds the channel request while the box
|
|
34
|
+
boots, so the 2 s polling on a 202 answer is gone; a 202 from an older Copilot means the chat
|
|
35
|
+
follows the Copilot socket.
|
|
36
|
+
- Depend on `@mitralab.io/sdk-core@0.2.4`, which carries the `runtime` session option into the
|
|
37
|
+
create request, exports `AgentTaskRuntime`, and sends a prompt whose task already exists even
|
|
38
|
+
when the session was closed inside its `taskCreated` handler.
|
|
39
|
+
|
|
40
|
+
## 1.2.0-beta.1
|
|
41
|
+
|
|
42
|
+
- Add `signInWithEmail()`: the platform auth page collects the address and the one-time code, and
|
|
43
|
+
the single-use exchange code it returns is redeemed at IAM's `/auth/magic-link/exchange` for the
|
|
44
|
+
same app session Google and Microsoft SSO already produce.
|
|
45
|
+
- Add `completeEmailSignInRedirect()`, which finishes both the mobile redirect and the tab opened
|
|
46
|
+
by the link in the message.
|
|
47
|
+
- Keep the pending email request, the one-time state and the auth page URL and never a token, in
|
|
48
|
+
`localStorage` for 10 minutes, so the tab opened by the link in the message finishes the flow
|
|
49
|
+
through the same state check the redirect uses. Writing it is best effort for a popup and
|
|
50
|
+
required for a redirect.
|
|
51
|
+
- Consume a fragment of the flow's own provider even when it cannot be completed, so a rejected or
|
|
52
|
+
expired redirect is reported once instead of on every reload. A fragment of another flow stays
|
|
53
|
+
untouched, and a pending request is still dropped only when it expires.
|
|
54
|
+
- Name the flow in the one-time state (`google.<random>`, `microsoft.<random>`, `email.<random>`),
|
|
55
|
+
which the auth page echoes verbatim, so every `complete*SignInRedirect()` recognizes its own
|
|
56
|
+
fragment: a fragment from another method returns `null` untouched, whatever this browser has
|
|
57
|
+
pending, and an application that offers all three can call all three at startup in any order. A
|
|
58
|
+
fragment that names this flow without matching its pending request is rejected as forged.
|
|
59
|
+
- Generalize the auth page handshake into `AuthPageFlow`, parameterized by provider, exchange
|
|
60
|
+
route, and where the pending request lives, instead of a second copy for email.
|
|
61
|
+
- Upgrading mid-flow: a redirect started by an earlier version stored a state without the provider
|
|
62
|
+
name, so the completion after the upgrade returns `null` and the person signs in again. Nothing
|
|
63
|
+
is lost beyond that one attempt, and only for redirects in flight during the upgrade.
|
|
64
|
+
- Give each provider its own popup window name.
|
|
65
|
+
- Point the deprecated `signIn` and `signUp` failures at `signInWithEmail()`.
|
|
66
|
+
- Add `mitra.emailLoginEnabled`, read from `/info` during `init()` next to `allowSignup`, so an
|
|
67
|
+
application only offers "sign in with email" when this app is inside the platform's rollout.
|
|
68
|
+
A Code Studio older than the field answers without it, and any value that is not a boolean is
|
|
69
|
+
read as `false`, so `init()` keeps working and an app that cannot prove it is enabled stops
|
|
70
|
+
offering the option.
|
|
71
|
+
|
|
72
|
+
## 1.1.2
|
|
73
|
+
|
|
74
|
+
- Move the `@mitralab.io/sdk-core` pin from `0.2.1` to `0.2.2`: same surface, published with the
|
|
75
|
+
contract corpus that consumers pin, so every SDK released that day sits on the same core.
|
|
76
|
+
|
|
77
|
+
## 1.1.1
|
|
78
|
+
|
|
79
|
+
- Depend on `@mitralab.io/sdk-core@0.2.1`, which replays `textChunk` and late deltas after an
|
|
80
|
+
interrupted turn.
|
|
81
|
+
- Serve the Agent chat from the T3 box over the direct channel when the Copilot offers it.
|
|
82
|
+
- Treat a half-open Agent session channel as a disconnect instead of a live one.
|
|
83
|
+
|
|
84
|
+
## 1.1.0-beta.2
|
|
85
|
+
|
|
86
|
+
`1.1.0-beta.1` was published from `main` before this change landed, so it still depends on Core `0.2.0-beta.0`; use `1.1.0-beta.2`.
|
|
87
|
+
|
|
88
|
+
- Depend on `@mitralab.io/sdk-core@0.2.0-beta.1`, which reads back integration configs with a
|
|
89
|
+
null `templateId` (configs born from an inline definition). The browser adapter still only
|
|
90
|
+
lists and executes integration configs; authoring stays in the studio SDK and the MCP.
|
|
91
|
+
|
|
92
|
+
## 1.1.0-beta.0
|
|
93
|
+
|
|
94
|
+
- Complete native Function sync, async, polling, cancellation, and anonymous public execution.
|
|
95
|
+
- Expose browser-safe Agent Tasks, restricted Agent Credentials, and model discovery through Core 0.2 contracts.
|
|
96
|
+
- Compose the Core-owned Agent task session manager with Platform WebSocket and HTTP/SSE adapters.
|
|
97
|
+
- Add native anonymous polling for executions created by the public async Function route.
|
|
98
|
+
- Keep business-Agent administration out of the browser adapter according to the app-role permission matrix.
|
|
99
|
+
- Expose app-scoped integration config listing and execution by alias from Core 0.2.
|
|
100
|
+
- Document the missing producer contract for native record selection by `jdbcConnectionConfigId` instead of inventing a browser-side translation.
|
|
101
|
+
- Document that entity `update` already implements the producer's partial PUT semantics, so no duplicate PATCH method is needed.
|
|
102
|
+
- Derive Function execution, integration proxy input, and custom query result types directly from Core without narrowing nullable or producer-returned fields.
|
|
103
|
+
- Preserve the complete Data Manager record envelope and execute Custom Queries with only
|
|
104
|
+
producer parameters, without a caller-selected Data Source or an `init()` precondition.
|
|
105
|
+
|
|
106
|
+
- Refresh app sessions proactively through IAM before authenticated native requests, with a 30-second JWT expiry heuristic and one shared refresh flight.
|
|
107
|
+
- Preserve sessions on transient refresh failures, clear them on definitive IAM client failures, and retain the one-time reactive `401` retry.
|
|
108
|
+
- Rotate both tokens without fetching the current user or notifying public auth-state listeners, while keeping the legacy bridge synchronized.
|
|
109
|
+
- Reject decodable access and refresh tokens whose app scope is missing or differs from the configured app while keeping opaque tokens server-authoritative.
|
|
110
|
+
- Fence refresh responses by session generation so late success or failure cannot undo sign-out or overwrite a newer login or bridged session.
|
|
111
|
+
- Bind reactive `401` handling to the token used by the rejected request so an old response cannot refresh or clear a replacement session.
|
|
112
|
+
- Redact values under sensitive credential field names from recursive API error details.
|
|
113
|
+
- Preserve the retained session when `auth.me()` reaches `401` after transient proactive and reactive refresh failures.
|
|
114
|
+
- Add native Google SSO through popup and redirect flows with direct IAM code exchange.
|
|
115
|
+
- Validate Google SSO origin, popup source, one-time state, cancellation, timeout, and token response shape.
|
|
116
|
+
- Require redirect errors to bind to the stored state before exposing or consuming them.
|
|
117
|
+
- Keep Google options limited to popup or redirect mode; account creation and locale remain producer concerns.
|
|
118
|
+
- Leave legacy-only `returnTo` and `title` on the deprecated aliases because the old runtime did not implement them as native Google controls.
|
|
119
|
+
- Preserve the email/password methods already public in Platform SDK 1.0.9 without presenting them as the new template flow.
|
|
120
|
+
- Route deprecated calls and legacy authentication through `${apiUrl}/legacy`.
|
|
121
|
+
- Apply the native auth page URL precedence to the deprecated SSO bridge.
|
|
122
|
+
- Propagate native sign-in, refresh, token changes, and sign-out to the legacy SDK session.
|
|
123
|
+
- Re-export the deprecated `mitra-interactions-sdk` surface from the package entrypoint.
|
|
124
|
+
- Mark every legacy type alias as deprecated in generated declarations.
|
|
125
|
+
- Share one session between this SDK and the legacy SDK in both directions.
|
|
126
|
+
- Make the SonarCloud job wait for the Quality Gate result.
|
|
127
|
+
- Align the public package metadata and ESM, CommonJS, and TypeScript artifacts.
|
|
128
|
+
- Add package shape checks and public tarball smoke coverage.
|
|
129
|
+
- Correct public imports and required configuration in documentation examples.
|
|
130
|
+
- Add the MIT license.
|
|
131
|
+
|
|
132
|
+
## 1.0.8
|
|
133
|
+
|
|
134
|
+
- Share environment-neutral API contracts through `@mitralab.io/sdk-core`.
|
|
135
|
+
- Preserve the Platform SDK 1.x browser authentication and entity facade.
|
|
136
|
+
- Validate redirects, API errors, sensitive-value redaction, and package consumers.
|
package/README.md
CHANGED
|
@@ -30,10 +30,10 @@ await mitra.init()
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
`init()` resolves the application's public Code Studio configuration, including nullable
|
|
33
|
-
`dataSourceId` and `
|
|
34
|
-
compatibility flow; native Entities and Custom Queries resolve the current app through
|
|
35
|
-
authenticated request. Call `init()` during application startup before the compatibility
|
|
36
|
-
method needs `allowSignup`.
|
|
33
|
+
`dataSourceId`, `allowSignup`, and `emailLoginEnabled`. The Data Source value remains part of the
|
|
34
|
+
Platform 1.x compatibility flow; native Entities and Custom Queries resolve the current app through
|
|
35
|
+
the authenticated request. Call `init()` during application startup before the compatibility
|
|
36
|
+
sign-up method needs `allowSignup` or the login screen needs `emailLoginEnabled`.
|
|
37
37
|
|
|
38
38
|
## Configuration
|
|
39
39
|
|
|
@@ -169,6 +169,23 @@ the app session SSO already returns, persisted and refreshed the same way:
|
|
|
169
169
|
const user = await mitra.auth.signInWithEmail()
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
+
Not every app is in the rollout. `mitra.emailLoginEnabled` is this app's own verdict, read from
|
|
173
|
+
`/info` during `init()`, and it is what a login screen should offer the option on:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
await mitra.init()
|
|
177
|
+
|
|
178
|
+
if (mitra.emailLoginEnabled) {
|
|
179
|
+
// render "sign in with email"
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
It is `false` before `init()` runs, `false` when the server answers without the field or with
|
|
184
|
+
something that is not a boolean, and `false` is the safe answer: the app is outside the rollout,
|
|
185
|
+
IAM answers a request neutrally without sending anything, and the person would wait for a message
|
|
186
|
+
that never arrives. Calling `signInWithEmail()` anyway is not blocked by the SDK; the verdict is
|
|
187
|
+
there so the application does not offer a door that does not open.
|
|
188
|
+
|
|
172
189
|
Redirect mode navigates the current page instead of opening a popup, and is completed during
|
|
173
190
|
startup like the SSO redirect:
|
|
174
191
|
|
|
@@ -314,12 +331,18 @@ session.close()
|
|
|
314
331
|
|
|
315
332
|
A chat created with `create: true` over the `auto` or `websocket` transport is born on the T3 box (`runtime: "T3"` in the create request), so the first open does not wait for the box to adopt it; a chat created with `transport: "http"` stays on the Copilot runner. Pass `runtime: "RUNNER"` or `runtime: "T3"` to decide explicitly.
|
|
316
333
|
|
|
334
|
+
`session({ create: true, agentId, scope: "ACCOUNT" })` and `agentTasks.create({ agentType, agentId, scope: "ACCOUNT" })` send `scope` in the create body, so the chat runs on the credential the person connected to their own account, the one the IDE and the builder read, instead of the agent's connection. The Copilot honors `ACCOUNT` only for apps listed by flag and answers `ACCOUNT_CREDENTIAL_NOT_ALLOWED` otherwise; a turn without a credential on the account fails with `ACCOUNT_CREDENTIAL_MISSING`. Through `agentTasks.session(...)` those refusals reach the session `error` event with the message and code the Copilot sends; through `agentTasks.create()` and the `agentCredentials` methods they reject the promise with a `MitraApiError` carrying status and code. No platform session is involved: the app token is used as always. Without `scope` nothing changes.
|
|
335
|
+
|
|
317
336
|
Open an existing task with `session({ taskId })`. The default `auto` transport refreshes before connecting, asks the Copilot once where the chat is served, and opens whichever channel it names: the box that runs the agent when one is offered, `/copilot/ws/tasks/{taskId}` otherwise. The Copilot holds that request while the box boots and answers only once the box is ready or cannot be had; the SDK does not poll. The choice belongs to the server, never to application configuration, so a Copilot that stops offering the box leaves every application on the Copilot socket without a republish. Opening the box never asks it to replay, whether the conversation is new to the session or is being opened again after an idle close: what an idle conversation missed is history, which the application loads over REST. A box socket that drops in the middle of a turn is redialed by the SDK itself, with a bounded backoff (1, 2, 4, 8 and 16 seconds) and the replay from the last position seen on that socket, so the answer keeps streaming; a position taken on one box is forgotten when the Copilot points the conversation to another box; replayed `textChunk` frames reach the `delta` event like live text. While that happens the session emits `raw` events of type `channelReconnecting` (payload `attempt`, `maxAttempts`, `reason`) and `channelConnected` (payload `attempt`); the session `status` stays `streaming`, because Core has no reconnecting status. The disconnect reaches Core, and with it the `error` event, only when the attempts run out or the Copilot no longer offers the box. A drop with no turn in flight, a channel taken over by another tab (close code 4409), and any close of the Copilot socket the session did not ask for are reported at once, whatever the code, so the next send reopens the channel instead of waiting on a socket that is gone. Recovery through persisted history plus the HTTP/SSE channel is unchanged. Set `transport: "http"` when WebSockets are unavailable. Messages sent during a turn enter a FIFO queue with a maximum of 10 items; the session also exposes edit, remove, clear, approval, cancel, history, close, and typed events.
|
|
318
337
|
|
|
338
|
+
On the direct channel the message and the interrupt are written on the box socket itself, as the frames the box reads from a client: `{ "type": "message", "content", "agentType"?, "reasoningEffort"? }` and `{ "type": "interrupt" }`. The box asks the Copilot to admit the turn and the Copilot records the history; the admission, its refusal and the turn itself come back on that same socket as the events the session already handles, so a message the box refuses surfaces through the `error` event with the box's code. `POST /copilot/api/v1/tasks/{taskId}/inputs` is the path when there is no box socket: a chat served by the Copilot socket or by SSE, a box socket that is not open at the moment of the send (a drop being redialed included), and every approval answer. A frame written on a socket that closes before the box acknowledges it is not sent again over REST, because the box may already have admitted the turn; the redial replays the box log, as it does for a turn started over REST.
|
|
339
|
+
|
|
319
340
|
A prompt sent while the browser says it is offline (`navigator.onLine === false`) does not enter Core at all, because Core opens the channel and reads the turn baseline before the prompt goes out and every one of those requests would fail first: the session keeps the prompt in an outbox, emits a `raw` event of type `inputUnsent` (payload `attempt` 0, `reason`, `waitingForOnline` true) and hands it to Core, in order, when the browser fires `online`; the turn starts then. A prompt whose `POST /inputs` went out but got no response at all is kept the same way: the session sends the same request again when the browser fires `online` or on a bounded backoff (2, 5, 10, 20 and 40 seconds), while the turn stays `streaming`, with `inputUnsent` events (payload `attempt`, `reason`, `waitingForOnline`, `retryInMs` when a timer is armed) and, once it goes through, `inputSent` (payload `attempts`). A response from the server, an error included, is never retried: the prompt fails through the `error` event as before. A session closed with a prompt still waiting emits `error` with code `INPUT_UNSENT` before it goes quiet, and `sendAndWait` rejects. The retry cannot tell a request the server never received from one whose response was lost on the way back, so a prompt may reach the server twice in that case; the Copilot's `/inputs` accepts no client message id yet. The public `agentTasks.sendInput` primitive is not held back: it fails immediately, as it always did.
|
|
320
341
|
|
|
321
342
|
API keys and removal accept `ANTHROPIC` or `OPENAI`. OAuth accepts only `ANTHROPIC`; device authorization accepts only `OPENAI`. The facade enforces those producer-supported pairs in TypeScript and at runtime.
|
|
322
343
|
|
|
344
|
+
Every `agentCredentials` method takes a trailing `options` with `scope: "ACCOUNT"`, sent as the `scope` query parameter, so the credential is read from or written to the person's own account instead of the app: `startOAuth("ANTHROPIC", { scope: "ACCOUNT" })`, `exchangeOAuth("ANTHROPIC", input, { scope: "ACCOUNT" })`, `list({ scope: "ACCOUNT" })`. The Copilot honors `ACCOUNT` only for apps listed by flag and answers `ACCOUNT_CREDENTIAL_NOT_ALLOWED` otherwise. No platform session is involved: the app token is used as always. Without `options` the request is the same as before.
|
|
345
|
+
|
|
323
346
|
The browser token roles expose Agent tasks, credential status, and model discovery. Administrative business-Agent CRUD is intentionally not exposed by this adapter because the `USE` app role does not carry `AGENT_*` authority.
|
|
324
347
|
|
|
325
348
|
## Custom queries
|
|
@@ -392,7 +415,7 @@ await loginWithGoogleMitra()
|
|
|
392
415
|
console.log(mitra.auth.accessToken)
|
|
393
416
|
```
|
|
394
417
|
|
|
395
|
-
Google
|
|
418
|
+
Google, Microsoft and e-mail sign-in have native replacements: `mitra.auth.signInWithGoogle`, `mitra.auth.signInWithMicrosoft` and `mitra.auth.signInWithEmail`, each with its `complete...SignInRedirect` counterpart. Agent tasks, Agent credentials, public Functions, entities, custom queries, Function execution, and integrations also have native replacements. Only `loginMitra('mitra')` still has no native equivalent and remains available through the deprecated re-export surface.
|
|
396
419
|
|
|
397
420
|
`createClient` configures the legacy SDK with both `baseURL` and `authUrl` set to `${apiUrl}/legacy`, after removing trailing slashes, plus `projectId: appId`. This keeps deprecated calls and legacy login routed through the BFF while the new modules call their native APIs directly. Its `authPageUrl` uses the same precedence as native Google SSO: explicit client config, `window.__mitraEnv.authPageUrl`, then `/sdk-auth.html` on the `apiUrl` origin. Existing query parameters are preserved.
|
|
398
421
|
|
package/dist/index.cjs
CHANGED
|
@@ -1811,6 +1811,7 @@ var CONNECT_TIMEOUT_MS = 15e3;
|
|
|
1811
1811
|
var SILENCE_TIMEOUT_MS = 6e4;
|
|
1812
1812
|
var RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3];
|
|
1813
1813
|
var SUPERSEDED_CLOSE_CODE = 4409;
|
|
1814
|
+
var SOCKET_OPEN = 1;
|
|
1814
1815
|
var SilenceWatchdog = class {
|
|
1815
1816
|
constructor(onSilence) {
|
|
1816
1817
|
this.onSilence = onSilence;
|
|
@@ -1926,6 +1927,8 @@ var BrowserAgentTaskEventSource = class {
|
|
|
1926
1927
|
*/
|
|
1927
1928
|
boxCursors = /* @__PURE__ */ new Map();
|
|
1928
1929
|
boxAddresses = /* @__PURE__ */ new Map();
|
|
1930
|
+
/** The box socket a task is talking on right now; absent while it is lost or being redialed. */
|
|
1931
|
+
directSockets = /* @__PURE__ */ new Map();
|
|
1929
1932
|
async open(taskId, observer, signal, transport = "auto") {
|
|
1930
1933
|
if (transport === "http") return this.openSse(taskId, observer, signal);
|
|
1931
1934
|
if (transport === "websocket") return this.openWebSocket(taskId, observer, signal);
|
|
@@ -1957,6 +1960,23 @@ var BrowserAgentTaskEventSource = class {
|
|
|
1957
1960
|
}
|
|
1958
1961
|
};
|
|
1959
1962
|
}
|
|
1963
|
+
/**
|
|
1964
|
+
* Writes a message or an interrupt on the box socket when the task is on the direct channel
|
|
1965
|
+
* and that socket is open right now. The box accepts the core's input as its own inbound
|
|
1966
|
+
* frame, asks the copilot for admission itself and answers on this same socket with the
|
|
1967
|
+
* frames the observer already reads, so the copilot's host socket is off the message path.
|
|
1968
|
+
* False sends the caller to REST: no direct channel, a socket lost or mid-redial, or an
|
|
1969
|
+
* approval, which stays on REST as it is.
|
|
1970
|
+
*
|
|
1971
|
+
* A frame written on a socket that closes before the box acknowledges it is not sent again
|
|
1972
|
+
* over REST: the box may have admitted the turn already, and a second copy would start it
|
|
1973
|
+
* twice. The redial replays the box log, which is the same recovery a REST 202 gets when its
|
|
1974
|
+
* turn is lost.
|
|
1975
|
+
*/
|
|
1976
|
+
sendOnChannel(taskId, input) {
|
|
1977
|
+
if (input.type === "approval_response") return false;
|
|
1978
|
+
return this.directSockets.get(taskId)?.send(JSON.stringify(input)) ?? false;
|
|
1979
|
+
}
|
|
1960
1980
|
async requireFreshToken() {
|
|
1961
1981
|
const fresh = await this.auth.ensureFreshSession();
|
|
1962
1982
|
const token = this.auth.accessToken;
|
|
@@ -2043,6 +2063,11 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2043
2063
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2044
2064
|
let inTurn = false;
|
|
2045
2065
|
let current = null;
|
|
2066
|
+
const track = (socket) => {
|
|
2067
|
+
if (socket) this.directSockets.set(taskId, socket);
|
|
2068
|
+
else if (current && this.directSockets.get(taskId) === current) this.directSockets.delete(taskId);
|
|
2069
|
+
current = socket;
|
|
2070
|
+
};
|
|
2046
2071
|
const onFrame = (event) => {
|
|
2047
2072
|
if (typeof event.sequence === "number") {
|
|
2048
2073
|
const seen = this.boxCursors.get(taskId) ?? 0;
|
|
@@ -2052,22 +2077,21 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2052
2077
|
observer.onEvent(event);
|
|
2053
2078
|
};
|
|
2054
2079
|
const onLost = (error, code) => {
|
|
2055
|
-
|
|
2080
|
+
track(null);
|
|
2056
2081
|
if (link.signal.aborted) return;
|
|
2057
2082
|
if (!inTurn || code === SUPERSEDED_CLOSE_CODE) {
|
|
2058
2083
|
observer.onDisconnect(error);
|
|
2059
2084
|
return;
|
|
2060
2085
|
}
|
|
2061
|
-
void this.redial(taskId, error, link.signal, observer, { onFrame, onLost }).then(
|
|
2062
|
-
current = socket;
|
|
2063
|
-
});
|
|
2086
|
+
void this.redial(taskId, error, link.signal, observer, { onFrame, onLost }).then(track);
|
|
2064
2087
|
};
|
|
2065
|
-
|
|
2088
|
+
track(await this.dial(channel.wsUrl, { signal: link.signal, onFrame, onLost }));
|
|
2066
2089
|
return {
|
|
2067
2090
|
close: () => {
|
|
2068
2091
|
signal?.removeEventListener("abort", onAbort);
|
|
2069
2092
|
link.abort();
|
|
2070
2093
|
current?.close();
|
|
2094
|
+
track(null);
|
|
2071
2095
|
}
|
|
2072
2096
|
};
|
|
2073
2097
|
}
|
|
@@ -2152,6 +2176,15 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2152
2176
|
removeAbortListener();
|
|
2153
2177
|
socket.close(1e3, "Client closed");
|
|
2154
2178
|
};
|
|
2179
|
+
const send = (frame) => {
|
|
2180
|
+
if (intentionalClose || socket.readyState !== SOCKET_OPEN) return false;
|
|
2181
|
+
try {
|
|
2182
|
+
socket.send(frame);
|
|
2183
|
+
return true;
|
|
2184
|
+
} catch {
|
|
2185
|
+
return false;
|
|
2186
|
+
}
|
|
2187
|
+
};
|
|
2155
2188
|
const onAbort = () => {
|
|
2156
2189
|
if (!opened) {
|
|
2157
2190
|
rejectHandshake(signal?.reason instanceof Error ? signal.reason : new Error("Agent WebSocket connection aborted."));
|
|
@@ -2175,7 +2208,7 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2175
2208
|
} catch {
|
|
2176
2209
|
}
|
|
2177
2210
|
}
|
|
2178
|
-
resolve({ close });
|
|
2211
|
+
resolve({ close, send });
|
|
2179
2212
|
};
|
|
2180
2213
|
socket.onerror = () => {
|
|
2181
2214
|
if (!opened) rejectHandshake(new Error("Failed to connect to the Agent WebSocket."));
|
|
@@ -2311,7 +2344,10 @@ function createBrowserAgentTasksModule(httpClient, auth, apiUrl) {
|
|
|
2311
2344
|
}
|
|
2312
2345
|
};
|
|
2313
2346
|
const manager = (0, import_sdk_core8.createAgentTaskSessionManager)({
|
|
2314
|
-
tasks: {
|
|
2347
|
+
tasks: {
|
|
2348
|
+
...tasks,
|
|
2349
|
+
sendInput: (taskId, input) => source.sendOnChannel(taskId, input) ? Promise.resolve() : outbox.sendInput(taskId, input)
|
|
2350
|
+
},
|
|
2315
2351
|
eventSource
|
|
2316
2352
|
});
|
|
2317
2353
|
return (0, import_sdk_core8.withAgentTaskSessions)(tasks, {
|
|
@@ -2329,31 +2365,31 @@ function requireProvider(provider, allowed, flow) {
|
|
|
2329
2365
|
function createBrowserAgentCredentialsModule(httpClient) {
|
|
2330
2366
|
const core = (0, import_sdk_core9.createAgentCredentialsModule)(httpClient, coreErrors);
|
|
2331
2367
|
return {
|
|
2332
|
-
list: () => core.list(),
|
|
2333
|
-
listModels: (agentId) => core.listModels(agentId),
|
|
2334
|
-
saveApiKey: (provider, apiKey) => {
|
|
2368
|
+
list: (options) => core.list(options),
|
|
2369
|
+
listModels: (agentId, options) => core.listModels(agentId, options),
|
|
2370
|
+
saveApiKey: (provider, apiKey, options) => {
|
|
2335
2371
|
requireProvider(provider, ["ANTHROPIC", "OPENAI"], "API key authentication");
|
|
2336
|
-
return core.saveApiKey(provider, apiKey);
|
|
2372
|
+
return core.saveApiKey(provider, apiKey, options);
|
|
2337
2373
|
},
|
|
2338
|
-
remove: (provider) => {
|
|
2374
|
+
remove: (provider, options) => {
|
|
2339
2375
|
requireProvider(provider, ["ANTHROPIC", "OPENAI"], "Credential removal");
|
|
2340
|
-
return core.remove(provider);
|
|
2376
|
+
return core.remove(provider, options);
|
|
2341
2377
|
},
|
|
2342
|
-
startOAuth: (provider) => {
|
|
2378
|
+
startOAuth: (provider, options) => {
|
|
2343
2379
|
requireProvider(provider, ["ANTHROPIC"], "OAuth");
|
|
2344
|
-
return core.startOAuth(provider);
|
|
2380
|
+
return core.startOAuth(provider, options);
|
|
2345
2381
|
},
|
|
2346
|
-
exchangeOAuth: (provider, input) => {
|
|
2382
|
+
exchangeOAuth: (provider, input, options) => {
|
|
2347
2383
|
requireProvider(provider, ["ANTHROPIC"], "OAuth");
|
|
2348
|
-
return core.exchangeOAuth(provider, input);
|
|
2384
|
+
return core.exchangeOAuth(provider, input, options);
|
|
2349
2385
|
},
|
|
2350
|
-
startDeviceAuthorization: (provider) => {
|
|
2386
|
+
startDeviceAuthorization: (provider, options) => {
|
|
2351
2387
|
requireProvider(provider, ["OPENAI"], "Device authorization");
|
|
2352
|
-
return core.startDeviceAuthorization(provider);
|
|
2388
|
+
return core.startDeviceAuthorization(provider, options);
|
|
2353
2389
|
},
|
|
2354
|
-
pollDeviceAuthorization: (provider, deviceAuthId) => {
|
|
2390
|
+
pollDeviceAuthorization: (provider, deviceAuthId, options) => {
|
|
2355
2391
|
requireProvider(provider, ["OPENAI"], "Device authorization");
|
|
2356
|
-
return core.pollDeviceAuthorization(provider, deviceAuthId);
|
|
2392
|
+
return core.pollDeviceAuthorization(provider, deviceAuthId, options);
|
|
2357
2393
|
}
|
|
2358
2394
|
};
|
|
2359
2395
|
}
|
|
@@ -2377,7 +2413,12 @@ function expectAppInfoResponse(value) {
|
|
|
2377
2413
|
}
|
|
2378
2414
|
return {
|
|
2379
2415
|
dataSourceId: response.dataSourceId,
|
|
2380
|
-
allowSignup: response.allowSignup
|
|
2416
|
+
allowSignup: response.allowSignup,
|
|
2417
|
+
// Unlike the fields above, a missing or non-boolean value is read as `false`
|
|
2418
|
+
// instead of failing `init()`: a Code Studio older than the email login gate
|
|
2419
|
+
// answers without this field, and an app that cannot prove it is enabled
|
|
2420
|
+
// should stop offering the option, not stop starting.
|
|
2421
|
+
emailLoginEnabled: response.emailLoginEnabled === true
|
|
2381
2422
|
};
|
|
2382
2423
|
}
|
|
2383
2424
|
function createClient(config) {
|
|
@@ -2445,6 +2486,7 @@ function createClient(config) {
|
|
|
2445
2486
|
legacyBridge.connect();
|
|
2446
2487
|
let initialized = false;
|
|
2447
2488
|
let allowSignup = true;
|
|
2489
|
+
let emailLoginEnabled = false;
|
|
2448
2490
|
async function init() {
|
|
2449
2491
|
if (initialized) return;
|
|
2450
2492
|
const publicClient = new HttpClient({
|
|
@@ -2460,6 +2502,7 @@ function createClient(config) {
|
|
|
2460
2502
|
entitiesModule.setDataSourceId(appInfo.dataSourceId);
|
|
2461
2503
|
}
|
|
2462
2504
|
allowSignup = appInfo.allowSignup;
|
|
2505
|
+
emailLoginEnabled = appInfo.emailLoginEnabled;
|
|
2463
2506
|
initialized = true;
|
|
2464
2507
|
}
|
|
2465
2508
|
return {
|
|
@@ -2475,6 +2518,9 @@ function createClient(config) {
|
|
|
2475
2518
|
get allowSignup() {
|
|
2476
2519
|
return allowSignup;
|
|
2477
2520
|
},
|
|
2521
|
+
get emailLoginEnabled() {
|
|
2522
|
+
return emailLoginEnabled;
|
|
2523
|
+
},
|
|
2478
2524
|
config
|
|
2479
2525
|
};
|
|
2480
2526
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Transport, TransportRequestOptions, QueryParamValue, EntityTable, FunctionExecution, ListTemplateConfigsOptions, TemplateConfigPage, ProxyResult, ProxyInput, QueryResult, CredentialStatus, AgentModel as AgentModel$1, OAuthStartResult, OAuthExchangeInput, AuthenticationResult, DeviceAuthorization, PublicFunctionsModule, AgentTasksWithSessions } from '@mitralab.io/sdk-core';
|
|
2
|
-
export { AgentQueueItem, AgentSendAndWaitOptions, AgentSendOptions, AgentSessionTransport, AgentTask, AgentTaskCreateInput, AgentTaskInput, AgentTaskListOptions, AgentTaskRuntime, AgentTaskSessionEventMap, AgentTaskSessionOptions, AgentTaskSessionStatus, AgentTurnResult, AuthenticationResult, CredentialStatus, DeviceAuthorization, EntityListOptions, EntityTable, ExistingAgentTaskSessionOptions, FunctionExecution, ListTemplateConfigsOptions, AgentMessage as NativeAgentMessage, AgentModel as NativeAgentModel, AgentTaskSession as NativeAgentTaskSession, AgentTimelineItem as NativeAgentTimelineItem, AgentToolEvent as NativeAgentToolEvent, NewAgentTaskSessionOptions, OAuthExchangeInput, OAuthStartResult, Page, PageOptions, ProxyInput, ProxyResult, PublicFunctionAsyncResult, PublicFunctionResult, PublicFunctionsModule, QueryResult, TemplateConfigPage } from '@mitralab.io/sdk-core';
|
|
1
|
+
import { Transport, TransportRequestOptions, QueryParamValue, EntityTable, FunctionExecution, ListTemplateConfigsOptions, TemplateConfigPage, ProxyResult, ProxyInput, QueryResult, AgentCredentialOptions, CredentialStatus, AgentModel as AgentModel$1, OAuthStartResult, OAuthExchangeInput, AuthenticationResult, DeviceAuthorization, PublicFunctionsModule, AgentTasksWithSessions } from '@mitralab.io/sdk-core';
|
|
2
|
+
export { AgentCredentialOptions, AgentCredentialScope, AgentQueueItem, AgentSendAndWaitOptions, AgentSendOptions, AgentSessionTransport, AgentTask, AgentTaskCreateInput, AgentTaskInput, AgentTaskListOptions, AgentTaskRuntime, AgentTaskSessionEventMap, AgentTaskSessionOptions, AgentTaskSessionStatus, AgentTurnResult, AuthenticationResult, CredentialStatus, DeviceAuthorization, EntityListOptions, EntityTable, ExistingAgentTaskSessionOptions, FunctionExecution, ListTemplateConfigsOptions, AgentMessage as NativeAgentMessage, AgentModel as NativeAgentModel, AgentTaskSession as NativeAgentTaskSession, AgentTimelineItem as NativeAgentTimelineItem, AgentToolEvent as NativeAgentToolEvent, NewAgentTaskSessionOptions, OAuthExchangeInput, OAuthStartResult, Page, PageOptions, ProxyInput, ProxyResult, PublicFunctionAsyncResult, PublicFunctionResult, PublicFunctionsModule, QueryResult, TemplateConfigPage } from '@mitralab.io/sdk-core';
|
|
3
3
|
import * as LegacyTypes from 'mitra-interactions-sdk';
|
|
4
4
|
import { exchangeSsoCodeMitra as exchangeSsoCodeMitra$1, loginMitra as loginMitra$1, loginWithGoogleMitra as loginWithGoogleMitra$1, loginWithMicrosoftMitra as loginWithMicrosoftMitra$1 } from 'mitra-interactions-sdk';
|
|
5
5
|
export { callIntegrationMitra, configureSdkMitra, createMitraInstance, createRecordMitra, createRecordsBatchMitra, deleteRecordMitra, executePublicServerFunctionAsyncMitra, executePublicServerFunctionMitra, executeServerFunctionAsyncMitra, executeServerFunctionMitra, getAgentTaskMitra, getConfig, getPublicServerFunctionExecutionMitra, getRecordMitra, listIntegrationsMitra, listRecordsMitra, manageAgentChatMitra, manageAgentCredentialMitra, patchRecordMitra, refreshTokenSilently, resolveProjectId, stopServerFunctionExecutionMitra, updateRecordMitra } from 'mitra-interactions-sdk';
|
|
@@ -652,14 +652,14 @@ type AgentCredentialProvider = 'ANTHROPIC' | 'OPENAI';
|
|
|
652
652
|
type AgentOAuthProvider = 'ANTHROPIC';
|
|
653
653
|
type AgentDeviceProvider = 'OPENAI';
|
|
654
654
|
interface AgentCredentialsModule {
|
|
655
|
-
list(): Promise<CredentialStatus[]>;
|
|
656
|
-
listModels(agentId?: string): Promise<AgentModel$1[]>;
|
|
657
|
-
saveApiKey(provider: AgentCredentialProvider, apiKey: string): Promise<void>;
|
|
658
|
-
remove(provider: AgentCredentialProvider): Promise<void>;
|
|
659
|
-
startOAuth(provider: AgentOAuthProvider): Promise<OAuthStartResult>;
|
|
660
|
-
exchangeOAuth(provider: AgentOAuthProvider, input: OAuthExchangeInput): Promise<AuthenticationResult>;
|
|
661
|
-
startDeviceAuthorization(provider: AgentDeviceProvider): Promise<DeviceAuthorization>;
|
|
662
|
-
pollDeviceAuthorization(provider: AgentDeviceProvider, deviceAuthId: string): Promise<AuthenticationResult>;
|
|
655
|
+
list(options?: AgentCredentialOptions): Promise<CredentialStatus[]>;
|
|
656
|
+
listModels(agentId?: string, options?: AgentCredentialOptions): Promise<AgentModel$1[]>;
|
|
657
|
+
saveApiKey(provider: AgentCredentialProvider, apiKey: string, options?: AgentCredentialOptions): Promise<void>;
|
|
658
|
+
remove(provider: AgentCredentialProvider, options?: AgentCredentialOptions): Promise<void>;
|
|
659
|
+
startOAuth(provider: AgentOAuthProvider, options?: AgentCredentialOptions): Promise<OAuthStartResult>;
|
|
660
|
+
exchangeOAuth(provider: AgentOAuthProvider, input: OAuthExchangeInput, options?: AgentCredentialOptions): Promise<AuthenticationResult>;
|
|
661
|
+
startDeviceAuthorization(provider: AgentDeviceProvider, options?: AgentCredentialOptions): Promise<DeviceAuthorization>;
|
|
662
|
+
pollDeviceAuthorization(provider: AgentDeviceProvider, deviceAuthId: string, options?: AgentCredentialOptions): Promise<AuthenticationResult>;
|
|
663
663
|
}
|
|
664
664
|
|
|
665
665
|
/**
|
|
@@ -741,7 +741,8 @@ interface MitraClient {
|
|
|
741
741
|
/**
|
|
742
742
|
* Initializes the client by resolving app config from the server.
|
|
743
743
|
*
|
|
744
|
-
* Fetches the compatibility dataSourceId
|
|
744
|
+
* Fetches the compatibility dataSourceId, allowSignup, and emailLoginEnabled
|
|
745
|
+
* from the public app info endpoint.
|
|
745
746
|
*
|
|
746
747
|
* Safe to call multiple times. Subsequent calls are no-ops.
|
|
747
748
|
*
|
|
@@ -827,6 +828,13 @@ interface MitraClient {
|
|
|
827
828
|
* Defaults to `true` before `init()` is called.
|
|
828
829
|
*/
|
|
829
830
|
readonly allowSignup: boolean;
|
|
831
|
+
/**
|
|
832
|
+
* Whether this app offers sign-in by email, so the application can hide the
|
|
833
|
+
* option instead of sending people to a request IAM would answer neutrally.
|
|
834
|
+
* Defaults to `false` before `init()` is called, and stays `false` when the
|
|
835
|
+
* server does not answer the field.
|
|
836
|
+
*/
|
|
837
|
+
readonly emailLoginEnabled: boolean;
|
|
830
838
|
/**
|
|
831
839
|
* The configuration used to create this client.
|
|
832
840
|
*/
|
|
@@ -842,8 +850,8 @@ interface MitraClient {
|
|
|
842
850
|
* - **integration**: Proxy HTTP requests to external APIs
|
|
843
851
|
* - **queries**: Custom query management and execution
|
|
844
852
|
*
|
|
845
|
-
* After creating the client, call `init()` to resolve the app's
|
|
846
|
-
* (dataSourceId, allowSignup) automatically from the server.
|
|
853
|
+
* After creating the client, call `init()` to resolve the app's public config
|
|
854
|
+
* (dataSourceId, allowSignup, emailLoginEnabled) automatically from the server.
|
|
847
855
|
*
|
|
848
856
|
* @param config - Configuration options for the client.
|
|
849
857
|
* @returns A configured MitraClient instance.
|
|
@@ -895,8 +903,10 @@ declare function createClient(config: MitraClientConfig): MitraClient;
|
|
|
895
903
|
*/
|
|
896
904
|
|
|
897
905
|
/**
|
|
898
|
-
* @deprecated Use `mitra.auth.signInWithGoogle()` when `method` is
|
|
899
|
-
*
|
|
906
|
+
* @deprecated Use `mitra.auth.signInWithGoogle()` when `method` is `google`,
|
|
907
|
+
* `mitra.auth.signInWithMicrosoft()` when it is `microsoft`, and
|
|
908
|
+
* `mitra.auth.signInWithEmail()` when it is `email`. Only `mitra` has no native
|
|
909
|
+
* equivalent yet and remains supported through this surface.
|
|
900
910
|
*/
|
|
901
911
|
declare const loginMitra: typeof loginMitra$1;
|
|
902
912
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Transport, TransportRequestOptions, QueryParamValue, EntityTable, FunctionExecution, ListTemplateConfigsOptions, TemplateConfigPage, ProxyResult, ProxyInput, QueryResult, CredentialStatus, AgentModel as AgentModel$1, OAuthStartResult, OAuthExchangeInput, AuthenticationResult, DeviceAuthorization, PublicFunctionsModule, AgentTasksWithSessions } from '@mitralab.io/sdk-core';
|
|
2
|
-
export { AgentQueueItem, AgentSendAndWaitOptions, AgentSendOptions, AgentSessionTransport, AgentTask, AgentTaskCreateInput, AgentTaskInput, AgentTaskListOptions, AgentTaskRuntime, AgentTaskSessionEventMap, AgentTaskSessionOptions, AgentTaskSessionStatus, AgentTurnResult, AuthenticationResult, CredentialStatus, DeviceAuthorization, EntityListOptions, EntityTable, ExistingAgentTaskSessionOptions, FunctionExecution, ListTemplateConfigsOptions, AgentMessage as NativeAgentMessage, AgentModel as NativeAgentModel, AgentTaskSession as NativeAgentTaskSession, AgentTimelineItem as NativeAgentTimelineItem, AgentToolEvent as NativeAgentToolEvent, NewAgentTaskSessionOptions, OAuthExchangeInput, OAuthStartResult, Page, PageOptions, ProxyInput, ProxyResult, PublicFunctionAsyncResult, PublicFunctionResult, PublicFunctionsModule, QueryResult, TemplateConfigPage } from '@mitralab.io/sdk-core';
|
|
1
|
+
import { Transport, TransportRequestOptions, QueryParamValue, EntityTable, FunctionExecution, ListTemplateConfigsOptions, TemplateConfigPage, ProxyResult, ProxyInput, QueryResult, AgentCredentialOptions, CredentialStatus, AgentModel as AgentModel$1, OAuthStartResult, OAuthExchangeInput, AuthenticationResult, DeviceAuthorization, PublicFunctionsModule, AgentTasksWithSessions } from '@mitralab.io/sdk-core';
|
|
2
|
+
export { AgentCredentialOptions, AgentCredentialScope, AgentQueueItem, AgentSendAndWaitOptions, AgentSendOptions, AgentSessionTransport, AgentTask, AgentTaskCreateInput, AgentTaskInput, AgentTaskListOptions, AgentTaskRuntime, AgentTaskSessionEventMap, AgentTaskSessionOptions, AgentTaskSessionStatus, AgentTurnResult, AuthenticationResult, CredentialStatus, DeviceAuthorization, EntityListOptions, EntityTable, ExistingAgentTaskSessionOptions, FunctionExecution, ListTemplateConfigsOptions, AgentMessage as NativeAgentMessage, AgentModel as NativeAgentModel, AgentTaskSession as NativeAgentTaskSession, AgentTimelineItem as NativeAgentTimelineItem, AgentToolEvent as NativeAgentToolEvent, NewAgentTaskSessionOptions, OAuthExchangeInput, OAuthStartResult, Page, PageOptions, ProxyInput, ProxyResult, PublicFunctionAsyncResult, PublicFunctionResult, PublicFunctionsModule, QueryResult, TemplateConfigPage } from '@mitralab.io/sdk-core';
|
|
3
3
|
import * as LegacyTypes from 'mitra-interactions-sdk';
|
|
4
4
|
import { exchangeSsoCodeMitra as exchangeSsoCodeMitra$1, loginMitra as loginMitra$1, loginWithGoogleMitra as loginWithGoogleMitra$1, loginWithMicrosoftMitra as loginWithMicrosoftMitra$1 } from 'mitra-interactions-sdk';
|
|
5
5
|
export { callIntegrationMitra, configureSdkMitra, createMitraInstance, createRecordMitra, createRecordsBatchMitra, deleteRecordMitra, executePublicServerFunctionAsyncMitra, executePublicServerFunctionMitra, executeServerFunctionAsyncMitra, executeServerFunctionMitra, getAgentTaskMitra, getConfig, getPublicServerFunctionExecutionMitra, getRecordMitra, listIntegrationsMitra, listRecordsMitra, manageAgentChatMitra, manageAgentCredentialMitra, patchRecordMitra, refreshTokenSilently, resolveProjectId, stopServerFunctionExecutionMitra, updateRecordMitra } from 'mitra-interactions-sdk';
|
|
@@ -652,14 +652,14 @@ type AgentCredentialProvider = 'ANTHROPIC' | 'OPENAI';
|
|
|
652
652
|
type AgentOAuthProvider = 'ANTHROPIC';
|
|
653
653
|
type AgentDeviceProvider = 'OPENAI';
|
|
654
654
|
interface AgentCredentialsModule {
|
|
655
|
-
list(): Promise<CredentialStatus[]>;
|
|
656
|
-
listModels(agentId?: string): Promise<AgentModel$1[]>;
|
|
657
|
-
saveApiKey(provider: AgentCredentialProvider, apiKey: string): Promise<void>;
|
|
658
|
-
remove(provider: AgentCredentialProvider): Promise<void>;
|
|
659
|
-
startOAuth(provider: AgentOAuthProvider): Promise<OAuthStartResult>;
|
|
660
|
-
exchangeOAuth(provider: AgentOAuthProvider, input: OAuthExchangeInput): Promise<AuthenticationResult>;
|
|
661
|
-
startDeviceAuthorization(provider: AgentDeviceProvider): Promise<DeviceAuthorization>;
|
|
662
|
-
pollDeviceAuthorization(provider: AgentDeviceProvider, deviceAuthId: string): Promise<AuthenticationResult>;
|
|
655
|
+
list(options?: AgentCredentialOptions): Promise<CredentialStatus[]>;
|
|
656
|
+
listModels(agentId?: string, options?: AgentCredentialOptions): Promise<AgentModel$1[]>;
|
|
657
|
+
saveApiKey(provider: AgentCredentialProvider, apiKey: string, options?: AgentCredentialOptions): Promise<void>;
|
|
658
|
+
remove(provider: AgentCredentialProvider, options?: AgentCredentialOptions): Promise<void>;
|
|
659
|
+
startOAuth(provider: AgentOAuthProvider, options?: AgentCredentialOptions): Promise<OAuthStartResult>;
|
|
660
|
+
exchangeOAuth(provider: AgentOAuthProvider, input: OAuthExchangeInput, options?: AgentCredentialOptions): Promise<AuthenticationResult>;
|
|
661
|
+
startDeviceAuthorization(provider: AgentDeviceProvider, options?: AgentCredentialOptions): Promise<DeviceAuthorization>;
|
|
662
|
+
pollDeviceAuthorization(provider: AgentDeviceProvider, deviceAuthId: string, options?: AgentCredentialOptions): Promise<AuthenticationResult>;
|
|
663
663
|
}
|
|
664
664
|
|
|
665
665
|
/**
|
|
@@ -741,7 +741,8 @@ interface MitraClient {
|
|
|
741
741
|
/**
|
|
742
742
|
* Initializes the client by resolving app config from the server.
|
|
743
743
|
*
|
|
744
|
-
* Fetches the compatibility dataSourceId
|
|
744
|
+
* Fetches the compatibility dataSourceId, allowSignup, and emailLoginEnabled
|
|
745
|
+
* from the public app info endpoint.
|
|
745
746
|
*
|
|
746
747
|
* Safe to call multiple times. Subsequent calls are no-ops.
|
|
747
748
|
*
|
|
@@ -827,6 +828,13 @@ interface MitraClient {
|
|
|
827
828
|
* Defaults to `true` before `init()` is called.
|
|
828
829
|
*/
|
|
829
830
|
readonly allowSignup: boolean;
|
|
831
|
+
/**
|
|
832
|
+
* Whether this app offers sign-in by email, so the application can hide the
|
|
833
|
+
* option instead of sending people to a request IAM would answer neutrally.
|
|
834
|
+
* Defaults to `false` before `init()` is called, and stays `false` when the
|
|
835
|
+
* server does not answer the field.
|
|
836
|
+
*/
|
|
837
|
+
readonly emailLoginEnabled: boolean;
|
|
830
838
|
/**
|
|
831
839
|
* The configuration used to create this client.
|
|
832
840
|
*/
|
|
@@ -842,8 +850,8 @@ interface MitraClient {
|
|
|
842
850
|
* - **integration**: Proxy HTTP requests to external APIs
|
|
843
851
|
* - **queries**: Custom query management and execution
|
|
844
852
|
*
|
|
845
|
-
* After creating the client, call `init()` to resolve the app's
|
|
846
|
-
* (dataSourceId, allowSignup) automatically from the server.
|
|
853
|
+
* After creating the client, call `init()` to resolve the app's public config
|
|
854
|
+
* (dataSourceId, allowSignup, emailLoginEnabled) automatically from the server.
|
|
847
855
|
*
|
|
848
856
|
* @param config - Configuration options for the client.
|
|
849
857
|
* @returns A configured MitraClient instance.
|
|
@@ -895,8 +903,10 @@ declare function createClient(config: MitraClientConfig): MitraClient;
|
|
|
895
903
|
*/
|
|
896
904
|
|
|
897
905
|
/**
|
|
898
|
-
* @deprecated Use `mitra.auth.signInWithGoogle()` when `method` is
|
|
899
|
-
*
|
|
906
|
+
* @deprecated Use `mitra.auth.signInWithGoogle()` when `method` is `google`,
|
|
907
|
+
* `mitra.auth.signInWithMicrosoft()` when it is `microsoft`, and
|
|
908
|
+
* `mitra.auth.signInWithEmail()` when it is `email`. Only `mitra` has no native
|
|
909
|
+
* equivalent yet and remains supported through this surface.
|
|
900
910
|
*/
|
|
901
911
|
declare const loginMitra: typeof loginMitra$1;
|
|
902
912
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1774,6 +1774,7 @@ var CONNECT_TIMEOUT_MS = 15e3;
|
|
|
1774
1774
|
var SILENCE_TIMEOUT_MS = 6e4;
|
|
1775
1775
|
var RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3];
|
|
1776
1776
|
var SUPERSEDED_CLOSE_CODE = 4409;
|
|
1777
|
+
var SOCKET_OPEN = 1;
|
|
1777
1778
|
var SilenceWatchdog = class {
|
|
1778
1779
|
constructor(onSilence) {
|
|
1779
1780
|
this.onSilence = onSilence;
|
|
@@ -1889,6 +1890,8 @@ var BrowserAgentTaskEventSource = class {
|
|
|
1889
1890
|
*/
|
|
1890
1891
|
boxCursors = /* @__PURE__ */ new Map();
|
|
1891
1892
|
boxAddresses = /* @__PURE__ */ new Map();
|
|
1893
|
+
/** The box socket a task is talking on right now; absent while it is lost or being redialed. */
|
|
1894
|
+
directSockets = /* @__PURE__ */ new Map();
|
|
1892
1895
|
async open(taskId, observer, signal, transport = "auto") {
|
|
1893
1896
|
if (transport === "http") return this.openSse(taskId, observer, signal);
|
|
1894
1897
|
if (transport === "websocket") return this.openWebSocket(taskId, observer, signal);
|
|
@@ -1920,6 +1923,23 @@ var BrowserAgentTaskEventSource = class {
|
|
|
1920
1923
|
}
|
|
1921
1924
|
};
|
|
1922
1925
|
}
|
|
1926
|
+
/**
|
|
1927
|
+
* Writes a message or an interrupt on the box socket when the task is on the direct channel
|
|
1928
|
+
* and that socket is open right now. The box accepts the core's input as its own inbound
|
|
1929
|
+
* frame, asks the copilot for admission itself and answers on this same socket with the
|
|
1930
|
+
* frames the observer already reads, so the copilot's host socket is off the message path.
|
|
1931
|
+
* False sends the caller to REST: no direct channel, a socket lost or mid-redial, or an
|
|
1932
|
+
* approval, which stays on REST as it is.
|
|
1933
|
+
*
|
|
1934
|
+
* A frame written on a socket that closes before the box acknowledges it is not sent again
|
|
1935
|
+
* over REST: the box may have admitted the turn already, and a second copy would start it
|
|
1936
|
+
* twice. The redial replays the box log, which is the same recovery a REST 202 gets when its
|
|
1937
|
+
* turn is lost.
|
|
1938
|
+
*/
|
|
1939
|
+
sendOnChannel(taskId, input) {
|
|
1940
|
+
if (input.type === "approval_response") return false;
|
|
1941
|
+
return this.directSockets.get(taskId)?.send(JSON.stringify(input)) ?? false;
|
|
1942
|
+
}
|
|
1923
1943
|
async requireFreshToken() {
|
|
1924
1944
|
const fresh = await this.auth.ensureFreshSession();
|
|
1925
1945
|
const token = this.auth.accessToken;
|
|
@@ -2006,6 +2026,11 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2006
2026
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2007
2027
|
let inTurn = false;
|
|
2008
2028
|
let current = null;
|
|
2029
|
+
const track = (socket) => {
|
|
2030
|
+
if (socket) this.directSockets.set(taskId, socket);
|
|
2031
|
+
else if (current && this.directSockets.get(taskId) === current) this.directSockets.delete(taskId);
|
|
2032
|
+
current = socket;
|
|
2033
|
+
};
|
|
2009
2034
|
const onFrame = (event) => {
|
|
2010
2035
|
if (typeof event.sequence === "number") {
|
|
2011
2036
|
const seen = this.boxCursors.get(taskId) ?? 0;
|
|
@@ -2015,22 +2040,21 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2015
2040
|
observer.onEvent(event);
|
|
2016
2041
|
};
|
|
2017
2042
|
const onLost = (error, code) => {
|
|
2018
|
-
|
|
2043
|
+
track(null);
|
|
2019
2044
|
if (link.signal.aborted) return;
|
|
2020
2045
|
if (!inTurn || code === SUPERSEDED_CLOSE_CODE) {
|
|
2021
2046
|
observer.onDisconnect(error);
|
|
2022
2047
|
return;
|
|
2023
2048
|
}
|
|
2024
|
-
void this.redial(taskId, error, link.signal, observer, { onFrame, onLost }).then(
|
|
2025
|
-
current = socket;
|
|
2026
|
-
});
|
|
2049
|
+
void this.redial(taskId, error, link.signal, observer, { onFrame, onLost }).then(track);
|
|
2027
2050
|
};
|
|
2028
|
-
|
|
2051
|
+
track(await this.dial(channel.wsUrl, { signal: link.signal, onFrame, onLost }));
|
|
2029
2052
|
return {
|
|
2030
2053
|
close: () => {
|
|
2031
2054
|
signal?.removeEventListener("abort", onAbort);
|
|
2032
2055
|
link.abort();
|
|
2033
2056
|
current?.close();
|
|
2057
|
+
track(null);
|
|
2034
2058
|
}
|
|
2035
2059
|
};
|
|
2036
2060
|
}
|
|
@@ -2115,6 +2139,15 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2115
2139
|
removeAbortListener();
|
|
2116
2140
|
socket.close(1e3, "Client closed");
|
|
2117
2141
|
};
|
|
2142
|
+
const send = (frame) => {
|
|
2143
|
+
if (intentionalClose || socket.readyState !== SOCKET_OPEN) return false;
|
|
2144
|
+
try {
|
|
2145
|
+
socket.send(frame);
|
|
2146
|
+
return true;
|
|
2147
|
+
} catch {
|
|
2148
|
+
return false;
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2118
2151
|
const onAbort = () => {
|
|
2119
2152
|
if (!opened) {
|
|
2120
2153
|
rejectHandshake(signal?.reason instanceof Error ? signal.reason : new Error("Agent WebSocket connection aborted."));
|
|
@@ -2138,7 +2171,7 @@ var BrowserAgentTaskEventSource = class {
|
|
|
2138
2171
|
} catch {
|
|
2139
2172
|
}
|
|
2140
2173
|
}
|
|
2141
|
-
resolve({ close });
|
|
2174
|
+
resolve({ close, send });
|
|
2142
2175
|
};
|
|
2143
2176
|
socket.onerror = () => {
|
|
2144
2177
|
if (!opened) rejectHandshake(new Error("Failed to connect to the Agent WebSocket."));
|
|
@@ -2274,7 +2307,10 @@ function createBrowserAgentTasksModule(httpClient, auth, apiUrl) {
|
|
|
2274
2307
|
}
|
|
2275
2308
|
};
|
|
2276
2309
|
const manager = createAgentTaskSessionManager({
|
|
2277
|
-
tasks: {
|
|
2310
|
+
tasks: {
|
|
2311
|
+
...tasks,
|
|
2312
|
+
sendInput: (taskId, input) => source.sendOnChannel(taskId, input) ? Promise.resolve() : outbox.sendInput(taskId, input)
|
|
2313
|
+
},
|
|
2278
2314
|
eventSource
|
|
2279
2315
|
});
|
|
2280
2316
|
return withAgentTaskSessions(tasks, {
|
|
@@ -2294,31 +2330,31 @@ function requireProvider(provider, allowed, flow) {
|
|
|
2294
2330
|
function createBrowserAgentCredentialsModule(httpClient) {
|
|
2295
2331
|
const core = createAgentCredentialsModule(httpClient, coreErrors);
|
|
2296
2332
|
return {
|
|
2297
|
-
list: () => core.list(),
|
|
2298
|
-
listModels: (agentId) => core.listModels(agentId),
|
|
2299
|
-
saveApiKey: (provider, apiKey) => {
|
|
2333
|
+
list: (options) => core.list(options),
|
|
2334
|
+
listModels: (agentId, options) => core.listModels(agentId, options),
|
|
2335
|
+
saveApiKey: (provider, apiKey, options) => {
|
|
2300
2336
|
requireProvider(provider, ["ANTHROPIC", "OPENAI"], "API key authentication");
|
|
2301
|
-
return core.saveApiKey(provider, apiKey);
|
|
2337
|
+
return core.saveApiKey(provider, apiKey, options);
|
|
2302
2338
|
},
|
|
2303
|
-
remove: (provider) => {
|
|
2339
|
+
remove: (provider, options) => {
|
|
2304
2340
|
requireProvider(provider, ["ANTHROPIC", "OPENAI"], "Credential removal");
|
|
2305
|
-
return core.remove(provider);
|
|
2341
|
+
return core.remove(provider, options);
|
|
2306
2342
|
},
|
|
2307
|
-
startOAuth: (provider) => {
|
|
2343
|
+
startOAuth: (provider, options) => {
|
|
2308
2344
|
requireProvider(provider, ["ANTHROPIC"], "OAuth");
|
|
2309
|
-
return core.startOAuth(provider);
|
|
2345
|
+
return core.startOAuth(provider, options);
|
|
2310
2346
|
},
|
|
2311
|
-
exchangeOAuth: (provider, input) => {
|
|
2347
|
+
exchangeOAuth: (provider, input, options) => {
|
|
2312
2348
|
requireProvider(provider, ["ANTHROPIC"], "OAuth");
|
|
2313
|
-
return core.exchangeOAuth(provider, input);
|
|
2349
|
+
return core.exchangeOAuth(provider, input, options);
|
|
2314
2350
|
},
|
|
2315
|
-
startDeviceAuthorization: (provider) => {
|
|
2351
|
+
startDeviceAuthorization: (provider, options) => {
|
|
2316
2352
|
requireProvider(provider, ["OPENAI"], "Device authorization");
|
|
2317
|
-
return core.startDeviceAuthorization(provider);
|
|
2353
|
+
return core.startDeviceAuthorization(provider, options);
|
|
2318
2354
|
},
|
|
2319
|
-
pollDeviceAuthorization: (provider, deviceAuthId) => {
|
|
2355
|
+
pollDeviceAuthorization: (provider, deviceAuthId, options) => {
|
|
2320
2356
|
requireProvider(provider, ["OPENAI"], "Device authorization");
|
|
2321
|
-
return core.pollDeviceAuthorization(provider, deviceAuthId);
|
|
2357
|
+
return core.pollDeviceAuthorization(provider, deviceAuthId, options);
|
|
2322
2358
|
}
|
|
2323
2359
|
};
|
|
2324
2360
|
}
|
|
@@ -2342,7 +2378,12 @@ function expectAppInfoResponse(value) {
|
|
|
2342
2378
|
}
|
|
2343
2379
|
return {
|
|
2344
2380
|
dataSourceId: response.dataSourceId,
|
|
2345
|
-
allowSignup: response.allowSignup
|
|
2381
|
+
allowSignup: response.allowSignup,
|
|
2382
|
+
// Unlike the fields above, a missing or non-boolean value is read as `false`
|
|
2383
|
+
// instead of failing `init()`: a Code Studio older than the email login gate
|
|
2384
|
+
// answers without this field, and an app that cannot prove it is enabled
|
|
2385
|
+
// should stop offering the option, not stop starting.
|
|
2386
|
+
emailLoginEnabled: response.emailLoginEnabled === true
|
|
2346
2387
|
};
|
|
2347
2388
|
}
|
|
2348
2389
|
function createClient(config) {
|
|
@@ -2410,6 +2451,7 @@ function createClient(config) {
|
|
|
2410
2451
|
legacyBridge.connect();
|
|
2411
2452
|
let initialized = false;
|
|
2412
2453
|
let allowSignup = true;
|
|
2454
|
+
let emailLoginEnabled = false;
|
|
2413
2455
|
async function init() {
|
|
2414
2456
|
if (initialized) return;
|
|
2415
2457
|
const publicClient = new HttpClient({
|
|
@@ -2425,6 +2467,7 @@ function createClient(config) {
|
|
|
2425
2467
|
entitiesModule.setDataSourceId(appInfo.dataSourceId);
|
|
2426
2468
|
}
|
|
2427
2469
|
allowSignup = appInfo.allowSignup;
|
|
2470
|
+
emailLoginEnabled = appInfo.emailLoginEnabled;
|
|
2428
2471
|
initialized = true;
|
|
2429
2472
|
}
|
|
2430
2473
|
return {
|
|
@@ -2440,6 +2483,9 @@ function createClient(config) {
|
|
|
2440
2483
|
get allowSignup() {
|
|
2441
2484
|
return allowSignup;
|
|
2442
2485
|
},
|
|
2486
|
+
get emailLoginEnabled() {
|
|
2487
|
+
return emailLoginEnabled;
|
|
2488
|
+
},
|
|
2443
2489
|
config
|
|
2444
2490
|
};
|
|
2445
2491
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mitralab.io/platform-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5-beta.0",
|
|
4
4
|
"description": "JavaScript/TypeScript SDK for building apps on the Mitra Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"url": "https://github.com/mitralab-dev/mitra-platform-sdk/issues"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@mitralab.io/sdk-core": "0.2.
|
|
65
|
+
"@mitralab.io/sdk-core": "0.2.5-beta.0",
|
|
66
66
|
"mitra-interactions-sdk": "1.0.60-beta.48"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|