@genui-a3/create 0.1.4 → 0.1.6

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/README.md CHANGED
@@ -5,14 +5,16 @@ Scaffold a new [A3](https://www.npmjs.com/package/@genui-a3/core) agentic app in
5
5
  ## Quick Start
6
6
 
7
7
  ```bash
8
- npx @genui-a3/create@latest my-app
8
+ npx @genui-a3/create@latest
9
9
  ```
10
10
 
11
- This will:
11
+ This starts an **interactive session** that will:
12
12
 
13
- 1. Create a new directory with your project name
14
- 1. Copy a production-ready Next.js template
15
- 1. Install all dependencies automatically
13
+ 1. Prompt for your project name and directory
14
+ 2. Let you select and configure LLM providers (OpenAI, Anthropic, Bedrock)
15
+ 3. Generate a production-ready Next.js template
16
+ 4. Automatically create your `.env` with the provided credentials
17
+ 5. Install all dependencies
16
18
 
17
19
  Then start developing:
18
20
 
@@ -34,6 +36,23 @@ A fully configured Next.js application with:
34
36
  - **Material UI** — pre-configured theming with MUI components
35
37
  - **TypeScript** — strict type-checking out of the box
36
38
 
39
+ ## Configuration & Providers
40
+
41
+ The CLI guides you through setting up your LLM providers and authentication during scaffolding.
42
+
43
+ ### Supported Providers
44
+
45
+ | Provider | Authentication | Auto-Generated Config |
46
+ |----------|---------------|------------------------|
47
+ | **OpenAI** | API Key | `OPENAI_API_KEY` |
48
+ | **Anthropic** | API Key | `ANTHROPIC_API_KEY` |
49
+ | **AWS Bedrock** | AWS Profile or Access Keys | `AWS_REGION`, `AWS_ACCESS_KEY_ID`, etc. |
50
+
51
+ ### Automatic Setup
52
+
53
+ - **Environment Variables**: A `.env` file is generated with your keys so you can run the app immediately.
54
+ - **Provider Registry**: The CLI generates `app/lib/provider.ts`, pre-configuring the A3 `Provider` factory with your primary model selection.
55
+
37
56
  ## Usage
38
57
 
39
58
  ```bash
package/dist/index.js CHANGED
@@ -14,45 +14,39 @@ import fs from "fs-extra";
14
14
 
15
15
  // src/utils/providers.ts
16
16
  var PROVIDER_META = {
17
- openai: {
18
- label: "OpenAI",
19
- importPath: "@genui-a3/providers/openai",
20
- factory: "createOpenAIProvider",
21
- models: ["gpt-4o", "gpt-4o-mini"]
22
- },
23
- bedrock: {
24
- label: "AWS Bedrock",
25
- importPath: "@genui-a3/providers/bedrock",
26
- factory: "createBedrockProvider",
27
- models: ["us.anthropic.claude-sonnet-4-5-20250929-v1:0", "us.anthropic.claude-haiku-4-5-20251001-v1:0"]
28
- }
17
+ openai: { label: "OpenAI", exportName: "openaiProvider", file: "openai.ts" },
18
+ bedrock: { label: "AWS Bedrock", exportName: "bedrockProvider", file: "bedrock.ts" },
19
+ anthropic: { label: "Anthropic", exportName: "anthropicProvider", file: "anthropic.ts" }
29
20
  };
30
21
 
31
22
  // src/utils/generators.ts
32
- function generateProviderFile(targetDir, primaryProvider) {
33
- const { importPath, factory, models } = PROVIDER_META[primaryProvider];
34
- const modelsLiteral = models.map((m) => `'${m}'`).join(", ");
35
- const content = `import { ${factory} } from '${importPath}'
36
- import type { Provider } from '@genui-a3/core'
37
-
38
- let _provider: Provider
39
-
40
- export function getProvider(): Provider {
41
- if (!_provider) {
42
- _provider = ${factory}({
43
- models: [${modelsLiteral}],
44
- })
23
+ function generateProviderFiles(targetDir, config) {
24
+ const providersDir = path.join(targetDir, "app", "lib", "providers");
25
+ for (const [key, meta] of Object.entries(PROVIDER_META)) {
26
+ if (!config.providers.includes(key)) {
27
+ const filePath = path.join(providersDir, meta.file);
28
+ if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
29
+ }
45
30
  }
46
- return _provider
47
- }
48
- `;
49
- fs.outputFileSync(path.join(targetDir, "app", "lib", "provider.ts"), content);
31
+ const primaryMeta = PROVIDER_META[config.primaryProvider];
32
+ const lines = [];
33
+ for (const provKey of config.providers) {
34
+ const meta = PROVIDER_META[provKey];
35
+ const baseName = meta.file.replace(".ts", "");
36
+ lines.push(`export { ${meta.exportName} } from './${baseName}'`);
37
+ }
38
+ lines.push(`export { ${primaryMeta.exportName} as provider } from './${primaryMeta.file.replace(".ts", "")}'`);
39
+ lines.push("");
40
+ fs.outputFileSync(path.join(providersDir, "index.ts"), lines.join("\n"));
50
41
  }
51
42
  function generateEnvFile(targetDir, config) {
52
43
  const lines = ["# Generated by create-genui-a3", "# This file is git-ignored. Do not commit credentials.", ""];
53
44
  if (config.providers.includes("openai")) {
54
45
  lines.push("# OpenAI", `OPENAI_API_KEY=${config.openaiApiKey || ""}`, "");
55
46
  }
47
+ if (config.providers.includes("anthropic")) {
48
+ lines.push("# Anthropic", `ANTHROPIC_API_KEY=${config.anthropicApiKey || ""}`, "");
49
+ }
56
50
  if (config.providers.includes("bedrock")) {
57
51
  if (config.bedrockAuthMode === "profile") {
58
52
  lines.push("# AWS Bedrock (profile mode)", `AWS_PROFILE=${config.awsProfile || "default"}`);
@@ -187,6 +181,18 @@ async function promptOpenAIConfig(config) {
187
181
  handleCancel(openaiApiKey);
188
182
  config.openaiApiKey = openaiApiKey;
189
183
  }
184
+ async function promptAnthropicConfig(config) {
185
+ p.log.step(PROVIDER_META.anthropic.label);
186
+ const anthropicApiKey = await p.text({
187
+ message: "Anthropic API key:",
188
+ placeholder: "sk-ant-...",
189
+ validate(input) {
190
+ if (!input) return "API key is required. Get one at https://console.anthropic.com/settings/keys";
191
+ }
192
+ });
193
+ handleCancel(anthropicApiKey);
194
+ config.anthropicApiKey = anthropicApiKey;
195
+ }
190
196
  async function promptBedrockConfig(config) {
191
197
  p.log.step(PROVIDER_META.bedrock.label);
192
198
  const authMode = await p.select({
@@ -281,7 +287,8 @@ async function promptProviders() {
281
287
  message: "Which LLM provider(s) do you want to configure?",
282
288
  options: [
283
289
  { label: "OpenAI", value: "openai" },
284
- { label: "AWS Bedrock", value: "bedrock" }
290
+ { label: "AWS Bedrock", value: "bedrock" },
291
+ { label: "Anthropic", value: "anthropic" }
285
292
  ],
286
293
  required: true
287
294
  });
@@ -296,6 +303,9 @@ async function promptProviders() {
296
303
  if (providers.includes("bedrock")) {
297
304
  await promptBedrockConfig(config);
298
305
  }
306
+ if (providers.includes("anthropic")) {
307
+ await promptAnthropicConfig(config);
308
+ }
299
309
  if (providers.length > 1) {
300
310
  await promptPrimaryProvider(providers, config);
301
311
  }
@@ -359,8 +369,8 @@ async function main() {
359
369
  const spin = p2.spinner();
360
370
  spin.start("Scaffolding project files");
361
371
  scaffoldProject(templateDir, targetDir, projectName);
362
- spin.message("Configuring provider");
363
- generateProviderFile(targetDir, providerConfig.primaryProvider);
372
+ spin.message("Configuring providers");
373
+ generateProviderFiles(targetDir, providerConfig);
364
374
  spin.message("Generating .env file");
365
375
  generateEnvFile(targetDir, providerConfig);
366
376
  spin.stop("Project scaffolded");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genui-a3/create",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "CLI scaffolding tool for A3 agentic apps",
5
5
  "keywords": [
6
6
  "genui",
@@ -2,7 +2,7 @@ import { NextRequest } from 'next/server'
2
2
  import { EventType, type RunAgentInput } from '@ag-ui/client'
3
3
  import { EventEncoder } from '@ag-ui/encoder'
4
4
  import { AgentRegistry, ChatSession, MemorySessionStore, AGUIAgent } from '@genui-a3/core'
5
- import { getProvider } from '../../lib/provider'
5
+ import { provider } from '../../lib/providers'
6
6
  import { greetingAgent, State } from '../../agents/greeting'
7
7
  import { ageAgent } from '../../agents/age'
8
8
 
@@ -23,7 +23,7 @@ const a3Agent = new AGUIAgent({
23
23
  sessionId: input.threadId,
24
24
  store,
25
25
  initialAgentId: 'greeting',
26
- provider: getProvider(),
26
+ provider,
27
27
  }),
28
28
  })
29
29
 
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { NextRequest, NextResponse } from 'next/server'
7
7
  import { AgentRegistry, ChatSession, MemorySessionStore } from '@genui-a3/core'
8
- import { getProvider } from '../../lib/provider'
8
+ import { provider } from '../../lib/providers'
9
9
  import { greetingAgent, State } from '../../agents/greeting'
10
10
  import { ageAgent } from '../../agents/age'
11
11
 
@@ -36,7 +36,7 @@ export async function POST(request: NextRequest) {
36
36
  store,
37
37
  initialAgentId: 'greeting',
38
38
  initialState: { userName: undefined },
39
- provider: getProvider(),
39
+ provider,
40
40
  })
41
41
 
42
42
  const result = await session.send({ message })
@@ -1,6 +1,6 @@
1
1
  import { NextRequest } from 'next/server'
2
2
  import { AgentRegistry, ChatSession, MemorySessionStore } from '@genui-a3/core'
3
- import { getProvider } from '../../lib/provider'
3
+ import { provider } from '../../lib/providers'
4
4
  import { greetingAgent, State } from '../../agents/greeting'
5
5
  import { ageAgent } from '../../agents/age'
6
6
 
@@ -31,7 +31,7 @@ export async function POST(request: NextRequest) {
31
31
  store,
32
32
  initialAgentId: 'greeting',
33
33
  initialState: { userName: undefined },
34
- provider: getProvider(),
34
+ provider,
35
35
  })
36
36
 
37
37
  const encoder = new TextEncoder()
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useState, useCallback } from 'react'
3
+ import { useState, useCallback, useEffect, useRef } from 'react'
4
4
  import styled from 'styled-components'
5
5
  import { TextField, Button, Box } from '@mui/material'
6
6
  import type { Theme } from '@mui/material/styles'
@@ -26,6 +26,18 @@ const InputForm = styled.form`
26
26
 
27
27
  export function ChatInput({ onSubmit, disabled, placeholder = 'Type a message...' }: Props) {
28
28
  const [value, setValue] = useState('')
29
+ const inputRef = useRef<HTMLInputElement>(null)
30
+ const prevDisabled = useRef(disabled)
31
+
32
+ useEffect(() => {
33
+ // When transitioning from disabled (true) back to enabled (false), restore focus
34
+ if (prevDisabled.current && !disabled) {
35
+ // Small timeout to ensure the clear-disabled DOM update finishes
36
+ const timer = setTimeout(() => inputRef.current?.focus(), 10)
37
+ return () => clearTimeout(timer)
38
+ }
39
+ prevDisabled.current = disabled
40
+ }, [disabled])
29
41
 
30
42
  const handleSubmit = useCallback(
31
43
  (e: React.FormEvent) => {
@@ -42,6 +54,7 @@ export function ChatInput({ onSubmit, disabled, placeholder = 'Type a message...
42
54
  <InputContainer>
43
55
  <InputForm onSubmit={handleSubmit}>
44
56
  <TextField
57
+ inputRef={inputRef}
45
58
  fullWidth
46
59
  value={value}
47
60
  onChange={(e) => setValue(e.target.value)}
@@ -0,0 +1,5 @@
1
+ import { createAnthropicProvider } from '@genui-a3/providers/anthropic'
2
+
3
+ export const anthropicProvider = createAnthropicProvider({
4
+ models: ['claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001'],
5
+ })
@@ -0,0 +1,5 @@
1
+ import { createBedrockProvider } from '@genui-a3/providers/bedrock'
2
+
3
+ export const bedrockProvider = createBedrockProvider({
4
+ models: ['us.anthropic.claude-sonnet-4-5-20250929-v1:0', 'us.anthropic.claude-haiku-4-5-20251001-v1:0'],
5
+ })
@@ -0,0 +1,3 @@
1
+ import { createOpenAIProvider } from '@genui-a3/providers/openai'
2
+
3
+ export const openaiProvider = createOpenAIProvider({ models: ['gpt-4o', 'gpt-4o-mini'] })
@@ -11,8 +11,8 @@
11
11
  "@ag-ui/encoder": "0.0.45",
12
12
  "@emotion/react": "11.14.0",
13
13
  "@emotion/styled": "11.14.1",
14
- "@genui-a3/core": "^0.1.8",
15
- "@genui-a3/providers": "^0.0.1",
14
+ "@genui-a3/core": "^0.1.10",
15
+ "@genui-a3/providers": "^0.0.2",
16
16
  "@mui/icons-material": "7.3.7",
17
17
  "@mui/material": "7.3.7",
18
18
  "next": "16.1.6",