@ai-matrx/chat 0.3.26 → 0.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/agents/hooks/useAgentLauncher.js +4 -3
  3. package/dist/agents/redux/agent-definition/run-tier-record.d.ts +27 -0
  4. package/dist/agents/redux/agent-definition/run-tier-record.js +95 -0
  5. package/dist/agents/redux/agent-definition/selectors.d.ts +235 -231
  6. package/dist/agents/redux/agent-definition/selectors.js +3 -2
  7. package/dist/agents/redux/agent-definition/thunks.d.ts +2 -2
  8. package/dist/agents/redux/agent-definition/thunks.js +8 -63
  9. package/dist/agents/redux/conversation-list/conversation-list.selectors.js +2 -1
  10. package/dist/agents/redux/conversation-list/conversation-list.thunks.js +2 -1
  11. package/dist/agents/redux/conversation-list/record-conversation-from-execution.js +2 -1
  12. package/dist/agents/redux/execution-system/context-rules/request-context.js +8 -3
  13. package/dist/agents/redux/execution-system/instance-ui-state/instance-ui-state.selectors.js +6 -5
  14. package/dist/agents/redux/execution-system/thunks/create-instance.thunk.js +3 -2
  15. package/dist/agents/redux/execution-system/thunks/execute-manual-instance.thunk.js +3 -2
  16. package/dist/agents/redux/execution-system/thunks/launch-agent-execution.thunk.js +4 -4
  17. package/dist/agents/redux/execution-system/thunks/load-conversation.thunk.js +2 -1
  18. package/dist/agents/redux/execution-system/thunks/refresh-surface-scope.thunk.js +3 -2
  19. package/dist/agents/runtime/generation-job.js +2 -1
  20. package/dist/agents/runtime/get-model-capabilities.js +2 -1
  21. package/dist/cx-chat/hooks/useInstanceBootstrap.js +3 -1
  22. package/dist/host/db-types.d.ts +47 -1
  23. package/dist/ui/mandates-storage/mandateStorage.d.ts +19 -0
  24. package/dist/ui/mandates-storage/shortcutStorage.d.ts +38 -0
  25. package/dist/ui/permission-levels.d.ts +8 -2
  26. package/dist/ui/permission-levels.js +12 -1
  27. package/package.json +6 -6
  28. package/dist/agents/components/shared/AgentDuplicateOutcomeDialog.d.ts +0 -57
  29. package/dist/agents/components/shared/AgentDuplicateOutcomeDialog.js +0 -188
@@ -1,10 +1,11 @@
1
1
  "use client";
2
2
  import { createSelector } from "reselect";
3
3
  import { fieldFlagsSize, hasField } from "@ai-matrx/agents/field-flags";
4
+ import { completeAgentRecords, readRunTierState } from "./run-tier-record.js";
4
5
  const selectAgentDefinitionSlice = (state) => state.agentDefinition;
5
6
  const selectAllAgents = createSelector(
6
- [selectAgentDefinitionSlice],
7
- (slice) => slice.agents
7
+ [(state) => selectAgentDefinitionSlice(state).agents, () => readRunTierState()],
8
+ (agents, runTier) => completeAgentRecords(agents, runTier)
8
9
  );
9
10
  const selectActiveAgentId = createSelector(
10
11
  [selectAgentDefinitionSlice],
@@ -120,8 +120,8 @@ export declare const fetchAgentRunControls: import("@reduxjs/toolkit").AsyncThun
120
120
  export type { SharedAgentItem, SharedAgentForChat } from "@ai-matrx/agents/runtime";
121
121
  export type AgentAccessLevel = AgentAccessLevelRow;
122
122
  /**
123
- * Returns the current user's permission level on a specific agent.
124
- * Also merges the result into the slice so selectors stay consistent.
123
+ * Returns the current user's permission level on a specific agent. The answer
124
+ * stays in the core run tier store; the record's selectors read it from there.
125
125
  *
126
126
  * Use when opening the agent builder, or when the record arrived via a
127
127
  * shortcut/execution RPC (which don't include access metadata).
@@ -29,12 +29,10 @@ import {
29
29
  setAgentError
30
30
  } from "./slice.js";
31
31
  import {
32
+ selectAgentById,
32
33
  selectAgentReadyForExecution,
33
34
  selectAgentRunControlsReady
34
35
  } from "./selectors.js";
35
- import {
36
- parseSkillConfigJson
37
- } from "./converters.js";
38
36
  import {
39
37
  isSignedOutVisitor,
40
38
  NotAuthenticatedError
@@ -131,31 +129,18 @@ function sameStringArray(a, b) {
131
129
  function isToolAssignmentPhantom(current, base) {
132
130
  return sameStringArray(current.tools, base.tools) && current.model_id === base.model_id && current.created_by === base.created_by && current.organization_id === base.organization_id && current.is_archived === base.is_archived;
133
131
  }
134
- const REGISTRY_ACCESS_LEVELS = [
135
- "owner",
136
- "admin",
137
- "editor",
138
- "viewer",
139
- "system"
140
- ];
141
- function toRegistryAccessLevel(value) {
142
- return REGISTRY_ACCESS_LEVELS.find(
143
- (level) => level === value
144
- ) ?? null;
145
- }
146
132
  const fetchAgentRunTier = createAsyncThunk(
147
133
  "agentDefinition/fetchRunTier",
148
134
  async (arg, { dispatch, getState }) => {
149
135
  const agentId = typeof arg === "string" ? arg : arg.agentId;
150
136
  const force = typeof arg !== "string" && arg.force;
151
- const existing = getState().agentDefinition.agents?.[agentId];
137
+ const existing = selectAgentById(getState(), agentId);
152
138
  if (!force && selectAgentReadyForExecution(getState(), agentId) && existing && hasField(existing._loadedFields, "modelId"))
153
139
  return;
154
140
  if (await isSignedOutVisitor()) throw new NotAuthenticatedError();
155
141
  dispatch(setAgentLoading({ id: agentId, loading: true }));
156
- let row;
157
142
  try {
158
- row = await getRunTierStore().loadRunTier(agentId, { force: true });
143
+ await getRunTierStore().loadRunTier(agentId, { force: true });
159
144
  } catch (e) {
160
145
  dispatch(setAgentLoading({ id: agentId, loading: false }));
161
146
  const failure = runTierFailure(agentId, e);
@@ -163,28 +148,8 @@ const fetchAgentRunTier = createAsyncThunk(
163
148
  throw failure;
164
149
  }
165
150
  dispatch(setAgentLoading({ id: agentId, loading: false }));
166
- dispatch(
167
- mergePartialAgent({
168
- id: row.id,
169
- variableDefinitions: row.variable_definitions,
170
- contextPolicies: row.context_policies ?? [],
171
- // Without it every run-tier record read "injection allowed" even for
172
- // an agent that refuses ad-hoc context.
173
- autoContextDisabled: row.auto_context_disabled === true,
174
- ...row.model_id ? { modelId: row.model_id } : {},
175
- uiGates: row.ui_gates ?? {},
176
- ...row.tool_ids ? { tools: row.tool_ids } : {},
177
- ...existing?.name ? {} : { name: row.name },
178
- ...existing?.description != null ? {} : { description: row.description ?? "" },
179
- ...existing?.accessLevel ? {} : { accessLevel: toRegistryAccessLevel(row.access_level) },
180
- runCounts: {
181
- customTools: row.custom_tool_count ?? 0,
182
- skills: row.skill_count ?? 0,
183
- connections: row.connection_count ?? 0
184
- }
185
- })
186
- );
187
- dispatch(setAgentFetchStatus({ id: row.id, status: "execution" }));
151
+ dispatch(mergePartialAgent({ id: agentId }));
152
+ dispatch(setAgentFetchStatus({ id: agentId, status: "execution" }));
188
153
  }
189
154
  );
190
155
  const fetchAgentExecutionMinimal = fetchAgentRunTier;
@@ -193,26 +158,14 @@ const fetchAgentRunControls = createAsyncThunk(
193
158
  async (agentId, { dispatch, getState }) => {
194
159
  if (selectAgentRunControlsReady(getState(), agentId)) return;
195
160
  if (await isSignedOutVisitor()) throw new NotAuthenticatedError();
196
- let row;
197
161
  try {
198
- row = await getRunTierStore().loadRunControls(agentId, { force: true });
162
+ await getRunTierStore().loadRunControls(agentId, { force: true });
199
163
  } catch (e) {
200
164
  const failure = runTierFailure(agentId, e);
201
165
  dispatch(setAgentError({ id: agentId, error: failure.message }));
202
166
  throw failure;
203
167
  }
204
- const loaded = getState().agentDefinition.agents?.[agentId]?._loadedFields;
205
- const missing = (field) => !loaded || !hasField(loaded, field);
206
- dispatch(
207
- mergePartialAgent({
208
- id: row.id,
209
- runControls: { customToolNames: row.custom_tool_names ?? [] },
210
- ...missing("tools") ? { tools: row.tool_ids ?? [] } : {},
211
- ...missing("autoToolsDisabled") ? { autoToolsDisabled: row.auto_tools_disabled === true } : {},
212
- ...missing("skillConfig") ? { skillConfig: parseSkillConfigJson(row.skill_config) } : {},
213
- ...missing("mcpServers") ? { mcpServers: row.mcp_servers ?? [] } : {}
214
- })
215
- );
168
+ dispatch(mergePartialAgent({ id: agentId }));
216
169
  }
217
170
  );
218
171
  true;
@@ -220,15 +173,7 @@ const fetchAgentAccessLevel = createAsyncThunk("agentDefinition/fetchAccessLevel
220
173
  const row = await getRunTierStore().loadAccessLevel(agentId, { force: true }).catch((e) => {
221
174
  throw runTierFailure(agentId, e);
222
175
  });
223
- dispatch(
224
- mergePartialAgent({
225
- id: agentId,
226
- isOwner: row.is_owner,
227
- accessLevel: row.access_level,
228
- sharedByEmail: row.is_owner ? null : null
229
- // not returned by this RPC
230
- })
231
- );
176
+ dispatch(mergePartialAgent({ id: agentId }));
232
177
  return row;
233
178
  });
234
179
  export {
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { selectAgentById } from "../agent-definition/selectors.js";
2
3
  import { createSelector } from "@reduxjs/toolkit";
3
4
  import {
4
5
  CONVERSATION_LIST_TTL_MS,
@@ -75,7 +76,7 @@ function selectAgentConversationsEntry(state, agentId, versionFilter) {
75
76
  function selectAgentConversationsEntryForInstance(state, instanceId, versionFilter) {
76
77
  const mapKey = selectAgentIdFromInstance(instanceId)(state);
77
78
  if (!mapKey) return void 0;
78
- const agent = state.agentDefinition.agents?.[mapKey];
79
+ const agent = selectAgentById(state, mapKey);
79
80
  const canonicalAgentId = agent?.parentAgentId ?? agent?.id ?? mapKey;
80
81
  return selectAgentConversationsEntry(state, canonicalAgentId, versionFilter);
81
82
  }
@@ -1,3 +1,4 @@
1
+ import { selectAgentById } from "../agent-definition/selectors.js";
1
2
  import { createAsyncThunk } from "@reduxjs/toolkit";
2
3
  import { supabase } from "../../../host/db.js";
3
4
  import { favoritesService } from "../../../context/sources/scopes.js";
@@ -25,7 +26,7 @@ function resolveCanonicalAgentIdForConversationsFetch(input, state) {
25
26
  mapKey = selectAgentIdFromInstance(input.instanceId)(state);
26
27
  }
27
28
  if (!mapKey) return null;
28
- const agent = state.agentDefinition.agents?.[mapKey];
29
+ const agent = selectAgentById(state, mapKey);
29
30
  const canonicalAgentId = agent?.parentAgentId ?? agent?.id ?? mapKey;
30
31
  return { canonicalAgentId, versionFilter };
31
32
  }
@@ -1,9 +1,10 @@
1
+ import { selectAgentById } from "../agent-definition/selectors.js";
1
2
  import { conversationListCacheKey } from "./conversation-list.types.js";
2
3
  import { upsertConversationInCaches } from "./conversation-list.slice.js";
3
4
  function buildConversationListItemFromExecution(state, instanceId, conversationId, overrides) {
4
5
  const instance = state.conversations.byConversationId[instanceId];
5
6
  if (!instance) return null;
6
- const agent = state.agentDefinition.agents?.[instance.agentId];
7
+ const agent = selectAgentById(state, instance.agentId);
7
8
  const canonicalAgentId = agent?.parentAgentId ?? agent?.id ?? instance.agentId;
8
9
  const hist = state.messages.byConversationId[instanceId];
9
10
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -30,7 +30,8 @@ import { selectPageContextOff } from "../instance-ui-state/instance-ui-state.sel
30
30
  import {
31
31
  selectAgentAutoContextDisabled,
32
32
  selectAgentContextPolicies,
33
- selectAgentReadyForExecution
33
+ selectAgentReadyForExecution,
34
+ selectAgentById
34
35
  } from "../../agent-definition/selectors.js";
35
36
  import { selectResourceContextPayload } from "../instance-resources/instance-resources.selectors.js";
36
37
  import {
@@ -281,7 +282,7 @@ function displayInputs(state, conversationId) {
281
282
  return [
282
283
  state.instanceContext?.byConversationId[conversationId],
283
284
  conversation?.surfaceName ?? null,
284
- agentId ? state.agentDefinition?.agents[agentId] : null,
285
+ agentId ? selectAgentById(state, agentId) : null,
285
286
  state.instanceResources?.byConversationId[conversationId],
286
287
  selectSavedContextRuleRows(state),
287
288
  state.instanceContext?.receiptByConversationId?.[conversationId]?.receipt.cap ?? null,
@@ -370,7 +371,11 @@ const selectDisplayContextRows = (conversationId, mandateKillSwitch = false) =>
370
371
  }
371
372
  const actual = toContextReceipt(receipt);
372
373
  const shown = new Set(rows.map((row) => row.key));
373
- const unsent = expected ? compareReceipt(expected.rows, actual).systemRows : actual.rows.filter((row) => row.origin !== "client");
374
+ const systemRows = expected ? compareReceipt(expected.rows, actual).systemRows : actual.rows.filter((row) => row.origin !== "client");
375
+ const unsent = [
376
+ ...systemRows,
377
+ ...actual.rows.filter((row) => isServerAuthoritativeKey(row.key) && !systemRows.includes(row))
378
+ ];
374
379
  const cap = selectContextInlineCap(state, conversationId);
375
380
  const primarySurface = resolveClientSurface(state, conversationId) ?? null;
376
381
  const serverAdded = systemRowsToResolved(unsent).filter((row) => !shown.has(row.key)).map((row) => ({
@@ -1,3 +1,4 @@
1
+ import { selectAgentById, selectAllAgents } from "../../agent-definition/selectors.js";
1
2
  import { createSelector } from "@reduxjs/toolkit";
2
3
  import { getShortcutRecordFromState } from "../../agent-shortcuts/selectors.js";
3
4
  const selectInstanceUIState = (conversationId) => (state) => state.instanceUIState.byConversationId[conversationId];
@@ -63,12 +64,12 @@ const selectInstanceShortcutLabel = (conversationId) => (state) => {
63
64
  const selectInstanceAgentName = (conversationId) => (state) => {
64
65
  const agentId = state.conversations.byConversationId[conversationId]?.agentId;
65
66
  if (!agentId) return void 0;
66
- return state.agentDefinition.agents?.[agentId]?.name || void 0;
67
+ return selectAgentById(state, agentId)?.name || void 0;
67
68
  };
68
69
  const selectInstanceAgentDescription = (conversationId) => (state) => {
69
70
  const agentId = state.conversations.byConversationId[conversationId]?.agentId;
70
71
  if (!agentId) return void 0;
71
- return state.agentDefinition.agents?.[agentId]?.description;
72
+ return selectAgentById(state, agentId)?.description;
72
73
  };
73
74
  const selectInstanceTitle = (conversationId) => (state) => {
74
75
  const instance = state.conversations.byConversationId[conversationId];
@@ -81,7 +82,7 @@ const selectInstanceTitle = (conversationId) => (state) => {
81
82
  if (label) return label;
82
83
  }
83
84
  if (instance.agentId) {
84
- const name = state.agentDefinition.agents?.[instance.agentId]?.name;
85
+ const name = selectAgentById(state, instance.agentId)?.name;
85
86
  if (name) return name;
86
87
  }
87
88
  return void 0;
@@ -99,7 +100,7 @@ const selectInstanceDisplayTitle = (conversationId) => (state) => {
99
100
  if (label) return label;
100
101
  }
101
102
  if (instance.agentId) {
102
- const name = state.agentDefinition.agents?.[instance.agentId]?.name;
103
+ const name = selectAgentById(state, instance.agentId)?.name;
103
104
  if (name) return name;
104
105
  }
105
106
  return "Agent";
@@ -173,7 +174,7 @@ const selectAllUIStateConversationIds = createSelector(
173
174
  const selectUIStateInstancesByAgent = createSelector(
174
175
  (state) => state.instanceUIState.byConversationId,
175
176
  (state) => state.conversations.byConversationId,
176
- (state) => state.agentDefinition.agents,
177
+ (state) => selectAllAgents(state),
177
178
  (byUIConversationId, byExecConversationId, agents) => {
178
179
  const groupMap = /* @__PURE__ */ new Map();
179
180
  for (const conversationId of Object.keys(byUIConversationId)) {
@@ -1,3 +1,4 @@
1
+ import { selectAgentById } from "../../agent-definition/selectors.js";
1
2
  import { createAsyncThunk } from "@reduxjs/toolkit";
2
3
  import { createInstanceFull } from "../create-instance-full.js";
3
4
  import { getShortcutRecordFromState } from "../../agent-shortcuts/selectors.js";
@@ -54,7 +55,7 @@ import {
54
55
  import { initInstanceMessages } from "../messages/messages.slice.js";
55
56
  import { mapScopeToInstanceWithSurface } from "../../../utils/scope-mapping.js";
56
57
  function readAgentSnapshot(state, agentId) {
57
- const agent = state.agentDefinition.agents?.[agentId];
58
+ const agent = selectAgentById(state, agentId);
58
59
  if (agent && !hasField(agent._loadedFields, "modelId")) {
59
60
  console.warn(
60
61
  `[readAgentSnapshot] Agent ${agentId} snapshotted before modelId loaded \u2014 instance baseSettings.model will be empty. Ensure the run tier is fetched before instance creation (launch-agent-execution Step 0.5).`
@@ -103,7 +104,7 @@ const createManualInstance = createAsyncThunk("instances/createManual", async (a
103
104
  } = args;
104
105
  const conversationId = providedConversationId ?? generateConversationId();
105
106
  const preSnapshotState = getState();
106
- const preSnapshotAgent = preSnapshotState.agentDefinition.agents?.[agentId];
107
+ const preSnapshotAgent = selectAgentById(preSnapshotState, agentId);
107
108
  if (apiEndpointMode !== "manual" && preSnapshotAgent && !hasField(preSnapshotAgent._loadedFields, "modelId")) {
108
109
  await dispatch(fetchAgentRunTier(agentId)).unwrap();
109
110
  }
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  executionRejectionMeta
3
3
  } from "./execution-rejection-meta.js";
4
+ import { selectAgentById } from "../../agent-definition/selectors.js";
4
5
  import { mintClientTempId } from "@ai-matrx/kit/ids";
5
6
  import { createAsyncThunk } from "@reduxjs/toolkit";
6
7
  import { v4 as uuidv4 } from "uuid";
@@ -141,7 +142,7 @@ async function assembleManualRequest(state, conversationId, opts) {
141
142
  return null;
142
143
  }
143
144
  const sourceId = instance.initialAgentVersionId ?? instance.agentId;
144
- const agent = state.agentDefinition.agents?.[sourceId];
145
+ const agent = selectAgentById(state, sourceId);
145
146
  if (!agent) return null;
146
147
  const ai_model_id = agent.modelId;
147
148
  if (!ai_model_id) return null;
@@ -392,7 +393,7 @@ const executeManualInstance = createAsyncThunk(
392
393
  const submission = handedSubmission ?? captureSubmission(state, conversationId);
393
394
  const userInputText = submission.text;
394
395
  const sourceId = instance.initialAgentVersionId ?? instance.agentId;
395
- const liveAgent = state.agentDefinition.agents?.[sourceId];
396
+ const liveAgent = selectAgentById(state, sourceId);
396
397
  const instanceVariables = state.instanceVariableValues.byConversationId[conversationId];
397
398
  const firstTurnVariables = isFirstTurn(state, conversationId) ? resolveVariablesForRequest({
398
399
  definitions: liveAgent?.variableDefinitions ?? instanceVariables?.definitions ?? [],
@@ -31,7 +31,7 @@ import {
31
31
  NotAuthenticatedError
32
32
  } from "../../../../host/identity.js";
33
33
  import { applyLaunchModelOverrides } from "../instance-model-overrides/launch-model-overrides.js";
34
- import { selectAgentRunTier } from "../../agent-definition/selectors.js";
34
+ import { selectAgentRunTier, selectAgentById } from "../../agent-definition/selectors.js";
35
35
  import { getShortcutRecordFromState } from "../../agent-shortcuts/selectors.js";
36
36
  import { ensureShortcutLoaded } from "../../agent-shortcuts/thunks.js";
37
37
  import { resolveShortcutMappings } from "../../../shortcuts/resolveShortcutMappings.js";
@@ -251,7 +251,7 @@ const launchAgentExecution = createAsyncThunk("instances/launch", async (options
251
251
  }
252
252
  const postState = getState();
253
253
  const postPayload = selectAgentRunTier(postState, agentId);
254
- const agentError = postState.agentDefinition.agents?.[agentId]?._error ?? null;
254
+ const agentError = selectAgentById(postState, agentId)?._error ?? null;
255
255
  if (debugProjectCreate) {
256
256
  if (!postPayload.isReady) {
257
257
  warnProjectCreateAi(
@@ -373,7 +373,7 @@ const launchAgentExecution = createAsyncThunk("instances/launch", async (options
373
373
  })
374
374
  ).unwrap();
375
375
  onConversationCreated?.(conversationId);
376
- const shortcutAgentRecord = shortcut.agentId ? getState().agentDefinition.agents?.[shortcut.agentId] : void 0;
376
+ const shortcutAgentRecord = shortcut.agentId ? selectAgentById(getState(), shortcut.agentId) : void 0;
377
377
  const {
378
378
  variables: shortcutPinnedVariables,
379
379
  contextEntries: shortcutLaunchMappedContext
@@ -487,7 +487,7 @@ const launchAgentExecution = createAsyncThunk("instances/launch", async (options
487
487
  }
488
488
  if (applicationScope) {
489
489
  const agState = getState();
490
- const agent = agState.agentDefinition.agents?.[agentId];
490
+ const agent = selectAgentById(agState, agentId);
491
491
  if (agent) {
492
492
  let surfaceValueMappings = null;
493
493
  if (surfaceName) {
@@ -1,3 +1,4 @@
1
+ import { selectAgentById } from "../../agent-definition/selectors.js";
1
2
  import { createAsyncThunk } from "@reduxjs/toolkit";
2
3
  import { supabase } from "../../../../host/db.js";
3
4
  import {
@@ -438,7 +439,7 @@ function storedTtftMs(metadata) {
438
439
  }
439
440
  async function agentClassPinForModel(state, agentId, modelId) {
440
441
  if (!agentId) return null;
441
- const record = state.agentDefinition?.agents?.[agentId];
442
+ const record = selectAgentById(state, agentId);
442
443
  if (record?.settings && record.modelId) {
443
444
  const pin2 = record.settings.offering_id;
444
445
  return record.modelId === modelId && typeof pin2 === "string" && pin2 ? pin2 : null;
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { selectAgentById } from "../../agent-definition/selectors.js";
2
3
  import { createAsyncThunk } from "@reduxjs/toolkit";
3
4
  import { toast } from "../../../../host/notify.js";
4
5
  import { getShortcutRecordFromState } from "../../agent-shortcuts/selectors.js";
@@ -39,7 +40,7 @@ async function refreshCompanionScope(conversationId, state, dispatch, { preview
39
40
  return { refreshed: false, reason: "no_surface" };
40
41
  }
41
42
  const agentId = state.conversations.byConversationId[conversationId]?.agentId;
42
- const agent = agentId ? state.agentDefinition.agents?.[agentId] : void 0;
43
+ const agent = agentId ? selectAgentById(state, agentId) : void 0;
43
44
  const result = mapScopeToInstanceWithSurface(
44
45
  scope,
45
46
  null,
@@ -212,7 +213,7 @@ const refreshSurfaceScope = createAsyncThunk(
212
213
  throw new Error(message, { cause: error });
213
214
  }
214
215
  applyLaunchWritePolicies(resolvedLayers, agentId, surfaceName);
215
- const agent = state.agentDefinition.agents?.[agentId];
216
+ const agent = selectAgentById(state, agentId);
216
217
  const displayMode = state.instanceUIState.byConversationId[conversationId]?.displayMode ?? "direct";
217
218
  const surfaceMappings = resolvedLayers ? await prepareLaunchMappings({
218
219
  merged: resolvedLayers.merged,
@@ -1,3 +1,4 @@
1
+ import { selectAgentById } from "../redux/agent-definition/selectors.js";
1
2
  import {
2
3
  fetchModelById,
3
4
  selectModelById
@@ -14,7 +15,7 @@ function selectRunModelId(state, conversationId) {
14
15
  const instance = state.conversations.byConversationId[conversationId];
15
16
  const sourceId = instance?.initialAgentVersionId ?? instance?.agentId;
16
17
  if (!sourceId) return null;
17
- return state.agentDefinition.agents?.[sourceId]?.modelId ?? null;
18
+ return selectAgentById(state, sourceId)?.modelId ?? null;
18
19
  }
19
20
  function resolveGenerationJob(state, conversationId) {
20
21
  const modelId = selectRunModelId(state, conversationId);
@@ -1,3 +1,4 @@
1
+ import { selectAgentById } from "../redux/agent-definition/selectors.js";
1
2
  import { selectModelById } from "../model-registry/modelRegistrySlice.js";
2
3
  import {
3
4
  parseCapabilities
@@ -5,7 +6,7 @@ import {
5
6
  function getCapabilitiesForConversation(state, conversationId) {
6
7
  const instance = state.conversations.byConversationId[conversationId];
7
8
  if (!instance?.agentId) return null;
8
- const agent = state.agentDefinition.agents?.[instance.agentId];
9
+ const agent = selectAgentById(state, instance.agentId);
9
10
  if (!agent?.modelId) return null;
10
11
  const model = selectModelById(state, agent.modelId);
11
12
  if (!model) return null;
@@ -10,6 +10,7 @@ import { loadConversation } from "../../agents/redux/execution-system/thunks/loa
10
10
  import { followWhatIsStillInFlight } from "../../agents/runtime-reconnect/follow-what-is-still-in-flight.js";
11
11
  import { toast } from "../../host/notify.js";
12
12
  import { isNotAuthenticatedError } from "../../host/identity.js";
13
+ import { isOrganizationSelectionCancelled } from "../../host/org.js";
13
14
  import { DEFAULT_AGENT_ID } from "../components/agent/local-agents.js";
14
15
  import { replaceAddressWithoutNavigating } from "../../ui/addressWithoutNavigating.js";
15
16
  import { ensureAgentCatalog, isAgentCatalogStale } from "../../agents/identity/agent-identity.js";
@@ -90,7 +91,8 @@ function useInstanceBootstrap() {
90
91
  resolvedId = result.payload.conversationId;
91
92
  instanceByAgentId.current.set(agentId, resolvedId);
92
93
  } else if (launchAgentExecution.rejected.match(result) && // Signed out is a state (the sign-in gate), not a failed launch.
93
- !isNotAuthenticatedError(result.error)) {
94
+ !isNotAuthenticatedError(result.error) && // A closed organization chooser is the person's "not now", never a failure.
95
+ !isOrganizationSelectionCancelled(result.error)) {
94
96
  toast.error(
95
97
  result.error.message ?? "Failed to start the agent conversation."
96
98
  );
@@ -2240,6 +2240,25 @@ export type ChatDatabase = {
2240
2240
  };
2241
2241
  Returns: Json;
2242
2242
  };
2243
+ duplicate_agent: {
2244
+ Args: {
2245
+ p_agent_id: string;
2246
+ p_as_system?: boolean;
2247
+ p_follows_source?: boolean;
2248
+ p_name?: string;
2249
+ p_organization_id?: string;
2250
+ };
2251
+ Returns: string;
2252
+ };
2253
+ duplicate_version: {
2254
+ Args: {
2255
+ p_as_system?: boolean;
2256
+ p_name?: string;
2257
+ p_organization_id?: string;
2258
+ p_version_id: string;
2259
+ };
2260
+ Returns: string;
2261
+ };
2243
2262
  message_flag_problems: {
2244
2263
  Args: never;
2245
2264
  Returns: {
@@ -9789,6 +9808,33 @@ export type ChatDatabase = {
9789
9808
  };
9790
9809
  Relationships: [];
9791
9810
  };
9811
+ rag_library_docs_bodies: {
9812
+ Row: {
9813
+ archived_at: string | null;
9814
+ body: string | null;
9815
+ body_hash: string | null;
9816
+ id: string;
9817
+ processed_document_id: string | null;
9818
+ title: string | null;
9819
+ };
9820
+ Insert: {
9821
+ archived_at?: string | null;
9822
+ body?: string | null;
9823
+ body_hash?: string | null;
9824
+ id: string;
9825
+ processed_document_id?: string | null;
9826
+ title?: string | null;
9827
+ };
9828
+ Update: {
9829
+ archived_at?: string | null;
9830
+ body?: string | null;
9831
+ body_hash?: string | null;
9832
+ id?: string;
9833
+ processed_document_id?: string | null;
9834
+ title?: string | null;
9835
+ };
9836
+ Relationships: [];
9837
+ };
9792
9838
  research_rs_content_bodies: {
9793
9839
  Row: {
9794
9840
  archived_at: string;
@@ -46153,7 +46199,7 @@ export type ChatDatabase = {
46153
46199
  operation_type: "insert" | "update" | "delete";
46154
46200
  org_role: "owner" | "member" | "admin";
46155
46201
  orientation: "vertical" | "horizontal" | "default";
46156
- permission_level: "viewer" | "commenter" | "editor" | "admin";
46202
+ permission_level: "viewer" | "commenter" | "edit_content" | "editor" | "admin";
46157
46203
  project_role: "owner" | "admin" | "member";
46158
46204
  recipe_status: "live" | "draft" | "in_review" | "active_testing" | "archived" | "other";
46159
46205
  reg_func_category: "Recipes" | "Agents" | "Prompts" | "Processors" | "Extractors" | "Files" | "Database" | "Web" | "Media" | "Documents" | "Integrations" | "Commands" | "Executors" | "API" | "Other";
@@ -10298,6 +10298,25 @@ export declare function mandateNotes(supabase: Client): import("@supabase/supaba
10298
10298
  };
10299
10299
  Returns: Json;
10300
10300
  };
10301
+ duplicate_agent: {
10302
+ Args: {
10303
+ p_agent_id: string;
10304
+ p_as_system?: boolean;
10305
+ p_follows_source?: boolean;
10306
+ p_name?: string;
10307
+ p_organization_id?: string;
10308
+ };
10309
+ Returns: string;
10310
+ };
10311
+ duplicate_version: {
10312
+ Args: {
10313
+ p_as_system?: boolean;
10314
+ p_name?: string;
10315
+ p_organization_id?: string;
10316
+ p_version_id: string;
10317
+ };
10318
+ Returns: string;
10319
+ };
10301
10320
  message_flag_problems: {
10302
10321
  Args: never;
10303
10322
  Returns: {
@@ -1941,6 +1941,25 @@ declare const agentShortcutTable: (supabase: Client) => import("@supabase/supaba
1941
1941
  };
1942
1942
  Returns: import("../../host/db-types.js").Json;
1943
1943
  };
1944
+ duplicate_agent: {
1945
+ Args: {
1946
+ p_agent_id: string;
1947
+ p_as_system?: boolean;
1948
+ p_follows_source?: boolean;
1949
+ p_name?: string;
1950
+ p_organization_id?: string;
1951
+ };
1952
+ Returns: string;
1953
+ };
1954
+ duplicate_version: {
1955
+ Args: {
1956
+ p_as_system?: boolean;
1957
+ p_name?: string;
1958
+ p_organization_id?: string;
1959
+ p_version_id: string;
1960
+ };
1961
+ Returns: string;
1962
+ };
1944
1963
  message_flag_problems: {
1945
1964
  Args: never;
1946
1965
  Returns: {
@@ -4137,6 +4156,25 @@ declare const agentContextMenuView: (supabase: Client) => import("@supabase/supa
4137
4156
  };
4138
4157
  Returns: import("../../host/db-types.js").Json;
4139
4158
  };
4159
+ duplicate_agent: {
4160
+ Args: {
4161
+ p_agent_id: string;
4162
+ p_as_system?: boolean;
4163
+ p_follows_source?: boolean;
4164
+ p_name?: string;
4165
+ p_organization_id?: string;
4166
+ };
4167
+ Returns: string;
4168
+ };
4169
+ duplicate_version: {
4170
+ Args: {
4171
+ p_as_system?: boolean;
4172
+ p_name?: string;
4173
+ p_organization_id?: string;
4174
+ p_version_id: string;
4175
+ };
4176
+ Returns: string;
4177
+ };
4140
4178
  message_flag_problems: {
4141
4179
  Args: never;
4142
4180
  Returns: {
@@ -44,12 +44,18 @@ import type { ChatDatabase as Database } from "../host/db-types.js";
44
44
  * The canonical ladder, ascending. THE ONE PLACE a level is declared.
45
45
  * Order is authority order: each entry outranks every entry before it.
46
46
  */
47
- export declare const PERMISSION_LEVELS: readonly ["viewer", "commenter", "editor", "admin"];
47
+ export declare const PERMISSION_LEVELS: readonly ["viewer", "commenter", "edit_content", "editor", "admin"];
48
48
  export type PermissionLevel = (typeof PERMISSION_LEVELS)[number];
49
49
  /** Ordinal rank, 1-based, derived from the ladder so it can never drift. */
50
50
  export declare const PERMISSION_LEVEL_RANK: Record<PermissionLevel, number>;
51
51
  /** Sentence labels, used where the level is described ("Can view"). */
52
52
  export declare const PERMISSION_LEVEL_LABELS: Record<PermissionLevel, string>;
53
+ /**
54
+ * One line each, for a picker's tooltip: what the level lets a person do. `edit_content` is
55
+ * Notion's "Can edit content" - change the rows and page content, never the structure
56
+ * (columns, views, settings) or the sharing. It sorts between `commenter` and `editor`.
57
+ */
58
+ export declare const PERMISSION_LEVEL_HINTS: Record<PermissionLevel, string>;
53
59
  /** Noun labels, used in pickers and chips ("Viewer"). */
54
60
  export declare const PERMISSION_LEVEL_SHORT_LABELS: Record<PermissionLevel, string>;
55
61
  /**
@@ -63,7 +69,7 @@ export type DbPermissionLevel = Database["public"]["Enums"]["permission_level"];
63
69
  * below: when `public.permission_level` gains a value and `pnpm db-types` regenerates, this
64
70
  * line stops compiling until the new value is added — never a silent gap.
65
71
  */
66
- export declare const DB_PERMISSION_LEVELS: readonly ["viewer", "commenter", "editor", "admin"];
72
+ export declare const DB_PERMISSION_LEVELS: readonly ["viewer", "commenter", "edit_content", "editor", "admin"];
67
73
  /** Type guard for an arbitrary value being a known code-ladder level. */
68
74
  export declare function isPermissionLevel(raw: unknown): raw is PermissionLevel;
69
75
  /** True when the database enum can currently store this level. */