create-polos 0.1.0

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 (2) hide show
  1. package/dist/index.js +445 -0
  2. package/package.json +31 -0
package/dist/index.js ADDED
@@ -0,0 +1,445 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import path2 from "path";
5
+ import fs2 from "fs";
6
+ import * as p from "@clack/prompts";
7
+
8
+ // src/providers.ts
9
+ var providers = [
10
+ {
11
+ label: "Anthropic",
12
+ value: "anthropic",
13
+ import: `import { anthropic } from '@ai-sdk/anthropic'`,
14
+ call: `anthropic('claude-sonnet-4-5')`,
15
+ package: "@ai-sdk/anthropic",
16
+ packageVersion: "^3.0.0",
17
+ envVar: "ANTHROPIC_API_KEY",
18
+ envPlaceholder: "sk-ant-..."
19
+ },
20
+ {
21
+ label: "OpenAI",
22
+ value: "openai",
23
+ import: `import { openai } from '@ai-sdk/openai'`,
24
+ call: `openai('gpt-4o-mini')`,
25
+ package: "@ai-sdk/openai",
26
+ packageVersion: "^3.0.0",
27
+ envVar: "OPENAI_API_KEY",
28
+ envPlaceholder: "sk-..."
29
+ },
30
+ {
31
+ label: "Google Gemini",
32
+ value: "google",
33
+ import: `import { google } from '@ai-sdk/google'`,
34
+ call: `google('gemini-2.0-flash')`,
35
+ package: "@ai-sdk/google",
36
+ packageVersion: "^3.0.0",
37
+ envVar: "GOOGLE_GENERATIVE_AI_API_KEY",
38
+ envPlaceholder: "AIza..."
39
+ }
40
+ ];
41
+
42
+ // src/scaffold.ts
43
+ import fs from "fs";
44
+ import path from "path";
45
+ import { execSync } from "child_process";
46
+
47
+ // src/templates/package-json.ts
48
+ function packageJsonTemplate(projectName, provider) {
49
+ return `{
50
+ "name": ${JSON.stringify(projectName)},
51
+ "version": "0.1.0",
52
+ "private": true,
53
+ "type": "module",
54
+ "scripts": {
55
+ "dev": "polos dev",
56
+ "start": "tsx src/main.ts"
57
+ },
58
+ "dependencies": {
59
+ "${provider.package}": "${provider.packageVersion}",
60
+ "@polos/sdk": "latest",
61
+ "dotenv": "^16.4.0"
62
+ },
63
+ "devDependencies": {
64
+ "@types/node": "^22.0.0",
65
+ "tsx": "^4.0.0",
66
+ "typescript": "^5.7.0"
67
+ }
68
+ }
69
+ `;
70
+ }
71
+
72
+ // src/templates/tsconfig-json.ts
73
+ function tsconfigJsonTemplate() {
74
+ return `{
75
+ "compilerOptions": {
76
+ "target": "ES2022",
77
+ "module": "ESNext",
78
+ "moduleResolution": "bundler",
79
+ "esModuleInterop": true,
80
+ "strict": true,
81
+ "skipLibCheck": true,
82
+ "outDir": "dist",
83
+ "rootDir": "src"
84
+ },
85
+ "include": ["src"]
86
+ }
87
+ `;
88
+ }
89
+
90
+ // src/templates/env-example.ts
91
+ function envExampleTemplate(provider) {
92
+ return `${provider.envVar}=${provider.envPlaceholder}
93
+ TAVILY_API_KEY=tvly-...
94
+ # POLOS_API_URL=http://localhost:8080
95
+ # POLOS_API_KEY=
96
+ `;
97
+ }
98
+
99
+ // src/templates/gitignore.ts
100
+ function gitignoreTemplate() {
101
+ return `node_modules/
102
+ dist/
103
+ .env
104
+ *.log
105
+ `;
106
+ }
107
+
108
+ // src/templates/readme.ts
109
+ function readmeTemplate(projectName, provider) {
110
+ return `# ${projectName}
111
+
112
+ A Polos agent project using **${provider.label}**.
113
+
114
+ ## Getting Started
115
+
116
+ 1. Install dependencies:
117
+ \`\`\`bash
118
+ npm install
119
+ \`\`\`
120
+
121
+ 2. Copy \`.env.example\` to \`.env\` and add your API keys:
122
+ \`\`\`bash
123
+ cp .env.example .env
124
+ \`\`\`
125
+
126
+ 3. Start the development server:
127
+ \`\`\`bash
128
+ npx polos dev
129
+ \`\`\`
130
+
131
+ ## Project Structure
132
+
133
+ \`\`\`
134
+ src/
135
+ main.ts # Entry point \u2014 imports agents, starts Polos
136
+ agents/
137
+ coding-agent.ts # Coding agent with local sandbox tools
138
+ assistant-agent.ts # Assistant with sandbox tools + web search + ask user
139
+ text-review/
140
+ agents.ts # Grammar, tone, correctness, and editor agents
141
+ workflow.ts # Parallel review workflow
142
+ \`\`\`
143
+
144
+ ## Agents
145
+
146
+ - **coding_agent** \u2014 A coding agent with local sandbox tools (exec, read, write, edit, glob, grep)
147
+ - **assistant_agent** \u2014 An assistant with sandbox tools, web search, and ask user
148
+ - **text_review** \u2014 A workflow that runs 3 reviewers in parallel, then a final editor
149
+
150
+ ## Learn More
151
+
152
+ - [Polos Documentation](https://docs.polos.dev)
153
+ `;
154
+ }
155
+
156
+ // src/templates/main.ts.ts
157
+ function mainTsTemplate() {
158
+ return `import 'dotenv/config';
159
+ import { Polos } from '@polos/sdk';
160
+
161
+ // Import agents and workflows for registration
162
+ import './agents/coding-agent.js';
163
+ import './agents/assistant-agent.js';
164
+ import './agents/text-review/agents.js';
165
+ import './agents/text-review/workflow.js';
166
+
167
+ const polos = new Polos();
168
+ await polos.serve();
169
+ `;
170
+ }
171
+
172
+ // src/templates/coding-agent.ts.ts
173
+ function codingAgentTemplate(provider) {
174
+ return `${provider.import};
175
+ import { defineAgent, maxSteps, sandboxTools } from '@polos/sdk';
176
+ import path from 'node:path';
177
+
178
+ const workspaceDir = path.resolve(process.cwd(), 'workspace');
179
+
180
+ const tools = sandboxTools({
181
+ env: 'local',
182
+ local: {
183
+ cwd: workspaceDir,
184
+ pathRestriction: workspaceDir,
185
+ },
186
+ });
187
+
188
+ export const codingAgent = defineAgent({
189
+ id: 'coding_agent',
190
+ model: ${provider.call},
191
+ systemPrompt: \`You are a coding agent with access to sandbox tools.
192
+ Your workspace is at \${workspaceDir}.
193
+ Use your tools to read, write, and execute code.\`,
194
+ tools,
195
+ stopConditions: [maxSteps({ count: 30 })],
196
+ });
197
+ `;
198
+ }
199
+
200
+ // src/templates/assistant-agent.ts.ts
201
+ function assistantAgentTemplate(provider) {
202
+ return `${provider.import};
203
+ import {
204
+ defineAgent,
205
+ maxSteps,
206
+ sandboxTools,
207
+ createWebSearchTool,
208
+ createAskUserTool,
209
+ } from '@polos/sdk';
210
+ import path from 'node:path';
211
+
212
+ const workspaceDir = path.resolve(process.cwd(), 'workspace');
213
+
214
+ const sandbox = sandboxTools({
215
+ env: 'local',
216
+ local: {
217
+ cwd: workspaceDir,
218
+ pathRestriction: workspaceDir,
219
+ },
220
+ });
221
+
222
+ const webSearch = createWebSearchTool({
223
+ maxResults: 5,
224
+ searchDepth: 'basic',
225
+ includeAnswer: true,
226
+ approval: 'always',
227
+ });
228
+
229
+ const askUser = createAskUserTool();
230
+
231
+ export const assistantAgent = defineAgent({
232
+ id: 'assistant_agent',
233
+ model: ${provider.call},
234
+ systemPrompt: \`You are a helpful assistant with access to sandbox tools, web search, and the ability to ask the user for clarification.
235
+ Your workspace is at \${workspaceDir}.
236
+ Use your tools to help the user with their tasks.\`,
237
+ tools: [...sandbox, webSearch, askUser],
238
+ stopConditions: [maxSteps({ count: 30 })],
239
+ });
240
+ `;
241
+ }
242
+
243
+ // src/templates/text-review-agents.ts.ts
244
+ function textReviewAgentsTemplate(provider) {
245
+ return `${provider.import};
246
+ import { defineAgent, maxSteps } from '@polos/sdk';
247
+
248
+ export const grammarReviewAgent = defineAgent({
249
+ id: 'grammar_reviewer',
250
+ model: ${provider.call},
251
+ systemPrompt: \`You are a grammar reviewer. Analyze the provided text for grammatical errors,
252
+ punctuation issues, and sentence structure problems. Provide a concise review with specific
253
+ suggestions for improvement. Return your review as a single string.\`,
254
+ stopConditions: [maxSteps({ count: 10 })],
255
+ });
256
+
257
+ export const toneConsistencyAgent = defineAgent({
258
+ id: 'tone_reviewer',
259
+ model: ${provider.call},
260
+ systemPrompt: \`You are a tone and consistency reviewer. Analyze the provided text for tone shifts,
261
+ inconsistencies in voice, and style issues. Provide a concise review with specific suggestions
262
+ for improvement. Return your review as a single string.\`,
263
+ stopConditions: [maxSteps({ count: 10 })],
264
+ });
265
+
266
+ export const correctnessAgent = defineAgent({
267
+ id: 'correctness_reviewer',
268
+ model: ${provider.call},
269
+ systemPrompt: \`You are a factual correctness reviewer. Analyze the provided text for factual accuracy,
270
+ logical consistency, and unsupported claims. Provide a concise review with specific concerns.
271
+ Return your review as a single string.\`,
272
+ stopConditions: [maxSteps({ count: 10 })],
273
+ });
274
+
275
+ export const finalEditorAgent = defineAgent({
276
+ id: 'final_editor',
277
+ model: ${provider.call},
278
+ systemPrompt: \`You are a final editor. You will receive the original text along with reviews from
279
+ grammar, tone, and correctness reviewers. Synthesize all feedback and produce an improved
280
+ version of the text. Return only the improved text.\`,
281
+ stopConditions: [maxSteps({ count: 10 })],
282
+ });
283
+ `;
284
+ }
285
+
286
+ // src/templates/text-review-workflow.ts.ts
287
+ function textReviewWorkflowTemplate() {
288
+ return `import { defineWorkflow } from '@polos/sdk';
289
+ import {
290
+ grammarReviewAgent,
291
+ toneConsistencyAgent,
292
+ correctnessAgent,
293
+ finalEditorAgent,
294
+ } from './agents.js';
295
+
296
+ interface TextReviewPayload {
297
+ text: string;
298
+ }
299
+
300
+ interface TextReviewResult {
301
+ originalText: string;
302
+ grammarReview: string;
303
+ toneReview: string;
304
+ correctnessReview: string;
305
+ finalText: string;
306
+ }
307
+
308
+ export const textReview = defineWorkflow<TextReviewPayload, unknown, TextReviewResult>(
309
+ { id: 'text_review' },
310
+ async (ctx, payload) => {
311
+ const { text } = payload;
312
+
313
+ // Run 3 reviewers in parallel
314
+ const reviewResults = await ctx.step.batchAgentInvokeAndWait<Record<string, unknown>>(
315
+ 'parallel_reviews',
316
+ [
317
+ grammarReviewAgent.withInput(\`Review this text for grammar:\\n\\n\${text}\`),
318
+ toneConsistencyAgent.withInput(\`Review this text for tone:\\n\\n\${text}\`),
319
+ correctnessAgent.withInput(\`Review this text for correctness:\\n\\n\${text}\`),
320
+ ],
321
+ );
322
+
323
+ const grammarReview = (reviewResults[0]?.['result'] as string) ?? '';
324
+ const toneReview = (reviewResults[1]?.['result'] as string) ?? '';
325
+ const correctnessReview = (reviewResults[2]?.['result'] as string) ?? '';
326
+
327
+ // Send all reviews to the final editor
328
+ const editorPrompt = \`Original text:
329
+ \${text}
330
+
331
+ Grammar review:
332
+ \${grammarReview}
333
+
334
+ Tone review:
335
+ \${toneReview}
336
+
337
+ Correctness review:
338
+ \${correctnessReview}
339
+
340
+ Please produce an improved version of the original text incorporating the feedback above.\`;
341
+
342
+ const editorResult = (await ctx.step.agentInvokeAndWait(
343
+ 'final_editor',
344
+ finalEditorAgent.withInput(editorPrompt),
345
+ )) as Record<string, unknown>;
346
+
347
+ return {
348
+ originalText: text,
349
+ grammarReview,
350
+ toneReview,
351
+ correctnessReview,
352
+ finalText: (editorResult['result'] as string) ?? '',
353
+ };
354
+ },
355
+ );
356
+ `;
357
+ }
358
+
359
+ // src/scaffold.ts
360
+ function generateFiles(projectName, provider) {
361
+ return [
362
+ { path: "package.json", content: packageJsonTemplate(projectName, provider) },
363
+ { path: "tsconfig.json", content: tsconfigJsonTemplate() },
364
+ { path: ".env.example", content: envExampleTemplate(provider) },
365
+ { path: ".gitignore", content: gitignoreTemplate() },
366
+ { path: "README.md", content: readmeTemplate(projectName, provider) },
367
+ { path: "src/main.ts", content: mainTsTemplate() },
368
+ { path: "src/agents/coding-agent.ts", content: codingAgentTemplate(provider) },
369
+ { path: "src/agents/assistant-agent.ts", content: assistantAgentTemplate(provider) },
370
+ { path: "src/agents/text-review/agents.ts", content: textReviewAgentsTemplate(provider) },
371
+ { path: "src/agents/text-review/workflow.ts", content: textReviewWorkflowTemplate() }
372
+ ];
373
+ }
374
+ function scaffoldProject(projectDir, files) {
375
+ for (const file of files) {
376
+ const filePath = path.join(projectDir, file.path);
377
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
378
+ fs.writeFileSync(filePath, file.content);
379
+ }
380
+ }
381
+ function installDependencies(projectDir) {
382
+ try {
383
+ execSync("npm install", { cwd: projectDir, stdio: "pipe" });
384
+ return true;
385
+ } catch {
386
+ return false;
387
+ }
388
+ }
389
+
390
+ // src/index.ts
391
+ async function main() {
392
+ p.intro("Create a new Polos project");
393
+ const projectName = await p.text({
394
+ message: "What is your project name?",
395
+ placeholder: "my-polos-project",
396
+ defaultValue: "my-polos-project",
397
+ validate(value) {
398
+ if (!value) return "Project name is required";
399
+ if (!/^[a-z0-9@][a-z0-9._\-/]*$/.test(value)) {
400
+ return "Invalid project name \u2014 use lowercase letters, numbers, hyphens, and dots";
401
+ }
402
+ }
403
+ });
404
+ if (p.isCancel(projectName)) {
405
+ p.cancel("Operation cancelled.");
406
+ process.exit(0);
407
+ }
408
+ const providerValue = await p.select({
409
+ message: "Which LLM provider do you want to use?",
410
+ options: providers.map((prov) => ({
411
+ label: prov.label,
412
+ value: prov.value
413
+ })),
414
+ initialValue: "anthropic"
415
+ });
416
+ if (p.isCancel(providerValue)) {
417
+ p.cancel("Operation cancelled.");
418
+ process.exit(0);
419
+ }
420
+ const provider = providers.find((prov) => prov.value === providerValue);
421
+ const projectDir = path2.resolve(process.cwd(), projectName);
422
+ if (fs2.existsSync(projectDir)) {
423
+ p.cancel(`Directory "${projectName}" already exists.`);
424
+ process.exit(1);
425
+ }
426
+ const s = p.spinner();
427
+ s.start("Creating project files...");
428
+ const files = generateFiles(projectName, provider);
429
+ scaffoldProject(projectDir, files);
430
+ s.stop("Project files created.");
431
+ s.start("Installing dependencies...");
432
+ const installed = installDependencies(projectDir);
433
+ if (installed) {
434
+ s.stop("Dependencies installed.");
435
+ } else {
436
+ s.stop("Could not install dependencies. Run `npm install` manually.");
437
+ }
438
+ p.outro(`Your project is ready!
439
+
440
+ Next steps:
441
+ cd ${projectName}
442
+ cp .env.example .env # add your ${provider.envVar}
443
+ npx polos dev`);
444
+ }
445
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "create-polos",
3
+ "version": "0.1.0",
4
+ "description": "Scaffold a new Polos agent project",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-polos": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsup",
11
+ "dev": "tsup --watch"
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "keywords": [
17
+ "polos",
18
+ "agents",
19
+ "scaffolding",
20
+ "cli"
21
+ ],
22
+ "license": "Apache-2.0",
23
+ "dependencies": {
24
+ "@clack/prompts": "^0.9.1"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^22.0.0",
28
+ "tsup": "^8.0.0",
29
+ "typescript": "^5.7.0"
30
+ }
31
+ }