@townco/ui 0.1.48 → 0.1.50

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 (51) hide show
  1. package/dist/core/hooks/index.d.ts +1 -0
  2. package/dist/core/hooks/index.js +1 -0
  3. package/dist/core/hooks/use-chat-input.d.ts +2 -0
  4. package/dist/core/hooks/use-chat-input.js +11 -1
  5. package/dist/core/hooks/use-chat-messages.d.ts +22 -1
  6. package/dist/core/hooks/use-chat-messages.js +19 -4
  7. package/dist/core/hooks/use-chat-session.d.ts +1 -1
  8. package/dist/core/hooks/use-chat-session.js +22 -0
  9. package/dist/core/hooks/use-message-history.d.ts +12 -0
  10. package/dist/core/hooks/use-message-history.js +113 -0
  11. package/dist/core/hooks/use-tool-calls.d.ts +11 -0
  12. package/dist/core/schemas/chat.d.ts +40 -0
  13. package/dist/core/schemas/chat.js +9 -0
  14. package/dist/core/schemas/tool-call.d.ts +34 -0
  15. package/dist/core/schemas/tool-call.js +27 -0
  16. package/dist/core/store/chat-store.d.ts +5 -0
  17. package/dist/core/store/chat-store.js +46 -0
  18. package/dist/gui/components/ChatEmptyState.d.ts +4 -0
  19. package/dist/gui/components/ChatEmptyState.js +2 -2
  20. package/dist/gui/components/ChatInput.d.ts +21 -1
  21. package/dist/gui/components/ChatInput.js +184 -7
  22. package/dist/gui/components/ChatLayout.d.ts +3 -2
  23. package/dist/gui/components/ChatLayout.js +7 -7
  24. package/dist/gui/components/ChatPanelTabContent.d.ts +17 -0
  25. package/dist/gui/components/ChatPanelTabContent.js +6 -5
  26. package/dist/gui/components/ChatView.d.ts +3 -1
  27. package/dist/gui/components/ChatView.js +81 -49
  28. package/dist/gui/components/InvokingGroup.d.ts +9 -0
  29. package/dist/gui/components/InvokingGroup.js +16 -0
  30. package/dist/gui/components/MessageContent.js +122 -6
  31. package/dist/gui/components/PanelTabsHeader.d.ts +1 -1
  32. package/dist/gui/components/PanelTabsHeader.js +6 -1
  33. package/dist/gui/components/Response.js +2 -0
  34. package/dist/gui/components/Task.js +3 -3
  35. package/dist/gui/components/TodoListItem.js +1 -1
  36. package/dist/gui/components/ToolCall.js +57 -5
  37. package/dist/gui/components/ToolCallGroup.d.ts +8 -0
  38. package/dist/gui/components/ToolCallGroup.js +29 -0
  39. package/dist/gui/components/index.d.ts +1 -2
  40. package/dist/gui/components/index.js +1 -2
  41. package/dist/sdk/client/acp-client.d.ts +24 -1
  42. package/dist/sdk/client/acp-client.js +28 -7
  43. package/dist/sdk/schemas/message.d.ts +41 -9
  44. package/dist/sdk/schemas/message.js +15 -3
  45. package/dist/sdk/schemas/session.d.ts +81 -16
  46. package/dist/sdk/transports/http.d.ts +14 -0
  47. package/dist/sdk/transports/http.js +130 -36
  48. package/dist/sdk/transports/stdio.d.ts +14 -0
  49. package/dist/sdk/transports/stdio.js +27 -10
  50. package/dist/sdk/transports/types.d.ts +29 -0
  51. package/package.json +7 -3
@@ -45,17 +45,25 @@ export class HttpTransport {
45
45
  };
46
46
  const initResponse = await this.sendRpcRequest("initialize", initRequest);
47
47
  if (initResponse.agentInfo) {
48
- // Read description and suggestedPrompts from _meta extension point (ACP protocol extension)
49
- const description = initResponse._meta &&
50
- typeof initResponse._meta === "object" &&
51
- "agentDescription" in initResponse._meta
52
- ? String(initResponse._meta.agentDescription)
48
+ // Read extended info from _meta extension point (ACP protocol extension)
49
+ const meta = initResponse._meta;
50
+ const metaIsObject = meta && typeof meta === "object";
51
+ const description = metaIsObject && "agentDescription" in meta
52
+ ? String(meta.agentDescription)
53
53
  : undefined;
54
- const suggestedPrompts = initResponse._meta &&
55
- typeof initResponse._meta === "object" &&
56
- "suggestedPrompts" in initResponse._meta &&
57
- Array.isArray(initResponse._meta.suggestedPrompts)
58
- ? initResponse._meta.suggestedPrompts
54
+ const suggestedPrompts = metaIsObject &&
55
+ "suggestedPrompts" in meta &&
56
+ Array.isArray(meta.suggestedPrompts)
57
+ ? meta.suggestedPrompts
58
+ : undefined;
59
+ const tools = metaIsObject && "tools" in meta && Array.isArray(meta.tools)
60
+ ? meta.tools
61
+ : undefined;
62
+ const mcps = metaIsObject && "mcps" in meta && Array.isArray(meta.mcps)
63
+ ? meta.mcps
64
+ : undefined;
65
+ const subagents = metaIsObject && "subagents" in meta && Array.isArray(meta.subagents)
66
+ ? meta.subagents
59
67
  : undefined;
60
68
  this.agentInfo = {
61
69
  name: initResponse.agentInfo.name,
@@ -66,6 +74,9 @@ export class HttpTransport {
66
74
  version: initResponse.agentInfo.version,
67
75
  ...(description ? { description } : {}),
68
76
  ...(suggestedPrompts ? { suggestedPrompts } : {}),
77
+ ...(tools ? { tools } : {}),
78
+ ...(mcps ? { mcps } : {}),
79
+ ...(subagents ? { subagents } : {}),
69
80
  };
70
81
  }
71
82
  logger.info("ACP connection initialized", { initResponse });
@@ -115,17 +126,25 @@ export class HttpTransport {
115
126
  logger.info("Loading session - initializing connection", { sessionId });
116
127
  const initResponse = await this.sendRpcRequest("initialize", initRequest);
117
128
  if (initResponse.agentInfo) {
118
- // Read description and suggestedPrompts from _meta extension point (ACP protocol extension)
119
- const description = initResponse._meta &&
120
- typeof initResponse._meta === "object" &&
121
- "agentDescription" in initResponse._meta
122
- ? String(initResponse._meta.agentDescription)
129
+ // Read extended info from _meta extension point (ACP protocol extension)
130
+ const meta = initResponse._meta;
131
+ const metaIsObject = meta && typeof meta === "object";
132
+ const description = metaIsObject && "agentDescription" in meta
133
+ ? String(meta.agentDescription)
134
+ : undefined;
135
+ const suggestedPrompts = metaIsObject &&
136
+ "suggestedPrompts" in meta &&
137
+ Array.isArray(meta.suggestedPrompts)
138
+ ? meta.suggestedPrompts
139
+ : undefined;
140
+ const tools = metaIsObject && "tools" in meta && Array.isArray(meta.tools)
141
+ ? meta.tools
123
142
  : undefined;
124
- const suggestedPrompts = initResponse._meta &&
125
- typeof initResponse._meta === "object" &&
126
- "suggestedPrompts" in initResponse._meta &&
127
- Array.isArray(initResponse._meta.suggestedPrompts)
128
- ? initResponse._meta.suggestedPrompts
143
+ const mcps = metaIsObject && "mcps" in meta && Array.isArray(meta.mcps)
144
+ ? meta.mcps
145
+ : undefined;
146
+ const subagents = metaIsObject && "subagents" in meta && Array.isArray(meta.subagents)
147
+ ? meta.subagents
129
148
  : undefined;
130
149
  this.agentInfo = {
131
150
  name: initResponse.agentInfo.name,
@@ -136,6 +155,9 @@ export class HttpTransport {
136
155
  version: initResponse.agentInfo.version,
137
156
  ...(description ? { description } : {}),
138
157
  ...(suggestedPrompts ? { suggestedPrompts } : {}),
158
+ ...(tools ? { tools } : {}),
159
+ ...(mcps ? { mcps } : {}),
160
+ ...(subagents ? { subagents } : {}),
139
161
  };
140
162
  }
141
163
  // Check if loadSession is supported
@@ -226,19 +248,43 @@ export class HttpTransport {
226
248
  this.streamComplete = false;
227
249
  this.messageQueue = [];
228
250
  // Convert our message format to ACP prompt format
229
- const textContent = message.content
230
- .filter((c) => c.type === "text")
231
- .map((c) => c.text)
232
- .join("\n");
251
+ // Send ALL content blocks (images, text, etc.) not just text
252
+ const promptBlocks = message.content.map((block) => {
253
+ if (block.type === "text") {
254
+ return {
255
+ type: "text",
256
+ text: block.text,
257
+ };
258
+ }
259
+ else if (block.type === "image") {
260
+ // Convert from Claude API format to ACP format
261
+ // Claude format: { type: "image", source: { type: "base64", media_type: "...", data: "..." } }
262
+ // ACP format: { type: "image", data: "...", mimeType: "..." }
263
+ if ("source" in block && block.source) {
264
+ return {
265
+ type: "image",
266
+ data: block.source.data,
267
+ mimeType: block.source.media_type,
268
+ };
269
+ }
270
+ // Fallback for other image formats
271
+ if ("data" in block && "mimeType" in block) {
272
+ return {
273
+ type: "image",
274
+ data: block.data,
275
+ mimeType: block.mimeType,
276
+ };
277
+ }
278
+ // Pass through as-is if neither format matches
279
+ return block;
280
+ }
281
+ // Other content types - pass through
282
+ return block;
283
+ });
233
284
  // Create ACP prompt request
234
285
  const promptRequest = {
235
286
  sessionId: this.currentSessionId,
236
- prompt: [
237
- {
238
- type: "text",
239
- text: textContent,
240
- },
241
- ],
287
+ prompt: promptBlocks,
242
288
  };
243
289
  // Send the prompt - this will trigger streaming responses via SSE
244
290
  const promptResponse = await this.sendRpcRequest("session/prompt", promptRequest);
@@ -565,7 +611,7 @@ export class HttpTransport {
565
611
  logger.debug("Tool call notification", {
566
612
  tokenUsage: update.tokenUsage,
567
613
  });
568
- // Extract messageId from _meta
614
+ // Extract messageId, prettyName, and icon from _meta
569
615
  const messageId = update._meta &&
570
616
  typeof update._meta === "object" &&
571
617
  "messageId" in update._meta
@@ -573,20 +619,36 @@ export class HttpTransport {
573
619
  : undefined;
574
620
  const prettyName = update._meta &&
575
621
  typeof update._meta === "object" &&
576
- "prettyName" in update._meta
577
- ? String(update._meta.prettyName)
622
+ "prettyName" in update._meta &&
623
+ typeof update._meta.prettyName === "string"
624
+ ? update._meta.prettyName
578
625
  : undefined;
579
626
  const icon = update._meta &&
580
627
  typeof update._meta === "object" &&
581
- "icon" in update._meta
582
- ? String(update._meta.icon)
628
+ "icon" in update._meta &&
629
+ typeof update._meta.icon === "string"
630
+ ? update._meta.icon
631
+ : undefined;
632
+ const subline = update._meta &&
633
+ typeof update._meta === "object" &&
634
+ "subline" in update._meta &&
635
+ typeof update._meta.subline === "string"
636
+ ? update._meta.subline
637
+ : undefined;
638
+ const batchId = update._meta &&
639
+ typeof update._meta === "object" &&
640
+ "batchId" in update._meta &&
641
+ typeof update._meta.batchId === "string"
642
+ ? update._meta.batchId
583
643
  : undefined;
584
644
  // Initial tool call notification
585
645
  const toolCall = {
586
646
  id: update.toolCallId ?? "",
647
+ batchId,
587
648
  title: update.title ?? "",
588
649
  prettyName,
589
650
  icon,
651
+ subline,
590
652
  kind: update.kind || "other",
591
653
  status: update.status || "pending",
592
654
  locations: update.locations,
@@ -650,16 +712,39 @@ export class HttpTransport {
650
712
  this.notifySessionUpdate(sessionUpdate);
651
713
  }
652
714
  else if (update?.sessionUpdate === "tool_call_update") {
653
- // Extract messageId from _meta
715
+ // Extract messageId and metadata from _meta
654
716
  const messageId = update._meta &&
655
717
  typeof update._meta === "object" &&
656
718
  "messageId" in update._meta
657
719
  ? String(update._meta.messageId)
658
720
  : undefined;
721
+ const prettyName = update._meta &&
722
+ typeof update._meta === "object" &&
723
+ "prettyName" in update._meta &&
724
+ typeof update._meta.prettyName === "string"
725
+ ? update._meta.prettyName
726
+ : undefined;
727
+ const icon = update._meta &&
728
+ typeof update._meta === "object" &&
729
+ "icon" in update._meta &&
730
+ typeof update._meta.icon === "string"
731
+ ? update._meta.icon
732
+ : undefined;
733
+ const batchId = update._meta &&
734
+ typeof update._meta === "object" &&
735
+ "batchId" in update._meta &&
736
+ typeof update._meta.batchId === "string"
737
+ ? update._meta.batchId
738
+ : undefined;
659
739
  // Tool call update notification
660
740
  const toolCallUpdate = {
661
741
  id: update.toolCallId ?? "",
662
742
  status: update.status,
743
+ title: update.title,
744
+ prettyName,
745
+ icon,
746
+ batchId,
747
+ rawInput: update.rawInput,
663
748
  locations: update.locations,
664
749
  rawOutput: update.rawOutput,
665
750
  tokenUsage: update.tokenUsage,
@@ -785,6 +870,15 @@ export class HttpTransport {
785
870
  ? content.terminalId
786
871
  : "",
787
872
  };
873
+ if (content.type === "image")
874
+ return {
875
+ type: "image",
876
+ data: typeof content.data === "string" ? content.data : "",
877
+ mimeType: typeof content.mimeType === "string"
878
+ ? content.mimeType
879
+ : "image/png",
880
+ alt: typeof content.alt === "string" ? content.alt : undefined,
881
+ };
788
882
  return { type: "text", text: "" };
789
883
  }),
790
884
  };
@@ -31,6 +31,20 @@ export declare class StdioTransport implements Transport {
31
31
  version?: string;
32
32
  description?: string;
33
33
  suggestedPrompts?: string[];
34
+ tools?: Array<{
35
+ name: string;
36
+ description?: string;
37
+ prettyName?: string;
38
+ icon?: string;
39
+ }>;
40
+ mcps?: Array<{
41
+ name: string;
42
+ transport: string;
43
+ }>;
44
+ subagents?: Array<{
45
+ name: string;
46
+ description: string;
47
+ }>;
34
48
  };
35
49
  private notifySessionUpdate;
36
50
  private notifyError;
@@ -109,12 +109,18 @@ export class StdioTransport {
109
109
  "icon" in update._meta
110
110
  ? String(update._meta.icon)
111
111
  : undefined;
112
+ const subline = update._meta &&
113
+ typeof update._meta === "object" &&
114
+ "subline" in update._meta
115
+ ? String(update._meta.subline)
116
+ : undefined;
112
117
  // Initial tool call notification
113
118
  const toolCall = {
114
119
  id: update.toolCallId ?? "",
115
120
  title: update.title ?? "",
116
121
  prettyName,
117
122
  icon,
123
+ subline,
118
124
  kind: update.kind || "other",
119
125
  status: update.status || "pending",
120
126
  locations: update.locations,
@@ -355,17 +361,25 @@ export class StdioTransport {
355
361
  },
356
362
  });
357
363
  if (initResponse.agentInfo) {
358
- // Read description and suggestedPrompts from _meta extension point (ACP protocol extension)
359
- const description = initResponse._meta &&
360
- typeof initResponse._meta === "object" &&
361
- "agentDescription" in initResponse._meta
362
- ? String(initResponse._meta.agentDescription)
364
+ // Read extended info from _meta extension point (ACP protocol extension)
365
+ const meta = initResponse._meta;
366
+ const metaIsObject = meta && typeof meta === "object";
367
+ const description = metaIsObject && "agentDescription" in meta
368
+ ? String(meta.agentDescription)
369
+ : undefined;
370
+ const suggestedPrompts = metaIsObject &&
371
+ "suggestedPrompts" in meta &&
372
+ Array.isArray(meta.suggestedPrompts)
373
+ ? meta.suggestedPrompts
374
+ : undefined;
375
+ const tools = metaIsObject && "tools" in meta && Array.isArray(meta.tools)
376
+ ? meta.tools
377
+ : undefined;
378
+ const mcps = metaIsObject && "mcps" in meta && Array.isArray(meta.mcps)
379
+ ? meta.mcps
363
380
  : undefined;
364
- const suggestedPrompts = initResponse._meta &&
365
- typeof initResponse._meta === "object" &&
366
- "suggestedPrompts" in initResponse._meta &&
367
- Array.isArray(initResponse._meta.suggestedPrompts)
368
- ? initResponse._meta.suggestedPrompts
381
+ const subagents = metaIsObject && "subagents" in meta && Array.isArray(meta.subagents)
382
+ ? meta.subagents
369
383
  : undefined;
370
384
  this.agentInfo = {
371
385
  name: initResponse.agentInfo.name,
@@ -376,6 +390,9 @@ export class StdioTransport {
376
390
  version: initResponse.agentInfo.version,
377
391
  ...(description ? { description } : {}),
378
392
  ...(suggestedPrompts ? { suggestedPrompts } : {}),
393
+ ...(tools ? { tools } : {}),
394
+ ...(mcps ? { mcps } : {}),
395
+ ...(subagents ? { subagents } : {}),
379
396
  };
380
397
  }
381
398
  logger.info("ACP connection initialized", { initResponse });
@@ -1,4 +1,27 @@
1
1
  import type { Message, MessageChunk, SessionUpdate } from "../schemas/index.js";
2
+ /**
3
+ * Agent tool information exposed via initialize response
4
+ */
5
+ export interface AgentToolInfo {
6
+ name: string;
7
+ description?: string;
8
+ prettyName?: string;
9
+ icon?: string;
10
+ }
11
+ /**
12
+ * Agent MCP (Model Context Protocol) server information
13
+ */
14
+ export interface AgentMcpInfo {
15
+ name: string;
16
+ transport: string;
17
+ }
18
+ /**
19
+ * Agent subagent information (exposed via Task tool metadata)
20
+ */
21
+ export interface AgentSubagentInfo {
22
+ name: string;
23
+ description: string;
24
+ }
2
25
  /**
3
26
  * Transport interface for different communication methods
4
27
  */
@@ -40,6 +63,9 @@ export interface Transport {
40
63
  * Get agent information
41
64
  * - displayName: Human-readable name for UI (from ACP title field)
42
65
  * - name: Programmatic name (fallback if displayName not set)
66
+ * - tools: List of tools available to the agent
67
+ * - mcps: List of MCP servers connected to the agent
68
+ * - subagents: List of subagents available via Task tool
43
69
  */
44
70
  getAgentInfo?(): {
45
71
  name?: string;
@@ -47,6 +73,9 @@ export interface Transport {
47
73
  version?: string;
48
74
  description?: string;
49
75
  suggestedPrompts?: string[];
76
+ tools?: AgentToolInfo[];
77
+ mcps?: AgentMcpInfo[];
78
+ subagents?: AgentSubagentInfo[];
50
79
  };
51
80
  }
52
81
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@townco/ui",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -15,18 +15,22 @@
15
15
  },
16
16
  "exports": {
17
17
  ".": {
18
+ "development": "./src/index.ts",
18
19
  "import": "./dist/index.js",
19
20
  "types": "./dist/index.d.ts"
20
21
  },
21
22
  "./core": {
23
+ "development": "./src/core/index.ts",
22
24
  "import": "./dist/core/index.js",
23
25
  "types": "./dist/core/index.d.ts"
24
26
  },
25
27
  "./tui": {
28
+ "development": "./src/tui/index.ts",
26
29
  "import": "./dist/tui/index.js",
27
30
  "types": "./dist/tui/index.d.ts"
28
31
  },
29
32
  "./gui": {
33
+ "development": "./src/gui/index.ts",
30
34
  "import": "./dist/gui/index.js",
31
35
  "types": "./dist/gui/index.d.ts"
32
36
  },
@@ -40,7 +44,7 @@
40
44
  },
41
45
  "dependencies": {
42
46
  "@agentclientprotocol/sdk": "^0.5.1",
43
- "@townco/core": "0.0.26",
47
+ "@townco/core": "0.0.28",
44
48
  "@radix-ui/react-dialog": "^1.1.15",
45
49
  "@radix-ui/react-dropdown-menu": "^2.1.16",
46
50
  "@radix-ui/react-label": "^2.1.8",
@@ -63,7 +67,7 @@
63
67
  },
64
68
  "devDependencies": {
65
69
  "@tailwindcss/postcss": "^4.1.17",
66
- "@townco/tsconfig": "0.1.45",
70
+ "@townco/tsconfig": "0.1.47",
67
71
  "@types/node": "^24.10.0",
68
72
  "@types/react": "^19.2.2",
69
73
  "ink": "^6.4.0",