create-loopengine 0.1.73 → 0.1.74

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-loopengine",
3
- "version": "0.1.73",
3
+ "version": "0.1.74",
4
4
  "description": "Scaffold a new loopengine agent project — a runnable HTTP server with one example agent, in your own repo.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -82,10 +82,16 @@ import {
82
82
  interviewTools,
83
83
  listInterviews,
84
84
  pickInterviewModel,
85
+ pickAgentModel,
85
86
  previewCandidate,
86
87
  startInterview,
87
88
  setInterviewProject,
88
89
  type InterviewAgentSource,
90
+ templatesPageHtml,
91
+ TemplateError,
92
+ createFromTemplate,
93
+ listTemplates,
94
+ previewTemplate,
89
95
  globalConfigPageHtml,
90
96
  addGatewayTool,
91
97
  agentDir,
@@ -958,6 +964,44 @@ async function handleInterviews(req: IncomingMessage, res: ServerResponse, pathn
958
964
  }
959
965
  }
960
966
 
967
+ // Templates (loopengine's web/templates-admin.ts): ready-made agents,
968
+ // created through the same scaffold and registration as Agents → + New.
969
+ // A template agent takes the model of an agent that already works here,
970
+ // as an interview's does; with none, it starts on the scaffold's default.
971
+ async function handleStarterTemplates(req: IncomingMessage, res: ServerResponse, pathname: string): Promise<void> {
972
+ const json = (status: number, body: unknown): void => {
973
+ res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store' }).end(JSON.stringify(body))
974
+ }
975
+ const [id, action] = pathname.split('/').slice(2).map(decodeURIComponent) // after /starter-templates
976
+ const exists = (name: string) => Boolean(getEntry(name)) || existsSync(join(projectDir(), 'agents', name))
977
+ try {
978
+ if (!id) {
979
+ if (req.method === 'GET') return json(200, { templates: listTemplates() })
980
+ return json(405, { error: 'method not allowed' })
981
+ }
982
+ if (action === 'preview' && req.method === 'GET') return json(200, previewTemplate(id, { agentExists: exists }))
983
+ if (action === 'create' && req.method === 'POST') {
984
+ const model = pickAgentModel(interviewAgents())
985
+ const created = await createFromTemplate(id, {
986
+ agentExists: exists,
987
+ createAgent: async (name, systemPrompt) => {
988
+ const parsed = parseAgentTemplateOptions({ systemPrompt, ...(model ? { model } : {}) })
989
+ if (!parsed.ok) throw new TemplateError(parsed.error)
990
+ const indexPath = await scaffoldAgent(projectDir(), name, parsed.value)
991
+ registerAgent(await loadAgentModule(indexPath, indexPath))
992
+ },
993
+ })
994
+ return json(200, created)
995
+ }
996
+ return json(404, { error: 'not found' })
997
+ } catch (err) {
998
+ const message = err instanceof Error ? err.message : String(err)
999
+ if (err instanceof TemplateError) return json(message === 'No such template' ? 404 : 400, { error: message })
1000
+ console.error('[loopengine] template failed:', err)
1001
+ return json(500, { error: `Couldn't create it: ${message}` })
1002
+ }
1003
+ }
1004
+
961
1005
  async function handleCreateAgent(req: IncomingMessage, res: ServerResponse): Promise<void> {
962
1006
  const body = await readJsonBody(req)
963
1007
  if (typeof body.name !== 'string' || !body.name) {
@@ -3272,6 +3316,15 @@ const server = createServer(async (req, res) => {
3272
3316
  await handleInterviews(req, res, pathname)
3273
3317
  return
3274
3318
  }
3319
+ // Templates: the page, and its routes.
3320
+ if (req.method === 'GET' && pathname === '/templates') {
3321
+ res.writeHead(200, { 'content-type': 'text/html' }).end(templatesPageHtml)
3322
+ return
3323
+ }
3324
+ if (pathname === '/starter-templates' || pathname.startsWith('/starter-templates/')) {
3325
+ await handleStarterTemplates(req, res, pathname)
3326
+ return
3327
+ }
3275
3328
  const editAgentMatch = req.method === 'PUT' && pathname.match(/^\/agents\/([^/]+)$/)
3276
3329
  if (editAgentMatch) {
3277
3330
  await handleEditAgent(req, res, decodeURIComponent(editAgentMatch[1]))
@@ -9,7 +9,7 @@
9
9
  "cli": "tsx adapters/cli.ts"
10
10
  },
11
11
  "dependencies": {
12
- "loopengine": "^0.1.91",
12
+ "loopengine": "^0.1.92",
13
13
  "actauth": "^0.0.12",
14
14
  "tsx": "^4.19.0",
15
15
  "typescript": "^5.7.0"