@ai-matrx/chat 0.7.6 → 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/agents/api/fetch-pending-calls.js +4 -3
  3. package/dist/agents/api/submit-tool-results.js +3 -6
  4. package/dist/agents/components/chat/begin-fresh-chat.js +2 -2
  5. package/dist/agents/components/inputs/smart-input/InputActionButtons.d.ts +2 -2
  6. package/dist/agents/components/inputs/smart-input/InputActionButtons.js +3 -1
  7. package/dist/agents/components/inputs/smart-input/SmartAgentInputStacked.js +8 -3
  8. package/dist/agents/components/inputs/smart-input/composer/ComposerSplash.js +2 -3
  9. package/dist/agents/components/inputs/smart-input/composer/useComposerMode.js +4 -2
  10. package/dist/agents/components/live-run/LiveRunDisplay.d.ts +7 -1
  11. package/dist/agents/components/live-run/LiveRunDisplay.js +3 -1
  12. package/dist/agents/components/messages-display/assistant/AssistantMessageFooter.js +4 -2
  13. package/dist/agents/components/shared/transcript-layout.d.ts +9 -8
  14. package/dist/agents/components/shared/transcript-layout.js +2 -2
  15. package/dist/agents/redux/agent-definition/agent-cache-bust-request.js +7 -7
  16. package/dist/agents/redux/execution-system/context-rules/receipt-check.js +2 -2
  17. package/dist/agents/redux/execution-system/inbox/inbox.thunks.d.ts +2 -2
  18. package/dist/agents/redux/execution-system/inbox/inbox.thunks.js +7 -15
  19. package/dist/agents/redux/execution-system/observational-memory/fetch-memory-cost.thunk.d.ts +1 -1
  20. package/dist/agents/redux/execution-system/observational-memory/fetch-memory-cost.thunk.js +7 -4
  21. package/dist/agents/redux/execution-system/selectors/aggregate.selectors.d.ts +1 -114
  22. package/dist/agents/redux/execution-system/selectors/aggregate.selectors.js +28 -43
  23. package/dist/agents/redux/execution-system/thunks/call-conversation-api.d.ts +44 -0
  24. package/dist/agents/redux/execution-system/thunks/call-conversation-api.js +78 -0
  25. package/dist/agents/redux/execution-system/thunks/continue-agent-json.d.ts +41 -0
  26. package/dist/agents/redux/execution-system/thunks/continue-agent-json.js +66 -0
  27. package/dist/agents/redux/execution-system/thunks/execute-instance.thunk.d.ts +20 -0
  28. package/dist/agents/redux/execution-system/thunks/execute-instance.thunk.js +9 -2
  29. package/dist/agents/redux/execution-system/thunks/launch-agent-execution.thunk.js +4 -6
  30. package/dist/agents/redux/execution-system/thunks/notify-and-play-dispatcher.d.ts +1 -5
  31. package/dist/agents/redux/execution-system/thunks/notify-and-play-dispatcher.js +2 -1
  32. package/dist/agents/redux/execution-system/thunks/resolve-base-url.js +7 -17
  33. package/dist/agents/redux/execution-system/thunks/settle-after-stop.thunk.js +2 -2
  34. package/dist/agents/redux/execution-system/thunks/smart-execute.thunk.js +3 -3
  35. package/dist/agents/redux/execution-system/utils/continuation-body.d.ts +8 -2
  36. package/dist/agents/redux/execution-system/utils/continuation-body.js +3 -3
  37. package/dist/agents/redux/execution-system/utils/required-organization.d.ts +18 -0
  38. package/dist/agents/redux/execution-system/utils/required-organization.js +14 -10
  39. package/dist/agents/services/mcp-connections.service.js +5 -8
  40. package/dist/agents/ui-first-tools/dispatcher/dispatch-ui-first-tool.thunk.js +2 -1
  41. package/dist/host/defaults/files-host.js +11 -1
  42. package/dist/host/defaults/server-api.d.ts +1 -15
  43. package/dist/host/defaults/server-api.js +0 -21
  44. package/dist/host/defaults/server.d.ts +2 -1
  45. package/dist/host/defaults/server.js +8 -6
  46. package/dist/host/request-headers.d.ts +26 -0
  47. package/dist/host/request-headers.js +17 -0
  48. package/dist/host/server/call-api.d.ts +0 -13
  49. package/dist/host/server/call-api.js +0 -2
  50. package/dist/host/server/matrx-transport.d.ts +0 -1
  51. package/dist/host/server/matrx-transport.js +0 -2
  52. package/dist/store/root-state.d.ts +4 -21
  53. package/dist/surfaces/hooks/useSurfaceConfig.js +2 -1
  54. package/dist/surfaces/manifests/agent-builder.manifest.d.ts +8 -0
  55. package/dist/surfaces/manifests/agent-builder.manifest.js +62 -2
  56. package/dist/surfaces/runtime/surface-feedback.js +2 -2
  57. package/dist/ui/mandates-storage/mandateStorage.d.ts +36 -0
  58. package/dist/ui/mandates-storage/shortcutStorage.d.ts +9 -0
  59. package/dist/ui/markdown-stream/EnhancedChatMarkdown.js +22 -0
  60. package/dist/ui/markdown-stream/MarkdownStreamImpl.js +3 -3
  61. package/dist/ui/markdown-stream/StreamTextFallback.d.ts +6 -0
  62. package/dist/ui/markdown-stream/StreamTextFallback.js +23 -0
  63. package/dist/ui/markdown-stream/merge-thinking-across-hidden.d.ts +19 -0
  64. package/dist/ui/markdown-stream/merge-thinking-across-hidden.js +21 -0
  65. package/package.json +16 -11
@@ -33,29 +33,33 @@ async function ensureExecutionOrganization(state, conversationId) {
33
33
  return null;
34
34
  }
35
35
  }
36
+ function conversationRequestOrganizationId(state, conversationId) {
37
+ const instance = state.conversations?.byConversationId?.[conversationId];
38
+ if (instance && instance.cacheOnly === false) {
39
+ return adminSeatReplyOrganizationId(state, conversationId) ?? instance.organizationId ?? null;
40
+ }
41
+ return instance?.organizationId ?? // A host with no database has no admin seat to bill (G-DOOR: this door branches on the host).
42
+ (chatHostHasDatabase() ? adminLaneOrganizationId() : null) ?? selectOrganizationId(state) ?? null;
43
+ }
36
44
  function requireExecutionOrganizationId(state, conversationId) {
37
45
  const instance = state.conversations.byConversationId[conversationId];
38
46
  if (!instance) {
39
47
  throw new Error(`Conversation ${conversationId} not found.`);
40
48
  }
49
+ const organizationId = conversationRequestOrganizationId(state, conversationId);
50
+ if (organizationId) return organizationId;
41
51
  if (instance.cacheOnly !== false) {
42
- const startOrganizationId = instance.organizationId ?? // A host with no database has no admin seat to bill (G-DOOR: this door branches on the host).
43
- (chatHostHasDatabase() ? adminLaneOrganizationId() : void 0) ?? selectOrganizationId(state);
44
- if (startOrganizationId) return startOrganizationId;
45
52
  throw new Error(
46
53
  "Select an organization before sending this message. The request was not sent."
47
54
  );
48
55
  }
49
- const organizationId = adminSeatReplyOrganizationId(state, conversationId) ?? instance.organizationId;
50
- if (!organizationId) {
51
- throw new Error(
52
- "This conversation has no organization. Reload it before sending another message."
53
- );
54
- }
55
- return organizationId;
56
+ throw new Error(
57
+ "This conversation has no organization. Reload it before sending another message."
58
+ );
56
59
  }
57
60
  export {
58
61
  adminSeatReplyOrganizationId,
62
+ conversationRequestOrganizationId,
59
63
  ensureExecutionOrganization,
60
64
  executionOrganizationForRequest,
61
65
  isFingerprintGuestExecution,
@@ -4,7 +4,7 @@ import {
4
4
  readMatrxJsonResponse,
5
5
  sendMatrxRequest
6
6
  } from "@ai-matrx/agents/matrx";
7
- import { applyOrganizationContextHeader } from "../../host/server/organization-context.js";
7
+ import { chatRequestHeaders } from "../../host/request-headers.js";
8
8
  import { ensureOrganizationForRequest } from "../../host/org.js";
9
9
  import { readSessionToken } from "../../host/identity.js";
10
10
  function backendBase() {
@@ -17,13 +17,10 @@ async function authHeaders(method, explicitOrganizationId) {
17
17
  method,
18
18
  organizationId: explicitOrganizationId
19
19
  });
20
- return applyOrganizationContextHeader(
21
- {
22
- Authorization: `Bearer ${accessToken}`,
23
- "Content-Type": "application/json"
24
- },
25
- organizationId
26
- );
20
+ return {
21
+ "Content-Type": "application/json",
22
+ ...chatRequestHeaders({ accessToken, fingerprintId: null }, organizationId)
23
+ };
27
24
  }
28
25
  async function mcpFetch(path, init, explicitOrganizationId) {
29
26
  const headers = await authHeaders(init?.method ?? "GET", explicitOrganizationId);
@@ -3,11 +3,12 @@ import { extractErrorMessage } from "@ai-matrx/data/net";
3
3
  import { submitToolResult } from "../../api/submit-tool-results.js";
4
4
  import { upsertToolLifecycle } from "../../redux/execution-system/active-requests/active-requests.slice.js";
5
5
  import { getUiFirstToolEntry } from "../tools/registry.js";
6
+ import { selectUserId } from "../../../host/identity.js";
6
7
  const dispatchUiFirstTool = createAsyncThunk(
7
8
  "uiFirstTools/dispatch",
8
9
  async ({ conversationId, requestId, callId, toolName, args }, { dispatch, getState }) => {
9
10
  const state = getState();
10
- const userId = state.userAuth?.id ?? null;
11
+ const userId = selectUserId(state);
11
12
  if (!userId) {
12
13
  dispatch(
13
14
  upsertToolLifecycle({
@@ -3,6 +3,7 @@ import {
3
3
  isFilesHostConfigured
4
4
  } from "@ai-matrx/media/files/engine/host/configure";
5
5
  import { getStoreSingleton } from "../../store/store-singleton.js";
6
+ import { chatRequestHeaders } from "../request-headers.js";
6
7
  const DEFAULT_FILES_SERVICE_URL = "https://files.matrxserver.com";
7
8
  const UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
8
9
  const FILES_SERVICE_ROUTES = [
@@ -45,7 +46,16 @@ function createDefaultFilesServer(host) {
45
46
  async function buildHeaders(opts, includeContentType) {
46
47
  const requestId = opts.requestId ?? (globalThis.crypto?.randomUUID?.() ?? `${Date.now()}`);
47
48
  const headers = { ...await host().server.headers?.() ?? {}, "X-Request-Id": requestId };
48
- if (opts.organizationId) headers["X-Organization-Id"] = opts.organizationId;
49
+ if (opts.organizationId) {
50
+ const identity = host().identity;
51
+ Object.assign(
52
+ headers,
53
+ chatRequestHeaders(
54
+ { accessToken: await identity.getAccessToken(), fingerprintId: identity.current().fingerprintId },
55
+ opts.organizationId
56
+ )
57
+ );
58
+ }
49
59
  if (opts.idempotencyKey) headers["Idempotency-Key"] = opts.idempotencyKey;
50
60
  if (includeContentType) headers["Content-Type"] = "application/json";
51
61
  return { headers, requestId };
@@ -10,7 +10,7 @@
10
10
  * values here — no admin lane, no admin door, no endpoint overrides, no local
11
11
  * engine, no browser extension (each refusal says so once).
12
12
  */
13
- import { applyOrganizationContextHeader, type MatrxCallError, type MatrxCallResult, type MatrxCancelResponse, type MatrxTransport, type ProviderSessionFailure, type ProviderSessionFailureVerdict } from "@ai-matrx/agents/matrx";
13
+ import { applyOrganizationContextHeader, type MatrxCallError, type MatrxCallResult, type MatrxTransport, type ProviderSessionFailure, type ProviderSessionFailureVerdict } from "@ai-matrx/agents/matrx";
14
14
  import type { TypedStreamEvent } from "@ai-matrx/agents/generated/stream-events";
15
15
  import type { ApiPaths, ApiSchemas as Schemas, DefaultBrokeredCredential, DefaultRequestOptions, GetResult, PatchBody, PatchResult, PathWith, PostBody, PostResult } from "./typed-paths.js";
16
16
  import type { ChatIdentityPort, ChatOrgPort, ChatServerPort } from "../contract.js";
@@ -113,19 +113,6 @@ export declare function createDefaultServerApi(host: () => ServerHostView): {
113
113
  resolveScope: (_state?: unknown, overrides?: Partial<DefaultCallScope>) => DefaultCallScope;
114
114
  buildRequestBody: (body: unknown, scope: DefaultCallScope) => Record<string, unknown>;
115
115
  waitForAuthReady: (_getState?: AnyGetState) => Promise<boolean>;
116
- callConversationMemoryCost: (conversationId: string, options?: {
117
- signal?: AbortSignal;
118
- scopeOverrides?: Partial<DefaultCallScope>;
119
- }) => DefaultServerThunk<Promise<DefaultApiCallResult<{
120
- conversation_id: string;
121
- total_cost: number;
122
- total_input_tokens: number;
123
- total_output_tokens: number;
124
- event_count: number;
125
- by_event_type: {
126
- [key: string]: import("@ai-matrx/agents/generated/api-types").components["schemas"]["MemoryCostByEventType"];
127
- };
128
- }>>>;
129
116
  callConversationFork: (options: {
130
117
  conversationId: string;
131
118
  body?: unknown;
@@ -302,7 +289,6 @@ export declare function createDefaultServerApi(host: () => ServerHostView): {
302
289
  source?: string;
303
290
  expectedErrorStatuses?: readonly number[];
304
291
  }) => MatrxTransport;
305
- cancelAgentRunRequest: (requestId: string, mode?: "cancel" | "interrupt", seenSeq?: number) => DefaultServerThunk<Promise<DefaultApiCallResult<MatrxCancelResponse>>>;
306
292
  peekSelectedOrganizationId: () => string | null;
307
293
  waitForOrganizationAdmission: () => Promise<DefaultChatServerTypes["OrganizationAdmission"]>;
308
294
  adminLaneOrganizationId: () => string | null;
@@ -3,7 +3,6 @@ import {
3
3
  applyOrganizationContextHeader,
4
4
  buildMatrxRequestBody,
5
5
  buildMatrxRequestUrl,
6
- cancelAgentRun,
7
6
  createMatrxTransport as createPackageTransport,
8
7
  executeMatrxCall,
9
8
  normalizeMatrxError,
@@ -156,14 +155,6 @@ function createDefaultServerApi(host) {
156
155
  resolveScope,
157
156
  buildRequestBody,
158
157
  waitForAuthReady: async (_getState) => true,
159
- callConversationMemoryCost: (conversationId, options) => callApi({
160
- path: "/ai/conversations/{conversation_id}/memory_cost",
161
- method: "GET",
162
- pathParams: { conversation_id: conversationId },
163
- stream: false,
164
- ...options?.signal ? { signal: options.signal } : {},
165
- ...options?.scopeOverrides ? { scopeOverrides: options.scopeOverrides } : {}
166
- }),
167
158
  callConversationFork: call("POST", "/cx/conversations/{conversation_id}/fork"),
168
159
  callConversationForkAndRun: call("POST", "/ai/conversations/{conversation_id}/fork-and-run", true),
169
160
  callBatchDeleteMessages: call("POST", "/cx/conversations/{conversation_id}/messages/delete"),
@@ -184,18 +175,6 @@ function createDefaultServerApi(host) {
184
175
  ...options.source ? { source: options.source } : {},
185
176
  ...options.expectedErrorStatuses ? { expectedErrorStatuses: options.expectedErrorStatuses } : {}
186
177
  }),
187
- cancelAgentRunRequest: (requestId, mode = "cancel", seenSeq) => async () => {
188
- const base = transport();
189
- const sender = seenSeq === void 0 ? base : {
190
- fetch: (path, init) => base.fetch(`${path}${path.includes("?") ? "&" : "?"}seen_seq=${seenSeq}`, init)
191
- };
192
- try {
193
- const data = await cancelAgentRun(sender, requestId, { mode });
194
- return { data, requestId: data.request_id };
195
- } catch (error) {
196
- return { error: normalizeMatrxError(error) };
197
- }
198
- },
199
178
  // organization admission + the admin seat (none in a bare host)
200
179
  peekSelectedOrganizationId: () => host().org.active()?.id ?? null,
201
180
  waitForOrganizationAdmission: async () => host().org.active() ? "ready" : "unresolved",
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Default server port: the production AI Dream server; headers carry the
3
- * bearer token and the active organization.
3
+ * session credential and the active organization, built by THE ONE header
4
+ * builder (`../request-headers.ts`).
4
5
  */
5
6
  import type { ChatIdentityPort, ChatOrgPort, ChatServerPort } from "../contract.js";
6
7
  export declare const DEFAULT_CHAT_SERVER_URL = "https://server.app.matrxserver.com";
@@ -1,14 +1,16 @@
1
+ import { chatRequestHeaders } from "../request-headers.js";
1
2
  const DEFAULT_CHAT_SERVER_URL = "https://server.app.matrxserver.com";
2
3
  function createDefaultServer(identity, org) {
3
4
  return {
4
5
  baseUrl: () => DEFAULT_CHAT_SERVER_URL,
5
6
  async headers() {
6
- const headers = {};
7
- const token = await identity().getAccessToken();
8
- if (token) headers.Authorization = `Bearer ${token}`;
9
- const active = org().active();
10
- if (active) headers["X-Organization-Id"] = active.id;
11
- return headers;
7
+ return chatRequestHeaders(
8
+ {
9
+ accessToken: await identity().getAccessToken(),
10
+ fingerprintId: identity().current().fingerprintId
11
+ },
12
+ org().active()?.id ?? null
13
+ );
12
14
  }
13
15
  };
14
16
  }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * THE ONE HEADER BUILDER for every request the chat package sends to an AI Matrx server
3
+ * (Audit B family 8, "the inbox class").
4
+ *
5
+ * Who is asking (credential) and which organization the request names, as headers:
6
+ * - `Authorization: Bearer <jwt>` for a signed-in session, else `X-Fingerprint-ID` for a guest
7
+ * (the platform's one credential mapping, `credentialToHeaders` in `@ai-matrx/data`, which
8
+ * `@ai-matrx/api` carries forward unchanged);
9
+ * - `X-Organization-Id` when an organization is named;
10
+ * - the admin-lane marker when that organization is the platform tenant on the admin seat
11
+ * (`adminLaneHeadersFor`, the host's rule; none in a bare host).
12
+ *
13
+ * Every request path uses it: the conversation door (`resolveBackendForConversation`, which every
14
+ * turn and every conversation-bound call rides), the package default server port and the web
15
+ * app's server port. WHICH organization a conversation request names is a separate, single rule:
16
+ * `conversationRequestOrganizationId` (`agents/redux/execution-system/utils/required-organization.ts`).
17
+ * Guard: `host/__tests__/one-header-builder.test.ts` fails when a second builder appears.
18
+ */
19
+ export interface ChatRequestCredential {
20
+ /** The session's bearer token, or null. */
21
+ accessToken: string | null;
22
+ /** The guest fingerprint a signed-out visitor is known by, or null. */
23
+ fingerprintId: string | null;
24
+ }
25
+ /** The headers that say who is asking and in which organization. */
26
+ export declare function chatRequestHeaders(credential: ChatRequestCredential, organizationId: string | null | undefined): Record<string, string>;
@@ -0,0 +1,17 @@
1
+ import { credentialToHeaders } from "@ai-matrx/data";
2
+ import { adminLaneHeadersFor } from "./server/admin-lane.js";
3
+ import { isChatHostConfigured } from "./configure.js";
4
+ function chatRequestHeaders(credential, organizationId) {
5
+ const presented = credential.accessToken ? { kind: "user", accessToken: credential.accessToken } : credential.fingerprintId ? { kind: "guest", fingerprintId: credential.fingerprintId } : null;
6
+ const headers = credentialToHeaders(presented);
7
+ if (!organizationId) return headers;
8
+ return {
9
+ ...headers,
10
+ "X-Organization-Id": organizationId,
11
+ // The admin lane is the configured host's rule; a host still being resolved has none yet.
12
+ ...isChatHostConfigured() ? adminLaneHeadersFor(organizationId) : {}
13
+ };
14
+ }
15
+ export {
16
+ chatRequestHeaders
17
+ };
@@ -8,19 +8,6 @@ export declare const callApi: <T = unknown>(config: import("../defaults/server-a
8
8
  export declare const buildRequestBody: (body: unknown, scope: import("../defaults/server-api.js").DefaultCallScope) => Record<string, unknown>;
9
9
  export declare const resolveScope: (_state?: unknown, overrides?: Partial<import("../defaults/server-api.js").DefaultCallScope>) => import("../defaults/server-api.js").DefaultCallScope;
10
10
  export declare const waitForAuthReady: (_getState?: () => unknown) => Promise<boolean>;
11
- export declare const callConversationMemoryCost: (conversationId: string, options?: {
12
- signal?: AbortSignal;
13
- scopeOverrides?: Partial<import("../defaults/server-api.js").DefaultCallScope>;
14
- }) => import("../defaults/server-api.js").DefaultServerThunk<Promise<import("../defaults/server-api.js").DefaultApiCallResult<{
15
- conversation_id: string;
16
- total_cost: number;
17
- total_input_tokens: number;
18
- total_output_tokens: number;
19
- event_count: number;
20
- by_event_type: {
21
- [key: string]: import("@ai-matrx/agents/generated/api-types").components["schemas"]["MemoryCostByEventType"];
22
- };
23
- }>>>;
24
11
  export declare const callConversationFork: (options: {
25
12
  conversationId: string;
26
13
  body?: unknown;
@@ -3,7 +3,6 @@ const callApi = forwardServer("callApi");
3
3
  const buildRequestBody = forwardServer("buildRequestBody");
4
4
  const resolveScope = forwardServer("resolveScope");
5
5
  const waitForAuthReady = forwardServer("waitForAuthReady");
6
- const callConversationMemoryCost = forwardServer("callConversationMemoryCost");
7
6
  const callConversationFork = forwardServer("callConversationFork");
8
7
  const callConversationForkAndRun = forwardServer("callConversationForkAndRun");
9
8
  const callBatchDeleteMessages = forwardServer("callBatchDeleteMessages");
@@ -23,7 +22,6 @@ export {
23
22
  callConversationDelete,
24
23
  callConversationFork,
25
24
  callConversationForkAndRun,
26
- callConversationMemoryCost,
27
25
  callConversationSandboxBind,
28
26
  callConversationSandboxUnbind,
29
27
  callConversationUpdate,
@@ -17,5 +17,4 @@ export declare const createMatrxTransportFromTarget: (getState: () => unknown, r
17
17
  source?: string;
18
18
  expectedErrorStatuses?: readonly number[];
19
19
  }) => import("@ai-matrx/agents").MatrxTransport;
20
- export declare const cancelAgentRunRequest: (requestId: string, mode?: "cancel" | "interrupt", seenSeq?: number) => import("../defaults/server-api.js").DefaultServerThunk<Promise<import("../defaults/server-api.js").DefaultApiCallResult<import("@ai-matrx/agents").MatrxCancelResponse>>>;
21
20
  export type MatrxTransportOptions = ChatServerTypes["MatrxTransportOptions"];
@@ -1,9 +1,7 @@
1
1
  import { forwardServer } from "../server.js";
2
2
  const createMatrxTransport = forwardServer("createMatrxTransport");
3
3
  const createMatrxTransportFromTarget = forwardServer("createMatrxTransportFromTarget");
4
- const cancelAgentRunRequest = forwardServer("cancelAgentRunRequest");
5
4
  export {
6
- cancelAgentRunRequest,
7
5
  createMatrxTransport,
8
6
  createMatrxTransportFromTarget
9
7
  };
@@ -4,32 +4,15 @@ import type { ChatState } from "./state.js";
4
4
  export interface ChatStoreRegister {
5
5
  }
6
6
  /**
7
- * Slices the HOST owns that package code reads when present (§2.3). A private store has none of
7
+ * Slices the HOST owns that package code reads when present (§2.3). Identity, the active
8
+ * organization and the profile are NEVER read from host slices: they come from the package's own
9
+ * `chatHost` slice (the host's identity and org ports) — guard
10
+ * `store/__tests__/no-host-identity-slice-reads.test.ts`. A private store has none of
8
11
  * them, so every read is optional; a registered host store supplies the real shapes. Only the
9
12
  * fields the package reads are named, with no index signatures, so a host's concrete slice
10
13
  * interfaces (which carry extra fields) stay assignable.
11
14
  */
12
15
  export interface ChatHostReadSlices {
13
- userAuth?: {
14
- id: string | null;
15
- email?: string | null;
16
- isAnonymous?: boolean;
17
- accessToken?: string | null;
18
- isAdmin?: boolean;
19
- adminLaneOpen?: boolean;
20
- adminLevel?: string | null;
21
- };
22
- appContext?: {
23
- organization_id?: string | null;
24
- };
25
- userProfile?: {
26
- fingerprintId?: string | null;
27
- userMetadata?: {
28
- fullName?: string | null;
29
- name?: string | null;
30
- preferredUsername?: string | null;
31
- } | null;
32
- };
33
16
  cloudFiles?: {
34
17
  filesById: Record<string, {
35
18
  fileName?: string | null;
@@ -12,6 +12,7 @@ import {
12
12
  addRosterItem
13
13
  } from "../services/surface-config.service.js";
14
14
  import { getNamespaceHandler } from "../config/namespace-registry.js";
15
+ import { selectUserId } from "../../host/identity.js";
15
16
  function useSurfaceConfig(surfaceName) {
16
17
  const dispatch = useAppDispatch();
17
18
  const entry = useAppSelector((s) => selectSurfaceConfigEntry(s, surfaceName));
@@ -42,7 +43,7 @@ function useSurfaceConfig(surfaceName) {
42
43
  }
43
44
  function useSurfaceAgentRoles(surfaceName) {
44
45
  const { status, roles, refresh } = useSurfaceConfig(surfaceName);
45
- const userId = useAppSelector((s) => s.userAuth?.id ?? null);
46
+ const userId = useAppSelector(selectUserId);
46
47
  const buildView = useCallback(
47
48
  (resolved) => {
48
49
  const first = resolved.effective[0] ?? null;
@@ -80,4 +80,12 @@ export declare function createAgentBuilderScope(values: {
80
80
  variable_custom_component?: unknown;
81
81
  variable_binding?: unknown;
82
82
  variable_json?: object;
83
+ test_run_conversation_id?: string;
84
+ test_run_variables?: Record<string, unknown>;
85
+ test_run_user_input?: string;
86
+ test_run_response?: string;
87
+ test_run_transcript?: {
88
+ role: string;
89
+ text: string;
90
+ }[];
83
91
  }): SurfaceScopePayload;
@@ -42,9 +42,66 @@ const groups = [
42
42
  label: "Focused variable",
43
43
  sortOrder: 700,
44
44
  description: "The single variable definition the user is editing right now in the variable editor."
45
+ },
46
+ {
47
+ key: "test_run",
48
+ label: "Test run",
49
+ sortOrder: 800,
50
+ description: "The person's latest run of this agent in the builder's test panel: the values it ran with, what they typed, the answer and the whole exchange."
45
51
  }
46
52
  ];
47
53
  const surfaceSpecific = [
54
+ // ── Test run (800-840) — Agent Factory R58: the helper beside the builder sees the run ──
55
+ {
56
+ name: "test_run_conversation_id",
57
+ label: "Test run conversation",
58
+ description: "Id of the conversation the person last ran this agent in, in the builder's test panel. Absent until they run it.",
59
+ valueType: "string",
60
+ alwaysAvailable: false,
61
+ typicalCharCount: 36,
62
+ group: "test_run",
63
+ sortOrder: 800
64
+ },
65
+ {
66
+ name: "test_run_variables",
67
+ label: "Test run variables",
68
+ description: "The variable values the agent ran with in that test run (name \u2192 value). Absent until the person runs it.",
69
+ valueType: "object",
70
+ alwaysAvailable: false,
71
+ typicalCharCount: 600,
72
+ group: "test_run",
73
+ sortOrder: 810
74
+ },
75
+ {
76
+ name: "test_run_user_input",
77
+ label: "Test run input",
78
+ description: "What the person typed in their latest test-run turn. Empty when they only filled variables.",
79
+ valueType: "string",
80
+ alwaysAvailable: false,
81
+ typicalCharCount: 300,
82
+ group: "test_run",
83
+ sortOrder: 820
84
+ },
85
+ {
86
+ name: "test_run_response",
87
+ label: "Test run answer",
88
+ description: "The agent's latest answer in the test run, as the person read it. Absent while it is still answering.",
89
+ valueType: "string",
90
+ alwaysAvailable: false,
91
+ typicalCharCount: 3e3,
92
+ group: "test_run",
93
+ sortOrder: 830
94
+ },
95
+ {
96
+ name: "test_run_transcript",
97
+ label: "Test run transcript",
98
+ description: "The whole test-run conversation in order, one { role, text } per message (person and agent turns). Use it to judge the answer against what was asked.",
99
+ valueType: "array",
100
+ alwaysAvailable: false,
101
+ typicalCharCount: 6e3,
102
+ group: "test_run",
103
+ sortOrder: 840
104
+ },
48
105
  // ── Agent identity (300-339) ──────────────────────────────────────────
49
106
  {
50
107
  name: "agent_id",
@@ -577,8 +634,11 @@ Read the values this way:
577
634
  - \`agent_is_read_only\` being true means the user cannot save \u2014 propose, do not
578
635
  promise to apply.
579
636
 
580
- You are helping AUTHOR an agent. Nothing here has run yet; the run transcript
581
- lives on the separate Agent Run surface.
637
+ You are helping AUTHOR an agent. When the person runs it in the builder's test
638
+ panel, the \`test_run_*\` values carry that run: the variables it ran with, what
639
+ they typed, the answer, and the whole exchange \u2014 judge the answer against the
640
+ agent's job and suggest what to change. Absent \`test_run_*\` values mean it has
641
+ not been run here yet.
582
642
 
583
643
  You can also WRITE here, but only to the authored prose: the system
584
644
  instruction, description, name, category, and tags. Everything that decides
@@ -6,6 +6,7 @@ import {
6
6
  SURFACE_FEEDBACK_MESSAGE_MAX,
7
7
  SURFACE_FEEDBACK_MESSAGE_MIN
8
8
  } from "../manifests/_baseline.manifest.js";
9
+ import { selectOrganizationId } from "../../host/org.js";
9
10
  const SURFACE_FEEDBACK_TARGET_NAME = PLATFORM_WRITE_TARGETS.surface_feedback.name;
10
11
  const KIND_LIST = SURFACE_FEEDBACK_KINDS.join(" | ");
11
12
  const SURFACE_FEEDBACK_TARGET = PLATFORM_WRITE_TARGETS.surface_feedback;
@@ -72,8 +73,7 @@ ${message}`,
72
73
  };
73
74
  }
74
75
  function readActiveOrganizationId() {
75
- const state = getStoreSingleton()?.getState();
76
- return state?.appContext?.organization_id ?? null;
76
+ return selectOrganizationId(getStoreSingleton()?.getState());
77
77
  }
78
78
  async function saveSurfaceFeedback(value, ctx) {
79
79
  const result = await getChatHost().feedback.submit(
@@ -955,6 +955,7 @@ declare const definitionTable: (supabase: Client) => import("@supabase/supabase-
955
955
  last_seen_revision: string | null;
956
956
  last_seen_scan_id: string | null;
957
957
  line: number | null;
958
+ line_end: number | null;
958
959
  mandate_id: string | null;
959
960
  mandate_key: string;
960
961
  metadata: Json;
@@ -997,6 +998,7 @@ declare const definitionTable: (supabase: Client) => import("@supabase/supabase-
997
998
  last_seen_revision?: string | null;
998
999
  last_seen_scan_id?: string | null;
999
1000
  line?: number | null;
1001
+ line_end?: number | null;
1000
1002
  mandate_id?: string | null;
1001
1003
  mandate_key: string;
1002
1004
  metadata?: Json;
@@ -1039,6 +1041,7 @@ declare const definitionTable: (supabase: Client) => import("@supabase/supabase-
1039
1041
  last_seen_revision?: string | null;
1040
1042
  last_seen_scan_id?: string | null;
1041
1043
  line?: number | null;
1044
+ line_end?: number | null;
1042
1045
  mandate_id?: string | null;
1043
1046
  mandate_key?: string;
1044
1047
  metadata?: Json;
@@ -1833,6 +1836,12 @@ declare const definitionTable: (supabase: Client) => import("@supabase/supabase-
1833
1836
  };
1834
1837
  Returns: boolean;
1835
1838
  };
1839
+ code_locations: {
1840
+ Args: {
1841
+ p_keys?: string[];
1842
+ };
1843
+ Returns: Json;
1844
+ };
1836
1845
  definition_restore: {
1837
1846
  Args: {
1838
1847
  p_mandate_id: string;
@@ -3108,6 +3117,7 @@ declare const provisionTable: (supabase: Client) => import("@supabase/supabase-j
3108
3117
  last_seen_revision: string | null;
3109
3118
  last_seen_scan_id: string | null;
3110
3119
  line: number | null;
3120
+ line_end: number | null;
3111
3121
  mandate_id: string | null;
3112
3122
  mandate_key: string;
3113
3123
  metadata: Json;
@@ -3150,6 +3160,7 @@ declare const provisionTable: (supabase: Client) => import("@supabase/supabase-j
3150
3160
  last_seen_revision?: string | null;
3151
3161
  last_seen_scan_id?: string | null;
3152
3162
  line?: number | null;
3163
+ line_end?: number | null;
3153
3164
  mandate_id?: string | null;
3154
3165
  mandate_key: string;
3155
3166
  metadata?: Json;
@@ -3192,6 +3203,7 @@ declare const provisionTable: (supabase: Client) => import("@supabase/supabase-j
3192
3203
  last_seen_revision?: string | null;
3193
3204
  last_seen_scan_id?: string | null;
3194
3205
  line?: number | null;
3206
+ line_end?: number | null;
3195
3207
  mandate_id?: string | null;
3196
3208
  mandate_key?: string;
3197
3209
  metadata?: Json;
@@ -3986,6 +3998,12 @@ declare const provisionTable: (supabase: Client) => import("@supabase/supabase-j
3986
3998
  };
3987
3999
  Returns: boolean;
3988
4000
  };
4001
+ code_locations: {
4002
+ Args: {
4003
+ p_keys?: string[];
4004
+ };
4005
+ Returns: Json;
4006
+ };
3989
4007
  definition_restore: {
3990
4008
  Args: {
3991
4009
  p_mandate_id: string;
@@ -5156,6 +5174,7 @@ declare const bindingTable: (supabase: Client) => import("@supabase/supabase-js"
5156
5174
  last_seen_revision: string | null;
5157
5175
  last_seen_scan_id: string | null;
5158
5176
  line: number | null;
5177
+ line_end: number | null;
5159
5178
  mandate_id: string | null;
5160
5179
  mandate_key: string;
5161
5180
  metadata: Json;
@@ -5198,6 +5217,7 @@ declare const bindingTable: (supabase: Client) => import("@supabase/supabase-js"
5198
5217
  last_seen_revision?: string | null;
5199
5218
  last_seen_scan_id?: string | null;
5200
5219
  line?: number | null;
5220
+ line_end?: number | null;
5201
5221
  mandate_id?: string | null;
5202
5222
  mandate_key: string;
5203
5223
  metadata?: Json;
@@ -5240,6 +5260,7 @@ declare const bindingTable: (supabase: Client) => import("@supabase/supabase-js"
5240
5260
  last_seen_revision?: string | null;
5241
5261
  last_seen_scan_id?: string | null;
5242
5262
  line?: number | null;
5263
+ line_end?: number | null;
5243
5264
  mandate_id?: string | null;
5244
5265
  mandate_key?: string;
5245
5266
  metadata?: Json;
@@ -6034,6 +6055,12 @@ declare const bindingTable: (supabase: Client) => import("@supabase/supabase-js"
6034
6055
  };
6035
6056
  Returns: boolean;
6036
6057
  };
6058
+ code_locations: {
6059
+ Args: {
6060
+ p_keys?: string[];
6061
+ };
6062
+ Returns: Json;
6063
+ };
6037
6064
  definition_restore: {
6038
6065
  Args: {
6039
6066
  p_mandate_id: string;
@@ -7252,6 +7279,7 @@ declare const treatmentTable: (supabase: Client) => import("@supabase/supabase-j
7252
7279
  last_seen_revision: string | null;
7253
7280
  last_seen_scan_id: string | null;
7254
7281
  line: number | null;
7282
+ line_end: number | null;
7255
7283
  mandate_id: string | null;
7256
7284
  mandate_key: string;
7257
7285
  metadata: Json;
@@ -7294,6 +7322,7 @@ declare const treatmentTable: (supabase: Client) => import("@supabase/supabase-j
7294
7322
  last_seen_revision?: string | null;
7295
7323
  last_seen_scan_id?: string | null;
7296
7324
  line?: number | null;
7325
+ line_end?: number | null;
7297
7326
  mandate_id?: string | null;
7298
7327
  mandate_key: string;
7299
7328
  metadata?: Json;
@@ -7336,6 +7365,7 @@ declare const treatmentTable: (supabase: Client) => import("@supabase/supabase-j
7336
7365
  last_seen_revision?: string | null;
7337
7366
  last_seen_scan_id?: string | null;
7338
7367
  line?: number | null;
7368
+ line_end?: number | null;
7339
7369
  mandate_id?: string | null;
7340
7370
  mandate_key?: string;
7341
7371
  metadata?: Json;
@@ -8130,6 +8160,12 @@ declare const treatmentTable: (supabase: Client) => import("@supabase/supabase-j
8130
8160
  };
8131
8161
  Returns: boolean;
8132
8162
  };
8163
+ code_locations: {
8164
+ Args: {
8165
+ p_keys?: string[];
8166
+ };
8167
+ Returns: Json;
8168
+ };
8133
8169
  definition_restore: {
8134
8170
  Args: {
8135
8171
  p_mandate_id: string;