@iloveagents/foundry-agent 0.1.5 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,107 @@
1
1
  # @iloveagents/foundry-agent
2
2
 
3
+ ## 0.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 8184a8c: shell: URL is authoritative for the runtime threadId — fixes
8
+ resume-creates-new-conversation race
9
+
10
+ `ChatConversationAwareRuntime` previously computed
11
+ `effectiveThreadId = sticky ?? urlMatch ?? freshIdRef.current`.
12
+ When the user navigated from one chat to another via a Recents
13
+ click, the synchronous render that followed the URL change had:
14
+ - `urlMatch = B` (read from the now-updated `useLocation`)
15
+ - `sticky = A` (the active-chat-store hadn't been updated by
16
+ `useTrackActiveChatFromUrl`'s `useEffect` yet — effects run
17
+ AFTER the commit phase)
18
+
19
+ `sticky ?? urlMatch` picked `A` (the previous chat). The AG-UI
20
+ adapter was constructed with `threadId = A`. The first message the
21
+ user sent went to `/api/agent` with `thread_id = A`, the middleware
22
+ created a new row keyed by `A`... wait actually no, here's what
23
+ happens — the runtime mints a fresh runner UUID when given a
24
+ mismatched threadId; that fresh UUID became a new conversation row,
25
+ appearing as "Untitled chat" at the top of the sidebar while the
26
+ URL still said `/chat/B`. Two active-looking dots: one for `B`
27
+ (NavLink URL match), one for the new row (statusDot from the
28
+ updated active-chat-store after the lazy ensure ran).
29
+
30
+ Swap the priority: `urlMatch ?? sticky ?? freshIdRef.current`. The
31
+ URL is authoritative whenever it's set (i.e. on `/chat/<id>`
32
+ routes), eliminating the stale-sticky race entirely. `sticky` is
33
+ still consulted as the second-priority fallback for non-chat
34
+ routes (`/spaces`, `/tasks`) so the popout chat stays "live" while
35
+ the user browses workspaces — that's the original purpose of
36
+ `useStickyConversationId` and it's preserved.
37
+
38
+ ## 0.2.1
39
+
40
+ ### Patch Changes
41
+
42
+ - No source changes. The 0.2.0 publish for `@iloveagents/foundry-agent` and
43
+ `@iloveagents/foundry-web-primitives` failed because npm had `0.2.0`
44
+ reserved for those two packages from an older publish-then-unpublish
45
+ cycle (the version was reserved before the recent v1 incident — see
46
+ git tag history). `@iloveagents/foundry-web-shell@0.2.0` and
47
+ `@iloveagents/foundry-web-ui@0.2.0` published cleanly. Bumping the
48
+ whole fixed group to 0.2.1 so all four publish together at a version
49
+ number that's free across all four packages.
50
+
51
+ ## 0.2.0
52
+
53
+ ### Minor Changes
54
+
55
+ - shell: ChatConversationConfig API + sticky-runtime threadId
56
+
57
+ Lets a downstream module (e.g. `@ltwlf/spaces-web-ui`) attach a
58
+ `ChatConversationConfig` to its `ChatModule`. The shell then:
59
+ - Pre-mints a fresh thread UUID via `useRef` so the AG-UI runtime's
60
+ `threadId` is defined from first render — no `undefined → defined`
61
+ remount mid-conversation when the user sends the first message.
62
+ - Calls `config.useStickyConversationId()` (when declared) and
63
+ feeds the resulting id into the runtime so the chat stays "live"
64
+ while the user browses non-chat routes (Workspaces, Jobs, etc.).
65
+ - Per-config keyed child components (`StickyAwareRuntime` vs
66
+ `UrlOnlyRuntime`) so optional hooks satisfy Rules-of-Hooks across
67
+ multi-module config swaps.
68
+
69
+ UI: collapsible nav groups in `sidebar.tsx` with persisted state via
70
+ `useSyncExternalStore` + localStorage, plus stable group ordering via
71
+ new `priority` field in `nav-config.ts`.
72
+
73
+ `ag-ui-runtime-provider.tsx` accepts an external `threadId` and
74
+ `historyAdapterFactory` so the consuming app can wire its own
75
+ persistence (e.g. `ThreadHistoryAdapter` → REST `/api/conversations`).
76
+
77
+ ### Patch Changes
78
+
79
+ - Fix `citationStore.clear()` so the registered handler survives per-conversation resets.
80
+
81
+ The previous implementation wiped both `results` AND `handler`. `useNewConversation` calls `clear()` on every "New Thread" click. Combined with the `registerOnce`-style handler registration in feature modules (e.g. SPACES' `registerSpacesCitationHandler`), the result was that all `[n]` citation markers in chat became inert non-clickable spans for the rest of the session after the first new-thread click. `clear()` now resets `results` only — the handler is module-level state and must persist.
82
+
83
+ - Move sibling `@iloveagents/foundry-*` declarations from `peerDependencies`
84
+ to `dependencies` in `foundry-web-shell` and `foundry-web-ui`. These four
85
+ packages always ship together as a coordinated fixed group from the same
86
+ monorepo — they were never independently-versioned peers, so declaring
87
+ them as peerDeps caused changesets' `shouldBumpMajor` cascade to promote
88
+ the entire group to a major version on every minor changeset (a single
89
+ minor on any of the four would exit the sibling's `^0.x.y` peerDep range
90
+ → all dependents promoted to major → fixed group synced all four to
91
+ major → 0.1.5 unexpectedly jumped to 1.0.0). Moving to `dependencies`
92
+ eliminates the cascade entirely; `dependencies` never trigger
93
+ `shouldBumpMajor`. Consumers that already install each foundry-\* package
94
+ directly are unaffected — pnpm hoists by name, so a single instance
95
+ resolves across the dep graph regardless of declaration site.
96
+
97
+ ### NOTE: 1.0.0 / 1.0.1 were accidental
98
+
99
+ These version numbers were published briefly on 2026-05-27 due to the
100
+ peerDep cascade bug described above, then unpublished. The version
101
+ numbers themselves are now permanently reserved on npm and CANNOT be
102
+ re-published. This 0.2.0 release captures all the work that was in
103
+ the accidental 1.0.x releases. Do not depend on 1.0.x.
104
+
3
105
  ## 0.1.5
4
106
 
5
107
  ## 0.1.4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloveagents/foundry-agent",
3
- "version": "0.1.5",
3
+ "version": "0.2.2",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "type": "module",
6
6
  "types": "./src/index.ts",
@@ -33,14 +33,20 @@ describe("citationStore", () => {
33
33
  });
34
34
 
35
35
  describe("clear", () => {
36
- it("resets results and handler", () => {
36
+ it("resets results but preserves the registered handler", () => {
37
+ // The handler is registered once at app boot by a feature module
38
+ // (e.g. SPACES). It MUST survive "New Thread" / per-conversation
39
+ // resets — otherwise every [n] marker in chat becomes inert after
40
+ // the first new-thread click, since the registration guard
41
+ // suppresses re-binding for the rest of the session.
42
+ const handler: CitationHandler = { openCitation: () => {} };
37
43
  citationStore.getState().setResults([mockResult]);
38
- citationStore.getState().setHandler({ openCitation: () => {} });
44
+ citationStore.getState().setHandler(handler);
39
45
 
40
46
  citationStore.getState().clear();
41
47
 
42
48
  expect(citationStore.getState().results).toEqual([]);
43
- expect(citationStore.getState().handler).toBeNull();
49
+ expect(citationStore.getState().handler).toBe(handler);
44
50
  });
45
51
  });
46
52
  });
@@ -26,7 +26,14 @@ interface CitationState {
26
26
  setResults: (results: CitationResult[]) => void;
27
27
  /** Register a handler for citation click actions */
28
28
  setHandler: (handler: CitationHandler) => void;
29
- /** Clear all citations (e.g. on new conversation) */
29
+ /**
30
+ * Reset per-conversation state. Clears ``results`` only — the handler
31
+ * is module-level state registered once at app boot by feature modules
32
+ * (e.g. ``registerSpacesCitationHandler``) and must persist across
33
+ * conversations. Wiping it on "New Thread" produced inert ``[n]``
34
+ * markers for the rest of the session, since the registration guard
35
+ * (``registerOnce`` in spaces ``use-spaces-init``) suppresses re-binding.
36
+ */
30
37
  clear: () => void;
31
38
  }
32
39
 
@@ -41,5 +48,5 @@ export const citationStore = createStore<CitationState>((set) => ({
41
48
  handler: null,
42
49
  setResults: (results) => set({ results }),
43
50
  setHandler: (handler) => set({ handler }),
44
- clear: () => set({ results: [], handler: null }),
51
+ clear: () => set({ results: [] }),
45
52
  }));