@strayl/agent 0.1.2 → 0.1.4

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 (58) hide show
  1. package/dist/agent.js +6 -7
  2. package/package.json +5 -1
  3. package/skills/api-creation/SKILL.md +631 -0
  4. package/skills/authentication/SKILL.md +294 -0
  5. package/skills/frontend-design/SKILL.md +108 -0
  6. package/skills/landing-creation/SKILL.md +125 -0
  7. package/skills/reference/SKILL.md +149 -0
  8. package/skills/web-application-creation/SKILL.md +231 -0
  9. package/src/agent.ts +0 -465
  10. package/src/checkpoints/manager.ts +0 -112
  11. package/src/context/manager.ts +0 -185
  12. package/src/context/summarizer.ts +0 -104
  13. package/src/context/trim.ts +0 -55
  14. package/src/emitter.ts +0 -14
  15. package/src/hitl/manager.ts +0 -77
  16. package/src/hitl/transport.ts +0 -13
  17. package/src/index.ts +0 -116
  18. package/src/llm/client.ts +0 -276
  19. package/src/llm/gemini-native.ts +0 -307
  20. package/src/llm/models.ts +0 -64
  21. package/src/middleware/compose.ts +0 -24
  22. package/src/middleware/credential-scrubbing.ts +0 -31
  23. package/src/middleware/forbidden-packages.ts +0 -107
  24. package/src/middleware/plan-mode.ts +0 -143
  25. package/src/middleware/prompt-caching.ts +0 -21
  26. package/src/middleware/tool-compression.ts +0 -25
  27. package/src/middleware/tool-filter.ts +0 -13
  28. package/src/prompts/implementation-mode.md +0 -16
  29. package/src/prompts/plan-mode.md +0 -51
  30. package/src/prompts/system.ts +0 -173
  31. package/src/skills/loader.ts +0 -53
  32. package/src/stdin-listener.ts +0 -61
  33. package/src/subagents/definitions.ts +0 -72
  34. package/src/subagents/manager.ts +0 -161
  35. package/src/todos/manager.ts +0 -61
  36. package/src/tools/builtin/delete.ts +0 -29
  37. package/src/tools/builtin/edit.ts +0 -74
  38. package/src/tools/builtin/exec.ts +0 -216
  39. package/src/tools/builtin/glob.ts +0 -104
  40. package/src/tools/builtin/grep.ts +0 -115
  41. package/src/tools/builtin/ls.ts +0 -54
  42. package/src/tools/builtin/move.ts +0 -31
  43. package/src/tools/builtin/read.ts +0 -69
  44. package/src/tools/builtin/write.ts +0 -42
  45. package/src/tools/executor.ts +0 -51
  46. package/src/tools/external/database.ts +0 -285
  47. package/src/tools/external/enter-plan-mode.ts +0 -34
  48. package/src/tools/external/generate-image.ts +0 -110
  49. package/src/tools/external/hitl-tools.ts +0 -118
  50. package/src/tools/external/preview.ts +0 -28
  51. package/src/tools/external/proxy-fetch.ts +0 -51
  52. package/src/tools/external/task.ts +0 -38
  53. package/src/tools/external/wait.ts +0 -20
  54. package/src/tools/external/web-fetch.ts +0 -57
  55. package/src/tools/external/web-search.ts +0 -61
  56. package/src/tools/registry.ts +0 -36
  57. package/src/tools/zod-to-json-schema.ts +0 -86
  58. package/src/types.ts +0 -151
@@ -1,57 +0,0 @@
1
- import { z } from "zod";
2
- import type { ToolDefinition, ToolContext } from "../../types.js";
3
- import { proxyFetch } from "./proxy-fetch.js";
4
-
5
- export const webFetchTool: ToolDefinition = {
6
- name: "web_fetch",
7
- description:
8
- "Fetch and extract content from a URL using Jina Reader API. " +
9
- "Returns the page title and main text content, cleaned of HTML.",
10
- parameters: z.object({
11
- url: z.string().describe("URL to fetch"),
12
- maxLength: z.number().optional().describe("Maximum content length in characters (default: 20000)"),
13
- }),
14
- execute: async (rawArgs: unknown, ctx: ToolContext): Promise<string> => {
15
- const args = rawArgs as { url: string; maxLength?: number };
16
- const maxLength = args.maxLength ?? 20000;
17
-
18
- try {
19
- const response = await proxyFetch(
20
- "jina",
21
- `https://r.jina.ai/${args.url}`,
22
- "JINA_API_KEY",
23
- {
24
- method: "GET",
25
- headers: { Accept: "application/json" },
26
- },
27
- ctx.env,
28
- );
29
-
30
- if (!response.ok) {
31
- return JSON.stringify({
32
- success: false,
33
- url: args.url,
34
- error: `Jina Reader error: ${response.status} ${response.statusText}`,
35
- });
36
- }
37
-
38
- const data = (await response.json()) as {
39
- data?: { title?: string; content?: string };
40
- title?: string;
41
- content?: string;
42
- };
43
-
44
- const title = data.data?.title ?? data.title ?? "";
45
- let content = data.data?.content ?? data.content ?? "";
46
-
47
- if (content.length > maxLength) {
48
- content = content.slice(0, maxLength) + "\n\n[... content truncated ...]";
49
- }
50
-
51
- return JSON.stringify({ success: true, url: args.url, title, content });
52
- } catch (e) {
53
- const msg = e instanceof Error ? e.message : String(e);
54
- return JSON.stringify({ success: false, url: args.url, error: `Fetch failed: ${msg}` });
55
- }
56
- },
57
- };
@@ -1,61 +0,0 @@
1
- import { z } from "zod";
2
- import type { ToolDefinition, ToolContext } from "../../types.js";
3
- import { proxyFetch } from "./proxy-fetch.js";
4
-
5
- export const webSearchTool: ToolDefinition = {
6
- name: "web_search",
7
- description:
8
- "Search the web for information using Tavily API. " +
9
- "Returns relevant results with titles, URLs, and content snippets.",
10
- parameters: z.object({
11
- query: z.string().describe("Search query"),
12
- maxResults: z.number().optional().describe("Maximum number of results (default: 5)"),
13
- topic: z.enum(["general", "news"]).optional().describe("Search topic: 'general' or 'news' (default: 'general')"),
14
- }),
15
- execute: async (rawArgs: unknown, ctx: ToolContext): Promise<string> => {
16
- const args = rawArgs as { query: string; maxResults?: number; topic?: string };
17
-
18
- try {
19
- const response = await proxyFetch(
20
- "tavily",
21
- "https://api.tavily.com/search",
22
- "TAVILY_API_KEY",
23
- {
24
- method: "POST",
25
- headers: { "Content-Type": "application/json" },
26
- body: JSON.stringify({
27
- query: args.query,
28
- max_results: args.maxResults ?? 5,
29
- topic: args.topic ?? "general",
30
- include_answer: true,
31
- }),
32
- },
33
- ctx.env,
34
- );
35
-
36
- if (!response.ok) {
37
- return JSON.stringify({ error: `Tavily API error: ${response.status} ${response.statusText}` });
38
- }
39
-
40
- const data = (await response.json()) as {
41
- query: string;
42
- answer?: string;
43
- results: Array<{ title: string; url: string; content: string }>;
44
- };
45
-
46
- return JSON.stringify({
47
- success: true,
48
- query: data.query,
49
- answer: data.answer,
50
- results: data.results.map(r => ({
51
- title: r.title,
52
- url: r.url,
53
- content: r.content?.slice(0, 500),
54
- })),
55
- });
56
- } catch (e) {
57
- const msg = e instanceof Error ? e.message : String(e);
58
- return JSON.stringify({ error: `Web search failed: ${msg}` });
59
- }
60
- },
61
- };
@@ -1,36 +0,0 @@
1
- import type OpenAI from "openai";
2
- import type { ToolDefinition } from "../types.js";
3
- import { zodToJsonSchema } from "./zod-to-json-schema.js";
4
-
5
- export class ToolRegistry {
6
- private tools = new Map<string, ToolDefinition>();
7
-
8
- register(tool: ToolDefinition): void {
9
- this.tools.set(tool.name, tool);
10
- }
11
-
12
- get(name: string): ToolDefinition | undefined {
13
- return this.tools.get(name);
14
- }
15
-
16
- has(name: string): boolean {
17
- return this.tools.has(name);
18
- }
19
-
20
- names(): string[] {
21
- return [...this.tools.keys()];
22
- }
23
-
24
- toOpenAITools(blocked?: Set<string>): OpenAI.ChatCompletionTool[] {
25
- return [...this.tools.values()]
26
- .filter(t => !blocked?.has(t.name))
27
- .map(t => ({
28
- type: "function" as const,
29
- function: {
30
- name: t.name,
31
- description: t.description,
32
- parameters: zodToJsonSchema(t.parameters),
33
- },
34
- }));
35
- }
36
- }
@@ -1,86 +0,0 @@
1
- import type { z } from "zod";
2
-
3
- export function zodToJsonSchema(schema: z.ZodType): Record<string, unknown> {
4
- return convertSchema(schema);
5
- }
6
-
7
- function convertSchema(schema: z.ZodType): Record<string, unknown> {
8
- const def = (schema as unknown as { _def: Record<string, unknown> })._def;
9
- const typeName = def.typeName as string;
10
- const description = def.description as string | undefined;
11
-
12
- const base: Record<string, unknown> = {};
13
- if (description) base.description = description;
14
-
15
- switch (typeName) {
16
- case "ZodString":
17
- return { ...base, type: "string" };
18
-
19
- case "ZodNumber":
20
- return { ...base, type: "number" };
21
-
22
- case "ZodBoolean":
23
- return { ...base, type: "boolean" };
24
-
25
- case "ZodEnum": {
26
- const values = (def.values as string[]);
27
- return { ...base, type: "string", enum: values };
28
- }
29
-
30
- case "ZodArray": {
31
- const itemSchema = def.type as z.ZodType;
32
- const result: Record<string, unknown> = { ...base, type: "array", items: convertSchema(itemSchema) };
33
- if (def.minLength != null) result.minItems = (def.minLength as { value: number }).value;
34
- if (def.maxLength != null) result.maxItems = (def.maxLength as { value: number }).value;
35
- return result;
36
- }
37
-
38
- case "ZodObject": {
39
- const shape = (def.shape as () => Record<string, z.ZodType>)();
40
- const properties: Record<string, unknown> = {};
41
- const required: string[] = [];
42
-
43
- for (const [key, value] of Object.entries(shape)) {
44
- const innerDef = (value as unknown as { _def: Record<string, unknown> })._def;
45
- if (innerDef.typeName === "ZodOptional") {
46
- properties[key] = convertSchema(innerDef.innerType as z.ZodType);
47
- } else {
48
- properties[key] = convertSchema(value);
49
- required.push(key);
50
- }
51
- }
52
-
53
- const result: Record<string, unknown> = { ...base, type: "object", properties };
54
- if (required.length > 0) result.required = required;
55
- return result;
56
- }
57
-
58
- case "ZodOptional": {
59
- return convertSchema(def.innerType as z.ZodType);
60
- }
61
-
62
- case "ZodDefault": {
63
- const inner = convertSchema(def.innerType as z.ZodType);
64
- inner.default = def.defaultValue;
65
- return inner;
66
- }
67
-
68
- case "ZodNullable": {
69
- const inner = convertSchema(def.innerType as z.ZodType);
70
- return { ...inner, nullable: true };
71
- }
72
-
73
- case "ZodLiteral": {
74
- const value = def.value;
75
- return { ...base, type: typeof value, const: value };
76
- }
77
-
78
- case "ZodUnion": {
79
- const options = (def.options as z.ZodType[]).map(convertSchema);
80
- return { ...base, oneOf: options };
81
- }
82
-
83
- default:
84
- return { ...base, type: "string" };
85
- }
86
- }
package/src/types.ts DELETED
@@ -1,151 +0,0 @@
1
- import type { z } from "zod";
2
- import type OpenAI from "openai";
3
- import type { Emitter } from "./emitter.js";
4
-
5
- // ─── Messages (OpenAI Chat Completions format) ──────────────────────
6
-
7
- export type Role = "system" | "user" | "assistant" | "tool";
8
-
9
- export interface ContentPart {
10
- type: "text" | "image_url";
11
- text?: string;
12
- image_url?: { url: string };
13
- }
14
-
15
- export interface ToolCallFunction {
16
- name: string;
17
- arguments: string;
18
- }
19
-
20
- export interface ToolCall {
21
- id: string;
22
- type: "function";
23
- function: ToolCallFunction;
24
- }
25
-
26
- export interface Message {
27
- role: Role;
28
- content: string | ContentPart[] | null;
29
- name?: string;
30
- tool_call_id?: string;
31
- tool_calls?: ToolCall[];
32
- }
33
-
34
- // ─── Agent Configuration ─────────────────────────────────────────────
35
-
36
- export type AgentMode = "normal" | "plan" | "implement";
37
-
38
- export interface AgentConfig {
39
- model: string;
40
- userMessage: string;
41
- sessionId: string;
42
- workDir: string;
43
- env: Record<string, string>;
44
- mode?: AgentMode;
45
- systemPromptExtra?: string;
46
- blockedTools?: string[];
47
- maxIterations?: number;
48
- summarizationThreshold?: number;
49
- preSummarizationRatio?: number;
50
- images?: Array<{ base64: string; contentType: string }>;
51
- previousSummary?: string;
52
- hitlDir?: string;
53
- skillsDir?: string;
54
- restoreCheckpoint?: CheckpointData;
55
- }
56
-
57
- // ─── Tool System ─────────────────────────────────────────────────────
58
-
59
- export interface ToolContext {
60
- emitter: Emitter;
61
- workDir: string;
62
- env: Record<string, string>;
63
- sessionId: string;
64
- toolCallId: string;
65
- }
66
-
67
- export interface ToolDefinition {
68
- name: string;
69
- description: string;
70
- parameters: z.ZodType;
71
- execute: (args: unknown, ctx: ToolContext) => Promise<string>;
72
- hitl?: boolean;
73
- }
74
-
75
- // ─── Middleware ───────────────────────────────────────────────────────
76
-
77
- export interface Middleware {
78
- name: string;
79
- beforeModel?: (messages: Message[]) => Message[];
80
- filterTools?: (tools: OpenAI.ChatCompletionTool[]) => OpenAI.ChatCompletionTool[];
81
- wrapToolCall?: (call: ToolCall, next: () => Promise<string>) => Promise<string>;
82
- }
83
-
84
- // ─── Events (stdout JSON-per-line) ───────────────────────────────────
85
-
86
- export type AgentEvent =
87
- | { type: "session-start"; model: string; session_id: string }
88
- | { type: "session-end"; usage: Usage; exit_reason: "complete" | "max_iterations" | "cancelled" | "error" }
89
- | { type: "text-delta"; text: string }
90
- | { type: "reasoning-delta"; text: string }
91
- | { type: "tool-call-start"; id: string; name: string; args: unknown }
92
- | { type: "tool-result"; id: string; name: string; output: unknown; error?: string }
93
- | { type: "file-complete"; id: string; path: string; lines: number; bytes: number }
94
- | { type: "exec-log"; id: string; data: string }
95
- | { type: "hitl-request"; id: string; safe_id: string; tool: string; args: unknown }
96
- | { type: "hitl-response"; id: string; decision: string; data: unknown }
97
- | { type: "subagent-start"; id: string; name: string; label: string }
98
- | { type: "subagent-delta"; id: string; text: string }
99
- | { type: "subagent-result"; id: string; output: string }
100
- | { type: "todos-update"; todos: TodoItem[] }
101
- | { type: "summarizing"; token_count: number; threshold: number }
102
- | { type: "summarized"; removed_msgs: number; kept_msgs: number; summary_chars: number }
103
- | { type: "usage-update"; input_tokens: number; output_tokens: number; cost?: number; peak_input_tokens: number; context_left_percent: number }
104
- | { type: "error"; message: string; recoverable: boolean }
105
- | { type: "activity"; activity: ActivityType; message?: string }
106
- | { type: "plan-mode-entered"; reason: string }
107
- | { type: "plan-confirmed"; plan: string }
108
- | { type: "mode-changed"; from: AgentMode; to: AgentMode }
109
- | { type: "preview"; port: number; title: string }
110
- | { type: "inject-received"; text: string }
111
- | { type: "checkpoint-saved"; id: string; iteration: number; checkpoint: CheckpointData }
112
- | { type: "checkpoint-restored"; id: string; iteration: number };
113
-
114
- export type ActivityType =
115
- | "creating-todos"
116
- | "updating-todos"
117
- | "clearing-todos"
118
- | "asking-user"
119
- | "planning"
120
- | "creating-database"
121
- | "running-query"
122
- | "running-migration"
123
- | "searching-web"
124
- | "fetching-page"
125
- | "generating-image"
126
- | "exploring-codebase"
127
- | "reading-file"
128
- | "writing-file"
129
- | "editing-file"
130
- | "running-command"
131
- | "delegating-task";
132
-
133
- export interface TodoItem {
134
- content: string;
135
- status: "pending" | "in_progress" | "completed";
136
- }
137
-
138
- export interface Usage {
139
- input_tokens: number;
140
- output_tokens: number;
141
- cost?: number;
142
- }
143
-
144
- export interface CheckpointData {
145
- id: string;
146
- iteration: number;
147
- timestamp: number;
148
- messages: Message[];
149
- todos: TodoItem[];
150
- usage: Usage;
151
- }