@townco/agent 0.1.43 → 0.1.45

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 (52) hide show
  1. package/dist/acp-server/adapter.d.ts +1 -0
  2. package/dist/acp-server/adapter.js +130 -9
  3. package/dist/acp-server/cli.d.ts +3 -1
  4. package/dist/acp-server/session-storage.d.ts +21 -1
  5. package/dist/acp-server/session-storage.js +19 -1
  6. package/dist/bin.js +0 -0
  7. package/dist/definition/index.d.ts +19 -0
  8. package/dist/definition/index.js +11 -0
  9. package/dist/definition/mcp.js +0 -1
  10. package/dist/definition/tools/todo.d.ts +49 -0
  11. package/dist/definition/tools/todo.js +80 -0
  12. package/dist/definition/tools/web_search.d.ts +4 -0
  13. package/dist/definition/tools/web_search.js +26 -0
  14. package/dist/dev-agent/index.d.ts +2 -0
  15. package/dist/dev-agent/index.js +18 -0
  16. package/dist/example.d.ts +2 -0
  17. package/dist/example.js +19 -0
  18. package/dist/index.js +13 -2
  19. package/dist/runner/agent-runner.d.ts +28 -2
  20. package/dist/runner/agent-runner.js +2 -1
  21. package/dist/runner/hooks/constants.d.ts +9 -0
  22. package/dist/runner/hooks/constants.js +19 -0
  23. package/dist/runner/hooks/executor.d.ts +23 -0
  24. package/dist/runner/hooks/executor.js +163 -0
  25. package/dist/runner/hooks/index.d.ts +5 -0
  26. package/dist/runner/hooks/index.js +5 -0
  27. package/dist/runner/hooks/loader.d.ts +5 -0
  28. package/dist/runner/hooks/loader.js +49 -0
  29. package/dist/runner/hooks/predefined/compaction-tool.d.ts +6 -0
  30. package/dist/runner/hooks/predefined/compaction-tool.js +42 -0
  31. package/dist/runner/hooks/registry.d.ts +14 -0
  32. package/dist/runner/hooks/registry.js +20 -0
  33. package/dist/runner/hooks/types.d.ts +144 -0
  34. package/dist/runner/hooks/types.js +33 -0
  35. package/dist/runner/index.d.ts +3 -1
  36. package/dist/runner/langchain/index.js +16 -10
  37. package/dist/runner/langchain/model-factory.js +3 -1
  38. package/dist/scaffold/claude-scaffold.js +8 -6
  39. package/dist/storage/index.js +3 -1
  40. package/dist/templates/index.d.ts +7 -0
  41. package/dist/templates/index.js +7 -2
  42. package/dist/test-script.js +3 -1
  43. package/dist/tsconfig.tsbuildinfo +1 -1
  44. package/index.ts +14 -2
  45. package/package.json +5 -5
  46. package/templates/index.ts +14 -2
  47. package/dist/acp-server/test-acp-summarize.d.ts +0 -7
  48. package/dist/acp-server/test-acp-summarize.js +0 -127
  49. package/dist/acp-server/test-summarizer.d.ts +0 -7
  50. package/dist/acp-server/test-summarizer.js +0 -170
  51. package/dist/acp-server/tool-summarizer.d.ts +0 -125
  52. package/dist/acp-server/tool-summarizer.js +0 -182
package/index.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import { basename } from "node:path";
2
+ import { createLogger } from "@townco/core";
2
3
  import { makeHttpTransport, makeStdioTransport } from "./acp-server";
3
4
  import type { AgentDefinition } from "./definition";
4
5
  import { makeSubagentsTool } from "./utils";
5
6
 
7
+ const logger = createLogger("agent-index");
8
+
6
9
  const exampleAgent: AgentDefinition = {
7
10
  model: "claude-sonnet-4-5-20250929",
8
11
  systemPrompt: "You are a helpful assistant.",
@@ -23,6 +26,15 @@ const exampleAgent: AgentDefinition = {
23
26
  ]),
24
27
  ],
25
28
  mcps: [],
29
+ hooks: [
30
+ {
31
+ type: "context_size",
32
+ setting: {
33
+ threshold: 95,
34
+ },
35
+ callback: "compaction_tool",
36
+ },
37
+ ],
26
38
  };
27
39
 
28
40
  // Parse transport type and flags from command line arguments
@@ -44,7 +56,7 @@ if (transport === "http") {
44
56
  } else if (transport === "stdio") {
45
57
  makeStdioTransport(exampleAgent);
46
58
  } else {
47
- console.error(`Invalid transport: ${transport}`);
48
- console.error("Usage: bun run index.ts [stdio|http] [--no-session]");
59
+ logger.error(`Invalid transport: ${transport}`);
60
+ logger.error("Usage: bun run index.ts [stdio|http] [--no-session]");
49
61
  process.exit(1);
50
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@townco/agent",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
4
4
  "type": "module",
5
5
  "module": "index.ts",
6
6
  "files": [
@@ -56,10 +56,10 @@
56
56
  "@langchain/google-genai": "^1.0.3",
57
57
  "@langchain/google-vertexai": "^1.0.3",
58
58
  "@langchain/mcp-adapters": "^1.0.0",
59
- "@townco/core": "0.0.16",
60
- "@townco/gui-template": "0.1.35",
61
- "@townco/tsconfig": "0.1.35",
62
- "@townco/ui": "0.1.38",
59
+ "@townco/core": "0.0.18",
60
+ "@townco/gui-template": "0.1.37",
61
+ "@townco/tsconfig": "0.1.37",
62
+ "@townco/ui": "0.1.40",
63
63
  "exa-js": "^2.0.0",
64
64
  "hono": "^4.10.4",
65
65
  "langchain": "^1.0.3",
@@ -19,6 +19,13 @@ export interface TemplateVars {
19
19
  >;
20
20
  systemPrompt: string | null;
21
21
  hasWebSearch: boolean;
22
+ hooks?:
23
+ | Array<{
24
+ type: "context_size";
25
+ setting?: { threshold: number } | undefined;
26
+ callback: string;
27
+ }>
28
+ | undefined;
22
29
  }
23
30
 
24
31
  export function getTemplateVars(
@@ -34,6 +41,7 @@ export function getTemplateVars(
34
41
  hasWebSearch: tools.some(
35
42
  (tool) => typeof tool === "string" && tool === "web_search",
36
43
  ),
44
+ hooks: definition.hooks,
37
45
  };
38
46
  }
39
47
 
@@ -78,11 +86,15 @@ export async function generateIndexTs(vars: TemplateVars): Promise<string> {
78
86
  model: vars.model,
79
87
  systemPrompt: vars.systemPrompt,
80
88
  tools: vars.tools,
89
+ hooks: vars.hooks,
81
90
  };
82
91
  return prettier.format(
83
92
  `import { makeHttpTransport, makeStdioTransport } from "@townco/agent/acp-server";
84
93
  import type { AgentDefinition } from "@townco/agent/definition";
85
94
  import { basename } from "node:path";
95
+ import { createLogger } from "@townco/core";
96
+
97
+ const logger = createLogger("agent-index");
86
98
 
87
99
  // Load agent definition from JSON file
88
100
  const agent: AgentDefinition = ${JSON.stringify(agentDef)};
@@ -93,14 +105,14 @@ const transport = process.argv[2] || "stdio";
93
105
  const agentDir = process.cwd();
94
106
  const agentName = basename(agentDir);
95
107
 
96
- console.log("[agent] Configuration:", { transport, agentDir, agentName });
108
+ logger.info("Configuration", { transport, agentDir, agentName });
97
109
 
98
110
  if (transport === "http") {
99
111
  makeHttpTransport(agent, agentDir, agentName);
100
112
  } else if (transport === "stdio") {
101
113
  makeStdioTransport(agent);
102
114
  } else {
103
- console.error(\`Invalid transport: \${transport}\`);
115
+ logger.error(\`Invalid transport: \${transport}\`);
104
116
  process.exit(1);
105
117
  }
106
118
  `,
@@ -1,7 +0,0 @@
1
- /**
2
- * Test the agent/summarize ACP method via the /rpc endpoint
3
- *
4
- * This test does NOT require an Anthropic API key because
5
- * summarization just analyzes existing messages without calling the API
6
- */
7
- export {};
@@ -1,127 +0,0 @@
1
- /**
2
- * Test the agent/summarize ACP method via the /rpc endpoint
3
- *
4
- * This test does NOT require an Anthropic API key because
5
- * summarization just analyzes existing messages without calling the API
6
- */
7
- // Make this a module
8
- export {};
9
- // Sample Anthropic API request with tool calls
10
- const request = {
11
- jsonrpc: "2.0",
12
- id: "test-123",
13
- method: "agent/summarize",
14
- params: {
15
- messages: [
16
- {
17
- role: "assistant",
18
- content: [
19
- {
20
- type: "tool_use",
21
- id: "toolu_01ABC",
22
- name: "read_file",
23
- input: {
24
- target_file: "package.json",
25
- },
26
- },
27
- ],
28
- },
29
- {
30
- role: "user",
31
- content: [
32
- {
33
- type: "tool_result",
34
- tool_use_id: "toolu_01ABC",
35
- content: '{"name":"my-project"}',
36
- },
37
- ],
38
- },
39
- {
40
- role: "assistant",
41
- content: [
42
- {
43
- type: "tool_use",
44
- id: "toolu_02DEF",
45
- name: "codebase_search",
46
- input: {
47
- query: "React components",
48
- target_directories: [],
49
- },
50
- },
51
- ],
52
- },
53
- {
54
- role: "user",
55
- content: [
56
- {
57
- type: "tool_result",
58
- tool_use_id: "toolu_02DEF",
59
- content: "Found 5 components",
60
- },
61
- ],
62
- },
63
- ],
64
- },
65
- };
66
- const serverUrl = process.env.ACP_SERVER_URL || "http://localhost:3100";
67
- console.log("=".repeat(60));
68
- console.log("Testing agent/summarize via ACP Protocol");
69
- console.log("=".repeat(60));
70
- console.log();
71
- console.log(`Server URL: ${serverUrl}`);
72
- console.log(`Method: agent/summarize`);
73
- console.log(`Tool Calls: 2 (read_file, codebase_search)`);
74
- console.log();
75
- try {
76
- const response = await fetch(`${serverUrl}/rpc`, {
77
- method: "POST",
78
- headers: {
79
- "Content-Type": "application/json",
80
- },
81
- body: JSON.stringify(request),
82
- });
83
- if (!response.ok) {
84
- console.error(`HTTP Error: ${response.status} ${response.statusText}`);
85
- const errorText = await response.text();
86
- console.error("Response:", errorText);
87
- process.exit(1);
88
- }
89
- const data = await response.json();
90
- // Check for JSON-RPC error
91
- if (data.error) {
92
- console.error("JSON-RPC Error:", JSON.stringify(data.error, null, 2));
93
- process.exit(1);
94
- }
95
- console.log("✅ Success! JSON-RPC Response:");
96
- console.log(JSON.stringify(data, null, 2));
97
- console.log();
98
- // Display the summary in a nice format
99
- if (data.result && data.result.summary) {
100
- console.log("Summary:");
101
- console.log(` Total: ${data.result.summary.total}`);
102
- console.log(` Completed: ${data.result.summary.byStatus.completed || 0}`);
103
- console.log(` Errors: ${data.result.summary.byStatus.error || 0}`);
104
- console.log();
105
- console.log("Tool Calls:");
106
- for (const toolCall of data.result.toolCalls || []) {
107
- const statusEmoji = toolCall.status === "completed"
108
- ? "✓"
109
- : toolCall.status === "error"
110
- ? "✗"
111
- : "⋯";
112
- console.log(` ${statusEmoji} ${toolCall.description}`);
113
- }
114
- }
115
- console.log();
116
- console.log("=".repeat(60));
117
- console.log("Test Complete - No API Key Required! ✅");
118
- console.log("=".repeat(60));
119
- }
120
- catch (error) {
121
- console.error("Connection Error:");
122
- console.error(error instanceof Error ? error.message : String(error));
123
- console.log();
124
- console.log("Make sure the ACP server is running:");
125
- console.log(" bun run dev:agent-http --no-session");
126
- process.exit(1);
127
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * Test script for the /summarize endpoint
3
- *
4
- * Usage:
5
- * bun packages/agent/acp-server/test-summarizer.ts
6
- */
7
- export {};
@@ -1,170 +0,0 @@
1
- /**
2
- * Test script for the /summarize endpoint
3
- *
4
- * Usage:
5
- * bun packages/agent/acp-server/test-summarizer.ts
6
- */
7
- import { extractToolCalls, generateTextSummary, summarizeToolCalls, } from "./tool-summarizer";
8
- // Test data: Sample Anthropic API request with tool calls
9
- const sampleRequest = {
10
- model: "claude-sonnet-4-5-20250929",
11
- messages: [
12
- {
13
- role: "user",
14
- content: "Please read the package.json file",
15
- },
16
- {
17
- role: "assistant",
18
- content: [
19
- {
20
- type: "text",
21
- text: "I'll read the package.json file for you.",
22
- },
23
- {
24
- type: "tool_use",
25
- id: "toolu_01ABC123",
26
- name: "read_file",
27
- input: {
28
- target_file: "package.json",
29
- },
30
- },
31
- ],
32
- },
33
- {
34
- role: "user",
35
- content: [
36
- {
37
- type: "tool_result",
38
- tool_use_id: "toolu_01ABC123",
39
- content: JSON.stringify({
40
- name: "my-project",
41
- version: "1.0.0",
42
- dependencies: {
43
- react: "^18.0.0",
44
- },
45
- }),
46
- },
47
- ],
48
- },
49
- {
50
- role: "assistant",
51
- content: [
52
- {
53
- type: "text",
54
- text: "Now let me search for React components.",
55
- },
56
- {
57
- type: "tool_use",
58
- id: "toolu_02DEF456",
59
- name: "codebase_search",
60
- input: {
61
- query: "React components using hooks",
62
- target_directories: [],
63
- },
64
- },
65
- ],
66
- },
67
- {
68
- role: "user",
69
- content: [
70
- {
71
- type: "tool_result",
72
- tool_use_id: "toolu_02DEF456",
73
- content: "Found 5 components...",
74
- },
75
- ],
76
- },
77
- {
78
- role: "assistant",
79
- content: [
80
- {
81
- type: "text",
82
- text: "Let me try to run a command that will fail.",
83
- },
84
- {
85
- type: "tool_use",
86
- id: "toolu_03GHI789",
87
- name: "run_terminal_cmd",
88
- input: {
89
- command: "invalid-command",
90
- },
91
- },
92
- ],
93
- },
94
- {
95
- role: "user",
96
- content: [
97
- {
98
- type: "tool_result",
99
- tool_use_id: "toolu_03GHI789",
100
- content: "Command not found: invalid-command",
101
- is_error: true,
102
- },
103
- ],
104
- },
105
- ],
106
- };
107
- console.log("=".repeat(60));
108
- console.log("Testing Tool Call Summarizer");
109
- console.log("=".repeat(60));
110
- console.log();
111
- // Test 1: Extract tool calls
112
- console.log("Test 1: Extract Tool Calls");
113
- console.log("-".repeat(60));
114
- const toolCalls = extractToolCalls(sampleRequest.messages);
115
- console.log(`Found ${toolCalls.length} tool calls`);
116
- console.log();
117
- for (const toolCall of toolCalls) {
118
- console.log(`- ${toolCall.description} [${toolCall.status}]`);
119
- console.log(` ID: ${toolCall.id}`);
120
- console.log(` Name: ${toolCall.name}`);
121
- }
122
- console.log();
123
- // Test 2: Generate summary
124
- console.log("Test 2: Generate Summary");
125
- console.log("-".repeat(60));
126
- const summary = summarizeToolCalls(sampleRequest);
127
- console.log(`Total: ${summary.total}`);
128
- console.log(`By Status:`, summary.byStatus);
129
- console.log(`By Tool:`, summary.byTool);
130
- console.log();
131
- // Test 3: Generate text summary
132
- console.log("Test 3: Generate Text Summary");
133
- console.log("-".repeat(60));
134
- const textSummary = generateTextSummary(summary.summaries, {
135
- includeDetails: true,
136
- });
137
- console.log(textSummary);
138
- console.log();
139
- // Test 4: Test with HTTP endpoint (if server is running)
140
- console.log("Test 4: Test HTTP Endpoint");
141
- console.log("-".repeat(60));
142
- const serverUrl = process.env.ACP_SERVER_URL || "http://localhost:3100";
143
- console.log(`Testing endpoint: ${serverUrl}/summarize`);
144
- try {
145
- const response = await fetch(`${serverUrl}/summarize`, {
146
- method: "POST",
147
- headers: {
148
- "Content-Type": "application/json",
149
- },
150
- body: JSON.stringify(sampleRequest),
151
- });
152
- if (!response.ok) {
153
- const errorData = await response.json();
154
- console.error("Error:", errorData);
155
- }
156
- else {
157
- const data = await response.json();
158
- console.log("Success! Response:");
159
- console.log(JSON.stringify(data, null, 2));
160
- }
161
- }
162
- catch (error) {
163
- console.error("Could not connect to server. Make sure the ACP server is running.");
164
- console.error("Start it with: bun packages/agent/acp-server/cli.ts");
165
- console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
166
- }
167
- console.log();
168
- console.log("=".repeat(60));
169
- console.log("Tests Complete");
170
- console.log("=".repeat(60));
@@ -1,125 +0,0 @@
1
- import { z } from "zod";
2
- /**
3
- * Anthropic API tool call format
4
- */
5
- export declare const AnthropicToolCallSchema: z.ZodObject<{
6
- id: z.ZodString;
7
- type: z.ZodLiteral<"tool_use">;
8
- name: z.ZodString;
9
- input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
10
- }, z.core.$strip>;
11
- export type AnthropicToolCall = z.infer<typeof AnthropicToolCallSchema>;
12
- /**
13
- * Anthropic API content block format
14
- */
15
- export declare const AnthropicContentBlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
16
- type: z.ZodLiteral<"text">;
17
- text: z.ZodString;
18
- }, z.core.$strip>, z.ZodObject<{
19
- id: z.ZodString;
20
- type: z.ZodLiteral<"tool_use">;
21
- name: z.ZodString;
22
- input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
23
- }, z.core.$strip>, z.ZodObject<{
24
- type: z.ZodLiteral<"tool_result">;
25
- tool_use_id: z.ZodString;
26
- content: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodObject<{
27
- type: z.ZodLiteral<"text">;
28
- text: z.ZodString;
29
- }, z.core.$strip>>]>;
30
- is_error: z.ZodOptional<z.ZodBoolean>;
31
- }, z.core.$strip>], "type">;
32
- export type AnthropicContentBlock = z.infer<typeof AnthropicContentBlockSchema>;
33
- /**
34
- * Anthropic API message format
35
- */
36
- export declare const AnthropicMessageSchema: z.ZodObject<{
37
- role: z.ZodEnum<{
38
- assistant: "assistant";
39
- user: "user";
40
- }>;
41
- content: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
42
- type: z.ZodLiteral<"text">;
43
- text: z.ZodString;
44
- }, z.core.$strip>, z.ZodObject<{
45
- id: z.ZodString;
46
- type: z.ZodLiteral<"tool_use">;
47
- name: z.ZodString;
48
- input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
49
- }, z.core.$strip>, z.ZodObject<{
50
- type: z.ZodLiteral<"tool_result">;
51
- tool_use_id: z.ZodString;
52
- content: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodObject<{
53
- type: z.ZodLiteral<"text">;
54
- text: z.ZodString;
55
- }, z.core.$strip>>]>;
56
- is_error: z.ZodOptional<z.ZodBoolean>;
57
- }, z.core.$strip>], "type">>]>;
58
- }, z.core.$strip>;
59
- export type AnthropicMessage = z.infer<typeof AnthropicMessageSchema>;
60
- /**
61
- * Anthropic API request format
62
- */
63
- export declare const AnthropicRequestSchema: z.ZodObject<{
64
- model: z.ZodOptional<z.ZodString>;
65
- messages: z.ZodArray<z.ZodObject<{
66
- role: z.ZodEnum<{
67
- assistant: "assistant";
68
- user: "user";
69
- }>;
70
- content: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
71
- type: z.ZodLiteral<"text">;
72
- text: z.ZodString;
73
- }, z.core.$strip>, z.ZodObject<{
74
- id: z.ZodString;
75
- type: z.ZodLiteral<"tool_use">;
76
- name: z.ZodString;
77
- input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
78
- }, z.core.$strip>, z.ZodObject<{
79
- type: z.ZodLiteral<"tool_result">;
80
- tool_use_id: z.ZodString;
81
- content: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodObject<{
82
- type: z.ZodLiteral<"text">;
83
- text: z.ZodString;
84
- }, z.core.$strip>>]>;
85
- is_error: z.ZodOptional<z.ZodBoolean>;
86
- }, z.core.$strip>], "type">>]>;
87
- }, z.core.$strip>>;
88
- max_tokens: z.ZodOptional<z.ZodNumber>;
89
- temperature: z.ZodOptional<z.ZodNumber>;
90
- tools: z.ZodOptional<z.ZodArray<z.ZodAny>>;
91
- system: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodAny>]>>;
92
- }, z.core.$strip>;
93
- export type AnthropicRequest = z.infer<typeof AnthropicRequestSchema>;
94
- /**
95
- * Tool call summary for display
96
- */
97
- export interface ToolCallSummary {
98
- id: string;
99
- name: string;
100
- description: string;
101
- input: Record<string, unknown>;
102
- output?: string | undefined;
103
- status: "pending" | "completed" | "error";
104
- error?: string | undefined;
105
- }
106
- /**
107
- * Extract tool calls from Anthropic API messages
108
- */
109
- export declare function extractToolCalls(messages: AnthropicMessage[]): ToolCallSummary[];
110
- /**
111
- * Generate a summary of tool calls for the entire conversation
112
- */
113
- export declare function summarizeToolCalls(request: AnthropicRequest): {
114
- total: number;
115
- byStatus: Record<string, number>;
116
- byTool: Record<string, number>;
117
- summaries: ToolCallSummary[];
118
- };
119
- /**
120
- * Generate a text summary of tool calls
121
- */
122
- export declare function generateTextSummary(summaries: ToolCallSummary[], options?: {
123
- includeDetails?: boolean;
124
- maxLength?: number;
125
- }): string;