Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 26 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,29 @@ Add durable exceptions here when a proposed sync should not be repeated.
- Do not implement `/responses` in this SDK unless explicitly requested.
- If a capability was intentionally rejected for product/design reasons, do not propose it again
until this file is updated.

## Coding practices

Besides the practices enforced through the CI checks (especially with ruff), we try to enforce the
following coding practices:

- Mark non-public modules, classes, methods, functions, and attributes private with a leading
underscore when they are not part of the SDK public API.
- Prefer [Google style guide imports](https://google.github.io/styleguide/pyguide.html#22-imports)
for new code: import modules instead of importing symbols, except for `typing` symbols, public
re-exports, and cases where the existing file convention makes module imports awkward.
- Treat anything exported from `linkup.__init__` or listed in `__all__` as public API; add exports
only intentionally.
- Keep API wire-format names at the request/response boundary only. Internal and public Python APIs
should stay snake_case, and camelCase/API aliases should live in request serialization or Pydantic
aliases.
- Keep sync and async methods structurally aligned: same parameters, same validation behavior, same
returned models, and same documented errors.
- Store secrets as `pydantic.SecretStr` or an equivalent secret container once they enter client
state; do not store raw API keys on instances.
- Prefer explicit SDK error classes over leaking transport or dependency exceptions from public
methods, except where deliberately documented.
- Add `# noqa`, `# type: ignore`, and `# pyright: ignore` only with a short reason.
- Avoid adding runtime dependencies for small conveniences; keep SDK dependencies minimal.
- Write tests through the public `linkup` API unless the test is specifically covering private or
internal behavior.
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,19 @@ The `search` function also supports three output types, through the `output_type

- with `"searchResults"`, the search will return a list of relevant documents
- with `"sourcedAnswer"`, the search will return a concise answer with sources
- with `"structured"`, the search will return a structured output according to a user-defined schema
- with `"structured"`, the search will return a structured output according to a user-defined object
schema

```python
from typing import Any

import linkup

client = linkup.Client() # API key can be read from the environment variable or passed as an argument
search_response: Any = client.search(
search_response: linkup.SourcedAnswer = client.search(
query="What are the 3 major events in the life of Abraham Lincoln?",
depth="deep", # "fast" (beta), "standard", or "deep"
output_type="sourcedAnswer", # "searchResults" or "sourcedAnswer" or "structured"
structured_output_schema=None, # must be filled if output_type is "structured"
)
assert isinstance(search_response, linkup.SourcedAnswer)
print(search_response.model_dump())
```

Expand Down Expand Up @@ -215,19 +213,17 @@ This makes possible to call the Linkup API several times concurrently for instan

```python
import asyncio
from typing import Any

import linkup

async def main() -> None:
client = linkup.Client() # API key can be read from the environment variable or passed as an argument
search_response: Any = await client.async_search(
search_response: linkup.SourcedAnswer = await client.async_search(
query="What are the 3 major events in the life of Abraham Lincoln?",
depth="deep", # "fast" (beta), "standard", or "deep"
output_type="sourcedAnswer", # "searchResults" or "sourcedAnswer" or "structured"
structured_output_schema=None, # must be filled if output_type is "structured"
)
assert isinstance(search_response, linkup.SourcedAnswer)
print(search_response.model_dump())

asyncio.run(main())
Expand Down
2 changes: 2 additions & 0 deletions src/linkup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
LinkupUnknownError,
)
from ._types import (
JSONObject,
LinkupFetchImageExtraction,
LinkupFetchResponse,
LinkupFetchTask,
Expand Down Expand Up @@ -92,6 +93,7 @@
"FetchUrlIsFileError",
"InsufficientCreditError",
"InvalidRequestError",
"JSONObject",
"LinkupAuthenticationError",
"LinkupBudgetLimitExceededError",
"LinkupClient",
Expand Down
Loading
Loading