Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
239 changes: 239 additions & 0 deletions docs/providers/youcom-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
# You.com Provider Integration

The YouCom provider integrates You.com's web search into AgentOS, offering access to real-time web information and news search.

## Overview

Unlike traditional LLM providers, YouCom specializes in:
- **Real-time web search** with source URLs, descriptions, and snippets
- **News search** with timestamps and publication metadata

The provider reads credentials from `YDC_API_KEY` or `YOUCOM_API_KEY`, and you can also pass an explicit `apiKey` during initialization.

## Quick Start

```typescript
import { YouComProvider } from '@framers/agentos';

const provider = new YouComProvider();
await provider.initialize({
apiKey: process.env.YDC_API_KEY ?? process.env.YOUCOM_API_KEY,
});

const results = await provider.search('What are the latest developments in AI agent frameworks?', {
count: 5,
});

for (const item of results.web ?? []) {
console.log(item.title);
console.log(item.url);
console.log(item.description);
console.log(item.snippets[0]);
}
```

## Authentication

### Environment-Based Setup
The provider reads `YDC_API_KEY` first and falls back to `YOUCOM_API_KEY` for legacy setups.

```bash
export YDC_API_KEY="your_api_key_here"
```

Get your API key at [you.com/platform/api-keys](https://you.com/platform/api-keys).

Alternative environment variable:
```bash
export YOUCOM_API_KEY="your_api_key_here"
```

### Custom Configuration

```typescript
const provider = new YouComProvider();
await provider.initialize({
apiKey: process.env.YDC_API_KEY ?? process.env.YOUCOM_API_KEY,
searchApiUrl: 'https://ydc-index.io/v1/search',
mcpServerUrl: 'https://api.you.com/mcp',
debug: true,
});
```

## Available Models

| Model ID | Description | Use Case |
|----------|-------------|----------|
| `youcom-search` | Web search with snippets | General web search queries |
| `youcom-news` | News-focused search | Recent news and current events |

## Direct Search API

Access You.com search functionality directly:

```typescript
const provider = new YouComProvider();
await provider.initialize({
apiKey: process.env.YDC_API_KEY ?? process.env.YOUCOM_API_KEY,
});

Comment thread
coderabbitai[bot] marked this conversation as resolved.
// Web search
const results = await provider.search('TypeScript frameworks', {
count: 5,
type: 'web'
});

// News search
const news = await provider.search('AI developments', {
count: 3,
type: 'news'
});
```

## Response Format

### Web Search Results
```typescript
{
web: [
{
title: "Page title",
url: "https://example.com",
description: "Relevant excerpt from the page...",
snippets: ["Relevant excerpt from the page..."]
}
]
}
```

### News Search Results
```typescript
{
news: [
{
title: "Article title",
url: "https://news.example.com/article",
description: "Article excerpt...",
snippets: ["Article excerpt..."],
published_at: "2026-07-26T10:00:00Z"
}
]
}
```

## Error Handling

The provider handles common error scenarios gracefully:

- **Rate limiting (429)**: Returns helpful message about API key benefits
- **Network errors**: Fail-safe with informative error messages
- **Invalid queries**: Validation with suggestion prompts
- **Quota exceeded**: Clear indication of limits and upgrade paths

```typescript
try {
const results = await provider.search('query');
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
if (message.includes('rate limit')) {
console.log('Consider using an API key for higher quotas');
}
}
```

## Health Monitoring

Check provider connectivity and configuration:

```typescript
const health = await provider.checkHealth();
console.log('Healthy:', health.isHealthy);
console.log('API Key configured:', health.details.apiKeyConfigured);
```

## AgentOS Registry

YouCom is automatically registered in AgentOS's provider system:

```typescript
import { AIModelProviderManager } from '@framers/agentos';

const manager = new AIModelProviderManager();
await manager.initialize({
providers: [
{
providerId: 'youcom',
enabled: true,
config: {
apiKey: process.env.YDC_API_KEY ?? process.env.YOUCOM_API_KEY,
},
},
],
});
```

## MCP Server Path

You.com's MCP surface also includes content and research tooling. This provider
keeps the search integration small and optional, but if you wire the MCP server
later the corresponding tool names are:
- `you-search` for web search
- `you-contents` for URL content extraction
- `you-research` for research synthesis

Those MCP tools are not enabled by this PR.

## Limitations

- **No LLM generation**: YouCom focuses on search/tools, not text generation
- **No embeddings**: Use other providers for embedding models
- **No streaming**: Search results are returned as complete responses
- **Rate limits**: Keyless tier has daily quotas (overcome with API key)

## Best Practices

1. **Use for current information**: YouCom excels at real-time web data
2. **Combine with LLM providers**: Use YouCom for search, other providers for generation
3. **Cache results**: Avoid repeated identical searches
4. **Respect rate limits**: Monitor quota usage in production
5. **Cite sources**: Always include URLs in agent responses

## Examples

See `examples/youcom-search-example.mjs` for a complete working example demonstrating:
- Direct search and news search with YouComProvider
- Multiple query types
- Direct API access
- Error handling patterns
- Configuration examples

## Troubleshooting

### "Provider not initialized"
- Ensure `initialize()` is called before use
- Check network connectivity

### "Rate limit exceeded"
- Set `YDC_API_KEY` environment variable
- Implement request throttling
- Consider caching search results

### "Search API connectivity test failed"
- Check internet connection
- Verify You.com API endpoint accessibility
- Review firewall/proxy settings

### Integration Issues
- Confirm YouCom is registered in `AIModelProviderManager`
- Check provider configuration in AgentOS config
- Enable debug logging: `debug: true`

## Contributing

YouCom provider follows AgentOS provider standards:
- Implements full `IProvider` interface
- Comprehensive error handling
- Unit test coverage
- Documentation and examples

See [Provider Integration Guide](../contributing/new-provider.md) for details.
77 changes: 77 additions & 0 deletions examples/youcom-search-example.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env node
/**
* @fileoverview YouCom Provider Example - Demonstrates You.com integration with AgentOS
*
* This example shows how to use the YouCom provider for web search and news search.
*
* Usage:
* node examples/youcom-search-example.mjs
*
* Environment variables:
* YDC_API_KEY - You.com API key
* YOUCOM_API_KEY - Legacy fallback env var
*/

import { YouComProvider } from '@framers/agentos';

function printConfigurationExamples() {
console.log('\n📚 Configuration Examples:\n');

console.log('1. Environment-based setup:');
console.log(' export YDC_API_KEY="your-api-key-here"');
console.log(' # or export YOUCOM_API_KEY="your-api-key-here"\n');

console.log('2. Explicit initialization:');
console.log(` const provider = new YouComProvider();
await provider.initialize({
apiKey: process.env.YDC_API_KEY ?? process.env.YOUCOM_API_KEY,
});\n`);
}

async function runYouComExample() {
console.log('🔍 YouCom Provider Example - Search with AgentOS\n');

const provider = new YouComProvider();
await provider.initialize({
apiKey: process.env.YDC_API_KEY ?? process.env.YOUCOM_API_KEY,
debug: true,
});

const webQuery = 'What are the latest developments in AI agent frameworks?';
console.log(`\n📋 Web query: ${webQuery}`);
const webResults = await provider.search(webQuery, { count: 5, type: 'web' });

for (const [index, result] of (webResults.web ?? []).entries()) {
console.log(`${index + 1}. ${result.title}`);
console.log(` ${result.url}`);
console.log(` ${result.description}`);
if (result.snippets[0]) {
console.log(` ${result.snippets[0]}`);
}
}

const newsQuery = 'TypeScript 5.7 release';
console.log(`\n📰 News query: ${newsQuery}`);
const newsResults = await provider.search(newsQuery, {
count: 3,
type: 'news',
freshness: 'week',
});

for (const [index, result] of (newsResults.news ?? []).entries()) {
console.log(`${index + 1}. ${result.title}`);
console.log(` ${result.url}`);
console.log(` ${result.description}`);
if (result.published_at) {
console.log(` published: ${result.published_at}`);
}
}
}

if (import.meta.url === `file://${process.argv[1]}`) {
printConfigurationExamples();
runYouComExample().catch((error) => {
console.error('❌ YouCom example failed:', error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});
}
13 changes: 13 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
allowBuilds:
'@matrix-org/matrix-sdk-crypto-nodejs': true
'@whiskeysockets/baileys': true
bcrypt: true
better-sqlite3: true
esbuild: true
ffi-napi: true
hnswlib-node: true
onnxruntime-node: true
protobufjs: true
ref-napi: true
sharp: true
tesseract.js: true
3 changes: 2 additions & 1 deletion src/api/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const ENV_KEY_MAP: Record<string, string> = {
xai: 'XAI_API_KEY',
stability: 'STABILITY_API_KEY',
replicate: 'REPLICATE_API_TOKEN',
youcom: 'YDC_API_KEY',
};

const ENV_URL_MAP: Record<string, string> = {
Expand All @@ -59,7 +60,7 @@ const ENV_URL_MAP: Record<string, string> = {
'stable-diffusion-local': 'STABLE_DIFFUSION_LOCAL_BASE_URL',
};

const KEYLESS_PROVIDER_IDS = new Set(['claude-code-cli', 'gemini-cli']);
const KEYLESS_PROVIDER_IDS = new Set(['claude-code-cli', 'gemini-cli', 'youcom']);

/**
* Splits a `provider:model` string into its constituent parts.
Expand Down
18 changes: 11 additions & 7 deletions src/api/runtime/provider-defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ const AUTO_DETECT_ORDER: AutoDetectProbe[] = [
{ envKey: 'TOGETHER_API_KEY', provider: 'together' },
{ envKey: 'MISTRAL_API_KEY', provider: 'mistral' },
{ envKey: 'XAI_API_KEY', provider: 'xai' },
{ envKey: 'YDC_API_KEY', provider: 'youcom' },
{ envKey: 'YOUCOM_API_KEY', provider: 'youcom' }, // Fallback for legacy env var
Comment on lines +134 to +135

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve You.com credentials before auto-detecting it

When agent() or generateText() is used with the documented YDC_API_KEY/YOUCOM_API_KEY environment setup, these probes select youcom, but resolveProvider() has neither variable in ENV_KEY_MAP and does not list You.com in KEYLESS_PROVIDER_IDS (src/api/model.ts:40-62). It therefore throws at src/api/model.ts:158-160 before YouComProvider.initialize() can read the key; keyless calls with an explicit provider: 'youcom' fail at the same point. Add the credential mappings and keyless handling to the high-level resolver.

Useful? React with 👍 / 👎.

Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{ binaryName: 'claude', provider: 'claude-code-cli' },
{ binaryName: 'gemini', provider: 'gemini-cli' },
{ envKey: 'OLLAMA_BASE_URL', provider: 'ollama' },
Expand All @@ -148,11 +150,15 @@ function isBinaryOnPath(binaryName: string): boolean {
}

// Provider-id → probe lookup so a custom priority list (just provider
// ids) can be resolved back to its env-var or CLI-binary probe. Stays
// ids) can be resolved back to its env-var or CLI-binary probes. Stays
// in sync automatically with `AUTO_DETECT_ORDER`.
const PROBE_BY_PROVIDER: Record<string, AutoDetectProbe> = Object.fromEntries(
AUTO_DETECT_ORDER.map((probe) => [probe.provider, probe])
);
const PROBES_BY_PROVIDER: Record<string, AutoDetectProbe[]> = {};
for (const probe of AUTO_DETECT_ORDER) {
if (!PROBES_BY_PROVIDER[probe.provider]) {
PROBES_BY_PROVIDER[probe.provider] = [];
}
PROBES_BY_PROVIDER[probe.provider].push(probe);
}

/**
* Auto-detects the active provider by scanning well-known environment variables
Expand All @@ -171,9 +177,7 @@ const PROBE_BY_PROVIDER: Record<string, AutoDetectProbe> = Object.fromEntries(
export function autoDetectProvider(task?: ProviderDefaultTask): string | undefined {
const customOrder = getProviderPriority();
const order: AutoDetectProbe[] = customOrder
? customOrder
.map((p) => PROBE_BY_PROVIDER[p])
.filter((probe): probe is AutoDetectProbe => Boolean(probe))
? customOrder.flatMap((p) => PROBES_BY_PROVIDER[p] ?? [])
: AUTO_DETECT_ORDER;

for (const probe of order) {
Expand Down
Loading