@townco/agent 0.1.55 → 0.1.57
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/acp-server/adapter.d.ts +7 -0
- package/dist/acp-server/adapter.js +96 -18
- package/dist/acp-server/http.js +74 -1
- package/dist/acp-server/session-storage.d.ts +14 -0
- package/dist/acp-server/session-storage.js +47 -0
- package/dist/definition/index.d.ts +16 -0
- package/dist/definition/index.js +16 -0
- package/dist/runner/agent-runner.d.ts +8 -1
- package/dist/runner/agent-runner.js +3 -1
- package/dist/runner/langchain/index.js +139 -7
- package/dist/runner/langchain/model-factory.d.ts +2 -0
- package/dist/runner/langchain/model-factory.js +19 -0
- package/dist/runner/langchain/tools/browser.d.ts +100 -0
- package/dist/runner/langchain/tools/browser.js +412 -0
- package/dist/runner/langchain/tools/subagent-connections.d.ts +28 -0
- package/dist/runner/langchain/tools/subagent-connections.js +58 -0
- package/dist/runner/langchain/tools/subagent.js +5 -1
- package/dist/runner/tools.d.ts +2 -2
- package/dist/runner/tools.js +1 -0
- package/dist/scaffold/index.js +7 -1
- package/dist/scaffold/templates/dot-claude/CLAUDE-append.md +2 -0
- package/dist/telemetry/index.d.ts +5 -0
- package/dist/telemetry/index.js +10 -0
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.js +29 -7
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/templates/index.ts +39 -7
|
@@ -24,6 +24,8 @@ export declare class AgentAcpAdapter implements acp.Agent {
|
|
|
24
24
|
private agentVersion;
|
|
25
25
|
private agentDescription;
|
|
26
26
|
private agentSuggestedPrompts;
|
|
27
|
+
private agentInitialMessage;
|
|
28
|
+
private agentUiConfig;
|
|
27
29
|
private currentToolOverheadTokens;
|
|
28
30
|
private currentMcpOverheadTokens;
|
|
29
31
|
constructor(agent: AgentRunner, connection: acp.AgentSideConnection, agentDir?: string, agentName?: string);
|
|
@@ -48,6 +50,11 @@ export declare class AgentAcpAdapter implements acp.Agent {
|
|
|
48
50
|
private saveSessionToDisk;
|
|
49
51
|
initialize(_params: acp.InitializeRequest): Promise<acp.InitializeResponse>;
|
|
50
52
|
newSession(params: acp.NewSessionRequest): Promise<acp.NewSessionResponse>;
|
|
53
|
+
/**
|
|
54
|
+
* Store an initial message in the session.
|
|
55
|
+
* Called by the HTTP transport after sending the initial message via SSE.
|
|
56
|
+
*/
|
|
57
|
+
storeInitialMessage(sessionId: string, content: string): Promise<void>;
|
|
51
58
|
loadSession(params: acp.LoadSessionRequest): Promise<acp.LoadSessionResponse>;
|
|
52
59
|
authenticate(_params: acp.AuthenticateRequest): Promise<acp.AuthenticateResponse | undefined>;
|
|
53
60
|
setSessionMode(_params: acp.SetSessionModeRequest): Promise<acp.SetSessionModeResponse>;
|
|
@@ -105,6 +105,8 @@ export class AgentAcpAdapter {
|
|
|
105
105
|
agentVersion;
|
|
106
106
|
agentDescription;
|
|
107
107
|
agentSuggestedPrompts;
|
|
108
|
+
agentInitialMessage;
|
|
109
|
+
agentUiConfig;
|
|
108
110
|
currentToolOverheadTokens = 0; // Track tool overhead for current turn
|
|
109
111
|
currentMcpOverheadTokens = 0; // Track MCP overhead for current turn
|
|
110
112
|
constructor(agent, connection, agentDir, agentName) {
|
|
@@ -117,6 +119,8 @@ export class AgentAcpAdapter {
|
|
|
117
119
|
this.agentVersion = agent.definition.version;
|
|
118
120
|
this.agentDescription = agent.definition.description;
|
|
119
121
|
this.agentSuggestedPrompts = agent.definition.suggestedPrompts;
|
|
122
|
+
this.agentInitialMessage = agent.definition.initialMessage;
|
|
123
|
+
this.agentUiConfig = agent.definition.uiConfig;
|
|
120
124
|
this.noSession = process.env.TOWN_NO_SESSION === "true";
|
|
121
125
|
this.storage =
|
|
122
126
|
agentDir && agentName && !this.noSession
|
|
@@ -129,6 +133,7 @@ export class AgentAcpAdapter {
|
|
|
129
133
|
agentVersion: this.agentVersion,
|
|
130
134
|
agentDescription: this.agentDescription,
|
|
131
135
|
suggestedPrompts: this.agentSuggestedPrompts,
|
|
136
|
+
initialMessage: this.agentInitialMessage,
|
|
132
137
|
noSession: this.noSession,
|
|
133
138
|
hasStorage: this.storage !== null,
|
|
134
139
|
sessionStoragePath: this.storage ? `${agentDir}/.sessions` : null,
|
|
@@ -259,6 +264,10 @@ export class AgentAcpAdapter {
|
|
|
259
264
|
...(this.agentSuggestedPrompts
|
|
260
265
|
? { suggestedPrompts: this.agentSuggestedPrompts }
|
|
261
266
|
: {}),
|
|
267
|
+
...(this.agentInitialMessage
|
|
268
|
+
? { initialMessage: this.agentInitialMessage }
|
|
269
|
+
: {}),
|
|
270
|
+
...(this.agentUiConfig ? { uiConfig: this.agentUiConfig } : {}),
|
|
262
271
|
...(toolsMetadata.length > 0 ? { tools: toolsMetadata } : {}),
|
|
263
272
|
...(mcpsMetadata.length > 0 ? { mcps: mcpsMetadata } : {}),
|
|
264
273
|
...(subagentsMetadata.length > 0 ? { subagents: subagentsMetadata } : {}),
|
|
@@ -273,10 +282,38 @@ export class AgentAcpAdapter {
|
|
|
273
282
|
context: [],
|
|
274
283
|
requestParams: params,
|
|
275
284
|
});
|
|
285
|
+
// Note: Initial message is sent by the HTTP transport when SSE connection is established
|
|
286
|
+
// This ensures the message is delivered after the client is ready to receive it
|
|
276
287
|
return {
|
|
277
288
|
sessionId,
|
|
278
289
|
};
|
|
279
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* Store an initial message in the session.
|
|
293
|
+
* Called by the HTTP transport after sending the initial message via SSE.
|
|
294
|
+
*/
|
|
295
|
+
async storeInitialMessage(sessionId, content) {
|
|
296
|
+
const session = this.sessions.get(sessionId);
|
|
297
|
+
if (!session) {
|
|
298
|
+
logger.warn("Cannot store initial message - session not found", {
|
|
299
|
+
sessionId,
|
|
300
|
+
});
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// Add the initial message as an assistant message
|
|
304
|
+
const initialMessage = {
|
|
305
|
+
role: "assistant",
|
|
306
|
+
content: [{ type: "text", text: content }],
|
|
307
|
+
timestamp: new Date().toISOString(),
|
|
308
|
+
};
|
|
309
|
+
session.messages.push(initialMessage);
|
|
310
|
+
// Save to disk if session persistence is enabled
|
|
311
|
+
await this.saveSessionToDisk(sessionId, session);
|
|
312
|
+
logger.debug("Stored initial message in session", {
|
|
313
|
+
sessionId,
|
|
314
|
+
contentPreview: content.slice(0, 100),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
280
317
|
async loadSession(params) {
|
|
281
318
|
if (!this.storage) {
|
|
282
319
|
throw new Error("Session storage is not configured");
|
|
@@ -510,13 +547,11 @@ export class AgentAcpAdapter {
|
|
|
510
547
|
? session.context[session.context.length - 1]
|
|
511
548
|
: undefined;
|
|
512
549
|
// Calculate context size for this snapshot
|
|
513
|
-
// Build message pointers for the new context (previous messages
|
|
550
|
+
// Build message pointers for the new context (previous messages only, NOT the new user message)
|
|
551
|
+
// The new user message will be passed separately via the prompt parameter
|
|
514
552
|
const messageEntries = previousContext
|
|
515
|
-
? [
|
|
516
|
-
|
|
517
|
-
{ type: "pointer", index: session.messages.length - 1 },
|
|
518
|
-
]
|
|
519
|
-
: [{ type: "pointer", index: 0 }];
|
|
553
|
+
? [...previousContext.messages]
|
|
554
|
+
: [];
|
|
520
555
|
// Resolve message entries to actual messages
|
|
521
556
|
const contextMessages = [];
|
|
522
557
|
for (const entry of messageEntries) {
|
|
@@ -741,6 +776,23 @@ export class AgentAcpAdapter {
|
|
|
741
776
|
toolCallBlock.completedAt = Date.now();
|
|
742
777
|
}
|
|
743
778
|
}
|
|
779
|
+
// Forward tool_call_update with _meta to the client (for subagent connection info, etc.)
|
|
780
|
+
if (updateMsg._meta) {
|
|
781
|
+
logger.info("Forwarding tool_call_update with _meta to client", {
|
|
782
|
+
toolCallId: updateMsg.toolCallId,
|
|
783
|
+
status: updateMsg.status,
|
|
784
|
+
_meta: updateMsg._meta,
|
|
785
|
+
});
|
|
786
|
+
this.connection.sessionUpdate({
|
|
787
|
+
sessionId: params.sessionId,
|
|
788
|
+
update: {
|
|
789
|
+
sessionUpdate: "tool_call_update",
|
|
790
|
+
toolCallId: updateMsg.toolCallId,
|
|
791
|
+
status: updateMsg.status,
|
|
792
|
+
_meta: updateMsg._meta,
|
|
793
|
+
},
|
|
794
|
+
});
|
|
795
|
+
}
|
|
744
796
|
}
|
|
745
797
|
// Handle tool_output - update ToolCallBlock with output content
|
|
746
798
|
if ("sessionUpdate" in msg && msg.sessionUpdate === "tool_output") {
|
|
@@ -808,33 +860,53 @@ export class AgentAcpAdapter {
|
|
|
808
860
|
// Check if we already have a partial assistant message in messages
|
|
809
861
|
const lastMessage = session.messages[session.messages.length - 1];
|
|
810
862
|
let partialMessageIndex;
|
|
863
|
+
let userMessageIndex;
|
|
864
|
+
let isFirstToolInTurn;
|
|
811
865
|
if (lastMessage && lastMessage.role === "assistant") {
|
|
812
|
-
// Update existing partial message
|
|
866
|
+
// Update existing partial message (subsequent tool in same turn)
|
|
813
867
|
session.messages[session.messages.length - 1] =
|
|
814
868
|
partialAssistantMessage;
|
|
815
869
|
partialMessageIndex = session.messages.length - 1;
|
|
870
|
+
userMessageIndex = session.messages.length - 2;
|
|
871
|
+
isFirstToolInTurn = false;
|
|
816
872
|
}
|
|
817
873
|
else {
|
|
818
|
-
// Add new partial message
|
|
874
|
+
// Add new partial message (first tool in this turn)
|
|
819
875
|
session.messages.push(partialAssistantMessage);
|
|
820
876
|
partialMessageIndex = session.messages.length - 1;
|
|
877
|
+
userMessageIndex = session.messages.length - 2;
|
|
878
|
+
isFirstToolInTurn = true;
|
|
821
879
|
}
|
|
822
880
|
// Get the latest context
|
|
823
881
|
const latestContext = session.context.length > 0
|
|
824
882
|
? session.context[session.context.length - 1]
|
|
825
883
|
: undefined;
|
|
826
884
|
// Build message entries for the new context
|
|
827
|
-
// Check if we already have a pointer to this message (during mid-turn updates)
|
|
828
885
|
const existingMessages = latestContext?.messages ?? [];
|
|
829
|
-
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
886
|
+
// Check if we already have pointers to these messages
|
|
887
|
+
const hasUserPointer = existingMessages.some((entry) => entry.type === "pointer" && entry.index === userMessageIndex);
|
|
888
|
+
const hasAssistantPointer = existingMessages.some((entry) => entry.type === "pointer" &&
|
|
889
|
+
entry.index === partialMessageIndex);
|
|
890
|
+
let messageEntries;
|
|
891
|
+
if (isFirstToolInTurn && !hasUserPointer) {
|
|
892
|
+
// First tool: add both user and assistant pointers
|
|
893
|
+
messageEntries = [
|
|
835
894
|
...existingMessages,
|
|
895
|
+
{ type: "pointer", index: userMessageIndex },
|
|
836
896
|
{ type: "pointer", index: partialMessageIndex },
|
|
837
897
|
];
|
|
898
|
+
}
|
|
899
|
+
else if (!hasAssistantPointer) {
|
|
900
|
+
// Subsequent tool or user already added: just update/add assistant pointer
|
|
901
|
+
messageEntries = [
|
|
902
|
+
...existingMessages,
|
|
903
|
+
{ type: "pointer", index: partialMessageIndex },
|
|
904
|
+
];
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
// Both pointers already exist (updating existing assistant message)
|
|
908
|
+
messageEntries = existingMessages;
|
|
909
|
+
}
|
|
838
910
|
// Resolve message entries to actual messages
|
|
839
911
|
const contextMessages = [];
|
|
840
912
|
for (const entry of messageEntries) {
|
|
@@ -977,13 +1049,19 @@ export class AgentAcpAdapter {
|
|
|
977
1049
|
? session.context[session.context.length - 1]
|
|
978
1050
|
: undefined;
|
|
979
1051
|
// Calculate final context size
|
|
980
|
-
// Build message pointers for the new context
|
|
1052
|
+
// Build message pointers for the new context (add both user and assistant messages)
|
|
1053
|
+
const userMessageIndex = session.messages.length - 2;
|
|
1054
|
+
const assistantMessageIndex = session.messages.length - 1;
|
|
981
1055
|
const messageEntries = previousContext
|
|
982
1056
|
? [
|
|
983
1057
|
...previousContext.messages,
|
|
984
|
-
{ type: "pointer", index:
|
|
1058
|
+
{ type: "pointer", index: userMessageIndex },
|
|
1059
|
+
{ type: "pointer", index: assistantMessageIndex },
|
|
985
1060
|
]
|
|
986
|
-
: [
|
|
1061
|
+
: [
|
|
1062
|
+
{ type: "pointer", index: userMessageIndex },
|
|
1063
|
+
{ type: "pointer", index: assistantMessageIndex },
|
|
1064
|
+
];
|
|
987
1065
|
// Resolve message entries to actual messages
|
|
988
1066
|
const contextMessages = [];
|
|
989
1067
|
for (const entry of messageEntries) {
|
package/dist/acp-server/http.js
CHANGED
|
@@ -10,6 +10,7 @@ import { streamSSE } from "hono/streaming";
|
|
|
10
10
|
import { createLogger, isSubagent } from "../logger.js";
|
|
11
11
|
import { makeRunnerFromDefinition } from "../runner";
|
|
12
12
|
import { AgentAcpAdapter } from "./adapter";
|
|
13
|
+
import { SessionStorage } from "./session-storage";
|
|
13
14
|
const logger = createLogger("http");
|
|
14
15
|
/**
|
|
15
16
|
* Compress a payload using gzip if it's too large for PostgreSQL NOTIFY
|
|
@@ -65,10 +66,19 @@ export function makeHttpTransport(agent, agentDir, agentName) {
|
|
|
65
66
|
const outbound = new TransformStream();
|
|
66
67
|
const bridge = acp.ndJsonStream(outbound.writable, inbound.readable);
|
|
67
68
|
const agentRunner = "definition" in agent ? agent : makeRunnerFromDefinition(agent);
|
|
68
|
-
|
|
69
|
+
// Store adapter reference so we can call methods on it (e.g., storeInitialMessage)
|
|
70
|
+
let acpAdapter = null;
|
|
71
|
+
new acp.AgentSideConnection((conn) => {
|
|
72
|
+
acpAdapter = new AgentAcpAdapter(agentRunner, conn, agentDir, agentName);
|
|
73
|
+
return acpAdapter;
|
|
74
|
+
}, bridge);
|
|
69
75
|
const app = new Hono();
|
|
70
76
|
// Track active SSE streams by sessionId for direct output delivery
|
|
71
77
|
const sseStreams = new Map();
|
|
78
|
+
// Track sessions that have already received initial message
|
|
79
|
+
const initialMessageSentSessions = new Set();
|
|
80
|
+
// Get initial message config from agent definition
|
|
81
|
+
const initialMessageConfig = agentRunner.definition.initialMessage;
|
|
72
82
|
const decoder = new TextDecoder();
|
|
73
83
|
const encoder = new TextEncoder();
|
|
74
84
|
(async () => {
|
|
@@ -270,6 +280,28 @@ export function makeHttpTransport(agent, agentDir, agentName) {
|
|
|
270
280
|
allowMethods: ["GET", "POST", "OPTIONS"],
|
|
271
281
|
}));
|
|
272
282
|
app.get("/health", (c) => c.json({ ok: true }));
|
|
283
|
+
// List available sessions
|
|
284
|
+
app.get("/sessions", async (c) => {
|
|
285
|
+
if (!agentDir || !agentName) {
|
|
286
|
+
return c.json({ sessions: [], error: "Session storage not configured" });
|
|
287
|
+
}
|
|
288
|
+
const noSession = process.env.TOWN_NO_SESSION === "true";
|
|
289
|
+
if (noSession) {
|
|
290
|
+
return c.json({ sessions: [], error: "Sessions disabled" });
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
const storage = new SessionStorage(agentDir, agentName);
|
|
294
|
+
const sessions = await storage.listSessionsWithMetadata();
|
|
295
|
+
return c.json({ sessions });
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
logger.error("Failed to list sessions", { error });
|
|
299
|
+
return c.json({
|
|
300
|
+
sessions: [],
|
|
301
|
+
error: error instanceof Error ? error.message : String(error),
|
|
302
|
+
}, 500);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
273
305
|
// Serve static files from agent directory (for generated images, etc.)
|
|
274
306
|
if (agentDir) {
|
|
275
307
|
app.get("/static/*", async (c) => {
|
|
@@ -319,6 +351,47 @@ export function makeHttpTransport(agent, agentDir, agentName) {
|
|
|
319
351
|
// Register this stream for direct tool output delivery
|
|
320
352
|
sseStreams.set(sessionId, stream);
|
|
321
353
|
await stream.writeSSE({ event: "ping", data: "{}" });
|
|
354
|
+
// Send initial message if configured and not already sent for this session
|
|
355
|
+
if (initialMessageConfig?.enabled &&
|
|
356
|
+
initialMessageConfig.content &&
|
|
357
|
+
!initialMessageSentSessions.has(sessionId)) {
|
|
358
|
+
initialMessageSentSessions.add(sessionId);
|
|
359
|
+
// Process template variables in the content
|
|
360
|
+
let content = initialMessageConfig.content;
|
|
361
|
+
content = content.replace(/\{\{\.AgentName\}\}/g, agentName ?? "Agent");
|
|
362
|
+
const displayName = agentRunner.definition.displayName;
|
|
363
|
+
content = content.replace(/\{\{\.DisplayName\}\}/g, displayName ?? agentName ?? "Agent");
|
|
364
|
+
const initialMessage = {
|
|
365
|
+
jsonrpc: "2.0",
|
|
366
|
+
method: "session/update",
|
|
367
|
+
params: {
|
|
368
|
+
sessionId,
|
|
369
|
+
update: {
|
|
370
|
+
sessionUpdate: "agent_message_chunk",
|
|
371
|
+
content: {
|
|
372
|
+
type: "text",
|
|
373
|
+
text: content,
|
|
374
|
+
},
|
|
375
|
+
_meta: {
|
|
376
|
+
isInitialMessage: true,
|
|
377
|
+
isReplay: true, // Mark as replay so UI adds it to messages
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
await stream.writeSSE({
|
|
383
|
+
event: "message",
|
|
384
|
+
data: JSON.stringify(initialMessage),
|
|
385
|
+
});
|
|
386
|
+
// Store the initial message in the session for persistence
|
|
387
|
+
if (acpAdapter) {
|
|
388
|
+
await acpAdapter.storeInitialMessage(sessionId, content);
|
|
389
|
+
}
|
|
390
|
+
logger.info("Sent initial message via SSE", {
|
|
391
|
+
sessionId,
|
|
392
|
+
contentPreview: content.slice(0, 100),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
322
395
|
const hb = setInterval(() => {
|
|
323
396
|
// Heartbeat to keep proxies from terminating idle connections
|
|
324
397
|
void stream.writeSSE({ event: "ping", data: "{}" });
|
|
@@ -150,4 +150,18 @@ export declare class SessionStorage {
|
|
|
150
150
|
* List all session IDs
|
|
151
151
|
*/
|
|
152
152
|
listSessions(): Promise<string[]>;
|
|
153
|
+
/**
|
|
154
|
+
* Session summary for listing
|
|
155
|
+
*/
|
|
156
|
+
/**
|
|
157
|
+
* List all sessions with metadata
|
|
158
|
+
* Returns sessions sorted by updatedAt (most recent first)
|
|
159
|
+
*/
|
|
160
|
+
listSessionsWithMetadata(): Promise<Array<{
|
|
161
|
+
sessionId: string;
|
|
162
|
+
createdAt: string;
|
|
163
|
+
updatedAt: string;
|
|
164
|
+
messageCount: number;
|
|
165
|
+
firstUserMessage?: string;
|
|
166
|
+
}>>;
|
|
153
167
|
}
|
|
@@ -236,4 +236,51 @@ export class SessionStorage {
|
|
|
236
236
|
throw new Error(`Failed to list sessions: ${error instanceof Error ? error.message : String(error)}`);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Session summary for listing
|
|
241
|
+
*/
|
|
242
|
+
/**
|
|
243
|
+
* List all sessions with metadata
|
|
244
|
+
* Returns sessions sorted by updatedAt (most recent first)
|
|
245
|
+
*/
|
|
246
|
+
async listSessionsWithMetadata() {
|
|
247
|
+
if (!existsSync(this.sessionsDir)) {
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const files = readdirSync(this.sessionsDir);
|
|
252
|
+
const sessionFiles = files.filter((file) => file.endsWith(".json") && !file.endsWith(".tmp"));
|
|
253
|
+
const sessions = [];
|
|
254
|
+
for (const file of sessionFiles) {
|
|
255
|
+
const sessionId = file.replace(".json", "");
|
|
256
|
+
try {
|
|
257
|
+
const session = this.loadSessionSync(sessionId);
|
|
258
|
+
if (session) {
|
|
259
|
+
// Find the first user message for preview
|
|
260
|
+
const firstUserMsg = session.messages.find((m) => m.role === "user");
|
|
261
|
+
const firstUserText = firstUserMsg?.content.find((c) => c.type === "text");
|
|
262
|
+
const entry = {
|
|
263
|
+
sessionId: session.sessionId,
|
|
264
|
+
createdAt: session.metadata.createdAt,
|
|
265
|
+
updatedAt: session.metadata.updatedAt,
|
|
266
|
+
messageCount: session.messages.length,
|
|
267
|
+
};
|
|
268
|
+
if (firstUserText && "text" in firstUserText) {
|
|
269
|
+
entry.firstUserMessage = firstUserText.text.slice(0, 100);
|
|
270
|
+
}
|
|
271
|
+
sessions.push(entry);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// Skip invalid sessions
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Sort by updatedAt, most recent first
|
|
279
|
+
sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
280
|
+
return sessions;
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
throw new Error(`Failed to list sessions: ${error instanceof Error ? error.message : String(error)}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
239
286
|
}
|
|
@@ -26,6 +26,15 @@ export declare const HookConfigSchema: z.ZodObject<{
|
|
|
26
26
|
}, z.core.$strip>]>>;
|
|
27
27
|
callback: z.ZodString;
|
|
28
28
|
}, z.core.$strip>;
|
|
29
|
+
/** Initial message configuration schema. */
|
|
30
|
+
export declare const InitialMessageSchema: z.ZodObject<{
|
|
31
|
+
enabled: z.ZodBoolean;
|
|
32
|
+
content: z.ZodString;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
/** UI configuration schema for controlling the chat interface appearance. */
|
|
35
|
+
export declare const UiConfigSchema: z.ZodObject<{
|
|
36
|
+
hideTopBar: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
}, z.core.$strip>;
|
|
29
38
|
/** Agent definition schema. */
|
|
30
39
|
export declare const AgentDefinitionSchema: z.ZodObject<{
|
|
31
40
|
displayName: z.ZodOptional<z.ZodString>;
|
|
@@ -74,4 +83,11 @@ export declare const AgentDefinitionSchema: z.ZodObject<{
|
|
|
74
83
|
}, z.core.$strip>]>>;
|
|
75
84
|
callback: z.ZodString;
|
|
76
85
|
}, z.core.$strip>>>;
|
|
86
|
+
initialMessage: z.ZodOptional<z.ZodObject<{
|
|
87
|
+
enabled: z.ZodBoolean;
|
|
88
|
+
content: z.ZodString;
|
|
89
|
+
}, z.core.$strip>>;
|
|
90
|
+
uiConfig: z.ZodOptional<z.ZodObject<{
|
|
91
|
+
hideTopBar: z.ZodOptional<z.ZodBoolean>;
|
|
92
|
+
}, z.core.$strip>>;
|
|
77
93
|
}, z.core.$strip>;
|
package/dist/definition/index.js
CHANGED
|
@@ -71,6 +71,18 @@ export const HookConfigSchema = z.object({
|
|
|
71
71
|
.optional(),
|
|
72
72
|
callback: z.string(),
|
|
73
73
|
});
|
|
74
|
+
/** Initial message configuration schema. */
|
|
75
|
+
export const InitialMessageSchema = z.object({
|
|
76
|
+
/** Whether the agent should send an initial message when a session starts. */
|
|
77
|
+
enabled: z.boolean(),
|
|
78
|
+
/** The content of the initial message to send. Supports template variables like {{.AgentName}}. */
|
|
79
|
+
content: z.string(),
|
|
80
|
+
});
|
|
81
|
+
/** UI configuration schema for controlling the chat interface appearance. */
|
|
82
|
+
export const UiConfigSchema = z.object({
|
|
83
|
+
/** Whether to hide the top bar (session switcher, debugger link, settings). Useful for embedded/deployed mode. */
|
|
84
|
+
hideTopBar: z.boolean().optional(),
|
|
85
|
+
});
|
|
74
86
|
/** Agent definition schema. */
|
|
75
87
|
export const AgentDefinitionSchema = z.object({
|
|
76
88
|
/** Human-readable display name for the agent (shown in UI). */
|
|
@@ -84,4 +96,8 @@ export const AgentDefinitionSchema = z.object({
|
|
|
84
96
|
mcps: z.array(McpConfigSchema).optional(),
|
|
85
97
|
harnessImplementation: z.literal("langchain").optional(),
|
|
86
98
|
hooks: z.array(HookConfigSchema).optional(),
|
|
99
|
+
/** Configuration for an initial message the agent sends when a session starts. */
|
|
100
|
+
initialMessage: InitialMessageSchema.optional(),
|
|
101
|
+
/** UI configuration for controlling the chat interface appearance. */
|
|
102
|
+
uiConfig: UiConfigSchema.optional(),
|
|
87
103
|
});
|
|
@@ -8,7 +8,7 @@ export declare const zAgentRunnerParams: z.ZodObject<{
|
|
|
8
8
|
suggestedPrompts: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
9
9
|
systemPrompt: z.ZodNullable<z.ZodString>;
|
|
10
10
|
model: z.ZodString;
|
|
11
|
-
tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"filesystem">, z.ZodLiteral<"generate_image">]>, z.ZodObject<{
|
|
11
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"filesystem">, z.ZodLiteral<"generate_image">, z.ZodLiteral<"browser">]>, z.ZodObject<{
|
|
12
12
|
type: z.ZodLiteral<"custom">;
|
|
13
13
|
modulePath: z.ZodString;
|
|
14
14
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -52,6 +52,13 @@ export declare const zAgentRunnerParams: z.ZodObject<{
|
|
|
52
52
|
}, z.core.$strip>]>>;
|
|
53
53
|
callback: z.ZodString;
|
|
54
54
|
}, z.core.$strip>>>;
|
|
55
|
+
initialMessage: z.ZodOptional<z.ZodObject<{
|
|
56
|
+
enabled: z.ZodBoolean;
|
|
57
|
+
content: z.ZodString;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
uiConfig: z.ZodOptional<z.ZodObject<{
|
|
60
|
+
hideTopBar: z.ZodOptional<z.ZodBoolean>;
|
|
61
|
+
}, z.core.$strip>>;
|
|
55
62
|
}, z.core.$strip>;
|
|
56
63
|
export type CreateAgentRunnerParams = z.infer<typeof zAgentRunnerParams>;
|
|
57
64
|
export interface SessionMessage {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { HookConfigSchema, McpConfigSchema } from "../definition";
|
|
2
|
+
import { HookConfigSchema, InitialMessageSchema, McpConfigSchema, UiConfigSchema, } from "../definition";
|
|
3
3
|
import { zToolType } from "./tools";
|
|
4
4
|
export const zAgentRunnerParams = z.object({
|
|
5
5
|
displayName: z.string().optional(),
|
|
@@ -11,4 +11,6 @@ export const zAgentRunnerParams = z.object({
|
|
|
11
11
|
tools: z.array(zToolType).optional(),
|
|
12
12
|
mcps: z.array(McpConfigSchema).optional(),
|
|
13
13
|
hooks: z.array(HookConfigSchema).optional(),
|
|
14
|
+
initialMessage: InitialMessageSchema.optional(),
|
|
15
|
+
uiConfig: UiConfigSchema.optional(),
|
|
14
16
|
});
|