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.
- package/dist/index.js +445 -0
- 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
|
+
}
|