Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
bc4f670
draft concept
rblalock Dec 25, 2025
cc22972
further adjustments
rblalock Dec 25, 2025
70fc791
feat(auth): Phase 4 BetterAuth integration refinements
rblalock Dec 26, 2025
e979edb
test(auth): comprehensive e2e tests for BetterAuth integration
rblalock Dec 26, 2025
c3991bc
fix(auth): browser compatibility for BetterAuth client
rblalock Dec 26, 2025
a1dbedc
chore: update ag-auth-test-app gitignore and regenerated files
rblalock Dec 26, 2025
43245ab
revert vite hack
rblalock Dec 26, 2025
c62c861
feat(cli): add 'agentuity project auth init' command
rblalock Dec 26, 2025
187b143
test(cli): add tests for project auth init command
rblalock Dec 26, 2025
b2cca96
fix(cli): split SQL statements for migration execution
rblalock Dec 26, 2025
14e266d
fix(cli): use tuiColors for checklist formatting
rblalock Dec 26, 2025
41942a6
feat(cli): unified database picker with existing option
rblalock Dec 26, 2025
ea7fe59
fix(cli): clarify existing database source in picker
rblalock Dec 26, 2025
38df088
feat(cli): integrate auth setup into agentuity create command
rblalock Dec 26, 2025
75f15ef
chore(ag-auth-test-app): clean up and make canonical auth example
rblalock Dec 26, 2025
4f18e3e
chore(auth): remove trailing blank lines
rblalock Dec 26, 2025
07d7fa8
fix(cli): skip Agentuity Auth prompt for templates with existing auth
rblalock Dec 26, 2025
aa9e10e
fix(auth): rename createAuthHandler to mountBetterAuthRoutes with imp…
rblalock Dec 26, 2025
92feb4f
chore: remove temporary documentation file
rblalock Dec 26, 2025
6a1454e
refactor(auth): consolidate SQL schema to single source of truth
rblalock Dec 26, 2025
5fd528a
feat(test-app): add API Key, JWT, Bearer, and Organization plugin exa…
rblalock Dec 26, 2025
81ac0ec
fix(auth): fix API Key plugin to work with database storage
rblalock Dec 26, 2025
9755114
fix(auth): add proper TypeScript types for default plugin API methods
rblalock Dec 26, 2025
a8a9b75
fix(auth): simplify ensureAuthSchema and fix API key storage config
rblalock Dec 26, 2025
b482bc9
feat(auth): add visual UI for BetterAuth plugin testing
rblalock Dec 26, 2025
89a2585
feat(auth): add withSession wrapper and scope-based access control
rblalock Dec 27, 2025
7b16c8d
refactor(auth): remove scope-based access control
rblalock Dec 27, 2025
d46fecf
fix(auth): fix migration tests and prevent context re-renders
rblalock Dec 27, 2025
2f61283
feat(auth): add org/apiKey helpers with lazy loading
rblalock Dec 27, 2025
2ab9355
feat(auth): security improvements for first-class auth
rblalock Dec 27, 2025
77939eb
fix(cli): consolidate auth integration examples into complete API setup
rblalock Dec 27, 2025
c14ee3d
refactor(auth): remove deprecated createMiddleware alias
rblalock Dec 27, 2025
c0e8193
feat(auth): add client plugins and bump BetterAuth to v1.4.9
rblalock Dec 27, 2025
5e3baf3
feat(auth): auto-configure trustedOrigins for Agentuity deployments
rblalock Dec 28, 2025
638844d
feat(cli): add agentuity-auth template
rblalock Dec 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ playwright-report/

# Generated CLI skills
**/.agents/skills/
apps/testing/ag-auth-test-app/cookies.txt
apps/testing/ag-auth-test-app/agentuity.json
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ See [docs/testing.md](docs/testing.md) for detailed standards.
- Import from `../src/` in tests
- Use `@agentuity/test-utils` for mocks
- All errors AND warnings must be zero
- When running tests, prefer using a subagent (Task tool) to avoid context bloat from test output

## Special Instructions

Expand Down
308 changes: 308 additions & 0 deletions apps/testing/ag-auth-test-app/.agents/agentuity/sdk/agent/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
# Agents Folder Guide

This folder contains AI agents for your Agentuity application. Each agent is organized in its own subdirectory.

## Generated Types

The `src/generated/` folder contains auto-generated TypeScript files:

- `registry.ts` - Agent registry with strongly-typed agent definitions and schema types
- `routes.ts` - Route registry for API, WebSocket, and SSE endpoints
- `app.ts` - Application entry point (regenerated on every build)

**Important:** Never edit files in `src/generated/` - they are overwritten on every build.

Import generated types in your agents:

```typescript
import type { HelloInput, HelloOutput } from '../generated/registry';
```

## Directory Structure

Each agent folder must contain:

- **agent.ts** (required) - Agent definition with schema and handler

Example structure:

```
src/agent/
├── hello/
│ └── agent.ts
├── process-data/
│ └── agent.ts
└── (generated files in src/generated/)
```

**Note:** HTTP routes are defined separately in `src/api/` - see the API folder guide for details.

## Creating an Agent

### Basic Agent (agent.ts)

```typescript
import { createAgent } from '@agentuity/runtime';
import { s } from '@agentuity/schema';

const agent = createAgent('my-agent', {
description: 'What this agent does',
schema: {
input: s.object({
name: s.string(),
age: s.number(),
}),
output: s.string(),
},
handler: async (ctx, input) => {
// Access context: ctx.app, ctx.config, ctx.logger, ctx.kv, ctx.vector, ctx.stream
return `Hello, ${input.name}! You are ${input.age} years old.`;
},
});

export default agent;
```

### Agent with Lifecycle (setup/shutdown)

```typescript
import { createAgent } from '@agentuity/runtime';
import { s } from '@agentuity/schema';

const agent = createAgent('lifecycle-agent', {
description: 'Agent with setup and shutdown',
schema: {
input: s.object({ message: s.string() }),
output: s.object({ result: s.string() }),
},
setup: async (app) => {
// Initialize resources (runs once on startup)
// app contains: appName, version, startedAt, config
return {
agentId: `agent-${Math.random().toString(36).substr(2, 9)}`,
connectionPool: ['conn-1', 'conn-2'],
};
},
handler: async (ctx, input) => {
// Access setup config via ctx.config (fully typed)
ctx.logger.info('Agent ID:', ctx.config.agentId);
ctx.logger.info('Connections:', ctx.config.connectionPool);
return { result: `Processed: ${input.message}` };
},
shutdown: async (app, config) => {
// Cleanup resources (runs on shutdown)
console.log('Shutting down agent:', config.agentId);
},
});

export default agent;
```

### Agent with Event Listeners

```typescript
import { createAgent } from '@agentuity/runtime';
import { s } from '@agentuity/schema';

const agent = createAgent('event-agent', {
schema: {
input: s.object({ data: s.string() }),
output: s.string(),
},
handler: async (ctx, input) => {
return `Processed: ${input.data}`;
},
});

agent.addEventListener('started', (eventName, agent, ctx) => {
ctx.logger.info('Agent started');
});

agent.addEventListener('completed', (eventName, agent, ctx) => {
ctx.logger.info('Agent completed');
});

agent.addEventListener('errored', (eventName, agent, ctx, error) => {
ctx.logger.error('Agent errored:', error);
});

export default agent;
```

## Agent Context (ctx)

The handler receives a context object with:

- **ctx.app** - Application state (appName, version, startedAt, config from createApp)
- **ctx.config** - Agent-specific config (from setup return value, fully typed)
- **ctx.logger** - Structured logger (info, warn, error, debug, trace)
- **ctx.tracer** - OpenTelemetry tracer for custom spans
- **ctx.sessionId** - Unique session identifier
- **ctx.kv** - Key-value storage
- **ctx.vector** - Vector storage for embeddings
- **ctx.stream** - Stream storage for real-time data
- **ctx.state** - In-memory request-scoped state (Map)
- **ctx.thread** - Thread information for multi-turn conversations
- **ctx.session** - Session information
- **ctx.waitUntil** - Schedule background tasks

## Examples

### Using Key-Value Storage

```typescript
handler: async (ctx, input) => {
await ctx.kv.set('user:123', { name: 'Alice', age: 30 });
const user = await ctx.kv.get('user:123');
await ctx.kv.delete('user:123');
const keys = await ctx.kv.list('user:*');
return user;
};
```

### Using Vector Storage

```typescript
handler: async (ctx, input) => {
await ctx.vector.upsert('docs', [
{ id: '1', values: [0.1, 0.2, 0.3], metadata: { text: 'Hello' } },
]);
const results = await ctx.vector.query('docs', [0.1, 0.2, 0.3], { topK: 5 });
return results;
};
```

### Using Streams

```typescript
handler: async (ctx, input) => {
const stream = await ctx.stream.create('agent-logs');
await ctx.stream.write(stream.id, 'Processing step 1');
await ctx.stream.write(stream.id, 'Processing step 2');
return { streamId: stream.id };
};
```

### Background Tasks with waitUntil

```typescript
handler: async (ctx, input) => {
// Schedule background work that continues after response
ctx.waitUntil(async () => {
await ctx.kv.set('processed', Date.now());
ctx.logger.info('Background task complete');
});

return { status: 'processing' };
};
```

### Calling Another Agent

```typescript
// Import the agent directly
import otherAgent from '../other-agent/agent';

handler: async (ctx, input) => {
const result = await otherAgent.run({ data: input.value });
return `Other agent returned: ${result}`;
};
```

## Subagents (Nested Agents)

Agents can have subagents organized one level deep. This is useful for grouping related functionality.

### Directory Structure for Subagents

```
src/agent/
└── team/ # Parent agent
├── agent.ts # Parent agent
├── members/ # Subagent
│ └── agent.ts
└── tasks/ # Subagent
└── agent.ts
```

### Parent Agent

```typescript
import { createAgent } from '@agentuity/runtime';
import { s } from '@agentuity/schema';

const agent = createAgent('team', {
description: 'Team Manager',
schema: {
input: s.object({ action: s.union([s.literal('info'), s.literal('count')]) }),
output: s.object({
message: s.string(),
timestamp: s.string(),
}),
},
handler: async (ctx, { action }) => {
return {
message: 'Team parent agent - manages members and tasks',
timestamp: new Date().toISOString(),
};
},
});

export default agent;
```

### Subagent (Accessing Parent)

```typescript
import { createAgent } from '@agentuity/runtime';
import { s } from '@agentuity/schema';
import parentAgent from '../agent';

const agent = createAgent('team.members', {
description: 'Members Subagent',
schema: {
input: s.object({
action: s.union([s.literal('list'), s.literal('add'), s.literal('remove')]),
name: s.optional(s.string()),
}),
output: s.object({
members: s.array(s.string()),
parentInfo: s.optional(s.string()),
}),
},
handler: async (ctx, { action, name }) => {
// Call parent agent directly
const parentResult = await parentAgent.run({ action: 'info' });
const parentInfo = `Parent says: ${parentResult.message}`;

let members = ['Alice', 'Bob'];
if (action === 'add' && name) {
members.push(name);
}

return { members, parentInfo };
},
});

export default agent;
```

### Key Points About Subagents

- **One level deep**: Only one level of nesting is supported (no nested subagents)
- **Access parent**: Import and call parent agents directly
- **Agent names**: Subagents have dotted names like `"team.members"`
- **Shared context**: Subagents share the same app context (kv, logger, etc.)

## Rules

- Each agent folder name becomes the agent's route name (e.g., `hello/` → `/agent/hello`)
- **agent.ts** must export default the agent instance
- The first argument to `createAgent()` is the agent name (must match folder structure)
- Input/output schemas are enforced with @agentuity/schema validation
- Setup return value type automatically flows to ctx.config (fully typed)
- Use ctx.logger for logging, not console.log
- Import agents directly to call them (recommended approach)
- Subagents are one level deep only (team/members/, not team/members/subagent/)

<!-- prompt_hash: 9a71bb6d5544990d6ab3ecdf143b3a5caad26ce2e250df3b728a8d70bbf1fbad -->
Loading
Loading