mitra-interactions-sdk 1.0.60-beta.41 → 1.0.60-beta.43

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/README.md CHANGED
@@ -87,6 +87,23 @@ const result = await loginWithMicrosoftMitra();
87
87
  // result: { token, baseURL, refreshToken }
88
88
  ```
89
89
 
90
+ `create` separa a intenção do SSO sem quebrar integrações existentes:
91
+
92
+ | Valor | Comportamento |
93
+ | --- | --- |
94
+ | omitido | Fluxo combinado compatível: autentica e cria o vínculo quando o app permite |
95
+ | `false` | Login estrito: exige acesso efetivo existente e nunca cria o vínculo |
96
+ | `true` | Signup explícito: cria o vínculo quando o app permite |
97
+
98
+ ```typescript
99
+ await loginWithGoogleMitra({ create: false }); // Entrar
100
+ await loginWithGoogleMitra({ create: true }); // Criar conta
101
+ ```
102
+
103
+ O login estrito pode retornar `APP_ACCESS_REQUIRED` quando não existe acesso ou
104
+ `APP_ACCESS_REVOKED` quando o vínculo foi desligado. Signup bloqueado retorna
105
+ `SIGNUP_NOT_ALLOWED`. O mesmo campo é preservado no modo redirect.
106
+
90
107
  ### Login via Redirect (mobile)
91
108
 
92
109
  No celular o popup vira aba — use `mode: 'redirect'`: a página de auth navega de volta pro app com `#codeMitra`/`#stateMitra` no fragment, e o app conclui com `exchangeSsoCodeMitra`.
@@ -284,13 +301,24 @@ const existing = getAgentTaskMitra({ taskId: 'uuid-da-task' });
284
301
  await existing.loadHistory({ limit: 50 });
285
302
  ```
286
303
 
287
- `getAgentTaskMitra({ create: true, agentType?, name?, agentId?, reasoningEffort?, transport? })` ou `getAgentTaskMitra({ taskId, transport? })`.
304
+ `getAgentTaskMitra({ create: true, agentType?, name?, agentId?, reasoningEffort?, transport?, userId? })` ou `getAgentTaskMitra({ taskId, transport?, userId? })`.
288
305
 
289
306
  **Agente autônomo**: a autonomia é **propriedade do AGENTE** (`autonomous` em `createAgentMitra`/`updateAgentMitra`, no `mitra-sdk`) — não existe flag na criação do chat. Ao criar um chat contra um agente autônomo (`getAgentTaskMitra({ create: true, agentId })`), o copilot deriva a autonomia do agente e o chat já nasce **sem dono** (`user_id NULL` — a dona é o agente), usando a connection anexada ao agente como credencial. Exige auth `AGENT_WRITE` (chave de SF ou token de app EDIT) — usuário business comum não abre chat autônomo. Depois de criado, dirigir/listar é igual ao chat normal (`getAgentTaskMitra({ taskId })`, `send`, `manageAgentChatMitra({ list, agentId })`).
290
307
 
291
308
  - `agentType` vem de `manageAgentCredentialMitra({ action: 'list_models' })` — ex.: `'ANTHROPIC_CLAUDE_OPUS'`, `'OPENAI_GPT5'`. Default: `'ANTHROPIC_CLAUDE_OPUS'`.
292
309
  - **`agentId`**: id de um agente business (CRUD via `mitra-sdk`: `listAgentsMitra` e família). A sessão sobe com o system prompt do agente e um token escopado — as tools enxergam só as Server Functions dele. **Sem `agentId`: sessão business sem agente** — sem system prompt e sem acesso às Server Functions (as tools recusam); não há adoção automática de agente único. Na prática, sempre passe `agentId`.
293
310
 
311
+ **Agir em nome do dono (`userId`)**: uma Server Function disparada por webhook/cron pode abrir e dirigir o chat de um usuário específico, em nome dele — o chat é normal, com dono; o turno roda com a identidade e a credencial do dono (connection do agente primeiro, senão a conta dele). Exige `AGENT_WRITE` no app (senão 403); o backend decide a autorização, a SDK só repassa. Tudo opcional: ausente = comportamento de sempre, byte a byte.
312
+
313
+ ```typescript
314
+ // SF reagindo a webhook: continua a thread da pessoa atendida
315
+ const task = getAgentTaskMitra({ create: true, agentId, userId: 'uuid-do-usuario' }); // chat nasce DELE
316
+ const dela = await manageAgentChatMitra({ action: 'list', userId: 'uuid-do-usuario' }); // chats DELA
317
+ const mesma = getAgentTaskMitra({ taskId, userId: 'uuid-do-usuario' }); // defensivo: 404 se o chat não for dela
318
+ ```
319
+
320
+ Erros nomeados: `403` sem `AGENT_WRITE`; `400 AUTONOMOUS_TASK_HAS_NO_OWNER` (userId + agente autônomo é contradição); `404` quando o `userId` defensivo não bate com o dono real. Nunca invente `userId` de texto do usuário — use o id do vínculo canal→usuário da sua aplicação.
321
+
294
322
  #### Propriedades (somente leitura)
295
323
 
296
324
  | Propriedade | Tipo | Descrição |
@@ -348,7 +376,18 @@ const { providers } = await manageAgentCredentialMitra({ action: 'list_providers
348
376
  const { models } = await manageAgentCredentialMitra({ action: 'list_models' });
349
377
  // AgentModel[]: { model, name, provider, agentType, reasoningOptions }
350
378
  // reasoningOptions = registro das intensidades válidas por modelo (variam por
351
- // harness) — monte o seletor de reasoning a partir DAQUI, nunca hardcode
379
+ // harness) — monte o seletor de reasoning a partir DAQUI, nunca hardcode.
380
+ // Round-trip: os valores vêm em minúsculo e são aceitos na entrada COMO ESTÃO.
381
+
382
+ // Com agentId: o que o PRÓXIMO TURNO daquele agente consegue rodar.
383
+ // Agente com connection → catálogo da connection, SEMPRE (é ela que roda o
384
+ // turno, mesmo que o caller tenha credencial própria). Sem connection →
385
+ // fallback pro catálogo da credencial do usuário.
386
+ const doAgente = await manageAgentCredentialMitra({ action: 'list_models', agentId: 'uuid-do-agente' });
387
+ // Erros nomeados (err.code, HTTP 400 — reaja pelo código):
388
+ // NO_CREDENTIAL_AVAILABLE → nenhuma credencial utilizável (nunca vem lista
389
+ // vazia nesse caso) — mande conectar um provider
390
+ // CONNECTION_NOT_FOUND → a connection do agente não existe mais
352
391
 
353
392
  // API key
354
393
  await manageAgentCredentialMitra({ action: 'save', target: 'openai', key: 'sk-...' });
package/dist/index.d.mts CHANGED
@@ -10,7 +10,12 @@ interface LoginOptions {
10
10
  mode?: 'popup' | 'redirect';
11
11
  /** URL de retorno após login com mode 'redirect'. A página de auth redirecionará de volta para esta URL com token nos query params. */
12
12
  returnTo?: string;
13
- /** Se true, abre o fluxo de criar conta em vez de login. */
13
+ /**
14
+ * Controls the SSO intent sent to POST /auth/{provider}.
15
+ * Omitted preserves the combined legacy behavior. `false` performs a strict
16
+ * login without creating app access. `true` performs signup and may create
17
+ * app access when signup is allowed.
18
+ */
14
19
  create?: boolean;
15
20
  /** Título exibido na página de auth (ex: nome da aplicação). */
16
21
  title?: string;
@@ -243,6 +248,11 @@ interface ManageAgentChatListOptions {
243
248
  projectId?: number | string;
244
249
  /** Filtra os chats de um agente business específico. Omitido = todos os chats. */
245
250
  agentId?: string;
251
+ /**
252
+ * Em nome de outro usuário (exige AGENT_WRITE no app; senão 403): lista os
253
+ * chats DELE em vez dos do caller. Omitido = chats de quem chama, como sempre.
254
+ */
255
+ userId?: string;
246
256
  /** Inclui só arquivados (true) ou só ativos (false, default). */
247
257
  archived?: boolean;
248
258
  /** Busca por título. */
@@ -308,6 +318,17 @@ interface GetAgentTaskCreateOptions {
308
318
  * automaticamente — não existe flag aqui; exige auth AGENT_WRITE.
309
319
  */
310
320
  agentId?: string;
321
+ /**
322
+ * Agir EM NOME do dono do chat (exige AGENT_WRITE no app; senão 403) — o
323
+ * chat nasce pertencendo a esse usuário e o turno roda com a identidade e a
324
+ * credencial DELE (connection do agente primeiro, senão a conta do dono).
325
+ * Uso típico: Server Function reagindo a webhook/cron/canal externo que
326
+ * continua a thread da pessoa atendida. NUNCA invente userId a partir de
327
+ * texto — use o id que a aplicação já tem no vínculo canal→usuário.
328
+ * Omitido = chat do caller, byte a byte como sempre.
329
+ * Com agente AUTÔNOMO é contradição: 400 AUTONOMOUS_TASK_HAS_NO_OWNER.
330
+ */
331
+ userId?: string;
311
332
  /** Transporte do prompt (default 'ws'). */
312
333
  transport?: AgentTaskTransport;
313
334
  }
@@ -318,6 +339,12 @@ interface GetAgentTaskOpenOptions {
318
339
  projectId?: number | string;
319
340
  /** Transporte do prompt (default 'ws'). */
320
341
  transport?: AgentTaskTransport;
342
+ /**
343
+ * Validação defensiva ao agir em nome do dono (AGENT_WRITE): viaja no
344
+ * readChat e nos inputs — o backend devolve 404 se o chat não pertencer a
345
+ * esse usuário. Omitido = contexto do caller.
346
+ */
347
+ userId?: string;
321
348
  }
322
349
  type GetAgentTaskOptions = GetAgentTaskCreateOptions | GetAgentTaskOpenOptions;
323
350
  type AgentTaskStatus = 'opening' | 'idle' | 'streaming' | 'cancelled' | 'error' | 'closed';
@@ -336,8 +363,9 @@ interface SendOptions {
336
363
  * Intensidade de reasoning DESTA mensagem. Valores válidos vêm SEMPRE do
337
364
  * registro `reasoningOptions` do modelo em list_models (variam por harness) —
338
365
  * nunca invente: valor fora do registro é recusado pelo copilot
339
- * (INVALID_REASONING_EFFORT). Sobrescreve o default da session; a SDK envia
340
- * em maiúsculo. Omitido = herda o default da abertura (ou o do backend).
366
+ * (INVALID_REASONING_EFFORT). Sobrescreve o default da session; round-trip —
367
+ * a SDK envia o valor COMO ESTÁ (minúsculo), sem normalizar. Omitido = herda
368
+ * o default da abertura (ou o do backend).
341
369
  */
342
370
  reasoningEffort?: string;
343
371
  /**
@@ -448,6 +476,8 @@ interface AgentModel {
448
476
  * ['none','minimal','low','medium','high','xhigh','max','ultra'].
449
477
  * A UI monta o seletor a partir DAQUI; valor fora do registro é recusado
450
478
  * pelo copilot (INVALID_REASONING_EFFORT).
479
+ * ROUND-TRIP: os valores vêm em minúsculo e são aceitos na entrada COMO
480
+ * ESTÃO — a SDK não normaliza (não maiusculize, não traduza).
451
481
  * ATENÇÃO: a lista de models vem VAZIA enquanto nenhuma credencial/connection
452
482
  * estiver conectada (o catálogo é escopado pelo que dá pra rodar) — o seletor
453
483
  * só existe depois de conectar um provider e escolher um modelo.
@@ -483,6 +513,7 @@ type ManageAgentCredentialOptions = {
483
513
  projectId?: number | string;
484
514
  } | {
485
515
  action: 'list_models';
516
+ agentId?: string;
486
517
  projectId?: number | string;
487
518
  } | {
488
519
  action: 'save';
@@ -656,7 +687,7 @@ declare function getAgentTaskMitra(options: GetAgentTaskOptions): AgentTaskSessi
656
687
  * Função ÚNICA `manageAgentCredentialMitra`, toda HTTP pela BFF no baseURL
657
688
  * normal (`/agentAiShortcut/*`) — herda fetchWithRefresh e o CORS do BFF:
658
689
  * - list_providers → GET /agentAiShortcut/listProviders?projectId=
659
- * - list_models → GET /agentAiShortcut/listModels?projectId=
690
+ * - list_models → GET /agentAiShortcut/listModels?projectId=&agentId= (agentId opcional)
660
691
  * - save → POST /agentAiShortcut/saveCredential {projectId, provider, key}
661
692
  * - remove → POST /agentAiShortcut/removeCredential {projectId, provider}
662
693
  * - auth → POST /agentAiShortcut/oauthStart {projectId, provider}
@@ -681,6 +712,7 @@ declare function manageAgentCredentialMitra(options: {
681
712
  }): Promise<ListAgentProvidersResult>;
682
713
  declare function manageAgentCredentialMitra(options: {
683
714
  action: 'list_models';
715
+ agentId?: string;
684
716
  projectId?: number | string;
685
717
  }): Promise<ListAgentModelsResult>;
686
718
  declare function manageAgentCredentialMitra(options: {
package/dist/index.d.ts CHANGED
@@ -10,7 +10,12 @@ interface LoginOptions {
10
10
  mode?: 'popup' | 'redirect';
11
11
  /** URL de retorno após login com mode 'redirect'. A página de auth redirecionará de volta para esta URL com token nos query params. */
12
12
  returnTo?: string;
13
- /** Se true, abre o fluxo de criar conta em vez de login. */
13
+ /**
14
+ * Controls the SSO intent sent to POST /auth/{provider}.
15
+ * Omitted preserves the combined legacy behavior. `false` performs a strict
16
+ * login without creating app access. `true` performs signup and may create
17
+ * app access when signup is allowed.
18
+ */
14
19
  create?: boolean;
15
20
  /** Título exibido na página de auth (ex: nome da aplicação). */
16
21
  title?: string;
@@ -243,6 +248,11 @@ interface ManageAgentChatListOptions {
243
248
  projectId?: number | string;
244
249
  /** Filtra os chats de um agente business específico. Omitido = todos os chats. */
245
250
  agentId?: string;
251
+ /**
252
+ * Em nome de outro usuário (exige AGENT_WRITE no app; senão 403): lista os
253
+ * chats DELE em vez dos do caller. Omitido = chats de quem chama, como sempre.
254
+ */
255
+ userId?: string;
246
256
  /** Inclui só arquivados (true) ou só ativos (false, default). */
247
257
  archived?: boolean;
248
258
  /** Busca por título. */
@@ -308,6 +318,17 @@ interface GetAgentTaskCreateOptions {
308
318
  * automaticamente — não existe flag aqui; exige auth AGENT_WRITE.
309
319
  */
310
320
  agentId?: string;
321
+ /**
322
+ * Agir EM NOME do dono do chat (exige AGENT_WRITE no app; senão 403) — o
323
+ * chat nasce pertencendo a esse usuário e o turno roda com a identidade e a
324
+ * credencial DELE (connection do agente primeiro, senão a conta do dono).
325
+ * Uso típico: Server Function reagindo a webhook/cron/canal externo que
326
+ * continua a thread da pessoa atendida. NUNCA invente userId a partir de
327
+ * texto — use o id que a aplicação já tem no vínculo canal→usuário.
328
+ * Omitido = chat do caller, byte a byte como sempre.
329
+ * Com agente AUTÔNOMO é contradição: 400 AUTONOMOUS_TASK_HAS_NO_OWNER.
330
+ */
331
+ userId?: string;
311
332
  /** Transporte do prompt (default 'ws'). */
312
333
  transport?: AgentTaskTransport;
313
334
  }
@@ -318,6 +339,12 @@ interface GetAgentTaskOpenOptions {
318
339
  projectId?: number | string;
319
340
  /** Transporte do prompt (default 'ws'). */
320
341
  transport?: AgentTaskTransport;
342
+ /**
343
+ * Validação defensiva ao agir em nome do dono (AGENT_WRITE): viaja no
344
+ * readChat e nos inputs — o backend devolve 404 se o chat não pertencer a
345
+ * esse usuário. Omitido = contexto do caller.
346
+ */
347
+ userId?: string;
321
348
  }
322
349
  type GetAgentTaskOptions = GetAgentTaskCreateOptions | GetAgentTaskOpenOptions;
323
350
  type AgentTaskStatus = 'opening' | 'idle' | 'streaming' | 'cancelled' | 'error' | 'closed';
@@ -336,8 +363,9 @@ interface SendOptions {
336
363
  * Intensidade de reasoning DESTA mensagem. Valores válidos vêm SEMPRE do
337
364
  * registro `reasoningOptions` do modelo em list_models (variam por harness) —
338
365
  * nunca invente: valor fora do registro é recusado pelo copilot
339
- * (INVALID_REASONING_EFFORT). Sobrescreve o default da session; a SDK envia
340
- * em maiúsculo. Omitido = herda o default da abertura (ou o do backend).
366
+ * (INVALID_REASONING_EFFORT). Sobrescreve o default da session; round-trip —
367
+ * a SDK envia o valor COMO ESTÁ (minúsculo), sem normalizar. Omitido = herda
368
+ * o default da abertura (ou o do backend).
341
369
  */
342
370
  reasoningEffort?: string;
343
371
  /**
@@ -448,6 +476,8 @@ interface AgentModel {
448
476
  * ['none','minimal','low','medium','high','xhigh','max','ultra'].
449
477
  * A UI monta o seletor a partir DAQUI; valor fora do registro é recusado
450
478
  * pelo copilot (INVALID_REASONING_EFFORT).
479
+ * ROUND-TRIP: os valores vêm em minúsculo e são aceitos na entrada COMO
480
+ * ESTÃO — a SDK não normaliza (não maiusculize, não traduza).
451
481
  * ATENÇÃO: a lista de models vem VAZIA enquanto nenhuma credencial/connection
452
482
  * estiver conectada (o catálogo é escopado pelo que dá pra rodar) — o seletor
453
483
  * só existe depois de conectar um provider e escolher um modelo.
@@ -483,6 +513,7 @@ type ManageAgentCredentialOptions = {
483
513
  projectId?: number | string;
484
514
  } | {
485
515
  action: 'list_models';
516
+ agentId?: string;
486
517
  projectId?: number | string;
487
518
  } | {
488
519
  action: 'save';
@@ -656,7 +687,7 @@ declare function getAgentTaskMitra(options: GetAgentTaskOptions): AgentTaskSessi
656
687
  * Função ÚNICA `manageAgentCredentialMitra`, toda HTTP pela BFF no baseURL
657
688
  * normal (`/agentAiShortcut/*`) — herda fetchWithRefresh e o CORS do BFF:
658
689
  * - list_providers → GET /agentAiShortcut/listProviders?projectId=
659
- * - list_models → GET /agentAiShortcut/listModels?projectId=
690
+ * - list_models → GET /agentAiShortcut/listModels?projectId=&agentId= (agentId opcional)
660
691
  * - save → POST /agentAiShortcut/saveCredential {projectId, provider, key}
661
692
  * - remove → POST /agentAiShortcut/removeCredential {projectId, provider}
662
693
  * - auth → POST /agentAiShortcut/oauthStart {projectId, provider}
@@ -681,6 +712,7 @@ declare function manageAgentCredentialMitra(options: {
681
712
  }): Promise<ListAgentProvidersResult>;
682
713
  declare function manageAgentCredentialMitra(options: {
683
714
  action: 'list_models';
715
+ agentId?: string;
684
716
  projectId?: number | string;
685
717
  }): Promise<ListAgentModelsResult>;
686
718
  declare function manageAgentCredentialMitra(options: {
package/dist/index.js CHANGED
@@ -86,11 +86,12 @@ function stripToOriginPath(url) {
86
86
  return url.split("?")[0].split("#")[0];
87
87
  }
88
88
  }
89
- async function exchangeSsoCode(authUrl, provider, code, redirectUri, projectId) {
89
+ async function exchangeSsoCode(authUrl, provider, code, redirectUri, projectId, create) {
90
90
  const data = await postBffAuth(buildBffAuthEndpoint(authUrl, `/${provider}`), {
91
91
  appId: String(projectId),
92
92
  code,
93
- redirectUri
93
+ redirectUri,
94
+ ...create !== void 0 ? { create } : {}
94
95
  });
95
96
  const response = {
96
97
  token: data.token,
@@ -229,7 +230,10 @@ async function loginWithProvider(provider, options) {
229
230
  const startUrl = buildStartUrl(authPageUrl, provider, state, appId, authUrl);
230
231
  const { code, token } = await openOAuthPopup(startUrl, pageOrigin, state);
231
232
  if (code) {
232
- return await exchangeSsoCode(authUrl, provider, code, redirectUri, projectId);
233
+ return await exchangeSsoCode(authUrl, provider, code, redirectUri, projectId, options == null ? void 0 : options.create);
234
+ }
235
+ if ((options == null ? void 0 : options.create) !== void 0) {
236
+ throw new Error("Explicit SSO intent requires an auth page that returns the authorization code.");
233
237
  }
234
238
  const response = normalizeResponse(token, authUrl);
235
239
  autoConfigureFromLogin(response, authUrl, projectId);
@@ -246,7 +250,14 @@ async function startSsoRedirect(provider, options) {
246
250
  const appId = String(projectId);
247
251
  const authPageUrl = await fetchSsoAuthPageUrl();
248
252
  const redirectUri = stripToOriginPath(authPageUrl);
249
- persistRedirectContext({ state, provider, authUrl, projectId: appId, redirectUri });
253
+ persistRedirectContext({
254
+ state,
255
+ provider,
256
+ authUrl,
257
+ projectId: appId,
258
+ redirectUri,
259
+ ...(options == null ? void 0 : options.create) !== void 0 ? { create: options.create } : {}
260
+ });
250
261
  const startUrl = buildStartUrl(authPageUrl, provider, state, appId, authUrl, window.location.href);
251
262
  window.location.assign(startUrl);
252
263
  return new Promise(() => {
@@ -258,7 +269,14 @@ async function exchangeSsoCodeMitra(options) {
258
269
  if (!ctx || ctx.state !== options.state) {
259
270
  throw new Error("State inv\xE1lido no retorno do SSO (poss\xEDvel CSRF).");
260
271
  }
261
- return exchangeSsoCode(ctx.authUrl, ctx.provider, options.code, ctx.redirectUri, ctx.projectId);
272
+ return exchangeSsoCode(
273
+ ctx.authUrl,
274
+ ctx.provider,
275
+ options.code,
276
+ ctx.redirectUri,
277
+ ctx.projectId,
278
+ ctx.create
279
+ );
262
280
  }
263
281
  async function loginWithGoogleMitra(options) {
264
282
  return loginWithProvider("google", options);
@@ -342,15 +360,18 @@ async function tryRefreshToken() {
342
360
  }
343
361
  }
344
362
  async function handleResponse(response) {
363
+ var _a, _b, _c, _d;
345
364
  const text = await response.text();
346
365
  const { data, isJson } = parseBody(text);
347
366
  if (!response.ok) {
348
367
  const fallback = !isJson && text ? `HTTP ${response.status} \u2014 ${text}` : `HTTP ${response.status}`;
349
- const base = isJson && ((data == null ? void 0 : data.message) || (data == null ? void 0 : data.error)) || fallback;
368
+ const base = isJson && ((data == null ? void 0 : data.message) || ((_a = data == null ? void 0 : data.error) == null ? void 0 : _a.message) || (data == null ? void 0 : data.error)) || fallback;
350
369
  const msg = isJson && (data == null ? void 0 : data.hint) ? `${base} \u2014 ${data.hint}` : base;
370
+ const code = isJson && ((_d = (_c = data == null ? void 0 : data.error_code) != null ? _c : (_b = data == null ? void 0 : data.error) == null ? void 0 : _b.code) != null ? _d : data == null ? void 0 : data.code) || void 0;
351
371
  throw {
352
- message: msg,
372
+ message: typeof msg === "string" ? msg : fallback,
353
373
  status: response.status,
374
+ ...code ? { code } : {},
354
375
  details: data
355
376
  };
356
377
  }
@@ -483,6 +504,7 @@ var AgentTaskSession = class {
483
504
  this._isNew = init.kind === "new";
484
505
  this._transport = (_a = init.transport) != null ? _a : "ws";
485
506
  this._projectId = init.projectId;
507
+ this._userId = init.userId;
486
508
  if (init.kind === "new") {
487
509
  this._agentType = (_b = init.agentType) != null ? _b : DEFAULT_AGENT_TYPE;
488
510
  this._initialName = init.name;
@@ -521,7 +543,7 @@ var AgentTaskSession = class {
521
543
  // ── Abertura de chat existente ─────────
522
544
  async _openExisting(taskId) {
523
545
  try {
524
- const t = await readChatTask(taskId, this._projectId);
546
+ const t = await readChatTask(taskId, this._projectId, this._userId);
525
547
  this._task = toAgentChat(t);
526
548
  this._agentType = this._task.agentType;
527
549
  if (this._status === "opening") this._setStatus("idle");
@@ -546,9 +568,10 @@ var AgentTaskSession = class {
546
568
  }
547
569
  /**
548
570
  * Corpo do input `message` — idêntico no WS e no POST /inputs.
549
- * reasoningEffort: da mensagem, senão o default da session; enviado em
550
- * MAIÚSCULO (contrato do copilot). agentType por mensagem troca o modelo
551
- * dentro do mesmo harness (Claude<->Codex é recusado com HARNESS_SWITCH).
571
+ * reasoningEffort: da mensagem, senão o default da session; round-trip com
572
+ * reasoningOptions do list_models — vai COMO ESTÁ (minúsculo), sem
573
+ * normalizar. agentType por mensagem troca o modelo dentro do mesmo harness
574
+ * (Claude<->Codex é recusado com HARNESS_SWITCH).
552
575
  */
553
576
  _buildMessageInput(prompt, options) {
554
577
  var _a;
@@ -556,7 +579,9 @@ var AgentTaskSession = class {
556
579
  return {
557
580
  type: "message",
558
581
  content: prompt,
559
- ...effort ? { reasoningEffort: String(effort).toUpperCase() } : {},
582
+ // Round-trip com list_models: o valor de reasoningOptions vai COMO ESTÁ
583
+ // (minúsculo) — a SDK não normaliza.
584
+ ...effort ? { reasoningEffort: String(effort) } : {},
560
585
  ...(options == null ? void 0 : options.agentType) ? { agentType: options.agentType } : {}
561
586
  };
562
587
  }
@@ -573,7 +598,8 @@ var AgentTaskSession = class {
573
598
  projectId: this._projectId,
574
599
  title: this._initialName,
575
600
  agentType: this._agentType,
576
- agentId: this._agentId
601
+ agentId: this._agentId,
602
+ userId: this._userId
577
603
  });
578
604
  this._task = toAgentChat(t);
579
605
  this._taskId = this._task.id;
@@ -721,6 +747,7 @@ var AgentTaskSession = class {
721
747
  throw new Error("AgentTaskSession: sem taskId \u2014 task ainda n\xE3o criada.");
722
748
  }
723
749
  if (isTokenExpiring()) await tryRefreshToken();
750
+ const payload = this._userId ? { ...body, userId: this._userId } : body;
724
751
  const doPost = async () => fetch(
725
752
  `${getTaskHttpBase()}/${encodeURIComponent(this._taskId)}/inputs`,
726
753
  {
@@ -729,7 +756,7 @@ var AgentTaskSession = class {
729
756
  "Content-Type": "application/json",
730
757
  Authorization: `Bearer ${getRawToken()}`
731
758
  },
732
- body: JSON.stringify(body)
759
+ body: JSON.stringify(payload)
733
760
  }
734
761
  );
735
762
  let res = await doPost();
@@ -1051,14 +1078,23 @@ async function createChatTask(options) {
1051
1078
  // Autonomia é propriedade do AGENTE (createAgentMitra/updateAgentMitra no
1052
1079
  // mitra-sdk): o copilot deriva do agentId — o chat de agente autônomo já
1053
1080
  // nasce ownerless sem flag nenhum aqui.
1054
- ...options.agentId ? { agentId: options.agentId } : {}
1081
+ ...options.agentId ? { agentId: options.agentId } : {},
1082
+ // Agir EM NOME do dono (SF/webhook/cron com AGENT_WRITE): o chat nasce
1083
+ // pertencendo a esse usuário; o turno roda com a identidade/credencial
1084
+ // DELE. Ausente = chat do caller, byte a byte como sempre.
1085
+ // Erros do backend passam crus: 403 (sem AGENT_WRITE),
1086
+ // 400 AUTONOMOUS_TASK_HAS_NO_OWNER (userId + agente autônomo é contradição).
1087
+ ...options.userId ? { userId: options.userId } : {}
1055
1088
  });
1056
1089
  return env.result;
1057
1090
  }
1058
- async function readChatTask(taskId, projectId) {
1091
+ async function readChatTask(taskId, projectId, userId) {
1059
1092
  const env = await http.get("/agentAiShortcut/readChat", {
1060
1093
  projectId: resolveProjectId(projectId),
1061
- taskId
1094
+ taskId,
1095
+ // Validação defensiva: com userId, o backend devolve 404 se o chat não
1096
+ // pertencer àquele dono.
1097
+ ...userId ? { userId } : {}
1062
1098
  });
1063
1099
  return env.result;
1064
1100
  }
@@ -1086,6 +1122,8 @@ async function manageAgentChatMitra(options) {
1086
1122
  const env = await http.get("/agentAiShortcut/listChats", {
1087
1123
  projectId,
1088
1124
  agentId: options.agentId,
1125
+ // Em nome de outro usuário (AGENT_WRITE): lista os chats DELE, não os do caller.
1126
+ userId: options.userId,
1089
1127
  archived: options.archived,
1090
1128
  search: options.search,
1091
1129
  page: options.page,
@@ -1121,7 +1159,8 @@ function getAgentTaskMitra(options) {
1121
1159
  kind: "existing",
1122
1160
  taskId: options.taskId,
1123
1161
  projectId: options.projectId,
1124
- transport: options.transport
1162
+ transport: options.transport,
1163
+ userId: options.userId
1125
1164
  });
1126
1165
  }
1127
1166
  if ("create" in options && options.create) {
@@ -1132,7 +1171,8 @@ function getAgentTaskMitra(options) {
1132
1171
  name: options.name,
1133
1172
  agentId: options.agentId,
1134
1173
  transport: options.transport,
1135
- reasoningEffort: options.reasoningEffort
1174
+ reasoningEffort: options.reasoningEffort,
1175
+ userId: options.userId
1136
1176
  });
1137
1177
  }
1138
1178
  throw new Error("getAgentTaskMitra: passe { create: true } ou { taskId }.");
@@ -1158,7 +1198,10 @@ async function manageAgentCredentialMitra(options) {
1158
1198
  return { providers: (_a = env.result) != null ? _a : [] };
1159
1199
  }
1160
1200
  case "list_models": {
1161
- const env = await http.get("/agentAiShortcut/listModels", { projectId });
1201
+ const env = await http.get("/agentAiShortcut/listModels", {
1202
+ projectId,
1203
+ ...options.agentId ? { agentId: options.agentId } : {}
1204
+ });
1162
1205
  return { models: (_b = env.result) != null ? _b : [] };
1163
1206
  }
1164
1207
  case "save": {