@townco/ui 0.1.44 → 0.1.46
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/dist/core/hooks/use-chat-messages.d.ts +6 -0
- package/dist/core/hooks/use-chat-messages.js +22 -1
- package/dist/core/hooks/use-chat-session.js +19 -3
- package/dist/core/hooks/use-tool-calls.d.ts +6 -0
- package/dist/core/schemas/chat.d.ts +18 -0
- package/dist/core/schemas/tool-call.d.ts +9 -0
- package/dist/core/schemas/tool-call.js +9 -0
- package/dist/core/store/chat-store.d.ts +14 -0
- package/dist/core/store/chat-store.js +3 -0
- package/dist/gui/components/Button.d.ts +1 -1
- package/dist/gui/components/ChatView.js +29 -15
- package/dist/gui/components/ContextUsageButton.d.ts +11 -3
- package/dist/gui/components/ContextUsageButton.js +22 -3
- package/dist/gui/components/MessageContent.d.ts +5 -0
- package/dist/gui/components/MessageContent.js +2 -55
- package/dist/gui/components/ToolCall.js +1 -1
- package/dist/sdk/client/acp-client.d.ts +12 -0
- package/dist/sdk/client/acp-client.js +19 -0
- package/dist/sdk/schemas/message.d.ts +14 -2
- package/dist/sdk/schemas/message.js +16 -0
- package/dist/sdk/schemas/session.d.ts +19 -6
- package/dist/sdk/schemas/session.js +1 -0
- package/dist/sdk/transports/http.d.ts +8 -0
- package/dist/sdk/transports/http.js +79 -8
- package/dist/sdk/transports/stdio.d.ts +8 -0
- package/dist/sdk/transports/stdio.js +28 -0
- package/dist/sdk/transports/types.d.ts +12 -0
- package/dist/tui/components/ToolCall.js +1 -1
- package/package.json +3 -3
- package/src/styles/global.css +15 -0
- package/dist/core/lib/logger.d.ts +0 -59
- package/dist/core/lib/logger.js +0 -191
- package/dist/tui/components/LogsPanel.d.ts +0 -5
- package/dist/tui/components/LogsPanel.js +0 -29
|
@@ -13,9 +13,9 @@ export type MessageRole = z.infer<typeof MessageRole>;
|
|
|
13
13
|
* Content type for messages
|
|
14
14
|
*/
|
|
15
15
|
export declare const ContentType: z.ZodEnum<{
|
|
16
|
-
file: "file";
|
|
17
16
|
text: "text";
|
|
18
17
|
image: "image";
|
|
18
|
+
file: "file";
|
|
19
19
|
tool_call: "tool_call";
|
|
20
20
|
tool_result: "tool_result";
|
|
21
21
|
}>;
|
|
@@ -25,9 +25,9 @@ export type ContentType = z.infer<typeof ContentType>;
|
|
|
25
25
|
*/
|
|
26
26
|
export declare const BaseContent: z.ZodObject<{
|
|
27
27
|
type: z.ZodEnum<{
|
|
28
|
-
file: "file";
|
|
29
28
|
text: "text";
|
|
30
29
|
image: "image";
|
|
30
|
+
file: "file";
|
|
31
31
|
tool_call: "tool_call";
|
|
32
32
|
tool_result: "tool_result";
|
|
33
33
|
}>;
|
|
@@ -196,5 +196,17 @@ export declare const MessageChunk: z.ZodObject<{
|
|
|
196
196
|
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
197
197
|
totalTokens: z.ZodOptional<z.ZodNumber>;
|
|
198
198
|
}, z.core.$strip>>;
|
|
199
|
+
contextInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
200
|
+
_meta: z.ZodOptional<z.ZodObject<{
|
|
201
|
+
context_size: z.ZodOptional<z.ZodObject<{
|
|
202
|
+
systemPromptTokens: z.ZodNumber;
|
|
203
|
+
userMessagesTokens: z.ZodNumber;
|
|
204
|
+
assistantMessagesTokens: z.ZodNumber;
|
|
205
|
+
toolInputTokens: z.ZodNumber;
|
|
206
|
+
toolResultsTokens: z.ZodNumber;
|
|
207
|
+
totalEstimated: z.ZodNumber;
|
|
208
|
+
llmReportedInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
209
|
+
}, z.core.$strip>>;
|
|
210
|
+
}, z.core.$strip>>;
|
|
199
211
|
}, z.core.$strip>;
|
|
200
212
|
export type MessageChunk = z.infer<typeof MessageChunk>;
|
|
@@ -99,4 +99,20 @@ export const MessageChunk = z.object({
|
|
|
99
99
|
totalTokens: z.number().optional(),
|
|
100
100
|
})
|
|
101
101
|
.optional(),
|
|
102
|
+
contextInputTokens: z.number().optional(),
|
|
103
|
+
_meta: z
|
|
104
|
+
.object({
|
|
105
|
+
context_size: z
|
|
106
|
+
.object({
|
|
107
|
+
systemPromptTokens: z.number(),
|
|
108
|
+
userMessagesTokens: z.number(),
|
|
109
|
+
assistantMessagesTokens: z.number(),
|
|
110
|
+
toolInputTokens: z.number(),
|
|
111
|
+
toolResultsTokens: z.number(),
|
|
112
|
+
totalEstimated: z.number(),
|
|
113
|
+
llmReportedInputTokens: z.number().optional(),
|
|
114
|
+
})
|
|
115
|
+
.optional(),
|
|
116
|
+
})
|
|
117
|
+
.optional(),
|
|
102
118
|
});
|
|
@@ -3,12 +3,12 @@ import { z } from "zod";
|
|
|
3
3
|
* Session status
|
|
4
4
|
*/
|
|
5
5
|
export declare const SessionStatus: z.ZodEnum<{
|
|
6
|
-
error: "error";
|
|
7
6
|
idle: "idle";
|
|
8
7
|
connecting: "connecting";
|
|
9
8
|
connected: "connected";
|
|
10
9
|
active: "active";
|
|
11
10
|
streaming: "streaming";
|
|
11
|
+
error: "error";
|
|
12
12
|
disconnected: "disconnected";
|
|
13
13
|
}>;
|
|
14
14
|
export type SessionStatus = z.infer<typeof SessionStatus>;
|
|
@@ -40,12 +40,12 @@ export type SessionMetadata = z.infer<typeof SessionMetadata>;
|
|
|
40
40
|
export declare const Session: z.ZodObject<{
|
|
41
41
|
id: z.ZodString;
|
|
42
42
|
status: z.ZodEnum<{
|
|
43
|
-
error: "error";
|
|
44
43
|
idle: "idle";
|
|
45
44
|
connecting: "connecting";
|
|
46
45
|
connected: "connected";
|
|
47
46
|
active: "active";
|
|
48
47
|
streaming: "streaming";
|
|
48
|
+
error: "error";
|
|
49
49
|
disconnected: "disconnected";
|
|
50
50
|
}>;
|
|
51
51
|
config: z.ZodObject<{
|
|
@@ -108,12 +108,12 @@ export type Session = z.infer<typeof Session>;
|
|
|
108
108
|
export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
109
109
|
sessionId: z.ZodString;
|
|
110
110
|
status: z.ZodOptional<z.ZodEnum<{
|
|
111
|
-
error: "error";
|
|
112
111
|
idle: "idle";
|
|
113
112
|
connecting: "connecting";
|
|
114
113
|
connected: "connected";
|
|
115
114
|
active: "active";
|
|
116
115
|
streaming: "streaming";
|
|
116
|
+
error: "error";
|
|
117
117
|
disconnected: "disconnected";
|
|
118
118
|
}>>;
|
|
119
119
|
message: z.ZodOptional<z.ZodObject<{
|
|
@@ -154,6 +154,7 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
154
154
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
155
155
|
}, z.core.$strip>>;
|
|
156
156
|
error: z.ZodOptional<z.ZodString>;
|
|
157
|
+
_meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
157
158
|
type: z.ZodLiteral<"tool_call">;
|
|
158
159
|
toolCall: z.ZodObject<{
|
|
159
160
|
id: z.ZodString;
|
|
@@ -212,17 +213,26 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
212
213
|
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
213
214
|
totalTokens: z.ZodOptional<z.ZodNumber>;
|
|
214
215
|
}, z.core.$strip>>;
|
|
216
|
+
_meta: z.ZodOptional<z.ZodObject<{
|
|
217
|
+
truncationWarning: z.ZodOptional<z.ZodString>;
|
|
218
|
+
compactionAction: z.ZodOptional<z.ZodEnum<{
|
|
219
|
+
compacted: "compacted";
|
|
220
|
+
truncated: "truncated";
|
|
221
|
+
}>>;
|
|
222
|
+
originalTokens: z.ZodOptional<z.ZodNumber>;
|
|
223
|
+
finalTokens: z.ZodOptional<z.ZodNumber>;
|
|
224
|
+
}, z.core.$strip>>;
|
|
215
225
|
}, z.core.$strip>;
|
|
216
226
|
messageId: z.ZodOptional<z.ZodString>;
|
|
217
227
|
}, z.core.$strip>, z.ZodObject<{
|
|
218
228
|
sessionId: z.ZodString;
|
|
219
229
|
status: z.ZodOptional<z.ZodEnum<{
|
|
220
|
-
error: "error";
|
|
221
230
|
idle: "idle";
|
|
222
231
|
connecting: "connecting";
|
|
223
232
|
connected: "connected";
|
|
224
233
|
active: "active";
|
|
225
234
|
streaming: "streaming";
|
|
235
|
+
error: "error";
|
|
226
236
|
disconnected: "disconnected";
|
|
227
237
|
}>>;
|
|
228
238
|
message: z.ZodOptional<z.ZodObject<{
|
|
@@ -263,6 +273,7 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
263
273
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
264
274
|
}, z.core.$strip>>;
|
|
265
275
|
error: z.ZodOptional<z.ZodString>;
|
|
276
|
+
_meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
266
277
|
type: z.ZodLiteral<"tool_call_update">;
|
|
267
278
|
toolCallUpdate: z.ZodObject<{
|
|
268
279
|
id: z.ZodString;
|
|
@@ -308,12 +319,12 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
308
319
|
}, z.core.$strip>, z.ZodObject<{
|
|
309
320
|
sessionId: z.ZodString;
|
|
310
321
|
status: z.ZodOptional<z.ZodEnum<{
|
|
311
|
-
error: "error";
|
|
312
322
|
idle: "idle";
|
|
313
323
|
connecting: "connecting";
|
|
314
324
|
connected: "connected";
|
|
315
325
|
active: "active";
|
|
316
326
|
streaming: "streaming";
|
|
327
|
+
error: "error";
|
|
317
328
|
disconnected: "disconnected";
|
|
318
329
|
}>>;
|
|
319
330
|
message: z.ZodOptional<z.ZodObject<{
|
|
@@ -354,6 +365,7 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
354
365
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
355
366
|
}, z.core.$strip>>;
|
|
356
367
|
error: z.ZodOptional<z.ZodString>;
|
|
368
|
+
_meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
357
369
|
type: z.ZodLiteral<"tool_output">;
|
|
358
370
|
toolOutput: z.ZodObject<{
|
|
359
371
|
id: z.ZodString;
|
|
@@ -364,12 +376,12 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
364
376
|
}, z.core.$strip>, z.ZodObject<{
|
|
365
377
|
sessionId: z.ZodString;
|
|
366
378
|
status: z.ZodOptional<z.ZodEnum<{
|
|
367
|
-
error: "error";
|
|
368
379
|
idle: "idle";
|
|
369
380
|
connecting: "connecting";
|
|
370
381
|
connected: "connected";
|
|
371
382
|
active: "active";
|
|
372
383
|
streaming: "streaming";
|
|
384
|
+
error: "error";
|
|
373
385
|
disconnected: "disconnected";
|
|
374
386
|
}>>;
|
|
375
387
|
message: z.ZodOptional<z.ZodObject<{
|
|
@@ -410,6 +422,7 @@ export declare const SessionUpdate: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
410
422
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
411
423
|
}, z.core.$strip>>;
|
|
412
424
|
error: z.ZodOptional<z.ZodString>;
|
|
425
|
+
_meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
413
426
|
type: z.ZodOptional<z.ZodLiteral<"generic">>;
|
|
414
427
|
}, z.core.$strip>]>;
|
|
415
428
|
export type SessionUpdate = z.infer<typeof SessionUpdate>;
|
|
@@ -52,6 +52,7 @@ const BaseSessionUpdate = z.object({
|
|
|
52
52
|
status: SessionStatus.optional(),
|
|
53
53
|
message: Message.optional(),
|
|
54
54
|
error: z.string().optional(),
|
|
55
|
+
_meta: z.record(z.string(), z.unknown()).optional(),
|
|
55
56
|
});
|
|
56
57
|
/**
|
|
57
58
|
* Session update with tool call (sessionUpdate: "tool_call")
|
|
@@ -21,6 +21,7 @@ export declare class HttpTransport implements Transport {
|
|
|
21
21
|
private options;
|
|
22
22
|
private isReceivingMessages;
|
|
23
23
|
private isInReplayMode;
|
|
24
|
+
private agentInfo?;
|
|
24
25
|
constructor(options: HttpTransportOptions);
|
|
25
26
|
connect(): Promise<void>;
|
|
26
27
|
/**
|
|
@@ -34,6 +35,13 @@ export declare class HttpTransport implements Transport {
|
|
|
34
35
|
isConnected(): boolean;
|
|
35
36
|
onSessionUpdate(callback: (update: SessionUpdate) => void): () => void;
|
|
36
37
|
onError(callback: (error: Error) => void): () => void;
|
|
38
|
+
getAgentInfo(): {
|
|
39
|
+
name?: string;
|
|
40
|
+
displayName?: string;
|
|
41
|
+
version?: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
suggestedPrompts?: string[];
|
|
44
|
+
};
|
|
37
45
|
/**
|
|
38
46
|
* Send an ACP RPC request to the server
|
|
39
47
|
*/
|
|
@@ -22,6 +22,7 @@ export class HttpTransport {
|
|
|
22
22
|
options;
|
|
23
23
|
isReceivingMessages = false;
|
|
24
24
|
isInReplayMode = false; // True during session replay, ignores non-replay streaming
|
|
25
|
+
agentInfo;
|
|
25
26
|
constructor(options) {
|
|
26
27
|
// Ensure baseUrl doesn't end with a slash
|
|
27
28
|
this.options = { ...options, baseUrl: options.baseUrl.replace(/\/$/, "") };
|
|
@@ -43,6 +44,30 @@ export class HttpTransport {
|
|
|
43
44
|
},
|
|
44
45
|
};
|
|
45
46
|
const initResponse = await this.sendRpcRequest("initialize", initRequest);
|
|
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)
|
|
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
|
|
59
|
+
: undefined;
|
|
60
|
+
this.agentInfo = {
|
|
61
|
+
name: initResponse.agentInfo.name,
|
|
62
|
+
// title is the ACP field for human-readable display name
|
|
63
|
+
...(initResponse.agentInfo.title
|
|
64
|
+
? { displayName: initResponse.agentInfo.title }
|
|
65
|
+
: {}),
|
|
66
|
+
version: initResponse.agentInfo.version,
|
|
67
|
+
...(description ? { description } : {}),
|
|
68
|
+
...(suggestedPrompts ? { suggestedPrompts } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
46
71
|
logger.info("ACP connection initialized", { initResponse });
|
|
47
72
|
// Step 2: Create a new session
|
|
48
73
|
const sessionRequest = {
|
|
@@ -89,6 +114,30 @@ export class HttpTransport {
|
|
|
89
114
|
};
|
|
90
115
|
logger.info("Loading session - initializing connection", { sessionId });
|
|
91
116
|
const initResponse = await this.sendRpcRequest("initialize", initRequest);
|
|
117
|
+
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)
|
|
123
|
+
: 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
|
|
129
|
+
: undefined;
|
|
130
|
+
this.agentInfo = {
|
|
131
|
+
name: initResponse.agentInfo.name,
|
|
132
|
+
// title is the ACP field for human-readable display name
|
|
133
|
+
...(initResponse.agentInfo.title
|
|
134
|
+
? { displayName: initResponse.agentInfo.title }
|
|
135
|
+
: {}),
|
|
136
|
+
version: initResponse.agentInfo.version,
|
|
137
|
+
...(description ? { description } : {}),
|
|
138
|
+
...(suggestedPrompts ? { suggestedPrompts } : {}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
92
141
|
// Check if loadSession is supported
|
|
93
142
|
if (!initResponse.agentCapabilities?.loadSession) {
|
|
94
143
|
logger.error("Agent does not support loading sessions", {
|
|
@@ -287,6 +336,9 @@ export class HttpTransport {
|
|
|
287
336
|
this.errorCallbacks.delete(callback);
|
|
288
337
|
};
|
|
289
338
|
}
|
|
339
|
+
getAgentInfo() {
|
|
340
|
+
return this.agentInfo || {};
|
|
341
|
+
}
|
|
290
342
|
/**
|
|
291
343
|
* Send an ACP RPC request to the server
|
|
292
344
|
*/
|
|
@@ -759,18 +811,32 @@ export class HttpTransport {
|
|
|
759
811
|
if (this.isInReplayMode && !isReplay) {
|
|
760
812
|
return;
|
|
761
813
|
}
|
|
762
|
-
// Handle agent message chunks
|
|
763
|
-
const sessionUpdate = {
|
|
764
|
-
type: "generic",
|
|
765
|
-
sessionId,
|
|
766
|
-
status: "active",
|
|
767
|
-
};
|
|
768
814
|
// Extract token usage from _meta if present
|
|
769
815
|
const tokenUsage = update._meta &&
|
|
770
816
|
typeof update._meta === "object" &&
|
|
771
817
|
"tokenUsage" in update._meta
|
|
772
818
|
? update._meta.tokenUsage
|
|
773
819
|
: undefined;
|
|
820
|
+
// Extract context input tokens from _meta if present
|
|
821
|
+
const contextInputTokens = update._meta &&
|
|
822
|
+
typeof update._meta === "object" &&
|
|
823
|
+
"contextInputTokens" in update._meta &&
|
|
824
|
+
typeof update._meta.contextInputTokens === "number"
|
|
825
|
+
? update._meta.contextInputTokens
|
|
826
|
+
: undefined;
|
|
827
|
+
// Extract context_size from _meta if present
|
|
828
|
+
const context_size = update._meta &&
|
|
829
|
+
typeof update._meta === "object" &&
|
|
830
|
+
"context_size" in update._meta
|
|
831
|
+
? update._meta.context_size
|
|
832
|
+
: undefined;
|
|
833
|
+
// Handle agent message chunks
|
|
834
|
+
const sessionUpdate = {
|
|
835
|
+
type: "generic",
|
|
836
|
+
sessionId,
|
|
837
|
+
status: "active",
|
|
838
|
+
_meta: update._meta,
|
|
839
|
+
};
|
|
774
840
|
// Queue message chunks if present (but skip during replay)
|
|
775
841
|
// For agent_message_chunk, content is an object, not an array
|
|
776
842
|
const content = update.content;
|
|
@@ -783,6 +849,8 @@ export class HttpTransport {
|
|
|
783
849
|
role: "assistant",
|
|
784
850
|
contentDelta: { type: "text", text: contentObj.text },
|
|
785
851
|
tokenUsage,
|
|
852
|
+
contextInputTokens,
|
|
853
|
+
_meta: context_size ? { context_size } : undefined,
|
|
786
854
|
isComplete: false,
|
|
787
855
|
};
|
|
788
856
|
}
|
|
@@ -824,8 +892,11 @@ export class HttpTransport {
|
|
|
824
892
|
this.notifySessionUpdate(messageSessionUpdate);
|
|
825
893
|
}
|
|
826
894
|
}
|
|
827
|
-
//
|
|
828
|
-
|
|
895
|
+
// Send session update for:
|
|
896
|
+
// 1. Live streaming (not replay)
|
|
897
|
+
// 2. Replay messages with context_size (need to restore context on session load)
|
|
898
|
+
const hasContextSize = sessionUpdate._meta && "context_size" in sessionUpdate._meta;
|
|
899
|
+
if (!isReplay || hasContextSize) {
|
|
829
900
|
this.notifySessionUpdate(sessionUpdate);
|
|
830
901
|
}
|
|
831
902
|
}
|
|
@@ -15,6 +15,7 @@ export declare class StdioTransport implements Transport {
|
|
|
15
15
|
private currentSessionId;
|
|
16
16
|
private chunkResolvers;
|
|
17
17
|
private streamComplete;
|
|
18
|
+
private agentInfo?;
|
|
18
19
|
private originalConsole;
|
|
19
20
|
constructor(options: StdioTransportOptions);
|
|
20
21
|
connect(): Promise<void>;
|
|
@@ -24,6 +25,13 @@ export declare class StdioTransport implements Transport {
|
|
|
24
25
|
isConnected(): boolean;
|
|
25
26
|
onSessionUpdate(callback: (update: SessionUpdate) => void): () => void;
|
|
26
27
|
onError(callback: (error: Error) => void): () => void;
|
|
28
|
+
getAgentInfo(): {
|
|
29
|
+
name?: string;
|
|
30
|
+
displayName?: string;
|
|
31
|
+
version?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
suggestedPrompts?: string[];
|
|
34
|
+
};
|
|
27
35
|
private notifySessionUpdate;
|
|
28
36
|
private notifyError;
|
|
29
37
|
}
|
|
@@ -18,6 +18,7 @@ export class StdioTransport {
|
|
|
18
18
|
currentSessionId = null;
|
|
19
19
|
chunkResolvers = [];
|
|
20
20
|
streamComplete = false;
|
|
21
|
+
agentInfo;
|
|
21
22
|
originalConsole = null;
|
|
22
23
|
constructor(options) {
|
|
23
24
|
this.options = options;
|
|
@@ -353,6 +354,30 @@ export class StdioTransport {
|
|
|
353
354
|
},
|
|
354
355
|
},
|
|
355
356
|
});
|
|
357
|
+
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)
|
|
363
|
+
: 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
|
|
369
|
+
: undefined;
|
|
370
|
+
this.agentInfo = {
|
|
371
|
+
name: initResponse.agentInfo.name,
|
|
372
|
+
// title is the ACP field for human-readable display name
|
|
373
|
+
...(initResponse.agentInfo.title
|
|
374
|
+
? { displayName: initResponse.agentInfo.title }
|
|
375
|
+
: {}),
|
|
376
|
+
version: initResponse.agentInfo.version,
|
|
377
|
+
...(description ? { description } : {}),
|
|
378
|
+
...(suggestedPrompts ? { suggestedPrompts } : {}),
|
|
379
|
+
};
|
|
380
|
+
}
|
|
356
381
|
logger.info("ACP connection initialized", { initResponse });
|
|
357
382
|
this.connected = true;
|
|
358
383
|
}
|
|
@@ -511,6 +536,9 @@ export class StdioTransport {
|
|
|
511
536
|
this.errorCallbacks.delete(callback);
|
|
512
537
|
};
|
|
513
538
|
}
|
|
539
|
+
getAgentInfo() {
|
|
540
|
+
return this.agentInfo || {};
|
|
541
|
+
}
|
|
514
542
|
notifySessionUpdate(update) {
|
|
515
543
|
for (const callback of this.sessionUpdateCallbacks) {
|
|
516
544
|
try {
|
|
@@ -36,6 +36,18 @@ export interface Transport {
|
|
|
36
36
|
* Subscribe to errors
|
|
37
37
|
*/
|
|
38
38
|
onError(callback: (error: Error) => void): () => void;
|
|
39
|
+
/**
|
|
40
|
+
* Get agent information
|
|
41
|
+
* - displayName: Human-readable name for UI (from ACP title field)
|
|
42
|
+
* - name: Programmatic name (fallback if displayName not set)
|
|
43
|
+
*/
|
|
44
|
+
getAgentInfo?(): {
|
|
45
|
+
name?: string;
|
|
46
|
+
displayName?: string;
|
|
47
|
+
version?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
suggestedPrompts?: string[];
|
|
50
|
+
};
|
|
39
51
|
}
|
|
40
52
|
/**
|
|
41
53
|
* Stdio transport options
|
|
@@ -37,5 +37,5 @@ export function ToolCall({ toolCall }) {
|
|
|
37
37
|
? ((toolCall.tokenUsage.inputTokens / 1_000_000) * 3 +
|
|
38
38
|
(toolCall.tokenUsage.outputTokens / 1_000_000) * 15).toFixed(4)
|
|
39
39
|
: null;
|
|
40
|
-
return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: statusColors[toolCall.status], children: statusIndicators[toolCall.status] }), _jsx(Text, { color: "cyan", bold: true, children: "[TOOL]" }), _jsx(Text, { children: toolCall.title }), startTime && (_jsxs(Text, { color: "gray", dimColor: true, children: ["| ", startTime] })), duration && (_jsxs(Text, { color: "gray", dimColor: true, children: ["| ", duration, "s"] })), cost && (_jsxs(Text, { color: "gray", dimColor: true, children: ["| $", cost] }))] }));
|
|
40
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: statusColors[toolCall.status], children: statusIndicators[toolCall.status] }), _jsx(Text, { color: "cyan", bold: true, children: "[TOOL]" }), _jsx(Text, { children: toolCall.title }), startTime && (_jsxs(Text, { color: "gray", dimColor: true, children: ["| ", startTime] })), duration && (_jsxs(Text, { color: "gray", dimColor: true, children: ["| ", duration, "s"] })), cost && (_jsxs(Text, { color: "gray", dimColor: true, children: ["| $", cost] }))] }), toolCall._meta?.truncationWarning && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "yellow", bold: true, children: ["\u26A0\uFE0F ", toolCall._meta.truncationWarning] }) }))] }));
|
|
41
41
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@townco/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@agentclientprotocol/sdk": "^0.5.1",
|
|
43
|
-
"@townco/core": "0.0.
|
|
43
|
+
"@townco/core": "0.0.24",
|
|
44
44
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
45
45
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
46
46
|
"@radix-ui/react-label": "^2.1.8",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@tailwindcss/postcss": "^4.1.17",
|
|
66
|
-
"@townco/tsconfig": "0.1.
|
|
66
|
+
"@townco/tsconfig": "0.1.43",
|
|
67
67
|
"@types/node": "^24.10.0",
|
|
68
68
|
"@types/react": "^19.2.2",
|
|
69
69
|
"ink": "^6.4.0",
|
package/src/styles/global.css
CHANGED
|
@@ -378,3 +378,18 @@
|
|
|
378
378
|
transform: translateX(0);
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
|
+
|
|
382
|
+
@keyframes pulse-scale {
|
|
383
|
+
0%, 100% {
|
|
384
|
+
transform: scale(1);
|
|
385
|
+
background-color: var(--color-neutral-500);
|
|
386
|
+
}
|
|
387
|
+
50% {
|
|
388
|
+
transform: scale(.9);
|
|
389
|
+
background-color: var(--color-neutral-500);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.animate-pulse-scale {
|
|
394
|
+
animation: pulse-scale 1s ease-in-out infinite;
|
|
395
|
+
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser-compatible logger
|
|
3
|
-
* Outputs structured JSON logs to console with color-coding
|
|
4
|
-
* Also captures logs to a global store for in-app viewing
|
|
5
|
-
* In Node.js environment with logsDir option, also writes to .logs/ directory
|
|
6
|
-
*/
|
|
7
|
-
export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
8
|
-
export interface LogEntry {
|
|
9
|
-
id: string;
|
|
10
|
-
timestamp: string;
|
|
11
|
-
level: LogLevel;
|
|
12
|
-
service: string;
|
|
13
|
-
message: string;
|
|
14
|
-
metadata?: Record<string, unknown>;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Get all captured logs
|
|
18
|
-
*/
|
|
19
|
-
export declare function getCapturedLogs(): LogEntry[];
|
|
20
|
-
/**
|
|
21
|
-
* Clear all captured logs
|
|
22
|
-
*/
|
|
23
|
-
export declare function clearCapturedLogs(): void;
|
|
24
|
-
/**
|
|
25
|
-
* Subscribe to log updates
|
|
26
|
-
*/
|
|
27
|
-
type LogSubscriber = (entry: LogEntry) => void;
|
|
28
|
-
export declare function subscribeToLogs(callback: LogSubscriber): () => void;
|
|
29
|
-
/**
|
|
30
|
-
* Configure global logs directory for file writing
|
|
31
|
-
* Must be called before creating any loggers (typically at TUI startup)
|
|
32
|
-
*/
|
|
33
|
-
export declare function configureLogsDir(logsDir: string): void;
|
|
34
|
-
export declare class Logger {
|
|
35
|
-
private service;
|
|
36
|
-
private minLevel;
|
|
37
|
-
private logFilePath?;
|
|
38
|
-
private logsDir?;
|
|
39
|
-
private writeQueue;
|
|
40
|
-
private isWriting;
|
|
41
|
-
constructor(service: string, minLevel?: LogLevel);
|
|
42
|
-
private setupFileLogging;
|
|
43
|
-
private writeToFile;
|
|
44
|
-
private shouldLog;
|
|
45
|
-
private log;
|
|
46
|
-
trace(message: string, metadata?: Record<string, unknown>): void;
|
|
47
|
-
debug(message: string, metadata?: Record<string, unknown>): void;
|
|
48
|
-
info(message: string, metadata?: Record<string, unknown>): void;
|
|
49
|
-
warn(message: string, metadata?: Record<string, unknown>): void;
|
|
50
|
-
error(message: string, metadata?: Record<string, unknown>): void;
|
|
51
|
-
fatal(message: string, metadata?: Record<string, unknown>): void;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Create a logger instance for a service
|
|
55
|
-
* @param service - Service name (e.g., "gui", "http-agent", "tui")
|
|
56
|
-
* @param minLevel - Minimum log level to display (default: "debug")
|
|
57
|
-
*/
|
|
58
|
-
export declare function createLogger(service: string, minLevel?: LogLevel): Logger;
|
|
59
|
-
export {};
|